From 60519723912106814617cfb1223a3db4a07114a0 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sat, 7 Mar 2026 21:33:56 +0300 Subject: [PATCH] fix(meta-compile,meta-validate): fix 7 e2e bugs, add hints and reserved name checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Group 1: ExchangePlan — remove invalid CodeType/CheckUnique/Autonumbering; Flowchart.xml — add version="2.17"; Content.xml — fix namespace + version. Group 2: Add missing GeneratedType categories — DefinedType, ChartOfAccounts ExtDimensionTypes/Row, CalculationRegister RecalculationsManager/Recalcs. Group 3: BusinessProcess — emit property from DSL. Group 4: Cross-reference [HINT] output after compilation for AccountingRegister, CalculationRegister, BusinessProcess, ChartOfAccounts (oriented to /meta-edit DSL). Group 5: Reserved attribute name warnings in meta-compile and meta-validate (Check 7b); cross-reference validation in Check 10 with [HINT] output. All changes synced to both PS1 and PY versions. Co-Authored-By: Claude Opus 4.6 --- .../meta-compile/scripts/meta-compile.ps1 | 71 +++++++++++++--- .../meta-compile/scripts/meta-compile.py | 70 ++++++++++++++-- .../meta-validate/scripts/meta-validate.ps1 | 80 +++++++++++++++++++ .../meta-validate/scripts/meta-validate.py | 72 +++++++++++++++++ docs/meta-dsl-spec.md | 3 +- 5 files changed, 274 insertions(+), 22 deletions(-) diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index 6995acc3..c67e614a 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -436,13 +436,16 @@ $script:generatedTypes = @{ @{ prefix = "CalculationRegisterList"; category = "List" } @{ prefix = "CalculationRegisterRecordSet"; category = "RecordSet" } @{ prefix = "CalculationRegisterRecordKey"; category = "RecordKey" } + @{ prefix = "RecalculationsManager"; category = "Recalcs" } ) "ChartOfAccounts" = @( - @{ prefix = "ChartOfAccountsObject"; category = "Object" } - @{ prefix = "ChartOfAccountsRef"; category = "Ref" } - @{ prefix = "ChartOfAccountsSelection"; category = "Selection" } - @{ prefix = "ChartOfAccountsList"; category = "List" } - @{ prefix = "ChartOfAccountsManager"; category = "Manager" } + @{ prefix = "ChartOfAccountsObject"; category = "Object" } + @{ prefix = "ChartOfAccountsRef"; category = "Ref" } + @{ prefix = "ChartOfAccountsSelection"; category = "Selection" } + @{ prefix = "ChartOfAccountsList"; category = "List" } + @{ prefix = "ChartOfAccountsManager"; category = "Manager" } + @{ prefix = "ChartOfAccountsExtDimensionTypes"; category = "ExtDimensionTypes" } + @{ prefix = "ChartOfAccountsExtDimensionTypesRow"; category = "ExtDimensionTypesRow" } ) "ChartOfCharacteristicTypes" = @( @{ prefix = "ChartOfCharacteristicTypesObject"; category = "Object" } @@ -487,6 +490,9 @@ $script:generatedTypes = @{ @{ prefix = "ExchangePlanList"; category = "List" } @{ prefix = "ExchangePlanManager"; category = "Manager" } ) + "DefinedType" = @( + @{ prefix = "DefinedType"; category = "DefinedType" } + ) "DocumentJournal" = @( @{ prefix = "DocumentJournalSelection"; category = "Selection" } @{ prefix = "DocumentJournalList"; category = "List" } @@ -592,9 +598,26 @@ function Emit-TabularStandardAttributes { # --- 8. Attribute emitter --- +$script:reservedAttrNames = @{ + "Ref"="Ссылка"; "DeletionMark"="ПометкаУдаления"; "Code"="Код"; "Description"="Наименование" + "Date"="Дата"; "Number"="Номер"; "Posted"="Проведен"; "Parent"="Родитель"; "Owner"="Владелец" + "IsFolder"="ЭтоГруппа"; "Predefined"="Предопределенный"; "PredefinedDataName"="ИмяПредопределенныхДанных" + "Recorder"="Регистратор"; "Period"="Период"; "LineNumber"="НомерСтроки"; "Active"="Активность" + "Order"="Порядок"; "Type"="Тип"; "OffBalance"="Забалансовый" + "Started"="Стартован"; "Completed"="Завершен"; "HeadTask"="ВедущаяЗадача" + "Executed"="Выполнена"; "RoutePoint"="ТочкаМаршрута"; "BusinessProcess"="БизнесПроцесс" + "ThisNode"="ЭтотУзел"; "SentNo"="НомерОтправленного"; "ReceivedNo"="НомерПринятого" + "CalculationType"="ВидРасчета"; "RegistrationPeriod"="ПериодРегистрации"; "ReversingEntry"="СторноЗапись" + "Account"="Счет"; "ValueType"="ТипЗначения"; "ActionPeriodIsBasic"="ПериодДействияБазовый" +} + function Emit-Attribute { param([string]$indent, $parsed, [string]$context) # $context: "catalog", "document", "object", "processor", "tabular", "processor-tabular", "register" + $attrName = $parsed.name + if ($script:reservedAttrNames.ContainsKey($attrName) -or $script:reservedAttrNames.ContainsValue($attrName)) { + Write-Warning "Attribute '$attrName' conflicts with a standard attribute name. This may cause errors when loading into 1C." + } $uuid = New-Guid-String X "$indent" X "$indent`t" @@ -1440,19 +1463,13 @@ function Emit-ExchangePlanProperties { $codeLength = if ($null -ne $def.codeLength) { "$($def.codeLength)" } else { "9" } $descriptionLength = if ($null -ne $def.descriptionLength) { "$($def.descriptionLength)" } else { "100" } - $codeType = if ($def.codeType) { "$($def.codeType)" } else { "String" } $codeAllowedLength = if ($def.codeAllowedLength) { "$($def.codeAllowedLength)" } else { "Variable" } - $autonumbering = if ($def.autonumbering -eq $false) { "false" } else { "true" } - $checkUnique = if ($def.checkUnique -eq $true) { "true" } else { "false" } X "$i$codeLength" - X "$i$codeType" X "$i$codeAllowedLength" X "$i$descriptionLength" X "$iAsDescription" X "$iInDialog" - X "$i$checkUnique" - X "$i$autonumbering" Emit-StandardAttributes $i "ExchangePlan" @@ -1941,6 +1958,13 @@ function Emit-BusinessProcessProperties { Emit-StandardAttributes $i "BusinessProcess" X "$i" + $task = if ($def.task) { "$($def.task)" } else { "" } + if ($task) { + X "$i$task" + } else { + X "$i" + } + X "$i" X "$i" X "$i`tBusinessProcess.$objName.StandardAttribute.Number" @@ -2708,7 +2732,7 @@ if ($objType -in $typesWithModule) { if ($objType -eq "ExchangePlan") { $contentPath = Join-Path $extDir "Content.xml" if (-not (Test-Path $contentPath)) { - $contentXml = "`r`n`r`n" + $contentXml = "`r`n`r`n" [System.IO.File]::WriteAllText($contentPath, $contentXml, $enc) $modulesCreated += $contentPath } @@ -2716,7 +2740,7 @@ if ($objType -eq "ExchangePlan") { if ($objType -eq "BusinessProcess") { $flowchartPath = Join-Path $extDir "Flowchart.xml" if (-not (Test-Path $flowchartPath)) { - $flowchartXml = "`r`n`r`n" + $flowchartXml = "`r`n`r`n" [System.IO.File]::WriteAllText($flowchartPath, $flowchartXml, $enc) $modulesCreated += $flowchartPath } @@ -2842,3 +2866,24 @@ switch ($regResult) { "no-childobj" { Write-Warning "Configuration.xml found but not found" } "no-config" { Write-Host " Configuration.xml: not found at $configXmlPath (register manually)" } } + +# Cross-reference hints +if ($objType -eq "AccountingRegister" -and -not $def.chartOfAccounts) { + Write-Host "[HINT] AccountingRegister requires ChartOfAccounts reference:" + Write-Host " /meta-edit -Operation modify-property -Value `"ChartOfAccounts=ChartOfAccounts.XXX`"" +} +if ($objType -eq "CalculationRegister" -and -not $def.chartOfCalculationTypes) { + Write-Host "[HINT] CalculationRegister requires ChartOfCalculationTypes reference:" + Write-Host " /meta-edit -Operation modify-property -Value `"ChartOfCalculationTypes=ChartOfCalculationTypes.XXX`"" +} +if ($objType -eq "BusinessProcess" -and -not $def.task) { + Write-Host "[HINT] BusinessProcess requires Task reference:" + Write-Host " /meta-edit -Operation modify-property -Value `"Task=Task.XXX`"" +} +if ($objType -eq "ChartOfAccounts") { + $maxExtDim = if ($null -ne $def.maxExtDimensionCount) { [int]$def.maxExtDimensionCount } else { 0 } + if ($maxExtDim -gt 0 -and -not $def.extDimensionTypes) { + Write-Host "[HINT] ChartOfAccounts with MaxExtDimensionCount>0 requires ExtDimensionTypes:" + Write-Host " /meta-edit -Operation modify-property -Value `"ExtDimensionTypes=ChartOfCharacteristicTypes.XXX`"" + } +} diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index 045b09af..b1ea7bcf 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -406,6 +406,7 @@ generated_types = { {'prefix': 'CalculationRegisterList', 'category': 'List'}, {'prefix': 'CalculationRegisterRecordSet', 'category': 'RecordSet'}, {'prefix': 'CalculationRegisterRecordKey', 'category': 'RecordKey'}, + {'prefix': 'RecalculationsManager', 'category': 'Recalcs'}, ], 'ChartOfAccounts': [ {'prefix': 'ChartOfAccountsObject', 'category': 'Object'}, @@ -413,6 +414,8 @@ generated_types = { {'prefix': 'ChartOfAccountsSelection', 'category': 'Selection'}, {'prefix': 'ChartOfAccountsList', 'category': 'List'}, {'prefix': 'ChartOfAccountsManager', 'category': 'Manager'}, + {'prefix': 'ChartOfAccountsExtDimensionTypes', 'category': 'ExtDimensionTypes'}, + {'prefix': 'ChartOfAccountsExtDimensionTypesRow', 'category': 'ExtDimensionTypesRow'}, ], 'ChartOfCharacteristicTypes': [ {'prefix': 'ChartOfCharacteristicTypesObject', 'category': 'Object'}, @@ -457,6 +460,9 @@ generated_types = { {'prefix': 'ExchangePlanList', 'category': 'List'}, {'prefix': 'ExchangePlanManager', 'category': 'Manager'}, ], + 'DefinedType': [ + {'prefix': 'DefinedType', 'category': 'DefinedType'}, + ], 'DocumentJournal': [ {'prefix': 'DocumentJournalSelection', 'category': 'Selection'}, {'prefix': 'DocumentJournalList', 'category': 'List'}, @@ -554,7 +560,40 @@ def emit_tabular_standard_attributes(indent): # 8. Attribute emitter # --------------------------------------------------------------------------- +RESERVED_ATTR_NAMES = { + 'Ref', 'DeletionMark', 'Code', 'Description', 'Date', 'Number', 'Posted', + 'Parent', 'Owner', 'IsFolder', 'Predefined', 'PredefinedDataName', + 'Recorder', 'Period', 'LineNumber', 'Active', 'Order', 'Type', 'OffBalance', + 'Started', 'Completed', 'HeadTask', 'Executed', 'RoutePoint', 'BusinessProcess', + 'ThisNode', 'SentNo', 'ReceivedNo', 'CalculationType', 'RegistrationPeriod', + 'ReversingEntry', 'Account', 'ValueType', 'ActionPeriodIsBasic', +} +RESERVED_ATTR_NAMES_RU = { + '\u0421\u0441\u044b\u043b\u043a\u0430', '\u041f\u043e\u043c\u0435\u0442\u043a\u0430\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u044f', + '\u041a\u043e\u0434', '\u041d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435', + '\u0414\u0430\u0442\u0430', '\u041d\u043e\u043c\u0435\u0440', '\u041f\u0440\u043e\u0432\u0435\u0434\u0435\u043d', + '\u0420\u043e\u0434\u0438\u0442\u0435\u043b\u044c', '\u0412\u043b\u0430\u0434\u0435\u043b\u0435\u0446', + '\u042d\u0442\u043e\u0413\u0440\u0443\u043f\u043f\u0430', '\u041f\u0440\u0435\u0434\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439', + '\u0418\u043c\u044f\u041f\u0440\u0435\u0434\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445\u0414\u0430\u043d\u043d\u044b\u0445', + '\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440', '\u041f\u0435\u0440\u0438\u043e\u0434', + '\u041d\u043e\u043c\u0435\u0440\u0421\u0442\u0440\u043e\u043a\u0438', '\u0410\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c', + '\u041f\u043e\u0440\u044f\u0434\u043e\u043a', '\u0422\u0438\u043f', '\u0417\u0430\u0431\u0430\u043b\u0430\u043d\u0441\u043e\u0432\u044b\u0439', + '\u0421\u0442\u0430\u0440\u0442\u043e\u0432\u0430\u043d', '\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043d', + '\u0412\u0435\u0434\u0443\u0449\u0430\u044f\u0417\u0430\u0434\u0430\u0447\u0430', + '\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430', '\u0422\u043e\u0447\u043a\u0430\u041c\u0430\u0440\u0448\u0440\u0443\u0442\u0430', + '\u0411\u0438\u0437\u043d\u0435\u0441\u041f\u0440\u043e\u0446\u0435\u0441\u0441', + '\u042d\u0442\u043e\u0442\u0423\u0437\u0435\u043b', '\u041d\u043e\u043c\u0435\u0440\u041e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e', + '\u041d\u043e\u043c\u0435\u0440\u041f\u0440\u0438\u043d\u044f\u0442\u043e\u0433\u043e', + '\u0412\u0438\u0434\u0420\u0430\u0441\u0447\u0435\u0442\u0430', '\u041f\u0435\u0440\u0438\u043e\u0434\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438', + '\u0421\u0442\u043e\u0440\u043d\u043e\u0417\u0430\u043f\u0438\u0441\u044c', + '\u0421\u0447\u0435\u0442', '\u0422\u0438\u043f\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u044f', + '\u041f\u0435\u0440\u0438\u043e\u0434\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u0411\u0430\u0437\u043e\u0432\u044b\u0439', +} + def emit_attribute(indent, parsed, context): + attr_name = parsed['name'] + if attr_name in RESERVED_ATTR_NAMES or attr_name in RESERVED_ATTR_NAMES_RU: + print(f"WARNING: Attribute '{attr_name}' conflicts with a standard attribute name. This may cause errors when loading into 1C.", file=sys.stderr) uid = new_uuid() X(f'{indent}') X(f'{indent}\t') @@ -1250,18 +1289,12 @@ def emit_exchange_plan_properties(indent): X(f'{i}true') code_length = str(defn['codeLength']) if defn.get('codeLength') is not None else '9' description_length = str(defn['descriptionLength']) if defn.get('descriptionLength') is not None else '100' - code_type = str(defn['codeType']) if defn.get('codeType') else 'String' code_allowed_length = str(defn['codeAllowedLength']) if defn.get('codeAllowedLength') else 'Variable' - autonumbering = 'false' if defn.get('autonumbering') is False else 'true' - check_unique = 'true' if defn.get('checkUnique') is True else 'false' X(f'{i}{code_length}') - X(f'{i}{code_type}') X(f'{i}{code_allowed_length}') X(f'{i}{description_length}') X(f'{i}AsDescription') X(f'{i}InDialog') - X(f'{i}{check_unique}') - X(f'{i}{autonumbering}') emit_standard_attributes(i, 'ExchangePlan') distributed = 'true' if defn.get('distributedInfoBase') is True else 'false' include_ext = 'true' if defn.get('includeConfigurationExtensions') is True else 'false' @@ -1664,6 +1697,11 @@ def emit_business_process_properties(indent): X(f'{i}{autonumbering}') emit_standard_attributes(i, 'BusinessProcess') X(f'{i}') + task_ref = str(defn['task']) if defn.get('task') else '' + if task_ref: + X(f'{i}{task_ref}') + else: + X(f'{i}') X(f'{i}') X(f'{i}') X(f'{i}\tBusinessProcess.{obj_name}.StandardAttribute.Number') @@ -2335,14 +2373,14 @@ if obj_type in types_with_module: if obj_type == 'ExchangePlan': content_path = os.path.join(ext_dir, 'Content.xml') if not os.path.isfile(content_path): - content_xml = '\r\n\r\n' + content_xml = '\r\n\r\n' write_utf8_bom(content_path, content_xml) modules_created.append(content_path) if obj_type == 'BusinessProcess': flowchart_path = os.path.join(ext_dir, 'Flowchart.xml') if not os.path.isfile(flowchart_path): - flowchart_xml = '\r\n\r\n' + flowchart_xml = '\r\n\r\n' write_utf8_bom(flowchart_path, flowchart_xml) modules_created.append(flowchart_path) @@ -2464,3 +2502,19 @@ elif reg_result == 'no-childobj': print('WARNING: Configuration.xml found but not found', file=sys.stderr) elif reg_result == 'no-config': print(f' Configuration.xml: not found at {config_xml_path} (register manually)') + +# Cross-reference hints +if obj_type == 'AccountingRegister' and not defn.get('chartOfAccounts'): + print('[HINT] AccountingRegister requires ChartOfAccounts reference:') + print(' /meta-edit -Operation modify-property -Value "ChartOfAccounts=ChartOfAccounts.XXX"') +if obj_type == 'CalculationRegister' and not defn.get('chartOfCalculationTypes'): + print('[HINT] CalculationRegister requires ChartOfCalculationTypes reference:') + print(' /meta-edit -Operation modify-property -Value "ChartOfCalculationTypes=ChartOfCalculationTypes.XXX"') +if obj_type == 'BusinessProcess' and not defn.get('task'): + print('[HINT] BusinessProcess requires Task reference:') + print(' /meta-edit -Operation modify-property -Value "Task=Task.XXX"') +if obj_type == 'ChartOfAccounts': + max_ext_dim = int(defn['maxExtDimensionCount']) if defn.get('maxExtDimensionCount') is not None else 0 + if max_ext_dim > 0 and not defn.get('extDimensionTypes'): + print('[HINT] ChartOfAccounts with MaxExtDimensionCount>0 requires ExtDimensionTypes:') + print(' /meta-edit -Operation modify-property -Value "ExtDimensionTypes=ChartOfCharacteristicTypes.XXX"') diff --git a/.claude/skills/meta-validate/scripts/meta-validate.ps1 b/.claude/skills/meta-validate/scripts/meta-validate.ps1 index aba022bf..e2f2f46a 100644 --- a/.claude/skills/meta-validate/scripts/meta-validate.ps1 +++ b/.claude/skills/meta-validate/scripts/meta-validate.ps1 @@ -649,6 +649,41 @@ if ($childObjNode) { if ($script:stopped) { & $finalize; exit 1 } +# --- Check 7b: Reserved attribute names --- + +$reservedAttrNames = @( + "Ref","DeletionMark","Code","Description","Date","Number","Posted","Parent","Owner", + "IsFolder","Predefined","PredefinedDataName","Recorder","Period","LineNumber","Active", + "Order","Type","OffBalance","Started","Completed","HeadTask","Executed","RoutePoint", + "BusinessProcess","ThisNode","SentNo","ReceivedNo","CalculationType","RegistrationPeriod", + "ReversingEntry","Account","ValueType","ActionPeriodIsBasic" +) + +if ($childObjNode) { + $check7bOk = $true + $attrNodes = $childObjNode.SelectNodes("md:Attribute", $ns) + foreach ($attrNode in $attrNodes) { + $attrProps = $attrNode.SelectSingleNode("md:Properties", $ns) + if ($attrProps) { + $attrNameNode = $attrProps.SelectSingleNode("md:Name", $ns) + if ($attrNameNode -and $attrNameNode.InnerText) { + $an = $attrNameNode.InnerText + if ($reservedAttrNames -contains $an) { + Report-Warn "7b. Attribute '$an' conflicts with a standard attribute name" + $check7bOk = $false + } + } + } + } + if ($check7bOk) { + Report-OK "7b. Reserved attribute names: no conflicts" + } +} else { + Report-OK "7b. Reserved attribute names: N/A" +} + +if ($script:stopped) { & $finalize; exit 1 } + # --- Check 8: Name uniqueness --- function Check-Uniqueness { @@ -887,6 +922,51 @@ if ($propsNode) { $check10Issues++ } } + + # AccountingRegister: ChartOfAccounts must not be empty + if ($mdType -eq "AccountingRegister") { + $coa = $propsNode.SelectSingleNode("md:ChartOfAccounts", $ns) + if (-not $coa -or -not $coa.InnerText.Trim()) { + Report-Error "10. AccountingRegister: empty ChartOfAccounts" + $check10Ok = $false + $check10Issues++ + Write-Host "[HINT] /meta-edit -Operation modify-property -Value `"ChartOfAccounts=ChartOfAccounts.XXX`"" + } + } + + # CalculationRegister: ChartOfCalculationTypes must not be empty + if ($mdType -eq "CalculationRegister") { + $coct = $propsNode.SelectSingleNode("md:ChartOfCalculationTypes", $ns) + if (-not $coct -or -not $coct.InnerText.Trim()) { + Report-Error "10. CalculationRegister: empty ChartOfCalculationTypes" + $check10Ok = $false + $check10Issues++ + Write-Host "[HINT] /meta-edit -Operation modify-property -Value `"ChartOfCalculationTypes=ChartOfCalculationTypes.XXX`"" + } + } + + # BusinessProcess: Task should not be empty + if ($mdType -eq "BusinessProcess") { + $taskProp = $propsNode.SelectSingleNode("md:Task", $ns) + if (-not $taskProp -or -not $taskProp.InnerText.Trim()) { + Report-Warn "10. BusinessProcess: empty Task reference" + $check10Issues++ + Write-Host "[HINT] /meta-edit -Operation modify-property -Value `"Task=Task.XXX`"" + } + } + + # ChartOfAccounts: ExtDimensionTypes should be set if MaxExtDimensionCount > 0 + if ($mdType -eq "ChartOfAccounts") { + $maxExtDim = $propsNode.SelectSingleNode("md:MaxExtDimensionCount", $ns) + if ($maxExtDim -and [int]$maxExtDim.InnerText -gt 0) { + $edt = $propsNode.SelectSingleNode("md:ExtDimensionTypes", $ns) + if (-not $edt -or -not $edt.InnerText.Trim()) { + Report-Warn "10. ChartOfAccounts: MaxExtDimensionCount>0 but ExtDimensionTypes is empty" + $check10Issues++ + Write-Host "[HINT] /meta-edit -Operation modify-property -Value `"ExtDimensionTypes=ChartOfCharacteristicTypes.XXX`"" + } + } + } } if ($check10Ok -and $check10Issues -eq 0) { diff --git a/.claude/skills/meta-validate/scripts/meta-validate.py b/.claude/skills/meta-validate/scripts/meta-validate.py index 14004de4..f7cea0c6 100644 --- a/.claude/skills/meta-validate/scripts/meta-validate.py +++ b/.claude/skills/meta-validate/scripts/meta-validate.py @@ -626,6 +626,37 @@ if stopped: finalize() sys.exit(1) +# ── Check 7b: Reserved attribute names ─────────────────────── + +RESERVED_ATTR_NAMES = { + 'Ref', 'DeletionMark', 'Code', 'Description', 'Date', 'Number', 'Posted', + 'Parent', 'Owner', 'IsFolder', 'Predefined', 'PredefinedDataName', + 'Recorder', 'Period', 'LineNumber', 'Active', 'Order', 'Type', 'OffBalance', + 'Started', 'Completed', 'HeadTask', 'Executed', 'RoutePoint', 'BusinessProcess', + 'ThisNode', 'SentNo', 'ReceivedNo', 'CalculationType', 'RegistrationPeriod', + 'ReversingEntry', 'Account', 'ValueType', 'ActionPeriodIsBasic', +} + +if child_obj_node is not None: + check7b_ok = True + for attr_node in find_all(child_obj_node, 'md:Attribute'): + attr_props = find(attr_node, 'md:Properties') + if attr_props is not None: + attr_name_node = find(attr_props, 'md:Name') + if attr_name_node is not None and inner_text(attr_name_node): + an = inner_text(attr_name_node) + if an in RESERVED_ATTR_NAMES: + report_warn(f"7b. Attribute '{an}' conflicts with a standard attribute name") + check7b_ok = False + if check7b_ok: + report_ok("7b. Reserved attribute names: no conflicts") +else: + report_ok("7b. Reserved attribute names: N/A") + +if stopped: + finalize() + sys.exit(1) + # ── Check 8: Name uniqueness ───────────────────────────────── @@ -841,6 +872,47 @@ if props_node is not None: check10_ok = False check10_issues += 1 + # AccountingRegister: ChartOfAccounts must not be empty + if md_type == 'AccountingRegister': + coa = find(props_node, 'md:ChartOfAccounts') + if coa is None or not text_of(coa): + report_error('10. AccountingRegister: empty ChartOfAccounts') + check10_ok = False + check10_issues += 1 + print('[HINT] /meta-edit -Operation modify-property -Value "ChartOfAccounts=ChartOfAccounts.XXX"') + + # CalculationRegister: ChartOfCalculationTypes must not be empty + if md_type == 'CalculationRegister': + coct = find(props_node, 'md:ChartOfCalculationTypes') + if coct is None or not text_of(coct): + report_error('10. CalculationRegister: empty ChartOfCalculationTypes') + check10_ok = False + check10_issues += 1 + print('[HINT] /meta-edit -Operation modify-property -Value "ChartOfCalculationTypes=ChartOfCalculationTypes.XXX"') + + # BusinessProcess: Task should not be empty + if md_type == 'BusinessProcess': + task_prop = find(props_node, 'md:Task') + if task_prop is None or not text_of(task_prop): + report_warn('10. BusinessProcess: empty Task reference') + check10_issues += 1 + print('[HINT] /meta-edit -Operation modify-property -Value "Task=Task.XXX"') + + # ChartOfAccounts: ExtDimensionTypes should be set if MaxExtDimensionCount > 0 + if md_type == 'ChartOfAccounts': + max_ext_dim = find(props_node, 'md:MaxExtDimensionCount') + if max_ext_dim is not None: + try: + med_val = int(inner_text(max_ext_dim) or '0') + except ValueError: + med_val = 0 + if med_val > 0: + edt = find(props_node, 'md:ExtDimensionTypes') + if edt is None or not text_of(edt): + report_warn('10. ChartOfAccounts: MaxExtDimensionCount>0 but ExtDimensionTypes is empty') + check10_issues += 1 + print('[HINT] /meta-edit -Operation modify-property -Value "ExtDimensionTypes=ChartOfCharacteristicTypes.XXX"') + if check10_ok and check10_issues == 0: report_ok("10. Cross-property consistency") diff --git a/docs/meta-dsl-spec.md b/docs/meta-dsl-spec.md index a5792a15..bbd2a35e 100644 --- a/docs/meta-dsl-spec.md +++ b/docs/meta-dsl-spec.md @@ -580,6 +580,7 @@ DSL для `columns` (§12). | `autonumbering` | `true` | Autonumbering | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | +| `task` | `""` | Task (ссылка на Task.XXX) | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | @@ -587,7 +588,7 @@ DSL для `columns` (§12). Дополнительно: `Ext/Flowchart.xml` (заглушка карты маршрута). ```json -{ "type": "BusinessProcess", "name": "Задание", "attributes": ["Описание: String(200)"] } +{ "type": "BusinessProcess", "name": "Задание", "task": "Task.ЗадачаИсполнителя", "attributes": ["Описание: String(200)"] } ``` ### 7.21 Task