feat(mxl-compile): короткая форма строки — массив ячеек

Строка, записанная массивом ("rows": [["А","Б","В"]]), молча превращалась в
пустую строку в обоих портах. Форма не выдумана: ровно так документированы
макеты в skd-compile, и привычка естественно переносится на табличный документ.

Масштаб потери был виден в самом репозитории — ПЯТЬ кейсов семейства mxl-*
написаны в этой форме и потому проверяли пустые макеты: снэпшот
lenient-key-case содержал единственную строку <empty>true</empty>. После правки
все пять снэпшотов наполнились ячейками, которые терялись.

Семантика повторяет skd-compile: позиция ячейки — индекс в массиве, ">"
продолжает ячейку слева (span), "|" — сверху (rowspan), null пропускает
колонку, "{Имя}" даёт параметр. Элемент можно записать и объектом, когда нужен
style или detail; col в нём запрещён — это смешение двух способов адресации.
Разворот идёт отдельным пред-проходом в обычные строки с явными col/span/rowspan,
поэтому остальной компилятор о короткой форме не знает.

Форма документирована — в отличие от прощающего пропуска col: модель пишет канон
соседнего навыка, и выравнивание двух табличных DSL убирает развилку. По каскаду
в SKILL.md только правило и пример, подробности и таблица ошибок — в спеке
(обе копии: docs/ и reference/ навыка).

