mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-24 05:31:02 +03:00
fix(skd-compile): object-form structure, OrGroup string items, useRestriction alias
- Default structure item type to 'group' when omitted; accept groupFields as alias for groupBy
- Parse string shorthand items inside OrGroup/AndGroup/NotGroup filter recursion
- Accept useRestriction key (object form { field: true }) alongside restrict array
- Deduplicate SelectedItemAuto in skd-edit add-selection
- Update SKILL.md with object structure and useRestriction docs
- Add test cases for all 4 fixes
skd-compile v1.9→v1.10, skd-edit v1.8→v1.9
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
46e065adb9
commit
384e68cab4
@@ -83,6 +83,8 @@ powershell.exe -NoProfile -File .claude/skills/skd-compile/scripts/skd-compile.p
|
||||
|
||||
Ограничения: `#noField`, `#noFilter`, `#noGroup`, `#noOrder`.
|
||||
|
||||
В объектной форме: `"useRestriction": { "field": true, "condition": true, "group": true, "order": true }` или `"restrict": ["noField", "noFilter"]`.
|
||||
|
||||
### Итоги (shorthand)
|
||||
|
||||
```json
|
||||
@@ -168,7 +170,20 @@ powershell.exe -NoProfile -File .claude/skills/skd-compile/scripts/skd-compile.p
|
||||
|
||||
`>` разделяет уровни группировки. `details` (или `детали`) = детальные записи. `selection` и `order` по умолчанию `["Auto"]` на каждом уровне.
|
||||
|
||||
Для сложных случаев (таблицы, диаграммы, фильтры на уровне группировки) используется объектная форма.
|
||||
Объектная форма — для сложных случаев (именованные группировки, selection/filter на уровне группировки, таблицы, диаграммы):
|
||||
|
||||
```json
|
||||
"structure": [
|
||||
{
|
||||
"name": "ПоОрганизациям",
|
||||
"groupFields": ["Организация"],
|
||||
"selection": ["Организация", "Сумма", "Auto"],
|
||||
"children": [{ "groupFields": [] }]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
`type` по умолчанию `"group"` (можно не указывать). `groupFields` — алиас для `groupBy`. Поддержка `name`, `selection`, `order`, `filter`, `outputParameters`, рекурсивных `children`.
|
||||
|
||||
### Варианты настроек
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# skd-compile v1.9 — Compile 1C DCS from JSON
|
||||
# skd-compile v1.10 — Compile 1C DCS from JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$DefinitionFile,
|
||||
@@ -790,15 +790,26 @@ function Emit-CalcFields {
|
||||
Emit-ValueType -typeStr $cfType -indent "`t`t`t"
|
||||
X "`t`t</valueType>"
|
||||
}
|
||||
if ($cf.restrict) {
|
||||
$restrictMap = @{
|
||||
"noField" = "field"; "noFilter" = "condition"; "noCondition" = "condition"
|
||||
"noGroup" = "group"; "noOrder" = "order"
|
||||
}
|
||||
$restrictVal = if ($cf.restrict) { $cf.restrict } elseif ($cf.useRestriction) { $cf.useRestriction } else { $null }
|
||||
if ($restrictVal) {
|
||||
X "`t`t<useRestriction>"
|
||||
foreach ($r in $cf.restrict) {
|
||||
$xmlName = $restrictMap["$r"]
|
||||
if ($xmlName) { X "`t`t`t<$xmlName>true</$xmlName>" }
|
||||
if ($restrictVal -is [System.Management.Automation.PSCustomObject] -or $restrictVal -is [hashtable]) {
|
||||
# Object form: { "field": true, "condition": true, ... }
|
||||
foreach ($prop in $restrictVal.PSObject.Properties) {
|
||||
if ($prop.Value -eq $true) {
|
||||
X "`t`t`t<$($prop.Name)>true</$($prop.Name)>"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# Array form: ["noField", "noFilter", ...]
|
||||
$restrictMap = @{
|
||||
"noField" = "field"; "noFilter" = "condition"; "noCondition" = "condition"
|
||||
"noGroup" = "group"; "noOrder" = "order"
|
||||
}
|
||||
foreach ($r in $restrictVal) {
|
||||
$xmlName = $restrictMap["$r"]
|
||||
if ($xmlName) { X "`t`t`t<$xmlName>true</$xmlName>" }
|
||||
}
|
||||
}
|
||||
X "`t`t</useRestriction>"
|
||||
}
|
||||
@@ -1443,6 +1454,16 @@ function Emit-FilterItem {
|
||||
X "$indent`t<dcsset:groupType>$groupType</dcsset:groupType>"
|
||||
if ($item.items) {
|
||||
foreach ($sub in $item.items) {
|
||||
if ($sub -is [string]) {
|
||||
$parsed = Parse-FilterShorthand $sub
|
||||
$obj = @{ field = $parsed.field; op = $parsed.op }
|
||||
if ($parsed.use -eq $false) { $obj.use = $false }
|
||||
if ($null -ne $parsed.value) { $obj.value = $parsed.value }
|
||||
if ($parsed["valueType"]) { $obj.valueType = $parsed["valueType"] }
|
||||
if ($parsed.userSettingID) { $obj.userSettingID = $parsed.userSettingID }
|
||||
if ($parsed.viewMode) { $obj.viewMode = $parsed.viewMode }
|
||||
$sub = [pscustomobject]$obj
|
||||
}
|
||||
Emit-FilterItem -item $sub -indent "$indent`t"
|
||||
}
|
||||
}
|
||||
@@ -1844,7 +1865,7 @@ function Parse-StructureShorthand {
|
||||
function Emit-StructureItem {
|
||||
param($item, [string]$indent)
|
||||
|
||||
$type = "$($item.type)"
|
||||
$type = if ($item.type) { "$($item.type)" } else { "group" }
|
||||
|
||||
if ($type -eq "group") {
|
||||
X "$indent<dcsset:item xsi:type=`"dcsset:StructureItemGroup`">"
|
||||
@@ -1853,7 +1874,8 @@ function Emit-StructureItem {
|
||||
X "$indent`t<dcsset:name>$(Esc-Xml "$($item.name)")</dcsset:name>"
|
||||
}
|
||||
|
||||
Emit-GroupItems -groupBy $item.groupBy -indent "$indent`t"
|
||||
$gb = if ($item.groupBy) { $item.groupBy } else { $item.groupFields }
|
||||
Emit-GroupItems -groupBy $gb -indent "$indent`t"
|
||||
|
||||
# Default order to ["Auto"] if not specified
|
||||
$orderItems = $item.order
|
||||
@@ -1891,7 +1913,8 @@ function Emit-StructureItem {
|
||||
if ($item.columns) {
|
||||
foreach ($col in $item.columns) {
|
||||
X "$indent`t<dcsset:column>"
|
||||
Emit-GroupItems -groupBy $col.groupBy -indent "$indent`t`t"
|
||||
$colGb = if ($col.groupBy) { $col.groupBy } else { $col.groupFields }
|
||||
Emit-GroupItems -groupBy $colGb -indent "$indent`t`t"
|
||||
$colOrder = $col.order; if (-not $colOrder) { $colOrder = @("Auto") }
|
||||
Emit-Order -items $colOrder -indent "$indent`t`t"
|
||||
$colSel = $col.selection; if (-not $colSel) { $colSel = @("Auto") }
|
||||
@@ -1907,7 +1930,8 @@ function Emit-StructureItem {
|
||||
if ($row.name) {
|
||||
X "$indent`t`t<dcsset:name>$(Esc-Xml "$($row.name)")</dcsset:name>"
|
||||
}
|
||||
Emit-GroupItems -groupBy $row.groupBy -indent "$indent`t`t"
|
||||
$rowGb = if ($row.groupBy) { $row.groupBy } else { $row.groupFields }
|
||||
Emit-GroupItems -groupBy $rowGb -indent "$indent`t`t"
|
||||
$rowOrder = $row.order; if (-not $rowOrder) { $rowOrder = @("Auto") }
|
||||
Emit-Order -items $rowOrder -indent "$indent`t`t"
|
||||
$rowSel = $row.selection; if (-not $rowSel) { $rowSel = @("Auto") }
|
||||
@@ -1928,7 +1952,8 @@ function Emit-StructureItem {
|
||||
# Points
|
||||
if ($item.points) {
|
||||
X "$indent`t<dcsset:point>"
|
||||
Emit-GroupItems -groupBy $item.points.groupBy -indent "$indent`t`t"
|
||||
$ptGb = if ($item.points.groupBy) { $item.points.groupBy } else { $item.points.groupFields }
|
||||
Emit-GroupItems -groupBy $ptGb -indent "$indent`t`t"
|
||||
$ptOrder = $item.points.order; if (-not $ptOrder) { $ptOrder = @("Auto") }
|
||||
Emit-Order -items $ptOrder -indent "$indent`t`t"
|
||||
$ptSel = $item.points.selection; if (-not $ptSel) { $ptSel = @("Auto") }
|
||||
@@ -1939,7 +1964,8 @@ function Emit-StructureItem {
|
||||
# Series
|
||||
if ($item.series) {
|
||||
X "$indent`t<dcsset:series>"
|
||||
Emit-GroupItems -groupBy $item.series.groupBy -indent "$indent`t`t"
|
||||
$srGb = if ($item.series.groupBy) { $item.series.groupBy } else { $item.series.groupFields }
|
||||
Emit-GroupItems -groupBy $srGb -indent "$indent`t`t"
|
||||
$srOrder = $item.series.order; if (-not $srOrder) { $srOrder = @("Auto") }
|
||||
Emit-Order -items $srOrder -indent "$indent`t`t"
|
||||
$srSel = $item.series.selection; if (-not $srSel) { $srSel = @("Auto") }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# skd-compile v1.9 — Compile 1C DCS from JSON
|
||||
# skd-compile v1.10 — Compile 1C DCS from JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import json
|
||||
@@ -640,16 +640,24 @@ def emit_calc_fields(lines, defn):
|
||||
lines.append('\t\t<valueType>')
|
||||
emit_value_type(lines, cf_type, '\t\t\t')
|
||||
lines.append('\t\t</valueType>')
|
||||
if cf.get('restrict'):
|
||||
restrict_map = {
|
||||
'noField': 'field', 'noFilter': 'condition', 'noCondition': 'condition',
|
||||
'noGroup': 'group', 'noOrder': 'order',
|
||||
}
|
||||
restrict_val = cf.get('restrict') or cf.get('useRestriction')
|
||||
if restrict_val:
|
||||
lines.append('\t\t<useRestriction>')
|
||||
for r in cf['restrict']:
|
||||
xml_name = restrict_map.get(str(r))
|
||||
if xml_name:
|
||||
lines.append(f'\t\t\t<{xml_name}>true</{xml_name}>')
|
||||
if isinstance(restrict_val, dict):
|
||||
# Object form: { "field": true, "condition": true, ... }
|
||||
for xml_name, flag in restrict_val.items():
|
||||
if flag:
|
||||
lines.append(f'\t\t\t<{esc_xml(str(xml_name))}>true</{esc_xml(str(xml_name))}>')
|
||||
else:
|
||||
# Array form: ["noField", "noFilter", ...]
|
||||
restrict_map = {
|
||||
'noField': 'field', 'noFilter': 'condition', 'noCondition': 'condition',
|
||||
'noGroup': 'group', 'noOrder': 'order',
|
||||
}
|
||||
for r in restrict_val:
|
||||
xml_name = restrict_map.get(str(r))
|
||||
if xml_name:
|
||||
lines.append(f'\t\t\t<{xml_name}>true</{xml_name}>')
|
||||
lines.append('\t\t</useRestriction>')
|
||||
if cf.get('appearance'):
|
||||
lines.append('\t\t<appearance>')
|
||||
@@ -1219,6 +1227,19 @@ def emit_filter_item(lines, item, indent):
|
||||
lines.append(f'{indent}\t<dcsset:groupType>{group_type}</dcsset:groupType>')
|
||||
if item.get('items'):
|
||||
for sub in item['items']:
|
||||
if isinstance(sub, str):
|
||||
parsed = parse_filter_shorthand(sub)
|
||||
sub = {'field': parsed['field'], 'op': parsed['op']}
|
||||
if parsed['use'] is False:
|
||||
sub['use'] = False
|
||||
if parsed.get('value') is not None:
|
||||
sub['value'] = parsed['value']
|
||||
if parsed.get('valueType'):
|
||||
sub['valueType'] = parsed['valueType']
|
||||
if parsed.get('userSettingID'):
|
||||
sub['userSettingID'] = parsed['userSettingID']
|
||||
if parsed.get('viewMode'):
|
||||
sub['viewMode'] = parsed['viewMode']
|
||||
emit_filter_item(lines, sub, f'{indent}\t')
|
||||
lines.append(f'{indent}</dcsset:item>')
|
||||
return
|
||||
@@ -1551,7 +1572,7 @@ def parse_structure_shorthand(s):
|
||||
|
||||
|
||||
def emit_structure_item(lines, item, indent):
|
||||
item_type = str(item.get('type', ''))
|
||||
item_type = str(item.get('type', 'group'))
|
||||
|
||||
if item_type == 'group':
|
||||
lines.append(f'{indent}<dcsset:item xsi:type="dcsset:StructureItemGroup">')
|
||||
@@ -1559,7 +1580,7 @@ def emit_structure_item(lines, item, indent):
|
||||
if item.get('name'):
|
||||
lines.append(f'{indent}\t<dcsset:name>{esc_xml(str(item["name"]))}</dcsset:name>')
|
||||
|
||||
emit_group_items(lines, item.get('groupBy'), f'{indent}\t')
|
||||
emit_group_items(lines, item.get('groupBy') or item.get('groupFields'), f'{indent}\t')
|
||||
|
||||
# Default order to ["Auto"] if not specified
|
||||
order_items = item.get('order') or ['Auto']
|
||||
@@ -1591,7 +1612,7 @@ def emit_structure_item(lines, item, indent):
|
||||
if item.get('columns'):
|
||||
for col in item['columns']:
|
||||
lines.append(f'{indent}\t<dcsset:column>')
|
||||
emit_group_items(lines, col.get('groupBy'), f'{indent}\t\t')
|
||||
emit_group_items(lines, col.get('groupBy') or col.get('groupFields'), f'{indent}\t\t')
|
||||
col_order = col.get('order') or ['Auto']
|
||||
emit_order(lines, col_order, f'{indent}\t\t')
|
||||
col_sel = col.get('selection') or ['Auto']
|
||||
@@ -1604,7 +1625,7 @@ def emit_structure_item(lines, item, indent):
|
||||
lines.append(f'{indent}\t<dcsset:row>')
|
||||
if row.get('name'):
|
||||
lines.append(f'{indent}\t\t<dcsset:name>{esc_xml(str(row["name"]))}</dcsset:name>')
|
||||
emit_group_items(lines, row.get('groupBy'), f'{indent}\t\t')
|
||||
emit_group_items(lines, row.get('groupBy') or row.get('groupFields'), f'{indent}\t\t')
|
||||
row_order = row.get('order') or ['Auto']
|
||||
emit_order(lines, row_order, f'{indent}\t\t')
|
||||
row_sel = row.get('selection') or ['Auto']
|
||||
@@ -1622,7 +1643,7 @@ def emit_structure_item(lines, item, indent):
|
||||
# Points
|
||||
if item.get('points'):
|
||||
lines.append(f'{indent}\t<dcsset:point>')
|
||||
emit_group_items(lines, item['points'].get('groupBy'), f'{indent}\t\t')
|
||||
emit_group_items(lines, item['points'].get('groupBy') or item['points'].get('groupFields'), f'{indent}\t\t')
|
||||
pt_order = item['points'].get('order') or ['Auto']
|
||||
emit_order(lines, pt_order, f'{indent}\t\t')
|
||||
pt_sel = item['points'].get('selection') or ['Auto']
|
||||
@@ -1632,7 +1653,7 @@ def emit_structure_item(lines, item, indent):
|
||||
# Series
|
||||
if item.get('series'):
|
||||
lines.append(f'{indent}\t<dcsset:series>')
|
||||
emit_group_items(lines, item['series'].get('groupBy'), f'{indent}\t\t')
|
||||
emit_group_items(lines, item['series'].get('groupBy') or item['series'].get('groupFields'), f'{indent}\t\t')
|
||||
sr_order = item['series'].get('order') or ['Auto']
|
||||
emit_order(lines, sr_order, f'{indent}\t\t')
|
||||
sr_sel = item['series'].get('selection') or ['Auto']
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# skd-edit v1.8 — Atomic 1C DCS editor
|
||||
# skd-edit v1.9 — Atomic 1C DCS editor
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -1924,6 +1924,23 @@ switch ($Operation) {
|
||||
}
|
||||
|
||||
$selection = Ensure-SettingsChild $targetEl "selection" @()
|
||||
|
||||
# Dedup: skip if SelectedItemAuto already exists
|
||||
if ($fieldName -eq "Auto") {
|
||||
$isDup = $false
|
||||
foreach ($ch in $selection.ChildNodes) {
|
||||
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'item') {
|
||||
$typeAttr = $ch.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
if ($typeAttr -and $typeAttr.Contains("SelectedItemAuto")) { $isDup = $true; break }
|
||||
}
|
||||
}
|
||||
if ($isDup) {
|
||||
$target = if ($groupName) { "group `"$groupName`"" } else { "variant `"$varName`"" }
|
||||
Write-Host "[WARN] SelectedItemAuto already exists in $target — skipped"
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
$selIndent = Get-ContainerChildIndent $selection
|
||||
|
||||
$selXml = Build-SelectionItemFragment -fieldName $fieldName -indent $selIndent
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# skd-edit v1.8 — Atomic 1C DCS editor (Python port)
|
||||
# skd-edit v1.9 — Atomic 1C DCS editor (Python port)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import os
|
||||
@@ -1642,6 +1642,21 @@ elif operation == "add-selection":
|
||||
target_el = settings
|
||||
|
||||
selection = ensure_settings_child(target_el, "selection", [])
|
||||
|
||||
# Dedup: skip if SelectedItemAuto already exists
|
||||
if field_name == "Auto":
|
||||
is_dup = False
|
||||
for ch in selection:
|
||||
if isinstance(ch.tag, str) and local_name(ch) == "item":
|
||||
type_attr = ch.get(XSI_TYPE, "")
|
||||
if "SelectedItemAuto" in type_attr:
|
||||
is_dup = True
|
||||
break
|
||||
if is_dup:
|
||||
target = f'group "{group_name}"' if group_name else f'variant "{var_name}"'
|
||||
print(f'[WARN] SelectedItemAuto already exists in {target} -- skipped')
|
||||
continue
|
||||
|
||||
sel_indent = get_container_child_indent(selection)
|
||||
sel_xml = build_selection_item_fragment(field_name, sel_indent)
|
||||
sel_nodes = import_fragment(xml_doc, sel_xml)
|
||||
|
||||
Reference in New Issue
Block a user