fix(mxl-compile,mxl-decompile): расшифровка ячейки без параметра заполнения

Ключ detail описывал ячейку только вместе с param, а платформа ставит
расшифровку самостоятельно: на корпусе ERP 20 404 ячейки несут её БЕЗ
параметра (12 653 пустых, 5 949 с текстом, 1 802 поля ввода) против
8 582 с параметром. Компилятор такую расшифровку молча выбрасывал,
декомпилятор молча не читал, а ячейку, где кроме расшифровки ничего нет,
считал заполнителем строки и терял целиком.

Заодно выправлен порядок тегов ячейки: расшифровка идёт ПОСЛЕ текста,
а не перед ним (корпус: f · parameter · tl|v · detailParameter).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-15 13:07:32 +03:00
co-authored by Claude Opus 5
parent d7c81505d8
commit 66bb285636
11 changed files with 215 additions and 12 deletions
@@ -179,7 +179,7 @@
| `rowspan` | нет | `1` | Объединение по вертикали (количество строк) |
| `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) |
| `param` | нет | — | Параметр заполнения |
| `detail` | нет | — | Параметр расшифровки (только с `param`) |
| `detail` | нет | — | Параметр расшифровки. Самостоятельный ключ: ставится и на ячейку без `param` — с текстом, пустую или поле ввода |
| `text` | нет | — | Статический текст. Строка или объект `{ ru, en }` — см. ниже |
| `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` |
| `valueType` | нет | — | Тип значения: ячейка становится полем ввода (см. ниже) |
@@ -1711,9 +1711,6 @@ foreach ($area in $def.areas) {
if ($cellInfo.Param) {
X "`t`t`t`t`t<parameter>$($cellInfo.Param)</parameter>"
if ($cellInfo.Detail) {
X "`t`t`t`t`t<detailParameter>$($cellInfo.Detail)</detailParameter>"
}
}
# Проверяем НАЛИЧИЕ ключа, а не истинность: пустая строка — это текст, платформа
@@ -1722,6 +1719,14 @@ foreach ($area in $def.areas) {
if ($null -ne $cellInfo.Template) { Emit-CellText $cellInfo.Template }
# Расшифровка от параметра заполнения не зависит: на корпусе 20 404 ячейки несут
# её БЕЗ параметра (у текста, у пустой ячейки, у поля ввода) против 8 582 с ним.
# Пока она стояла внутри ветки параметра, две трети расшифровок терялись молча.
# Порядок тегов ячейки снят с корпуса: parameter · текст · detailParameter.
if ($cellInfo.Detail) {
X "`t`t`t`t`t<detailParameter>$($cellInfo.Detail)</detailParameter>"
}
X "`t`t`t`t</c>"
X "`t`t`t</c>"
}
@@ -1658,8 +1658,6 @@ def main():
if cell_info['Param']:
lines.append(f'\t\t\t\t\t<parameter>{cell_info["Param"]}</parameter>')
if cell_info['Detail']:
lines.append(f'\t\t\t\t\t<detailParameter>{cell_info["Detail"]}</detailParameter>')
# Проверяем НАЛИЧИЕ ключа, а не истинность: пустая строка — это текст,
# платформа такие ячейки пишет с пустым <tl>, и по истинности он терялся.
@@ -1669,6 +1667,13 @@ def main():
if cell_info['Template'] is not None:
emit_cell_text(lines, cell_info['Template'])
# Расшифровка от параметра заполнения не зависит: на корпусе 20 404 ячейки несут
# её БЕЗ параметра (у текста, у пустой ячейки, у поля ввода) против 8 582 с ним.
# Пока она стояла внутри ветки параметра, две трети расшифровок терялись молча.
# Порядок тегов ячейки снят с корпуса: parameter · текст · detailParameter.
if cell_info['Detail']:
lines.append(f'\t\t\t\t\t<detailParameter>{cell_info["Detail"]}</detailParameter>')
lines.append('\t\t\t\t</c>')
lines.append('\t\t\t</c>')
@@ -1035,7 +1035,9 @@ foreach ($area in $blocks) {
# значение задаёт её формат. Без этого такая строка уходила бы в пустые.
$cf = Get-Format $cell.FormatIdx
$hasValue = ($cf -and $cf.Props['containsValue'] -ceq 'true')
$hasContent = $cell.Param -or $cell.HasText -or $hasValue
# Расшифровка сама по себе делает ячейку содержательной: в корпусе 12 653 ячейки
# несут только её. Без этого такая ячейка уходила в заполнители и терялась.
$hasContent = $cell.Param -or $cell.HasText -or $hasValue -or $cell.Detail
$hasMerge = $mergeMap.ContainsKey("$globalRow,$($cell.Col)")
if ($hasContent -or $hasMerge) {
@@ -1140,12 +1142,15 @@ foreach ($area in $blocks) {
if ($cell.Param) {
$dslCell["param"] = $cell.Param
if ($cell.Detail) { $dslCell["detail"] = $cell.Detail }
} elseif ($fillType -eq "Template" -and $cell.HasText) {
$dslCell["template"] = Get-DslText $cell.Text
} elseif ($cell.HasText) {
$dslCell["text"] = Get-DslText $cell.Text
}
# Расшифровка живёт отдельно от параметра заполнения: на корпусе 20 404 ячейки
# несут её без параметра против 8 582 с ним. Пока она читалась только вместе
# с параметром, две трети расшифровок терялись молча.
if ($cell.Detail) { $dslCell["detail"] = $cell.Detail }
$dslCells += $dslCell
}
@@ -1032,7 +1032,9 @@ def main():
# нет: значение задаёт её формат. Без этого такая строка уходила бы в пустые.
cf = get_format(cell["FormatIdx"])
has_value = bool(cf and cf["Props"].get("containsValue") == "true")
has_content = cell["Param"] or cell["HasText"] or has_value
# Расшифровка сама по себе делает ячейку содержательной: в корпусе 12 653 ячейки
# несут только её. Без этого такая ячейка уходила в заполнители и терялась.
has_content = cell["Param"] or cell["HasText"] or has_value or cell["Detail"]
has_merge = f"{global_row},{cell['Col']}" in merge_map
if has_content or has_merge:
@@ -1132,12 +1134,15 @@ def main():
if cell["Param"]:
dsl_cell["param"] = cell["Param"]
if cell["Detail"]:
dsl_cell["detail"] = cell["Detail"]
elif fill_type == "Template" and cell["HasText"]:
dsl_cell["template"] = get_dsl_text(cell["Text"])
elif cell["HasText"]:
dsl_cell["text"] = get_dsl_text(cell["Text"])
# Расшифровка живёт отдельно от параметра заполнения: на корпусе 20 404 ячейки
# несут её без параметра против 8 582 с ним. Пока она читалась только вместе
# с параметром, две трети расшифровок терялись молча.
if cell["Detail"]:
dsl_cell["detail"] = cell["Detail"]
dsl_cells.append(dsl_cell)
+1 -1
View File
@@ -179,7 +179,7 @@
| `rowspan` | нет | `1` | Объединение по вертикали (количество строк) |
| `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) |
| `param` | нет | — | Параметр заполнения |
| `detail` | нет | — | Параметр расшифровки (только с `param`) |
| `detail` | нет | — | Параметр расшифровки. Самостоятельный ключ: ставится и на ячейку без `param` — с текстом, пустую или поле ввода |
| `text` | нет | — | Статический текст. Строка или объект `{ ru, en }` — см. ниже |
| `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` |
| `valueType` | нет | — | Тип значения: ячейка становится полем ввода (см. ниже) |
@@ -0,0 +1,21 @@
{
"name": "Расшифровка без параметра заполнения",
"input": {
"columns": 3,
"areas": [
{
"name": "Расшифровки",
"rows": [
{ "cells": [
{ "col": 1, "text": "Итого", "detail": "ПоказательИтога" },
{ "col": 2, "detail": "ПустаяЯчейка" },
{ "col": 3, "param": "Сумма", "detail": "Расшифровка" }
]}
]
}
]
},
"params": {
"outputPath": "Template.xml"
}
}
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://v8.1c.ru/8.2/data/spreadsheet" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<languageSettings>
<currentLanguage>ru</currentLanguage>
<defaultLanguage>ru</defaultLanguage>
<languageInfo>
<id>ru</id>
<code>Русский</code>
<description>Русский</description>
</languageInfo>
</languageSettings>
<columns>
<size>3</size>
</columns>
<rowsItem>
<index>0</index>
<row>
<c>
<c>
<f>0</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Итого</v8:content>
</v8:item>
</tl>
<detailParameter>ПоказательИтога</detailParameter>
</c>
</c>
<c>
<c>
<f>0</f>
<detailParameter>ПустаяЯчейка</detailParameter>
</c>
</c>
<c>
<c>
<f>1</f>
<parameter>Сумма</parameter>
<detailParameter>Расшифровка</detailParameter>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
<defaultFormatIndex>2</defaultFormatIndex>
<height>1</height>
<vgRows>1</vgRows>
<namedItem xsi:type="NamedItemCells">
<name>Расшифровки</name>
<area>
<type>Rows</type>
<beginRow>0</beginRow>
<endRow>0</endRow>
<beginColumn>-1</beginColumn>
<endColumn>-1</endColumn>
</area>
</namedItem>
<format>
<fillType>Parameter</fillType>
</format>
<format>
<width>10</width>
</format>
</document>
@@ -0,0 +1,31 @@
{
"name": "Roundtrip — расшифровка без параметра заполнения",
"preRun": [
{
"script": "mxl-compile/scripts/mxl-compile",
"input": {
"columns": 3,
"areas": [
{
"name": "Расшифровки",
"rows": [
{ "cells": [
{ "col": 1, "text": "Итого", "detail": "ПоказательИтога" },
{ "col": 2, "detail": "ПустаяЯчейка" },
{ "col": 3, "param": "Сумма", "detail": "Расшифровка" }
]}
]
}
]
},
"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:"
}
}
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://v8.1c.ru/8.2/data/spreadsheet" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<languageSettings>
<currentLanguage>ru</currentLanguage>
<defaultLanguage>ru</defaultLanguage>
<languageInfo>
<id>ru</id>
<code>Русский</code>
<description>Русский</description>
</languageInfo>
</languageSettings>
<columns>
<size>3</size>
</columns>
<rowsItem>
<index>0</index>
<row>
<c>
<c>
<f>0</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Итого</v8:content>
</v8:item>
</tl>
<detailParameter>ПоказательИтога</detailParameter>
</c>
</c>
<c>
<c>
<f>0</f>
<detailParameter>ПустаяЯчейка</detailParameter>
</c>
</c>
<c>
<c>
<f>1</f>
<parameter>Сумма</parameter>
<detailParameter>Расшифровка</detailParameter>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
<defaultFormatIndex>2</defaultFormatIndex>
<height>1</height>
<vgRows>1</vgRows>
<namedItem xsi:type="NamedItemCells">
<name>Расшифровки</name>
<area>
<type>Rows</type>
<beginRow>0</beginRow>
<endRow>0</endRow>
<beginColumn>-1</beginColumn>
<endColumn>-1</endColumn>
</area>
</namedItem>
<format>
<fillType>Parameter</fillType>
</format>
<format>
<width>10</width>
</format>
</document>
@@ -0,0 +1 @@
{ "columns": 3, "defaultWidth": 10, "fonts": {}, "styles": {}, "areas": [{ "name": "Расшифровки", "rows": [[{ "text": "Итого", "detail": "ПоказательИтога" }, { "detail": "ПустаяЯчейка" }, { "param": "Сумма", "detail": "Расшифровка" }]] }] }