diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index 7bbc9f47..021bfa9d 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -1,4 +1,4 @@ -# meta-compile v1.25 — Compile 1C metadata object from JSON +# meta-compile v1.26 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -1377,6 +1377,7 @@ function Expand-CharField { param([string]$field, [string]$from) $s = "$field" if (-not $s) { return $s } + if ($s -eq '-1') { return '-1' } # поле не задано (empty-характеристика) — как есть if ($s -match '^(StandardAttribute|Attribute|Dimension|Resource)\.') { return "$from.$s" } if (-not $s.Contains('.')) { $en = Resolve-CharStdEn $s @@ -1386,15 +1387,8 @@ function Expand-CharField { return $s } -# filterValue: голый предопределённый → префикс каталога (2 сегмента) из typesFrom; полный путь → verbatim. -function Expand-CharFilterValue { - param([string]$fv, [string]$typesFrom) - $s = "$fv" - if (-not $s -or $s.Contains('.')) { return $s } - $tp = @("$typesFrom" -split '\.') - if ($tp.Count -ge 2) { return "$($tp[0]).$($tp[1]).$s" } - return $s -} +# Числовое поле-флаг Characteristics (DataPathField/MultipleValues*) — дефолт -1. +function Get-CharIntField { param($obj, [string[]]$names) $v = Get-ChElProp $obj $names; if ($null -eq $v -or "$v" -eq '') { return -1 } return [int]$v } function Emit-Characteristics { param([string]$indent, $chars) @@ -1407,24 +1401,35 @@ function Emit-Characteristics { $vFrom = Normalize-CharFrom "$(Get-ChElProp $values @('from','source','источник'))" $key = Expand-CharField "$(Get-ChElProp $types @('key','keyField'))" $tFrom $tff = Expand-CharField "$(Get-ChElProp $types @('filterField','typesFilterField'))" $tFrom - $tfv = Expand-CharFilterValue "$(Get-ChElProp $types @('filterValue','typesFilterValue'))" $tFrom $obj = Expand-CharField "$(Get-ChElProp $values @('object','objectField'))" $vFrom $typ = Expand-CharField "$(Get-ChElProp $values @('type','typeField'))" $vFrom $val = Expand-CharField "$(Get-ChElProp $values @('value','valueField'))" $vFrom + # числовые поля-флаги (обычно -1; иногда 0) + $dpf = Get-CharIntField $types @('dataPathField') + $mvu = Get-CharIntField $types @('multipleValuesUseField') + $mvk = Get-CharIntField $values @('multipleValuesKeyField') + $mvo = Get-CharIntField $values @('multipleValuesOrderField') X "$indent`t" X "$indent`t`t" X "$indent`t`t`t$(Esc-Xml $key)" X "$indent`t`t`t$(Esc-Xml $tff)" - X "$indent`t`t`t$(Esc-Xml $tfv)" - X "$indent`t`t`t-1" - X "$indent`t`t`t-1" + # filterValue: $null→nil; голое→xs:string, полный путь→DTR, bool→xs:boolean. + $tfvRaw = Get-ChElProp $types @('filterValue','typesFilterValue') + if ($null -eq $tfvRaw) { X "$indent`t`t`t" } + else { + $tfvN = Normalize-ChoiceValue $tfvRaw + if ([string]::IsNullOrEmpty($tfvN.Text)) { X "$indent`t`t`t" } + else { X "$indent`t`t`t$(Esc-Xml $tfvN.Text)" } + } + X "$indent`t`t`t$dpf" + X "$indent`t`t`t$mvu" X "$indent`t`t" X "$indent`t`t" X "$indent`t`t`t$(Esc-Xml $obj)" X "$indent`t`t`t$(Esc-Xml $typ)" X "$indent`t`t`t$(Esc-Xml $val)" - X "$indent`t`t`t-1" - X "$indent`t`t`t-1" + X "$indent`t`t`t$mvk" + X "$indent`t`t`t$mvo" X "$indent`t`t" X "$indent`t" } diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index 7960fe1f..2dd773ef 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# meta-compile v1.25 — Compile 1C metadata object from JSON +# meta-compile v1.26 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -1425,10 +1425,18 @@ def resolve_char_std_en(name): return 'Owner' return None +def char_int_field(obj, names): + v = ch_el_prop(obj, names) + if v is None or str(v) == '': + return -1 + return int(v) + def expand_char_field(field, from_): s = str(field or '') if not s: return s + if s == '-1': + return '-1' # поле не задано (empty-характеристика) if re.match(r'^(StandardAttribute|Attribute|Dimension|Resource)\.', s): return f'{from_}.{s}' if '.' not in s: @@ -1438,15 +1446,6 @@ def expand_char_field(field, from_): return f'{from_}.Attribute.{s}' return s -def expand_char_filter_value(fv, types_from): - s = str(fv or '') - if not s or '.' in s: - return s - tp = str(types_from).split('.') - if len(tp) >= 2: - return f'{tp[0]}.{tp[1]}.{s}' - return s - def emit_characteristics(indent, chars): if not chars: X(f'{indent}') @@ -1459,24 +1458,36 @@ def emit_characteristics(indent, chars): v_from = normalize_char_from(ch_el_prop(values, ['from', 'source', 'источник']) or '') key = expand_char_field(ch_el_prop(types, ['key', 'keyField']), t_from) tff = expand_char_field(ch_el_prop(types, ['filterField', 'typesFilterField']), t_from) - tfv = expand_char_filter_value(ch_el_prop(types, ['filterValue', 'typesFilterValue']), t_from) obj = expand_char_field(ch_el_prop(values, ['object', 'objectField']), v_from) typ = expand_char_field(ch_el_prop(values, ['type', 'typeField']), v_from) val = expand_char_field(ch_el_prop(values, ['value', 'valueField']), v_from) + dpf = char_int_field(types, ['dataPathField']) + mvu = char_int_field(types, ['multipleValuesUseField']) + mvk = char_int_field(values, ['multipleValuesKeyField']) + mvo = char_int_field(values, ['multipleValuesOrderField']) X(f'{indent}\t') X(f'{indent}\t\t') X(f'{indent}\t\t\t{esc_xml(key)}') X(f'{indent}\t\t\t{esc_xml(tff)}') - X(f'{indent}\t\t\t{esc_xml(tfv)}') - X(f'{indent}\t\t\t-1') - X(f'{indent}\t\t\t-1') + # filterValue: None→nil; голое→xs:string, полный путь→DTR, bool→xs:boolean. + tfv_raw = ch_el_prop(types, ['filterValue', 'typesFilterValue']) + if tfv_raw is None: + X(f'{indent}\t\t\t') + else: + tfv_xt, tfv_tx = normalize_choice_value(tfv_raw) + if tfv_tx == '' or tfv_tx is None: + X(f'{indent}\t\t\t') + else: + X(f'{indent}\t\t\t{esc_xml(tfv_tx)}') + X(f'{indent}\t\t\t{dpf}') + X(f'{indent}\t\t\t{mvu}') X(f'{indent}\t\t') X(f'{indent}\t\t') X(f'{indent}\t\t\t{esc_xml(obj)}') X(f'{indent}\t\t\t{esc_xml(typ)}') X(f'{indent}\t\t\t{esc_xml(val)}') - X(f'{indent}\t\t\t-1') - X(f'{indent}\t\t\t-1') + X(f'{indent}\t\t\t{mvk}') + X(f'{indent}\t\t\t{mvo}') X(f'{indent}\t\t') X(f'{indent}\t') X(f'{indent}') diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 index be24eaf2..dcfceaf7 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.16 — XML объекта метаданных 1С → JSON-черновик формата meta-compile +# meta-decompile v0.17 — XML объекта метаданных 1С → JSON-черновик формата meta-compile # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # # Пилот: только Catalog. Инверс meta-compile (omit-on-default: ключ эмитим только @@ -421,14 +421,6 @@ function Shorten-CharField { param([string]$full, [string]$from) } return $full } -function Shorten-CharFilterValue { param([string]$full, [string]$typesFrom) - $tp = @("$typesFrom" -split '\.') - if ($tp.Count -ge 2) { - $pref = "$($tp[0]).$($tp[1])." - if ($full.StartsWith($pref)) { $tail = $full.Substring($pref.Length); if (-not $tail.Contains('.')) { return $tail } } - } - return $full -} $charsNode = $props.SelectSingleNode('md:Characteristics', $nsm) if ($charsNode) { $chList = @($charsNode.SelectNodes('xr:Characteristic', $nsm)) @@ -439,18 +431,25 @@ if ($charsNode) { $cv = $ch.SelectSingleNode('xr:CharacteristicValues', $nsm) $tFrom = $ct.GetAttribute('from'); $vFrom = $cv.GetAttribute('from') $gt = { param($n, $node) $x = $node.SelectSingleNode("xr:$n", $nsm); if ($x) { $x.InnerText } else { "" } } + $giv = { param($n, $node) $x = $node.SelectSingleNode("xr:$n", $nsm); if ($x -and $x.InnerText -ne '') { [int]$x.InnerText } else { -1 } } + $tfvNode = $ct.SelectSingleNode('xr:TypesFilterValue', $nsm) + $tfvNil = if ($tfvNode) { $tfvNode.GetAttribute('nil', 'http://www.w3.org/2001/XMLSchema-instance') } else { '' } $types = [ordered]@{ from = $tFrom key = Shorten-CharField (& $gt 'KeyField' $ct) $tFrom filterField = Shorten-CharField (& $gt 'TypesFilterField' $ct) $tFrom - filterValue = Shorten-CharFilterValue (& $gt 'TypesFilterValue' $ct) $tFrom + filterValue = if ($tfvNil -eq 'true') { $null } else { Convert-ChScalarNode $tfvNode } } + $dpf = & $giv 'DataPathField' $ct; if ($dpf -ne -1) { $types['dataPathField'] = $dpf } + $mvu = & $giv 'MultipleValuesUseField' $ct; if ($mvu -ne -1) { $types['multipleValuesUseField'] = $mvu } $values = [ordered]@{ from = $vFrom object = Shorten-CharField (& $gt 'ObjectField' $cv) $vFrom type = Shorten-CharField (& $gt 'TypeField' $cv) $vFrom value = Shorten-CharField (& $gt 'ValueField' $cv) $vFrom } + $mvk = & $giv 'MultipleValuesKeyField' $cv; if ($mvk -ne -1) { $values['multipleValuesKeyField'] = $mvk } + $mvo = & $giv 'MultipleValuesOrderField' $cv; if ($mvo -ne -1) { $values['multipleValuesOrderField'] = $mvo } [void]$chArr.Add([ordered]@{ types = $types; values = $values }) } $dsl['characteristics'] = $chArr diff --git a/docs/meta-dsl-spec.md b/docs/meta-dsl-spec.md index 79e183a0..df65e940 100644 --- a/docs/meta-dsl-spec.md +++ b/docs/meta-dsl-spec.md @@ -473,8 +473,11 @@ JSON DSL для описания объектов метаданных конф голое имя → `StandardAttribute.` для ссылочных станд. (`Ссылка`/`Родитель`/`Владелец`, RU→EN), иначе → `Attribute.<имя>`; частичное `Dimension.X`/`Resource.X`/`StandardAttribute.X` → + префикс `from` (форма для регистров ДопСведения); полный путь → как есть. -- **`filterValue`** — предопределённое значение фильтра типов (`xr:DesignTimeRef`); голое имя → + префикс каталога - из `types.from`; полный путь → как есть. +- **`filterValue`** — значение фильтра типов (обычно предопределённый набор): голое имя → `xs:string` (частый случай, + напр. `Справочник_Организации`); полный путь → `xr:DesignTimeRef` (`Catalog.X.Справочник_Y`); bool → `xs:boolean`; + `null` → `xsi:nil` (пустая характеристика). Различает вид по наличию точки. +- **Числовые флаги** `dataPathField`/`multipleValuesUseField` (в `types`), `multipleValuesKeyField`/ + `multipleValuesOrderField` (в `values`) — по умолчанию `-1`, задавать не нужно (кроме редких `0`). - **Синонимы ключей:** `types`/`characteristicTypes`, `values`/`characteristicValues`, `key`/`keyField`, `filterField`/`typesFilterField`, `filterValue`/`typesFilterValue`, `object`/`objectField`, `type`/`typeField`, `value`/`valueField`. diff --git a/tests/skills/cases/meta-compile/catalog-characteristics.json b/tests/skills/cases/meta-compile/catalog-characteristics.json index 55786202..289b6d4d 100644 --- a/tests/skills/cases/meta-compile/catalog-characteristics.json +++ b/tests/skills/cases/meta-compile/catalog-characteristics.json @@ -5,7 +5,7 @@ "name": "Организации", "characteristics": [ { "types": { "from": "Справочник.НаборыДопРеквИСвед.ДополнительныеРеквизиты", - "key": "Свойство", "filterField": "Ссылка", "filterValue": "Справочник_Организации" }, + "key": "Свойство", "filterField": "Ссылка", "filterValue": "Catalog.НаборыДопРеквИСвед.Справочник_Организации" }, "values": { "from": "Catalog.Организации.TabularSection.ДополнительныеРеквизиты", "object": "Ссылка", "type": "Свойство", "value": "Значение" } }, { "types": { "from": "Catalog.НаборыДопРеквИСвед.TabularSection.ДополнительныеСведения", diff --git a/tests/skills/cases/meta-compile/snapshots/catalog-characteristics/Catalogs/Организации.xml b/tests/skills/cases/meta-compile/snapshots/catalog-characteristics/Catalogs/Организации.xml index 3c222e05..695ba52f 100644 --- a/tests/skills/cases/meta-compile/snapshots/catalog-characteristics/Catalogs/Организации.xml +++ b/tests/skills/cases/meta-compile/snapshots/catalog-characteristics/Catalogs/Организации.xml @@ -69,7 +69,7 @@ Catalog.НаборыДопРеквИСвед.TabularSection.ДополнительныеСведения.Attribute.Свойство Catalog.НаборыДопРеквИСвед.TabularSection.ДополнительныеСведения.StandardAttribute.Ref - Catalog.НаборыДопРеквИСвед.Справочник_Организации + Справочник_Организации -1 -1