mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-03 02:00:22 +03:00
fix(meta-decompile,meta-compile): пустая ссылка в ChoiceParameters теряла тип
Раундтрип по справочникам УТ 11.5.27 вскрыл: <app:value xsi:type="xr:DesignTimeRef"/>
с пустым содержимым декомпилировался в "value": "", и компилятор законно
эмитил свой дефолт xs:string — тип ссылки терялся.
Конвенция для этого случая уже была (маркер {emptyRef: true} у fillValue),
пробел был только в ChoiceParameters. Декомпилятор теперь ставит маркер,
компилятор его понимает — и в скалярном значении, и внутри FixedArray.
Форма редкая, поэтому прежние кампании её не поймали: в acc она встречается
1 раз, в erp — ни разу, в УТ — 7 раз.
Is-EmptyRef в PS явно отсекает коллекции: у массива $v.emptyRef разворачивается
в свойства элементов (member enumeration), и массив с одним таким элементом
схлопывал FixedArray в скаляр. В py-порте isinstance(v, dict) такого не допускает —
расхождение поймано снэпшотом.
Проверка: справочники УТ 519/519 без расхождений (было 519 diff),
сюита meta-compile 76/76 на обоих портах, 1С-сертификация кейса пройдена.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2067778ba3
commit
75e861da6e
@@ -1,4 +1,4 @@
|
|||||||
# meta-compile v1.69 — Compile 1C metadata object from JSON
|
# meta-compile v1.70 — Compile 1C metadata object from JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -1612,6 +1612,15 @@ function ConvertFrom-ChLinkShorthand {
|
|||||||
|
|
||||||
# <ChoiceParameters> — [{name, value?}]. Значение ПРЯМО на app:value (xsi:type=тип); массив → v8:FixedArray
|
# <ChoiceParameters> — [{name, value?}]. Значение ПРЯМО на app:value (xsi:type=тип); массив → v8:FixedArray
|
||||||
# с детьми v8:Value; без value → app:value nil.
|
# с детьми v8:Value; без value → app:value nil.
|
||||||
|
# Маркер пустой ссылки от декомпилятора: {emptyRef: true}. Работает и на Hashtable, и на PSCustomObject.
|
||||||
|
# Массивы отсекаем ЯВНО: у коллекции `$v.emptyRef` разворачивается в свойства элементов (member
|
||||||
|
# enumeration), и массив с одним таким элементом дал бы -eq $true → FixedArray схлопнулся бы в скаляр.
|
||||||
|
function Is-EmptyRef($v) {
|
||||||
|
if ($null -eq $v -or $v -is [string]) { return $false }
|
||||||
|
if (($v -is [System.Array]) -or ($v -is [System.Collections.IList])) { return $false }
|
||||||
|
return ($v.emptyRef -eq $true)
|
||||||
|
}
|
||||||
|
|
||||||
function Emit-ChoiceParameters {
|
function Emit-ChoiceParameters {
|
||||||
param([string]$indent, $cp, [string]$tag = 'ChoiceParameters')
|
param([string]$indent, $cp, [string]$tag = 'ChoiceParameters')
|
||||||
if (-not $cp -or @($cp).Count -eq 0) { X "$indent<$tag/>"; return }
|
if (-not $cp -or @($cp).Count -eq 0) { X "$indent<$tag/>"; return }
|
||||||
@@ -1632,9 +1641,13 @@ function Emit-ChoiceParameters {
|
|||||||
X "$indent`t<app:item name=`"$(Esc-Xml "$name")`">"
|
X "$indent`t<app:item name=`"$(Esc-Xml "$name")`">"
|
||||||
if (-not $hasVal) {
|
if (-not $hasVal) {
|
||||||
X "$indent`t`t<app:value xsi:nil=`"true`"/>"
|
X "$indent`t`t<app:value xsi:nil=`"true`"/>"
|
||||||
|
} elseif ((Is-EmptyRef $val)) {
|
||||||
|
# Пустая ссылка (маркер декомпилятора emptyRef) — тип обязан остаться DesignTimeRef.
|
||||||
|
X "$indent`t`t<app:value xsi:type=`"xr:DesignTimeRef`"/>"
|
||||||
} elseif ($valIsArray) {
|
} elseif ($valIsArray) {
|
||||||
X "$indent`t`t<app:value xsi:type=`"v8:FixedArray`">"
|
X "$indent`t`t<app:value xsi:type=`"v8:FixedArray`">"
|
||||||
foreach ($v in $val) {
|
foreach ($v in $val) {
|
||||||
|
if (Is-EmptyRef $v) { X "$indent`t`t`t<v8:Value xsi:type=`"xr:DesignTimeRef`"/>"; continue }
|
||||||
$norm = Normalize-ChoiceValueT $v $ptype
|
$norm = Normalize-ChoiceValueT $v $ptype
|
||||||
if ([string]::IsNullOrEmpty($norm.Text)) { X "$indent`t`t`t<v8:Value xsi:type=`"$($norm.XsiType)`"/>" }
|
if ([string]::IsNullOrEmpty($norm.Text)) { X "$indent`t`t`t<v8:Value xsi:type=`"$($norm.XsiType)`"/>" }
|
||||||
else { X "$indent`t`t`t<v8:Value xsi:type=`"$($norm.XsiType)`">$(Esc-Xml $norm.Text)</v8:Value>" }
|
else { X "$indent`t`t`t<v8:Value xsi:type=`"$($norm.XsiType)`">$(Esc-Xml $norm.Text)</v8:Value>" }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# meta-compile v1.69 — Compile 1C metadata object from JSON
|
# meta-compile v1.70 — Compile 1C metadata object from JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -1706,6 +1706,11 @@ def convert_from_ch_link_shorthand(s):
|
|||||||
o['dataPath'] = rest
|
o['dataPath'] = rest
|
||||||
return o
|
return o
|
||||||
|
|
||||||
|
def is_empty_ref(v):
|
||||||
|
"""Маркер пустой ссылки от декомпилятора: {emptyRef: true}."""
|
||||||
|
return isinstance(v, dict) and v.get('emptyRef') is True
|
||||||
|
|
||||||
|
|
||||||
def emit_choice_parameters(indent, cp, tag='ChoiceParameters'):
|
def emit_choice_parameters(indent, cp, tag='ChoiceParameters'):
|
||||||
if not cp:
|
if not cp:
|
||||||
X(f'{indent}<{tag}/>')
|
X(f'{indent}<{tag}/>')
|
||||||
@@ -1724,9 +1729,15 @@ def emit_choice_parameters(indent, cp, tag='ChoiceParameters'):
|
|||||||
X(f'{indent}\t<app:item name="{esc_xml(str(name))}">')
|
X(f'{indent}\t<app:item name="{esc_xml(str(name))}">')
|
||||||
if not has_val:
|
if not has_val:
|
||||||
X(f'{indent}\t\t<app:value xsi:nil="true"/>')
|
X(f'{indent}\t\t<app:value xsi:nil="true"/>')
|
||||||
|
elif is_empty_ref(val):
|
||||||
|
# Пустая ссылка (маркер декомпилятора emptyRef) — тип обязан остаться DesignTimeRef.
|
||||||
|
X(f'{indent}\t\t<app:value xsi:type="xr:DesignTimeRef"/>')
|
||||||
elif val_is_array:
|
elif val_is_array:
|
||||||
X(f'{indent}\t\t<app:value xsi:type="v8:FixedArray">')
|
X(f'{indent}\t\t<app:value xsi:type="v8:FixedArray">')
|
||||||
for v in val:
|
for v in val:
|
||||||
|
if is_empty_ref(v):
|
||||||
|
X(f'{indent}\t\t\t<v8:Value xsi:type="xr:DesignTimeRef"/>')
|
||||||
|
continue
|
||||||
xt, tx = normalize_choice_value_t(v, ptype)
|
xt, tx = normalize_choice_value_t(v, ptype)
|
||||||
if tx == '' or tx is None:
|
if tx == '' or tx is None:
|
||||||
X(f'{indent}\t\t\t<v8:Value xsi:type="{xt}"/>')
|
X(f'{indent}\t\t\t<v8:Value xsi:type="{xt}"/>')
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# meta-decompile v0.55 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
|
# meta-decompile v0.56 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
#
|
#
|
||||||
# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document,
|
# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document,
|
||||||
@@ -226,6 +226,9 @@ function Convert-ChScalarNode {
|
|||||||
if ($txt -match '^-?\d+$') { return [int]$txt }
|
if ($txt -match '^-?\d+$') { return [int]$txt }
|
||||||
return [double]::Parse($txt, [System.Globalization.CultureInfo]::InvariantCulture)
|
return [double]::Parse($txt, [System.Globalization.CultureInfo]::InvariantCulture)
|
||||||
}
|
}
|
||||||
|
# Пустой DesignTimeRef ≠ пустая строка: без маркера тип терялся, и компилятор эмитил xs:string.
|
||||||
|
# Та же конвенция, что у fillValue (см. ниже) — маркер emptyRef.
|
||||||
|
if ($xt -match 'DesignTimeRef$' -and $txt -eq '') { return [ordered]@{ emptyRef = $true } }
|
||||||
return $txt
|
return $txt
|
||||||
}
|
}
|
||||||
# app:value (тип прямо на узле) → значение ЛИБО массив (v8:FixedArray с детьми v8:Value).
|
# app:value (тип прямо на узле) → значение ЛИБО массив (v8:FixedArray с детьми v8:Value).
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# meta-decompile v0.55 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
|
# meta-decompile v0.56 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
#
|
#
|
||||||
# Зеркало meta-decompile.ps1 (КАНОН). Структура 1:1 — те же имена функций, порядок, комментарии.
|
# Зеркало meta-decompile.ps1 (КАНОН). Структура 1:1 — те же имена функций, порядок, комментарии.
|
||||||
@@ -299,6 +299,10 @@ def convert_ch_scalar_node(vN):
|
|||||||
if re.match(r'^-?\d+$', txt):
|
if re.match(r'^-?\d+$', txt):
|
||||||
return int(txt)
|
return int(txt)
|
||||||
return float(txt)
|
return float(txt)
|
||||||
|
# Пустой DesignTimeRef != пустая строка: без маркера тип терялся, и компилятор эмитил xs:string.
|
||||||
|
# Та же конвенция, что у fillValue — маркер emptyRef.
|
||||||
|
if re.search(r'DesignTimeRef$', xt, re.I) and txt == '':
|
||||||
|
return {'emptyRef': True}
|
||||||
return txt
|
return txt
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,11 @@
|
|||||||
{ "name": "ТипТТН", "type": "CatalogRef.ВидыТранспорта",
|
{ "name": "ТипТТН", "type": "CatalogRef.ВидыТранспорта",
|
||||||
"choiceParameters": [ { "name": "Отбор.Тип", "type": "EnumRef.ТипыВЕТИС", "value": ["EmptyRef", "ТТН"] } ] },
|
"choiceParameters": [ { "name": "Отбор.Тип", "type": "EnumRef.ТипыВЕТИС", "value": ["EmptyRef", "ТТН"] } ] },
|
||||||
{ "name": "Валюта", "type": "CatalogRef.Валюты",
|
{ "name": "Валюта", "type": "CatalogRef.Валюты",
|
||||||
"choiceParameterLinks": "Отбор.Владелец=Ссылка" }
|
"choiceParameterLinks": "Отбор.Владелец=Ссылка" },
|
||||||
|
{ "name": "ПустаяСсылка", "type": "String(10)",
|
||||||
|
"choiceParameters": [ { "name": "Отбор.ТипПоказателя", "value": { "emptyRef": true } } ] },
|
||||||
|
{ "name": "ПустаяСсылкаВМассиве", "type": "String(10)",
|
||||||
|
"choiceParameters": [ { "name": "Отбор.Набор", "value": [ { "emptyRef": true }, "ТТН" ] } ] }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"validatePath": "Catalogs/ТестВыбора",
|
"validatePath": "Catalogs/ТестВыбора",
|
||||||
|
|||||||
+99
@@ -270,6 +270,105 @@
|
|||||||
<DataHistory>Use</DataHistory>
|
<DataHistory>Use</DataHistory>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Attribute>
|
</Attribute>
|
||||||
|
<Attribute uuid="UUID-016">
|
||||||
|
<Properties>
|
||||||
|
<Name>ПустаяСсылка</Name>
|
||||||
|
<Synonym>
|
||||||
|
<v8:item>
|
||||||
|
<v8:lang>ru</v8:lang>
|
||||||
|
<v8:content>Пустая ссылка</v8:content>
|
||||||
|
</v8:item>
|
||||||
|
</Synonym>
|
||||||
|
<Comment/>
|
||||||
|
<Type>
|
||||||
|
<v8:Type>xs:string</v8:Type>
|
||||||
|
<v8:StringQualifiers>
|
||||||
|
<v8:Length>10</v8:Length>
|
||||||
|
<v8:AllowedLength>Variable</v8:AllowedLength>
|
||||||
|
</v8:StringQualifiers>
|
||||||
|
</Type>
|
||||||
|
<PasswordMode>false</PasswordMode>
|
||||||
|
<Format/>
|
||||||
|
<EditFormat/>
|
||||||
|
<ToolTip/>
|
||||||
|
<MarkNegatives>false</MarkNegatives>
|
||||||
|
<Mask/>
|
||||||
|
<MultiLine>false</MultiLine>
|
||||||
|
<ExtendedEdit>false</ExtendedEdit>
|
||||||
|
<MinValue xsi:nil="true"/>
|
||||||
|
<MaxValue xsi:nil="true"/>
|
||||||
|
<FillFromFillingValue>false</FillFromFillingValue>
|
||||||
|
<FillValue xsi:type="xs:string"/>
|
||||||
|
<FillChecking>DontCheck</FillChecking>
|
||||||
|
<ChoiceFoldersAndItems>Items</ChoiceFoldersAndItems>
|
||||||
|
<ChoiceParameterLinks/>
|
||||||
|
<ChoiceParameters>
|
||||||
|
<app:item name="Отбор.ТипПоказателя">
|
||||||
|
<app:value xsi:type="xr:DesignTimeRef"/>
|
||||||
|
</app:item>
|
||||||
|
</ChoiceParameters>
|
||||||
|
<QuickChoice>Auto</QuickChoice>
|
||||||
|
<CreateOnInput>Auto</CreateOnInput>
|
||||||
|
<ChoiceForm/>
|
||||||
|
<LinkByType/>
|
||||||
|
<ChoiceHistoryOnInput>Auto</ChoiceHistoryOnInput>
|
||||||
|
<Use>ForItem</Use>
|
||||||
|
<Indexing>DontIndex</Indexing>
|
||||||
|
<FullTextSearch>Use</FullTextSearch>
|
||||||
|
<DataHistory>Use</DataHistory>
|
||||||
|
</Properties>
|
||||||
|
</Attribute>
|
||||||
|
<Attribute uuid="UUID-017">
|
||||||
|
<Properties>
|
||||||
|
<Name>ПустаяСсылкаВМассиве</Name>
|
||||||
|
<Synonym>
|
||||||
|
<v8:item>
|
||||||
|
<v8:lang>ru</v8:lang>
|
||||||
|
<v8:content>Пустая ссылка вмассиве</v8:content>
|
||||||
|
</v8:item>
|
||||||
|
</Synonym>
|
||||||
|
<Comment/>
|
||||||
|
<Type>
|
||||||
|
<v8:Type>xs:string</v8:Type>
|
||||||
|
<v8:StringQualifiers>
|
||||||
|
<v8:Length>10</v8:Length>
|
||||||
|
<v8:AllowedLength>Variable</v8:AllowedLength>
|
||||||
|
</v8:StringQualifiers>
|
||||||
|
</Type>
|
||||||
|
<PasswordMode>false</PasswordMode>
|
||||||
|
<Format/>
|
||||||
|
<EditFormat/>
|
||||||
|
<ToolTip/>
|
||||||
|
<MarkNegatives>false</MarkNegatives>
|
||||||
|
<Mask/>
|
||||||
|
<MultiLine>false</MultiLine>
|
||||||
|
<ExtendedEdit>false</ExtendedEdit>
|
||||||
|
<MinValue xsi:nil="true"/>
|
||||||
|
<MaxValue xsi:nil="true"/>
|
||||||
|
<FillFromFillingValue>false</FillFromFillingValue>
|
||||||
|
<FillValue xsi:type="xs:string"/>
|
||||||
|
<FillChecking>DontCheck</FillChecking>
|
||||||
|
<ChoiceFoldersAndItems>Items</ChoiceFoldersAndItems>
|
||||||
|
<ChoiceParameterLinks/>
|
||||||
|
<ChoiceParameters>
|
||||||
|
<app:item name="Отбор.Набор">
|
||||||
|
<app:value xsi:type="v8:FixedArray">
|
||||||
|
<v8:Value xsi:type="xr:DesignTimeRef"/>
|
||||||
|
<v8:Value xsi:type="xs:string">ТТН</v8:Value>
|
||||||
|
</app:value>
|
||||||
|
</app:item>
|
||||||
|
</ChoiceParameters>
|
||||||
|
<QuickChoice>Auto</QuickChoice>
|
||||||
|
<CreateOnInput>Auto</CreateOnInput>
|
||||||
|
<ChoiceForm/>
|
||||||
|
<LinkByType/>
|
||||||
|
<ChoiceHistoryOnInput>Auto</ChoiceHistoryOnInput>
|
||||||
|
<Use>ForItem</Use>
|
||||||
|
<Indexing>DontIndex</Indexing>
|
||||||
|
<FullTextSearch>Use</FullTextSearch>
|
||||||
|
<DataHistory>Use</DataHistory>
|
||||||
|
</Properties>
|
||||||
|
</Attribute>
|
||||||
</ChildObjects>
|
</ChildObjects>
|
||||||
</Catalog>
|
</Catalog>
|
||||||
</MetaDataObject>
|
</MetaDataObject>
|
||||||
|
|||||||
Reference in New Issue
Block a user