fix(cfe-patch-method): паритет портов по прощающему вводу + карта в реестр

Проверка «работает ли гард во все стороны» вскрыла, что он проверяет только
заявленные карты. Попытка автообнаружения незаявленных дала 112 срабатываний,
из них большинство — ложные (накопители массивов, чей блок разбирается неверно),
поэтому сама проверка в гард не попала. Но она нашла реальное:

у cfe-patch-method карта типов не была в реестре, и порты по ней разошлись —
PS1 принимал и Catalog.X, и Catalogs.X (32 записи), PY только Catalog.X (16).
Расхождение доставшееся, не из этой ветки. PY дополнен формами множественного
числа: ввод, работавший в одном порте, теперь работает в обоих.

В реестр карт типов добавлены cfe-patch-method (TYPE_DIR_MAP, DIR_TO_TYPE),
cf-edit.RU_TYPE_MAP и cfe-borrow.SYNONYM_MAP — 28 проверяемых карт стало 36.
Для частичных карт добавлен флаг partial (полнота не требуется, каталоги
сверяются), для прощающих — keyMayBeDir (ключом принимается имя каталога).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-09 15:27:44 +03:00
co-authored by Claude Opus 5
parent 04d78fe816
commit 707a5c293f
3 changed files with 40 additions and 6 deletions
@@ -1,4 +1,4 @@
# cfe-patch-method v2.5 — Source-aware method interceptor for 1C extension (CFE)
# cfe-patch-method v2.6 — Source-aware method interceptor for 1C extension (CFE) (+прощающий ввод: имя каталога наравне с именем типа)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# cfe-patch-method v2.5 — Source-aware method interceptor for 1C extension (CFE)
# cfe-patch-method v2.6 — Source-aware method interceptor for 1C extension (CFE) (+прощающий ввод: имя каталога наравне с именем типа)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -19,6 +19,24 @@ TYPE_DIR_MAP = {
"BusinessProcess": "BusinessProcesses", "Task": "Tasks",
"InformationRegister": "InformationRegisters", "AccumulationRegister": "AccumulationRegisters",
"AccountingRegister": "AccountingRegisters", "CalculationRegister": "CalculationRegisters",
# Прощающий ввод: имя каталога принимается наравне с именем типа (Catalogs.X ≡ Catalog.X) —
# PS1-порт так умел с самого начала, PY отставал.
"Catalogs": "Catalogs",
"Documents": "Documents",
"Enums": "Enums",
"CommonModules": "CommonModules",
"Reports": "Reports",
"DataProcessors": "DataProcessors",
"ExchangePlans": "ExchangePlans",
"ChartsOfAccounts": "ChartsOfAccounts",
"ChartsOfCharacteristicTypes": "ChartsOfCharacteristicTypes",
"ChartsOfCalculationTypes": "ChartsOfCalculationTypes",
"BusinessProcesses": "BusinessProcesses",
"Tasks": "Tasks",
"InformationRegisters": "InformationRegisters",
"AccumulationRegisters": "AccumulationRegisters",
"AccountingRegisters": "AccountingRegisters",
"CalculationRegisters": "CalculationRegisters",
}
# accept plural forms too
for _v in list(TYPE_DIR_MAP.values()):
+20 -4
View File
@@ -65,6 +65,17 @@ const MAPS = [
{ skill: 'subsystem-edit', file: 'subsystem-edit', kind: 'alias', py: 'CONTENT_TYPE_MAP', ps1: null },
{ skill: 'subsystem-compile', file: 'subsystem-compile', kind: 'alias', py: 'CONTENT_TYPE_MAP', ps1: null },
{ skill: 'meta-remove', file: 'meta-remove', kind: 'keys', py: 'TYPE_PLURAL_MAP', ps1: '$typePluralMap' },
{ skill: 'cf-edit', file: 'cf-edit', kind: 'alias', py: 'RU_TYPE_MAP', ps1: '$script:ruTypeMap' },
{ skill: 'cfe-borrow', file: 'cfe-borrow', kind: 'alias', py: 'SYNONYM_MAP', ps1: '$synonymMap' },
{ skill: 'cfe-patch-method', file: 'cfe-patch-method', kind: 'alias',
py: 'DIR_TO_TYPE', ps1: '$script:dirToType' },
{
// Частичная карта тип→каталог: перехватывать метод можно только у объектов с модулями,
// поэтому полнота не требуется. Плюс прощающий ввод — ключом принимается и имя каталога
// (Catalogs.X ≡ Catalog.X), поэтому ключи сверяем как «тип ИЛИ каталог типа».
skill: 'cfe-patch-method', file: 'cfe-patch-method', kind: 'dir', partial: true, keyMayBeDir: true,
py: 'TYPE_DIR_MAP', ps1: '$script:typeDirMap',
},
];
// ─── Эталон из спецификации ─────────────────────────────────────────────────
@@ -94,7 +105,10 @@ function sliceBlock(text, startIdx, open, close) {
if (from < 0) return null;
const closer = `\n${indent}${close}`;
const to = text.indexOf(closer, from);
return text.slice(from + open.length, to < 0 ? text.length : to);
// Закрывашки нет — значит это не блок, а выражение в одну строку. Возвращать «до конца файла»
// нельзя: обнаружение тогда видит в таком «блоке» все канонические имена сразу.
if (to < 0) return null;
return text.slice(from + open.length, to);
}
function extractPy(text, name, kind) {
@@ -174,15 +188,17 @@ for (const entry of MAPS) {
if (entry.kind === 'dir') {
seen.push({ tag, count: data.length });
const dirNames = new Set(spec.dirOf.values());
for (const [type, dir] of data) {
if (!canonical.has(type)) {
const asDir = entry.keyMayBeDir && dirNames.has(type);
if (!canonical.has(type) && !asDir) {
errors.push(`${tag}: тип '${type}' отсутствует в таблице спецификации`);
continue;
}
const want = spec.dirOf.get(type);
const want = asDir ? type : spec.dirOf.get(type);
if (dir !== want) errors.push(`${tag}: '${type}' → '${dir}', в таблице '${want}'`);
}
checkMissing(tag, new Set(data.map((d) => d[0])), exclude);
if (!entry.partial) checkMissing(tag, new Set(data.map((d) => d[0])), exclude);
continue;
}