diff --git a/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 b/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 index 8f3d45b5..2760ec11 100644 --- a/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 +++ b/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 @@ -1,4 +1,4 @@ -# mxl-compile v1.50 — Compile 1C spreadsheet from JSON +# mxl-compile v1.51 — Compile 1C spreadsheet from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -1191,10 +1191,12 @@ function Emit-CellText { } else { foreach ($l in $textLanguages) { $pairs += @{ Lang = $l; Text = "$value" } } } - # Пустой объект — отдельное состояние: тег текста есть, языков в нём нет. Платформа - # пишет его самозакрывающимся. Для авторинга бесполезно (визуально это тот же пустой - # текст, что и ""), поэтому в описании DSL записи нет — она нужна раундтрипу. - if ($pairs.Count -eq 0) { + # Пустой текст платформа хранит ТОЛЬКО самозакрывающимся тегом: в корпусе ERP таких + # 1 224 460, а из 780 934 непустых блоков ни одного со всеми пустыми языками нет. + # Поэтому и пустая строка, и пустой объект дают одну и ту же запись. + $allEmpty = $true + foreach ($pr in $pairs) { if ("$($pr.Text)" -ne '') { $allEmpty = $false; break } } + if ($pairs.Count -eq 0 -or $allEmpty) { X "`t`t`t`t`t" return } diff --git a/.claude/skills/mxl-compile/scripts/mxl-compile.py b/.claude/skills/mxl-compile/scripts/mxl-compile.py index 6d3ec4a4..1f7dcaf1 100644 --- a/.claude/skills/mxl-compile/scripts/mxl-compile.py +++ b/.claude/skills/mxl-compile/scripts/mxl-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# mxl-compile v1.50 — Compile 1C spreadsheet from JSON +# mxl-compile v1.51 — Compile 1C spreadsheet from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import hashlib @@ -1210,10 +1210,10 @@ def main(): pairs = [(str(k), str(v)) for k, v in value.items()] else: pairs = [(lang, str(value)) for lang in text_languages] - # Пустой объект — отдельное состояние: тег текста есть, языков в нём нет. Платформа - # пишет его самозакрывающимся. Для авторинга бесполезно (визуально это тот же пустой - # текст, что и ""), поэтому в описании DSL записи нет — она нужна раундтрипу. - if not pairs: + # Пустой текст платформа хранит ТОЛЬКО самозакрывающимся тегом: в корпусе ERP таких + # 1 224 460, а из 780 934 непустых блоков ни одного со всеми пустыми языками нет. + # Поэтому и пустая строка, и пустой объект дают одну и ту же запись. + if not pairs or all(content == '' for _, content in pairs): lines.append('\t\t\t\t\t') return lines.append('\t\t\t\t\t') diff --git a/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1 b/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1 index 9775c3f6..e1739819 100644 --- a/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1 +++ b/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1 @@ -1,4 +1,4 @@ -# mxl-decompile v1.29 — Decompile 1C spreadsheet to JSON +# mxl-decompile v1.30 — Decompile 1C spreadsheet to JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -723,6 +723,10 @@ $textLanguages = @($docLangs.Keys) function Get-DslText { param($byLang) if ($byLang -isnot [System.Collections.IDictionary]) { return $byLang } + # Пустой текст () записывается в DSL пустой строкой — той же формой, что + # авторская. Без этой ветки макет, где ДРУГОГО текста нет вовсе, отдавал $null, + # и ячейка с пустым текстом теряла содержимое. + if ($byLang.Count -eq 0) { return '' } if ($byLang.Count -ne $textLanguages.Count) { return $byLang } $common = $null foreach ($l in $textLanguages) { @@ -1219,8 +1223,10 @@ function ConvertTo-PositionalCells { # Позиционная форма ценна компактностью: если она длиннее объектной, смысла в ней нет. $a = Try-InlineJson $out $b = Try-InlineJson $cells - if ($null -ne $a -and $null -ne $b -and $a.Length -gt $b.Length) { return $cells } - return $out + if ($null -ne $a -and $null -ne $b -and $a.Length -gt $b.Length) { return ,$cells } + # Запятая обязательна: без неё список из одной ячейки разворачивается в саму ячейку, + # а список из одного $null — в $null, и строка целиком уходила в пустые. + return ,$out } # --- 12. Build areas --- diff --git a/.claude/skills/mxl-decompile/scripts/mxl-decompile.py b/.claude/skills/mxl-decompile/scripts/mxl-decompile.py index c9819005..86e21ab4 100644 --- a/.claude/skills/mxl-decompile/scripts/mxl-decompile.py +++ b/.claude/skills/mxl-decompile/scripts/mxl-decompile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# mxl-decompile v1.29 — Decompile 1C spreadsheet to JSON +# mxl-decompile v1.30 — Decompile 1C spreadsheet to JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -849,6 +849,11 @@ def main(): def get_dsl_text(by_lang): if not isinstance(by_lang, dict): return by_lang + # Пустой текст () записывается в DSL пустой строкой — той же формой, что + # авторская. Без этой ветки макет, где ДРУГОГО текста нет вовсе, отдавал null, + # и ячейка с пустым текстом теряла содержимое. + if not by_lang: + return '' if len(by_lang) != len(text_languages): return by_lang common = None diff --git a/tests/skills/cases/mxl-compile/empty-cell-text.json b/tests/skills/cases/mxl-compile/empty-cell-text.json new file mode 100644 index 00000000..60830f4d --- /dev/null +++ b/tests/skills/cases/mxl-compile/empty-cell-text.json @@ -0,0 +1,16 @@ +{ + "name": "Пустой текст ячейки: строка, объект и все языки пустые", + "input": { + "columns": 2, + "textLanguages": ["ru", "en"], + "areas": [{ + "rows": [ + { "cells": [{ "col": 1, "text": "" }] }, + { "cells": [{ "col": 1, "text": {} }] }, + { "cells": [{ "col": 1, "text": { "ru": "", "en": "" } }] }, + { "cells": [{ "col": 1, "text": { "ru": "А", "en": "" } }] } + ] + }] + }, + "params": { "outputPath": "Template.xml" } +} diff --git a/tests/skills/cases/mxl-compile/snapshots/empty-cell-text/Template.xml b/tests/skills/cases/mxl-compile/snapshots/empty-cell-text/Template.xml new file mode 100644 index 00000000..74a37483 --- /dev/null +++ b/tests/skills/cases/mxl-compile/snapshots/empty-cell-text/Template.xml @@ -0,0 +1,75 @@ + + + + ru + ru + + ru + Русский + Русский + + + + 2 + + + 0 + + + + 0 + + + + + + + 1 + + + + 0 + + + + + + + 2 + + + + 0 + + + + + + + 3 + + + + 0 + + + ru + А + + + en + + + + + + + + true + 1 + 4 + 4 + + 10 + + \ No newline at end of file diff --git a/tests/skills/cases/mxl-decompile/roundtrip-empty-text.json b/tests/skills/cases/mxl-decompile/roundtrip-empty-text.json new file mode 100644 index 00000000..442ddfd8 --- /dev/null +++ b/tests/skills/cases/mxl-decompile/roundtrip-empty-text.json @@ -0,0 +1,18 @@ +{ + "name": "Roundtrip — пустой текст ячейки возвращается как \"\"", + "preRun": [ + { "script": "mxl-compile/scripts/mxl-compile", + "input": { + "columns": 2, + "areas": [{ "rows": [ + { "cells": [{ "col": 1, "text": "" }] }, + { "cells": [{ "col": 1, "text": "Текст" }] } + ]}] + }, + "args": { "-JsonPath": "{inputFile}", "-OutputPath": "Template.xml" }, + "cwd": "{workDir}" } + ], + "params": { "templatePath": "Template.xml" }, + "args_extra": ["-OutputPath", "{workDir}/back.json"], + "expect": { "files": ["back.json"], "stdoutContains": "[OK] Decompiled:" } +} diff --git a/tests/skills/cases/mxl-decompile/snapshots/roundtrip-empty-text/Template.xml b/tests/skills/cases/mxl-decompile/snapshots/roundtrip-empty-text/Template.xml new file mode 100644 index 00000000..8f0a78c2 --- /dev/null +++ b/tests/skills/cases/mxl-decompile/snapshots/roundtrip-empty-text/Template.xml @@ -0,0 +1,49 @@ + + + + ru + ru + + ru + Русский + Русский + + + + 2 + + + 0 + + + + 0 + + + + + + + 1 + + + + 0 + + + ru + Текст + + + + + + + true + 1 + 2 + 2 + + 10 + + \ No newline at end of file diff --git a/tests/skills/cases/mxl-decompile/snapshots/roundtrip-empty-text/back.json b/tests/skills/cases/mxl-decompile/snapshots/roundtrip-empty-text/back.json new file mode 100644 index 00000000..35c04f31 --- /dev/null +++ b/tests/skills/cases/mxl-decompile/snapshots/roundtrip-empty-text/back.json @@ -0,0 +1 @@ +{ "columns": 2, "defaultWidth": 10, "fonts": {}, "styles": {}, "areas": [{ "rows": [[""], ["Текст"]] }] } \ No newline at end of file