feat(form-decompile,form-compile): пустой/whitespace right фильтра + GetInvisibleFieldPresentations (кластер Attribute>right)

(1) Пустой <dcsset:right xsi:type="xs:string"/> ≠ отсутствие <right>: декомпилятор
схлопывал оба в shorthand-маркер `_`, а компилятор для shorthand `_` не эмитит right
вовсе → пустой right терялся (Get-FilterValueWithType маппит наличие пустого/nil right
в '_', отсутствие → $null — РАЗЛИЧИМЫ). Фикс (декомпилятор): при value='_' с реально
присутствующим <right> форсим объектную форму {value:"_"} — компилятор эмитит
self-closing right (ветка `_` уже была). Заодно whitespace-/пробельные значения,
рвущие shorthand-парсинг (split по пробелам), уходят в объектную форму.

(2) Whitespace-only <right>   </right> (9 пробелов): PreserveWhitespace=false стрипал
в '' → '_' → self-closing. Восстанавливаем реальные пробелы из WS-дока (Resolve-WS,
как у whitespace-заголовков) → объектная форма value="   ".

(3) GetInvisibleFieldPresentations — Settings-скаляр дин-списка (после MainTable;
дефолт true, корпус 20/20 = false → эмит отклонения). Захват/эмит факт. значения,
зеркало py.

