mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-13 01:14:56 +03:00
feat(skd-decompile): сохранение viewMode/itemsViewMode для round-trip
Decompile теперь читает viewMode/itemsViewMode из XML и сохраняет в JSON точно как было — даже Normal-значения (платформа эмитит эти теги контекстно, и для bit-perfect нам важно наличие, а не сам режим). Чтение: - item-level: selection item, order item (новая object form) - block-level: selection/filter/order/conditionalAppearance → XViewMode на settings - structure group: viewMode + itemsViewMode на самом item - settings: itemsViewMode Дополнительно: - Убран shorthand @normal из filter/condApp/dataParam (Normal — default, шум в JSON) - Структурный shorthand "A > B > details" не сворачивается если есть viewMode/itemsViewMode на элементе - Selection/order на structure-item сохраняются даже = [Auto] — compile теперь не дефолтит, поэтому наличие важно для bit-perfect Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# skd-decompile v0.21 — Decompile 1C DCS Template.xml to JSON DSL (draft)
|
||||
# skd-decompile v0.22 — Decompile 1C DCS Template.xml to JSON DSL (draft)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -1287,8 +1287,8 @@ function Build-FilterItem {
|
||||
if ($use -eq 'false') { $flags += '@off' }
|
||||
if ($userId) { $flags += '@user' }
|
||||
if ($viewMode -eq 'QuickAccess') { $flags += '@quickAccess' }
|
||||
elseif ($viewMode -eq 'Normal') { $flags += '@normal' }
|
||||
elseif ($viewMode -eq 'Inaccessible') { $flags += '@inaccessible' }
|
||||
# Normal is the default — do not emit @normal
|
||||
|
||||
# nullity ops have no value
|
||||
$noValueOps = @('filled','notFilled')
|
||||
@@ -1299,7 +1299,7 @@ function Build-FilterItem {
|
||||
if ($op -notin $noValueOps -and $null -ne $value) { $obj['value'] = $value }
|
||||
if ($use -eq 'false') { $obj['use'] = $false }
|
||||
if ($userId) { $obj['userSettingID'] = 'auto' }
|
||||
if ($viewMode) { $obj['viewMode'] = $viewMode }
|
||||
if ($viewMode -and $viewMode -ne 'Normal') { $obj['viewMode'] = $viewMode }
|
||||
$obj['userSettingPresentation'] = Get-MLText $userPresNode
|
||||
return $obj
|
||||
}
|
||||
@@ -1334,7 +1334,14 @@ function Build-SelectionItem {
|
||||
$fName = Get-Text $item "dcsset:field"
|
||||
$titleNode = $item.SelectSingleNode("dcsset:lwsTitle", $ns)
|
||||
$title = Get-MLText $titleNode
|
||||
if ($title) { return [ordered]@{ field = $fName; title = $title } }
|
||||
$vm = Get-Text $item "dcsset:viewMode"
|
||||
$hasVM = $vm -and $vm -ne 'Normal'
|
||||
if ($title -or $hasVM) {
|
||||
$obj = [ordered]@{ field = $fName }
|
||||
if ($title) { $obj['title'] = $title }
|
||||
if ($hasVM) { $obj['viewMode'] = $vm }
|
||||
return $obj
|
||||
}
|
||||
return $fName
|
||||
}
|
||||
'SelectedItemFolder' {
|
||||
@@ -1379,7 +1386,15 @@ function Build-Order {
|
||||
'OrderItemField' {
|
||||
$fn = Get-Text $it "dcsset:field"
|
||||
$ot = Get-Text $it "dcsset:orderType"
|
||||
if ($ot -eq 'Desc') { $out += "$fn desc" } else { $out += $fn }
|
||||
$vm = Get-Text $it "dcsset:viewMode"
|
||||
if ($vm -and $vm -ne 'Normal') {
|
||||
$obj = [ordered]@{ field = $fn }
|
||||
if ($ot -eq 'Desc') { $obj['direction'] = 'desc' }
|
||||
$obj['viewMode'] = $vm
|
||||
$out += $obj
|
||||
} else {
|
||||
if ($ot -eq 'Desc') { $out += "$fn desc" } else { $out += $fn }
|
||||
}
|
||||
}
|
||||
default { $out += (New-Sentinel -kind "OrderItem:$xt" -loc $loc -detail 'Неизвестный тип сортировки') }
|
||||
}
|
||||
@@ -1437,7 +1452,7 @@ function Build-ConditionalAppearance {
|
||||
$pres = Get-Text $it "dcsset:presentation"
|
||||
if ($pres) { $entry['presentation'] = $pres }
|
||||
$vm = Get-Text $it "dcsset:viewMode"
|
||||
if ($vm) { $entry['viewMode'] = $vm }
|
||||
if ($vm -and $vm -ne 'Normal') { $entry['viewMode'] = $vm }
|
||||
$usid = Get-Text $it "dcsset:userSettingID"
|
||||
if ($usid) { $entry['userSettingID'] = 'auto' }
|
||||
$out += $entry
|
||||
@@ -1666,17 +1681,17 @@ function Build-Structure {
|
||||
$gFields = Get-GroupFields -parentNode $it -loc $loc
|
||||
if ($gFields.Count -gt 0) { $entry['groupFields'] = $gFields }
|
||||
|
||||
# Local selection — only emit if not "[Auto]" default
|
||||
# Local selection — preserve presence (even [Auto]) for bit-perfect round-trip
|
||||
$selNode = $it.SelectSingleNode("dcsset:selection", $ns)
|
||||
$selItems = Build-Selection -selNode $selNode -loc "$loc/selection"
|
||||
if ($selItems.Count -gt 0 -and -not ($selItems.Count -eq 1 -and $selItems[0] -eq 'Auto')) {
|
||||
$entry['selection'] = $selItems
|
||||
if ($selNode) {
|
||||
$selItems = Build-Selection -selNode $selNode -loc "$loc/selection"
|
||||
if ($selItems.Count -gt 0) { $entry['selection'] = $selItems }
|
||||
}
|
||||
# Local order
|
||||
# Local order — same
|
||||
$ordNode = $it.SelectSingleNode("dcsset:order", $ns)
|
||||
$ordItems = Build-Order -ordNode $ordNode -loc "$loc/order"
|
||||
if ($ordItems.Count -gt 0 -and -not ($ordItems.Count -eq 1 -and $ordItems[0] -eq 'Auto')) {
|
||||
$entry['order'] = $ordItems
|
||||
if ($ordNode) {
|
||||
$ordItems = Build-Order -ordNode $ordNode -loc "$loc/order"
|
||||
if ($ordItems.Count -gt 0) { $entry['order'] = $ordItems }
|
||||
}
|
||||
# Local filter
|
||||
$filterNode = $it.SelectSingleNode("dcsset:filter", $ns)
|
||||
@@ -1690,6 +1705,19 @@ function Build-Structure {
|
||||
$children = Build-Structure -node $it -loc "$loc/children"
|
||||
if ($children.Count -gt 0) { $entry['children'] = $children }
|
||||
|
||||
# viewMode / itemsViewMode on the group itself
|
||||
# Read direct-child <dcsset:viewMode> (avoid grabbing item-level ones from selection/filter/order)
|
||||
$gvm = $null; $givm = $null
|
||||
foreach ($ch in $it.ChildNodes) {
|
||||
if ($ch.NodeType -ne 'Element' -or $ch.NamespaceURI -ne 'http://v8.1c.ru/8.1/data-composition-system/settings') { continue }
|
||||
if ($ch.LocalName -eq 'viewMode' -and $null -eq $gvm) { $gvm = $ch.InnerText }
|
||||
elseif ($ch.LocalName -eq 'itemsViewMode' -and $null -eq $givm) { $givm = $ch.InnerText }
|
||||
}
|
||||
# Preserve explicit values (even Normal) so compile bit-perfect roundtrip works:
|
||||
# platform emits viewMode on some StructureItemGroup shapes but not others.
|
||||
if ($null -ne $gvm) { $entry['viewMode'] = $gvm }
|
||||
if ($null -ne $givm) { $entry['itemsViewMode'] = $givm }
|
||||
|
||||
$items += $entry
|
||||
$idx++
|
||||
}
|
||||
@@ -1711,6 +1739,8 @@ function Try-StructureShorthand {
|
||||
if ($cur.Contains('selection')) { return $null }
|
||||
if ($cur.Contains('order')) { return $null }
|
||||
if ($cur.Contains('filter')) { return $null }
|
||||
if ($cur.Contains('viewMode')) { return $null }
|
||||
if ($cur.Contains('itemsViewMode')) { return $null }
|
||||
$gfs = $cur['groupFields']
|
||||
if ($null -eq $gfs -or $gfs.Count -eq 0) {
|
||||
# details level (terminal)
|
||||
@@ -1953,10 +1983,24 @@ foreach ($sv in $svNodes) {
|
||||
$settingsNode = $sv.SelectSingleNode("dcsset:settings", $ns)
|
||||
$settings = [ordered]@{}
|
||||
|
||||
# Helper: read block-level <dcsset:viewMode> (direct child, not item-level)
|
||||
function Get-BlockVM($node) {
|
||||
if (-not $node) { return $null }
|
||||
foreach ($child in $node.ChildNodes) {
|
||||
if ($child.NodeType -eq 'Element' -and $child.LocalName -eq 'viewMode' -and $child.NamespaceURI -eq 'http://v8.1c.ru/8.1/data-composition-system/settings') {
|
||||
return $child.InnerText
|
||||
}
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
# selection (top-level)
|
||||
$selTop = $settingsNode.SelectSingleNode("dcsset:selection", $ns)
|
||||
$selItems = Build-Selection -selNode $selTop -loc "variant[$vi]/selection"
|
||||
if ($selItems.Count -gt 0) { $settings['selection'] = $selItems }
|
||||
# Block-level viewMode: preserve exact presence (even Normal) for bit-perfect round-trip
|
||||
$svm = Get-BlockVM $selTop
|
||||
if ($null -ne $svm) { $settings['selectionViewMode'] = $svm }
|
||||
|
||||
# filter
|
||||
$fTop = $settingsNode.SelectSingleNode("dcsset:filter", $ns)
|
||||
@@ -1965,11 +2009,15 @@ foreach ($sv in $svNodes) {
|
||||
foreach ($fc in $fTop.SelectNodes("dcsset:item", $ns)) { $fa += (Build-FilterItem -itemNode $fc -loc "variant[$vi]/filter") }
|
||||
$settings['filter'] = $fa
|
||||
}
|
||||
$fvm = Get-BlockVM $fTop
|
||||
if ($null -ne $fvm) { $settings['filterViewMode'] = $fvm }
|
||||
|
||||
# order
|
||||
$ordTop = $settingsNode.SelectSingleNode("dcsset:order", $ns)
|
||||
$ordItems = Build-Order -ordNode $ordTop -loc "variant[$vi]/order"
|
||||
if ($ordItems.Count -gt 0) { $settings['order'] = $ordItems }
|
||||
$ovm = Get-BlockVM $ordTop
|
||||
if ($null -ne $ovm) { $settings['orderViewMode'] = $ovm }
|
||||
|
||||
# conditionalAppearance
|
||||
$caTop = $settingsNode.SelectSingleNode("dcsset:conditionalAppearance", $ns)
|
||||
@@ -1977,6 +2025,8 @@ foreach ($sv in $svNodes) {
|
||||
$ca = Build-ConditionalAppearance -caNode $caTop -loc "variant[$vi]/ca"
|
||||
if ($ca.Count -gt 0) { $settings['conditionalAppearance'] = $ca }
|
||||
}
|
||||
$cavm = Get-BlockVM $caTop
|
||||
if ($null -ne $cavm) { $settings['conditionalAppearanceViewMode'] = $cavm }
|
||||
|
||||
# outputParameters
|
||||
$opTop = $settingsNode.SelectSingleNode("dcsset:outputParameters", $ns)
|
||||
@@ -1996,6 +2046,10 @@ foreach ($sv in $svNodes) {
|
||||
else { $settings['structure'] = $structItems }
|
||||
}
|
||||
|
||||
# <dcsset:itemsViewMode> on settings — preserve presence (even Normal)
|
||||
$sivmNode = $settingsNode.SelectSingleNode("dcsset:itemsViewMode", $ns)
|
||||
if ($sivmNode) { $settings['itemsViewMode'] = $sivmNode.InnerText }
|
||||
|
||||
# Skip pure-default variants: settings contains only "details" structure (or nothing) +
|
||||
# name=Основной + no distinctive title.
|
||||
$nonStructKeys = @($settings.Keys | Where-Object { $_ -ne 'structure' })
|
||||
|
||||
@@ -8,5 +8,6 @@
|
||||
"СписокДокументов: CatalogRef.Документы @valueList",
|
||||
"СлужебныйПар: string @hidden",
|
||||
{ "name": "ПорядокОкругления", "type": "EnumRef.Округления", "value": "Перечисление.Округления.Окр1", "availableValues": [{ "value": "Перечисление.Округления.Окр1_00", "presentation": "руб. коп" }, { "value": "Перечисление.Округления.Окр1", "presentation": "руб." }] }
|
||||
]
|
||||
],
|
||||
"settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{ "dataSets": [{ "name": "ПродажиПоПериодам", "query": "@decompiled-ПродажиПоПериодам.sql", "fields": ["Номенклатура: CatalogRef.Номенклатура @dimension", "Количество: decimal(15,3)", "Сумма: decimal(15,2)"] }] }
|
||||
{ "dataSets": [{ "name": "ПродажиПоПериодам", "query": "@decompiled-ПродажиПоПериодам.sql", "fields": ["Номенклатура: CatalogRef.Номенклатура @dimension", "Количество: decimal(15,3)", "Сумма: decimal(15,2)"] }], "settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }] }
|
||||
@@ -3,5 +3,6 @@
|
||||
{ "name": "Запрос1", "query": "ВЫБРАТЬ Номенклатура.Наименование КАК Имя ИЗ Справочник.Номенклатура КАК Номенклатура", "fields": ["Имя: string"] },
|
||||
{ "name": "Журнал", "objectName": "ЖурналОшибок", "fields": ["Сообщение: string(150)", "Уровень: string"] },
|
||||
{ "name": "Объединение", "items": [{ "name": "Часть1", "query": "ВЫБРАТЬ 1 КАК Поле", "fields": ["Поле: decimal(10,2)"] }, { "name": "Часть2", "query": "ВЫБРАТЬ 2 КАК Поле", "fields": ["Поле: decimal(10,2)"] }] }
|
||||
]
|
||||
],
|
||||
"settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }]
|
||||
}
|
||||
@@ -9,5 +9,6 @@
|
||||
{ "field": "ПростоЕА", "type": "CatalogRef.Сотрудники", "inputParameters": [{ "parameter": "ПараметрыВыбора", "choiceParameters": [] }, { "parameter": "БыстрыйВыбор", "use": false, "value": true }] }
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{ "dataSets": [{ "name": "Тест", "query": "ВЫБРАТЬ * ИЗ Справочник.ВидыРасчета", "fields": [{ "field": "ВидРасчета", "type": "CatalogRef.ВидыРасчета", "orderExpression": { "expression": "ЕстьNULL(ВидРасчета.Порядок, 10000)", "orderType": "Asc", "autoOrder": false } }] }] }
|
||||
{ "dataSets": [{ "name": "Тест", "query": "ВЫБРАТЬ * ИЗ Справочник.ВидыРасчета", "fields": [{ "field": "ВидРасчета", "type": "CatalogRef.ВидыРасчета", "orderExpression": { "expression": "ЕстьNULL(ВидРасчета.Порядок, 10000)", "orderType": "Asc", "autoOrder": false } }] }], "settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }] }
|
||||
@@ -1 +1,4 @@
|
||||
{ "dataSets": [{ "name": "Тест", "query": "ВЫБРАТЬ * ИЗ РегистрНакопления.Остатки", "fields": ["Период: date @period", "Контрагент: CatalogRef.Контрагенты @dimension @required", "СуммаНач: decimal(15,2) @balance balanceGroupName=Сумма balanceType=OpeningBalance", "СуммаКон: decimal(15,2) @balance balanceGroupName=Сумма balanceType=ClosingBalance"] }] }
|
||||
{
|
||||
"dataSets": [{ "name": "Тест", "query": "ВЫБРАТЬ * ИЗ РегистрНакопления.Остатки", "fields": ["Период: date @period", "Контрагент: CatalogRef.Контрагенты @dimension @required", "СуммаНач: decimal(15,2) @balance balanceGroupName=Сумма balanceType=OpeningBalance", "СуммаКон: decimal(15,2) @balance balanceGroupName=Сумма balanceType=ClosingBalance"] }],
|
||||
"settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }]
|
||||
}
|
||||
+2
-1
@@ -17,5 +17,6 @@
|
||||
{ "field": "СВыражениемПредставления", "type": "CatalogRef.Номенклатура", "presentationExpression": "Представление(СВыражениемПредставления)" }
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{ "dataSets": [{ "name": "НаборДанных1", "query": "ВЫБРАТЬ Номенклатура.Наименование КАК Наименование ИЗ Справочник.Номенклатура КАК Номенклатура", "fields": ["Наименование"] }] }
|
||||
{ "dataSets": [{ "name": "НаборДанных1", "query": "ВЫБРАТЬ Номенклатура.Наименование КАК Наименование ИЗ Справочник.Номенклатура КАК Номенклатура", "fields": ["Наименование"] }], "settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }] }
|
||||
@@ -1 +1 @@
|
||||
{ "dataSets": [{ "name": "Тест", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "fields": ["Поле: string"] }], "templates": [{ "name": "Заголовок", "style": "myHeader", "rows": [["A"]] }] }
|
||||
{ "dataSets": [{ "name": "Тест", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "fields": ["Поле: string"] }], "templates": [{ "name": "Заголовок", "style": "myHeader", "rows": [["A"]] }], "settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }] }
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{ "dataSets": [{ "name": "Тест", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "fields": ["Поле: string"] }], "templates": [{ "name": "СмешанныйМакет", "style": "data", "rows": [["A", { "value": "B", "style": "header" }, "C"]] }] }
|
||||
{ "dataSets": [{ "name": "Тест", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "fields": ["Поле: string"] }], "templates": [{ "name": "СмешанныйМакет", "style": "data", "rows": [["A", { "value": "B", "style": "header" }, "C"]] }], "settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }] }
|
||||
@@ -1 +1 @@
|
||||
{ "dataSets": [{ "name": "Тест", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "fields": ["Поле1: string", "Поле2: string"] }], "templates": [{ "name": "БезСтиля", "style": "none", "widths": ["7", "7"], "rows": [["A", "B"]] }] }
|
||||
{ "dataSets": [{ "name": "Тест", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "fields": ["Поле1: string", "Поле2: string"] }], "templates": [{ "name": "БезСтиля", "style": "none", "widths": ["7", "7"], "rows": [["A", "B"]] }], "settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }] }
|
||||
+2
-1
@@ -3,5 +3,6 @@
|
||||
"templates": [
|
||||
{ "name": "Шапка", "style": "header", "widths": ["20", "30", "25", "25"], "rows": [["Имя", "Сумма", "Поступление", ">"], ["|", "|", "из произв.", "со сч.40"], ["К1", "К2", "К3", "К4"]] },
|
||||
{ "name": "Данные", "style": "data", "widths": ["20", "30", "25", "25"], "rows": [["{Имя}", "{Сумма}", "{Поступление}", "{СчетПрочее}"]], "parameters": [{ "name": "Имя", "expression": "Имя" }, { "name": "Сумма", "expression": "Сумма" }, { "name": "Поступление", "expression": "СуммаПоступления", "drilldown": "СуммаПоступления" }, { "name": "СчетПрочее", "expression": "СчетПрочее" }] }
|
||||
]
|
||||
],
|
||||
"settingsVariants": [{ "name": "Основной", "settings": { "structure": [{ "selection": ["Auto"], "order": ["Auto"] }] } }]
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
"selection": ["Организация", { "folder": "Объёмы", "items": ["Сумма", "Количество"] }],
|
||||
"filter": ["Организация = _ @off @user", { "group": "Or", "items": ["Статус = Активен", "Сумма > 1000"] }],
|
||||
"order": ["Сумма desc"],
|
||||
"conditionalAppearance": [{ "filter": ["Сумма > 10000"], "appearance": { "ЦветТекста": "style:НегативныйТекстЦвет" }, "presentation": "Большие суммы", "viewMode": "Normal", "userSettingID": "auto" }],
|
||||
"conditionalAppearance": [{ "filter": ["Сумма > 10000"], "appearance": { "ЦветТекста": "style:НегативныйТекстЦвет" }, "presentation": "Большие суммы", "userSettingID": "auto" }],
|
||||
"outputParameters": { "Заголовок": "Сводка по организациям" },
|
||||
"dataParameters": "auto",
|
||||
"structure": "Организация > Номенклатура > details"
|
||||
|
||||
Reference in New Issue
Block a user