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 | Сортировка списка (см. ниже) |