Выборка 14 форм (ДоговорыКонтрагентов, ЕдиницыГенерирующие×2, РаботаСНоменклатурой,
ПравилаИнтеграции, … acc+erp): match 0→14, TOTAL→0. ps1==py байт-в-байт. Регресс 43/43.
Spec обновлён (getInvisibleFieldPresentations). (1)/(2) — декомпилятор-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-13 13:37:39 +03:00
parent 85ae72739f
commit e3ae9c27d1
4 changed files with 30 additions and 4 deletions
@@ -1,4 +1,4 @@
# form-compile v1.153 — Compile 1C managed form from JSON or object metadata
# form-compile v1.154 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$JsonPath,
@@ -5722,6 +5722,8 @@ function Emit-Attributes {
if ($st.keyType) { X "$si<KeyType>$(Esc-Xml "$($st.keyType)")</KeyType>" }
if ($st.keyFields) { foreach ($kf in @($st.keyFields)) { X "$si<KeyField>$(Esc-Xml "$kf")</KeyField>" } }
if ($st.mainTable) { X "$si<MainTable>$(Normalize-MetaTypeRef "$($st.mainTable)")</MainTable>" }
# GetInvisibleFieldPresentations — после MainTable (дефолт true; эмитим только при заданном ключе = отклонении false).
if ($null -ne $st.getInvisibleFieldPresentations) { X "$si<GetInvisibleFieldPresentations>$(if ($st.getInvisibleFieldPresentations){'true'}else{'false'})</GetInvisibleFieldPresentations>" }
# AutoSaveUserSettings — после MainTable (дефолт true; эмитим только при заданном ключе = отклонении).
if ($null -ne $st.autoSaveUserSettings) { X "$si<AutoSaveUserSettings>$(if ($st.autoSaveUserSettings){'true'}else{'false'})</AutoSaveUserSettings>" }
# ListSettings: filter/order/conditionalAppearance (skd-грамматика) + каноничные блок-GUID.
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# form-compile v1.153 — Compile 1C managed form from JSON or object metadata
# form-compile v1.154 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import copy
@@ -5480,6 +5480,9 @@ def emit_attributes(lines, attrs, indent, conditional_appearance=None):
lines.append(f'{si}<KeyField>{esc_xml(str(kf))}</KeyField>')
if s.get('mainTable'):
lines.append(f'{si}<MainTable>{normalize_meta_type_ref(str(s["mainTable"]))}</MainTable>')
# GetInvisibleFieldPresentations — после MainTable (дефолт true; эмитим только при заданном ключе = отклонении false).
if s.get('getInvisibleFieldPresentations') is not None:
lines.append(f'{si}<GetInvisibleFieldPresentations>{"true" if s["getInvisibleFieldPresentations"] else "false"}</GetInvisibleFieldPresentations>')
# AutoSaveUserSettings — после MainTable (дефолт true; эмитим только при заданном ключе = отклонении).
if s.get('autoSaveUserSettings') is not None:
lines.append(f'{si}<AutoSaveUserSettings>{"true" if s["autoSaveUserSettings"] else "false"}</AutoSaveUserSettings>')
@@ -1,4 +1,4 @@
# form-decompile v0.128 — Decompile 1C managed Form.xml to JSON DSL (draft)
# form-decompile v0.129 — Decompile 1C managed Form.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
param(
@@ -732,7 +732,25 @@ function Build-FilterItem {
$noValueOps = @('filled','notFilled')
if ($userPresNode -or $valueIsArrayFlag -or $valueTypeAttr -or $fiPres) {
# Пустой xs:string right (<dcsset:right xsi:type="xs:string"/>) ≠ отсутствие <right>:
# Get-FilterValueWithType маппит наличие пустого/nil right в value='_' (отсутствие → $null).
# Shorthand `_` неоднозначен (схлопывает оба, компилятор → нет right). Пробельные значения рвут
# shorthand-парсинг (split по пробелам). → форсим объектную форму (value='_' → self-closing;
# пробелы — как есть в <right>).
$valNeedsObj = $false
if ($rightNodes.Count -eq 1 -and -not $valueIsArrayFlag -and $op -notin $noValueOps) {
if ("$value" -eq '_') {
# Truly-empty <right xsi:type="xs:string"/> ИЛИ whitespace-only <right> </right>
# (PreserveWhitespace=false стрипнул пробелы в '' → Get-FilterValueWithType вернул '_').
# Восстанавливаем реальные пробелы из WS-дока (как у whitespace-заголовков).
$ws = Resolve-WS $rightNodes[0]
if ($ws -and $ws.Length -gt 0 -and $ws.Trim() -eq '') { $value = $ws }
$valNeedsObj = $true
}
elseif ($null -ne $value -and "$value" -match '\s') { $valNeedsObj = $true }
}
if ($userPresNode -or $valueIsArrayFlag -or $valueTypeAttr -or $fiPres -or $valNeedsObj) {
$obj = [ordered]@{ field = $field; op = $op }
if ($op -notin $noValueOps -and $null -ne $value) {
if ($valueIsArrayFlag) {
@@ -2693,6 +2711,8 @@ if ($attrsNode) {
# AutoFillAvailableFields — дефолт true, платформа эмитит только отклонение (false). Захват «как есть».
$afaf = Get-Child $setNode 'AutoFillAvailableFields'; if ($null -ne $afaf) { $so['autoFillAvailableFields'] = ($afaf -eq 'true') }
$mt = Get-Child $setNode 'MainTable'; if ($mt) { $so['mainTable'] = $mt }
# GetInvisibleFieldPresentations — дефолт true, платформа эмитит только отклонение (false, корпус 20/20). Факт. значение.
$gifp = Get-Child $setNode 'GetInvisibleFieldPresentations'; if ($null -ne $gifp) { $so['getInvisibleFieldPresentations'] = ($gifp -eq 'true') }
# Ключ набора (query-based список): KeyType (RowNumber/FieldValue/RowKey) + KeyField* (0+).
$kt = Get-Child $setNode 'KeyType'; if ($kt) { $so['keyType'] = $kt }
$kfNodes = @($setNode.SelectNodes("lf:KeyField", $ns) | ForEach-Object { $_.InnerText })
+1
View File
@@ -943,6 +943,7 @@ Forgiving-синонимы типа: XML-имя (`SpreadSheetDocumentField`) и
| `keyType` | string | Тип ключа набора запросного списка (без `mainTable`): `FieldValue` / `RowKey` / `RowNumber` |
| `keyFields` | array | Поля ключа набора (`<KeyField>`, 0+) — для запросного списка без `mainTable`. Эмитятся после параметров |
| `autoSaveUserSettings` | bool | Авто-сохранение пользовательских настроек дин-списка (`<AutoSaveUserSettings>`, после `MainTable`). **Умолчание `true`** — указывать только для отключения (`false`) |
| `getInvisibleFieldPresentations` | bool | Получать представления невидимых полей (`<GetInvisibleFieldPresentations>`, после `MainTable`). **Умолчание `true`** — указывать только для отключения (`false`) |
| `query` | string | Текст запроса (`ManualQuery=true`). Поддерживает `@file.sql` (путь относительно JSON) |
| `dynamicDataRead` | bool | Динамическое считывание. **Умолчание `true`** — указывать только для отключения (`false`) |
| `autoFillAvailableFields` | bool | Автозаполнение доступных полей (`<AutoFillAvailableFields>`). **Умолчание `true`** — указывать только для отключения (`false`; тогда поля берутся из явного запроса, не авто). Эмитится первым в `<Settings>` |