mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-26 22:51:03 +03:00
feat(meta-compile): type-подсказка для голых ref-значений choiceParameters (v1.24)
Раньше голое значение параметра выбора (["ПустаяСсылка","ТТН"]) тихо становилось xs:string вместо DTR — footgun для авторинга с нуля. Причина: у значения нет типа (тип задаёт поле-фильтр, не реквизит). Опциональный ключ `type` на элементе choiceParameters (напр. EnumRef.X / СправочникСсылка.X) разворачивает голые значения через ref-машинку: value ["EmptyRef","ТТН"] + type EnumRef.X → Enum.X.EmptyRef, Enum.X.EnumValue.ТТН. Полные пути и скаляры — без изменений; принимает Ref-форму и голый метатип (Enum.X), рус. корни. Только компилятор (декомпилятор пишет полные пути) → роундтрип не затронут (remaining=0). Кейс ТипТТН переведён на type+голые (снэпшот идентичен). Регресс 43/43 ps1+py, ps1↔py identical. spec §4.2. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7cf910396b
commit
e9e3323542
@@ -1,4 +1,4 @@
|
|||||||
# meta-compile v1.23 — Compile 1C metadata object from JSON
|
# meta-compile v1.24 — 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)]
|
||||||
@@ -1210,6 +1210,30 @@ function ConvertTo-ChScalar {
|
|||||||
return $t
|
return $t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Голое значение (без точки) + тип параметра → полный DTR-путь, либо $null. Принимает EnumRef.X / Enum.X / рус.
|
||||||
|
function Expand-ChoiceRefValue {
|
||||||
|
param([string]$value, [string]$typeStr)
|
||||||
|
if (-not $typeStr) { return $null }
|
||||||
|
$t = Resolve-TypeStr $typeStr
|
||||||
|
$root = $null; $tn = $null
|
||||||
|
if ($t -match '^(\w+Ref)\.(.+)$') { $root = $script:fillRefKindRoot[$Matches[1].ToLower()]; $tn = $Matches[2] }
|
||||||
|
elseif ($t -match '^([^.]+)\.(.+)$') { $root = $script:fillRefRoots[$Matches[1].ToLower()]; $tn = $Matches[2] }
|
||||||
|
if (-not $root) { return $null }
|
||||||
|
if ($script:fillEmptyRefWords -contains "$value".ToLower()) { return "$root.$tn.EmptyRef" }
|
||||||
|
if ($root -eq 'Enum') { return "Enum.$tn.EnumValue.$value" }
|
||||||
|
return "$root.$tn.$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Значение параметра выбора → @{XsiType; Text}. $typeStr (тип параметра) разворачивает голые ref-имена.
|
||||||
|
function Normalize-ChoiceValueT {
|
||||||
|
param($value, [string]$typeStr)
|
||||||
|
if ($typeStr -and ($value -is [string]) -and (-not "$value".Contains('.'))) {
|
||||||
|
$ex = Expand-ChoiceRefValue "$value" $typeStr
|
||||||
|
if ($ex) { return @{ XsiType='xr:DesignTimeRef'; Text=$ex } }
|
||||||
|
}
|
||||||
|
return Normalize-ChoiceValue $value
|
||||||
|
}
|
||||||
|
|
||||||
# Значение параметра выбора → @{XsiType; Text}. Авто-детект по значению (без типа реквизита).
|
# Значение параметра выбора → @{XsiType; Text}. Авто-детект по значению (без типа реквизита).
|
||||||
function Normalize-ChoiceValue {
|
function Normalize-ChoiceValue {
|
||||||
param($value)
|
param($value)
|
||||||
@@ -1256,6 +1280,7 @@ function Emit-ChoiceParameters {
|
|||||||
foreach ($item in @($cp)) {
|
foreach ($item in @($cp)) {
|
||||||
if ($item -is [string]) { $item = ConvertFrom-ChParamShorthand $item }
|
if ($item -is [string]) { $item = ConvertFrom-ChParamShorthand $item }
|
||||||
$name = Get-ChElProp $item @('name','имя')
|
$name = Get-ChElProp $item @('name','имя')
|
||||||
|
$ptype = Get-ChElProp $item @('type','тип')
|
||||||
$hasVal = $false; $val = $null
|
$hasVal = $false; $val = $null
|
||||||
if ($item -is [System.Collections.IDictionary]) {
|
if ($item -is [System.Collections.IDictionary]) {
|
||||||
if ($item.Contains('value')) { $hasVal = $true; $val = $item['value'] }
|
if ($item.Contains('value')) { $hasVal = $true; $val = $item['value'] }
|
||||||
@@ -1271,13 +1296,13 @@ function Emit-ChoiceParameters {
|
|||||||
} 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) {
|
||||||
$norm = Normalize-ChoiceValue -value $v
|
$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>" }
|
||||||
}
|
}
|
||||||
X "$indent`t`t</app:value>"
|
X "$indent`t`t</app:value>"
|
||||||
} else {
|
} else {
|
||||||
$norm = Normalize-ChoiceValue -value $val
|
$norm = Normalize-ChoiceValueT $val $ptype
|
||||||
if ([string]::IsNullOrEmpty($norm.Text)) { X "$indent`t`t<app:value xsi:type=`"$($norm.XsiType)`"/>" }
|
if ([string]::IsNullOrEmpty($norm.Text)) { X "$indent`t`t<app:value xsi:type=`"$($norm.XsiType)`"/>" }
|
||||||
else { X "$indent`t`t<app:value xsi:type=`"$($norm.XsiType)`">$(Esc-Xml $norm.Text)</app:value>" }
|
else { X "$indent`t`t<app:value xsi:type=`"$($norm.XsiType)`">$(Esc-Xml $norm.Text)</app:value>" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# meta-compile v1.23 — Compile 1C metadata object from JSON
|
# meta-compile v1.24 — 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
|
||||||
@@ -1260,6 +1260,37 @@ def convert_to_ch_scalar(s):
|
|||||||
return float(t)
|
return float(t)
|
||||||
return t
|
return t
|
||||||
|
|
||||||
|
def expand_choice_ref_value(value, type_str):
|
||||||
|
"""Голое значение (без точки) + тип параметра → полный DTR-путь, либо None. Принимает EnumRef.X / Enum.X / рус."""
|
||||||
|
if not type_str:
|
||||||
|
return None
|
||||||
|
t = resolve_type_str(type_str)
|
||||||
|
root = tn = None
|
||||||
|
m = re.match(r'^(\w+Ref)\.(.+)$', t)
|
||||||
|
if m:
|
||||||
|
root = fill_ref_kind_root.get(m.group(1).lower())
|
||||||
|
tn = m.group(2)
|
||||||
|
else:
|
||||||
|
m = re.match(r'^([^.]+)\.(.+)$', t)
|
||||||
|
if m:
|
||||||
|
root = fill_ref_roots.get(m.group(1).lower())
|
||||||
|
tn = m.group(2)
|
||||||
|
if not root:
|
||||||
|
return None
|
||||||
|
if str(value).lower() in fill_empty_ref_words:
|
||||||
|
return f'{root}.{tn}.EmptyRef'
|
||||||
|
if root == 'Enum':
|
||||||
|
return f'Enum.{tn}.EnumValue.{value}'
|
||||||
|
return f'{root}.{tn}.{value}'
|
||||||
|
|
||||||
|
def normalize_choice_value_t(value, type_str):
|
||||||
|
"""Значение параметра выбора → (xsi_type, text). type_str разворачивает голые ref-имена."""
|
||||||
|
if type_str and isinstance(value, str) and '.' not in value:
|
||||||
|
ex = expand_choice_ref_value(value, type_str)
|
||||||
|
if ex:
|
||||||
|
return ('xr:DesignTimeRef', ex)
|
||||||
|
return normalize_choice_value(value)
|
||||||
|
|
||||||
def normalize_choice_value(value):
|
def normalize_choice_value(value):
|
||||||
"""Значение параметра выбора → (xsi_type, text). Авто-детект по значению."""
|
"""Значение параметра выбора → (xsi_type, text). Авто-детект по значению."""
|
||||||
if isinstance(value, bool):
|
if isinstance(value, bool):
|
||||||
@@ -1311,6 +1342,7 @@ def emit_choice_parameters(indent, cp):
|
|||||||
if isinstance(item, str):
|
if isinstance(item, str):
|
||||||
item = convert_from_ch_param_shorthand(item)
|
item = convert_from_ch_param_shorthand(item)
|
||||||
name = ch_el_prop(item, ['name', 'имя'])
|
name = ch_el_prop(item, ['name', 'имя'])
|
||||||
|
ptype = ch_el_prop(item, ['type', 'тип'])
|
||||||
has_val = isinstance(item, dict) and ('value' in item or 'значение' in item)
|
has_val = isinstance(item, dict) and ('value' in item or 'значение' in item)
|
||||||
val = item.get('value', item.get('значение')) if has_val else None
|
val = item.get('value', item.get('значение')) if has_val else None
|
||||||
val_is_array = isinstance(val, (list, tuple))
|
val_is_array = isinstance(val, (list, tuple))
|
||||||
@@ -1320,14 +1352,14 @@ def emit_choice_parameters(indent, cp):
|
|||||||
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:
|
||||||
xt, tx = normalize_choice_value(v)
|
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}"/>')
|
||||||
else:
|
else:
|
||||||
X(f'{indent}\t\t\t<v8:Value xsi:type="{xt}">{esc_xml(tx)}</v8:Value>')
|
X(f'{indent}\t\t\t<v8:Value xsi:type="{xt}">{esc_xml(tx)}</v8:Value>')
|
||||||
X(f'{indent}\t\t</app:value>')
|
X(f'{indent}\t\t</app:value>')
|
||||||
else:
|
else:
|
||||||
xt, tx = normalize_choice_value(val)
|
xt, tx = normalize_choice_value_t(val, ptype)
|
||||||
if tx == '' or tx is None:
|
if tx == '' or tx is None:
|
||||||
X(f'{indent}\t\t<app:value xsi:type="{xt}"/>')
|
X(f'{indent}\t\t<app:value xsi:type="{xt}"/>')
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -158,7 +158,12 @@ JSON DSL для описания объектов метаданных конф
|
|||||||
`<Тип>.<Имя>.StandardAttribute.<EN>`;
|
`<Тип>.<Имя>.StandardAttribute.<EN>`;
|
||||||
- обычный реквизит: имя (`Свойство`) → `<Тип>.<Имя>.Attribute.Свойство`;
|
- обычный реквизит: имя (`Свойство`) → `<Тип>.<Имя>.Attribute.Свойство`;
|
||||||
- частичное `StandardAttribute.X` / `Attribute.X` → добавит префикс `<Тип>.<Имя>`; полный путь — как есть.
|
- частичное `StandardAttribute.X` / `Attribute.X` → добавит префикс `<Тип>.<Имя>`; полный путь — как есть.
|
||||||
| `choiceParameters` | ChoiceParameters | пусто | параметры выбора: массив `{name, value?}` ИЛИ строк `"name=value"`. value — bool/число/строка/DTR-путь ИЛИ массив (→ FixedArray); без value → nil |
|
| `choiceParameters` | ChoiceParameters | пусто | параметры выбора: массив `{name, type?, value?}` ИЛИ строк `"name=value"`. value — bool/число/строка/DTR-путь ИЛИ массив (→ FixedArray); без value → nil |
|
||||||
|
|
||||||
|
`value` в `choiceParameters` — ref-путь несёт тип в себе (`Enum.X.EmptyRef`, `Enum.X.EnumValue.Y`, рус. корни). Опц.
|
||||||
|
ключ **`type`** (тип поля-фильтра, напр. `EnumRef.ТипыВЕТИС` / `СправочникСсылка.X`) разворачивает **голые** значения:
|
||||||
|
`{name:"Отбор.Тип", type:"EnumRef.ТипыВЕТИС", value:["EmptyRef","ТТН"]}` → `Enum.ТипыВЕТИС.EmptyRef`,
|
||||||
|
`Enum.ТипыВЕТИС.EnumValue.ТТН`. Без `type` голое имя (`ТТН`) остаётся **строкой** (`xs:string`) — для ссылки нужен путь.
|
||||||
| `createOnInput` | CreateOnInput | Auto | Auto/Use/DontUse |
|
| `createOnInput` | CreateOnInput | Auto | Auto/Use/DontUse |
|
||||||
| `quickChoice` | QuickChoice | Auto | Auto/Use/DontUse. Прощаем bool (форм-стиль): `true`→Use, `false`→DontUse |
|
| `quickChoice` | QuickChoice | Auto | Auto/Use/DontUse. Прощаем bool (форм-стиль): `true`→Use, `false`→DontUse |
|
||||||
| `dataHistory` | DataHistory | Use | Use/DontUse |
|
| `dataHistory` | DataHistory | Use | Use/DontUse |
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
{ "name": "Партнер", "type": "CatalogRef.Партнеры",
|
{ "name": "Партнер", "type": "CatalogRef.Партнеры",
|
||||||
"choiceParameters": "Отбор.ЭтоГруппа=false" },
|
"choiceParameters": "Отбор.ЭтоГруппа=false" },
|
||||||
{ "name": "ТипТТН", "type": "CatalogRef.ВидыТранспорта",
|
{ "name": "ТипТТН", "type": "CatalogRef.ВидыТранспорта",
|
||||||
"choiceParameters": [ { "name": "Отбор.Тип", "value": ["Enum.ТипыВЕТИС.EmptyRef", "Enum.ТипыВЕТИС.EnumValue.ТТН"] } ] },
|
"choiceParameters": [ { "name": "Отбор.Тип", "type": "EnumRef.ТипыВЕТИС", "value": ["EmptyRef", "ТТН"] } ] },
|
||||||
{ "name": "Валюта", "type": "CatalogRef.Валюты",
|
{ "name": "Валюта", "type": "CatalogRef.Валюты",
|
||||||
"choiceParameterLinks": "Отбор.Владелец=Ссылка" }
|
"choiceParameterLinks": "Отбор.Владелец=Ссылка" }
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user