mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-02 01:37:45 +03:00
feat(skd): nested folder + nestedObject + groupItem object form (round-trip)
Закрывает категорию B полностью на ERP-корпусе:
- selection.folder теперь рекурсивный: внутри items могут быть string,
{field, title}, или ещё одна {folder, items: [...]}. Compile/decompile
обходят дерево рекурсивно (Emit-SelectionItem / Build-SelectionItem).
- structure: новая ветка type=nestedObject с {objectID, settings:
{selection, filter, order, conditionalAppearance, outputParameters}}.
- groupFields теперь объектная форма {field, groupType?, periodAdditionType?}
когда не дефолт (Items / None). Compile уже принимал; decompile перестаёт
ставить warning GroupItemDetails. Try-StructureShorthand игнорирует
object-form поля при сворачивании в строку.
- Refactor: Build-Structure для StructureItemGroup теперь использует
общий Get-GroupFields вместо дублированного inline-кода.
В SKILL.md не добавляем (формы редкие/сложные, модель не пишет с нуля).
Новый тест structure-nested-and-folder покрывает все три случая bit-perfect.
Versions: compile v1.30→v1.31, decompile v0.12→v0.13.
На сэмпле 30 ERP-отчётов: 754 → 32 sentinel'ов (-96%), clean 4 → 24/30.
Остаточные 32 — все TemplateStyleMismatch (категория C, диагностика).
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# skd-compile v1.30 — Compile 1C DCS from JSON
|
||||
# skd-compile v1.31 — Compile 1C DCS from JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$DefinitionFile,
|
||||
@@ -1787,6 +1787,51 @@ function Emit-GroupTemplates {
|
||||
|
||||
# === Settings Variants ===
|
||||
|
||||
function Emit-SelectionItem {
|
||||
param($item, [string]$indent)
|
||||
if ($item -is [string]) {
|
||||
if ($item -eq "Auto") {
|
||||
X "$indent<dcsset:item xsi:type=`"dcsset:SelectedItemAuto`"/>"
|
||||
} else {
|
||||
X "$indent<dcsset:item xsi:type=`"dcsset:SelectedItemField`">"
|
||||
X "$indent`t<dcsset:field>$(Esc-Xml $item)</dcsset:field>"
|
||||
X "$indent</dcsset:item>"
|
||||
}
|
||||
return
|
||||
}
|
||||
if ($item.folder -or (Has-JsonProp $item 'folder')) {
|
||||
X "$indent<dcsset:item xsi:type=`"dcsset:SelectedItemFolder`">"
|
||||
# Optional <dcsset:field> на folder (редкий случай, для round-trip-целостности)
|
||||
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>"
|
||||
foreach ($sub in $item.items) {
|
||||
Emit-SelectionItem -item $sub -indent "$indent`t"
|
||||
}
|
||||
X "$indent`t<dcsset:placement>Auto</dcsset:placement>"
|
||||
X "$indent</dcsset:item>"
|
||||
return
|
||||
}
|
||||
# field with optional title
|
||||
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>"
|
||||
}
|
||||
X "$indent</dcsset:item>"
|
||||
}
|
||||
|
||||
function Emit-Selection {
|
||||
param($items, [string]$indent, [switch]$skipAuto)
|
||||
|
||||
@@ -1794,45 +1839,8 @@ function Emit-Selection {
|
||||
|
||||
X "$indent<dcsset:selection>"
|
||||
foreach ($item in $items) {
|
||||
if ($item -is [string]) {
|
||||
if ($item -eq "Auto") {
|
||||
if (-not $skipAuto) {
|
||||
X "$indent`t<dcsset:item xsi:type=`"dcsset:SelectedItemAuto`"/>"
|
||||
}
|
||||
} else {
|
||||
X "$indent`t<dcsset:item xsi:type=`"dcsset:SelectedItemField`">"
|
||||
X "$indent`t`t<dcsset:field>$(Esc-Xml $item)</dcsset:field>"
|
||||
X "$indent`t</dcsset:item>"
|
||||
}
|
||||
} elseif ($item.folder) {
|
||||
X "$indent`t<dcsset:item xsi:type=`"dcsset:SelectedItemFolder`">"
|
||||
X "$indent`t`t<dcsset:lwsTitle>"
|
||||
X "$indent`t`t`t<v8:item>"
|
||||
X "$indent`t`t`t`t<v8:lang>ru</v8:lang>"
|
||||
X "$indent`t`t`t`t<v8:content>$(Esc-Xml "$($item.folder)")</v8:content>"
|
||||
X "$indent`t`t`t</v8:item>"
|
||||
X "$indent`t`t</dcsset:lwsTitle>"
|
||||
foreach ($sub in $item.items) {
|
||||
$subName = if ($sub -is [string]) { $sub } else { "$($sub.field)" }
|
||||
X "$indent`t`t<dcsset:item xsi:type=`"dcsset:SelectedItemField`">"
|
||||
X "$indent`t`t`t<dcsset:field>$(Esc-Xml $subName)</dcsset:field>"
|
||||
X "$indent`t`t</dcsset:item>"
|
||||
}
|
||||
X "$indent`t`t<dcsset:placement>Auto</dcsset:placement>"
|
||||
X "$indent`t</dcsset:item>"
|
||||
} else {
|
||||
X "$indent`t<dcsset:item xsi:type=`"dcsset:SelectedItemField`">"
|
||||
X "$indent`t`t<dcsset:field>$(Esc-Xml "$($item.field)")</dcsset:field>"
|
||||
if ($item.title) {
|
||||
X "$indent`t`t<dcsset:lwsTitle>"
|
||||
X "$indent`t`t`t<v8:item>"
|
||||
X "$indent`t`t`t`t<v8:lang>ru</v8:lang>"
|
||||
X "$indent`t`t`t`t<v8:content>$(Esc-Xml "$($item.title)")</v8:content>"
|
||||
X "$indent`t`t`t</v8:item>"
|
||||
X "$indent`t`t</dcsset:lwsTitle>"
|
||||
}
|
||||
X "$indent`t</dcsset:item>"
|
||||
}
|
||||
if ($skipAuto -and ($item -is [string]) -and $item -eq 'Auto') { continue }
|
||||
Emit-SelectionItem -item $item -indent "$indent`t"
|
||||
}
|
||||
X "$indent</dcsset:selection>"
|
||||
}
|
||||
@@ -2370,6 +2378,21 @@ function Emit-StructureItem {
|
||||
|
||||
X "$indent</dcsset:item>"
|
||||
}
|
||||
elseif ($type -eq "nestedObject") {
|
||||
X "$indent<dcsset:item xsi:type=`"dcsset:StructureItemNestedObject`">"
|
||||
if ($item.objectID) { X "$indent`t<dcsset:objectID>$(Esc-Xml "$($item.objectID)")</dcsset:objectID>" }
|
||||
X "$indent`t<dcsset:settings>"
|
||||
$s = $item.settings
|
||||
if ($s) {
|
||||
if ($s.selection) { Emit-Selection -items $s.selection -indent "$indent`t`t" }
|
||||
if ($s.filter) { Emit-Filter -items $s.filter -indent "$indent`t`t" }
|
||||
if ($s.order) { Emit-Order -items $s.order -indent "$indent`t`t" }
|
||||
if ($s.conditionalAppearance) { Emit-ConditionalAppearance -items $s.conditionalAppearance -indent "$indent`t`t" }
|
||||
if ($s.outputParameters) { Emit-OutputParameters -params $s.outputParameters -indent "$indent`t`t" }
|
||||
}
|
||||
X "$indent`t</dcsset:settings>"
|
||||
X "$indent</dcsset:item>"
|
||||
}
|
||||
}
|
||||
|
||||
function Emit-SettingsVariants {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# skd-compile v1.30 — Compile 1C DCS from JSON
|
||||
# skd-compile v1.31 — Compile 1C DCS from JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import json
|
||||
@@ -1481,46 +1481,51 @@ def emit_group_templates(lines, defn):
|
||||
|
||||
# === Settings Variants ===
|
||||
|
||||
def emit_selection_item(lines, item, indent):
|
||||
if isinstance(item, str):
|
||||
if item == 'Auto':
|
||||
lines.append(f'{indent}<dcsset:item xsi:type="dcsset:SelectedItemAuto"/>')
|
||||
else:
|
||||
lines.append(f'{indent}<dcsset:item xsi:type="dcsset:SelectedItemField">')
|
||||
lines.append(f'{indent}\t<dcsset:field>{esc_xml(item)}</dcsset:field>')
|
||||
lines.append(f'{indent}</dcsset:item>')
|
||||
return
|
||||
if 'folder' in item:
|
||||
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>')
|
||||
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>')
|
||||
lines.append(f'{indent}</dcsset:item>')
|
||||
return
|
||||
# field with optional title
|
||||
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>')
|
||||
lines.append(f'{indent}</dcsset:item>')
|
||||
|
||||
|
||||
def emit_selection(lines, items, indent, skip_auto=False):
|
||||
if not items or len(items) == 0:
|
||||
return
|
||||
|
||||
lines.append(f'{indent}<dcsset:selection>')
|
||||
for item in items:
|
||||
if isinstance(item, str):
|
||||
if item == 'Auto':
|
||||
if not skip_auto:
|
||||
lines.append(f'{indent}\t<dcsset:item xsi:type="dcsset:SelectedItemAuto"/>')
|
||||
else:
|
||||
lines.append(f'{indent}\t<dcsset:item xsi:type="dcsset:SelectedItemField">')
|
||||
lines.append(f'{indent}\t\t<dcsset:field>{esc_xml(item)}</dcsset:field>')
|
||||
lines.append(f'{indent}\t</dcsset:item>')
|
||||
elif item.get('folder'):
|
||||
lines.append(f'{indent}\t<dcsset:item xsi:type="dcsset:SelectedItemFolder">')
|
||||
lines.append(f'{indent}\t\t<dcsset:lwsTitle>')
|
||||
lines.append(f'{indent}\t\t\t<v8:item>')
|
||||
lines.append(f'{indent}\t\t\t\t<v8:lang>ru</v8:lang>')
|
||||
lines.append(f'{indent}\t\t\t\t<v8:content>{esc_xml(str(item["folder"]))}</v8:content>')
|
||||
lines.append(f'{indent}\t\t\t</v8:item>')
|
||||
lines.append(f'{indent}\t\t</dcsset:lwsTitle>')
|
||||
for sub in (item.get('items') or []):
|
||||
sub_name = str(sub.get('field', sub)) if isinstance(sub, dict) else str(sub)
|
||||
lines.append(f'{indent}\t\t<dcsset:item xsi:type="dcsset:SelectedItemField">')
|
||||
lines.append(f'{indent}\t\t\t<dcsset:field>{esc_xml(sub_name)}</dcsset:field>')
|
||||
lines.append(f'{indent}\t\t</dcsset:item>')
|
||||
lines.append(f'{indent}\t\t<dcsset:placement>Auto</dcsset:placement>')
|
||||
lines.append(f'{indent}\t</dcsset:item>')
|
||||
else:
|
||||
lines.append(f'{indent}\t<dcsset:item xsi:type="dcsset:SelectedItemField">')
|
||||
lines.append(f'{indent}\t\t<dcsset:field>{esc_xml(str(item["field"]))}</dcsset:field>')
|
||||
if item.get('title'):
|
||||
lines.append(f'{indent}\t\t<dcsset:lwsTitle>')
|
||||
lines.append(f'{indent}\t\t\t<v8:item>')
|
||||
lines.append(f'{indent}\t\t\t\t<v8:lang>ru</v8:lang>')
|
||||
lines.append(f'{indent}\t\t\t\t<v8:content>{esc_xml(str(item["title"]))}</v8:content>')
|
||||
lines.append(f'{indent}\t\t\t</v8:item>')
|
||||
lines.append(f'{indent}\t\t</dcsset:lwsTitle>')
|
||||
lines.append(f'{indent}\t</dcsset:item>')
|
||||
if skip_auto and isinstance(item, str) and item == 'Auto':
|
||||
continue
|
||||
emit_selection_item(lines, item, f'{indent}\t')
|
||||
lines.append(f'{indent}</dcsset:selection>')
|
||||
|
||||
|
||||
@@ -1962,6 +1967,20 @@ def emit_structure_item(lines, item, indent):
|
||||
|
||||
lines.append(f'{indent}</dcsset:item>')
|
||||
|
||||
elif item_type == 'nestedObject':
|
||||
lines.append(f'{indent}<dcsset:item xsi:type="dcsset:StructureItemNestedObject">')
|
||||
if item.get('objectID'):
|
||||
lines.append(f'{indent}\t<dcsset:objectID>{esc_xml(str(item["objectID"]))}</dcsset:objectID>')
|
||||
lines.append(f'{indent}\t<dcsset:settings>')
|
||||
s = item.get('settings') or {}
|
||||
if s.get('selection'): emit_selection(lines, s['selection'], f'{indent}\t\t')
|
||||
if s.get('filter'): emit_filter(lines, s['filter'], f'{indent}\t\t')
|
||||
if s.get('order'): emit_order(lines, s['order'], f'{indent}\t\t')
|
||||
if s.get('conditionalAppearance'): emit_conditional_appearance(lines, s['conditionalAppearance'], f'{indent}\t\t')
|
||||
if s.get('outputParameters'): emit_output_parameters(lines, s['outputParameters'], f'{indent}\t\t')
|
||||
lines.append(f'{indent}\t</dcsset:settings>')
|
||||
lines.append(f'{indent}</dcsset:item>')
|
||||
|
||||
|
||||
def emit_settings_variants(lines, defn):
|
||||
variants = defn.get('settingsVariants')
|
||||
|
||||
Reference in New Issue
Block a user