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