mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-13 17:34:57 +03:00
fix(meta-compile,meta-edit): sync type handling and validation between scripts
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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 "$indent<v8:Type>xs:decimal</v8:Type>"
|
||||
X "$indent<v8:NumberQualifiers>"
|
||||
X "$indent`t<v8:Digits>10</v8:Digits>"
|
||||
X "$indent`t<v8:FractionDigits>0</v8:FractionDigits>"
|
||||
X "$indent`t<v8:AllowedSign>Any</v8:AllowedSign>"
|
||||
X "$indent</v8:NumberQualifiers>"
|
||||
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 "$indent<v8:Type>xs:base64Binary</v8:Type>"
|
||||
return
|
||||
}
|
||||
|
||||
# Reference types — use local xmlns declaration for 1C compatibility
|
||||
if ($typeStr -match '^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.(.+)$') {
|
||||
X "$indent<v8:Type xmlns:d5p1=`"http://v8.1c.ru/8.1/data/enterprise/current-config`">d5p1:$typeStr</v8:Type>"
|
||||
|
||||
@@ -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}\t<v8:AllowedLength>Variable</v8:AllowedLength>')
|
||||
X(f'{indent}</v8:StringQualifiers>')
|
||||
return
|
||||
# Number without params -> Number(10,0)
|
||||
if type_str == 'Number':
|
||||
X(f'{indent}<v8:Type>xs:decimal</v8:Type>')
|
||||
X(f'{indent}<v8:NumberQualifiers>')
|
||||
X(f'{indent}\t<v8:Digits>10</v8:Digits>')
|
||||
X(f'{indent}\t<v8:FractionDigits>0</v8:FractionDigits>')
|
||||
X(f'{indent}\t<v8:AllowedSign>Any</v8:AllowedSign>')
|
||||
X(f'{indent}</v8:NumberQualifiers>')
|
||||
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}<v8:TypeSet>cfg:DefinedType.{dt_name}</v8:TypeSet>')
|
||||
return
|
||||
# ValueStorage
|
||||
if type_str == 'ValueStorage':
|
||||
X(f'{indent}<v8:Type>xs:base64Binary</v8:Type>')
|
||||
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:
|
||||
|
||||
@@ -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("$indent<v8:Type>xs:string</v8:Type>") | Out-Null
|
||||
$sb.AppendLine("$indent<v8:StringQualifiers>") | Out-Null
|
||||
$sb.AppendLine("$indent`t<v8:Length>$len</v8:Length>") | 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
|
||||
|
||||
|
||||
@@ -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}<v8:Type>xs:string</v8:Type>")
|
||||
lines.append(f"{indent}<v8:StringQualifiers>")
|
||||
lines.append(f"{indent}\t<v8:Length>{length}</v8: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 = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user