Правка на ps1, зазеркалена в py: вывод портов совпадает байт в байт, decompile →
compile возвращает исходный XML байт в байт.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-10 14:07:51 +03:00
co-authored by Claude Opus 5
parent ccbbecbcf2
commit 6719d7e647
17 changed files with 908 additions and 15 deletions
@@ -0,0 +1,16 @@
{
"name": "Ошибка: > первым элементом строки — слева нет ячейки",
"input": {
"columns": 3,
"areas": [
{
"name": "Шапка",
"rows": [[">", "А"]]
}
]
},
"params": {
"outputPath": "Template.xml"
},
"expectError": "Row shorthand: '>' has no cell to the left: area \"Шапка\", row 1, cell 1"
}
@@ -0,0 +1,16 @@
{
"name": "Ошибка: объектный элемент шортката несёт col",
"input": {
"columns": 3,
"areas": [
{
"name": "Шапка",
"rows": [["А", { "col": 2, "text": "Б" }]]
}
]
},
"params": {
"outputPath": "Template.xml"
},
"expectError": "Row shorthand: cell object must not carry 'col': area \"Шапка\", row 1, cell 2"
}
@@ -0,0 +1,16 @@
{
"name": "Ошибка: | в первой строке области — сверху нет ячейки",
"input": {
"columns": 3,
"areas": [
{
"name": "Шапка",
"rows": [["А", "|"]]
}
]
},
"params": {
"outputPath": "Template.xml"
},
"expectError": "Row shorthand: '|' has no cell above: area \"Шапка\", row 1, cell 2"
}
@@ -0,0 +1,23 @@
{
"name": "Шорткат строк: двухуровневая шапка через > и |",
"input": {
"columns": 4,
"areas": [
{
"name": "Шапка",
"rows": [
["Вид", "Остаток", ">", "Итог"],
["|", "начало", "конец", "|"],
["{Вид}", "{Нач}", "{Кон}", "{Итог}"]
]
}
]
},
"params": {
"outputPath": "Template.xml"
},
"validatePath": "Template.xml",
"expect": {
"files": ["Template.xml"]
}
}
@@ -0,0 +1,23 @@
{
"name": "Шорткат строк: текст, параметр, пропуск, объектный элемент",
"input": {
"columns": 4,
"styles": { "hdr": { "align": "center", "border": "all" } },
"areas": [
{
"name": "Таблица",
"rows": [
["Наименование", "Количество", "Сумма", "Примечание"],
["{Товар}", "{Кол}", null, { "text": "хвост", "style": "hdr" }]
]
}
]
},
"params": {
"outputPath": "Template.xml"
},
"validatePath": "Template.xml",
"expect": {
"files": ["Template.xml"]
}
}
@@ -15,7 +15,42 @@
<rowsItem>
<index>0</index>
<row>
<empty>true</empty>
<c>
<i>0</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Наименование</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>1</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Количество</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>2</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Сумма</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
@@ -36,4 +71,8 @@
<format>
<width>10</width>
</format>
<format>
<font>0</font>
<fillType>Text</fillType>
</format>
</document>
@@ -0,0 +1,161 @@
<?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>4</size>
</columns>
<rowsItem>
<index>0</index>
<row>
<c>
<i>0</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Вид</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>1</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Остаток</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>3</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Итог</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>1</index>
<row>
<c>
<i>1</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>начало</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>2</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>конец</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>2</index>
<row>
<c>
<i>0</i>
<c>
<f>3</f>
<parameter>Вид</parameter>
</c>
</c>
<c>
<i>1</i>
<c>
<f>3</f>
<parameter>Нач</parameter>
</c>
</c>
<c>
<i>2</i>
<c>
<f>3</f>
<parameter>Кон</parameter>
</c>
</c>
<c>
<i>3</i>
<c>
<f>3</f>
<parameter>Итог</parameter>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
<defaultFormatIndex>1</defaultFormatIndex>
<height>3</height>
<vgRows>3</vgRows>
<merge>
<r>0</r>
<c>0</c>
<h>1</h>
<w>0</w>
</merge>
<merge>
<r>0</r>
<c>1</c>
<w>1</w>
</merge>
<merge>
<r>0</r>
<c>3</c>
<h>1</h>
<w>0</w>
</merge>
<namedItem xsi:type="NamedItemCells">
<name>Шапка</name>
<area>
<type>Rows</type>
<beginRow>0</beginRow>
<endRow>2</endRow>
<beginColumn>-1</beginColumn>
<endColumn>-1</endColumn>
</area>
</namedItem>
<font faceName="Arial" height="10" bold="false" italic="false" underline="false" strikeout="false" kind="Absolute" scale="100"/>
<format>
<width>10</width>
</format>
<format>
<font>0</font>
<fillType>Text</fillType>
</format>
<format>
<font>0</font>
<fillType>Parameter</fillType>
</format>
</document>
@@ -0,0 +1,137 @@
<?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>4</size>
</columns>
<rowsItem>
<index>0</index>
<row>
<c>
<i>0</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Наименование</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>1</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Количество</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>2</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Сумма</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>3</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Примечание</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<rowsItem>
<index>1</index>
<row>
<c>
<i>0</i>
<c>
<f>3</f>
<parameter>Товар</parameter>
</c>
</c>
<c>
<i>1</i>
<c>
<f>3</f>
<parameter>Кол</parameter>
</c>
</c>
<c>
<i>3</i>
<c>
<f>4</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>хвост</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
<defaultFormatIndex>1</defaultFormatIndex>
<height>2</height>
<vgRows>2</vgRows>
<namedItem xsi:type="NamedItemCells">
<name>Таблица</name>
<area>
<type>Rows</type>
<beginRow>0</beginRow>
<endRow>1</endRow>
<beginColumn>-1</beginColumn>
<endColumn>-1</endColumn>
</area>
</namedItem>
<line width="1" gap="false">
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentCellLineType">Solid</v8ui:style>
</line>
<font faceName="Arial" height="10" bold="false" italic="false" underline="false" strikeout="false" kind="Absolute" scale="100"/>
<format>
<width>10</width>
</format>
<format>
<font>0</font>
<fillType>Text</fillType>
</format>
<format>
<font>0</font>
<fillType>Parameter</fillType>
</format>
<format>
<font>0</font>
<leftBorder>0</leftBorder>
<topBorder>0</topBorder>
<rightBorder>0</rightBorder>
<bottomBorder>0</bottomBorder>
<horizontalAlignment>Center</horizontalAlignment>
<fillType>Text</fillType>
</format>
</document>
@@ -15,7 +15,42 @@
<rowsItem>
<index>0</index>
<row>
<empty>true</empty>
<c>
<i>0</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Наименование</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>1</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Количество</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>2</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Сумма</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
@@ -36,4 +71,8 @@
<format>
<width>10</width>
</format>
<format>
<font>0</font>
<fillType>Text</fillType>
</format>
</document>
@@ -15,7 +15,42 @@
<rowsItem>
<index>0</index>
<row>
<empty>true</empty>
<c>
<i>0</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>A</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>1</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>B</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>2</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>C</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
@@ -36,4 +71,8 @@
<format>
<width>10</width>
</format>
<format>
<font>0</font>
<fillType>Text</fillType>
</format>
</document>
@@ -15,7 +15,42 @@
<rowsItem>
<index>0</index>
<row>
<empty>true</empty>
<c>
<i>0</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>A</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>1</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>B</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>2</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>C</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
@@ -36,4 +71,8 @@
<format>
<width>10</width>
</format>
<format>
<font>0</font>
<fillType>Text</fillType>
</format>
</document>
@@ -15,7 +15,42 @@
<rowsItem>
<index>0</index>
<row>
<empty>true</empty>
<c>
<i>0</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>A</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>1</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>B</v8:content>
</v8:item>
</tl>
</c>
</c>
<c>
<i>2</i>
<c>
<f>2</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>C</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<templateMode>true</templateMode>
@@ -36,4 +71,8 @@
<format>
<width>10</width>
</format>
<format>
<font>0</font>
<fillType>Text</fillType>
</format>
</document>