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): InputField choice-скаляры verbatim + Button Check + FixingInTable + слой рус.синонимов ключей
Раундтрип TOTAL 121→86 (−35), match 114→124. - InputField choice-кнопки: захват/эмит «как есть» (ChoiceButton/ClearButton/ DropListButton/SpinButton эмитились только при true, теряя явный false; ChoiceButton=true сидел под лишним StartChoice-гейтом). Убран дефолт choiceButton=true у ref-полей в from-object — вывод не изменился. - Новые InputField-скаляры: choiceListButton/quickChoice/autoChoiceIncomplete (bool), choiceForm/choiceHistoryOnInput/choiceFoldersAndItems/footerDataPath (value). - Button checked → <Check>true</Check> (пометка toggle-кнопки). Ключ checked, не check (check — тип-ключ CheckBoxField, был бы конфликт диспетчера типов). - fixingInTable — в generic-скаляры (input/labelField/колонки). - Общий слой русских синонимов ключей-свойств ($propSynonyms/PROP_SYNONYMS): Пометка/Заголовок/Ширина/КнопкаВыбора/ФормаВыбора/… → канон. Нормализация в Emit-Element рядом с тип-синонимами; case/space-insensitive; англ. побеждает. Зеркало py (контент байт-в-байт). Кейсы input-fields/table/synonyms расширены и сертифицированы загрузкой в 1С. Регресс 39/39 зелёный в обоих рантаймах. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# form-compile v1.84 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.86 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$JsonPath,
|
||||
@@ -380,10 +380,9 @@ function New-FieldElement {
|
||||
|
||||
$el = [ordered]@{ $elType = $attrName; path = $dataPath }
|
||||
|
||||
# Apply ref defaults
|
||||
if ($isRef -and $fieldDefaults -and $fieldDefaults.ref) {
|
||||
if ($fieldDefaults.ref.choiceButton -eq $true) { $el["choiceButton"] = $true }
|
||||
}
|
||||
# (ChoiceButton у ref-полей платформа выводит сама; компилятор эмитит true по StartChoice-эвристике.
|
||||
# Явный choiceButton из декомпиляции эмитится verbatim. Дефолт-«true» здесь НЕ ставим, чтобы
|
||||
# from-object вывод совпадал с сертифицированным и не плодил ChoiceButton на каждом ref-поле.)
|
||||
|
||||
# Extra props
|
||||
if ($extraProps) {
|
||||
@@ -2527,6 +2526,20 @@ function Emit-Element {
|
||||
}
|
||||
}
|
||||
|
||||
# Синонимы ключей-свойств (русские имена 1С → канон. англ.). Case/space-insensitive.
|
||||
# Канон побеждает: если задан и русский, и англ. ключ — англ. остаётся, русский отбрасываем.
|
||||
foreach ($pn in @($el.PSObject.Properties.Name)) {
|
||||
$norm = ($pn -replace '\s','').ToLower()
|
||||
$canon = $script:propSynonyms[$norm]
|
||||
if ($canon -and $pn -ne $canon) {
|
||||
if ($null -eq $el.PSObject.Properties[$canon]) {
|
||||
$val = $el.($pn)
|
||||
$el | Add-Member -NotePropertyName $canon -NotePropertyValue $val -Force
|
||||
}
|
||||
$el.PSObject.Properties.Remove($pn) | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
# Determine element type from key
|
||||
$typeKey = $null
|
||||
$xmlTag = $null
|
||||
@@ -2614,12 +2627,18 @@ function Emit-Element {
|
||||
# generic-скаляры (pass-through) + точечные
|
||||
"verticalAlign"=1;"throughAlign"=1;"enableContentChange"=1;"pictureSize"=1;"titleHeight"=1
|
||||
"childItemsWidth"=1;"showLeftMargin"=1;"cellHyperlink"=1;"viewMode"=1;"verticalScrollBar"=1
|
||||
"rowInputMode"=1;"mask"=1;"createButton"=1
|
||||
"rowInputMode"=1;"mask"=1;"createButton"=1;"fixingInTable"=1
|
||||
# InputField choice-скаляры
|
||||
"choiceListButton"=1;"quickChoice"=1;"autoChoiceIncomplete"=1
|
||||
"choiceForm"=1;"choiceHistoryOnInput"=1;"footerDataPath"=1
|
||||
# Button — пометка toggle-кнопки (ключ 'checked', не 'check' — во избежание конфликта с типом)
|
||||
"checked"=1
|
||||
}
|
||||
# Оформление (цвета/шрифты/граница) — авто-регистрация из самих структур, чтобы allowlist
|
||||
# не дрейфовал при добавлении новых ключей/синонимов. Канонические + forgiving-синонимы.
|
||||
foreach ($k in $script:appearanceSpec.Keys) { $knownKeys[$k] = 1 }
|
||||
foreach ($k in $script:appearanceSynonyms.Keys) { $knownKeys[$k] = 1 }
|
||||
foreach ($k in $script:propSynonyms.Keys) { $knownKeys[$k] = 1 }
|
||||
foreach ($p in $el.PSObject.Properties) {
|
||||
if ($p.Name -like '_*') { continue } # внутренние маркеры (напр. _dynList)
|
||||
if (-not $knownKeys.ContainsKey($p.Name)) {
|
||||
@@ -2782,6 +2801,22 @@ $script:appearanceSynonyms = @{
|
||||
'цветтекстаподвала'='footerTextColor'; 'цветфонаподвала'='footerBackColor'; 'шрифтподвала'='footerFont'
|
||||
'шрифт'='font'; 'рамка'='border'
|
||||
}
|
||||
# Синонимы ключей-свойств: русские имена свойств 1С (как в Конфигураторе) → канон. англ. ключ.
|
||||
# Ключи карты нормализованы (lowercase, без пробелов); сопоставление в Normalize-PropSynonyms тоже.
|
||||
# Прощающий ввод: модель может писать свойство по-русски. Англ. ключ работает всегда (это доп. слой).
|
||||
# Видимость/Доступность НЕ включаем — наш hidden/disabled инвертирован, был бы баг семантики.
|
||||
$script:propSynonyms = @{
|
||||
'пометка'='checked'
|
||||
'кнопкавыбора'='choiceButton'; 'кнопкаочистки'='clearButton'; 'кнопкарегулирования'='spinButton'
|
||||
'кнопкавыпадающегосписка'='dropListButton'; 'кнопкасписковоговыбора'='choiceListButton'
|
||||
'кнопкаоткрытия'='openButton'; 'кнопкапоумолчанию'='defaultButton'
|
||||
'быстрыйвыбор'='quickChoice'; 'формавыбора'='choiceForm'; 'историявыборапривводе'='choiceHistoryOnInput'
|
||||
'выборгруппиэлементов'='choiceFoldersAndItems'; 'фиксациявтаблице'='fixingInTable'
|
||||
'путькданнымподвала'='footerDataPath'; 'автоотметканезаполненного'='markIncomplete'
|
||||
'многострочныйрежим'='multiLine'; 'режимпароля'='passwordMode'; 'переноспословам'='wrap'
|
||||
'расположениезаголовка'='titleLocation'; 'пропускатьпривводе'='skipOnInput'
|
||||
'заголовок'='title'; 'ширина'='width'; 'высота'='height'; 'подсказкаввода'='inputHint'
|
||||
}
|
||||
# Профили порядка тегов по базовым типам (XSD-последовательность)
|
||||
$script:appOrderField = @('titleTextColor','titleBackColor','titleFont','footerTextColor','footerBackColor','footerFont','textColor','backColor','borderColor','border','font')
|
||||
$script:appOrderDecoration = @('textColor','font','backColor','borderColor','border')
|
||||
@@ -2803,6 +2838,7 @@ $script:genericScalars = @(
|
||||
@{ Tag='RowInputMode'; Key='rowInputMode'; Kind='value' }
|
||||
@{ Tag='Mask'; Key='mask'; Kind='value' }
|
||||
@{ Tag='CreateButton'; Key='createButton'; Kind='bool' }
|
||||
@{ Tag='FixingInTable'; Key='fixingInTable'; Kind='value' }
|
||||
)
|
||||
|
||||
function Emit-GenericScalars {
|
||||
@@ -3107,11 +3143,14 @@ function Emit-Input {
|
||||
|
||||
if ($el.multiLine -eq $true) { X "$inner<MultiLine>true</MultiLine>" }
|
||||
if ($el.passwordMode -eq $true) { X "$inner<PasswordMode>true</PasswordMode>" }
|
||||
if ($el.choiceButton -eq $false) { X "$inner<ChoiceButton>false</ChoiceButton>" }
|
||||
elseif ($el.choiceButton -eq $true -and (Test-ElementEvent $el 'StartChoice')) { X "$inner<ChoiceButton>true</ChoiceButton>" }
|
||||
if ($el.clearButton -eq $true) { X "$inner<ClearButton>true</ClearButton>" }
|
||||
if ($el.spinButton -eq $true) { X "$inner<SpinButton>true</SpinButton>" }
|
||||
if ($el.dropListButton -eq $true) { X "$inner<DropListButton>true</DropListButton>" }
|
||||
# ChoiceButton — захват «как есть» (платформа эмитит явное значение; ref-поля выводят сама,
|
||||
# декомпилятор фиксирует факт. значение). Нет ключа → не эмитим (не додумываем по событию).
|
||||
if ($null -ne $el.choiceButton) { X "$inner<ChoiceButton>$(if ($el.choiceButton){'true'}else{'false'})</ChoiceButton>" }
|
||||
# Кнопки поля ввода — захват «как есть» (платформа эмитит явное значение, в т.ч. false)
|
||||
if ($null -ne $el.clearButton) { X "$inner<ClearButton>$(if ($el.clearButton){'true'}else{'false'})</ClearButton>" }
|
||||
if ($null -ne $el.spinButton) { X "$inner<SpinButton>$(if ($el.spinButton){'true'}else{'false'})</SpinButton>" }
|
||||
if ($null -ne $el.dropListButton) { X "$inner<DropListButton>$(if ($el.dropListButton){'true'}else{'false'})</DropListButton>" }
|
||||
if ($null -ne $el.choiceListButton) { X "$inner<ChoiceListButton>$(if ($el.choiceListButton){'true'}else{'false'})</ChoiceListButton>" }
|
||||
if ($el.markIncomplete -eq $true) { X "$inner<AutoMarkIncomplete>true</AutoMarkIncomplete>" }
|
||||
if ($el.editMode) { X "$inner<EditMode>$($el.editMode)</EditMode>" }
|
||||
Emit-ColumnPics -el $el -indent $inner
|
||||
@@ -3119,10 +3158,18 @@ function Emit-Input {
|
||||
# InputField-специфичные скаляры (захват «как есть»: платформа эмитит явное не-дефолтное значение)
|
||||
foreach ($p in @(
|
||||
@('wrap','Wrap'), @('openButton','OpenButton'), @('listChoiceMode','ListChoiceMode'),
|
||||
@('extendedEditMultipleValues','ExtendedEditMultipleValues'), @('chooseType','ChooseType')
|
||||
@('extendedEditMultipleValues','ExtendedEditMultipleValues'), @('chooseType','ChooseType'),
|
||||
@('quickChoice','QuickChoice'), @('autoChoiceIncomplete','AutoChoiceIncomplete')
|
||||
)) {
|
||||
if ($null -ne $el.($p[0])) { X "$inner<$($p[1])>$(if ($el.($p[0])){'true'}else{'false'})</$($p[1])>" }
|
||||
}
|
||||
# InputField-специфичные value-скаляры
|
||||
foreach ($p in @(
|
||||
@('choiceForm','ChoiceForm'), @('choiceHistoryOnInput','ChoiceHistoryOnInput'),
|
||||
@('choiceFoldersAndItems','ChoiceFoldersAndItems'), @('footerDataPath','FooterDataPath')
|
||||
)) {
|
||||
if ($el.($p[0])) { X "$inner<$($p[1])>$(Esc-Xml "$($el.($p[0]))")</$($p[1])>" }
|
||||
}
|
||||
if ($el.choiceButtonRepresentation) { X "$inner<ChoiceButtonRepresentation>$($el.choiceButtonRepresentation)</ChoiceButtonRepresentation>" }
|
||||
Emit-Layout -el $el -indent $inner -multiLineDefault ([bool]($el.multiLine -eq $true))
|
||||
|
||||
@@ -3935,6 +3982,9 @@ function Emit-Button {
|
||||
Emit-CommonFlags -el $el -indent $inner
|
||||
|
||||
if ($el.defaultButton -eq $true) { X "$inner<DefaultButton>true</DefaultButton>" }
|
||||
# Check (пометка toggle-кнопки командной панели) — платформа эмитит только true.
|
||||
# Ключ 'checked' (не 'check': 'check' — тип-ключ CheckBoxField, был бы конфликт диспетчера типов)
|
||||
if ($el.checked -eq $true) { X "$inner<Check>true</Check>" }
|
||||
|
||||
# Picture
|
||||
Emit-CommandPicture -pic $el.picture -elemLt $el.loadTransparent -indent $inner
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# form-compile v1.84 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.86 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import copy
|
||||
@@ -357,10 +357,9 @@ def new_field_element(attr_name, data_path, attr_type, field_defaults, extra_pro
|
||||
el[el_type] = attr_name
|
||||
el['path'] = data_path
|
||||
|
||||
# Apply ref defaults
|
||||
if is_ref and field_defaults and field_defaults.get('ref'):
|
||||
if field_defaults['ref'].get('choiceButton') is True:
|
||||
el['choiceButton'] = True
|
||||
# (ChoiceButton у ref-полей платформа выводит сама; компилятор эмитит true по StartChoice-эвристике.
|
||||
# Явный choiceButton из декомпиляции эмитится verbatim. Дефолт-«true» здесь НЕ ставим, чтобы
|
||||
# from-object вывод совпадал с сертифицированным и не плодил ChoiceButton на каждом ref-поле.)
|
||||
|
||||
# Extra props
|
||||
if extra_props:
|
||||
@@ -1816,7 +1815,12 @@ KNOWN_KEYS = {
|
||||
# generic-скаляры (pass-through)
|
||||
"verticalAlign", "throughAlign", "enableContentChange", "pictureSize", "titleHeight",
|
||||
"childItemsWidth", "showLeftMargin", "cellHyperlink", "viewMode", "verticalScrollBar",
|
||||
"rowInputMode", "mask", "createButton",
|
||||
"rowInputMode", "mask", "createButton", "fixingInTable",
|
||||
# InputField choice-скаляры
|
||||
"choiceListButton", "quickChoice", "autoChoiceIncomplete",
|
||||
"choiceForm", "choiceHistoryOnInput", "footerDataPath",
|
||||
# Button — пометка toggle-кнопки
|
||||
"checked",
|
||||
}
|
||||
|
||||
# picture/picField — НИЗКИЙ приоритет: 'picture' это и тип (PictureDecoration), и свойство-иконка
|
||||
@@ -2588,7 +2592,22 @@ APPEARANCE_SYNONYMS = {
|
||||
'цветтекстаподвала': 'footerTextColor', 'цветфонаподвала': 'footerBackColor', 'шрифтподвала': 'footerFont',
|
||||
'шрифт': 'font', 'рамка': 'border',
|
||||
}
|
||||
APP_ORDER_FIELD = ['titleTextColor', 'titleBackColor', 'titleFont', 'footerTextColor', 'footerBackColor', 'footerFont', 'textColor', 'backColor', 'borderColor', 'border', 'font']
|
||||
# Синонимы ключей-свойств: русские имена свойств 1С (как в Конфигураторе) → канон. англ. ключ.
|
||||
# Ключи нормализованы (lowercase, без пробелов); сопоставление в emit_element тоже. Англ. ключ
|
||||
# работает всегда (доп. слой прощающего ввода). Видимость/Доступность НЕ включаем (hidden/disabled инвертирован).
|
||||
PROP_SYNONYMS = {
|
||||
'пометка': 'checked',
|
||||
'кнопкавыбора': 'choiceButton', 'кнопкаочистки': 'clearButton', 'кнопкарегулирования': 'spinButton',
|
||||
'кнопкавыпадающегосписка': 'dropListButton', 'кнопкасписковоговыбора': 'choiceListButton',
|
||||
'кнопкаоткрытия': 'openButton', 'кнопкапоумолчанию': 'defaultButton',
|
||||
'быстрыйвыбор': 'quickChoice', 'формавыбора': 'choiceForm', 'историявыборапривводе': 'choiceHistoryOnInput',
|
||||
'выборгруппиэлементов': 'choiceFoldersAndItems', 'фиксациявтаблице': 'fixingInTable',
|
||||
'путькданнымподвала': 'footerDataPath', 'автоотметканезаполненного': 'markIncomplete',
|
||||
'многострочныйрежим': 'multiLine', 'режимпароля': 'passwordMode', 'переноспословам': 'wrap',
|
||||
'расположениезаголовка': 'titleLocation', 'пропускатьпривводе': 'skipOnInput',
|
||||
'заголовок': 'title', 'ширина': 'width', 'высота': 'height', 'подсказкаввода': 'inputHint',
|
||||
}
|
||||
APP_ORDER_FIELD =['titleTextColor', 'titleBackColor', 'titleFont', 'footerTextColor', 'footerBackColor', 'footerFont', 'textColor', 'backColor', 'borderColor', 'border', 'font']
|
||||
APP_ORDER_DECORATION = ['textColor', 'font', 'backColor', 'borderColor', 'border']
|
||||
APP_ORDER_BUTTON = ['textColor', 'backColor', 'borderColor', 'font']
|
||||
|
||||
@@ -2668,6 +2687,7 @@ GENERIC_SCALARS = [
|
||||
('RowInputMode', 'rowInputMode', 'value'),
|
||||
('Mask', 'mask', 'value'),
|
||||
('CreateButton', 'createButton', 'bool'),
|
||||
('FixingInTable', 'fixingInTable', 'value'),
|
||||
]
|
||||
|
||||
|
||||
@@ -2985,6 +3005,16 @@ def emit_element(lines, el, indent, in_cmd_bar=False):
|
||||
continue
|
||||
el[dst] = el.pop(src)
|
||||
|
||||
# Синонимы ключей-свойств (русские имена 1С → канон. англ.). Case/space-insensitive.
|
||||
# Канон побеждает: если задан и русский, и англ. ключ — англ. остаётся, русский отбрасываем.
|
||||
for p_name in list(el.keys()):
|
||||
norm = p_name.replace(' ', '').lower()
|
||||
canon = PROP_SYNONYMS.get(norm)
|
||||
if canon and p_name != canon:
|
||||
val = el.pop(p_name)
|
||||
if canon not in el:
|
||||
el[canon] = val
|
||||
|
||||
type_key = None
|
||||
for key in TYPE_KEYS:
|
||||
if el.get(key) is not None:
|
||||
@@ -3165,16 +3195,19 @@ def emit_input(lines, el, name, eid, indent):
|
||||
lines.append(f'{inner}<MultiLine>true</MultiLine>')
|
||||
if el.get('passwordMode') is True:
|
||||
lines.append(f'{inner}<PasswordMode>true</PasswordMode>')
|
||||
if el.get('choiceButton') is False:
|
||||
lines.append(f'{inner}<ChoiceButton>false</ChoiceButton>')
|
||||
elif el.get('choiceButton') is True and test_element_event(el, 'StartChoice'):
|
||||
lines.append(f'{inner}<ChoiceButton>true</ChoiceButton>')
|
||||
if el.get('clearButton') is True:
|
||||
lines.append(f'{inner}<ClearButton>true</ClearButton>')
|
||||
if el.get('spinButton') is True:
|
||||
lines.append(f'{inner}<SpinButton>true</SpinButton>')
|
||||
if el.get('dropListButton') is True:
|
||||
lines.append(f'{inner}<DropListButton>true</DropListButton>')
|
||||
# ChoiceButton — захват «как есть» (платформа эмитит явное значение; ref-поля выводят сама,
|
||||
# декомпилятор фиксирует факт. значение). Нет ключа → не эмитим (не додумываем по событию).
|
||||
if el.get('choiceButton') is not None:
|
||||
lines.append(f'{inner}<ChoiceButton>{"true" if el["choiceButton"] else "false"}</ChoiceButton>')
|
||||
# Кнопки поля ввода — захват «как есть» (платформа эмитит явное значение, в т.ч. false)
|
||||
if el.get('clearButton') is not None:
|
||||
lines.append(f'{inner}<ClearButton>{"true" if el["clearButton"] else "false"}</ClearButton>')
|
||||
if el.get('spinButton') is not None:
|
||||
lines.append(f'{inner}<SpinButton>{"true" if el["spinButton"] else "false"}</SpinButton>')
|
||||
if el.get('dropListButton') is not None:
|
||||
lines.append(f'{inner}<DropListButton>{"true" if el["dropListButton"] else "false"}</DropListButton>')
|
||||
if el.get('choiceListButton') is not None:
|
||||
lines.append(f'{inner}<ChoiceListButton>{"true" if el["choiceListButton"] else "false"}</ChoiceListButton>')
|
||||
if el.get('markIncomplete') is True:
|
||||
lines.append(f'{inner}<AutoMarkIncomplete>true</AutoMarkIncomplete>')
|
||||
if el.get('editMode'):
|
||||
@@ -3184,9 +3217,15 @@ def emit_input(lines, el, name, eid, indent):
|
||||
lines.append(f'{inner}<TextEdit>false</TextEdit>')
|
||||
# InputField-специфичные скаляры (захват «как есть»: платформа эмитит явное не-дефолтное значение)
|
||||
for key, tag in (('wrap', 'Wrap'), ('openButton', 'OpenButton'), ('listChoiceMode', 'ListChoiceMode'),
|
||||
('extendedEditMultipleValues', 'ExtendedEditMultipleValues'), ('chooseType', 'ChooseType')):
|
||||
('extendedEditMultipleValues', 'ExtendedEditMultipleValues'), ('chooseType', 'ChooseType'),
|
||||
('quickChoice', 'QuickChoice'), ('autoChoiceIncomplete', 'AutoChoiceIncomplete')):
|
||||
if el.get(key) is not None:
|
||||
lines.append(f'{inner}<{tag}>{"true" if el[key] else "false"}</{tag}>')
|
||||
# InputField-специфичные value-скаляры
|
||||
for key, tag in (('choiceForm', 'ChoiceForm'), ('choiceHistoryOnInput', 'ChoiceHistoryOnInput'),
|
||||
('choiceFoldersAndItems', 'ChoiceFoldersAndItems'), ('footerDataPath', 'FooterDataPath')):
|
||||
if el.get(key):
|
||||
lines.append(f'{inner}<{tag}>{esc_xml(str(el[key]))}</{tag}>')
|
||||
if el.get('choiceButtonRepresentation'):
|
||||
lines.append(f'{inner}<ChoiceButtonRepresentation>{el["choiceButtonRepresentation"]}</ChoiceButtonRepresentation>')
|
||||
emit_layout(lines, el, inner, multi_line_default=(el.get('multiLine') is True))
|
||||
@@ -3636,6 +3675,10 @@ def emit_button(lines, el, name, eid, indent, in_cmd_bar=False):
|
||||
|
||||
if el.get('defaultButton') is True:
|
||||
lines.append(f'{inner}<DefaultButton>true</DefaultButton>')
|
||||
# Check (пометка toggle-кнопки командной панели) — платформа эмитит только true.
|
||||
# Ключ 'checked' (не 'check': 'check' — тип-ключ CheckBoxField, был бы конфликт диспетчера типов)
|
||||
if el.get('checked') is True:
|
||||
lines.append(f'{inner}<Check>true</Check>')
|
||||
|
||||
# Picture
|
||||
emit_command_picture(lines, el.get('picture'), el.get('loadTransparent'), inner)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# form-decompile v0.61 — Decompile 1C managed Form.xml to JSON DSL (draft)
|
||||
# form-decompile v0.62 — Decompile 1C managed Form.xml to JSON DSL (draft)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
|
||||
param(
|
||||
@@ -1135,6 +1135,7 @@ $GENERIC_SCALARS = @(
|
||||
@{ Tag='RowInputMode'; Key='rowInputMode'; Kind='value' }
|
||||
@{ Tag='Mask'; Key='mask'; Kind='value' }
|
||||
@{ Tag='CreateButton'; Key='createButton'; Kind='bool' }
|
||||
@{ Tag='FixingInTable'; Key='fixingInTable'; Kind='value' }
|
||||
)
|
||||
|
||||
# Захват generic-скаляров. Специфичная обработка (если ключ уже задан) — побеждает.
|
||||
@@ -1376,13 +1377,17 @@ function Decompile-Element {
|
||||
$em = Get-Child $node 'EditMode'; if ($em) { $obj['editMode'] = $em }
|
||||
$tl = Get-Child $node 'TitleLocation'; if ($tl) { $obj['titleLocation'] = $tl.ToLower() }
|
||||
$ih = $node.SelectSingleNode("lf:InputHint", $ns); if ($ih) { $t = Get-LangText $ih; if ($t) { $obj['inputHint'] = $t } }
|
||||
foreach ($p in @('ChoiceButton','ClearButton','SpinButton','DropListButton')) {
|
||||
foreach ($p in @('ChoiceButton','ClearButton','SpinButton','DropListButton','ChoiceListButton')) {
|
||||
$v = Get-Child $node $p; if ($null -ne $v) { $obj[($p.Substring(0,1).ToLower()+$p.Substring(1))] = (To-Bool $v) }
|
||||
}
|
||||
# InputField-специфичные скаляры (захват «как есть»)
|
||||
foreach ($p in @('Wrap','OpenButton','ListChoiceMode','ExtendedEditMultipleValues','ChooseType')) {
|
||||
# InputField-специфичные bool-скаляры (захват «как есть»)
|
||||
foreach ($p in @('Wrap','OpenButton','ListChoiceMode','ExtendedEditMultipleValues','ChooseType','QuickChoice','AutoChoiceIncomplete')) {
|
||||
$v = Get-Child $node $p; if ($null -ne $v) { $obj[($p.Substring(0,1).ToLower()+$p.Substring(1))] = (To-Bool $v) }
|
||||
}
|
||||
# InputField-специфичные value-скаляры (захват «как есть»)
|
||||
foreach ($p in @('ChoiceForm','ChoiceHistoryOnInput','ChoiceFoldersAndItems','FooterDataPath')) {
|
||||
$v = Get-Child $node $p; if ($null -ne $v) { $obj[($p.Substring(0,1).ToLower()+$p.Substring(1))] = $v }
|
||||
}
|
||||
$cbr = Get-Child $node 'ChoiceButtonRepresentation'; if ($cbr) { $obj['choiceButtonRepresentation'] = $cbr }
|
||||
if ((Get-Child $node 'TextEdit') -eq 'false') { $obj['textEdit'] = $false }
|
||||
$cl = Decompile-ChoiceList $node; if ($cl) { $obj['choiceList'] = $cl }
|
||||
@@ -1554,6 +1559,7 @@ function Decompile-Element {
|
||||
$type = Get-Child $node 'Type'
|
||||
if ($type) { $tmap=@{'CommandBarButton'='commandBar';'UsualButton'='usual';'Hyperlink'='hyperlink';'CommandBarHyperlink'='hyperlink'}; if ($tmap.ContainsKey($type)) { $obj['type']=$tmap[$type] } else { $obj['type']=$type } }
|
||||
if ((Get-Child $node 'DefaultButton') -eq 'true') { $obj['defaultButton'] = $true }
|
||||
if ((Get-Child $node 'Check') -eq 'true') { $obj['checked'] = $true }
|
||||
$ref = $node.SelectSingleNode("lf:Picture/xr:Ref", $ns); if ($ref) { $obj['picture'] = $ref.InnerText }
|
||||
# Дефолт у picture кнопки/попапа = true → фиксируем только отклонение false (true опускаем)
|
||||
$lt = $node.SelectSingleNode("lf:Picture/xr:LoadTransparent", $ns); if ($lt -and $lt.InnerText -eq 'false') { $obj['loadTransparent'] = $false }
|
||||
|
||||
@@ -135,6 +135,10 @@
|
||||
|
||||
Флаг авто-детектится по наличию известной разметки/`</>`: для plain-строки объект не нужен. Явная форма `{text, formatted}` — только когда авто-детект неверен (formatted-текст без разметки, либо буквальные `<…>`-плейсхолдеры в неформатированном).
|
||||
|
||||
#### Русские синонимы ключей-свойств (прощающий ввод)
|
||||
|
||||
Скалярные свойства элементов можно писать русскими именами 1С (как в Конфигураторе) — компилятор молча нормализует их в канонические англ. ключи. Сопоставление **регистро- и пробело-независимое** (`Пометка` = `пометка`, `Быстрый выбор` = `быстрыйВыбор`). Англ. ключ работает всегда; если заданы оба — побеждает англ. Поддержаны (в т.ч.): `Пометка`→`checked`, `Заголовок`→`title`, `Ширина`→`width`, `Высота`→`height`, `КнопкаВыбора`→`choiceButton`, `КнопкаОчистки`→`clearButton`, `КнопкаВыпадающегоСписка`→`dropListButton`, `КнопкаСписковогоВыбора`→`choiceListButton`, `БыстрыйВыбор`→`quickChoice`, `ФормаВыбора`→`choiceForm`, `ИсторияВыбораПриВводе`→`choiceHistoryOnInput`, `ВыборГруппИЭлементов`→`choiceFoldersAndItems`, `ФиксацияВТаблице`→`fixingInTable`, `ПутьКДаннымПодвала`→`footerDataPath`, `МногострочныйРежим`→`multiLine`, `РежимПароля`→`passwordMode`, `РасположениеЗаголовка`→`titleLocation`. (`Видимость`/`Доступность` НЕ синонимы — у нас `hidden`/`disabled` с обратной полярностью.) Оформление имеет свой набор рус. синонимов (§4.1e).
|
||||
|
||||
### 4.1c. Доступ по ролям (`userVisible` / `view` / `edit` / `use`)
|
||||
|
||||
Единый механизм платформы (role-adjustable boolean): «общее значение + исключения по ролям».
|
||||
@@ -373,6 +377,14 @@ companion-панели с собственным контентом. Оба не
|
||||
| `listChoiceMode` | bool | Режим выбора из списка (`<ListChoiceMode>`) |
|
||||
| `extendedEditMultipleValues` | bool | Расширенное редактирование нескольких значений |
|
||||
| `chooseType` | bool | Выбор типа (`<ChooseType>`) |
|
||||
| `choiceListButton` | bool | Кнопка списочного выбора (`<ChoiceListButton>`) |
|
||||
| `quickChoice` | bool | Быстрый выбор (`<QuickChoice>`) |
|
||||
| `autoChoiceIncomplete` | bool | Автоматический выбор незаполненного (`<AutoChoiceIncomplete>`) |
|
||||
| `choiceForm` | string | Форма выбора (`<ChoiceForm>`), напр. `Catalog.X.Form.ФормаВыбора` |
|
||||
| `choiceHistoryOnInput` | string | История выбора при вводе (`<ChoiceHistoryOnInput>`): `Auto`, `DontUse` |
|
||||
| `choiceFoldersAndItems` | string | Выбор групп и элементов (`<ChoiceFoldersAndItems>`): `Items`, `Folders`, `FoldersAndItems` |
|
||||
| `fixingInTable` | string | Фиксация колонки в таблице (`<FixingInTable>`): `Left`, `Right`, `None`. Так же у `labelField` и др. полей |
|
||||
| `footerDataPath` | string | DataPath подвала колонки таблицы (`<FooterDataPath>`) |
|
||||
| `choiceButtonRepresentation` | string | `ShowInInputField`, `ShowInDropList`, `ShowInDropListAndInInputField` |
|
||||
| `width` | int | Ширина |
|
||||
| `height` | int | Высота |
|
||||
@@ -623,6 +635,7 @@ Pages поддерживает `pagesRepresentation`: `None`, `TabsOnTop`, `Tabs
|
||||
| `stdCommand` | string | Стандартная команда (→ `Form.StandardCommand.<name>`; `X.Y` → `Form.Item.X.StandardCommand.Y`) |
|
||||
| `type` | string | `usual`, `hyperlink`, `commandBar` |
|
||||
| `defaultButton` | bool | Кнопка по умолчанию |
|
||||
| `checked` | bool | Пометка (нажатое состояние toggle-кнопки командной панели) → `<Check>true</Check>`. Платформа эмитит только `true`. Ключ `checked` (не `check` — `check` — тип-ключ ПоляФлажка) |
|
||||
| `picture` | string \| object | Ссылка на картинку (`StdPicture.Name`). Скаляр-строка ИЛИ объект `{src, loadTransparent}` (прощающий ввод — флаг можно задать прямо в объекте) |
|
||||
| `loadTransparent` | bool | Загружать картинку прозрачной (у `<Picture>` кнопки/команды/попапа). **Дефолт `true`** (эмитится всегда; `false` — явно). Элемент-уровневый ключ ИЛИ поле объекта `picture`. Также у `command` (§7) и `popup`. ⚠️ Полярность обратна `headerPicture`/`valuesPicture` (там дефолт `false`, см. §4.1) |
|
||||
| `path` | string | DataPath кнопки общей команды (`Объект.Ref`, `Items.X.CurrentData.Поле`) — привязка к контексту |
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
{ "labelField": "Ссылка", "path": "ОбычноеПоле", "titleLocation": "left", "hyperlink": true, "format": { "ru": "ДЛФ=D", "en": "DLF=D" } },
|
||||
{ "input": "МногострочноеПоле", "path": "МногострочноеПоле", "multiLine": true, "height": 5, "title": "Комментарий", "wrap": false, "showInHeader": false, "showInFooter": false, "autoCellHeight": true, "footerHorizontalAlign": "Right", "openButton": false, "chooseType": false },
|
||||
{ "input": "ПолеПароля", "path": "ПолеПароля", "passwordMode": true, "title": "Пароль" },
|
||||
{ "input": "ПолеСКнопками", "path": "ПолеСКнопками", "choiceButton": true, "clearButton": true, "title": "Выбор" },
|
||||
{ "input": "ПолеСКнопками", "path": "ПолеСКнопками", "choiceButton": true, "clearButton": true, "dropListButton": false, "spinButton": true, "choiceListButton": true, "quickChoice": false, "autoChoiceIncomplete": true, "choiceHistoryOnInput": "DontUse", "choiceForm": "DataProcessor.ПоляВвода.Form.Форма", "title": "Выбор" },
|
||||
{ "input": "ПолеСписокВыбора", "path": "ПолеСписокВыбора", "title": "Список выбора", "choiceList": [
|
||||
{ "value": "", "presentation": "Все" },
|
||||
{ "value": "Первый" },
|
||||
|
||||
+8
@@ -109,7 +109,15 @@
|
||||
<v8:content>Выбор</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<ChoiceButton>true</ChoiceButton>
|
||||
<ClearButton>true</ClearButton>
|
||||
<SpinButton>true</SpinButton>
|
||||
<DropListButton>false</DropListButton>
|
||||
<ChoiceListButton>true</ChoiceListButton>
|
||||
<QuickChoice>false</QuickChoice>
|
||||
<AutoChoiceIncomplete>true</AutoChoiceIncomplete>
|
||||
<ChoiceForm>DataProcessor.ПоляВвода.Form.Форма</ChoiceForm>
|
||||
<ChoiceHistoryOnInput>DontUse</ChoiceHistoryOnInput>
|
||||
<ContextMenu name="ПолеСКнопкамиКонтекстноеМеню" id="14"/>
|
||||
<ExtendedTooltip name="ПолеСКнопкамиРасширеннаяПодсказка" id="15"/>
|
||||
</InputField>
|
||||
|
||||
+4
@@ -19,6 +19,9 @@
|
||||
<ChildItems>
|
||||
<InputField name="Поле" id="3">
|
||||
<DataPath>Поле</DataPath>
|
||||
<ChoiceButton>true</ChoiceButton>
|
||||
<QuickChoice>false</QuickChoice>
|
||||
<Width>15</Width>
|
||||
<ContextMenu name="ПолеКонтекстноеМеню" id="4"/>
|
||||
<ExtendedTooltip name="ПолеРасширеннаяПодсказка" id="5"/>
|
||||
</InputField>
|
||||
@@ -28,6 +31,7 @@
|
||||
<Button name="Кн2" id="8">
|
||||
<Type>CommandBarButton</Type>
|
||||
<CommandName>Form.Command.Кн2</CommandName>
|
||||
<Check>true</Check>
|
||||
<ExtendedTooltip name="Кн2РасширеннаяПодсказка" id="9"/>
|
||||
</Button>
|
||||
</ChildItems>
|
||||
|
||||
+2
@@ -41,6 +41,7 @@
|
||||
<Button name="ПанельОбновить" id="8">
|
||||
<Type>CommandBarButton</Type>
|
||||
<CommandName>Form.Command.Обновить</CommandName>
|
||||
<Check>true</Check>
|
||||
<ExtendedTooltip name="ПанельОбновитьРасширеннаяПодсказка" id="9"/>
|
||||
</Button>
|
||||
</ChildItems>
|
||||
@@ -73,6 +74,7 @@
|
||||
<ChildItems>
|
||||
<InputField name="Дата" id="20">
|
||||
<DataPath>Данные.Дата</DataPath>
|
||||
<FixingInTable>Left</FixingInTable>
|
||||
<ContextMenu name="ДатаКонтекстноеМеню" id="21"/>
|
||||
<ExtendedTooltip name="ДатаРасширеннаяПодсказка" id="22"/>
|
||||
</InputField>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "Синонимы commandBar/autoCommandBar нормализуются молча",
|
||||
"name": "Синонимы commandBar/autoCommandBar + русские имена свойств нормализуются молча",
|
||||
"preRun": [
|
||||
{
|
||||
"script": "meta-compile/scripts/meta-compile",
|
||||
@@ -23,9 +23,9 @@
|
||||
{ "autoCommandBar": "ФормаКоманднаяПанель", "children": [
|
||||
{ "button": "Кн1", "command": "Кн1" }
|
||||
]},
|
||||
{ "input": "Поле", "path": "Поле" },
|
||||
{ "input": "Поле", "path": "Поле", "КнопкаВыбора": true, "Быстрый выбор": false, "Ширина": 15 },
|
||||
{ "commandBar": "ДопПанель", "children": [
|
||||
{ "button": "Кн2", "command": "Кн2" }
|
||||
{ "button": "Кн2", "command": "Кн2", "Пометка": true }
|
||||
]}
|
||||
],
|
||||
"commands": [
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"viewStatusLocation": "None", "searchControlLocation": "None",
|
||||
"excludedCommands": ["Add", "Delete", "MoveUp", "MoveDown"],
|
||||
"commandBar": { "autofill": false, "children": [
|
||||
{ "button": "ПанельОбновить", "command": "Обновить" }
|
||||
{ "button": "ПанельОбновить", "command": "Обновить", "checked": true }
|
||||
]},
|
||||
"contextMenu": { "children": [
|
||||
{ "buttonGroup": "МенюГруппа", "children": [
|
||||
@@ -28,7 +28,7 @@
|
||||
]}
|
||||
]},
|
||||
"columns": [
|
||||
{ "input": "Дата", "path": "Данные.Дата" },
|
||||
{ "input": "Дата", "path": "Данные.Дата", "fixingInTable": "Left" },
|
||||
{ "input": "Сумма", "path": "Данные.Сумма" },
|
||||
{ "input": "Комментарий", "path": "Данные.Комментарий" }
|
||||
]}
|
||||
|
||||
Reference in New Issue
Block a user