mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-14 18:04:58 +03:00
feat(form-decompile,form-compile): appearance Текст/Заголовок/Формат — xs:string/Field/typed LocalString (категория картинок→текст оформления)
В значениях параметров оформления (dcsset:appearance) компилятор форсил
мультиязычный LocalStringType по имени ключа (Текст/Заголовок/Формат), теряя
плоскую xs:string и dcscor:Field. Корпус 8.3.24 (Текст/Заголовок/Формат):
xs:string 823, LocalString одноязычный 658, многоязычный 188, dcscor:Field 105.
Контекст (форменный CA vs Settings дин-списка) НЕ детерминирует (целевая форма
СправкаРасчётПостоянныхИВременныхРазниц — форменный CA с xs:string).
Решение (scoped-различие по форме значения, в этом конкретном контексте — не общая
конвенция DSL): голая строка → плоский xs:string (нелокализ. литерал; "" →
самозакрывающийся тег); объект {ru,en} → LocalStringType; объект {field:"путь"} →
dcscor:Field. Декомпилятор перестаёт схлопывать одноязычный LocalString здесь
(всегда объект-карта языков → различим от xs:string).
Заодно пред-существующий баг: LocalString-значение параметра несёт
xsi:type="v8:LocalStringType" на теге dcscor:value (846 случаев) — Emit-MLText
эмитил голый тег; добавлен опц. параметр xsiType (ps+py).
Зеркало py (байт-в-байт). Выборка 57 CA-форм (xs:string/LocalString/Field, вкл.
целевую): appearance-потерь 0, целевая → match (match 26→40). Кейс input-fields
(+CA Текст: плоский/multilang/пустой/field) сертифицирован в 1С. Регресс 43/43.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# form-compile v1.115 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.116 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$JsonPath,
|
||||
@@ -1570,8 +1570,9 @@ function Emit-MLItems {
|
||||
}
|
||||
|
||||
function Emit-MLText {
|
||||
param([string]$tag, $text, [string]$indent)
|
||||
X "$indent<$tag>"
|
||||
param([string]$tag, $text, [string]$indent, [string]$xsiType)
|
||||
$attr = if ($xsiType) { " xsi:type=`"$xsiType`"" } else { "" }
|
||||
X "$indent<$tag$attr>"
|
||||
Emit-MLItems -val $text -indent "$indent`t"
|
||||
X "$indent</$tag>"
|
||||
}
|
||||
@@ -1860,8 +1861,12 @@ function Emit-AppearanceValue {
|
||||
if ($null -ne $av) { $attrParts += "$attrName=`"$(Esc-Xml "$av")`"" }
|
||||
}
|
||||
X "$indent`t<dcscor:value xsi:type=`"v8ui:Font`" $($attrParts -join ' ')/>"
|
||||
} elseif ($isDict -and (_HasKey $innerVal 'field')) {
|
||||
# Ссылка на поле (dcscor:Field) — значение параметра оформления = поле компоновки
|
||||
X "$indent`t<dcscor:value xsi:type=`"dcscor:Field`">$(Esc-Xml "$(_Get $innerVal 'field')")</dcscor:value>"
|
||||
} elseif ($isDict) {
|
||||
Emit-MLText -tag "dcscor:value" -text $innerVal -indent "$indent`t"
|
||||
# Локализуемый текст параметра оформления: платформа объявляет xsi:type на dcscor:value
|
||||
Emit-MLText -tag "dcscor:value" -text $innerVal -indent "$indent`t" -xsiType "v8:LocalStringType"
|
||||
} else {
|
||||
$actualVal = "$innerVal"
|
||||
$keyTypeMap = @{
|
||||
@@ -1876,7 +1881,13 @@ function Emit-AppearanceValue {
|
||||
if ($keyType) { X "$indent`t<dcscor:value xsi:type=`"$keyType`">$(Esc-Xml $actualVal)</dcscor:value>" }
|
||||
elseif ($actualVal -match '^(style|web|win):') { X "$indent`t<dcscor:value xsi:type=`"v8ui:Color`">$(Esc-Xml $actualVal)</dcscor:value>" }
|
||||
elseif ($actualVal -eq "true" -or $actualVal -eq "false") { X "$indent`t<dcscor:value xsi:type=`"xs:boolean`">$actualVal</dcscor:value>" }
|
||||
elseif ($key -eq "Текст" -or $key -eq "Заголовок" -or $key -eq "Формат") { Emit-MLText -tag "dcscor:value" -text $actualVal -indent "$indent`t" }
|
||||
elseif ($key -eq "Текст" -or $key -eq "Заголовок" -or $key -eq "Формат") {
|
||||
# Текст/Заголовок/Формат: голая строка = плоский xs:string (так платформа хранит
|
||||
# нелокализованный литерал). Локализуемый текст → объект {ru,en} (ветка isDict выше).
|
||||
# Пустая строка → самозакрывающийся тег (как у платформы).
|
||||
if ($actualVal -eq '') { X "$indent`t<dcscor:value xsi:type=`"xs:string`"/>" }
|
||||
else { X "$indent`t<dcscor:value xsi:type=`"xs:string`">$(Esc-Xml $actualVal)</dcscor:value>" }
|
||||
}
|
||||
elseif ($actualVal -match '^-?\d+(\.\d+)?$') { X "$indent`t<dcscor:value xsi:type=`"xs:decimal`">$actualVal</dcscor:value>" }
|
||||
elseif ($key -eq 'ЦветТекста' -or $key -eq 'ЦветФона' -or $key -eq 'ЦветГраницы') { X "$indent`t<dcscor:value xsi:type=`"v8ui:Color`">$(Esc-Xml $actualVal)</dcscor:value>" }
|
||||
else { X "$indent`t<dcscor:value xsi:type=`"xs:string`">$(Esc-Xml $actualVal)</dcscor:value>" }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# form-compile v1.115 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.116 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import copy
|
||||
@@ -1300,11 +1300,12 @@ def emit_ml_items(lines, indent, val):
|
||||
lines.append(f"{indent}</v8:item>")
|
||||
|
||||
|
||||
def emit_mltext(lines, indent, tag, text):
|
||||
def emit_mltext(lines, indent, tag, text, xsi_type=None):
|
||||
attr = f' xsi:type="{xsi_type}"' if xsi_type else ''
|
||||
if not text:
|
||||
lines.append(f"{indent}<{tag}/>")
|
||||
lines.append(f"{indent}<{tag}{attr}/>")
|
||||
return
|
||||
lines.append(f"{indent}<{tag}>")
|
||||
lines.append(f"{indent}<{tag}{attr}>")
|
||||
emit_ml_items(lines, f"{indent}\t", text)
|
||||
lines.append(f"{indent}</{tag}>")
|
||||
|
||||
@@ -1606,8 +1607,12 @@ def emit_appearance_value(lines, key, val, indent):
|
||||
if av is not None:
|
||||
attr_parts.append(f'{attr_name}="{esc_xml(str(av))}"')
|
||||
lines.append(f'{indent}\t<dcscor:value xsi:type="v8ui:Font" {" ".join(attr_parts)}/>')
|
||||
elif is_dict and _has_key(inner_val, 'field'):
|
||||
# Ссылка на поле (dcscor:Field) — значение параметра оформления = поле компоновки
|
||||
lines.append(f'{indent}\t<dcscor:value xsi:type="dcscor:Field">{esc_xml(str(_get(inner_val, "field")))}</dcscor:value>')
|
||||
elif is_dict:
|
||||
emit_mltext(lines, f'{indent}\t', 'dcscor:value', inner_val)
|
||||
# Локализуемый текст параметра оформления: платформа объявляет xsi:type на dcscor:value
|
||||
emit_mltext(lines, f'{indent}\t', 'dcscor:value', inner_val, xsi_type='v8:LocalStringType')
|
||||
else:
|
||||
actual_val = str(inner_val)
|
||||
key_type_map = {
|
||||
@@ -1626,7 +1631,12 @@ def emit_appearance_value(lines, key, val, indent):
|
||||
elif actual_val == 'true' or actual_val == 'false':
|
||||
lines.append(f'{indent}\t<dcscor:value xsi:type="xs:boolean">{actual_val}</dcscor:value>')
|
||||
elif key == 'Текст' or key == 'Заголовок' or key == 'Формат':
|
||||
emit_mltext(lines, f'{indent}\t', 'dcscor:value', actual_val)
|
||||
# Голая строка = плоский xs:string (нелокализованный литерал). Локализуемый → объект {ru,en}.
|
||||
# Пустая строка → самозакрывающийся тег (как у платформы).
|
||||
if actual_val == '':
|
||||
lines.append(f'{indent}\t<dcscor:value xsi:type="xs:string"/>')
|
||||
else:
|
||||
lines.append(f'{indent}\t<dcscor:value xsi:type="xs:string">{esc_xml(actual_val)}</dcscor:value>')
|
||||
elif re.match(r'^-?\d+(\.\d+)?$', actual_val):
|
||||
lines.append(f'{indent}\t<dcscor:value xsi:type="xs:decimal">{actual_val}</dcscor:value>')
|
||||
elif key == 'ЦветТекста' or key == 'ЦветФона' or key == 'ЦветГраницы':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# form-decompile v0.91 — Decompile 1C managed Form.xml to JSON DSL (draft)
|
||||
# form-decompile v0.92 — Decompile 1C managed Form.xml to JSON DSL (draft)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
|
||||
param(
|
||||
@@ -407,14 +407,26 @@ function Get-LineValue {
|
||||
return $obj
|
||||
}
|
||||
|
||||
# Прочитать <dcscor:value> в JSON-значение: Font/Line/multilang/raw text.
|
||||
# Прочитать <dcscor:value> в JSON-значение: Font/Line/Field/multilang/raw text.
|
||||
function Read-AppearanceValueNode {
|
||||
param($valNode)
|
||||
if (-not $valNode) { return $null }
|
||||
$vt = Get-LocalXsiType $valNode
|
||||
if ($vt -eq 'LocalStringType') { return (Get-MLText $valNode) }
|
||||
if ($vt -eq 'LocalStringType') {
|
||||
# НЕ схлопываем одноязычный в строку: значение параметра оформления различает
|
||||
# xs:string (плоская строка) и LocalStringType (локализуемый текст) — обе формы
|
||||
# одноязычно дают одну строку. Всегда объект-карта языков → компилятор эмитит LocalStringType.
|
||||
$map = [ordered]@{}
|
||||
foreach ($it in @($valNode.SelectNodes("v8:item", $ns))) {
|
||||
$lang = $it.SelectSingleNode("v8:lang", $ns); $content = $it.SelectSingleNode("v8:content", $ns)
|
||||
if ($lang) { $map[$lang.InnerText] = if ($content) { $content.InnerText } else { "" } }
|
||||
}
|
||||
return $map
|
||||
}
|
||||
if ($vt -eq 'Font') { return (Get-FontValue $valNode) }
|
||||
if ($vt -eq 'Line') { return (Get-LineValue $valNode) }
|
||||
# dcscor:Field — значение = ссылка на поле компоновки → объект {field:путь}
|
||||
if ($vt -eq 'Field') { return [ordered]@{ field = $valNode.InnerText } }
|
||||
return $valNode.InnerText
|
||||
}
|
||||
|
||||
|
||||
@@ -976,6 +976,7 @@ Forgiving-синонимы типа: XML-имя (`SpreadSheetDocumentField`) и
|
||||
- **order** — строка `"Поле"` (asc) / `"Поле desc"` (синонимы `убыв`/`desc`, `возр`/`asc`) / `"Auto"`, либо объект `{ field, direction?, use?, viewMode? }`.
|
||||
- **filter** — shorthand `"Поле оператор значение @флаги"` (`@off`, `@user`, `@quickAccess`, `@normal`, `@inaccessible`; `_` = пусто) или объект `{ field, op, value?, use?, userSettingID? }` или группа `{ group: "And"|"Or"|"Not", items: [...] }`.
|
||||
- **conditionalAppearance** — объект `{ selection?, filter?, appearance?, presentation?, viewMode?, userSettingID?, use? }`. `appearance` — словарь «параметр: значение» платформы (`ЦветТекста`, `ЦветФона`, `Шрифт` и т.п.).
|
||||
- Значение текстовых параметров (`Текст`/`Заголовок`/`Формат`) ведётся **по форме значения**: голая строка → плоский `xs:string` (нелокализованный литерал; `""` → самозакрывающийся тег); объект `{ru,en}` → локализуемый `LocalStringType`; объект `{field:"путь"}` → ссылка на поле компоновки (`dcscor:Field`). (В отличие от `title`/`tooltip`, где голая строка = `LocalStringType` — здесь это намеренное scoped-различие: платформа хранит обе формы, и их надо различать.)
|
||||
|
||||
`userSettingID: "auto"` → платформа сгенерирует идентификатор пользовательской настройки. Пустые контейнеры (без правил) эмитируются автоматически.
|
||||
|
||||
|
||||
@@ -69,8 +69,11 @@
|
||||
{ "name": "ЧисловоеПоле", "type": "number(10,2)" }
|
||||
],
|
||||
"conditionalAppearance": [
|
||||
{ "selection": ["ОбычноеПоле"], "filter": ["ЧисловоеПоле > 100"], "appearance": { "ЦветФона": "style:FormBackColor" },
|
||||
"presentation": { "ru": "Подсветка", "en": "Highlight" } }
|
||||
{ "selection": ["ОбычноеПоле"], "filter": ["ЧисловоеПоле > 100"], "appearance": { "ЦветФона": "style:FormBackColor", "Текст": "Плоский текст" },
|
||||
"presentation": { "ru": "Подсветка", "en": "Highlight" } },
|
||||
{ "filter": ["ЧисловоеПоле = 0"], "appearance": { "Текст": { "ru": "Локализованный", "en": "Localized" } } },
|
||||
{ "filter": ["ЧисловоеПоле < 0"], "appearance": { "Текст": "" } },
|
||||
{ "filter": ["ЧисловоеПоле = 1"], "appearance": { "Текст": { "field": "ОбычноеПоле" } } }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+61
@@ -629,6 +629,10 @@
|
||||
<dcscor:parameter>ЦветФона</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8ui:Color">style:FormBackColor</dcscor:value>
|
||||
</dcscor:item>
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:parameter>Текст</dcscor:parameter>
|
||||
<dcscor:value xsi:type="xs:string">Плоский текст</dcscor:value>
|
||||
</dcscor:item>
|
||||
</dcsset:appearance>
|
||||
<dcsset:presentation xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
@@ -641,6 +645,63 @@
|
||||
</v8:item>
|
||||
</dcsset:presentation>
|
||||
</dcsset:item>
|
||||
<dcsset:item>
|
||||
<dcsset:selection/>
|
||||
<dcsset:filter>
|
||||
<dcsset:item xsi:type="dcsset:FilterItemComparison">
|
||||
<dcsset:left xsi:type="dcscor:Field">ЧисловоеПоле</dcsset:left>
|
||||
<dcsset:comparisonType>Equal</dcsset:comparisonType>
|
||||
<dcsset:right xsi:type="xs:decimal">0</dcsset:right>
|
||||
</dcsset:item>
|
||||
</dcsset:filter>
|
||||
<dcsset:appearance>
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:parameter>Текст</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Локализованный</v8:content>
|
||||
</v8:item>
|
||||
<v8:item>
|
||||
<v8:lang>en</v8:lang>
|
||||
<v8:content>Localized</v8:content>
|
||||
</v8:item>
|
||||
</dcscor:value>
|
||||
</dcscor:item>
|
||||
</dcsset:appearance>
|
||||
</dcsset:item>
|
||||
<dcsset:item>
|
||||
<dcsset:selection/>
|
||||
<dcsset:filter>
|
||||
<dcsset:item xsi:type="dcsset:FilterItemComparison">
|
||||
<dcsset:left xsi:type="dcscor:Field">ЧисловоеПоле</dcsset:left>
|
||||
<dcsset:comparisonType>Less</dcsset:comparisonType>
|
||||
<dcsset:right xsi:type="xs:decimal">0</dcsset:right>
|
||||
</dcsset:item>
|
||||
</dcsset:filter>
|
||||
<dcsset:appearance>
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:parameter>Текст</dcscor:parameter>
|
||||
<dcscor:value xsi:type="xs:string"/>
|
||||
</dcscor:item>
|
||||
</dcsset:appearance>
|
||||
</dcsset:item>
|
||||
<dcsset:item>
|
||||
<dcsset:selection/>
|
||||
<dcsset:filter>
|
||||
<dcsset:item xsi:type="dcsset:FilterItemComparison">
|
||||
<dcsset:left xsi:type="dcscor:Field">ЧисловоеПоле</dcsset:left>
|
||||
<dcsset:comparisonType>Equal</dcsset:comparisonType>
|
||||
<dcsset:right xsi:type="xs:decimal">1</dcsset:right>
|
||||
</dcsset:item>
|
||||
</dcsset:filter>
|
||||
<dcsset:appearance>
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:parameter>Текст</dcscor:parameter>
|
||||
<dcscor:value xsi:type="dcscor:Field">ОбычноеПоле</dcscor:value>
|
||||
</dcscor:item>
|
||||
</dcsset:appearance>
|
||||
</dcsset:item>
|
||||
</ConditionalAppearance>
|
||||
</Attributes>
|
||||
</Form>
|
||||
|
||||
Reference in New Issue
Block a user