diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index 1f3382c9..1f99abb2 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -1,4 +1,4 @@ -# meta-compile v1.45 — Compile 1C metadata object from JSON +# meta-compile v1.46 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -1605,9 +1605,9 @@ function Emit-Attribute { Emit-MinMaxValue "$indent`t`t" "MinValue" $parsed.minValue Emit-MinMaxValue "$indent`t`t" "MaxValue" $parsed.maxValue - # FillFromFillingValue — not for tabular/processor/chart/register-other + # FillFromFillingValue — not for tabular/processor/chart/register-other/register-accum # (Chart*, AccumulationRegister/AccountingRegister/CalculationRegister don't support these) - if ($context -notin @("tabular", "processor", "chart", "register-other")) { + if ($context -notin @("tabular", "processor", "chart", "register-other", "register-accum")) { # Флаг-shorthand `master` у ведущего измерения регистра конвенционально ставит и FillFromFillingValue=true # (эргономика авторинга; декомпилятор пишет key-форму master:true + явный fillFromFillingValue → роундтрип цел). $ffv = if ($parsed.fillFromFillingValue -eq $true -or ($elemTag -eq "Dimension" -and $parsed.flags -contains "master")) { "true" } else { "false" } @@ -1615,7 +1615,7 @@ function Emit-Attribute { } # FillValue — same restriction - if ($context -notin @("tabular", "processor", "chart", "register-other")) { + if ($context -notin @("tabular", "processor", "chart", "register-other", "register-accum")) { Emit-FillValue "$indent`t`t" $typeStr $parsed.fillValue $parsed.hasFillValue } @@ -1647,6 +1647,12 @@ function Emit-Attribute { X "$indent`t`t$denyIncomplete" } + # Измерение регистра накопления: DenyIncompleteValues (между ChoiceHistoryOnInput и Indexing). + if ($elemTag -eq "Dimension" -and $context -eq "register-accum") { + $denyIncomplete = if ($parsed.denyIncompleteValues -eq $true -or $parsed.flags -contains "denyincomplete") { "true" } else { "false" } + X "$indent`t`t$denyIncomplete" + } + # Use — only for catalog top-level attributes if ($context -eq "catalog") { $use = if ($parsed.use) { $parsed.use } else { "ForItem" } @@ -1657,17 +1663,25 @@ function Emit-Attribute { if ($context -notin @("processor", "processor-tabular")) { # Признаки учёта ПС (account-flag) не имеют /, но имеют . if ($context -ne "account-flag") { - $indexing = "DontIndex" - if ($parsed.flags -contains "index") { $indexing = "Index" } - if ($parsed.flags -contains "indexadditional") { $indexing = "IndexWithAdditionalOrder" } - if ($parsed.indexing) { $indexing = $parsed.indexing } - X "$indent`t`t$indexing" + # Ресурс регистра накопления НЕ имеет (только ); измерение/реквизит — имеют. + if (-not ($context -eq "register-accum" -and $elemTag -eq "Resource")) { + $indexing = "DontIndex" + if ($parsed.flags -contains "index") { $indexing = "Index" } + if ($parsed.flags -contains "indexadditional") { $indexing = "IndexWithAdditionalOrder" } + if ($parsed.indexing) { $indexing = $parsed.indexing } + X "$indent`t`t$indexing" + } $fts = if ($parsed.fullTextSearch) { $parsed.fullTextSearch } else { "Use" } X "$indent`t`t$fts" } + # Измерение регистра накопления: UseInTotals (после FullTextSearch, дефолт true). + if ($elemTag -eq "Dimension" -and $context -eq "register-accum") { + $useInTotals = if ($parsed.useInTotals -eq $false -or $parsed.flags -contains "nouseintotals") { "false" } else { "true" } + X "$indent`t`t$useInTotals" + } # DataHistory — not for Chart* types and non-InformationRegister register family - if ($context -notin @("chart", "register-other")) { + if ($context -notin @("chart", "register-other", "register-accum")) { $dh = if ($parsed.dataHistory) { $parsed.dataHistory } else { "Use" } X "$indent`t`t$dh" } @@ -2299,19 +2313,21 @@ function Emit-AccumulationRegisterProperties { X "$i$(Esc-Xml $objName)" Emit-MLText $i "Synonym" $synonym - X "$i" - X "$itrue" - X "$i" - X "$i" + if ($def.comment) { X "$i$(Esc-XmlText "$($def.comment)")" } else { X "$i" } + $useStdCmd = if (Get-BoolProp "useStandardCommands" $true) { "true" } else { "false" } + X "$i$useStdCmd" + Emit-FormRef $i "DefaultListForm" $def.defaultListForm + Emit-FormRef $i "AuxiliaryListForm" $def.auxiliaryListForm $registerType = Get-EnumProp "RegisterType" "registerType" "Balance" X "$i$registerType" - X "$ifalse" + $inclHelp = if (Get-BoolProp "includeHelpInContents" $false) { "true" } else { "false" } + X "$i$inclHelp" Emit-StandardAttributes $i "AccumulationRegister" - $dataLockControlMode = Get-EnumProp "DataLockControlMode" "dataLockControlMode" "Automatic" + $dataLockControlMode = Get-EnumProp "DataLockControlMode" "dataLockControlMode" "Managed" X "$i$dataLockControlMode" $fullTextSearch = Get-EnumProp "FullTextSearch" "fullTextSearch" "Use" @@ -2320,9 +2336,9 @@ function Emit-AccumulationRegisterProperties { $enableTotalsSplitting = if ($def.enableTotalsSplitting -eq $false) { "false" } else { "true" } X "$i$enableTotalsSplitting" - X "$i" - X "$i" - X "$i" + Emit-MLText $i "ListPresentation" $def.listPresentation + Emit-MLText $i "ExtendedListPresentation" $def.extendedListPresentation + Emit-MLText $i "Explanation" $def.explanation } # --- 13a. Wave 1: DefinedType, CommonModule, ScheduledJob, EventSubscription --- @@ -3685,14 +3701,15 @@ if ($objType -in @("InformationRegister","AccumulationRegister","AccountingRegis # InformationRegister.Attribute supports FillFromFillingValue/FillValue/DataHistory; # AccumulationRegister/AccountingRegister/CalculationRegister.Attribute do NOT. $regCtx = if ($objType -eq "InformationRegister") { "register-info" } else { "register-other" } - # InformationRegister: ресурсы/измерения — через богатый Emit-Attribute (общий слой object-свойств). - # Прочие регистры — легаси Emit-Resource/Emit-Dimension (пока не портированы). + # InformationRegister/AccumulationRegister: ресурсы/измерения — через богатый Emit-Attribute (общий слой + # object-свойств). Прочие регистры (Accounting/Calculation) — легаси Emit-Resource/Emit-Dimension (пока не портированы). + $dimResCtx = switch ($objType) { "InformationRegister" { "register-info" } "AccumulationRegister" { "register-accum" } default { $null } } foreach ($r in $resources) { - if ($objType -eq "InformationRegister") { Emit-Attribute "`t`t`t" $r "register-info" "Resource" } + if ($dimResCtx) { Emit-Attribute "`t`t`t" $r $dimResCtx "Resource" } else { Emit-Resource "`t`t`t" $r $objType } } foreach ($d in $dims) { - if ($objType -eq "InformationRegister") { Emit-Attribute "`t`t`t" $d "register-info" "Dimension" } + if ($dimResCtx) { Emit-Attribute "`t`t`t" $d $dimResCtx "Dimension" } else { Emit-Dimension "`t`t`t" $d $objType } } foreach ($a in $regAttrs) { diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index a7643989..49c98a40 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# meta-compile v1.45 — Compile 1C metadata object from JSON +# meta-compile v1.46 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -1681,10 +1681,10 @@ def emit_attribute(indent, parsed, context, elem_tag='Attribute'): emit_min_max_value(f'{indent}\t\t', 'MaxValue', parsed.get('maxValue')) # FillFromFillingValue / FillValue — not for tabular/processor/chart/register-other # (Chart*, AccumulationRegister/AccountingRegister/CalculationRegister don't support these) - if context not in ('tabular', 'processor', 'chart', 'register-other'): + if context not in ('tabular', 'processor', 'chart', 'register-other', 'register-accum'): ffv = 'true' if (parsed.get('fillFromFillingValue') is True or (elem_tag == 'Dimension' and 'master' in parsed.get('flags', []))) else 'false' X(f'{indent}\t\t{ffv}') - if context not in ('tabular', 'processor', 'chart', 'register-other'): + if context not in ('tabular', 'processor', 'chart', 'register-other', 'register-accum'): emit_fill_value(f'{indent}\t\t', type_str, parsed.get('fillValue'), parsed.get('hasFillValue')) fill_checking = 'DontCheck' if 'req' in parsed.get('flags', []): @@ -1709,22 +1709,32 @@ def emit_attribute(indent, parsed, context, elem_tag='Attribute'): X(f'{indent}\t\t{master}') X(f'{indent}\t\t{main_filter}') X(f'{indent}\t\t{deny_incomplete}') + # Измерение регистра накопления: DenyIncompleteValues (между ChoiceHistoryOnInput и Indexing). + if elem_tag == 'Dimension' and context == 'register-accum': + deny_incomplete = 'true' if (parsed.get('denyIncompleteValues') is True or 'denyincomplete' in parsed.get('flags', [])) else 'false' + X(f'{indent}\t\t{deny_incomplete}') if context == 'catalog': X(f'{indent}\t\t{parsed.get("use") or "ForItem"}') if context not in ('processor', 'processor-tabular'): # Признаки учёта ПС (account-flag) не имеют /, но имеют . if context != 'account-flag': - indexing = 'DontIndex' - if 'index' in parsed.get('flags', []): - indexing = 'Index' - if 'indexadditional' in parsed.get('flags', []): - indexing = 'IndexWithAdditionalOrder' - if parsed.get('indexing'): - indexing = parsed['indexing'] - X(f'{indent}\t\t{indexing}') + # Ресурс регистра накопления НЕ имеет (только ); измерение/реквизит — имеют. + if not (context == 'register-accum' and elem_tag == 'Resource'): + indexing = 'DontIndex' + if 'index' in parsed.get('flags', []): + indexing = 'Index' + if 'indexadditional' in parsed.get('flags', []): + indexing = 'IndexWithAdditionalOrder' + if parsed.get('indexing'): + indexing = parsed['indexing'] + X(f'{indent}\t\t{indexing}') X(f'{indent}\t\t{parsed.get("fullTextSearch") or "Use"}') + # Измерение регистра накопления: UseInTotals (после FullTextSearch, дефолт true). + if elem_tag == 'Dimension' and context == 'register-accum': + use_in_totals = 'false' if (parsed.get('useInTotals') is False or 'nouseintotals' in parsed.get('flags', [])) else 'true' + X(f'{indent}\t\t{use_in_totals}') # DataHistory — not for Chart* types and non-InformationRegister register family - if context not in ('chart', 'register-other'): + if context not in ('chart', 'register-other', 'register-accum'): X(f'{indent}\t\t{parsed.get("dataHistory") or "Use"}') X(f'{indent}\t') X(f'{indent}') @@ -2278,23 +2288,28 @@ def emit_accumulation_register_properties(indent): i = indent X(f'{i}{esc_xml(obj_name)}') emit_mltext(i, 'Synonym', synonym) - X(f'{i}') - X(f'{i}true') - X(f'{i}') - X(f'{i}') + if defn.get('comment'): + X(f'{i}{esc_xml_text(str(defn["comment"]))}') + else: + X(f'{i}') + use_std_cmd = 'true' if get_bool_prop('useStandardCommands', True) else 'false' + X(f'{i}{use_std_cmd}') + emit_form_ref(i, 'DefaultListForm', defn.get('defaultListForm')) + emit_form_ref(i, 'AuxiliaryListForm', defn.get('auxiliaryListForm')) register_type = get_enum_prop('RegisterType', 'registerType', 'Balance') X(f'{i}{register_type}') - X(f'{i}false') + incl_help = 'true' if get_bool_prop('includeHelpInContents', False) else 'false' + X(f'{i}{incl_help}') emit_standard_attributes(i, 'AccumulationRegister') - data_lock_control_mode = get_enum_prop('DataLockControlMode', 'dataLockControlMode', 'Automatic') + data_lock_control_mode = get_enum_prop('DataLockControlMode', 'dataLockControlMode', 'Managed') X(f'{i}{data_lock_control_mode}') full_text_search = get_enum_prop('FullTextSearch', 'fullTextSearch', 'Use') X(f'{i}{full_text_search}') enable_totals_splitting = 'false' if defn.get('enableTotalsSplitting') is False else 'true' X(f'{i}{enable_totals_splitting}') - X(f'{i}') - X(f'{i}') - X(f'{i}') + emit_mltext(i, 'ListPresentation', defn.get('listPresentation')) + emit_mltext(i, 'ExtendedListPresentation', defn.get('extendedListPresentation')) + emit_mltext(i, 'Explanation', defn.get('explanation')) # --- 13a. DefinedType, CommonModule, ScheduledJob, EventSubscription --- @@ -3491,16 +3506,17 @@ if obj_type in ('InformationRegister', 'AccumulationRegister', 'AccountingRegist # InformationRegister.Attribute supports FillFromFillingValue/FillValue/DataHistory; # AccumulationRegister/AccountingRegister/CalculationRegister.Attribute do NOT. reg_ctx = 'register-info' if obj_type == 'InformationRegister' else 'register-other' - # InformationRegister: ресурсы/измерения — через богатый emit_attribute (общий слой object-свойств). - # Прочие регистры — легаси emit_resource/emit_dimension (пока не портированы). + # InformationRegister/AccumulationRegister: ресурсы/измерения — через богатый emit_attribute (общий слой + # object-свойств). Прочие регистры (Accounting/Calculation) — легаси emit_resource/emit_dimension (не портированы). + dim_res_ctx = {'InformationRegister': 'register-info', 'AccumulationRegister': 'register-accum'}.get(obj_type) for r in resources: - if obj_type == 'InformationRegister': - emit_attribute('\t\t\t', r, 'register-info', 'Resource') + if dim_res_ctx: + emit_attribute('\t\t\t', r, dim_res_ctx, 'Resource') else: emit_resource('\t\t\t', r, obj_type) for d in dims: - if obj_type == 'InformationRegister': - emit_attribute('\t\t\t', d, 'register-info', 'Dimension') + if dim_res_ctx: + emit_attribute('\t\t\t', d, dim_res_ctx, 'Dimension') else: emit_dimension('\t\t\t', d, obj_type) for a in reg_attrs: diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 index b1a340fa..37522481 100644 --- a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 +++ b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 @@ -1,4 +1,4 @@ -# meta-decompile v0.37 — XML объекта метаданных 1С → JSON-черновик формата meta-compile +# meta-decompile v0.38 — XML объекта метаданных 1С → JSON-черновик формата meta-compile # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # # Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document. Инверс meta-compile (omit-on-default: ключ эмитим только @@ -91,8 +91,8 @@ foreach ($c in $rootEl.ChildNodes) { if ($c.NodeType -eq 'Element') { $objNode = if (-not $objNode) { [Console]::Error.WriteLine("meta-decompile: пустой MetaDataObject"); exit 3 } $objType = $objNode.LocalName -if ($objType -notin @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes', 'Document', 'InformationRegister')) { - [Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document, InformationRegister)"); exit 3 +if ($objType -notin @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes', 'Document', 'InformationRegister', 'AccumulationRegister')) { + [Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document, InformationRegister, AccumulationRegister)"); exit 3 } $props = $objNode.SelectSingleNode('md:Properties', $nsm) @@ -297,6 +297,7 @@ function Attr-ToDsl { $v = & $en 'Master'; if ($v -eq 'true') { $extra['master'] = $true } $v = & $en 'MainFilter'; if ($v -eq 'true') { $extra['mainFilter'] = $true } $v = & $en 'DenyIncompleteValues'; if ($v -eq 'true') { $extra['denyIncompleteValues'] = $true } + $v = & $en 'UseInTotals'; if ($v -eq 'false') { $extra['useInTotals'] = $false } # дефолт true → захват при false # MinValue/MaxValue — граница диапазона (omit при nil). Тип сохраняем: xs:string→строка, xs:decimal→число. foreach ($mm in @('MinValue','MaxValue')) { $mn = $ap.SelectSingleNode("md:$mm", $nsm) @@ -516,6 +517,11 @@ if ($objType -eq 'InformationRegister') { Add-BoolProp 'updateDataHistoryImmediatelyAfterWrite' 'UpdateDataHistoryImmediatelyAfterWrite' $false Add-BoolProp 'executeAfterWriteDataHistoryVersionProcessing' 'ExecuteAfterWriteDataHistoryVersionProcessing' $false } +# AccumulationRegister-специфичные свойства: тип регистра, разделение итогов. +if ($objType -eq 'AccumulationRegister') { + Add-EnumProp 'registerType' 'RegisterType' 'Balance' + Add-BoolProp 'enableTotalsSplitting' 'EnableTotalsSplitting' $true +} # Короткая форма поля: ..StandardAttribute.X / .Attribute.X → StandardAttribute.X / Attribute.X # (Expand-DataPath компилятора разворачивает частичную форму обратно — dogfood резолвера). @@ -704,8 +710,8 @@ if ($saNode) { } # Условный тип (Catalog): пустой $saMap = триггер блока. Не-условный (ExchangePlan): блок и так эмитится → пустой не пишем. if ($saMap.Count -gt 0 -or ($stdConditionalTypes -contains $objType)) { $dsl['standardAttributes'] = $saMap } -} elseif ($objType -eq 'InformationRegister') { - # Регистр опускает all-default блок стандартных реквизитов (~5%, правило не выводимо) — компилятор эмитит его +} elseif ($objType -in @('InformationRegister', 'AccumulationRegister')) { + # Регистр опускает all-default блок стандартных реквизитов (~5-9%, правило не выводимо) — компилятор эмитит его # по дефолту, поэтому отсутствие фиксируем opt-out `standardAttributes:""` (дом-конвенция суппресса). $dsl['standardAttributes'] = '' } diff --git a/docs/meta-dsl-spec.md b/docs/meta-dsl-spec.md index a50cb7b5..78bdd1b8 100644 --- a/docs/meta-dsl-spec.md +++ b/docs/meta-dsl-spec.md @@ -836,13 +836,23 @@ choiceParameters/indexing/fullTextSearch/dataHistory/…, см. §3–4). При | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| -| `registerType` | `Balance` | RegisterType | +| `registerType` | `Balance` | RegisterType (Balance/Turnovers) | | `enableTotalsSplitting` | `true` | EnableTotalsSplitting | -| `dataLockControlMode` | `Automatic` | DataLockControlMode | +| `dataLockControlMode` | `Managed` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | -| `dimensions` | `[]` | → Dimension в ChildObjects | -| `resources` | `[]` | → Resource в ChildObjects | +| `useStandardCommands` | `true` | UseStandardCommands | +| `comment` | пусто | Comment | +| `listPresentation` / `extendedListPresentation` / `explanation` | пусто | презентации (ML) | +| `defaultListForm` / `auxiliaryListForm` | пусто | *ListForm (ссылка на форму) | +| `standardAttributes` | (блок всегда) | `""` — opt-out: подавить all-default блок (~9% регистров опускают) | +| `dimensions` | `[]` | → Dimension в ChildObjects (богатый object-слой + `denyIncomplete`/`useInTotals`) | +| `resources` | `[]` | → Resource в ChildObjects (богатый object-слой; без Indexing/DataHistory) | | `attributes` | `[]` | → Attribute в ChildObjects | +| `commands` | `[]` | → Command в ChildObjects (см. §7.1.3) | + +Измерения/ресурсы РН поддерживают полный object-слой реквизита (synonym/tooltip/comment/type/choiceParameters/…, §3–4). +Признаки измерения — флаги shorthand (`denyIncomplete`, `nouseintotals`) ЛИБО object-ключи (`denyIncompleteValues`, +`useInTotals`: bool, дефолт true). Ресурс РН НЕ имеет `` (только ``). ### 7.7 DefinedType diff --git a/tests/skills/cases/meta-compile/snapshots/accumulation-register/AccumulationRegisters/ОстаткиТоваров.xml b/tests/skills/cases/meta-compile/snapshots/accumulation-register/AccumulationRegisters/ОстаткиТоваров.xml index ca8e7b23..f3ce2359 100644 --- a/tests/skills/cases/meta-compile/snapshots/accumulation-register/AccumulationRegisters/ОстаткиТоваров.xml +++ b/tests/skills/cases/meta-compile/snapshots/accumulation-register/AccumulationRegisters/ОстаткиТоваров.xml @@ -147,7 +147,7 @@ - Automatic + Managed Use true