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