mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-25 06:01:02 +03:00
fix(skd): multilang в calcField appearance и selection lwsTitle + hidden combo
Найдено через новый debug-tool debug/skd-decompile/verify-roundtrip.ps1
(XML→decompile→compile→diff на сэмпле 30 ERP).
1. Emit-CalcFields appearance: третий дубликат-emitter с тем же
multilang-багом как был в Emit-AppearanceValue для field/cond. Унифи-
цирован через Emit-AppearanceValue. (compile.ps1+py)
2. Emit-SelectionItem: lwsTitle для folder + field-with-title
эмитили "$($item.folder)" — для hashtable получали "@{ru=X; en=Y}".
Унифицирован через Emit-MLText с новой опцией -NoXsiType
(lwsTitle в оригинале без xsi:type, в отличие от <title> в fields).
(compile.ps1+py)
3. Build-Parameter hidden detection: combo availableAsField=false +
useRestriction=true. Только availableAsField=false (без
useRestriction) → object form `availableAsField: false`.
На сэмпле 30 ERP roundtrip-diff: ADDED <content> 667 → 129
(multilang-потери в selection закрыты). Остаточные LOST <item> ~10k —
другие потери (attributeUseRestriction и проч.) — отдельная задача.
Versions: compile v1.35→v1.36, decompile v0.20→v0.21.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# skd-compile v1.35 — Compile 1C DCS from JSON
|
||||
# skd-compile v1.36 — Compile 1C DCS from JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$DefinitionFile,
|
||||
@@ -121,8 +121,12 @@ function Resolve-QueryValue {
|
||||
}
|
||||
|
||||
function Emit-MLText {
|
||||
param([string]$tag, $text, [string]$indent)
|
||||
X "$indent<$tag xsi:type=`"v8:LocalStringType`">"
|
||||
param([string]$tag, $text, [string]$indent, [switch]$NoXsiType)
|
||||
if ($NoXsiType) {
|
||||
X "$indent<$tag>"
|
||||
} else {
|
||||
X "$indent<$tag xsi:type=`"v8:LocalStringType`">"
|
||||
}
|
||||
# Multi-lang: object form { ru: "...", en: "..." } → one <v8:item> per language
|
||||
if ($text -is [System.Management.Automation.PSCustomObject] -or $text -is [hashtable] -or $text -is [System.Collections.IDictionary]) {
|
||||
$props = if ($text -is [System.Management.Automation.PSCustomObject]) { $text.PSObject.Properties } else { $text.GetEnumerator() | ForEach-Object { @{ Name = $_.Key; Value = $_.Value } } }
|
||||
@@ -1129,10 +1133,15 @@ function Emit-CalcFields {
|
||||
if ($appearance) {
|
||||
X "`t`t<appearance>"
|
||||
foreach ($prop in $appearance.PSObject.Properties) {
|
||||
X "`t`t`t<dcscor:item xsi:type=`"dcsset:SettingsParameterValue`">"
|
||||
X "`t`t`t`t<dcscor:parameter>$(Esc-Xml $prop.Name)</dcscor:parameter>"
|
||||
X "`t`t`t`t<dcscor:value xsi:type=`"xs:string`">$(Esc-Xml "$($prop.Value)")</dcscor:value>"
|
||||
X "`t`t`t</dcscor:item>"
|
||||
# ГоризонтальноеПоложение — особый xsi:type (если не multilang)
|
||||
if ($prop.Name -eq "ГоризонтальноеПоложение" -and -not ($prop.Value -is [hashtable] -or $prop.Value -is [System.Collections.IDictionary] -or $prop.Value -is [PSCustomObject])) {
|
||||
X "`t`t`t<dcscor:item xsi:type=`"dcsset:SettingsParameterValue`">"
|
||||
X "`t`t`t`t<dcscor:parameter>$(Esc-Xml $prop.Name)</dcscor:parameter>"
|
||||
X "`t`t`t`t<dcscor:value xsi:type=`"v8ui:HorizontalAlign`">$(Esc-Xml "$($prop.Value)")</dcscor:value>"
|
||||
X "`t`t`t</dcscor:item>"
|
||||
} else {
|
||||
Emit-AppearanceValue -key $prop.Name -val $prop.Value -indent "`t`t`t"
|
||||
}
|
||||
}
|
||||
X "`t`t</appearance>"
|
||||
}
|
||||
@@ -1847,12 +1856,7 @@ function Emit-SelectionItem {
|
||||
if ($item.field) {
|
||||
X "$indent`t<dcsset:field>$(Esc-Xml "$($item.field)")</dcsset:field>"
|
||||
}
|
||||
X "$indent`t<dcsset:lwsTitle>"
|
||||
X "$indent`t`t<v8:item>"
|
||||
X "$indent`t`t`t<v8:lang>ru</v8:lang>"
|
||||
X "$indent`t`t`t<v8:content>$(Esc-Xml "$($item.folder)")</v8:content>"
|
||||
X "$indent`t`t</v8:item>"
|
||||
X "$indent`t</dcsset:lwsTitle>"
|
||||
Emit-MLText -tag "dcsset:lwsTitle" -text $item.folder -indent "$indent`t" -NoXsiType
|
||||
foreach ($sub in $item.items) {
|
||||
Emit-SelectionItem -item $sub -indent "$indent`t"
|
||||
}
|
||||
@@ -1864,12 +1868,7 @@ function Emit-SelectionItem {
|
||||
X "$indent<dcsset:item xsi:type=`"dcsset:SelectedItemField`">"
|
||||
X "$indent`t<dcsset:field>$(Esc-Xml "$($item.field)")</dcsset:field>"
|
||||
if ($item.title) {
|
||||
X "$indent`t<dcsset:lwsTitle>"
|
||||
X "$indent`t`t<v8:item>"
|
||||
X "$indent`t`t`t<v8:lang>ru</v8:lang>"
|
||||
X "$indent`t`t`t<v8:content>$(Esc-Xml "$($item.title)")</v8:content>"
|
||||
X "$indent`t`t</v8:item>"
|
||||
X "$indent`t</dcsset:lwsTitle>"
|
||||
Emit-MLText -tag "dcsset:lwsTitle" -text $item.title -indent "$indent`t" -NoXsiType
|
||||
}
|
||||
X "$indent</dcsset:item>"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# skd-compile v1.35 — Compile 1C DCS from JSON
|
||||
# skd-compile v1.36 — Compile 1C DCS from JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import json
|
||||
@@ -36,11 +36,14 @@ def resolve_query_value(val, base_dir):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def emit_mltext(lines, indent, tag, text):
|
||||
def emit_mltext(lines, indent, tag, text, no_xsi_type=False):
|
||||
if not text:
|
||||
lines.append(f"{indent}<{tag}/>")
|
||||
return
|
||||
lines.append(f'{indent}<{tag} xsi:type="v8:LocalStringType">')
|
||||
if no_xsi_type:
|
||||
lines.append(f"{indent}<{tag}>")
|
||||
else:
|
||||
lines.append(f'{indent}<{tag} xsi:type="v8:LocalStringType">')
|
||||
# Multi-lang: object form { ru: "...", en: "..." } -- one <v8:item> per language
|
||||
if isinstance(text, dict):
|
||||
for lang, content in text.items():
|
||||
@@ -886,10 +889,13 @@ def emit_calc_fields(lines, defn):
|
||||
if appearance:
|
||||
lines.append('\t\t<appearance>')
|
||||
for k, v in appearance.items():
|
||||
lines.append('\t\t\t<dcscor:item xsi:type="dcsset:SettingsParameterValue">')
|
||||
lines.append(f'\t\t\t\t<dcscor:parameter>{esc_xml(k)}</dcscor:parameter>')
|
||||
lines.append(f'\t\t\t\t<dcscor:value xsi:type="xs:string">{esc_xml(str(v))}</dcscor:value>')
|
||||
lines.append('\t\t\t</dcscor:item>')
|
||||
if k == 'ГоризонтальноеПоложение' and not isinstance(v, dict):
|
||||
lines.append('\t\t\t<dcscor:item xsi:type="dcsset:SettingsParameterValue">')
|
||||
lines.append(f'\t\t\t\t<dcscor:parameter>{esc_xml(k)}</dcscor:parameter>')
|
||||
lines.append(f'\t\t\t\t<dcscor:value xsi:type="v8ui:HorizontalAlign">{esc_xml(str(v))}</dcscor:value>')
|
||||
lines.append('\t\t\t</dcscor:item>')
|
||||
else:
|
||||
emit_appearance_value(lines, k, v, '\t\t\t')
|
||||
lines.append('\t\t</appearance>')
|
||||
|
||||
lines.append('\t</calculatedField>')
|
||||
@@ -1536,12 +1542,7 @@ def emit_selection_item(lines, item, indent):
|
||||
lines.append(f'{indent}<dcsset:item xsi:type="dcsset:SelectedItemFolder">')
|
||||
if item.get('field'):
|
||||
lines.append(f'{indent}\t<dcsset:field>{esc_xml(str(item["field"]))}</dcsset:field>')
|
||||
lines.append(f'{indent}\t<dcsset:lwsTitle>')
|
||||
lines.append(f'{indent}\t\t<v8:item>')
|
||||
lines.append(f'{indent}\t\t\t<v8:lang>ru</v8:lang>')
|
||||
lines.append(f'{indent}\t\t\t<v8:content>{esc_xml(str(item["folder"]))}</v8:content>')
|
||||
lines.append(f'{indent}\t\t</v8:item>')
|
||||
lines.append(f'{indent}\t</dcsset:lwsTitle>')
|
||||
emit_mltext(lines, f'{indent}\t', 'dcsset:lwsTitle', item['folder'], no_xsi_type=True)
|
||||
for sub in (item.get('items') or []):
|
||||
emit_selection_item(lines, sub, f'{indent}\t')
|
||||
lines.append(f'{indent}\t<dcsset:placement>Auto</dcsset:placement>')
|
||||
@@ -1551,12 +1552,7 @@ def emit_selection_item(lines, item, indent):
|
||||
lines.append(f'{indent}<dcsset:item xsi:type="dcsset:SelectedItemField">')
|
||||
lines.append(f'{indent}\t<dcsset:field>{esc_xml(str(item["field"]))}</dcsset:field>')
|
||||
if item.get('title'):
|
||||
lines.append(f'{indent}\t<dcsset:lwsTitle>')
|
||||
lines.append(f'{indent}\t\t<v8:item>')
|
||||
lines.append(f'{indent}\t\t\t<v8:lang>ru</v8:lang>')
|
||||
lines.append(f'{indent}\t\t\t<v8:content>{esc_xml(str(item["title"]))}</v8:content>')
|
||||
lines.append(f'{indent}\t\t</v8:item>')
|
||||
lines.append(f'{indent}\t</dcsset:lwsTitle>')
|
||||
emit_mltext(lines, f'{indent}\t', 'dcsset:lwsTitle', item['title'], no_xsi_type=True)
|
||||
lines.append(f'{indent}</dcsset:item>')
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# skd-decompile v0.20 — Decompile 1C DCS Template.xml to JSON DSL (draft)
|
||||
# skd-decompile v0.21 — Decompile 1C DCS Template.xml to JSON DSL (draft)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -180,7 +180,7 @@ function Try-InlineJson {
|
||||
}
|
||||
|
||||
function ConvertTo-CompactJson {
|
||||
param($obj, [int]$depth = 0, [string]$indentUnit = ' ', [int]$lineLimit = 120)
|
||||
param($obj, [int]$depth = 0, [string]$indentUnit = ' ', [int]$lineLimit = 400)
|
||||
$indent = $indentUnit * $depth
|
||||
$childIndent = $indentUnit * ($depth + 1)
|
||||
|
||||
@@ -681,11 +681,13 @@ function Build-Parameter {
|
||||
|
||||
$valueListAllowed = (Get-Text $pNode "r:valueListAllowed") -eq 'true'
|
||||
$availableAsField = Get-Text $pNode "r:availableAsField"
|
||||
$hidden = $availableAsField -eq 'false'
|
||||
$denyIncomplete = (Get-Text $pNode "r:denyIncompleteValues") -eq 'true'
|
||||
$useAttr = Get-Text $pNode "r:use"
|
||||
$useRestriction = (Get-Text $pNode "r:useRestriction") -eq 'true'
|
||||
$expression = Get-Text $pNode "r:expression"
|
||||
# hidden — combo: availableAsField=false + useRestriction=true (как эмитит compile @hidden)
|
||||
$notAField = ($availableAsField -eq 'false')
|
||||
$hidden = $notAField -and $useRestriction
|
||||
|
||||
# availableValues
|
||||
$avNodes = $pNode.SelectNodes("r:availableValue", $ns)
|
||||
@@ -709,6 +711,7 @@ function Build-Parameter {
|
||||
valueIsNil = $valueIsNil
|
||||
valueListAllowed = $valueListAllowed
|
||||
hidden = $hidden
|
||||
notAField = ($notAField -and -not $hidden) # availableAsField=false без useRestriction
|
||||
denyIncomplete = $denyIncomplete
|
||||
useAttr = $useAttr
|
||||
useRestriction = $useRestriction
|
||||
@@ -749,6 +752,7 @@ function Render-Parameter {
|
||||
}
|
||||
# useRestriction is auto-generated by compile for @hidden params; ignore as object trigger
|
||||
if ($p.expression) { $needsObject = $true }
|
||||
if ($p.notAField) { $needsObject = $true }
|
||||
|
||||
if (-not $needsObject) {
|
||||
$s = $name
|
||||
@@ -766,6 +770,7 @@ function Render-Parameter {
|
||||
if ($p.useAttr -and -not $p.autoDates) { $obj['use'] = $p.useAttr }
|
||||
if ($p.denyIncomplete -and -not $p.autoDates) { $obj['denyIncompleteValues'] = $true }
|
||||
if ($p.hidden) { $obj['hidden'] = $true }
|
||||
if ($p.notAField) { $obj['availableAsField'] = $false }
|
||||
if ($p.valueListAllowed) { $obj['valueListAllowed'] = $true }
|
||||
if ($p.autoDates) { $obj['autoDates'] = $true }
|
||||
if ($p.expression) { $obj['expression'] = $p.expression }
|
||||
|
||||
Reference in New Issue
Block a user