mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-13 22:35:16 +03:00
fix(meta-compile,meta-decompile): Characteristics edge-кейсы filterValue/-1/0 (v1.26/v0.17)
Досверка на всех 212 объектах корпуса вскрыла 3 недочёта первой версии
(category-objects по «Characteristics» их не ловил — листы отдельные owner'ы):
• TypesFilterValue: в корпусе доминирует xs:string с ГОЛЫМ именем (315),
а не DesignTimeRef с полным путём (62); +2 xs:boolean. Захардкоженный DTR
ломал 315. Теперь через Normalize-ChoiceValue: голое→xs:string, полный
путь→DTR, bool→xs:boolean, null→xsi:nil.
• «Пустая» характеристика: поля = -1 → эмитим -1 verbatim (не разворачиваем).
• DataPathField/MultipleValues* не всегда -1 (иногда 0) → опциональные ключи
dataPathField/multipleValues*Field, дефолт -1.
remaining ВСЕХ листовых категорий Characteristics = 0 на 212 объектах (match
4→22). Кейс покрывает обе формы filterValue. Регресс 44/44 ps1+py, ps1↔py
identical. spec §7.1.4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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<xr:Characteristic>"
|
||||
X "$indent`t`t<xr:CharacteristicTypes from=`"$(Esc-Xml $tFrom)`">"
|
||||
X "$indent`t`t`t<xr:KeyField>$(Esc-Xml $key)</xr:KeyField>"
|
||||
X "$indent`t`t`t<xr:TypesFilterField>$(Esc-Xml $tff)</xr:TypesFilterField>"
|
||||
X "$indent`t`t`t<xr:TypesFilterValue xsi:type=`"xr:DesignTimeRef`">$(Esc-Xml $tfv)</xr:TypesFilterValue>"
|
||||
X "$indent`t`t`t<xr:DataPathField>-1</xr:DataPathField>"
|
||||
X "$indent`t`t`t<xr:MultipleValuesUseField>-1</xr:MultipleValuesUseField>"
|
||||
# filterValue: $null→nil; голое→xs:string, полный путь→DTR, bool→xs:boolean.
|
||||
$tfvRaw = Get-ChElProp $types @('filterValue','typesFilterValue')
|
||||
if ($null -eq $tfvRaw) { X "$indent`t`t`t<xr:TypesFilterValue xsi:nil=`"true`"/>" }
|
||||
else {
|
||||
$tfvN = Normalize-ChoiceValue $tfvRaw
|
||||
if ([string]::IsNullOrEmpty($tfvN.Text)) { X "$indent`t`t`t<xr:TypesFilterValue xsi:type=`"$($tfvN.XsiType)`"/>" }
|
||||
else { X "$indent`t`t`t<xr:TypesFilterValue xsi:type=`"$($tfvN.XsiType)`">$(Esc-Xml $tfvN.Text)</xr:TypesFilterValue>" }
|
||||
}
|
||||
X "$indent`t`t`t<xr:DataPathField>$dpf</xr:DataPathField>"
|
||||
X "$indent`t`t`t<xr:MultipleValuesUseField>$mvu</xr:MultipleValuesUseField>"
|
||||
X "$indent`t`t</xr:CharacteristicTypes>"
|
||||
X "$indent`t`t<xr:CharacteristicValues from=`"$(Esc-Xml $vFrom)`">"
|
||||
X "$indent`t`t`t<xr:ObjectField>$(Esc-Xml $obj)</xr:ObjectField>"
|
||||
X "$indent`t`t`t<xr:TypeField>$(Esc-Xml $typ)</xr:TypeField>"
|
||||
X "$indent`t`t`t<xr:ValueField>$(Esc-Xml $val)</xr:ValueField>"
|
||||
X "$indent`t`t`t<xr:MultipleValuesKeyField>-1</xr:MultipleValuesKeyField>"
|
||||
X "$indent`t`t`t<xr:MultipleValuesOrderField>-1</xr:MultipleValuesOrderField>"
|
||||
X "$indent`t`t`t<xr:MultipleValuesKeyField>$mvk</xr:MultipleValuesKeyField>"
|
||||
X "$indent`t`t`t<xr:MultipleValuesOrderField>$mvo</xr:MultipleValuesOrderField>"
|
||||
X "$indent`t`t</xr:CharacteristicValues>"
|
||||
X "$indent`t</xr:Characteristic>"
|
||||
}
|
||||
|
||||
@@ -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}<Characteristics/>')
|
||||
@@ -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<xr:Characteristic>')
|
||||
X(f'{indent}\t\t<xr:CharacteristicTypes from="{esc_xml(t_from)}">')
|
||||
X(f'{indent}\t\t\t<xr:KeyField>{esc_xml(key)}</xr:KeyField>')
|
||||
X(f'{indent}\t\t\t<xr:TypesFilterField>{esc_xml(tff)}</xr:TypesFilterField>')
|
||||
X(f'{indent}\t\t\t<xr:TypesFilterValue xsi:type="xr:DesignTimeRef">{esc_xml(tfv)}</xr:TypesFilterValue>')
|
||||
X(f'{indent}\t\t\t<xr:DataPathField>-1</xr:DataPathField>')
|
||||
X(f'{indent}\t\t\t<xr:MultipleValuesUseField>-1</xr:MultipleValuesUseField>')
|
||||
# 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<xr:TypesFilterValue xsi:nil="true"/>')
|
||||
else:
|
||||
tfv_xt, tfv_tx = normalize_choice_value(tfv_raw)
|
||||
if tfv_tx == '' or tfv_tx is None:
|
||||
X(f'{indent}\t\t\t<xr:TypesFilterValue xsi:type="{tfv_xt}"/>')
|
||||
else:
|
||||
X(f'{indent}\t\t\t<xr:TypesFilterValue xsi:type="{tfv_xt}">{esc_xml(tfv_tx)}</xr:TypesFilterValue>')
|
||||
X(f'{indent}\t\t\t<xr:DataPathField>{dpf}</xr:DataPathField>')
|
||||
X(f'{indent}\t\t\t<xr:MultipleValuesUseField>{mvu}</xr:MultipleValuesUseField>')
|
||||
X(f'{indent}\t\t</xr:CharacteristicTypes>')
|
||||
X(f'{indent}\t\t<xr:CharacteristicValues from="{esc_xml(v_from)}">')
|
||||
X(f'{indent}\t\t\t<xr:ObjectField>{esc_xml(obj)}</xr:ObjectField>')
|
||||
X(f'{indent}\t\t\t<xr:TypeField>{esc_xml(typ)}</xr:TypeField>')
|
||||
X(f'{indent}\t\t\t<xr:ValueField>{esc_xml(val)}</xr:ValueField>')
|
||||
X(f'{indent}\t\t\t<xr:MultipleValuesKeyField>-1</xr:MultipleValuesKeyField>')
|
||||
X(f'{indent}\t\t\t<xr:MultipleValuesOrderField>-1</xr:MultipleValuesOrderField>')
|
||||
X(f'{indent}\t\t\t<xr:MultipleValuesKeyField>{mvk}</xr:MultipleValuesKeyField>')
|
||||
X(f'{indent}\t\t\t<xr:MultipleValuesOrderField>{mvo}</xr:MultipleValuesOrderField>')
|
||||
X(f'{indent}\t\t</xr:CharacteristicValues>')
|
||||
X(f'{indent}\t</xr:Characteristic>')
|
||||
X(f'{indent}</Characteristics>')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -473,8 +473,11 @@ JSON DSL для описания объектов метаданных конф
|
||||
голое имя → `StandardAttribute.<EN>` для ссылочных станд. (`Ссылка`/`Родитель`/`Владелец`, 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`.
|
||||
|
||||
|
||||
@@ -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.ДополнительныеСведения",
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@
|
||||
<xr:CharacteristicTypes from="Catalog.НаборыДопРеквИСвед.TabularSection.ДополнительныеСведения">
|
||||
<xr:KeyField>Catalog.НаборыДопРеквИСвед.TabularSection.ДополнительныеСведения.Attribute.Свойство</xr:KeyField>
|
||||
<xr:TypesFilterField>Catalog.НаборыДопРеквИСвед.TabularSection.ДополнительныеСведения.StandardAttribute.Ref</xr:TypesFilterField>
|
||||
<xr:TypesFilterValue xsi:type="xr:DesignTimeRef">Catalog.НаборыДопРеквИСвед.Справочник_Организации</xr:TypesFilterValue>
|
||||
<xr:TypesFilterValue xsi:type="xs:string">Справочник_Организации</xr:TypesFilterValue>
|
||||
<xr:DataPathField>-1</xr:DataPathField>
|
||||
<xr:MultipleValuesUseField>-1</xr:MultipleValuesUseField>
|
||||
</xr:CharacteristicTypes>
|
||||
|
||||
Reference in New Issue
Block a user