diff --git a/.claude/skills/mxl-compile/SKILL.md b/.claude/skills/mxl-compile/SKILL.md
index f35b8140..0f9e679d 100644
--- a/.claude/skills/mxl-compile/SKILL.md
+++ b/.claude/skills/mxl-compile/SKILL.md
@@ -64,3 +64,12 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-compile.ps1" -J
- Тип заполнения определяется автоматически: `param` → Parameter, `text` → Text, `template` → Template
- `rowspan` — объединение строк вниз (rowStyle учитывает занятые ячейки)
- `empty` в строке — шорткат для N подряд пустых строк (`{ "empty": 3 }` = три `{}`)
+- Строку можно писать массивом ячеек — позиция из порядка, `col` не нужен: `"текст"`, `"{Имя}"` — параметр, `">"` — продолжить ячейку слева, `"|"` — сверху, `null` — пропуск колонки. Та же форма, что у макетов в `/skd-compile`
+
+```json
+"rows": [
+ ["Вид", "Остаток", ">", "Итог"],
+ ["|", "начало", "конец", "|"],
+ ["{Вид}", "{Нач}", "{Кон}", "{Итог}"]
+]
+```
diff --git a/.claude/skills/mxl-compile/reference/dsl-spec.md b/.claude/skills/mxl-compile/reference/dsl-spec.md
index 9320e10e..3d6ac3a6 100644
--- a/.claude/skills/mxl-compile/reference/dsl-spec.md
+++ b/.claude/skills/mxl-compile/reference/dsl-spec.md
@@ -124,11 +124,47 @@
Строка без `cells` и `rowStyle` → пустая строка. `{ "empty": 3 }` эквивалентно трём `{}`.
+### Короткая форма: строка массивом
+
+Вместо объекта строка может быть массивом ячеек — позиция определяется порядком, `col` не указывается. Соглашения совпадают с макетами СКД (`/skd-compile`).
+
+| Элемент | Значение |
+|---------|----------|
+| `"текст"` | Статический текст (`text`) |
+| `"{Имя}"` | Параметр (`param`) |
+| `">"` | Продолжение ячейки слева — увеличивает её `span` |
+| `"|"` | Продолжение ячейки сверху — увеличивает её `rowspan` |
+| `null` | Пустая колонка: позиция занята, ячейка не создаётся |
+| `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` |
+
+```json
+"rows": [
+ ["Вид", "Остаток", ">", "Итог"],
+ ["|", "начало", "конец", "|"],
+ ["{Вид}", "{Нач}", "{Кон}", "{Итог}"]
+]
+```
+Здесь «Вид» и «Итог» объединены по вертикали на две строки, «Остаток» — по горизонтали на две колонки.
+
+Ограничения короткой формы:
+- не задать `height` и `rowStyle` — это свойства строки, а не ячейки;
+- не выразить текст, совпадающий с `">"`, `"|"` или с шаблоном `"{...}"`;
+- `"|"` продолжает ячейку из предыдущей строки, только если её позиция известна явно (`col` задан или строка записана массивом).
+
+Ошибки короткой формы (stderr, код возврата 1):
+
+| Условие | Сообщение |
+|---------|-----------|
+| `">"` без ячейки слева | `Row shorthand: '>' has no cell to the left: area "…", row N, cell M` |
+| `"|"` без ячейки сверху | `Row shorthand: '|' has no cell above: area "…", row N, cell M` |
+| объектный элемент с `col` | `Row shorthand: cell object must not carry 'col': area "…", row N, cell M` |
+| элементов больше `columns` | `Row exceeds 'columns' (K): area "…", row N` |
+
## Ячейки (`cells[]`)
| Поле | Обяз. | По умолч. | Описание |
|------|:-----:|-----------|----------|
-| `col` | да | — | Позиция колонки (1-based) |
+| `col` | да | — | Позиция колонки (1-based). В короткой форме строки не указывается — позиция берётся из порядка |
| `span` | нет | `1` | Объединение по горизонтали (количество колонок) |
| `rowspan` | нет | `1` | Объединение по вертикали (количество строк) |
| `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) |
diff --git a/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 b/.claude/skills/mxl-compile/scripts/mxl-compile.ps1
index 0b9630a5..fd4b0acd 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.15 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
+# mxl-compile v1.16 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -520,6 +520,129 @@ function Register-CellFormat {
return Register-Format -key $key -props $props
}
+# --- 5.5. Шорткат строк: строка-массив ячеек ---
+# Та же форма, что у макетов СКД (skd-compile): позиция ячейки = индекс в массиве,
+# ">" продолжает ячейку слева, "|" — ячейку сверху, null — пустая колонка,
+# "{Имя}" — параметр. Разворачиваем в обычную строку с явными col/span/rowspan,
+# поэтому весь код ниже про шорткат не знает.
+
+function Set-CellProp {
+ param($cell, [string]$name, $value)
+ $cell | Add-Member -NotePropertyName $name -NotePropertyValue $value -Force
+}
+
+function Expand-ShorthandRow {
+ param($row, [string]$areaName, [int]$rowIdx, $openByCol)
+
+ $cells = @()
+ $placed = @{} # 1-based col -> ячейка, занимающая колонку в ЭТОЙ строке
+ $extended = @() # ячейки, чей rowspan уже нарастили в этой строке (span>1 даёт несколько "|")
+ $last = $null # последняя реальная ячейка слева — цель для ">"
+ $idx = 0
+
+ foreach ($el in $row) {
+ $idx++
+ # Внутри функции пишем в stderr напрямую: Write-Error приписал бы к сообщению имя
+ # функции, и текст перестал бы совпадать с py-портом.
+ if ($idx -gt $totalColumns) {
+ [Console]::Error.WriteLine("Row exceeds 'columns' ($totalColumns): area `"$areaName`", row $rowIdx")
+ exit 1
+ }
+
+ if ($null -eq $el) { $last = $null; continue }
+
+ if ($el -is [string] -and $el -eq '>') {
+ if ($null -eq $last) {
+ [Console]::Error.WriteLine("Row shorthand: '>' has no cell to the left: area `"$areaName`", row $rowIdx, cell $idx")
+ exit 1
+ }
+ $span = if ($last.span) { [int]$last.span } else { 1 }
+ Set-CellProp $last 'span' ($span + 1)
+ $placed[$idx] = $last
+ continue
+ }
+
+ if ($el -is [string] -and $el -eq '|') {
+ $above = $openByCol[$idx]
+ if ($null -eq $above) {
+ [Console]::Error.WriteLine("Row shorthand: '|' has no cell above: area `"$areaName`", row $rowIdx, cell $idx")
+ exit 1
+ }
+ if (-not ($extended -contains $above)) {
+ $rowspan = if ($above.rowspan) { [int]$above.rowspan } else { 1 }
+ Set-CellProp $above 'rowspan' ($rowspan + 1)
+ $extended += $above
+ }
+ $placed[$idx] = $above
+ $last = $null
+ continue
+ }
+
+ if ($el -is [string]) {
+ $cell = [PSCustomObject]@{ col = $idx; span = 1 }
+ $m = [regex]::Match($el, '^\{(.+)\}$')
+ if ($m.Success) { Set-CellProp $cell 'param' $m.Groups[1].Value }
+ else { Set-CellProp $cell 'text' $el }
+ } else {
+ # Объектный элемент — обычная ячейка mxl, позиция берётся из индекса.
+ if ($el.PSObject.Properties['col']) {
+ [Console]::Error.WriteLine("Row shorthand: cell object must not carry 'col': area `"$areaName`", row $rowIdx, cell $idx")
+ exit 1
+ }
+ $cell = $el
+ Set-CellProp $cell 'col' $idx
+ if (-not $cell.span) { Set-CellProp $cell 'span' 1 }
+ }
+
+ $cells += $cell
+ $placed[$idx] = $cell
+ $last = $cell
+ }
+
+ # Колонки, не занятые в этой строке, теряют «ячейку сверху».
+ $openByCol.Clear()
+ foreach ($k in $placed.Keys) { $openByCol[$k] = $placed[$k] }
+
+ return [PSCustomObject]@{ cells = $cells }
+}
+
+# Карту занятых колонок ведём и по объектным строкам: "|" продолжает ту ячейку,
+# которая реально стоит выше, независимо от того, какой формой её записали.
+function Update-OpenByCol {
+ param($row, $openByCol)
+ $placed = @{}
+ if ($row.cells) {
+ foreach ($cell in $row.cells) {
+ # Ячейки без col (строка с автопотоком) на этом шаге ещё не разложены — позиция
+ # станет известна позже, поэтому «ячейку сверху» они не дают, и "|" под такой
+ # строкой честно скажет, что сверху ничего нет.
+ if (-not $cell.PSObject.Properties['col'] -or $null -eq $cell.col) { continue }
+ $col = [int]$cell.col
+ $span = if ($cell.span) { [int]$cell.span } else { 1 }
+ for ($c = $col; $c -lt ($col + $span); $c++) { $placed[$c] = $cell }
+ }
+ }
+ $openByCol.Clear()
+ foreach ($k in $placed.Keys) { $openByCol[$k] = $placed[$k] }
+}
+
+foreach ($area in $def.areas) {
+ $areaName = $area.name
+ $openByCol = @{}
+ $rowIdx = 0
+ $expandedRows = @()
+ foreach ($row in $area.rows) {
+ $rowIdx++
+ if ($row -is [array]) {
+ $expandedRows += Expand-ShorthandRow -row $row -areaName $areaName -rowIdx $rowIdx -openByCol $openByCol
+ } else {
+ $expandedRows += $row
+ if ($row.empty) { $openByCol.Clear() } else { Update-OpenByCol -row $row -openByCol $openByCol }
+ }
+ }
+ $area.rows = $expandedRows
+}
+
# Pre-register all formats from areas
foreach ($area in $def.areas) {
foreach ($row in $area.rows) {
diff --git a/.claude/skills/mxl-compile/scripts/mxl-compile.py b/.claude/skills/mxl-compile/scripts/mxl-compile.py
index be3bae0d..74365dec 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.15 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
+# mxl-compile v1.16 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import json
@@ -585,12 +585,117 @@ def main():
}
return register_format(key, props)
+ # --- 5.5. Шорткат строк: строка-массив ячеек ---
+ # Та же форма, что у макетов СКД (skd-compile): позиция ячейки = индекс в массиве,
+ # ">" продолжает ячейку слева, "|" — ячейку сверху, null — пустая колонка,
+ # "{Имя}" — параметр. Разворачиваем в обычную строку с явными col/span/rowspan,
+ # поэтому весь код ниже про шорткат не знает.
+
+ def expand_shorthand_row(row, area_name, row_idx, open_by_col):
+ cells = []
+ placed = {} # 1-based col -> ячейка, занимающая колонку в ЭТОЙ строке
+ extended = [] # ячейки, чей rowspan уже нарастили в этой строке (span>1 даёт несколько "|")
+ last = None # последняя реальная ячейка слева — цель для ">"
+
+ for idx, el in enumerate(row, start=1):
+ if idx > total_columns:
+ print(f'Row exceeds \'columns\' ({total_columns}): area "{area_name}",'
+ f' row {row_idx}', file=sys.stderr)
+ sys.exit(1)
+
+ if el is None:
+ last = None
+ continue
+
+ if isinstance(el, str) and el == '>':
+ if last is None:
+ print(f'Row shorthand: \'>\' has no cell to the left: area "{area_name}",'
+ f' row {row_idx}, cell {idx}', file=sys.stderr)
+ sys.exit(1)
+ last['span'] = int(last.get('span', 1)) + 1
+ placed[idx] = last
+ continue
+
+ if isinstance(el, str) and el == '|':
+ above = open_by_col.get(idx)
+ if above is None:
+ print(f'Row shorthand: \'|\' has no cell above: area "{area_name}",'
+ f' row {row_idx}, cell {idx}', file=sys.stderr)
+ sys.exit(1)
+ if not any(above is e for e in extended):
+ above['rowspan'] = int(above.get('rowspan', 1)) + 1
+ extended.append(above)
+ placed[idx] = above
+ last = None
+ continue
+
+ if isinstance(el, str):
+ cell = CIDict()
+ cell['col'] = idx
+ cell['span'] = 1
+ m = re.match(r'^\{(.+)\}$', el)
+ if m:
+ cell['param'] = m.group(1)
+ else:
+ cell['text'] = el
+ else:
+ # Объектный элемент — обычная ячейка mxl, позиция берётся из индекса.
+ if 'col' in el:
+ print(f'Row shorthand: cell object must not carry \'col\': area "{area_name}",'
+ f' row {row_idx}, cell {idx}', file=sys.stderr)
+ sys.exit(1)
+ cell = el
+ cell['col'] = idx
+ if not cell.get('span'):
+ cell['span'] = 1
+
+ cells.append(cell)
+ placed[idx] = cell
+ last = cell
+
+ # Колонки, не занятые в этой строке, теряют «ячейку сверху».
+ open_by_col.clear()
+ open_by_col.update(placed)
+
+ out = CIDict()
+ out['cells'] = cells
+ return out
+
+ # Карту занятых колонок ведём и по объектным строкам: "|" продолжает ту ячейку,
+ # которая реально стоит выше, независимо от того, какой формой её записали.
+ def update_open_by_col(row, open_by_col):
+ placed = {}
+ for cell in (row.get('cells') or []):
+ # Ячейки без col (строка с автопотоком) на этом шаге ещё не разложены — позиция
+ # станет известна позже, поэтому «ячейку сверху» они не дают, и "|" под такой
+ # строкой честно скажет, что сверху ничего нет.
+ if cell.get('col') is None:
+ continue
+ col = int(cell['col'])
+ span = int(cell.get('span', 1))
+ for c in range(col, col + span):
+ placed[c] = cell
+ open_by_col.clear()
+ open_by_col.update(placed)
+
+ for area in defn['areas']:
+ area_name = area.get('name', '')
+ open_by_col = {}
+ expanded_rows = []
+ for row_idx, row in enumerate(area.get('rows', []), start=1):
+ if isinstance(row, list):
+ expanded_rows.append(expand_shorthand_row(row, area_name, row_idx, open_by_col))
+ else:
+ expanded_rows.append(row)
+ if row.get('empty'):
+ open_by_col.clear()
+ else:
+ update_open_by_col(row, open_by_col)
+ area['rows'] = expanded_rows
+
# Pre-register all formats from areas
for area in defn['areas']:
for row in area.get('rows', []):
- # Skip list-of-values shorthand rows (treated as empty rows like PS1)
- if isinstance(row, list):
- continue
# Skip empty row placeholder
if row.get('empty'):
continue
@@ -668,9 +773,6 @@ def main():
local_row = 0
for row in area.get('rows', []):
- # List-of-values shorthand: treat as row with no properties (like PS1)
- if isinstance(row, list):
- row = {}
# Empty row placeholder: emit N empty rows
if row.get('empty'):
count = int(row['empty'])
diff --git a/docs/mxl-dsl-spec.md b/docs/mxl-dsl-spec.md
index f65b541e..12a6b208 100644
--- a/docs/mxl-dsl-spec.md
+++ b/docs/mxl-dsl-spec.md
@@ -124,11 +124,47 @@
Строка без `cells` и `rowStyle` → пустая строка. `{ "empty": 3 }` эквивалентно трём `{}`.
+### Короткая форма: строка массивом
+
+Вместо объекта строка может быть массивом ячеек — позиция определяется порядком, `col` не указывается. Соглашения совпадают с макетами СКД (`/skd-compile`).
+
+| Элемент | Значение |
+|---------|----------|
+| `"текст"` | Статический текст (`text`) |
+| `"{Имя}"` | Параметр (`param`) |
+| `">"` | Продолжение ячейки слева — увеличивает её `span` |
+| `"|"` | Продолжение ячейки сверху — увеличивает её `rowspan` |
+| `null` | Пустая колонка: позиция занята, ячейка не создаётся |
+| `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` |
+
+```json
+"rows": [
+ ["Вид", "Остаток", ">", "Итог"],
+ ["|", "начало", "конец", "|"],
+ ["{Вид}", "{Нач}", "{Кон}", "{Итог}"]
+]
+```
+Здесь «Вид» и «Итог» объединены по вертикали на две строки, «Остаток» — по горизонтали на две колонки.
+
+Ограничения короткой формы:
+- не задать `height` и `rowStyle` — это свойства строки, а не ячейки;
+- не выразить текст, совпадающий с `">"`, `"|"` или с шаблоном `"{...}"`;
+- `"|"` продолжает ячейку из предыдущей строки, только если её позиция известна явно (`col` задан или строка записана массивом).
+
+Ошибки короткой формы (stderr, код возврата 1):
+
+| Условие | Сообщение |
+|---------|-----------|
+| `">"` без ячейки слева | `Row shorthand: '>' has no cell to the left: area "…", row N, cell M` |
+| `"|"` без ячейки сверху | `Row shorthand: '|' has no cell above: area "…", row N, cell M` |
+| объектный элемент с `col` | `Row shorthand: cell object must not carry 'col': area "…", row N, cell M` |
+| элементов больше `columns` | `Row exceeds 'columns' (K): area "…", row N` |
+
## Ячейки (`cells[]`)
| Поле | Обяз. | По умолч. | Описание |
|------|:-----:|-----------|----------|
-| `col` | да | — | Позиция колонки (1-based) |
+| `col` | да | — | Позиция колонки (1-based). В короткой форме строки не указывается — позиция берётся из порядка |
| `span` | нет | `1` | Объединение по горизонтали (количество колонок) |
| `rowspan` | нет | `1` | Объединение по вертикали (количество строк) |
| `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) |
diff --git a/tests/skills/cases/mxl-compile/error-shorthand-caret-first.json b/tests/skills/cases/mxl-compile/error-shorthand-caret-first.json
new file mode 100644
index 00000000..eab6cba3
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/error-shorthand-caret-first.json
@@ -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"
+}
diff --git a/tests/skills/cases/mxl-compile/error-shorthand-object-col.json b/tests/skills/cases/mxl-compile/error-shorthand-object-col.json
new file mode 100644
index 00000000..317eb4ac
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/error-shorthand-object-col.json
@@ -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"
+}
diff --git a/tests/skills/cases/mxl-compile/error-shorthand-pipe-first-row.json b/tests/skills/cases/mxl-compile/error-shorthand-pipe-first-row.json
new file mode 100644
index 00000000..55fb9f10
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/error-shorthand-pipe-first-row.json
@@ -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"
+}
diff --git a/tests/skills/cases/mxl-compile/shorthand-merges.json b/tests/skills/cases/mxl-compile/shorthand-merges.json
new file mode 100644
index 00000000..3617c238
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/shorthand-merges.json
@@ -0,0 +1,23 @@
+{
+ "name": "Шорткат строк: двухуровневая шапка через > и |",
+ "input": {
+ "columns": 4,
+ "areas": [
+ {
+ "name": "Шапка",
+ "rows": [
+ ["Вид", "Остаток", ">", "Итог"],
+ ["|", "начало", "конец", "|"],
+ ["{Вид}", "{Нач}", "{Кон}", "{Итог}"]
+ ]
+ }
+ ]
+ },
+ "params": {
+ "outputPath": "Template.xml"
+ },
+ "validatePath": "Template.xml",
+ "expect": {
+ "files": ["Template.xml"]
+ }
+}
diff --git a/tests/skills/cases/mxl-compile/shorthand-rows.json b/tests/skills/cases/mxl-compile/shorthand-rows.json
new file mode 100644
index 00000000..d2a8d671
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/shorthand-rows.json
@@ -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"]
+ }
+}
diff --git a/tests/skills/cases/mxl-compile/snapshots/lenient-key-case/Template.xml b/tests/skills/cases/mxl-compile/snapshots/lenient-key-case/Template.xml
index 384ee851..e27634fd 100644
--- a/tests/skills/cases/mxl-compile/snapshots/lenient-key-case/Template.xml
+++ b/tests/skills/cases/mxl-compile/snapshots/lenient-key-case/Template.xml
@@ -15,7 +15,42 @@
0
- true
+
+ 0
+
+ 2
+
+
+ ru
+ Наименование
+
+
+
+
+
+ 1
+
+ 2
+
+
+ ru
+ Количество
+
+
+
+
+
+ 2
+
+ 2
+
+
+ ru
+ Сумма
+
+
+
+
true
@@ -36,4 +71,8 @@
10
+
+ 0
+ Text
+
\ No newline at end of file
diff --git a/tests/skills/cases/mxl-compile/snapshots/shorthand-merges/Template.xml b/tests/skills/cases/mxl-compile/snapshots/shorthand-merges/Template.xml
new file mode 100644
index 00000000..735529b4
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/snapshots/shorthand-merges/Template.xml
@@ -0,0 +1,161 @@
+
+
+
+ ru
+ ru
+
+ ru
+ Русский
+ Русский
+
+
+
+ 4
+
+
+ 0
+
+
+ 0
+
+ 2
+
+
+ ru
+ Вид
+
+
+
+
+
+ 1
+
+ 2
+
+
+ ru
+ Остаток
+
+
+
+
+
+ 3
+
+ 2
+
+
+ ru
+ Итог
+
+
+
+
+
+
+
+ 1
+
+
+ 1
+
+ 2
+
+
+ ru
+ начало
+
+
+
+
+
+ 2
+
+ 2
+
+
+ ru
+ конец
+
+
+
+
+
+
+
+ 2
+
+
+ 0
+
+ 3
+ Вид
+
+
+
+ 1
+
+ 3
+ Нач
+
+
+
+ 2
+
+ 3
+ Кон
+
+
+
+ 3
+
+ 3
+ Итог
+
+
+
+
+ true
+ 1
+ 3
+ 3
+
+ 0
+ 0
+ 1
+ 0
+
+
+ 0
+ 1
+ 1
+
+
+ 0
+ 3
+ 1
+ 0
+
+
+ Шапка
+
+ Rows
+ 0
+ 2
+ -1
+ -1
+
+
+
+
+ 10
+
+
+ 0
+ Text
+
+
+ 0
+ Parameter
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/mxl-compile/snapshots/shorthand-rows/Template.xml b/tests/skills/cases/mxl-compile/snapshots/shorthand-rows/Template.xml
new file mode 100644
index 00000000..929aada0
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/snapshots/shorthand-rows/Template.xml
@@ -0,0 +1,137 @@
+
+
+
+ ru
+ ru
+
+ ru
+ Русский
+ Русский
+
+
+
+ 4
+
+
+ 0
+
+
+ 0
+
+ 2
+
+
+ ru
+ Наименование
+
+
+
+
+
+ 1
+
+ 2
+
+
+ ru
+ Количество
+
+
+
+
+
+ 2
+
+ 2
+
+
+ ru
+ Сумма
+
+
+
+
+
+ 3
+
+ 2
+
+
+ ru
+ Примечание
+
+
+
+
+
+
+
+ 1
+
+
+ 0
+
+ 3
+ Товар
+
+
+
+ 1
+
+ 3
+ Кол
+
+
+
+ 3
+
+ 4
+
+
+ ru
+ хвост
+
+
+
+
+
+
+ true
+ 1
+ 2
+ 2
+
+ Таблица
+
+ Rows
+ 0
+ 1
+ -1
+ -1
+
+
+
+ Solid
+
+
+
+ 10
+
+
+ 0
+ Text
+
+
+ 0
+ Parameter
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ Center
+ Text
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/mxl-compile/snapshots/simple-template/Template.xml b/tests/skills/cases/mxl-compile/snapshots/simple-template/Template.xml
index 384ee851..e27634fd 100644
--- a/tests/skills/cases/mxl-compile/snapshots/simple-template/Template.xml
+++ b/tests/skills/cases/mxl-compile/snapshots/simple-template/Template.xml
@@ -15,7 +15,42 @@
0
- true
+
+ 0
+
+ 2
+
+
+ ru
+ Наименование
+
+
+
+
+
+ 1
+
+ 2
+
+
+ ru
+ Количество
+
+
+
+
+
+ 2
+
+ 2
+
+
+ ru
+ Сумма
+
+
+
+
true
@@ -36,4 +71,8 @@
10
+
+ 0
+ Text
+
\ No newline at end of file
diff --git a/tests/skills/cases/mxl-decompile/snapshots/roundtrip/Template.xml b/tests/skills/cases/mxl-decompile/snapshots/roundtrip/Template.xml
index faa869be..0f05cee4 100644
--- a/tests/skills/cases/mxl-decompile/snapshots/roundtrip/Template.xml
+++ b/tests/skills/cases/mxl-decompile/snapshots/roundtrip/Template.xml
@@ -15,7 +15,42 @@
0
- true
+
+ 0
+
+ 2
+
+
+ ru
+ A
+
+
+
+
+
+ 1
+
+ 2
+
+
+ ru
+ B
+
+
+
+
+
+ 2
+
+ 2
+
+
+ ru
+ C
+
+
+
+
true
@@ -36,4 +71,8 @@
10
+
+ 0
+ Text
+
\ No newline at end of file
diff --git a/tests/skills/cases/mxl-info/snapshots/template-overview/Template.xml b/tests/skills/cases/mxl-info/snapshots/template-overview/Template.xml
index 384ee851..19739083 100644
--- a/tests/skills/cases/mxl-info/snapshots/template-overview/Template.xml
+++ b/tests/skills/cases/mxl-info/snapshots/template-overview/Template.xml
@@ -15,7 +15,42 @@
0
- true
+
+ 0
+
+ 2
+
+
+ ru
+ A
+
+
+
+
+
+ 1
+
+ 2
+
+
+ ru
+ B
+
+
+
+
+
+ 2
+
+ 2
+
+
+ ru
+ C
+
+
+
+
true
@@ -36,4 +71,8 @@
10
+
+ 0
+ Text
+
\ No newline at end of file
diff --git a/tests/skills/cases/mxl-validate/snapshots/valid-template/Template.xml b/tests/skills/cases/mxl-validate/snapshots/valid-template/Template.xml
index faa869be..0f05cee4 100644
--- a/tests/skills/cases/mxl-validate/snapshots/valid-template/Template.xml
+++ b/tests/skills/cases/mxl-validate/snapshots/valid-template/Template.xml
@@ -15,7 +15,42 @@
0
- true
+
+ 0
+
+ 2
+
+
+ ru
+ A
+
+
+
+
+
+ 1
+
+ 2
+
+
+ ru
+ B
+
+
+
+
+
+ 2
+
+ 2
+
+
+ ru
+ C
+
+
+
+
true
@@ -36,4 +71,8 @@
10
+
+ 0
+ Text
+
\ No newline at end of file