From 03de2dc86d3be626900830e4895e9635ae5d5070 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Fri, 3 Jul 2026 15:33:18 +0300 Subject: [PATCH] =?UTF-8?q?feat(meta-compile,meta-decompile):=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=8A=D0=B5=D0=BA=D1=82=D0=BD=D0=B0=D1=8F=20=D1=84=D0=BE?= =?UTF-8?q?=D1=80=D0=BC=D0=B0=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=87=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20=D1=87=D0=B0=D1=81=D1=82=D0=B8=20(=D1=81=D0=B8?= =?UTF-8?q?=D0=BD=D0=BE=D0=BD=D0=B8=D0=BC/=D0=BF=D0=BE=D0=B4=D1=81=D0=BA?= =?UTF-8?q?=D0=B0=D0=B7=D0=BA=D0=B0/=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D1=80=D0=B8=D0=B9=20=D0=A2=D0=A7)=20(v1.23/v0.8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Раундтрип-находка: синоним ТЧ кастомный/мультиязычный у 84% (корпус 1728 ТЧ: multi 1032, custom-ru 417, auto лишь 279), ToolTip у 24% (413). Компилятор хардкодил синоним=Split-CamelCase, Comment/ToolTip пусто. DSL: значение ТЧ — массив колонок (синоним авто) ЛИБО объект {synonym, tooltip, comment, attributes/columns} (по образцу реквизита: shorthand vs object). synonym/tooltip — ML. - meta-compile (дуал-порт): нормализация ТЧ → {columns, synonym, tooltip, comment}; Emit-TabularSection параметризован (synonym через Emit-MLText, Comment/ToolTip из DSL). - meta-decompile: ТЧ → объектная форма при кастомном синониме/подсказке/комментарии, иначе массив. - spec §5. Валидация: PS==PY; TS-категории ~0 (item 4566→6, ToolTip 2188→44); −10067 (89687→79620); регресс 37/37; 1С-cert зелёный. Остаток TabularSection>Synonym (~50) — станд. реквизит LineNumber ТЧ (отдельная категория). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../meta-compile/scripts/meta-compile.ps1 | 32 ++-- .../meta-compile/scripts/meta-compile.py | 30 ++-- .../meta-decompile/scripts/meta-decompile.ps1 | 20 ++- docs/meta-dsl-spec.md | 14 +- .../cases/meta-compile/catalog-tabparts.json | 7 + .../catalog-tabparts/Catalogs/Товары.xml | 146 ++++++++++++++++++ 6 files changed, 220 insertions(+), 29 deletions(-) diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index aaecc5f4..d52c7c2b 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -1078,7 +1078,7 @@ function Emit-Attribute { # --- 9. TabularSection emitter --- function Emit-TabularSection { - param([string]$indent, [string]$tsName, $columns, [string]$objectType, [string]$objectName) + param([string]$indent, [string]$tsName, $columns, [string]$objectType, [string]$objectName, $tsSynonymArg = $null, $tsTooltip = $null, $tsComment = $null) $uuid = New-Guid-String X "$indent" @@ -1097,13 +1097,13 @@ function Emit-TabularSection { X "$indent`t`t" X "$indent`t" - $tsSynonym = Split-CamelCase $tsName + $tsSynonym = if ($null -ne $tsSynonymArg) { $tsSynonymArg } else { Split-CamelCase $tsName } X "$indent`t" X "$indent`t`t$(Esc-Xml $tsName)" Emit-MLText "$indent`t`t" "Synonym" $tsSynonym - X "$indent`t`t" - X "$indent`t`t" + if ($tsComment) { X "$indent`t`t$(Esc-XmlText $tsComment)" } else { X "$indent`t`t" } + Emit-MLText "$indent`t`t" "ToolTip" $tsTooltip X "$indent`t`tDontCheck" Emit-TabularStandardAttributes "$indent`t`t" # Use=ForItem only for Catalog tabular sections (Document does not have Use) @@ -2880,17 +2880,19 @@ if ($objType -in $typesWithAttrTS) { } $tsSections = [ordered]@{} if ($def.tabularSections) { - # Normalize array format: [{name:"X", attributes:[...]}, ...] → {"X": [...]} + # Значение ТЧ: массив колонок (синоним авто) ЛИБО объект {attributes/columns, synonym, tooltip, comment}. + # Нормализуем в $tsSections[name] = @{ columns; synonym; tooltip; comment }. + function New-TsEntry { param($val) + if ($val -is [array] -or $val.GetType().Name -eq 'Object[]') { + return @{ columns = @($val); synonym = $null; tooltip = $null; comment = $null } + } + $cols = if ($val.attributes) { @($val.attributes) } elseif ($val.columns) { @($val.columns) } else { @() } + return @{ columns = $cols; synonym = $val.synonym; tooltip = $val.tooltip; comment = if ($val.comment) { "$($val.comment)" } else { $null } } + } if ($def.tabularSections -is [array] -or $def.tabularSections.GetType().Name -eq "Object[]") { - foreach ($ts in $def.tabularSections) { - $tsName = $ts.name - $tsCols = if ($ts.attributes) { @($ts.attributes) } else { @() } - $tsSections[$tsName] = $tsCols - } + foreach ($ts in $def.tabularSections) { $tsSections[$ts.name] = New-TsEntry $ts } } else { - $def.tabularSections.PSObject.Properties | ForEach-Object { - $tsSections[$_.Name] = @($_.Value) - } + $def.tabularSections.PSObject.Properties | ForEach-Object { $tsSections[$_.Name] = New-TsEntry $_.Value } } } @@ -2923,8 +2925,8 @@ if ($objType -in $typesWithAttrTS) { Emit-Attribute "`t`t`t" $a $context } foreach ($tsName in $tsSections.Keys) { - $columns = $tsSections[$tsName] - Emit-TabularSection "`t`t`t" $tsName $columns $objType $objName + $tsE = $tsSections[$tsName] + Emit-TabularSection "`t`t`t" $tsName $tsE.columns $objType $objName $tsE.synonym $tsE.tooltip $tsE.comment } foreach ($af in $acctFlags) { $afName = if ($af.name) { $af.name } else { "$af" } diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index 6bdb6ad0..651ae312 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -1066,7 +1066,7 @@ def emit_attribute(indent, parsed, context): # 9. TabularSection emitter # --------------------------------------------------------------------------- -def emit_tabular_section(indent, ts_name, columns, object_type, object_name): +def emit_tabular_section(indent, ts_name, columns, object_type, object_name, ts_synonym_arg=None, ts_tooltip=None, ts_comment=None): uid = new_uuid() X(f'{indent}') type_prefix = f'{object_type}TabularSection' @@ -1081,12 +1081,15 @@ def emit_tabular_section(indent, ts_name, columns, object_type, object_name): X(f'{indent}\t\t\t{new_uuid()}') X(f'{indent}\t\t') X(f'{indent}\t') - ts_synonym = split_camel_case(ts_name) + ts_synonym = ts_synonym_arg if ts_synonym_arg is not None else split_camel_case(ts_name) X(f'{indent}\t') X(f'{indent}\t\t{esc_xml(ts_name)}') emit_mltext(f'{indent}\t\t', 'Synonym', ts_synonym) - X(f'{indent}\t\t') - X(f'{indent}\t\t') + if ts_comment: + X(f'{indent}\t\t{esc_xml_text(ts_comment)}') + else: + X(f'{indent}\t\t') + emit_mltext(f'{indent}\t\t', 'ToolTip', ts_tooltip) X(f'{indent}\t\tDontCheck') emit_tabular_standard_attributes(f'{indent}\t\t') if object_type == 'Catalog': @@ -2598,15 +2601,20 @@ if obj_type in types_with_attr_ts: ts_order = [] if defn.get('tabularSections'): ts_data = defn['tabularSections'] + # Значение ТЧ: массив колонок (синоним авто) ЛИБО объект {attributes/columns, synonym, tooltip, comment}. + def new_ts_entry(val): + if isinstance(val, list): + return {'columns': val, 'synonym': None, 'tooltip': None, 'comment': None} + cols = _as_list(val.get('attributes') or val.get('columns') or []) + return {'columns': cols, 'synonym': val.get('synonym'), 'tooltip': val.get('tooltip'), + 'comment': str(val['comment']) if val.get('comment') else None} if isinstance(ts_data, list): for ts in ts_data: - ts_name = ts['name'] - ts_cols = _as_list(ts.get('attributes', [])) - ts_sections[ts_name] = ts_cols - ts_order.append(ts_name) + ts_sections[ts['name']] = new_ts_entry(ts) + ts_order.append(ts['name']) else: for k, v in ts_data.items(): - ts_sections[k] = _as_list(v) + ts_sections[k] = new_ts_entry(v) ts_order.append(k) # ChartOfAccounts: AccountingFlags + ExtDimensionAccountingFlags acct_flags = [] @@ -2637,8 +2645,8 @@ if obj_type in types_with_attr_ts: for a in attrs: emit_attribute('\t\t\t', a, context) for ts_name in ts_order: - columns = ts_sections[ts_name] - emit_tabular_section('\t\t\t', ts_name, columns, obj_type, obj_name) + e = ts_sections[ts_name] + emit_tabular_section('\t\t\t', ts_name, e['columns'], obj_type, obj_name, e['synonym'], e['tooltip'], e['comment']) for af in acct_flags: af_name = af['name'] if isinstance(af, dict) else str(af) emit_accounting_flag('\t\t\t', af_name) diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 index 83d8a92a..af14d17d 100644 --- a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 +++ b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 @@ -1,4 +1,4 @@ -# meta-decompile v0.7 — XML объекта метаданных 1С → JSON-черновик формата meta-compile +# meta-decompile v0.8 — XML объекта метаданных 1С → JSON-черновик формата meta-compile # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # # Пилот: только Catalog. Инверс meta-compile (omit-on-default: ключ эмитим только @@ -325,7 +325,23 @@ if ($childObjs) { $tco = $ts.SelectSingleNode('md:ChildObjects', $nsm) $cols = [System.Collections.ArrayList]@() if ($tco) { foreach ($ca in @($tco.SelectNodes('md:Attribute', $nsm))) { [void]$cols.Add((Attr-ToDsl $ca)) } } - $tsMap[$tsName] = $cols + # Синоним/подсказка/комментарий ТЧ. Кастом → объектная форма {synonym?, tooltip?, comment?, attributes}. + $tsSyn = Get-MLValue ($tsp.SelectSingleNode('md:Synonym', $nsm)) + $tsSynCustom = $false + if ($tsSyn -is [string]) { if ($tsSyn -ne (Split-CamelWords $tsName)) { $tsSynCustom = $true } } + elseif ($null -ne $tsSyn) { $tsSynCustom = $true } + $tsTt = Get-MLValue ($tsp.SelectSingleNode('md:ToolTip', $nsm)) + $tsCmtN = $tsp.SelectSingleNode('md:Comment', $nsm); $tsCmt = if ($tsCmtN) { $tsCmtN.InnerText } else { '' } + if ($tsSynCustom -or ($null -ne $tsTt) -or $tsCmt) { + $to = [ordered]@{} + if ($tsSynCustom) { $to['synonym'] = $tsSyn } + if ($null -ne $tsTt) { $to['tooltip'] = $tsTt } + if ($tsCmt) { $to['comment'] = $tsCmt } + $to['attributes'] = $cols + $tsMap[$tsName] = $to + } else { + $tsMap[$tsName] = $cols + } } $dsl['tabularSections'] = $tsMap } diff --git a/docs/meta-dsl-spec.md b/docs/meta-dsl-spec.md index 0b95aeaf..bad57c67 100644 --- a/docs/meta-dsl-spec.md +++ b/docs/meta-dsl-spec.md @@ -213,7 +213,19 @@ JSON DSL для описания объектов метаданных конф } ``` -Ключ — имя табличной части, значение — массив реквизитов (в строковой или объектной форме). +Ключ — имя табличной части, значение — **массив реквизитов** (в строковой или объектной форме; синоним ТЧ авто из имени) ЛИБО **объект** с собственными свойствами ТЧ: + +```json +"tabularSections": { + "Представления": { + "synonym": { "ru": "Представления", "en": "Presentations" }, + "tooltip": "Локализованные представления", + "attributes": [ "КодЯзыка: String(10) | index", "Наименование: String(150)" ] + } +} +``` + +Свойства объектной формы ТЧ: `synonym` (ML; нет ключа → авто из имени), `tooltip` (ML), `comment` (строка), `attributes` (колонки; синоним `columns`). Для Catalog добавляется `ForItem` в Properties табличной части. Для Document Use не применяется. diff --git a/tests/skills/cases/meta-compile/catalog-tabparts.json b/tests/skills/cases/meta-compile/catalog-tabparts.json index 2a9735e5..c0e242c8 100644 --- a/tests/skills/cases/meta-compile/catalog-tabparts.json +++ b/tests/skills/cases/meta-compile/catalog-tabparts.json @@ -12,6 +12,13 @@ "attributes": [ { "name": "Штрихкод", "type": "String", "length": 128 } ] + }, + { + "name": "Характеристики", + "synonym": { "ru": "Характеристики", "en": "Features" }, + "tooltip": "Дополнительные характеристики товара", + "comment": "ТЧ характеристик", + "attributes": [ "Свойство: String(100)", "Значение: String(200)" ] } ] }, diff --git a/tests/skills/cases/meta-compile/snapshots/catalog-tabparts/Catalogs/Товары.xml b/tests/skills/cases/meta-compile/snapshots/catalog-tabparts/Catalogs/Товары.xml index 08077bbb..37cfd19e 100644 --- a/tests/skills/cases/meta-compile/snapshots/catalog-tabparts/Catalogs/Товары.xml +++ b/tests/skills/cases/meta-compile/snapshots/catalog-tabparts/Catalogs/Товары.xml @@ -227,6 +227,152 @@ + + + + UUID-020 + UUID-021 + + + UUID-022 + UUID-023 + + + + Характеристики + + + ru + Характеристики + + + en + Features + + + ТЧ характеристик + + + ru + Дополнительные характеристики товара + + + DontCheck + + + + DontCheck + false + false + Auto + + + false + + + Auto + Auto + + false + Use + false + + + + Use + + + + + + + ForItem + + + + + Свойство + + + ru + Свойство + + + + + xs:string + + 100 + Variable + + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + DontIndex + Use + Use + + + + + Значение + + + ru + Значение + + + + + xs:string + + 200 + Variable + + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + DontIndex + Use + Use + + + +