mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-26 14:41:02 +03:00
feat(form-decompile,form-compile): функциональные опции + фиксы round-trip типов (ValueList/UUID/платформенные)
1) Функциональные опции (<FunctionalOptions><Item>FunctionalOption.X</Item>…>) у Attribute (4391) / Command (2385) / Column (1272) — не захватывались. Ключ functionalOptions (массив имён; forgiving "X"/"FunctionalOption.X"; GUID-опции расширений — как есть). Общий хелпер Emit/Decompile-FunctionalOptions (+py). Порядок: атрибут после FillChecking; команда после Action; колонка после Type. 2) ValueList round-trip баг: Decompile-Type switch без break → общий case ^(v8|v8ui|cfg): перетирал специфичный v8:ValueListType → выдавал «ValueListType» (голый), компилятор эмитил <v8:Type>ValueListType</v8:Type> без префикса. Добавлены break во все cases. 3) Платформенные типы без friendly-шортката (v8:UUID 3132, v8:StandardPeriod 233, v8:Null, v8:StandardBeginningDate, v8ui:VerticalAlign …) теряли префикс (декомпилятор снимал v8:, компилятор эмитил голый). Теперь декомпилятор оставляет префикс для не-friendly v8:/v8ui: типов (friendly — ValueTable/ValueTree/ValueList/ TypeDescription/FormattedString/Picture/Color/Font — шорткат), компилятор эмитит токены с префиксом (v8:/v8ui:/xs:/dcs*:) verbatim. Покрыт весь хвост. TOTAL diff lines выборки 2.17: 4068 → 3869 (-199). FunctionalOptions/ValueListType/UUID residual → 0. Снапшот attributes-types (+ValueList, +v8:UUID) сертифицирован в 1С (8.3.24). Регресс form-compile 33/33 зелёный на ps + python. decompile v0.35, compile v1.53. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9b77f06aba
commit
fdbfa3b643
@@ -1,4 +1,4 @@
|
||||
# form-compile v1.52 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.53 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$JsonPath,
|
||||
@@ -2134,7 +2134,10 @@ function Emit-SingleType {
|
||||
if ($script:knownInvalidTypes.ContainsKey($typeStr)) {
|
||||
throw "Invalid form attribute type '$typeStr': $($script:knownInvalidTypes[$typeStr])"
|
||||
}
|
||||
if ($typeStr.Contains('.')) {
|
||||
# Платформенный тип с префиксом (v8:/v8ui:/xs:/dcs*:) — эмитим verbatim (напр. v8:UUID, v8:StandardPeriod).
|
||||
if ($typeStr -match '^(v8|v8ui|xs|ent|style|sys|web|win|dcs\w*):') {
|
||||
X "$indent<v8:Type>$typeStr</v8:Type>"
|
||||
} elseif ($typeStr.Contains('.')) {
|
||||
X "$indent<v8:Type>cfg:$typeStr</v8:Type>"
|
||||
} else {
|
||||
Write-Warning "Unrecognized bare type '$typeStr' — will be emitted without namespace prefix"
|
||||
@@ -3597,6 +3600,22 @@ function Emit-Popup {
|
||||
|
||||
# --- 8. Attribute emitter ---
|
||||
|
||||
# <FunctionalOptions><Item>FunctionalOption.X</Item>…</FunctionalOptions> — у Attribute/Command/Column.
|
||||
# DSL: массив строк. Forgiving: "X" / "FunctionalOption.X" → FunctionalOption.X; GUID (расширение) — как есть.
|
||||
function Emit-FunctionalOptions {
|
||||
param($fo, [string]$indent)
|
||||
if (-not $fo -or @($fo).Count -eq 0) { return }
|
||||
X "$indent<FunctionalOptions>"
|
||||
foreach ($opt in @($fo)) {
|
||||
$v = "$opt"
|
||||
if ($v -match '^[0-9a-fA-F]{8}-[0-9a-fA-F-]{27,}$') { } # GUID — как есть
|
||||
elseif ($v -match '^FunctionalOption\.') { } # уже с префиксом
|
||||
else { $v = "FunctionalOption.$v" }
|
||||
X "$indent`t<Item>$v</Item>"
|
||||
}
|
||||
X "$indent</FunctionalOptions>"
|
||||
}
|
||||
|
||||
function Emit-Attributes {
|
||||
param($attrs, [string]$indent)
|
||||
|
||||
@@ -3638,6 +3657,7 @@ function Emit-Attributes {
|
||||
if ($attr.fillChecking) {
|
||||
X "$inner<FillChecking>$($attr.fillChecking)</FillChecking>"
|
||||
}
|
||||
Emit-FunctionalOptions -fo $attr.functionalOptions -indent $inner
|
||||
|
||||
# Columns (for ValueTable/ValueTree)
|
||||
if ($attr.columns -and $attr.columns.Count -gt 0) {
|
||||
@@ -3649,6 +3669,7 @@ function Emit-Attributes {
|
||||
Emit-MLText -tag "Title" -text $col.title -indent "$inner`t`t"
|
||||
}
|
||||
Emit-Type -typeStr "$($col.type)" -indent "$inner`t`t"
|
||||
Emit-FunctionalOptions -fo $col.functionalOptions -indent "$inner`t`t"
|
||||
X "$inner`t</Column>"
|
||||
}
|
||||
X "$inner</Columns>"
|
||||
@@ -3756,6 +3777,8 @@ function Emit-Commands {
|
||||
X "$inner<Action>$($cmd.action)</Action>"
|
||||
}
|
||||
|
||||
Emit-FunctionalOptions -fo $cmd.functionalOptions -indent $inner
|
||||
|
||||
if ($cmd.currentRowUse) {
|
||||
X "$inner<CurrentRowUse>$($cmd.currentRowUse)</CurrentRowUse>"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# form-compile v1.52 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.53 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import copy
|
||||
@@ -2452,7 +2452,10 @@ def emit_single_type(lines, type_str, indent):
|
||||
# Fallback with validation
|
||||
if type_str in KNOWN_INVALID_TYPES:
|
||||
raise ValueError(f"Invalid form attribute type '{type_str}': {KNOWN_INVALID_TYPES[type_str]}")
|
||||
if '.' in type_str:
|
||||
# Платформенный тип с префиксом (v8:/v8ui:/xs:/dcs*:) — verbatim (напр. v8:UUID, v8:StandardPeriod).
|
||||
if re.match(r'^(v8|v8ui|xs|ent|style|sys|web|win|dcs\w*):', type_str):
|
||||
lines.append(f'{indent}<v8:Type>{type_str}</v8:Type>')
|
||||
elif '.' in type_str:
|
||||
lines.append(f'{indent}<v8:Type>cfg:{type_str}</v8:Type>')
|
||||
else:
|
||||
print(f"WARNING: Unrecognized bare type '{type_str}' — will be emitted without namespace prefix", file=sys.stderr)
|
||||
@@ -3271,6 +3274,24 @@ def emit_button_group(lines, el, name, eid, indent):
|
||||
|
||||
# --- Attribute emitter ---
|
||||
|
||||
def emit_functional_options(lines, fo, indent):
|
||||
# <FunctionalOptions><Item>FunctionalOption.X</Item>…> — у Attribute/Command/Column.
|
||||
# Forgiving: "X"/"FunctionalOption.X" → FunctionalOption.X; GUID (расширение) — как есть.
|
||||
if not fo:
|
||||
return
|
||||
lines.append(f'{indent}<FunctionalOptions>')
|
||||
for opt in fo:
|
||||
v = str(opt)
|
||||
if re.match(r'^[0-9a-fA-F]{8}-[0-9a-fA-F-]{27,}$', v):
|
||||
pass
|
||||
elif v.startswith('FunctionalOption.'):
|
||||
pass
|
||||
else:
|
||||
v = f'FunctionalOption.{v}'
|
||||
lines.append(f'{indent}\t<Item>{v}</Item>')
|
||||
lines.append(f'{indent}</FunctionalOptions>')
|
||||
|
||||
|
||||
def emit_attributes(lines, attrs, indent):
|
||||
if not attrs or len(attrs) == 0:
|
||||
return
|
||||
@@ -3310,6 +3331,7 @@ def emit_attributes(lines, attrs, indent):
|
||||
lines.append(f'{inner}<SavedData>true</SavedData>')
|
||||
if attr.get('fillChecking'):
|
||||
lines.append(f'{inner}<FillChecking>{attr["fillChecking"]}</FillChecking>')
|
||||
emit_functional_options(lines, attr.get('functionalOptions'), inner)
|
||||
|
||||
# Columns (for ValueTable/ValueTree)
|
||||
if attr.get('columns') and len(attr['columns']) > 0:
|
||||
@@ -3320,6 +3342,7 @@ def emit_attributes(lines, attrs, indent):
|
||||
if col.get('title'):
|
||||
emit_mltext(lines, f'{inner}\t\t', 'Title', col['title'])
|
||||
emit_type(lines, str(col.get('type', '')), f'{inner}\t\t')
|
||||
emit_functional_options(lines, col.get('functionalOptions'), f'{inner}\t\t')
|
||||
lines.append(f'{inner}\t</Column>')
|
||||
lines.append(f'{inner}</Columns>')
|
||||
|
||||
@@ -3414,6 +3437,8 @@ def emit_commands(lines, cmds, indent):
|
||||
if cmd.get('action'):
|
||||
lines.append(f'{inner}<Action>{cmd["action"]}</Action>')
|
||||
|
||||
emit_functional_options(lines, cmd.get('functionalOptions'), inner)
|
||||
|
||||
if cmd.get('currentRowUse'):
|
||||
lines.append(f'{inner}<CurrentRowUse>{cmd["currentRowUse"]}</CurrentRowUse>')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user