fix(meta-compile): регистронезависимый ввод в py-порте — паритет с PS

PowerShell не различает регистр нигде, куда попадает пользовательский ввод:
свойства объекта из ConvertFrom-Json, ключи Hashtable, -eq/-contains, имена
параметров, ValidateSet. Python различает везде, поэтому один и тот же DSL
давал разный результат на разных портах — и чаще всего молча: "CodeLength"
вместо "codeLength" в py просто не находился, навык печатал [OK], а свойство
в выход не попадало.

Пилот на meta-compile. В py-порт добавлены общие обёртки: CIDict (поиск без
учёта регистра, ключи хранятся как есть — часть из них имена объектов и
попадает в XML), ci_json (рекурсивно на разобранный DSL), ci_parse_args (имена
параметров и значения choices). Ими же обёрнуты словари синонимов видов,
алиасов enum и типов.

Попутно исправлен дефект самого канона: PS принимал "type":"catalog", но
дальше использовал значение как есть — в имени тега и в регистрации в
Configuration.xml, то есть отдавал <catalog>, которую платформа не примет.
Теперь вид приводится к канону списка в обоих портах.

check-inline-drift: extractPy научен доставать class (иначе тело CIDict
невидимо), заведены три семьи с ps1: null — в PS1 этих обёрток быть не должно.

Проверка: кейс lenient-key-case зелёный на обоих портах; полный регресс
673/673 (PS) и 670+3 skipped (PY); гарды 4/4; sweep по 400 справочникам трёх
конфигураций (декомпиляция → компиляция обоими портами) — 0 расхождений.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-09 19:48:24 +03:00
co-authored by Claude Opus 5
parent 4622234b52
commit 8c0fbed7d6
14 changed files with 863 additions and 5 deletions
+20 -1
View File
@@ -270,6 +270,23 @@ const FAMILIES = [
],
},
// ─── Регистронезависимый ввод: паритет с PS1 ─────────────────────────────
// Существует только в PY: PowerShell регистронезависим сам по себе (свойства PSObject, ключи
// Hashtable, -eq/-contains, имена параметров, ValidateSet), поэтому в .ps1 копии нет и быть
// не должно — ps1: null.
{
name: 'case-insensitive input: CIDict', py: 'CIDict', ps1: null,
variants: [{ id: 'base', authority: 'meta-compile', consumers: [] }],
},
{
name: 'case-insensitive input: ci_json', py: 'ci_json', ps1: null,
variants: [{ id: 'base', authority: 'meta-compile', consumers: [] }],
},
{
name: 'case-insensitive input: ci_parse_args', py: 'ci_parse_args', ps1: null,
variants: [{ id: 'base', authority: 'meta-compile', consumers: [] }],
},
];
// ─── Семьи, разъехавшиеся целиком ───────────────────────────────────────────
@@ -301,7 +318,9 @@ function extractPy(text) {
for (let i = 0; i < lines.length; i++) {
// Определение бывает вложенным: *-info объявляют is_external_root внутри другой функции.
// Поиск только по `^def` делал такие копии невидимыми для гарда — то есть давал ложное «OK».
const m = /^(\s*)def ([A-Za-z_]\w*)\(/.exec(lines[i]);
// Классы забирает та же ветка: общая утилита бывает и классом (CIDict), а без этого её тело
// гарду невидимо и семью для неё не завести.
const m = /^(\s*)(?:def|class) ([A-Za-z_]\w*)[(:]/.exec(lines[i]);
if (!m) continue;
const indent = m[1].length;
const body = [lines[i]];