fix(mxl-decompile): абсолютный OutputPath + общий сериализатор декомпиляторов

Безусловная склейка OutputPath с текущим каталогом давала "C:\cwd\C:\out.json" и
роняла запись сообщением про формат пути — навык не умел писать по абсолютному
пути вообще. Py-порт этот случай обрабатывал, ps1 нет. Приведено к общей идиоме
репозитория; кейс на абсолютный путь падает без правки и проходит с ней.

Кейс заодно вскрыл, что порты пишут РАЗНЫЙ JSON: ps1 отдавал стиль ConvertTo-Json
из PS 5.1 (выравнивание ключей, \uXXXX вместо кириллицы), py — json.dumps(indent=2).
Один и тот же макет давал 4708 байт против 1744. Не всплывало потому, что ни один
кейс не снимал сам JSON — все проверяли только stdout.

mxl-decompile был единственным декомпилятором мимо общего сериализатора: у
form/meta/skd-decompile для этого свой ConvertTo-CompactJson. Перенесён вариант
skd-decompile как самый полный, py дополнительно переведён на newline='' —
как у соседей. Теперь порты совпадают байт в байт, а decompile→compile даёт
исходный XML байт в байт.

Семья заведена в check-inline-drift.mjs (4 функции, 3 варианта): раньше шесть
копий жили вообще без гарда. В form-decompile переименована локальная переменная
в string-literal — копии различались только ею.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-10 13:35:50 +03:00
co-authored by Claude Opus 5
parent f33436adff
commit ccbbecbcf2
8 changed files with 387 additions and 27 deletions
+37
View File
@@ -319,6 +319,43 @@ const FAMILIES = [
],
},
// ─── Компактный JSON декомпиляторов ─────────────────────────────────────
// Штатные сериализаторы не годятся: ConvertTo-Json (PS5.1) выравнивает ключи по самому
// длинному и эскейпит кириллицу в \uXXXX, json.dumps даёт иную раскладку inline/multiline.
// Поэтому у декомпиляторов свой сериализатор — и он обязан совпадать в портах байт в байт,
// иначе один и тот же макет даёт разный DSL на разных рантаймах.
{
name: 'decompile json: string literal',
py: 'convert_string_to_json_literal', ps1: 'Convert-StringToJsonLiteral',
variants: [
{ id: 'base', authority: 'skd-decompile', consumers: ['form-decompile', 'mxl-decompile'] }],
},
{
name: 'decompile json: try inline',
py: 'try_inline_json', ps1: 'Try-InlineJson',
variants: [
{ id: 'base', authority: 'skd-decompile', consumers: ['mxl-decompile'] },
{ id: 'no-pscustomobject', authority: 'form-decompile', consumers: [],
why: 'form-decompile строит дерево на ordered-хэштейблах и ветку PSCustomObject не проходит' }],
},
{
// Только в PY: в ps1 числа печатает [System.Convert]::ToString с InvariantCulture прямо
// в теле сериализатора, отдельной функции там нет — ps1: null.
name: 'decompile json: number', py: '_fmt_number', ps1: null,
variants: [
{ id: 'base', authority: 'skd-decompile', consumers: ['mxl-decompile'] }],
},
{
name: 'decompile json: compact',
py: 'convert_to_compact_json', ps1: 'ConvertTo-CompactJson',
variants: [
{ id: 'base', authority: 'skd-decompile', consumers: ['mxl-decompile'] },
{ id: 'line-limit-120', authority: 'form-decompile', consumers: [],
why: 'у форм строки DSL длиннее, порог inline снижен со 400 до 120' },
{ id: 'legacy', authority: 'meta-decompile', consumers: [],
why: 'ранний вариант со своим Quote-Json и без inline-попытки; сведение меняет вывод meta-decompile' }],
},
];
// ─── Семьи, разъехавшиеся целиком ───────────────────────────────────────────