diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1
index 97978a58..19368529 100644
--- a/.claude/skills/form-compile/scripts/form-compile.ps1
+++ b/.claude/skills/form-compile/scripts/form-compile.ps1
@@ -1,4 +1,4 @@
-# form-compile v1.170 — Compile 1C managed form from JSON or object metadata
+# form-compile v1.171 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$JsonPath,
@@ -5327,6 +5327,13 @@ function Emit-DLInputParameters {
}
X "$indent`t`t"
}
+ } elseif (Has-DLProp $item 'typeLink') {
+ # Связь по типу (dcscor:TypeLink) — field + linkItem (структурное значение параметра).
+ $tl = $item.typeLink
+ X "$indent`t`t"
+ $tlf = Get-Prop $tl 'field'; if ($null -ne $tlf) { X "$indent`t`t`t$(Esc-Xml "$tlf")" }
+ $tli = Get-Prop $tl 'linkItem'; if ($null -ne $tli) { X "$indent`t`t`t$(Esc-Xml "$tli")" }
+ X "$indent`t`t"
} elseif (Has-DLProp $item 'value') {
$val = $item.value
if ($val -is [bool]) { X "$indent`t`t$(if ($val) { 'true' } else { 'false' })" }
@@ -5762,11 +5769,16 @@ function Emit-Attributes {
foreach ($fld in $st.fields) {
# Тип поля набора: DataSetFieldField (дефолт) vs DataSetFieldNestedDataSet
# (поле-вложенный набор = реквизит табличной части; маркер nested).
- $ftype = if ($fld.nested) { "DataSetFieldNestedDataSet" } else { "DataSetFieldField" }
+ # folder = папка-группировка полей (DataSetFieldFolder, без ); nested = вложенный набор.
+ $isFolder = [bool](Get-Prop $fld 'folder')
+ $ftype = if ($fld.nested) { "DataSetFieldNestedDataSet" } elseif ($isFolder) { "DataSetFieldFolder" } else { "DataSetFieldField" }
X "$si"
- $dp = if ($fld.dataPath) { $fld.dataPath } else { $fld.field }
- X "$si`t$(Esc-Xml "$dp")"
- X "$si`t$(Esc-Xml "$($fld.field)")"
+ # dataPath: явный (включая пустой "" → self-closing ) побеждает; иначе fallback на field.
+ if ($null -ne (Get-Prop $fld 'dataPath')) { $dp = "$($fld.dataPath)" }
+ elseif ($isFolder) { $dp = "" }
+ else { $dp = "$($fld.field)" }
+ if ($dp -eq "") { X "$si`t" } else { X "$si`t$(Esc-Xml "$dp")" }
+ if (-not $isFolder) { X "$si`t$(Esc-Xml "$($fld.field)")" }
if ($fld.title) {
X "$si`t"
Emit-MLItems -val $fld.title -indent "$si`t`t"
diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py
index ef2d36d8..af439151 100644
--- a/.claude/skills/form-compile/scripts/form-compile.py
+++ b/.claude/skills/form-compile/scripts/form-compile.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# form-compile v1.170 — Compile 1C managed form from JSON or object metadata
+# form-compile v1.171 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import copy
@@ -5074,6 +5074,15 @@ def emit_dl_input_parameters(lines, ip, indent):
lines.append(f'{indent}\t\t\t\t{mode}')
lines.append(f'{indent}\t\t\t')
lines.append(f'{indent}\t\t')
+ elif 'typeLink' in item:
+ # Связь по типу (dcscor:TypeLink) — field + linkItem (структурное значение параметра).
+ tl = item.get('typeLink') or {}
+ lines.append(f'{indent}\t\t')
+ if tl.get('field') is not None:
+ lines.append(f'{indent}\t\t\t{esc_xml(str(tl.get("field")))}')
+ if tl.get('linkItem') is not None:
+ lines.append(f'{indent}\t\t\t{esc_xml(str(tl.get("linkItem")))}')
+ lines.append(f'{indent}\t\t')
elif 'value' in item:
val = item.get('value')
if isinstance(val, bool):
@@ -5526,11 +5535,23 @@ def emit_attributes(lines, attrs, indent, conditional_appearance=None):
for fld in s['fields']:
# Тип поля набора: DataSetFieldField (дефолт) vs DataSetFieldNestedDataSet
# (поле-вложенный набор = реквизит табличной части; маркер nested).
- ftype = 'DataSetFieldNestedDataSet' if fld.get('nested') else 'DataSetFieldField'
+ # folder = папка-группировка полей (DataSetFieldFolder, без ); nested = вложенный набор.
+ is_folder = bool(fld.get('folder'))
+ ftype = 'DataSetFieldNestedDataSet' if fld.get('nested') else ('DataSetFieldFolder' if is_folder else 'DataSetFieldField')
lines.append(f'{si}')
- dp = fld.get('dataPath') or fld.get('field')
- lines.append(f'{si}\t{esc_xml(str(dp))}')
- lines.append(f'{si}\t{esc_xml(str(fld.get("field", "")))}')
+ # dataPath: явный (включая "" → self-closing) побеждает; иначе fallback на field.
+ if fld.get('dataPath') is not None:
+ dp = str(fld.get('dataPath'))
+ elif is_folder:
+ dp = ''
+ else:
+ dp = str(fld.get('field', ''))
+ if dp == '':
+ lines.append(f'{si}\t')
+ else:
+ lines.append(f'{si}\t{esc_xml(dp)}')
+ if not is_folder:
+ lines.append(f'{si}\t{esc_xml(str(fld.get("field", "")))}')
if fld.get('title'):
lines.append(f'{si}\t')
emit_ml_items(lines, f'{si}\t\t', fld['title'])
diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1
index 1ebdea54..e33cfc4e 100644
--- a/.claude/skills/form-decompile/scripts/form-decompile.ps1
+++ b/.claude/skills/form-decompile/scripts/form-decompile.ps1
@@ -1,4 +1,4 @@
-# form-decompile v0.146 — Decompile 1C managed Form.xml to JSON DSL (draft)
+# form-decompile v0.147 — Decompile 1C managed Form.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
param(
@@ -1423,6 +1423,13 @@ function Build-DLInputParameters {
[void]$cpls.Add($cpo)
}
$io['choiceParameterLinks'] = @($cpls)
+ } elseif ($vt -match 'TypeLink$') {
+ # Связь по типу (dcscor:TypeLink): field + linkItem — структурное значение,
+ # НЕ склеивать InnerText в строку ("СчетДт"+"1"="СчетДт1").
+ $tlo = [ordered]@{}
+ $tlf = Get-Child $valN 'field'; if ($null -ne $tlf) { $tlo['field'] = $tlf }
+ $tli = Get-Child $valN 'linkItem'; if ($null -ne $tli) { $tlo['linkItem'] = if ($tli -match '^-?\d+$') { [int]$tli } else { $tli } }
+ $io['typeLink'] = $tlo
} else {
if ($valN.GetAttribute("nil", $NS_XSI) -ne 'true') { $io['value'] = Convert-TypedValue -raw $valN.InnerText -xsiType $vt }
}
@@ -2798,10 +2805,12 @@ if ($attrsNode) {
$fld = Get-Child $fn 'field'
$dp = Get-Child $fn 'dataPath'
if ($fld) { $fo['field'] = $fld }
- if ($dp -and $dp -ne $fld) { $fo['dataPath'] = $dp }
+ if ((Has-Child $fn 'dataPath') -and $dp -ne $fld) { $fo['dataPath'] = $dp }
# Тип поля набора: DataSetFieldField (дефолт, компилятор хардкодит) vs
# DataSetFieldNestedDataSet (поле-вложенный набор = реквизит табличной части). Маркер nested.
- if ($fn.GetAttribute("type", $NS_XSI) -match 'NestedDataSet$') { $fo['nested'] = $true }
+ $fTypeAttr = $fn.GetAttribute("type", $NS_XSI)
+ if ($fTypeAttr -match 'NestedDataSet$') { $fo['nested'] = $true }
+ elseif ($fTypeAttr -match 'Folder$') { $fo['folder'] = $true }
$ftn = $fn.SelectSingleNode("dcssch:title", $ns)
if ($ftn) { $t = Get-LangText $ftn; if ($null -ne $t) { $fo['title'] = $t } }
# valueType поля набора (тип значения; вычисляемые/кастомные поля). Грамматика типа.
diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md
index 01512824..d531b611 100644
--- a/docs/form-dsl-spec.md
+++ b/docs/form-dsl-spec.md
@@ -950,7 +950,7 @@ Forgiving-синонимы типа: XML-имя (`SpreadSheetDocumentField`) и
| `query` | string | Текст запроса (`ManualQuery=true`). Поддерживает `@file.sql` (путь относительно JSON) |
| `dynamicDataRead` | bool | Динамическое считывание. **Умолчание `true`** — указывать только для отключения (`false`) |
| `autoFillAvailableFields` | bool | Автозаполнение доступных полей (``). **Умолчание `true`** — указывать только для отключения (`false`; тогда поля берутся из явного запроса, не авто). Эмитится первым в `` |
-| `fields` | array | Явные поля набора (редко): `{ field, dataPath?, title?, useRestriction?, attributeUseRestriction?, valueType?, presentationExpression?, appearance?, inputParameters?, nested? }` — для переопределения свойств поля. `useRestriction`/`attributeUseRestriction` — ограничения использования: объект `{ field?, condition?, group?, order? }` (bool) или флаг-строка `"#noField #noFilter #noGroup #noOrder"`. `valueType` — тип значения (грамматика типа). `presentationExpression` — выражение представления поля (строка). `appearance` — оформление/формат поля: объект `{ Параметр: Значение }` (та же грамматика, что `appearance` условного оформления, напр. `{ "Формат": "ДЛ=9", "ЦветТекста": "web:Gray" }`). `inputParameters` — связь по параметрам выбора (как у параметра дин-списка). `nested: true` помечает поле-вложенный набор (`DataSetFieldNestedDataSet` = реквизит табличной части объекта; дефолт — `DataSetFieldField`). Обычно поля выводятся из запроса автоматически |
+| `fields` | array | Явные поля набора (редко): `{ field, dataPath?, title?, useRestriction?, attributeUseRestriction?, valueType?, presentationExpression?, appearance?, inputParameters?, nested?, folder? }` — для переопределения свойств поля. `useRestriction`/`attributeUseRestriction` — ограничения использования: объект `{ field?, condition?, group?, order? }` (bool) или флаг-строка `"#noField #noFilter #noGroup #noOrder"`. `valueType` — тип значения (грамматика типа). `presentationExpression` — выражение представления поля (строка). `appearance` — оформление/формат поля: объект `{ Параметр: Значение }` (та же грамматика, что `appearance` условного оформления, напр. `{ "Формат": "ДЛ=9", "ЦветТекста": "web:Gray" }`). `inputParameters` — связь по параметрам выбора (как у параметра дин-списка); элемент `{ parameter, value? \| choiceParameters? \| choiceParameterLinks? \| typeLink? }`. `typeLink: { field, linkItem }` — связь по типу (`dcscor:TypeLink`, напр. субконто, тип которого определяется счётом): `field` = поле-источник типа, `linkItem` = индекс. `nested: true` помечает поле-вложенный набор (`DataSetFieldNestedDataSet` = реквизит табличной части объекта). `folder: true` помечает поле-папку (`DataSetFieldFolder` = группировка вложенных полей, напр. `СубконтоДт` над `СубконтоДт1/2/3`; без ``). Дефолт — `DataSetFieldField`. Пустой `dataPath: ""` → self-closing `` (поле без пути, только `field`). Обычно поля выводятся из запроса автоматически |
| `calculatedFields` | array | Вычисляемые поля набора (см. ниже) |
| `parameters` | array | Параметры схемы запроса (`DataCompositionSchemaParameter`) — см. ниже |
| `order` | array | Сортировка списка (см. ниже) |