mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-13 23:13:22 +03:00
Раздел ограничений врал в обе стороны. Он обещал потерю областей Columns и Rectangle — они поддержаны предыдущим коммитом; и молчал про то, что теряется на самом деле. Проверено по коду обоих навыков, доли — по корпусу ERP 8.3.24: ячейки-поля ввода (53% макетов), несколько наборов колонок (63%), объединения вне ячеек (16%), рисунки (2%), цвета, скрытые строки, отступ, посторонние стили линий, группировки, колонтитулы и параметры печати. Отдельно записано, что многоязычные надписи не поддерживаются: при разборе берётся первый вариант текста, при генерации язык всегда ru — для двуязычных макетов остальные языки теряются. Заодно убрано то, что описывает реализацию, а не использование: - таблицы с точными текстами сообщений об ошибках и кодом возврата. Модель, вызвавшая навык, видит и текст, и код прямо в выводе; документировать их незачем, а протухают они молча — ровно как протух раздел ограничений. Правила, из-за которых ошибка возникает, остались; сами строки зафиксированы в кейсах через expectError, где расхождение ловится механически. В остальных пяти спеках таких таблиц и не было — там принята одна фраза «ненулевой код выхода и сообщение в stderr»; - фраза про порядок эмиссии именованных элементов: автор DSL на него не влияет. Сам факт (платформа хранит их отсортированными по имени) перенесён в docs/1c-spreadsheet-spec.md, где описывается XML-уровень, вместе с оговоркой, что случай с «ё» не проверен. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
233 lines
14 KiB
Markdown
233 lines
14 KiB
Markdown
# Спецификация MXL DSL — JSON-формат описания табличного документа
|
||
|
||
Компактный JSON-формат для описания макетов табличных документов 1С (SpreadsheetDocument). Используется навыками `/mxl-compile` (JSON → XML) и `/mxl-decompile` (XML → JSON).
|
||
|
||
## Пример
|
||
|
||
```json
|
||
{
|
||
"columns": 10,
|
||
"defaultWidth": 30,
|
||
"columnWidths": { "1": 15, "2-8": 40, "9-10": 50 },
|
||
|
||
"fonts": {
|
||
"default": { "face": "Arial", "size": 10 },
|
||
"bold": { "face": "Arial", "size": 10, "bold": true },
|
||
"header": { "face": "Arial", "size": 14, "bold": true }
|
||
},
|
||
|
||
"styles": {
|
||
"default": {},
|
||
"header": { "font": "header", "align": "center" },
|
||
"label": { "font": "bold" },
|
||
"bordered": { "border": "all" },
|
||
"bordered-right": { "border": "all", "align": "right" },
|
||
"total-right": { "font": "bold", "border": "top", "align": "right" }
|
||
},
|
||
|
||
"areas": [
|
||
{
|
||
"name": "Заголовок",
|
||
"rows": [
|
||
{ "height": 20, "cells": [
|
||
{ "col": 1, "span": 10, "style": "header", "param": "ТекстЗаголовка" }
|
||
]}
|
||
]
|
||
},
|
||
{
|
||
"name": "ШапкаТаблицы",
|
||
"rows": [
|
||
{ "rowStyle": "bordered", "cells": [
|
||
{ "col": 1, "text": "№" },
|
||
{ "col": 2, "span": 6, "text": "Наименование" },
|
||
{ "col": 9, "text": "Кол-во" },
|
||
{ "col": 10, "text": "Сумма" }
|
||
]}
|
||
]
|
||
},
|
||
{
|
||
"name": "Строка",
|
||
"rows": [
|
||
{ "rowStyle": "bordered", "cells": [
|
||
{ "col": 1, "param": "НомерСтроки" },
|
||
{ "col": 2, "span": 6, "param": "Товар", "detail": "Номенклатура" },
|
||
{ "col": 9, "style": "bordered-right", "param": "Количество" },
|
||
{ "col": 10, "style": "bordered-right", "param": "Сумма" }
|
||
]}
|
||
]
|
||
},
|
||
{
|
||
"name": "Итого",
|
||
"rows": [
|
||
{ "cells": [
|
||
{ "col": 8, "span": 2, "style": "total-right", "text": "Итого:" },
|
||
{ "col": 10, "style": "total-right", "param": "Всего" }
|
||
]}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## Верхний уровень
|
||
|
||
| Поле | Обяз. | По умолч. | Описание |
|
||
|------|:-----:|-----------|----------|
|
||
| `columns` | да | — | Количество колонок |
|
||
| `page` | нет | — | Формат страницы: `"A4-landscape"` (780), `"A4-portrait"` (540) или число. Автоматически вычисляет `defaultWidth` из суммы пропорций `"Nx"` |
|
||
| `defaultWidth` | нет | 10 | Ширина колонок по умолчанию. Игнорируется если задан `page` и все колонки используют `"Nx"` |
|
||
| `columnWidths` | нет | `{}` | Ширины колонок. Ключи 1-based: `"1"`, `"3-14"`, `"5,7,9"`. Значения: число (абсолют) или `"Nx"` (множитель от defaultWidth, напр. `"2x"`, `"0.5x"`) |
|
||
| `fonts` | нет | — | Именованные шрифты (если не задано, создаётся Arial 10) |
|
||
| `styles` | нет | `{}` | Именованные стили |
|
||
| `areas` | да | — | Массив областей — диапазонов подряд идущих строк (порядок = порядок в документе); имя необязательно |
|
||
| `namedAreas` | нет | — | Именованные области, заданные координатами (см. ниже) |
|
||
|
||
## Шрифты (`fonts.<name>`)
|
||
|
||
| Поле | По умолч. | Описание |
|
||
|------|-----------|----------|
|
||
| `face` | `"Arial"` | Имя шрифта |
|
||
| `size` | `10` | Размер |
|
||
| `bold` | `false` | Жирный |
|
||
| `italic` | `false` | Курсив |
|
||
| `underline` | `false` | Подчёркнутый |
|
||
| `strikeout` | `false` | Зачёркнутый |
|
||
|
||
Шрифт `"default"` используется когда стиль не указывает шрифт явно. Если не определён, создаётся автоматически (Arial 10).
|
||
|
||
## Стили (`styles.<name>`)
|
||
|
||
| Поле | По умолч. | Описание |
|
||
|------|-----------|----------|
|
||
| `font` | `"default"` | Ссылка на имя шрифта |
|
||
| `align` | — | `left`, `center`, `right` |
|
||
| `valign` | — | `top`, `center` |
|
||
| `border` | — | Стороны рамки: `all`, `top`, `bottom`, `left`, `right`, `none`. Через запятую: `"top,bottom"` |
|
||
| `borderWidth` | `"thin"` | Толщина рамки: `thin` (1px) или `thick` (2px) |
|
||
| `wrap` | `false` | Перенос текста |
|
||
| `format` | — | Формат данных 1С: `"ЧЦ=15; ЧДЦ=2"`, `"ДФ=dd.MM.yyyy"` и т.д. |
|
||
|
||
## Области (`areas[]`)
|
||
|
||
| Поле | Обяз. | Описание |
|
||
|------|:-----:|----------|
|
||
| `name` | нет | Имя области для `Макет.ПолучитьОбласть("Имя")` |
|
||
| `rows` | да | Массив строк |
|
||
|
||
Макет собирается из областей — диапазонов подряд идущих строк. Заданное здесь имя компилятор разворачивает в именованную область типа «строки» на диапазон этих строк. **Область без имени** — просто кусок сетки: так описываются строки, не принадлежащие ни одной именованной области.
|
||
|
||
## Именованные области координатами (`namedAreas[]`)
|
||
|
||
Для областей, которые диапазоном подряд идущих строк не описываются: полоса колонок, прямоугольник, ячейка, а также пересекающиеся с другими.
|
||
|
||
| Поле | Обяз. | Описание |
|
||
|------|:-----:|----------|
|
||
| `name` | да | Имя области |
|
||
| `rows` | \* | Строки: число или диапазон `"N-M"`, 1-based |
|
||
| `cols` | \* | Колонки: число или диапазон `"N-M"`, 1-based |
|
||
|
||
\* Обязательна хотя бы одна из осей.
|
||
|
||
**Тип области не указывается** — он следует из того, какие оси заданы, как в `ТабличныйДокумент.Область()`: только строки → полоса строк, только колонки → полоса колонок, обе оси → прямоугольник, одиночные значения по обеим осям → одна ячейка.
|
||
|
||
```json
|
||
"namedAreas": [
|
||
{ "name": "ОбластьПечатиПоВысоте", "rows": "1-48" },
|
||
{ "name": "ОбластьПечатиПоШирине", "cols": "1-35" },
|
||
{ "name": "HZY", "rows": 9, "cols": "16-17" }
|
||
]
|
||
```
|
||
|
||
Диапазон — та же грамматика, что у `columnWidths`, но **только** число или `"N-M"`: список через запятую запрещён, область непрерывна. Имя обязательно, и хотя бы одна ось должна быть задана; нарушение любого из этих правил → ненулевой код выхода и сообщение в stderr.
|
||
|
||
## Строки (`rows[]`)
|
||
|
||
| Поле | По умолч. | Описание |
|
||
|------|-----------|----------|
|
||
| `height` | — | Высота строки (если не задана, используется авто) |
|
||
| `rowStyle` | — | Стиль для ВСЕХ колонок (заполняет пустоты рамками) |
|
||
| `cells` | `[]` | Массив ячеек |
|
||
| `empty` | — | Количество подряд идущих пустых строк (заменяет N отдельных `{}`) |
|
||
|
||
Строка без `cells` и `rowStyle` → пустая строка. `{ "empty": 3 }` эквивалентно трём `{}`.
|
||
|
||
### Короткая форма: строка массивом
|
||
|
||
Вместо объекта строка может быть массивом ячеек — позиция определяется порядком, `col` не указывается.
|
||
|
||
| Элемент | Значение |
|
||
|---------|----------|
|
||
| `"текст"` | Статический текст (`text`) |
|
||
| `"{Имя}"` | Параметр (`param`) |
|
||
| `">"` | Продолжение ячейки слева — увеличивает её `span` |
|
||
| `"|"` | Продолжение ячейки сверху — увеличивает её `rowspan` |
|
||
| `null` | Пустая колонка: позиция занята, ячейка не создаётся |
|
||
| `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` |
|
||
|
||
```json
|
||
"rows": [
|
||
["Вид", "Остаток", ">", "Итог"],
|
||
["|", "начало", "конец", "|"],
|
||
["{Вид}", "{Нач}", "{Кон}", "{Итог}"]
|
||
]
|
||
```
|
||
Здесь «Вид» и «Итог» объединены по вертикали на две строки, «Остаток» — по горизонтали на две колонки.
|
||
|
||
Ограничения короткой формы:
|
||
- не задать `height` и `rowStyle` — это свойства строки, а не ячейки;
|
||
- не выразить текст, совпадающий с `">"`, `"|"` или с шаблоном `"{...}"`;
|
||
- `"|"` продолжает ячейку из предыдущей строки, только если её позиция известна явно (`col` задан или строка записана массивом).
|
||
|
||
`">"` без ячейки слева, `"|"` без ячейки сверху, объектный элемент с `col`, элементов больше `columns` → ненулевой код выхода и сообщение в stderr.
|
||
|
||
## Ячейки (`cells[]`)
|
||
|
||
| Поле | Обяз. | По умолч. | Описание |
|
||
|------|:-----:|-----------|----------|
|
||
| `col` | да | — | Позиция колонки (1-based). В короткой форме строки не указывается — позиция берётся из порядка |
|
||
| `span` | нет | `1` | Объединение по горизонтали (количество колонок) |
|
||
| `rowspan` | нет | `1` | Объединение по вертикали (количество строк) |
|
||
| `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) |
|
||
| `param` | нет | — | Параметр заполнения |
|
||
| `detail` | нет | — | Параметр расшифровки (только с `param`) |
|
||
| `text` | нет | — | Статический текст |
|
||
| `template` | нет | — | Шаблонный текст с `[Параметр]` |
|
||
|
||
### Тип заполнения
|
||
|
||
Определяется автоматически по содержимому ячейки:
|
||
- `param` → fillType=Parameter
|
||
- `template` → fillType=Template
|
||
- `text` → fillType=Text
|
||
- ничего → без fillType (пустая ячейка или рамка)
|
||
|
||
## `rowStyle` — автозаполнение
|
||
|
||
Когда задан `rowStyle`, компилятор создаёт ячейки для ВСЕХ колонок строки. Позиции без явных ячеек заполняются пустыми ячейками с указанным стилем. Это обеспечивает сплошные рамки в табличных строках.
|
||
|
||
Если в предыдущих строках той же области есть ячейки с `rowspan`, их колонки при автозаполнении пропускаются.
|
||
|
||
## Ограничения
|
||
|
||
DSL описывает не все конструкции табличного документа. Перечисленное ниже **теряется при
|
||
round-trip** (`/mxl-decompile` → `/mxl-compile`): в JSON оно не попадает, в сгенерированный
|
||
XML не возвращается. Доля — по корпусу типовой ERP 8.3.24 (10 924 макета), где измерялась.
|
||
|
||
| Конструкция | Доля макетов |
|
||
|-------------|--------------|
|
||
| Ячейки-поля ввода (`containsValue` / `valueType` / `controlType`) | 53% |
|
||
| Несколько наборов колонок (`columnsID`) — свои ширины у группы строк | 63% |
|
||
| Объединения, не привязанные к ячейке (по всей высоте или ширине) | 16% |
|
||
| Рисунки и картинки (в т.ч. штрихкоды) | 2% |
|
||
| Цвет текста, цвет фона ячейки, скрытые строки/колонки, отступ | — |
|
||
| Рамка с разным стилем у разных сторон; стили линий кроме сплошной | — |
|
||
| Группировки строк и колонок | — |
|
||
| Колонтитулы, параметры печати, область печати | — |
|
||
|
||
**Многоязычные надписи не поддерживаются:** при разборе берётся первый вариант текста,
|
||
при генерации язык всегда `ru`. Для двуязычных макетов (в ERP это почти весь корпус)
|
||
надписи на остальных языках теряются.
|
||
|
||
Отдельно: пересборка макета из DSL — это полная перегенерация, а не точечная правка XML,
|
||
поэтому diff после round-trip обычно шире фактической доработки.
|