From 707a5c293fa72fcaabc1e578220586b3a4d29c0f Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 9 Aug 2026 15:27:44 +0300 Subject: [PATCH] =?UTF-8?q?fix(cfe-patch-method):=20=D0=BF=D0=B0=D1=80?= =?UTF-8?q?=D0=B8=D1=82=D0=B5=D1=82=20=D0=BF=D0=BE=D1=80=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=BF=D0=BE=20=D0=BF=D1=80=D0=BE=D1=89=D0=B0=D1=8E=D1=89?= =?UTF-8?q?=D0=B5=D0=BC=D1=83=20=D0=B2=D0=B2=D0=BE=D0=B4=D1=83=20+=20?= =?UTF-8?q?=D0=BA=D0=B0=D1=80=D1=82=D0=B0=20=D0=B2=20=D1=80=D0=B5=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проверка «работает ли гард во все стороны» вскрыла, что он проверяет только заявленные карты. Попытка автообнаружения незаявленных дала 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) --- .../scripts/cfe-patch-method.ps1 | 2 +- .../scripts/cfe-patch-method.py | 20 +++++++++++++++- tests/skills/check-type-maps.mjs | 24 +++++++++++++++---- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.ps1 b/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.ps1 index 21715630..f04966aa 100644 --- a/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.ps1 +++ b/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.ps1 @@ -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)] diff --git a/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.py b/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.py index 6f7ae229..33fda80c 100644 --- a/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.py +++ b/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.py @@ -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()): diff --git a/tests/skills/check-type-maps.mjs b/tests/skills/check-type-maps.mjs index 2098b87f..035e87c4 100644 --- a/tests/skills/check-type-maps.mjs +++ b/tests/skills/check-type-maps.mjs @@ -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; }