From 10933e73865bb7d2568552d60f04b1cb6e590bc4 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Mon, 6 Jul 2026 16:09:05 +0300 Subject: [PATCH] =?UTF-8?q?feat(meta-compile,meta-decompile):=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA=D0=B0=20=D1=82=D0=B8?= =?UTF-8?q?=D0=BF=D0=B0=20Document=20(=D0=94=D0=BE=D0=BA=D1=83=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D1=8B)=20(v1.43/v0.32)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Шестой тип. Базовый роундтрип 151-выборки acc+erp: TOTAL 11450→166 (−98.5%), match 0→109/151, 0 крашей. Регресс 49/49 ps1+py, ps1==py identical. 1С-cert ✓. Emit-DocumentProperties переписан на общие хелперы (был легаси-хардкод): выбило Characteristics/формы/BasedOn/InputByString/презентации — декомпилятор их уже захватывал, баг был чисто компиляторный. SA-conditional + профиль {Date:ShowError}. Декомпилятор: Document-блок — нумерация, проведение, RegisterRecords (движения), Numerator, DataHistory-триплет, checkUnique-дефолт. Class-2 дефолт-фиксы (рассинхрон компилятор↔декомпилятор↔корпус): createOnInput DontUse→Use, registerRecordsWritingOnPost WriteModified→WriteSelected, dataLockControlMode Automatic→Managed. Новые/исправленные ключи (общее для реквизитов, всплыло на Document): markNegatives, choiceForm/choiceFoldersAndItems, format/editFormat станд.реквизита (SA-override), TS fillChecking. TS-суппресс `lineNumber: ""` — opt-out наличия TS-блока стандартных реквизитов (~6% ТЧ его опускают, правило не выводимо; чинит и хвост Catalog). verify-snapshots: getStructuralDeps стабит регистры registerRecords по MDObjectRef. Остаток (~166, 2 узких хвоста): choiceParameters FixedArray data-specific edge + FillValue станд.реквизита decimal/DTR/пробелы. spec §7.2, кейс document-full. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../meta-compile/scripts/meta-compile.ps1 | 147 ++--- .../meta-compile/scripts/meta-compile.py | 135 +++-- .../meta-decompile/scripts/meta-decompile.ps1 | 63 +- docs/meta-dsl-spec.md | 31 +- .../cases/meta-compile/document-full.json | 39 ++ .../Documents/ПриходнаяНакладная.xml | 138 +---- .../snapshots/document-full/Configuration.xml | 252 ++++++++ .../Documents/РеализацияУслуг.xml | 544 ++++++++++++++++++ .../РеализацияУслуг/Ext/ObjectModule.bsl | 0 .../Ext/ClientApplicationInterface.xml | 18 + .../document-full/Languages/Русский.xml | 16 + .../Documents/ПриходнаяНакладная.xml | 138 +---- .../Documents/РасходнаяНакладная.xml | 138 +---- .../Documents/РеализацияТоваров.xml | 138 +---- tests/skills/verify-snapshots.mjs | 15 + 15 files changed, 1127 insertions(+), 685 deletions(-) create mode 100644 tests/skills/cases/meta-compile/document-full.json create mode 100644 tests/skills/cases/meta-compile/snapshots/document-full/Configuration.xml create mode 100644 tests/skills/cases/meta-compile/snapshots/document-full/Documents/РеализацияУслуг.xml create mode 100644 tests/skills/cases/meta-compile/snapshots/document-full/Documents/РеализацияУслуг/Ext/ObjectModule.bsl create mode 100644 tests/skills/cases/meta-compile/snapshots/document-full/Ext/ClientApplicationInterface.xml create mode 100644 tests/skills/cases/meta-compile/snapshots/document-full/Languages/Русский.xml diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index 7c43c405..c8bb5731 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.42 — Compile 1C metadata object from JSON +# meta-compile v1.43 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -828,6 +828,9 @@ function Parse-AttributeShorthand { editFormat = $val.editFormat mask = if ($val.mask) { "$($val.mask)" } else { "" } extendedEdit = if ($val.extendedEdit -eq $true) { $true } else { $false } + markNegatives = if ($val.markNegatives -eq $true) { $true } else { $false } + choiceForm = if ($val.choiceForm) { "$($val.choiceForm)" } else { "" } + choiceFoldersAndItems = if ($val.choiceFoldersAndItems) { "$($val.choiceFoldersAndItems)" } else { "" } minValue = $val.minValue maxValue = $val.maxValue hasFillValue = ($val.PSObject -and $val.PSObject.Properties -and ($val.PSObject.Properties.Name -contains 'fillValue')) @@ -1060,6 +1063,10 @@ $script:stdAttrProfile = @{ "ChartOfCalculationTypes" = @{ "Description" = @{ FillChecking = "ShowError" } } + # Document: Дата → FillChecking=ShowError (974/1010 доков acc+erp; дата обязательна). + "Document" = @{ + "Date" = @{ FillChecking = "ShowError" } + } } # $ov — hashtable переопределений (профиль + DSL) для полей: FillChecking, FillFromFillingValue, @@ -1120,7 +1127,7 @@ function Emit-StandardAttribute { # Прочие типы (не в множестве) → блок эмитится всегда (текущее поведение, пока их правило не выведено). # - stdAttrProfile[тип]: профиль материализованного блока (пусто = schema-дефолт), поверх — DSL-override. # Миграция типа = добавить его в stdAttrConditionalTypes + stdAttrProfile и переснять снэпшоты; КОД НЕ ТРОГАЕМ. -$script:stdAttrConditionalTypes = @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes') +$script:stdAttrConditionalTypes = @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes', 'Document') function Emit-StandardAttributes { param([string]$indent, [string]$objectType) $attrs = $script:standardAttributesByType[$objectType] @@ -1151,6 +1158,8 @@ function Emit-StandardAttributes { if ($null -ne $d.choiceParameters) { $ov['ChoiceParameters'] = $d.choiceParameters } if ($d.comment) { $ov['Comment'] = "$($d.comment)" } if ($d.mask) { $ov['Mask'] = "$($d.mask)" } + if ($null -ne $d.format) { $ov['Format'] = $d.format } # строка ИЛИ {ru,en} + if ($null -ne $d.editFormat) { $ov['EditFormat'] = $d.editFormat } if ($d.choiceForm) { $ov['ChoiceForm'] = "$($d.choiceForm)" } } } @@ -1581,7 +1590,7 @@ function Emit-Attribute { Emit-MLText "$indent`t`t" "Format" $parsed.format Emit-MLText "$indent`t`t" "EditFormat" $parsed.editFormat Emit-MLText "$indent`t`t" "ToolTip" $parsed.tooltip - X "$indent`t`tfalse" + X "$indent`t`t$(if ($parsed.markNegatives -eq $true) { 'true' } else { 'false' })" if ($parsed.mask) { X "$indent`t`t$(Esc-XmlText $parsed.mask)" } else { X "$indent`t`t" } $multiLine = if ($parsed.multiLine -eq $true -or $parsed.flags -contains "multiline") { "true" } else { "false" } X "$indent`t`t$multiLine" @@ -1608,14 +1617,14 @@ function Emit-Attribute { if ($parsed.fillChecking) { $fillChecking = $parsed.fillChecking } X "$indent`t`t$fillChecking" - X "$indent`t`tItems" + X "$indent`t`t$(if ($parsed.choiceFoldersAndItems) { "$($parsed.choiceFoldersAndItems)" } else { 'Items' })" Emit-ChoiceParameterLinks "$indent`t`t" $parsed.choiceParameterLinks Emit-ChoiceParameters "$indent`t`t" $parsed.choiceParameters $qc = if ($parsed.quickChoice) { $parsed.quickChoice } else { "Auto" } X "$indent`t`t$qc" $coi = if ($parsed.createOnInput) { $parsed.createOnInput } else { "Auto" } X "$indent`t`t$coi" - X "$indent`t`t" + if ($parsed.choiceForm) { X "$indent`t`t$(Esc-Xml "$($parsed.choiceForm)")" } else { X "$indent`t`t" } Emit-LinkByType "$indent`t`t" $parsed.linkByType $chi = if ($parsed.choiceHistoryOnInput) { $parsed.choiceHistoryOnInput } else { "Auto" } X "$indent`t`t$chi" @@ -1712,7 +1721,7 @@ function Emit-Command { # --- 9. TabularSection emitter --- function Emit-TabularSection { - param([string]$indent, [string]$tsName, $columns, [string]$objectType, [string]$objectName, $tsSynonymArg = $null, $tsTooltip = $null, $tsComment = $null, $tsLineNumber = $null) + param([string]$indent, [string]$tsName, $columns, [string]$objectType, [string]$objectName, $tsSynonymArg = $null, $tsTooltip = $null, $tsComment = $null, $tsLineNumber = $null, $tsFillChecking = $null) $uuid = New-Guid-String X "$indent" @@ -1738,8 +1747,13 @@ function Emit-TabularSection { Emit-MLText "$indent`t`t" "Synonym" $tsSynonym if ($tsComment) { X "$indent`t`t$(Esc-XmlText $tsComment)" } else { X "$indent`t`t" } Emit-MLText "$indent`t`t" "ToolTip" $tsTooltip - X "$indent`t`tDontCheck" - Emit-TabularStandardAttributes "$indent`t`t" $tsLineNumber + $tsFc = if ($tsFillChecking) { "$tsFillChecking" } else { "DontCheck" } + X "$indent`t`t$tsFc" + # TS-блок стандартных реквизитов (LineNumber) эмитим ВСЕГДА, кроме подавления `lineNumber: ""` (дом-конвенция + # суппресса): ~6% ТЧ исторически опускают блок (правило не выводимо — Товары all-default его имеет, соседи нет). + if (-not ($tsLineNumber -is [string] -and $tsLineNumber -eq '')) { + Emit-TabularStandardAttributes "$indent`t`t" $tsLineNumber + } # Use=ForItem у ТЧ иерархических ссылочных типов (Catalog, ChartOfCharacteristicTypes); Document не имеет Use. if ($objectType -in @("Catalog", "ChartOfCharacteristicTypes")) { X "$indent`t`tForItem" @@ -1796,7 +1810,7 @@ function Emit-Dimension { X "$indent`t`t" X "$indent`t`t" X "$indent`t`t" - X "$indent`t`tfalse" + X "$indent`t`t$(if ($parsed.markNegatives -eq $true) { 'true' } else { 'false' })" X "$indent`t`t" $multiLine = if ($parsed.multiLine -eq $true -or $parsed.flags -contains "multiline") { "true" } else { "false" } X "$indent`t`t$multiLine" @@ -1816,12 +1830,12 @@ function Emit-Dimension { if ($parsed.flags -contains "req") { $fillChecking = "ShowError" } X "$indent`t`t$fillChecking" - X "$indent`t`tItems" + X "$indent`t`t$(if ($parsed.choiceFoldersAndItems) { "$($parsed.choiceFoldersAndItems)" } else { 'Items' })" X "$indent`t`t" X "$indent`t`t" X "$indent`t`tAuto" X "$indent`t`tAuto" - X "$indent`t`t" + if ($parsed.choiceForm) { X "$indent`t`t$(Esc-Xml "$($parsed.choiceForm)")" } else { X "$indent`t`t" } X "$indent`t`t" X "$indent`t`tAuto" @@ -1891,7 +1905,7 @@ function Emit-Resource { X "$indent`t`t" X "$indent`t`t" X "$indent`t`t" - X "$indent`t`tfalse" + X "$indent`t`t$(if ($parsed.markNegatives -eq $true) { 'true' } else { 'false' })" X "$indent`t`t" $multiLine = if ($parsed.multiLine -eq $true -or $parsed.flags -contains "multiline") { "true" } else { "false" } X "$indent`t`t$multiLine" @@ -1910,12 +1924,12 @@ function Emit-Resource { if ($parsed.flags -contains "req") { $fillChecking = "ShowError" } X "$indent`t`t$fillChecking" - X "$indent`t`tItems" + X "$indent`t`t$(if ($parsed.choiceFoldersAndItems) { "$($parsed.choiceFoldersAndItems)" } else { 'Items' })" X "$indent`t`t" X "$indent`t`t" X "$indent`t`tAuto" X "$indent`t`tAuto" - X "$indent`t`t" + if ($parsed.choiceForm) { X "$indent`t`t$(Esc-Xml "$($parsed.choiceForm)")" } else { X "$indent`t`t" } X "$indent`t`t" X "$indent`t`tAuto" @@ -2049,14 +2063,15 @@ function Emit-DocumentProperties { X "$i$(Esc-Xml $objName)" Emit-MLText $i "Synonym" $synonym - X "$i" - X "$itrue" - 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" + if ($def.numerator) { X "$i$(Esc-Xml "$($def.numerator)")" } else { X "$i" } $numberType = Get-EnumProp "NumberType" "numberType" "String" $numberLength = if ($null -ne $def.numberLength) { "$($def.numberLength)" } else { "11" } $numberAllowedLength = Get-EnumProp "NumberAllowedLength" "numberAllowedLength" "Variable" - $numberPeriodicity = if ($def.numberPeriodicity) { "$($def.numberPeriodicity)" } else { "Year" } + $numberPeriodicity = Get-EnumProp "NumberPeriodicity" "numberPeriodicity" "Year" $checkUnique = if ($def.checkUnique -eq $false) { "false" } else { "true" } $autonumbering = if ($def.autonumbering -eq $false) { "false" } else { "true" } @@ -2068,87 +2083,77 @@ function Emit-DocumentProperties { X "$i$autonumbering" Emit-StandardAttributes $i "Document" - X "$i" + Emit-Characteristics $i $def.characteristics + Emit-BasedOn $i $def.basedOn - X "$i" - X "$i" - X "$i`tDocument.$objName.StandardAttribute.Number" - X "$i" - X "$iDontUse" - X "$iBegin" + # InputByString: override `inputByString` ЛИБО дефолт [Номер]. + if (Test-DefKey 'inputByString') { + $ibFields = @($def.inputByString | ForEach-Object { Expand-DataPath "$_" }) + } else { + $ibFields = @("Document.$objName.StandardAttribute.Number") + } + Emit-FieldBlock $i "InputByString" $ibFields + X "$i$(Get-EnumProp 'CreateOnInput' 'createOnInput' 'Use')" + X "$i$(Get-EnumProp 'SearchStringModeOnInputByString' 'searchStringModeOnInputByString' 'Begin')" X "$iDontUse" X "$iDirectly" - X "$i" - X "$i" - X "$i" - X "$i" - X "$i" - X "$i" + Emit-FormRef $i "DefaultObjectForm" $def.defaultObjectForm + Emit-FormRef $i "DefaultListForm" $def.defaultListForm + Emit-FormRef $i "DefaultChoiceForm" $def.defaultChoiceForm + Emit-FormRef $i "AuxiliaryObjectForm" $def.auxiliaryObjectForm + Emit-FormRef $i "AuxiliaryListForm" $def.auxiliaryListForm + Emit-FormRef $i "AuxiliaryChoiceForm" $def.auxiliaryChoiceForm - $posting = Get-EnumProp "Posting" "posting" "Allow" - $realTimePosting = Get-EnumProp "RealTimePosting" "realTimePosting" "Deny" - $registerRecordsDeletion = Get-EnumProp "RegisterRecordsDeletion" "registerRecordsDeletion" "AutoDelete" - $registerRecordsWritingOnPost = Get-EnumProp "RegisterRecordsWritingOnPost" "registerRecordsWritingOnPost" "WriteModified" - $sequenceFilling = if ($def.sequenceFilling) { "$($def.sequenceFilling)" } else { "AutoFill" } - $postInPrivilegedMode = if ($def.postInPrivilegedMode -eq $false) { "false" } else { "true" } - $unpostInPrivilegedMode = if ($def.unpostInPrivilegedMode -eq $false) { "false" } else { "true" } + X "$i$(Get-EnumProp 'Posting' 'posting' 'Allow')" + X "$i$(Get-EnumProp 'RealTimePosting' 'realTimePosting' 'Deny')" + X "$i$(Get-EnumProp 'RegisterRecordsDeletion' 'registerRecordsDeletion' 'AutoDelete')" + X "$i$(Get-EnumProp 'RegisterRecordsWritingOnPost' 'registerRecordsWritingOnPost' 'WriteSelected')" + X "$i$(Get-EnumProp 'SequenceFilling' 'sequenceFilling' 'AutoFill')" - X "$i$posting" - X "$i$realTimePosting" - X "$i$registerRecordsDeletion" - X "$i$registerRecordsWritingOnPost" - X "$i$sequenceFilling" - - # RegisterRecords + # RegisterRecords — движения (список MDObjectRef, синонимы типов резолвятся). $regRecords = @() if ($def.registerRecords) { foreach ($rr in $def.registerRecords) { $rrStr = "$rr" - # Resolve Russian synonyms in register records if ($rrStr.Contains('.')) { $dotIdx = $rrStr.IndexOf('.') $rrPrefix = $rrStr.Substring(0, $dotIdx) $rrSuffix = $rrStr.Substring($dotIdx + 1) - if ($script:objectTypeSynonyms.ContainsKey($rrPrefix)) { - $rrPrefix = $script:objectTypeSynonyms[$rrPrefix] - } + if ($script:objectTypeSynonyms.ContainsKey($rrPrefix)) { $rrPrefix = $script:objectTypeSynonyms[$rrPrefix] } $regRecords += "$rrPrefix.$rrSuffix" - } else { - $regRecords += $rrStr - } + } else { $regRecords += $rrStr } } } - if ($regRecords.Count -gt 0) { X "$i" - foreach ($rr in $regRecords) { - X "$i`t$rr" - } + foreach ($rr in $regRecords) { X "$i`t$rr" } X "$i" } else { X "$i" } + $postInPrivilegedMode = if ($def.postInPrivilegedMode -eq $false) { "false" } else { "true" } + $unpostInPrivilegedMode = if ($def.unpostInPrivilegedMode -eq $false) { "false" } else { "true" } X "$i$postInPrivilegedMode" X "$i$unpostInPrivilegedMode" - X "$ifalse" - X "$i" - - $dataLockControlMode = Get-EnumProp "DataLockControlMode" "dataLockControlMode" "Automatic" - X "$i$dataLockControlMode" - - $fullTextSearch = Get-EnumProp "FullTextSearch" "fullTextSearch" "Use" - X "$i$fullTextSearch" + $inclHelp = if (Get-BoolProp "includeHelpInContents" $false) { "true" } else { "false" } + X "$i$inclHelp" + $dlFields = if (Test-DefKey 'dataLockFields') { @($def.dataLockFields | ForEach-Object { Expand-DataPath "$_" }) } else { @() } + Emit-FieldBlock $i "DataLockFields" $dlFields + X "$i$(Get-EnumProp 'DataLockControlMode' 'dataLockControlMode' 'Managed')" + X "$i$(Get-EnumProp 'FullTextSearch' 'fullTextSearch' 'Use')" Emit-MLText $i "ObjectPresentation" $def.objectPresentation Emit-MLText $i "ExtendedObjectPresentation" $def.extendedObjectPresentation Emit-MLText $i "ListPresentation" $def.listPresentation Emit-MLText $i "ExtendedListPresentation" $def.extendedListPresentation Emit-MLText $i "Explanation" $def.explanation - X "$iAuto" - X "$iDontUse" - X "$ifalse" - X "$ifalse" + X "$i$(Get-EnumProp 'ChoiceHistoryOnInput' 'choiceHistoryOnInput' 'Auto')" + X "$i$(Get-EnumProp 'DataHistory' 'dataHistory' 'DontUse')" + $updDH = if (Get-BoolProp "updateDataHistoryImmediatelyAfterWrite" $false) { "true" } else { "false" } + X "$i$updDH" + $execDH = if (Get-BoolProp "executeAfterWriteDataHistoryVersionProcessing" $false) { "true" } else { "false" } + X "$i$execDH" } function Emit-EnumProperties { @@ -3531,10 +3536,10 @@ if ($objType -in $typesWithAttrTS) { # Нормализуем в $tsSections[name] = @{ columns; synonym; tooltip; comment }. function New-TsEntry { param($val) if ($val -is [array] -or $val.GetType().Name -eq 'Object[]') { - return @{ columns = @($val); synonym = $null; tooltip = $null; comment = $null; lineNumber = $null } + return @{ columns = @($val); synonym = $null; tooltip = $null; comment = $null; lineNumber = $null; fillChecking = $null } } $cols = if ($val.attributes) { @($val.attributes) } elseif ($val.columns) { @($val.columns) } else { @() } - return @{ columns = $cols; synonym = $val.synonym; tooltip = $val.tooltip; comment = if ($val.comment) { "$($val.comment)" } else { $null }; lineNumber = $val.lineNumber } + return @{ columns = $cols; synonym = $val.synonym; tooltip = $val.tooltip; comment = if ($val.comment) { "$($val.comment)" } else { $null }; lineNumber = $val.lineNumber; fillChecking = $val.fillChecking } } if ($def.tabularSections -is [array] -or $def.tabularSections.GetType().Name -eq "Object[]") { foreach ($ts in $def.tabularSections) { $tsSections[$ts.name] = New-TsEntry $ts } @@ -3584,7 +3589,7 @@ if ($objType -in $typesWithAttrTS) { } foreach ($tsName in $tsSections.Keys) { $tsE = $tsSections[$tsName] - Emit-TabularSection "`t`t`t" $tsName $tsE.columns $objType $objName $tsE.synonym $tsE.tooltip $tsE.comment $tsE.lineNumber + Emit-TabularSection "`t`t`t" $tsName $tsE.columns $objType $objName $tsE.synonym $tsE.tooltip $tsE.comment $tsE.lineNumber $tsE.fillChecking } foreach ($af in $acctFlags) { Emit-Attribute "`t`t`t" $af "account-flag" "AccountingFlag" diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index d42417e6..0624131d 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.42 — Compile 1C metadata object from JSON +# meta-compile v1.43 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -855,6 +855,9 @@ def parse_attribute_shorthand(val): 'editFormat': val.get('editFormat'), 'mask': str(val['mask']) if val.get('mask') else '', 'extendedEdit': True if val.get('extendedEdit') is True else False, + 'markNegatives': True if val.get('markNegatives') is True else False, + 'choiceForm': str(val['choiceForm']) if val.get('choiceForm') else '', + 'choiceFoldersAndItems': str(val['choiceFoldersAndItems']) if val.get('choiceFoldersAndItems') else '', 'minValue': val.get('minValue'), 'maxValue': val.get('maxValue'), 'hasFillValue': ('fillValue' in val), @@ -1075,6 +1078,10 @@ std_attr_profile = { 'ChartOfCalculationTypes': { 'Description': {'FillChecking': 'ShowError'}, }, + # Document: Дата → FillChecking=ShowError (974/1010 доков acc+erp; дата обязательна). + 'Document': { + 'Date': {'FillChecking': 'ShowError'}, + }, } # ov — dict переопределений (профиль + DSL): FillChecking, FillFromFillingValue, Synonym, @@ -1140,7 +1147,7 @@ def emit_standard_attribute(indent, attr_name, ov=None): # Единый эмиттер блока StandardAttributes — поведение правят ДАННЫЕ, не форк кода (см. коммент в .ps1). # std_attr_conditional_types: типы, где блок только при кастомизации (DSL-ключ standardAttributes). # Прочие типы → блок всегда (текущее поведение). Миграция типа = +строчка в оба справочника + снэпшоты. -std_attr_conditional_types = {'Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes'} +std_attr_conditional_types = {'Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes', 'Document'} def emit_standard_attributes(indent, object_type): attrs = standard_attributes_by_type.get(object_type) if not attrs: @@ -1181,6 +1188,10 @@ def emit_standard_attributes(indent, object_type): ov['Comment'] = str(d['comment']) if d.get('mask'): ov['Mask'] = str(d['mask']) + if d.get('format') is not None: + ov['Format'] = d['format'] # строка ИЛИ {ru,en} + if d.get('editFormat') is not None: + ov['EditFormat'] = d['editFormat'] if d.get('choiceForm'): ov['ChoiceForm'] = str(d['choiceForm']) emit_standard_attribute(f'{indent}\t', a, ov) @@ -1650,7 +1661,7 @@ def emit_attribute(indent, parsed, context, elem_tag='Attribute'): emit_mltext(f'{indent}\t\t', 'Format', parsed.get('format')) emit_mltext(f'{indent}\t\t', 'EditFormat', parsed.get('editFormat')) emit_mltext(f'{indent}\t\t', 'ToolTip', parsed.get('tooltip')) - X(f'{indent}\t\tfalse') + X(f'{indent}\t\t{"true" if parsed.get("markNegatives") is True else "false"}') if parsed.get('mask'): X(f'{indent}\t\t{esc_xml_text(parsed["mask"])}') else: @@ -1674,12 +1685,12 @@ def emit_attribute(indent, parsed, context, elem_tag='Attribute'): if parsed.get('fillChecking'): fill_checking = parsed['fillChecking'] X(f'{indent}\t\t{fill_checking}') - X(f'{indent}\t\tItems') + X(f'{indent}\t\t{parsed.get("choiceFoldersAndItems") or "Items"}') emit_choice_parameter_links(f'{indent}\t\t', parsed.get('choiceParameterLinks')) emit_choice_parameters(f'{indent}\t\t', parsed.get('choiceParameters')) X(f'{indent}\t\t{parsed.get("quickChoice") or "Auto"}') X(f'{indent}\t\t{parsed.get("createOnInput") or "Auto"}') - X(f'{indent}\t\t') + X(f'{indent}\t\t{esc_xml(str(parsed["choiceForm"]))}' if parsed.get('choiceForm') else f'{indent}\t\t') emit_link_by_type(f'{indent}\t\t', parsed.get('linkByType')) chi = parsed.get('choiceHistoryOnInput') or 'Auto' X(f'{indent}\t\t{chi}') @@ -1770,7 +1781,7 @@ def emit_command(indent, cmd_name, cmd): X(f'{indent}\t') X(f'{indent}') -def emit_tabular_section(indent, ts_name, columns, object_type, object_name, ts_synonym_arg=None, ts_tooltip=None, ts_comment=None, ts_line_number=None): +def emit_tabular_section(indent, ts_name, columns, object_type, object_name, ts_synonym_arg=None, ts_tooltip=None, ts_comment=None, ts_line_number=None, ts_fill_checking=None): uid = new_uuid() X(f'{indent}') type_prefix = f'{object_type}TabularSection' @@ -1794,8 +1805,11 @@ def emit_tabular_section(indent, ts_name, columns, object_type, object_name, ts_ else: X(f'{indent}\t\t') emit_mltext(f'{indent}\t\t', 'ToolTip', ts_tooltip) - X(f'{indent}\t\tDontCheck') - emit_tabular_standard_attributes(f'{indent}\t\t', ts_line_number) + X(f'{indent}\t\t{ts_fill_checking if ts_fill_checking else "DontCheck"}') + # TS-блок стандартных реквизитов (LineNumber) эмитим ВСЕГДА, кроме подавления `lineNumber: ""` (дом-конвенция + # суппресса): ~6% ТЧ исторически опускают блок (правило не выводимо — Товары all-default его имеет, соседи нет). + if not (isinstance(ts_line_number, str) and ts_line_number == ''): + emit_tabular_standard_attributes(f'{indent}\t\t', ts_line_number) if object_type in ('Catalog', 'ChartOfCharacteristicTypes'): X(f'{indent}\t\tForItem') X(f'{indent}\t') @@ -1843,7 +1857,7 @@ def emit_dimension(indent, parsed, register_type): X(f'{indent}\t\t') X(f'{indent}\t\t') X(f'{indent}\t\t') - X(f'{indent}\t\tfalse') + X(f'{indent}\t\t{"true" if parsed.get("markNegatives") is True else "false"}') X(f'{indent}\t\t') multi_line = 'true' if (parsed.get('multiLine') is True or 'multiline' in parsed.get('flags', [])) else 'false' X(f'{indent}\t\t{multi_line}') @@ -1860,12 +1874,12 @@ def emit_dimension(indent, parsed, register_type): if 'req' in flags: fill_checking = 'ShowError' X(f'{indent}\t\t{fill_checking}') - X(f'{indent}\t\tItems') + X(f'{indent}\t\t{parsed.get("choiceFoldersAndItems") or "Items"}') X(f'{indent}\t\t') X(f'{indent}\t\t') X(f'{indent}\t\tAuto') X(f'{indent}\t\tAuto') - X(f'{indent}\t\t') + X(f'{indent}\t\t{esc_xml(str(parsed["choiceForm"]))}' if parsed.get('choiceForm') else f'{indent}\t\t') X(f'{indent}\t\t') X(f'{indent}\t\tAuto') if register_type == 'InformationRegister': @@ -1918,7 +1932,7 @@ def emit_resource(indent, parsed, register_type): X(f'{indent}\t\t') X(f'{indent}\t\t') X(f'{indent}\t\t') - X(f'{indent}\t\tfalse') + X(f'{indent}\t\t{"true" if parsed.get("markNegatives") is True else "false"}') X(f'{indent}\t\t') multi_line = 'true' if (parsed.get('multiLine') is True or 'multiline' in parsed.get('flags', [])) else 'false' X(f'{indent}\t\t{multi_line}') @@ -1934,12 +1948,12 @@ def emit_resource(indent, parsed, register_type): if 'req' in flags: fill_checking = 'ShowError' X(f'{indent}\t\t{fill_checking}') - X(f'{indent}\t\tItems') + X(f'{indent}\t\t{parsed.get("choiceFoldersAndItems") or "Items"}') X(f'{indent}\t\t') X(f'{indent}\t\t') X(f'{indent}\t\tAuto') X(f'{indent}\t\tAuto') - X(f'{indent}\t\t') + X(f'{indent}\t\t{esc_xml(str(parsed["choiceForm"]))}' if parsed.get('choiceForm') else f'{indent}\t\t') X(f'{indent}\t\t') X(f'{indent}\t\tAuto') if register_type == 'InformationRegister': @@ -2057,13 +2071,20 @@ def emit_document_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}') + 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}') + if defn.get('numerator'): + X(f'{i}{esc_xml(str(defn["numerator"]))}') + else: + X(f'{i}') number_type = get_enum_prop('NumberType', 'numberType', 'String') number_length = str(defn['numberLength']) if defn.get('numberLength') is not None else '11' number_allowed_length = get_enum_prop('NumberAllowedLength', 'numberAllowedLength', 'Variable') - number_periodicity = get_enum_prop('InformationRegisterPeriodicity', 'numberPeriodicity', 'Year') + number_periodicity = get_enum_prop('NumberPeriodicity', 'numberPeriodicity', 'Year') check_unique = 'false' if defn.get('checkUnique') is False else 'true' autonumbering = 'false' if defn.get('autonumbering') is False else 'true' X(f'{i}{number_type}') @@ -2073,34 +2094,30 @@ def emit_document_properties(indent): X(f'{i}{check_unique}') X(f'{i}{autonumbering}') emit_standard_attributes(i, 'Document') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}\tDocument.{obj_name}.StandardAttribute.Number') - X(f'{i}') - X(f'{i}DontUse') - X(f'{i}Begin') + emit_characteristics(i, defn.get('characteristics')) + emit_based_on(i, defn.get('basedOn')) + # InputByString: override `inputByString` ЛИБО дефолт [Номер]. + if 'inputByString' in defn: + ib_fields = [expand_data_path(str(x)) for x in (defn.get('inputByString') or [])] + else: + ib_fields = [f'Document.{obj_name}.StandardAttribute.Number'] + emit_field_block(i, 'InputByString', ib_fields) + X(f'{i}{get_enum_prop("CreateOnInput", "createOnInput", "Use")}') + X(f'{i}{get_enum_prop("SearchStringModeOnInputByString", "searchStringModeOnInputByString", "Begin")}') X(f'{i}DontUse') X(f'{i}Directly') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - posting = get_enum_prop('Posting', 'posting', 'Allow') - real_time_posting = get_enum_prop('RealTimePosting', 'realTimePosting', 'Deny') - reg_records_deletion = get_enum_prop('RegisterRecordsDeletion', 'registerRecordsDeletion', 'AutoDelete') - reg_records_writing = get_enum_prop('RegisterRecordsWritingOnPost', 'registerRecordsWritingOnPost', 'WriteModified') - sequence_filling = str(defn['sequenceFilling']) if defn.get('sequenceFilling') else 'AutoFill' - post_in_priv = 'false' if defn.get('postInPrivilegedMode') is False else 'true' - unpost_in_priv = 'false' if defn.get('unpostInPrivilegedMode') is False else 'true' - X(f'{i}{posting}') - X(f'{i}{real_time_posting}') - X(f'{i}{reg_records_deletion}') - X(f'{i}{reg_records_writing}') - X(f'{i}{sequence_filling}') - # RegisterRecords + emit_form_ref(i, 'DefaultObjectForm', defn.get('defaultObjectForm')) + emit_form_ref(i, 'DefaultListForm', defn.get('defaultListForm')) + emit_form_ref(i, 'DefaultChoiceForm', defn.get('defaultChoiceForm')) + emit_form_ref(i, 'AuxiliaryObjectForm', defn.get('auxiliaryObjectForm')) + emit_form_ref(i, 'AuxiliaryListForm', defn.get('auxiliaryListForm')) + emit_form_ref(i, 'AuxiliaryChoiceForm', defn.get('auxiliaryChoiceForm')) + X(f'{i}{get_enum_prop("Posting", "posting", "Allow")}') + X(f'{i}{get_enum_prop("RealTimePosting", "realTimePosting", "Deny")}') + X(f'{i}{get_enum_prop("RegisterRecordsDeletion", "registerRecordsDeletion", "AutoDelete")}') + X(f'{i}{get_enum_prop("RegisterRecordsWritingOnPost", "registerRecordsWritingOnPost", "WriteSelected")}') + X(f'{i}{get_enum_prop("SequenceFilling", "sequenceFilling", "AutoFill")}') + # RegisterRecords — движения (список MDObjectRef, синонимы типов резолвятся). reg_records = [] if defn.get('registerRecords'): for rr in defn['registerRecords']: @@ -2121,23 +2138,27 @@ def emit_document_properties(indent): X(f'{i}') else: X(f'{i}') + post_in_priv = 'false' if defn.get('postInPrivilegedMode') is False else 'true' + unpost_in_priv = 'false' if defn.get('unpostInPrivilegedMode') is False else 'true' X(f'{i}{post_in_priv}') X(f'{i}{unpost_in_priv}') - X(f'{i}false') - X(f'{i}') - data_lock_control_mode = get_enum_prop('DataLockControlMode', 'dataLockControlMode', 'Automatic') - X(f'{i}{data_lock_control_mode}') - full_text_search = get_enum_prop('FullTextSearch', 'fullTextSearch', 'Use') - X(f'{i}{full_text_search}') + incl_help = 'true' if get_bool_prop('includeHelpInContents', False) else 'false' + X(f'{i}{incl_help}') + dl_fields = [expand_data_path(str(x)) for x in (defn.get('dataLockFields') or [])] if 'dataLockFields' in defn else [] + emit_field_block(i, 'DataLockFields', dl_fields) + X(f'{i}{get_enum_prop("DataLockControlMode", "dataLockControlMode", "Managed")}') + X(f'{i}{get_enum_prop("FullTextSearch", "fullTextSearch", "Use")}') emit_mltext(i, 'ObjectPresentation', defn.get('objectPresentation')) emit_mltext(i, 'ExtendedObjectPresentation', defn.get('extendedObjectPresentation')) emit_mltext(i, 'ListPresentation', defn.get('listPresentation')) emit_mltext(i, 'ExtendedListPresentation', defn.get('extendedListPresentation')) emit_mltext(i, 'Explanation', defn.get('explanation')) - X(f'{i}Auto') - X(f'{i}DontUse') - X(f'{i}false') - X(f'{i}false') + X(f'{i}{get_enum_prop("ChoiceHistoryOnInput", "choiceHistoryOnInput", "Auto")}') + X(f'{i}{get_enum_prop("DataHistory", "dataHistory", "DontUse")}') + upd_dh = 'true' if get_bool_prop('updateDataHistoryImmediatelyAfterWrite', False) else 'false' + X(f'{i}{upd_dh}') + exec_dh = 'true' if get_bool_prop('executeAfterWriteDataHistoryVersionProcessing', False) else 'false' + X(f'{i}{exec_dh}') def emit_enum_properties(indent): i = indent @@ -3336,10 +3357,10 @@ if obj_type in types_with_attr_ts: # Значение ТЧ: массив колонок (синоним авто) ЛИБО объект {attributes/columns, synonym, tooltip, comment}. def new_ts_entry(val): if isinstance(val, list): - return {'columns': val, 'synonym': None, 'tooltip': None, 'comment': None, 'lineNumber': None} + return {'columns': val, 'synonym': None, 'tooltip': None, 'comment': None, 'lineNumber': None, 'fillChecking': None} cols = _as_list(val.get('attributes') or val.get('columns') or []) return {'columns': cols, 'synonym': val.get('synonym'), 'tooltip': val.get('tooltip'), - 'comment': str(val['comment']) if val.get('comment') else None, 'lineNumber': val.get('lineNumber')} + 'comment': str(val['comment']) if val.get('comment') else None, 'lineNumber': val.get('lineNumber'), 'fillChecking': val.get('fillChecking')} if isinstance(ts_data, list): for ts in ts_data: ts_sections[ts['name']] = new_ts_entry(ts) @@ -3391,7 +3412,7 @@ if obj_type in types_with_attr_ts: emit_attribute('\t\t\t', a, context) for ts_name in ts_order: e = ts_sections[ts_name] - emit_tabular_section('\t\t\t', ts_name, e['columns'], obj_type, obj_name, e['synonym'], e['tooltip'], e['comment'], e.get('lineNumber')) + emit_tabular_section('\t\t\t', ts_name, e['columns'], obj_type, obj_name, e['synonym'], e['tooltip'], e['comment'], e.get('lineNumber'), e.get('fillChecking')) for af in acct_flags: emit_attribute('\t\t\t', af, 'account-flag', 'AccountingFlag') for edf in ext_dim_flags: diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 index 64c1199a..38e590e6 100644 --- a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 +++ b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 @@ -1,7 +1,7 @@ -# meta-decompile v0.31 — XML объекта метаданных 1С → JSON-черновик формата meta-compile +# meta-decompile v0.32 — XML объекта метаданных 1С → JSON-черновик формата meta-compile # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # -# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts. Инверс meta-compile (omit-on-default: ключ эмитим только +# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document. Инверс meta-compile (omit-on-default: ключ эмитим только # когда значение в XML отличается от умолчания компилятора). Неподдерживаемый тип / не-MetaDataObject # root → exit 3 (ring3, как form-decompile). param( @@ -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')) { - [Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes)"); exit 3 +if ($objType -notin @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes', 'Document')) { + [Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document)"); exit 3 } $props = $objNode.SelectSingleNode('md:Properties', $nsm) @@ -290,6 +290,9 @@ function Attr-ToDsl { $v = & $en 'ChoiceHistoryOnInput'; if ($v -and $v -ne 'Auto') { $extra['choiceHistoryOnInput'] = $v } $v = & $en 'FillChecking'; if ($v -eq 'ShowWarning') { $extra['fillChecking'] = 'ShowWarning' } $v = & $en 'ExtendedEdit'; if ($v -eq 'true') { $extra['extendedEdit'] = $true } + $v = & $en 'MarkNegatives'; if ($v -eq 'true') { $extra['markNegatives'] = $true } + $v = & $en 'ChoiceFoldersAndItems'; if ($v -and $v -ne 'Items') { $extra['choiceFoldersAndItems'] = $v } + $v = & $en 'ChoiceForm'; if ($v) { $extra['choiceForm'] = $v } # MinValue/MaxValue — граница диапазона (omit при nil). Тип сохраняем: xs:string→строка, xs:decimal→число. foreach ($mm in @('MinValue','MaxValue')) { $mn = $ap.SelectSingleNode("md:$mm", $nsm) @@ -394,10 +397,10 @@ Add-EnumProp 'subordinationUse' 'SubordinationUse' 'ToItems' # Тип-зависимые дефолты (компилятор задаёт их по типу — декомпилятор обязан зеркалить, иначе omit ≠ значению). $descrLenDef = switch ($objType) { 'ExchangePlan' { 150 } 'ChartOfCharacteristicTypes' { 100 } 'ChartOfCalculationTypes' { 100 } default { 25 } } $codeLenDef = if ($objType -eq 'ChartOfCalculationTypes') { 5 } else { 9 } -$createInpDef = if ($objType -eq 'Catalog') { 'Use' } else { 'DontUse' } +$createInpDef = if ($objType -in @('Catalog', 'Document')) { 'Use' } else { 'DontUse' } $dataLockDef = if ($objType -in @('Catalog', 'ChartOfAccounts', 'ChartOfCalculationTypes')) { 'Automatic' } else { 'Managed' } $codeSeriesDef = switch ($objType) { 'ChartOfCharacteristicTypes' { 'WholeCharacteristicKind' } 'ChartOfAccounts' { 'WholeChartOfAccounts' } default { 'WholeCatalog' } } -$checkUniqueDef = ($objType -in @('ChartOfCharacteristicTypes', 'ChartOfAccounts')) # ПВХ/ПС дефолт true, Catalog false +$checkUniqueDef = ($objType -in @('ChartOfCharacteristicTypes', 'ChartOfAccounts', 'Document')) # ПВХ/ПС/Документ дефолт true, Catalog false $defPresDef = if ($objType -eq 'ChartOfAccounts') { 'AsCode' } else { 'AsDescription' } # ПС по умолчанию AsCode Add-IntProp 'codeLength' 'CodeLength' $codeLenDef Add-IntProp 'descriptionLength' 'DescriptionLength' $descrLenDef @@ -465,6 +468,31 @@ if ($objType -eq 'ChartOfCalculationTypes') { Add-BoolProp 'updateDataHistoryImmediatelyAfterWrite' 'UpdateDataHistoryImmediatelyAfterWrite' $false Add-BoolProp 'executeAfterWriteDataHistoryVersionProcessing' 'ExecuteAfterWriteDataHistoryVersionProcessing' $false } +# Document-специфичные свойства: нумерация, проведение, движения, DataHistory-триплет. +if ($objType -eq 'Document') { + $numRef = P 'Numerator'; if ($numRef) { $dsl['numerator'] = $numRef } + Add-EnumProp 'numberType' 'NumberType' 'String' + Add-IntProp 'numberLength' 'NumberLength' 11 + Add-EnumProp 'numberAllowedLength' 'NumberAllowedLength' 'Variable' + Add-EnumProp 'numberPeriodicity' 'NumberPeriodicity' 'Year' + # CheckUnique/Autonumbering у Document уже покрыты общим блоком (дефолты true/true совпадают). + Add-EnumProp 'posting' 'Posting' 'Allow' + Add-EnumProp 'realTimePosting' 'RealTimePosting' 'Deny' + Add-EnumProp 'registerRecordsDeletion' 'RegisterRecordsDeletion' 'AutoDelete' + Add-EnumProp 'registerRecordsWritingOnPost' 'RegisterRecordsWritingOnPost' 'WriteSelected' + Add-EnumProp 'sequenceFilling' 'SequenceFilling' 'AutoFill' + Add-BoolProp 'postInPrivilegedMode' 'PostInPrivilegedMode' $true + Add-BoolProp 'unpostInPrivilegedMode' 'UnpostInPrivilegedMode' $true + # RegisterRecords — движения (список MDObjectRef, omit-on-empty, verbatim). + $rrNode = $props.SelectSingleNode('md:RegisterRecords', $nsm) + if ($rrNode) { + $rrItems = @($rrNode.SelectNodes('xr:Item', $nsm) | ForEach-Object { $_.InnerText }) + if ($rrItems.Count -gt 0) { $dsl['registerRecords'] = [System.Collections.ArrayList]@($rrItems) } + } + Add-EnumProp 'dataHistory' 'DataHistory' 'DontUse' + Add-BoolProp 'updateDataHistoryImmediatelyAfterWrite' 'UpdateDataHistoryImmediatelyAfterWrite' $false + Add-BoolProp 'executeAfterWriteDataHistoryVersionProcessing' 'ExecuteAfterWriteDataHistoryVersionProcessing' $false +} # Короткая форма поля: ..StandardAttribute.X / .Attribute.X → StandardAttribute.X / Attribute.X # (Expand-DataPath компилятора разворачивает частичную форму обратно — dogfood резолвера). @@ -593,6 +621,9 @@ $stdProfileByType = @{ 'ChartOfCalculationTypes' = @{ 'Description' = @{ fillChecking = 'ShowError' } } + 'Document' = @{ + 'Date' = @{ fillChecking = 'ShowError' } + } } $catStdProfile = if ($stdProfileByType.ContainsKey($objType)) { $stdProfileByType[$objType] } else { @{} } # Фикс-список стандартных реквизитов типа (зеркало standardAttributesByType компилятора) — чтобы отличать @@ -603,11 +634,12 @@ $stdFixedByType = @{ 'ChartOfCharacteristicTypes' = @('PredefinedDataName','Predefined','Ref','DeletionMark','Description','Code','Parent','ValueType') 'ChartOfAccounts' = @('PredefinedDataName','Order','OffBalance','Type','Description','Code','Parent','Predefined','DeletionMark','Ref') 'ChartOfCalculationTypes' = @('PredefinedDataName','Predefined','Ref','DeletionMark','ActionPeriodIsBasic','Description','Code') + 'Document' = @('Ref','DeletionMark','Date','Number','Posted') } $stdFixed = if ($stdFixedByType.ContainsKey($objType)) { $stdFixedByType[$objType] } else { @() } # Условные типы: блок эмитим-как-триггер даже пустым (материализуется при отклонении ≥1 реквизита от schema-default; # у ExchangePlan это почти всегда — Description/Code=ShowError; редкий all-default EP блок опускает). -$stdConditionalTypes = @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes') +$stdConditionalTypes = @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes', 'Document') $saNode = $props.SelectSingleNode('md:StandardAttributes', $nsm) if ($saNode) { $saMap = [ordered]@{} @@ -636,6 +668,8 @@ if ($saNode) { if ($fvN -and $fvN.GetAttribute('nil', 'http://www.w3.org/2001/XMLSchema-instance') -ne 'true') { $ov['fillValue'] = Convert-ChScalarNode $fvN } $saCmt = $sa.SelectSingleNode('xr:Comment', $nsm); if ($saCmt -and $saCmt.InnerText) { $ov['comment'] = $saCmt.InnerText } $saMsk = $sa.SelectSingleNode('xr:Mask', $nsm); if ($saMsk -and $saMsk.InnerText) { $ov['mask'] = $saMsk.InnerText } + $saFmt = Get-MLValue ($sa.SelectSingleNode('xr:Format', $nsm)); if ($null -ne $saFmt) { $ov['format'] = $saFmt } + $saEfmt = Get-MLValue ($sa.SelectSingleNode('xr:EditFormat', $nsm)); if ($null -ne $saEfmt) { $ov['editFormat'] = $saEfmt } $saCf = $sa.SelectSingleNode('xr:ChoiceForm', $nsm); if ($saCf -and $saCf.InnerText) { $ov['choiceForm'] = $saCf.InnerText } $saCpl = Parse-ChoiceParameterLinks $sa 'xr:ChoiceParameterLinks'; if ($null -ne $saCpl) { $ov['choiceParameterLinks'] = $saCpl } $saCp = Parse-ChoiceParameters $sa 'xr:ChoiceParameters'; if ($null -ne $saCp) { $ov['choiceParameters'] = $saCp } @@ -685,9 +719,15 @@ if ($childObjs) { elseif ($null -ne $tsSyn) { $tsSynCustom = $true } $tsTt = Get-MLValue ($tsp.SelectSingleNode('md:ToolTip', $nsm)) $tsCmtN = $tsp.SelectSingleNode('md:Comment', $nsm); $tsCmt = if ($tsCmtN) { $tsCmtN.InnerText } else { '' } - # Кастомизация стандартного реквизита LineNumber (НомерСтроки) — omit-on-default по каждому свойству. + # FillChecking ТЧ (обязательность заполнения; omit при DontCheck). + $tsFcN = $tsp.SelectSingleNode('md:FillChecking', $nsm); $tsFc = if ($tsFcN -and $tsFcN.InnerText -ne 'DontCheck') { $tsFcN.InnerText } else { '' } + # TS-блок стандартных реквизитов (LineNumber). Наличие блока — пер-ТЧ артефакт (~6% ТЧ его опускают, + # правило не выводимо). Faithful roundtrip: нет блока → маркер подавления `lineNumber: ""` (дом-конвенция); + # есть блок → захват кастомизации LineNumber (omit-on-default по свойству), all-default → без ключа. $lnObj = [ordered]@{} - $lnNode = $tsp.SelectSingleNode("md:StandardAttributes/xr:StandardAttribute[@name='LineNumber']", $nsm) + $saTsNode = $tsp.SelectSingleNode('md:StandardAttributes', $nsm) + $hasBlock = ($saTsNode -and @($saTsNode.SelectNodes('xr:StandardAttribute', $nsm)).Count -gt 0) + $lnNode = if ($hasBlock) { $saTsNode.SelectSingleNode("xr:StandardAttribute[@name='LineNumber']", $nsm) } else { $null } if ($lnNode) { $lnSyn = Get-MLValue ($lnNode.SelectSingleNode('xr:Synonym', $nsm)); if ($null -ne $lnSyn) { $lnObj['synonym'] = $lnSyn } $lnCmtN = $lnNode.SelectSingleNode('xr:Comment', $nsm); if ($lnCmtN -and $lnCmtN.InnerText) { $lnObj['comment'] = $lnCmtN.InnerText } @@ -697,12 +737,13 @@ if ($childObjs) { $lnEfmt = Get-MLValue ($lnNode.SelectSingleNode('xr:EditFormat', $nsm)); if ($null -ne $lnEfmt) { $lnObj['editFormat'] = $lnEfmt } $lnChiN = $lnNode.SelectSingleNode('xr:ChoiceHistoryOnInput', $nsm); if ($lnChiN -and $lnChiN.InnerText -ne 'Auto') { $lnObj['choiceHistoryOnInput'] = $lnChiN.InnerText } } - if ($tsSynCustom -or ($null -ne $tsTt) -or $tsCmt -or $lnObj.Count -gt 0) { + if ($tsSynCustom -or ($null -ne $tsTt) -or $tsCmt -or $tsFc -or $lnObj.Count -gt 0 -or (-not $hasBlock)) { $to = [ordered]@{} if ($tsSynCustom) { $to['synonym'] = $tsSyn } if ($null -ne $tsTt) { $to['tooltip'] = $tsTt } if ($tsCmt) { $to['comment'] = $tsCmt } - if ($lnObj.Count -gt 0) { $to['lineNumber'] = $lnObj } + if ($tsFc) { $to['fillChecking'] = $tsFc } + if (-not $hasBlock) { $to['lineNumber'] = '' } elseif ($lnObj.Count -gt 0) { $to['lineNumber'] = $lnObj } $to['attributes'] = $cols $tsMap[$tsName] = $to } else { diff --git a/docs/meta-dsl-spec.md b/docs/meta-dsl-spec.md index 692cd71c..2c931c68 100644 --- a/docs/meta-dsl-spec.md +++ b/docs/meta-dsl-spec.md @@ -572,28 +572,47 @@ LineNumber дефолтные. Ключ `lineNumber` на объектной ф Декомпилятор: `inputByString` — только при отличии от выведенного дефолта (иначе опущен); `dataLockFields`/`basedOn` — omit-on-empty. Поля пишутся частичной формой (`StandardAttribute.X`/`Attribute.X`). -### 7.2 Document +### 7.2 Document (Документ) + +Общий с Catalog слой: `synonym`, `comment`, `useStandardCommands`, `inputByString` (§7.1.5, дефолт [Номер]), +формы (`defaultObjectForm`/`defaultListForm`/`defaultChoiceForm`/`auxiliary*`), `standardAttributes` (§7.1.1), +`characteristics` (§7.1.4), `basedOn`, `dataLockFields`, презентации, `createOnInput`, `choiceHistoryOnInput`, +`includeHelpInContents`. Стандартные реквизиты Document: Ref, DeletionMark, Date, Number, Posted. Блок SA +**условный** (профиль материализованного: **Дата → FillChecking=ShowError**, 974/1010 доков); опускается лишь у +редкого all-default дока. | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| +| `numerator` | `""` | Numerator (ссылка `DocumentNumerator.X`, omit-on-empty) | | `numberType` | `String` | NumberType | | `numberLength` | `11` | NumberLength | | `numberAllowedLength` | `Variable` | NumberAllowedLength | -| `numberPeriodicity` | `Year` | NumberPeriodicity | +| `numberPeriodicity` | `Year` | NumberPeriodicity *(корпусная мода; платформа-свежий `Nonperiodical`)* | | `checkUnique` | `true` | CheckUnique | | `autonumbering` | `true` | Autonumbering | | `posting` | `Allow` | Posting | | `realTimePosting` | `Deny` | RealTimePosting | -| `registerRecordsDeletion` | `AutoDelete` | RegisterRecordsDeletion | -| `registerRecordsWritingOnPost` | `WriteModified` | RegisterRecordsWritingOnPost | +| `registerRecordsDeletion` | `AutoDelete` | RegisterRecordsDeletion *(безопасный дефолт для авторства; в корпусе редкий)* | +| `registerRecordsWritingOnPost` | `WriteSelected` | RegisterRecordsWritingOnPost | +| `sequenceFilling` | `AutoFill` | SequenceFilling | | `postInPrivilegedMode` | `true` | PostInPrivilegedMode | | `unpostInPrivilegedMode` | `true` | UnpostInPrivilegedMode | -| `dataLockControlMode` | `Automatic` | DataLockControlMode | +| `createOnInput` | `Use` | CreateOnInput | +| `dataLockControlMode` | `Managed` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | -| `registerRecords` | `[]` | RegisterRecords | +| `dataHistory` | `DontUse` | DataHistory (+ триплет Update/Execute) | +| `registerRecords` | `[]` | RegisterRecords (список MDObjectRef движений; рус.синонимы типов резолвятся) | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | +**Реквизит** (общее для всех типов, всплыло на Document): `markNegatives` (bool, выделять отрицательные красным), +`choiceForm` (ссылка на форму выбора), `choiceFoldersAndItems` (Items|Folders|FoldersAndItems, дефолт Items), +`format`/`editFormat` стандартного реквизита (в `standardAttributes`-override, ML). + +**Табличная часть** (объектная форма): `fillChecking` (обязательность заполнения ТЧ, дефолт DontCheck); +`lineNumber: ""` — **подавляет** эмиссию TS-блока стандартных реквизитов (LineNumber). Наличие блока — пер-ТЧ +исторический артефакт (~6% доковых ТЧ его опускают, правило не выводимо); по умолчанию блок эмитится (opt-out). + ### 7.2a ExchangePlan (План обмена) Близок к Catalog (без иерархии/владельцев/кодогенерации), плюс два своих флага. Общий с Catalog слой: `synonym`, diff --git a/tests/skills/cases/meta-compile/document-full.json b/tests/skills/cases/meta-compile/document-full.json new file mode 100644 index 00000000..9b0df342 --- /dev/null +++ b/tests/skills/cases/meta-compile/document-full.json @@ -0,0 +1,39 @@ +{ + "name": "Документ: движения, проведение, нумерация, кастомизация ТЧ/реквизитов", + "input": { + "type": "Document", + "name": "РеализацияУслуг", + "comment": "полный документ", + "numberType": "String", + "numberLength": 9, + "posting": "Allow", + "realTimePosting": "Allow", + "registerRecordsWritingOnPost": "WriteModified", + "registerRecords": ["AccumulationRegister.Продажи"], + "standardAttributes": { "Date": { "fillChecking": "ShowError" }, "Number": { "synonym": "Номер документа" } }, + "attributes": [ + "Контрагент: CatalogRef.Контрагенты", + { "name": "Сумма", "type": "Number(15,2)", "markNegatives": true }, + { "name": "Ответственный", "type": "CatalogRef.Пользователи" } + ], + "tabularSections": [ + { + "name": "Услуги", + "fillChecking": "ShowError", + "attributes": ["Номенклатура: CatalogRef.Номенклатура", "Количество: Number(10,3)"] + }, + { + "name": "Комментарии", + "lineNumber": "", + "attributes": ["Текст: String(200)"] + } + ] + }, + "validatePath": "Documents/РеализацияУслуг", + "expect": { + "files": [ + "Documents/РеализацияУслуг.xml", + "Documents/РеализацияУслуг/Ext/ObjectModule.bsl" + ] + } +} diff --git a/tests/skills/cases/meta-compile/snapshots/document-basic/Documents/ПриходнаяНакладная.xml b/tests/skills/cases/meta-compile/snapshots/document-basic/Documents/ПриходнаяНакладная.xml index 0a56ae77..4cfba809 100644 --- a/tests/skills/cases/meta-compile/snapshots/document-basic/Documents/ПриходнаяНакладная.xml +++ b/tests/skills/cases/meta-compile/snapshots/document-basic/Documents/ПриходнаяНакладная.xml @@ -40,144 +40,12 @@ Year true true - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - Document.ПриходнаяНакладная.StandardAttribute.Number - DontUse + Use Begin DontUse Directly @@ -190,14 +58,14 @@ Allow Deny AutoDelete - WriteModified + WriteSelected AutoFill true true false - Automatic + Managed Use diff --git a/tests/skills/cases/meta-compile/snapshots/document-full/Configuration.xml b/tests/skills/cases/meta-compile/snapshots/document-full/Configuration.xml new file mode 100644 index 00000000..6f80b4f1 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/document-full/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + UUID-006 + UUID-007 + + + UUID-008 + UUID-009 + + + UUID-010 + UUID-011 + + + UUID-012 + UUID-013 + + + UUID-014 + UUID-015 + + + + TestConfig + + + ru + TestConfig + + + + + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + + + + false + false + false + + + + + + + + + + + + + + + + + + + + + + Biometrics + true + + + Location + false + + + BackgroundLocation + false + + + BluetoothPrinters + false + + + WiFiPrinters + false + + + Contacts + false + + + Calendars + false + + + PushNotifications + false + + + LocalNotifications + false + + + InAppPurchases + false + + + PersonalComputerFileExchange + false + + + Ads + false + + + NumberDialing + false + + + CallProcessing + false + + + CallLog + false + + + AutoSendSMS + false + + + ReceiveSMS + false + + + SMSLog + false + + + Camera + false + + + Microphone + false + + + MusicLibrary + false + + + PictureAndVideoLibraries + false + + + AudioPlaybackAndVibration + false + + + BackgroundAudioPlaybackAndVibration + false + + + InstallPackages + false + + + OSBackup + true + + + ApplicationUsageStatistics + false + + + BarcodeScanning + false + + + BackgroundAudioRecording + false + + + AllFilesAccess + false + + + Videoconferences + false + + + NFC + false + + + DocumentScanning + false + + + SpeechToText + false + + + Geofences + false + + + IncomingShareRequests + false + + + AllIncomingShareRequestsTypesProcessing + false + + + + + + Normal + + + Language.Русский + + + + + + Managed + NotAutoFree + DontUse + DontUse + TaxiEnableVersion8_2 + DontUse + Version8_3_24 + + + + Русский + РеализацияУслуг + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/snapshots/document-full/Documents/РеализацияУслуг.xml b/tests/skills/cases/meta-compile/snapshots/document-full/Documents/РеализацияУслуг.xml new file mode 100644 index 00000000..accfb650 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/document-full/Documents/РеализацияУслуг.xml @@ -0,0 +1,544 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + UUID-006 + UUID-007 + + + UUID-008 + UUID-009 + + + UUID-010 + UUID-011 + + + + РеализацияУслуг + + + ru + Реализация услуг + + + полный документ + true + + String + 9 + Variable + Year + true + true + + + + DontCheck + false + false + Auto + + + false + + + Auto + Auto + + false + Use + false + + + + Use + + + + + + + + DontCheck + false + false + Auto + + + false + + + Auto + Auto + + false + Use + false + + + + Use + + + + + + + + DontCheck + false + false + Auto + + + false + + + Auto + Auto + + false + Use + false + + + + Use + + + + + + + + ShowError + false + false + Auto + + + false + + + Auto + Auto + + false + Use + false + + + + Use + + + + + + + + DontCheck + false + false + Auto + + + false + + + Auto + Auto + + false + Use + false + + + + ru + Номер документа + + + + Use + + + + + + + + + + Document.РеализацияУслуг.StandardAttribute.Number + + Use + Begin + DontUse + Directly + + + + + + + Allow + Allow + AutoDelete + WriteModified + AutoFill + + AccumulationRegister.Продажи + + true + true + false + + Managed + Use + + + + + + Auto + DontUse + false + false + + + + + Контрагент + + + ru + Контрагент + + + + + d5p1:CatalogRef.Контрагенты + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + DontIndex + Use + Use + + + + + Сумма + + + ru + Сумма + + + + + xs:decimal + + 15 + 2 + Any + + + false + + + + true + + false + false + + + false + 0 + DontCheck + Items + + + Auto + Auto + + + Auto + DontIndex + Use + Use + + + + + Ответственный + + + ru + Ответственный + + + + + d5p1:CatalogRef.Пользователи + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + DontIndex + Use + Use + + + + + + UUID-016 + UUID-017 + + + UUID-018 + UUID-019 + + + + Услуги + + + ru + Услуги + + + + + ShowError + + + + DontCheck + false + false + Auto + + + false + + + Auto + Auto + + false + Use + false + + + + Use + + + + + + + + + + + Номенклатура + + + ru + Номенклатура + + + + + d5p1:CatalogRef.Номенклатура + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + DontIndex + Use + Use + + + + + Количество + + + ru + Количество + + + + + xs:decimal + + 10 + 3 + Any + + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + DontIndex + Use + Use + + + + + + + + UUID-023 + UUID-024 + + + UUID-025 + UUID-026 + + + + Комментарии + + + ru + Комментарии + + + + + DontCheck + + + + + Текст + + + ru + Текст + + + + + xs:string + + 200 + Variable + + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + DontIndex + Use + Use + + + + + + + diff --git a/tests/skills/cases/meta-compile/snapshots/document-full/Documents/РеализацияУслуг/Ext/ObjectModule.bsl b/tests/skills/cases/meta-compile/snapshots/document-full/Documents/РеализацияУслуг/Ext/ObjectModule.bsl new file mode 100644 index 00000000..e69de29b diff --git a/tests/skills/cases/meta-compile/snapshots/document-full/Ext/ClientApplicationInterface.xml b/tests/skills/cases/meta-compile/snapshots/document-full/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..3c1161b2 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/document-full/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/snapshots/document-full/Languages/Русский.xml b/tests/skills/cases/meta-compile/snapshots/document-full/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/document-full/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/snapshots/document-journal/Documents/ПриходнаяНакладная.xml b/tests/skills/cases/meta-compile/snapshots/document-journal/Documents/ПриходнаяНакладная.xml index 5678a0ed..1b2828fc 100644 --- a/tests/skills/cases/meta-compile/snapshots/document-journal/Documents/ПриходнаяНакладная.xml +++ b/tests/skills/cases/meta-compile/snapshots/document-journal/Documents/ПриходнаяНакладная.xml @@ -40,144 +40,12 @@ Year true true - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - Document.ПриходнаяНакладная.StandardAttribute.Number - DontUse + Use Begin DontUse Directly @@ -190,14 +58,14 @@ Allow Deny AutoDelete - WriteModified + WriteSelected AutoFill true true false - Automatic + Managed Use diff --git a/tests/skills/cases/meta-compile/snapshots/document-journal/Documents/РасходнаяНакладная.xml b/tests/skills/cases/meta-compile/snapshots/document-journal/Documents/РасходнаяНакладная.xml index 6f874e05..0f7a1042 100644 --- a/tests/skills/cases/meta-compile/snapshots/document-journal/Documents/РасходнаяНакладная.xml +++ b/tests/skills/cases/meta-compile/snapshots/document-journal/Documents/РасходнаяНакладная.xml @@ -40,144 +40,12 @@ Year true true - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - Document.РасходнаяНакладная.StandardAttribute.Number - DontUse + Use Begin DontUse Directly @@ -190,14 +58,14 @@ Allow Deny AutoDelete - WriteModified + WriteSelected AutoFill true true false - Automatic + Managed Use diff --git a/tests/skills/cases/meta-compile/snapshots/document-multiple-tabparts/Documents/РеализацияТоваров.xml b/tests/skills/cases/meta-compile/snapshots/document-multiple-tabparts/Documents/РеализацияТоваров.xml index 07d01121..a570777b 100644 --- a/tests/skills/cases/meta-compile/snapshots/document-multiple-tabparts/Documents/РеализацияТоваров.xml +++ b/tests/skills/cases/meta-compile/snapshots/document-multiple-tabparts/Documents/РеализацияТоваров.xml @@ -40,144 +40,12 @@ Year true true - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - Document.РеализацияТоваров.StandardAttribute.Number - DontUse + Use Begin DontUse Directly @@ -190,14 +58,14 @@ Allow Deny AutoDelete - WriteModified + WriteSelected AutoFill true true false - Automatic + Managed Use diff --git a/tests/skills/verify-snapshots.mjs b/tests/skills/verify-snapshots.mjs index 38c5c0ab..fa58d777 100644 --- a/tests/skills/verify-snapshots.mjs +++ b/tests/skills/verify-snapshots.mjs @@ -169,6 +169,21 @@ function getStructuralDeps(input) { } break; } + case 'Document': + // RegisterRecords (движения) ссылаются на регистры по MDObjectRef — 1С требует их существования. Стабим. + if (inp.registerRecords) { + const regSyn = { 'РегистрСведений': 'InformationRegister', 'РегистрНакопления': 'AccumulationRegister', 'РегистрБухгалтерии': 'AccountingRegister', 'РегистрРасчета': 'CalculationRegister' }; + for (const rr of inp.registerRecords) { + const ref = String(rr).split(':')[0].trim(); + const dot = ref.indexOf('.'); + if (dot < 0) continue; + const t = regSyn[ref.substring(0, dot)] || ref.substring(0, dot); + const n = ref.substring(dot + 1); + const dsl = makeStubDSL(t, n); + if (dsl) deps.push({ type: t, name: n, dsl }); + } + } + break; case 'DocumentJournal': if (inp.registeredDocuments) { for (const docRef of inp.registeredDocuments) {