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): Save — сохранение значения реквизита в польз. настройках
Ключ save на реквизите формы (<Save><Field>…): - true → <Field>имя</Field> (голое имя, 93% случаев) - строка/массив строк → под-поля с авто-префиксом "имя." (путь с точкой, UUID 1/0:guid, или совпадающее с именем — берутся как есть) - нет ключа или false → не эмитим Гипотеза подтверждена на корпусе: Field=имя в 383/410 (93%); gating формовыми SaveDataInSettings/AutoSaveDataInSettings НЕ требуется (51/160 форм с Save без них). Период-кейс (голое имя Период + Период.EndDate/StartDate/Variant) round-trip бит-в-бит. Переиспользует механику нормализации useAlways. ≠ savedData (отдельное, уже было). Декомпилятор: один Field=имя → save:true, иначе массив со снятым префиксом. Зеркало py (байт-в-байт), кейс attributes-types сертифицирован в 1С. Регресс 39/39 ps1+py. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# form-compile v1.75 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.76 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$JsonPath,
|
||||
@@ -4400,6 +4400,27 @@ function Emit-Attributes {
|
||||
if ($attr.savedData -eq $true -or $mainSaved) {
|
||||
X "$inner<SavedData>true</SavedData>"
|
||||
}
|
||||
# Save: сохранение значения реквизита в пользовательских настройках. true → <Field>имя</Field>;
|
||||
# строка/массив → под-поля с авто-префиксом "имя." (путь с точкой / UUID / =имя — как есть).
|
||||
# Нет ключа или false → не эмитим.
|
||||
if ($null -ne $attr.PSObject.Properties['save'] -and $null -ne $attr.save) {
|
||||
$saveFields = New-Object System.Collections.ArrayList
|
||||
if ($attr.save -is [bool]) {
|
||||
if ($attr.save) { [void]$saveFields.Add($attrName) }
|
||||
} else {
|
||||
foreach ($e in @($attr.save)) {
|
||||
$fld = "$e"
|
||||
if ([string]::IsNullOrEmpty($fld)) { continue }
|
||||
if ($fld -ne $attrName -and $fld -notmatch '\.' -and $fld -notmatch '^\d+/\d+:') { $fld = "$attrName.$fld" }
|
||||
if (-not $saveFields.Contains($fld)) { [void]$saveFields.Add($fld) }
|
||||
}
|
||||
}
|
||||
if ($saveFields.Count -gt 0) {
|
||||
X "$inner<Save>"
|
||||
foreach ($f in $saveFields) { X "$inner`t<Field>$(Esc-Xml $f)</Field>" }
|
||||
X "$inner</Save>"
|
||||
}
|
||||
}
|
||||
if ($attr.fillChecking) {
|
||||
X "$inner<FillChecking>$($attr.fillChecking)</FillChecking>"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# form-compile v1.75 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.76 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import copy
|
||||
@@ -4124,6 +4124,29 @@ def emit_attributes(lines, attrs, indent):
|
||||
main_saved = bool(re.match(r'^(CatalogObject|DocumentObject|ChartOfAccountsObject|ChartOfCalculationTypesObject|ChartOfCharacteristicTypesObject|ExchangePlanObject|BusinessProcessObject|TaskObject)\.', t)) or ('RecordManager.' in t)
|
||||
if attr.get('savedData') is True or main_saved:
|
||||
lines.append(f'{inner}<SavedData>true</SavedData>')
|
||||
# Save: сохранение значения реквизита в пользовательских настройках. true → <Field>имя</Field>;
|
||||
# строка/массив → под-поля с авто-префиксом "имя." (путь с точкой / UUID / =имя — как есть).
|
||||
# Нет ключа или false → не эмитим.
|
||||
if 'save' in attr and attr['save'] is not None:
|
||||
save_fields = []
|
||||
sv = attr['save']
|
||||
if isinstance(sv, bool):
|
||||
if sv:
|
||||
save_fields.append(attr_name)
|
||||
else:
|
||||
for e in (sv if isinstance(sv, (list, tuple)) else [sv]):
|
||||
fld = str(e)
|
||||
if not fld:
|
||||
continue
|
||||
if fld != attr_name and '.' not in fld and not re.match(r'^\d+/\d+:', fld):
|
||||
fld = f'{attr_name}.{fld}'
|
||||
if fld not in save_fields:
|
||||
save_fields.append(fld)
|
||||
if save_fields:
|
||||
lines.append(f'{inner}<Save>')
|
||||
for f in save_fields:
|
||||
lines.append(f'{inner}\t<Field>{esc_xml(f)}</Field>')
|
||||
lines.append(f'{inner}</Save>')
|
||||
if attr.get('fillChecking'):
|
||||
lines.append(f'{inner}<FillChecking>{attr["fillChecking"]}</FillChecking>')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# form-decompile v0.52 — Decompile 1C managed Form.xml to JSON DSL (draft)
|
||||
# form-decompile v0.53 — Decompile 1C managed Form.xml to JSON DSL (draft)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
|
||||
param(
|
||||
@@ -1689,6 +1689,21 @@ if ($attrsNode) {
|
||||
$ao['title'] = ''
|
||||
}
|
||||
if ((Get-Child $a 'SavedData') -eq 'true') { $ao['savedData'] = $true }
|
||||
# Save: сохранение значения реквизита в пользовательских настройках. Один Field=имя → save:true;
|
||||
# иначе снимаем префикс "имя." (голое имя/UUID/прочее — как есть) → строка (1) или массив.
|
||||
$saveNode = $a.SelectSingleNode("lf:Save", $ns)
|
||||
if ($saveNode) {
|
||||
$nm = "$($ao['name'])"
|
||||
$flds = @($saveNode.SelectNodes("lf:Field", $ns) | ForEach-Object { $_.InnerText })
|
||||
if ($flds.Count -eq 1 -and $flds[0] -eq $nm) {
|
||||
$ao['save'] = $true
|
||||
} elseif ($flds.Count -gt 0) {
|
||||
$stripped = @($flds | ForEach-Object {
|
||||
if ($_ -match "^$([regex]::Escape($nm))\.(.+)$") { $matches[1] } else { $_ }
|
||||
})
|
||||
if ($stripped.Count -eq 1) { $ao['save'] = $stripped[0] } else { $ao['save'] = $stripped }
|
||||
}
|
||||
}
|
||||
$fc = Get-Child $a 'FillChecking'; if ($fc) { $ao['fillChecking'] = $fc }
|
||||
$afo = Decompile-FunctionalOptions $a; if ($afo) { $ao['functionalOptions'] = $afo }
|
||||
$colsNode = $a.SelectSingleNode("lf:Columns", $ns)
|
||||
|
||||
@@ -740,7 +740,8 @@ Pages поддерживает `pagesRepresentation`: `None`, `TabsOnTop`, `Tabs
|
||||
| `edit` | bool/object | Редактирование по ролям (`<Edit>`). См. §4.1c |
|
||||
| `functionalOptions` | array | Функциональные опции (`<FunctionalOptions><Item>FunctionalOption.X</Item>…`). Массив имён; forgiving: `"X"`/`"FunctionalOption.X"`. Также у колонок (`columns[*]`) и команд (§7) |
|
||||
| `useAlways` | array | Поля, всегда читаемые (`<UseAlways><Field>Имя.Поле</Field>…`). Массив коротких имён полей (forgiving: с/без префикса `Имя.`). **Две формы**: этот массив на реквизите ИЛИ `useAlways: true` на колонке (`columns[*]`) — компилятор сливает. Для дин-списка — только массив (колонки не эмитятся, но формируют `<UseAlways>`) |
|
||||
| `savedData` | bool | Сохраняемые данные |
|
||||
| `savedData` | bool | Сохраняемые данные (`<SavedData>`) |
|
||||
| `save` | bool/string/array | Сохранение значения в пользовательских настройках (`<Save><Field>…`). `true` → `<Field>имя</Field>`; строка/массив строк → под-поля с авто-префиксом `имя.` (путь с точкой / UUID `1/0:…` / совпадающее с именем — берётся как есть). Нет ключа или `false` → не эмитится. Пример периода: `["Период","EndDate","StartDate","Variant"]` |
|
||||
| `fillChecking` | string | `Show`, `DontShow` |
|
||||
| `columns` | array | Колонки для ValueTable/ValueTree (`{ name, type, title?, functionalOptions?, useAlways? }`) |
|
||||
| `additionalColumns` | array | Доп. колонки табличных частей объекта: `[{ table: "Объект.ТабЧасть", columns: [<col>] }]`. У главного реквизита-объекта; `<col>` — та же грамматика, что у `columns`. Эмитятся в `<Columns>` после прямых колонок |
|
||||
|
||||
@@ -23,10 +23,11 @@
|
||||
],
|
||||
"attributes": [
|
||||
{ "name": "Объект", "type": "DataProcessorObject.Типы", "main": true },
|
||||
{ "name": "Строка", "type": "string(200)", "view": false },
|
||||
{ "name": "Строка", "type": "string(200)", "view": false, "save": true },
|
||||
{ "name": "Число", "type": "decimal(10,0,nonneg)", "edit": false },
|
||||
{ "name": "Дата", "type": "dateTime", "title": "" },
|
||||
{ "name": "Булево", "type": "boolean" },
|
||||
{ "name": "Период", "type": "v8:StandardPeriod", "save": ["Период", "EndDate", "StartDate", "Variant"] },
|
||||
{ "name": "СписокЗначений", "type": "ValueList" },
|
||||
{ "name": "Идентификатор", "type": "v8:UUID" }
|
||||
]
|
||||
|
||||
+22
-2
@@ -57,6 +57,9 @@
|
||||
<View>
|
||||
<xr:Common>false</xr:Common>
|
||||
</View>
|
||||
<Save>
|
||||
<Field>Строка</Field>
|
||||
</Save>
|
||||
</Attribute>
|
||||
<Attribute name="Число" id="15">
|
||||
<Title>
|
||||
@@ -96,7 +99,24 @@
|
||||
<v8:Type>xs:boolean</v8:Type>
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="СписокЗначений" id="18">
|
||||
<Attribute name="Период" id="18">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Период</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>v8:StandardPeriod</v8:Type>
|
||||
</Type>
|
||||
<Save>
|
||||
<Field>Период</Field>
|
||||
<Field>Период.EndDate</Field>
|
||||
<Field>Период.StartDate</Field>
|
||||
<Field>Период.Variant</Field>
|
||||
</Save>
|
||||
</Attribute>
|
||||
<Attribute name="СписокЗначений" id="19">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
@@ -107,7 +127,7 @@
|
||||
<v8:Type>v8:ValueListType</v8:Type>
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="Идентификатор" id="19">
|
||||
<Attribute name="Идентификатор" id="20">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
|
||||
Reference in New Issue
Block a user