From 72a4015a8d59de06a4a0765ca0155343c533c90a Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 8 Mar 2026 18:39:18 +0300 Subject: [PATCH] fix(meta-compile,meta-edit): sync type handling and validation between scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit meta-compile: bare Number→Number(10,0), ValueStorage→xs:base64Binary, lowercase ref synonyms (catalogref, documentref, enumref). meta-edit: bare String default 0→10, reserved attribute name warnings. Co-Authored-By: Claude Opus 4.6 --- .../meta-compile/scripts/meta-compile.ps1 | 21 +++++++++++++ .../meta-compile/scripts/meta-compile.py | 19 ++++++++++++ .../skills/meta-edit/scripts/meta-edit.ps1 | 26 +++++++++++++++- .claude/skills/meta-edit/scripts/meta-edit.py | 30 ++++++++++++++++++- 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index ed8cc6f4..37ccf14a 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -185,6 +185,10 @@ $script:typeSynonyms["бизнеспроцессссылка"] = "Bus $script:typeSynonyms["задачассылка"] = "TaskRef" $script:typeSynonyms["определяемыйтип"] = "DefinedType" $script:typeSynonyms["definedtype"] = "DefinedType" +# English lowercase ref synonyms +$script:typeSynonyms["catalogref"] = "CatalogRef" +$script:typeSynonyms["documentref"] = "DocumentRef" +$script:typeSynonyms["enumref"] = "EnumRef" function Resolve-TypeStr { param([string]$typeStr) @@ -248,6 +252,17 @@ function Emit-TypeContent { return } + # Number without params → Number(10,0) + if ($typeStr -eq "Number") { + X "$indentxs:decimal" + X "$indent" + X "$indent`t10" + X "$indent`t0" + X "$indent`tAny" + X "$indent" + return + } + # Number(D,F) or Number(D,F,nonneg) if ($typeStr -match '^Number\((\d+),(\d+)(,nonneg)?\)$') { $digits = $Matches[1] @@ -285,6 +300,12 @@ function Emit-TypeContent { return } + # ValueStorage + if ($typeStr -eq "ValueStorage") { + X "$indentxs:base64Binary" + return + } + # Reference types — use local xmlns declaration for 1C compatibility if ($typeStr -match '^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.(.+)$') { X "$indentd5p1:$typeStr" diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index f1e9db8b..9a7b5042 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -198,6 +198,10 @@ type_synonyms = { 'задачассылка': 'TaskRef', 'определяемыйтип': 'DefinedType', 'definedtype': 'DefinedType', + # English lowercase ref synonyms + 'catalogref': 'CatalogRef', + 'documentref': 'DocumentRef', + 'enumref': 'EnumRef', } def resolve_type_str(type_str): @@ -251,6 +255,16 @@ def emit_type_content(indent, type_str): X(f'{indent}\tVariable') X(f'{indent}') return + # Number without params -> Number(10,0) + if type_str == 'Number': + X(f'{indent}xs:decimal') + X(f'{indent}') + X(f'{indent}\t10') + X(f'{indent}\t0') + X(f'{indent}\tAny') + X(f'{indent}') + return + # Number(D,F) or Number(D,F,nonneg) m = re.match(r'^Number\((\d+),(\d+)(,nonneg)?\)$', type_str) if m: @@ -283,6 +297,11 @@ def emit_type_content(indent, type_str): dt_name = m.group(1) X(f'{indent}cfg:DefinedType.{dt_name}') return + # ValueStorage + if type_str == 'ValueStorage': + X(f'{indent}xs:base64Binary') + return + # Reference types — use local xmlns declaration for 1C compatibility m = re.match(r'^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.(.+)$', type_str) if m: diff --git a/.claude/skills/meta-edit/scripts/meta-edit.ps1 b/.claude/skills/meta-edit/scripts/meta-edit.ps1 index 89ca13e0..cafc9eaf 100644 --- a/.claude/skills/meta-edit/scripts/meta-edit.ps1 +++ b/.claude/skills/meta-edit/scripts/meta-edit.ps1 @@ -297,7 +297,7 @@ function Build-TypeContentXml { # String or String(N) if ($typeStr -match '^String(\((\d+)\))?$') { - $len = if ($Matches[2]) { $Matches[2] } else { "0" } + $len = if ($Matches[2]) { $Matches[2] } else { "10" } $sb.AppendLine("$indentxs:string") | Out-Null $sb.AppendLine("$indent") | Out-Null $sb.AppendLine("$indent`t$len") | Out-Null @@ -689,10 +689,34 @@ function Get-AttributeContext { } } +$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 Build-AttributeFragment { param($parsed, [string]$context, [string]$indent) if (-not $context) { $context = Get-AttributeContext } + + # Check reserved attribute names + $attrName = $parsed.name + if ($script:reservedAttrNames.ContainsKey($attrName)) { + Write-Warning "Attribute '$attrName' conflicts with a standard attribute name. This may cause errors when loading into 1C." + } + $ruValues = $script:reservedAttrNames.Values + if ($ruValues -contains $attrName) { + Write-Warning "Attribute '$attrName' conflicts with a standard attribute name (Russian). This may cause errors when loading into 1C." + } + $uuid = New-Guid-String $sb = New-Object System.Text.StringBuilder diff --git a/.claude/skills/meta-edit/scripts/meta-edit.py b/.claude/skills/meta-edit/scripts/meta-edit.py index e593f6c7..f2f4fdca 100644 --- a/.claude/skills/meta-edit/scripts/meta-edit.py +++ b/.claude/skills/meta-edit/scripts/meta-edit.py @@ -214,7 +214,7 @@ def build_type_content_xml(indent, type_str): # String or String(N) m = re.match(r"^String(\((\d+)\))?$", type_str) if m: - length = m.group(2) if m.group(2) else "0" + length = m.group(2) if m.group(2) else "10" lines.append(f"{indent}xs:string") lines.append(f"{indent}") lines.append(f"{indent}\t{length}") @@ -600,10 +600,38 @@ def get_attribute_context(): return "object" +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 = { + 'Ссылка', 'ПометкаУдаления', 'Код', 'Наименование', + 'Дата', 'Номер', 'Проведен', 'Родитель', 'Владелец', + 'ЭтоГруппа', 'Предопределенный', 'ИмяПредопределенныхДанных', + 'Регистратор', 'Период', 'НомерСтроки', 'Активность', + 'Порядок', 'Тип', 'Забалансовый', + 'Стартован', 'Завершен', 'ВедущаяЗадача', + 'Выполнена', 'ТочкаМаршрута', 'БизнесПроцесс', + 'ЭтотУзел', 'НомерОтправленного', 'НомерПринятого', + 'ВидРасчета', 'ПериодРегистрации', 'СторноЗапись', + 'Счет', 'ТипЗначения', 'ПериодДействияБазовый', +} + + def build_attribute_fragment(parsed, context, indent): """Build XML fragment string for an Attribute element.""" if not context: context = get_attribute_context() + + # Check reserved attribute names + 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() lines = []