From f0840864dc93ceefa45ccdae50ea5a07c4b0c05e Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 5 Jul 2026 17:46:26 +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=20ChartOfCharacteristicTypes=20(=D0=9F=D0=92=D0=A5?= =?UTF-8?q?)=20(v1.35/v0.24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Третий тип после Catalog/ExchangePlan. Декомпилятор расширен на ПВХ. Компилятор Emit-ChartOfCharacteristicTypesProperties переписан на общие хелперы в каноническом порядке; новое — блок Type (тип значения характеристики, составной) и CharacteristicExtValues; иерархия папки+элементы. StandardAttributes-профиль ПВХ (Наименование=ShowError, Родитель=FFV=true), блок условный. Крупная новая фича — предопределённые виды несут ТИП НА ЭЛЕМЕНТ: ключ `type` в объектной форме predefined (строка/массив; '' → пустой ). Root-элемент PlanOfCharacteristicKindPredefinedItems. Общие фиксы (не только ПВХ): • Get-TypeShorthand ищет квалификаторы String/Number/Date по всему typeNode — составной тип значения группирует квалификаторы в конце, не сразу за типом. • Expand-DataPath гард [:/]: спец-путь 0:GUID/0:GUID (зависимости ПВХ) не разворачивается. • Контекст реквизита ПВХ = catalog (у него полные Use/FillFromFillingValue/DataHistory). • TabularSection Use, GeneratedType Characteristic-префикс, CodeSeries +WholeCharacteristicKind. Роундтрип 24 ПВХ: match 0→16, TOTAL 4929→52 (−99%). Остаток (8) — принятые хвосты (FillValue-пробелы, TS-LineNumber-опущение). Catalog/EP не регрессировали (108/120, 39/42). Регресс 47/47 ps1+py, ps1↔py identical (6/6 ПВХ). spec §7.2b, кейс chart-of-characteristic-types (+valueType/predefined-with-type/standardAttributes). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../meta-compile/scripts/meta-compile.ps1 | 172 ++++++++++-------- .../meta-compile/scripts/meta-compile.py | 165 ++++++++++------- .../meta-decompile/scripts/meta-decompile.ps1 | 70 ++++--- docs/meta-dsl-spec.md | 26 +++ .../chart-of-characteristic-types.json | 9 +- .../ДополнительныеРеквизитыИСведения.xml | 42 +++-- .../Ext/Predefined.xml | 38 ++++ 7 files changed, 342 insertions(+), 180 deletions(-) create mode 100644 tests/skills/cases/meta-compile/snapshots/chart-of-characteristic-types/ChartsOfCharacteristicTypes/ДополнительныеРеквизитыИСведения/Ext/Predefined.xml diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index 23cfd241..2c169db7 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.34 — Compile 1C metadata object from JSON +# meta-compile v1.35 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -257,7 +257,7 @@ $script:validEnumValues = @{ "FillChecking" = @("DontCheck","ShowError","ShowWarning") "Indexing" = @("DontIndex","Index","IndexWithAdditionalOrder") "SubordinationUse" = @("ToItems","ToFolders","ToFoldersAndItems") - "CodeSeries" = @("WholeCatalog","WithinSubordination","WithinOwnerSubordination") + "CodeSeries" = @("WholeCatalog","WithinSubordination","WithinOwnerSubordination","WholeCharacteristicKind") "ChoiceMode" = @("BothWays","QuickChoice","FromForm") "CreateOnInput" = @("Auto","Use","DontUse") "ChoiceHistoryOnInput" = @("Auto","DontUse") @@ -932,7 +932,7 @@ $script:generatedTypes = @{ @{ prefix = "ChartOfCharacteristicTypesRef"; category = "Ref" } @{ prefix = "ChartOfCharacteristicTypesSelection"; category = "Selection" } @{ prefix = "ChartOfCharacteristicTypesList"; category = "List" } - @{ prefix = "ChartOfCharacteristicTypesCharacteristic"; category = "Characteristic" } + @{ prefix = "Characteristic"; category = "Characteristic" } @{ prefix = "ChartOfCharacteristicTypesManager"; category = "Manager" } ) "ChartOfCalculationTypes" = @( @@ -1037,11 +1037,16 @@ $script:stdAttrProfile = @{ "Parent" = @{ FillFromFillingValue = "true" } "Description" = @{ FillChecking = "ShowError" } } - # ExchangePlan: блок материализуется всегда (не условный), Наименование/Код → FillChecking=ShowError (корпус 40/38 из 41). + # ExchangePlan: Наименование/Код → FillChecking=ShowError (корпус 40/38 из 41). "ExchangePlan" = @{ "Description" = @{ FillChecking = "ShowError" } "Code" = @{ FillChecking = "ShowError" } } + # ChartOfCharacteristicTypes: Наименование → FillChecking=ShowError (21/23), Родитель → FFV=true (23/23). + "ChartOfCharacteristicTypes" = @{ + "Description" = @{ FillChecking = "ShowError" } + "Parent" = @{ FillFromFillingValue = "true" } + } } # $ov — hashtable переопределений (профиль + DSL) для полей: FillChecking, FillFromFillingValue, @@ -1102,7 +1107,7 @@ function Emit-StandardAttribute { # Прочие типы (не в множестве) → блок эмитится всегда (текущее поведение, пока их правило не выведено). # - stdAttrProfile[тип]: профиль материализованного блока (пусто = schema-дефолт), поверх — DSL-override. # Миграция типа = добавить его в stdAttrConditionalTypes + stdAttrProfile и переснять снэпшоты; КОД НЕ ТРОГАЕМ. -$script:stdAttrConditionalTypes = @('Catalog', 'ExchangePlan') +$script:stdAttrConditionalTypes = @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes') function Emit-StandardAttributes { param([string]$indent, [string]$objectType) $attrs = $script:standardAttributesByType[$objectType] @@ -1204,6 +1209,7 @@ function Expand-DataPath { param([string]$dp) if (-not $dp) { return $dp } $s = "$dp" + if ($s -match '[:/]') { return $s } # спец-путь (напр. 0:GUID/0:GUID в зависимостях ПВХ) — не разворачиваем if ($s -match '^(StandardAttribute|Attribute)\.') { return "$objType.$objName.$s" } if (-not $s.Contains('.')) { $en = Resolve-StdAttrEn $s @@ -1710,8 +1716,8 @@ function Emit-TabularSection { Emit-MLText "$indent`t`t" "ToolTip" $tsTooltip X "$indent`t`tDontCheck" Emit-TabularStandardAttributes "$indent`t`t" $tsLineNumber - # Use=ForItem only for Catalog tabular sections (Document does not have Use) - if ($objectType -eq "Catalog") { + # Use=ForItem у ТЧ иерархических ссылочных типов (Catalog, ChartOfCharacteristicTypes); Document не имеет Use. + if ($objectType -in @("Catalog", "ChartOfCharacteristicTypes")) { X "$indent`t`tForItem" } X "$indent`t" @@ -2557,35 +2563,21 @@ function Emit-ChartOfCharacteristicTypesProperties { X "$i$(Esc-Xml $objName)" Emit-MLText $i "Synonym" $synonym - X "$i" - X "$itrue" + if ($def.comment) { X "$i$(Esc-XmlText "$($def.comment)")" } else { X "$i" } + $useStdCmd = if (Get-BoolProp "useStandardCommands" $true) { "true" } else { "false" } + X "$i$useStdCmd" + $inclHelp = if (Get-BoolProp "includeHelpInContents" $false) { "true" } else { "false" } + X "$i$inclHelp" - $codeLength = if ($null -ne $def.codeLength) { "$($def.codeLength)" } else { "9" } - $descriptionLength = if ($null -ne $def.descriptionLength) { "$($def.descriptionLength)" } else { "25" } - $codeAllowedLength = Get-EnumProp "CodeAllowedLength" "codeAllowedLength" "Variable" - $autonumbering = if ($def.autonumbering -eq $false) { "false" } else { "true" } - $checkUnique = if ($def.checkUnique -eq $true) { "true" } else { "false" } - - X "$i$codeLength" - X "$i$codeAllowedLength" - X "$i$descriptionLength" - X "$i$checkUnique" - X "$i$autonumbering" - X "$iAsDescription" - - # CharacteristicExtValues - $charExtValues = if ($def.characteristicExtValues) { "$($def.characteristicExtValues)" } else { "" } - if ($charExtValues) { X "$i$charExtValues" } + # CharacteristicExtValues — ссылка на справочник доп. значений характеристик (обычно пусто). + if ($def.characteristicExtValues) { X "$i$(Esc-Xml "$($def.characteristicExtValues)")" } else { X "$i" } - # Type — composite type of allowed characteristic value types - $valueTypes = @() - if ($def.valueTypes) { $valueTypes = @($def.valueTypes) } - if ($valueTypes.Count -gt 0) { + # Type — тип значения характеристики (составной). DSL `valueType` строка "A + B + C" ИЛИ массив; нет ключа → дефолт. + $vt = $def.valueType; if (-not $vt -and $def.valueTypes) { $vt = ($def.valueTypes -join ' + ') } + if ($vt) { X "$i" - foreach ($vt in $valueTypes) { - Emit-TypeContent "$i`t" "$vt" - } + Emit-TypeContent "$i`t" "$vt" X "$i" } else { X "$i" @@ -2610,52 +2602,68 @@ function Emit-ChartOfCharacteristicTypesProperties { $hierarchical = if ($def.hierarchical -eq $true) { "true" } else { "false" } X "$i$hierarchical" - X "$itrue" + $foldersOnTop = if ($def.foldersOnTop -eq $false) { "false" } else { "true" } + X "$i$foldersOnTop" + + $codeLength = if ($null -ne $def.codeLength) { "$($def.codeLength)" } else { "9" } + $descriptionLength = if ($null -ne $def.descriptionLength) { "$($def.descriptionLength)" } else { "100" } + X "$i$codeLength" + X "$i$(Get-EnumProp 'CodeAllowedLength' 'codeAllowedLength' 'Variable')" + X "$i$descriptionLength" + X "$i$(Get-EnumProp 'CodeSeries' 'codeSeries' 'WholeCharacteristicKind')" + $checkUnique = if ($def.checkUnique -eq $false) { "false" } else { "true" } + X "$i$checkUnique" + $autonumbering = if ($def.autonumbering -eq $false) { "false" } else { "true" } + X "$i$autonumbering" + X "$i$(Get-EnumProp 'DefaultPresentation' 'defaultPresentation' 'AsDescription')" Emit-StandardAttributes $i "ChartOfCharacteristicTypes" - X "$i" - X "$iAuto" - X "$iInDialog" + Emit-Characteristics $i $def.characteristics + X "$i$(Get-EnumProp 'PredefinedDataUpdate' 'predefinedDataUpdate' 'Auto')" + X "$i$(Get-EnumProp 'EditType' 'editType' 'InDialog')" $quickChoice = if ($def.quickChoice -eq $true) { "true" } else { "false" } X "$i$quickChoice" - X "$iBothWays" - X "$i" - X "$i`tChartOfCharacteristicTypes.$objName.StandardAttribute.Description" - X "$i`tChartOfCharacteristicTypes.$objName.StandardAttribute.Code" - X "$i" - X "$iBegin" - X "$iDontUse" + X "$i$(Get-EnumProp 'ChoiceMode' 'choiceMode' 'BothWays')" + + # InputByString: override ЛИБО дефолт [Descr при D>0]+[Code при C>0] (prefix ChartOfCharacteristicTypes). + if (Test-DefKey 'inputByString') { + $ibFields = @($def.inputByString | ForEach-Object { Expand-DataPath "$_" }) + } else { + $ibFields = @() + if ([int]$descriptionLength -gt 0) { $ibFields += "ChartOfCharacteristicTypes.$objName.StandardAttribute.Description" } + if ([int]$codeLength -gt 0) { $ibFields += "ChartOfCharacteristicTypes.$objName.StandardAttribute.Code" } + } + Emit-FieldBlock $i "InputByString" $ibFields + X "$i$(Get-EnumProp 'CreateOnInput' 'createOnInput' 'DontUse')" + X "$i$(Get-EnumProp 'SearchStringModeOnInputByString' 'searchStringModeOnInputByString' 'Begin')" X "$iDirectly" - X "$i" - X "$i" - X "$i" - X "$i" - X "$i" - X "$i" - X "$i" - X "$i" - X "$i" - X "$i" - X "$ifalse" - X "$i" - X "$i" - - $dataLockControlMode = Get-EnumProp "DataLockControlMode" "dataLockControlMode" "Automatic" - X "$i$dataLockControlMode" - - $fullTextSearch = Get-EnumProp "FullTextSearch" "fullTextSearch" "Use" - X "$i$fullTextSearch" - + X "$iDontUse" + X "$i$(Get-EnumProp 'ChoiceHistoryOnInput' 'choiceHistoryOnInput' 'Auto')" + Emit-FormRef $i "DefaultObjectForm" $def.defaultObjectForm + Emit-FormRef $i "DefaultFolderForm" $def.defaultFolderForm + Emit-FormRef $i "DefaultListForm" $def.defaultListForm + Emit-FormRef $i "DefaultChoiceForm" $def.defaultChoiceForm + Emit-FormRef $i "DefaultFolderChoiceForm" $def.defaultFolderChoiceForm + Emit-FormRef $i "AuxiliaryObjectForm" $def.auxiliaryObjectForm + Emit-FormRef $i "AuxiliaryFolderForm" $def.auxiliaryFolderForm + Emit-FormRef $i "AuxiliaryListForm" $def.auxiliaryListForm + Emit-FormRef $i "AuxiliaryChoiceForm" $def.auxiliaryChoiceForm + Emit-FormRef $i "AuxiliaryFolderChoiceForm" $def.auxiliaryFolderChoiceForm + Emit-BasedOn $i $def.basedOn + $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 "$iDontUse" - X "$iAuto" - X "$iDontUse" - X "$ifalse" - X "$ifalse" + 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-DocumentJournalProperties { @@ -3549,7 +3557,8 @@ if ($objType -in $typesWithAttrTS) { "Catalog" { "catalog" } "Document" { "document" } { $_ -in @("DataProcessor","Report") } { "processor" } - { $_ -in @("ChartOfAccounts","ChartOfCharacteristicTypes","ChartOfCalculationTypes") } { "chart" } + "ChartOfCharacteristicTypes" { "catalog" } # реквизиты ПВХ структурно как у справочника (Use/FillFromFillingValue/DataHistory) + { $_ -in @("ChartOfAccounts","ChartOfCalculationTypes") } { "chart" } default { "object" } } foreach ($a in $attrs) { @@ -3756,7 +3765,7 @@ function Resolve-PredefItem { $name = $m.Groups[2].Value $code = if ($m.Groups[1].Success) { $m.Groups[1].Value } else { '' } $desc = if ($m.Groups[3].Success) { $m.Groups[3].Value } else { Split-CamelCase $name } - return @{ name = $name; code = $code; desc = $desc; isFolder = $false; children = @() } + return @{ name = $name; code = $code; desc = $desc; isFolder = $false; children = @(); type = $null } } # Объектная форма + русские синонимы (прощающий ввод). $gv = { param($o, [string[]]$keys) foreach ($k in $keys) { if ($o.PSObject.Properties[$k]) { return $o.$k } } return $null } @@ -3769,7 +3778,9 @@ function Resolve-PredefItem { $folderV = & $gv $val @('isFolder','группа') $isFolder = ($folderV -eq $true) $subs = & $gv $val @('childItems','подчиненные') - return @{ name = $name; code = $code; desc = $desc; isFolder = $isFolder; children = @(if ($subs) { $subs } else { @() }) } + $typeV = & $gv $val @('type','тип') # тип значения характеристики (ПВХ): строка "A + B" ИЛИ массив + if ($typeV -is [System.Array]) { $typeV = ($typeV -join ' + ') } + return @{ name = $name; code = $code; desc = $desc; isFolder = $isFolder; children = @(if ($subs) { $subs } else { @() }); type = $typeV } } function Emit-PredefItem { param($sb, $val, [string]$indent, [string]$codeType) @@ -3781,6 +3792,18 @@ function Emit-PredefItem { else { [void]$sb.Append("$indent`t$(Esc-XmlText $r.code)`n") } if ($r.desc -eq '') { [void]$sb.Append("$indent`t`n") } else { [void]$sb.Append("$indent`t$(Esc-XmlText $r.desc)`n") } + # Type — тип значения предопределённой характеристики (ПВХ); между Description и IsFolder. + # type=$null → блока нет (Catalog); type='' → пустой ; type='A + B' → наполненный. + if ($null -ne $r.type -and "$($r.type)" -eq '') { [void]$sb.Append("$indent`t`n") } + elseif ($r.type) { + [void]$sb.Append("$indent`t`n") + $tmp = New-Object System.Text.StringBuilder + $saveXml = $script:xml; $script:xml = $tmp + Emit-TypeContent "$indent`t`t" "$($r.type)" + $script:xml = $saveXml + [void]$sb.Append(($tmp.ToString() -replace "`r`n", "`n")) + [void]$sb.Append("$indent`t`n") + } [void]$sb.Append("$indent`t$(if ($r.isFolder) { 'true' } else { 'false' })`n") if ($r.children.Count -gt 0) { [void]$sb.Append("$indent`t`n") @@ -3897,11 +3920,12 @@ if ($objType -eq "BusinessProcess") { } } -# Предопределённые элементы (Ext/Predefined.xml) — пока Catalog. Пусто/нет ключа → файл не создаём. -if ($objType -eq "Catalog" -and $def.predefined -and @($def.predefined).Count -gt 0) { +# Предопределённые элементы (Ext/Predefined.xml). Root-элемент — по типу. Пусто/нет ключа → файл не создаём. +$predefRootByType = @{ 'Catalog' = 'CatalogPredefinedItems'; 'ChartOfCharacteristicTypes' = 'PlanOfCharacteristicKindPredefinedItems' } +if ($predefRootByType.ContainsKey($objType) -and $def.predefined -and @($def.predefined).Count -gt 0) { Ensure-ExtDir $catCodeType = if ($def.codeType) { "$($def.codeType)" } else { 'String' } - $predefXml = Build-PredefinedXml @($def.predefined) "CatalogPredefinedItems" $catCodeType + $predefXml = Build-PredefinedXml @($def.predefined) $predefRootByType[$objType] $catCodeType $predefPath = Join-Path $extDir "Predefined.xml" [System.IO.File]::WriteAllText($predefPath, $predefXml, $enc) $modulesCreated += $predefPath diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index 99a759da..446f3b67 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.34 — Compile 1C metadata object from JSON +# meta-compile v1.35 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -374,7 +374,7 @@ valid_enum_values = { 'FillChecking': ['DontCheck', 'ShowError', 'ShowWarning'], 'Indexing': ['DontIndex', 'Index', 'IndexWithAdditionalOrder'], 'SubordinationUse': ['ToItems', 'ToFolders', 'ToFoldersAndItems'], - 'CodeSeries': ['WholeCatalog', 'WithinSubordination', 'WithinOwnerSubordination'], + 'CodeSeries': ['WholeCatalog', 'WithinSubordination', 'WithinOwnerSubordination', 'WholeCharacteristicKind'], 'ChoiceMode': ['BothWays', 'QuickChoice', 'FromForm'], 'CreateOnInput': ['Auto', 'Use', 'DontUse'], 'ChoiceHistoryOnInput': ['Auto', 'DontUse'], @@ -952,7 +952,7 @@ generated_types = { {'prefix': 'ChartOfCharacteristicTypesRef', 'category': 'Ref'}, {'prefix': 'ChartOfCharacteristicTypesSelection', 'category': 'Selection'}, {'prefix': 'ChartOfCharacteristicTypesList', 'category': 'List'}, - {'prefix': 'ChartOfCharacteristicTypesCharacteristic', 'category': 'Characteristic'}, + {'prefix': 'Characteristic', 'category': 'Characteristic'}, {'prefix': 'ChartOfCharacteristicTypesManager', 'category': 'Manager'}, ], 'ChartOfCalculationTypes': [ @@ -1056,6 +1056,11 @@ std_attr_profile = { 'Description': {'FillChecking': 'ShowError'}, 'Code': {'FillChecking': 'ShowError'}, }, + # ChartOfCharacteristicTypes: Наименование → FillChecking=ShowError (21/23), Родитель → FFV=true (23/23). + 'ChartOfCharacteristicTypes': { + 'Description': {'FillChecking': 'ShowError'}, + 'Parent': {'FillFromFillingValue': 'true'}, + }, } # ov — dict переопределений (профиль + DSL): FillChecking, FillFromFillingValue, Synonym, @@ -1121,7 +1126,7 @@ def emit_standard_attribute(indent, attr_name, ov=None): # Единый эмиттер блока StandardAttributes — поведение правят ДАННЫЕ, не форк кода (см. коммент в .ps1). # std_attr_conditional_types: типы, где блок только при кастомизации (DSL-ключ standardAttributes). # Прочие типы → блок всегда (текущее поведение). Миграция типа = +строчка в оба справочника + снэпшоты. -std_attr_conditional_types = {'Catalog', 'ExchangePlan'} +std_attr_conditional_types = {'Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes'} def emit_standard_attributes(indent, object_type): attrs = standard_attributes_by_type.get(object_type) if not attrs: @@ -1273,6 +1278,8 @@ def expand_data_path(dp): if not dp: return dp s = str(dp) + if re.search(r'[:/]', s): + return s # спец-путь (напр. 0:GUID/0:GUID в зависимостях ПВХ) — не разворачиваем if re.match(r'^(StandardAttribute|Attribute)\.', s): return f'{obj_type}.{obj_name}.{s}' if '.' not in s: @@ -1764,7 +1771,7 @@ def emit_tabular_section(indent, ts_name, columns, object_type, object_name, ts_ 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) - if object_type == 'Catalog': + if object_type in ('Catalog', 'ChartOfCharacteristicTypes'): X(f'{indent}\t\tForItem') X(f'{indent}\t') ts_context = 'processor-tabular' if object_type in ('DataProcessor', 'Report') else 'tabular' @@ -2476,29 +2483,22 @@ def emit_chart_of_characteristic_types_properties(indent): i = indent X(f'{i}{esc_xml(obj_name)}') emit_mltext(i, 'Synonym', synonym) - X(f'{i}') - 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 '25' - code_allowed_length = get_enum_prop('CodeAllowedLength', 'codeAllowedLength', '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_allowed_length}') - X(f'{i}{description_length}') - X(f'{i}{check_unique}') - X(f'{i}{autonumbering}') - X(f'{i}AsDescription') - char_ext_values = str(defn['characteristicExtValues']) if defn.get('characteristicExtValues') else '' - if char_ext_values: - X(f'{i}{char_ext_values}') + if defn.get('comment'): + X(f'{i}{esc_xml_text(str(defn["comment"]))}') + else: + X(f'{i}') + X(f'{i}{"true" if get_bool_prop("useStandardCommands", True) else "false"}') + X(f'{i}{"true" if get_bool_prop("includeHelpInContents", False) else "false"}') + if defn.get('characteristicExtValues'): + X(f'{i}{esc_xml(str(defn["characteristicExtValues"]))}') else: X(f'{i}') - value_types = list(defn.get('valueTypes', [])) - if value_types: + vt = defn.get('valueType') + if not vt and defn.get('valueTypes'): + vt = ' + '.join(defn['valueTypes']) + if vt: X(f'{i}') - for vt in value_types: - emit_type_content(f'{i}\t', str(vt)) + emit_type_content(f'{i}\t', str(vt)) X(f'{i}') else: X(f'{i}') @@ -2519,50 +2519,60 @@ def emit_chart_of_characteristic_types_properties(indent): X(f'{i}\t\tDateTime') X(f'{i}\t') X(f'{i}') - hierarchical = 'true' if defn.get('hierarchical') is True else 'false' - X(f'{i}{hierarchical}') - X(f'{i}true') + X(f'{i}{"true" if defn.get("hierarchical") is True else "false"}') + X(f'{i}{"false" if defn.get("foldersOnTop") is False else "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' + X(f'{i}{code_length}') + X(f'{i}{get_enum_prop("CodeAllowedLength", "codeAllowedLength", "Variable")}') + X(f'{i}{description_length}') + X(f'{i}{get_enum_prop("CodeSeries", "codeSeries", "WholeCharacteristicKind")}') + X(f'{i}{"false" if defn.get("checkUnique") is False else "true"}') + X(f'{i}{"false" if defn.get("autonumbering") is False else "true"}') + X(f'{i}{get_enum_prop("DefaultPresentation", "defaultPresentation", "AsDescription")}') emit_standard_attributes(i, 'ChartOfCharacteristicTypes') - X(f'{i}') - X(f'{i}Auto') - X(f'{i}InDialog') - quick_choice = 'true' if defn.get('quickChoice') is True else 'false' - X(f'{i}{quick_choice}') - X(f'{i}BothWays') - X(f'{i}') - X(f'{i}\tChartOfCharacteristicTypes.{obj_name}.StandardAttribute.Description') - X(f'{i}\tChartOfCharacteristicTypes.{obj_name}.StandardAttribute.Code') - X(f'{i}') - X(f'{i}Begin') - X(f'{i}DontUse') + emit_characteristics(i, defn.get('characteristics')) + X(f'{i}{get_enum_prop("PredefinedDataUpdate", "predefinedDataUpdate", "Auto")}') + X(f'{i}{get_enum_prop("EditType", "editType", "InDialog")}') + X(f'{i}{"true" if defn.get("quickChoice") is True else "false"}') + X(f'{i}{get_enum_prop("ChoiceMode", "choiceMode", "BothWays")}') + if 'inputByString' in defn: + ib_fields = [expand_data_path(str(x)) for x in (defn.get('inputByString') or [])] + else: + ib_fields = [] + if int(description_length) > 0: + ib_fields.append(f'ChartOfCharacteristicTypes.{obj_name}.StandardAttribute.Description') + if int(code_length) > 0: + ib_fields.append(f'ChartOfCharacteristicTypes.{obj_name}.StandardAttribute.Code') + emit_field_block(i, 'InputByString', ib_fields) + X(f'{i}{get_enum_prop("CreateOnInput", "createOnInput", "DontUse")}') + X(f'{i}{get_enum_prop("SearchStringModeOnInputByString", "searchStringModeOnInputByString", "Begin")}') X(f'{i}Directly') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}false') - X(f'{i}') - 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}') + X(f'{i}DontUse') + X(f'{i}{get_enum_prop("ChoiceHistoryOnInput", "choiceHistoryOnInput", "Auto")}') + emit_form_ref(i, 'DefaultObjectForm', defn.get('defaultObjectForm')) + emit_form_ref(i, 'DefaultFolderForm', defn.get('defaultFolderForm')) + emit_form_ref(i, 'DefaultListForm', defn.get('defaultListForm')) + emit_form_ref(i, 'DefaultChoiceForm', defn.get('defaultChoiceForm')) + emit_form_ref(i, 'DefaultFolderChoiceForm', defn.get('defaultFolderChoiceForm')) + emit_form_ref(i, 'AuxiliaryObjectForm', defn.get('auxiliaryObjectForm')) + emit_form_ref(i, 'AuxiliaryFolderForm', defn.get('auxiliaryFolderForm')) + emit_form_ref(i, 'AuxiliaryListForm', defn.get('auxiliaryListForm')) + emit_form_ref(i, 'AuxiliaryChoiceForm', defn.get('auxiliaryChoiceForm')) + emit_form_ref(i, 'AuxiliaryFolderChoiceForm', defn.get('auxiliaryFolderChoiceForm')) + emit_based_on(i, defn.get('basedOn')) + dl_fields = [expand_data_path(str(x)) for x in defn.get('dataLockFields', [])] 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}DontUse') - X(f'{i}Auto') - X(f'{i}DontUse') - X(f'{i}false') - X(f'{i}false') + X(f'{i}{get_enum_prop("DataHistory", "dataHistory", "DontUse")}') + X(f'{i}{"true" if get_bool_prop("updateDataHistoryImmediatelyAfterWrite", False) else "false"}') + X(f'{i}{"true" if get_bool_prop("executeAfterWriteDataHistoryVersionProcessing", False) else "false"}') def emit_document_journal_properties(indent): i = indent @@ -3343,7 +3353,9 @@ if obj_type in types_with_attr_ts: context = 'document' elif obj_type in ('DataProcessor', 'Report'): context = 'processor' - elif obj_type in ('ChartOfAccounts', 'ChartOfCharacteristicTypes', 'ChartOfCalculationTypes'): + elif obj_type == 'ChartOfCharacteristicTypes': + context = 'catalog' # реквизиты ПВХ структурно как у справочника (Use/FillFromFillingValue/DataHistory) + elif obj_type in ('ChartOfAccounts', 'ChartOfCalculationTypes'): context = 'chart' else: context = 'object' @@ -3575,7 +3587,7 @@ def resolve_predef_item(val): name = m.group(2) code = m.group(1) if m.group(1) is not None else '' desc = m.group(3) if m.group(3) is not None else split_camel_case(name) - return {'name': name, 'code': code, 'desc': desc, 'isFolder': False, 'children': []} + return {'name': name, 'code': code, 'desc': desc, 'isFolder': False, 'children': [], 'type': None} def gv(keys): for k in keys: if k in val: @@ -3589,7 +3601,10 @@ def resolve_predef_item(val): desc = ('' if desc_v is None else str(desc_v)) if has_desc else split_camel_case(name) is_folder = gv(['isFolder', 'группа']) is True subs = gv(['childItems', 'подчиненные']) or [] - return {'name': name, 'code': code, 'desc': desc, 'isFolder': is_folder, 'children': list(subs)} + type_v = gv(['type', 'тип']) # тип значения характеристики (ПВХ): строка "A + B" ИЛИ массив + if isinstance(type_v, list): + type_v = ' + '.join(type_v) + return {'name': name, 'code': code, 'desc': desc, 'isFolder': is_folder, 'children': list(subs), 'type': type_v} def emit_predef_item(out, val, indent, code_type): r = resolve_predef_item(val) @@ -3605,6 +3620,19 @@ def emit_predef_item(out, val, indent, code_type): out.append(f'{indent}\t') else: out.append(f'{indent}\t{esc_xml_text(r["desc"])}') + # Type — тип значения предопределённой характеристики (ПВХ). None→нет блока; ''→; 'A + B'→наполненный. + rt = r.get('type') + if rt is not None and str(rt) == '': + out.append(f'{indent}\t') + elif rt: + out.append(f'{indent}\t') + global lines + saved = lines + lines = [] + emit_type_content(indent + '\t\t', str(rt)) + out.extend(lines) + lines = saved + out.append(f'{indent}\t') out.append(f'{indent}\t{"true" if r["isFolder"] else "false"}') if r['children']: out.append(f'{indent}\t') @@ -3638,11 +3666,12 @@ if obj_type == 'BusinessProcess': write_utf8_bom(flowchart_path, flowchart_xml) modules_created.append(flowchart_path) -# Предопределённые элементы (Ext/Predefined.xml) — пока Catalog. -if obj_type == 'Catalog' and defn.get('predefined'): +# Предопределённые элементы (Ext/Predefined.xml). Root-элемент по типу. +predef_root_by_type = {'Catalog': 'CatalogPredefinedItems', 'ChartOfCharacteristicTypes': 'PlanOfCharacteristicKindPredefinedItems'} +if obj_type in predef_root_by_type and defn.get('predefined'): ensure_ext_dir() cat_code_type = str(defn['codeType']) if defn.get('codeType') else 'String' - predef_xml = build_predefined_xml(defn['predefined'], 'CatalogPredefinedItems', cat_code_type) + predef_xml = build_predefined_xml(defn['predefined'], predef_root_by_type[obj_type], cat_code_type) predef_path = os.path.join(ext_dir, 'Predefined.xml') write_utf8_bom(predef_path, predef_xml) modules_created.append(predef_path) diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 index 9298b182..11bbc587 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.23 — XML объекта метаданных 1С → JSON-черновик формата meta-compile +# meta-decompile v0.24 — XML объекта метаданных 1С → JSON-черновик формата meta-compile # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # -# Поддержаны: Catalog, ExchangePlan. Инверс meta-compile (omit-on-default: ключ эмитим только +# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes. Инверс 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')) { - [Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (Catalog, ExchangePlan)"); exit 3 +if ($objType -notin @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes')) { + [Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (Catalog, ExchangePlan, ChartOfCharacteristicTypes)"); exit 3 } $props = $objNode.SelectSingleNode('md:Properties', $nsm) @@ -157,24 +157,27 @@ function Get-TypeShorthand { '(^|:)boolean$' { $parts += 'Boolean'; break } '(^|:)string$' { $len = '10'; $al = '' - if ($next -and $next.LocalName -eq 'StringQualifiers') { - $l = $next.SelectSingleNode('v8:Length', $nsm); if ($l) { $len = $l.InnerText } - $aln = $next.SelectSingleNode('v8:AllowedLength', $nsm); if ($aln -and $aln.InnerText -eq 'Fixed') { $al = ',fixed' } + $sq = if ($next -and $next.LocalName -eq 'StringQualifiers') { $next } else { $typeNode.SelectSingleNode('v8:StringQualifiers', $nsm) } + if ($sq) { + $l = $sq.SelectSingleNode('v8:Length', $nsm); if ($l) { $len = $l.InnerText } + $aln = $sq.SelectSingleNode('v8:AllowedLength', $nsm); if ($aln -and $aln.InnerText -eq 'Fixed') { $al = ',fixed' } } $parts += "String($len$al)"; break } '(^|:)decimal$' { $d = '10'; $f = '0'; $sign = '' - if ($next -and $next.LocalName -eq 'NumberQualifiers') { - $dn = $next.SelectSingleNode('v8:Digits', $nsm); if ($dn) { $d = $dn.InnerText } - $fn = $next.SelectSingleNode('v8:FractionDigits', $nsm); if ($fn) { $f = $fn.InnerText } - $sn = $next.SelectSingleNode('v8:AllowedSign', $nsm); if ($sn -and $sn.InnerText -eq 'Nonnegative') { $sign = ',nonneg' } + $nq = if ($next -and $next.LocalName -eq 'NumberQualifiers') { $next } else { $typeNode.SelectSingleNode('v8:NumberQualifiers', $nsm) } + if ($nq) { + $dn = $nq.SelectSingleNode('v8:Digits', $nsm); if ($dn) { $d = $dn.InnerText } + $fn = $nq.SelectSingleNode('v8:FractionDigits', $nsm); if ($fn) { $f = $fn.InnerText } + $sn = $nq.SelectSingleNode('v8:AllowedSign', $nsm); if ($sn -and $sn.InnerText -eq 'Nonnegative') { $sign = ',nonneg' } } $parts += "Number($d,$f$sign)"; break } '(^|:)dateTime$' { $fr = 'DateTime' - if ($next -and $next.LocalName -eq 'DateQualifiers') { $dn = $next.SelectSingleNode('v8:DateFractions', $nsm); if ($dn) { $fr = $dn.InnerText } } + $dq = if ($next -and $next.LocalName -eq 'DateQualifiers') { $next } else { $typeNode.SelectSingleNode('v8:DateQualifiers', $nsm) } + if ($dq) { $dn = $dq.SelectSingleNode('v8:DateFractions', $nsm); if ($dn) { $fr = $dn.InnerText } } $parts += $fr; break # Date | DateTime } '(^|:)base64Binary$' { $parts += 'ValueStorage'; break } @@ -389,16 +392,18 @@ if ($ownersNode) { } Add-EnumProp 'subordinationUse' 'SubordinationUse' 'ToItems' # Тип-зависимые дефолты (компилятор задаёт их по типу — декомпилятор обязан зеркалить, иначе omit ≠ значению). -$descrLenDef = if ($objType -eq 'ExchangePlan') { 150 } else { 25 } -$createInpDef = if ($objType -eq 'ExchangePlan') { 'DontUse' } else { 'Use' } -$dataLockDef = if ($objType -eq 'ExchangePlan') { 'Managed' } else { 'Automatic' } +$descrLenDef = switch ($objType) { 'ExchangePlan' { 150 } 'ChartOfCharacteristicTypes' { 100 } default { 25 } } +$createInpDef = if ($objType -eq 'Catalog') { 'Use' } else { 'DontUse' } +$dataLockDef = if ($objType -eq 'Catalog') { 'Automatic' } else { 'Managed' } +$codeSeriesDef = if ($objType -eq 'ChartOfCharacteristicTypes') { 'WholeCharacteristicKind' } else { 'WholeCatalog' } +$checkUniqueDef = ($objType -eq 'ChartOfCharacteristicTypes') # ПВХ дефолт true, Catalog false Add-IntProp 'codeLength' 'CodeLength' 9 Add-IntProp 'descriptionLength' 'DescriptionLength' $descrLenDef Add-EnumProp 'codeType' 'CodeType' 'String' Add-EnumProp 'codeAllowedLength' 'CodeAllowedLength' 'Variable' Add-BoolProp 'autonumbering' 'Autonumbering' $true -Add-BoolProp 'checkUnique' 'CheckUnique' $false -Add-EnumProp 'codeSeries' 'CodeSeries' 'WholeCatalog' +Add-BoolProp 'checkUnique' 'CheckUnique' $checkUniqueDef +Add-EnumProp 'codeSeries' 'CodeSeries' $codeSeriesDef Add-EnumProp 'defaultPresentation' 'DefaultPresentation' 'AsDescription' Add-BoolProp 'quickChoice' 'QuickChoice' $false Add-EnumProp 'choiceMode' 'ChoiceMode' 'BothWays' @@ -419,6 +424,19 @@ if ($objType -eq 'ExchangePlan') { Add-BoolProp 'updateDataHistoryImmediatelyAfterWrite' 'UpdateDataHistoryImmediatelyAfterWrite' $false Add-BoolProp 'executeAfterWriteDataHistoryVersionProcessing' 'ExecuteAfterWriteDataHistoryVersionProcessing' $false } +# ChartOfCharacteristicTypes-специфичные свойства. +if ($objType -eq 'ChartOfCharacteristicTypes') { + Add-EnumProp 'dataHistory' 'DataHistory' 'DontUse' + Add-BoolProp 'updateDataHistoryImmediatelyAfterWrite' 'UpdateDataHistoryImmediatelyAfterWrite' $false + Add-BoolProp 'executeAfterWriteDataHistoryVersionProcessing' 'ExecuteAfterWriteDataHistoryVersionProcessing' $false + $cev = P 'CharacteristicExtValues'; if ($cev) { $dsl['characteristicExtValues'] = $cev } + # Type — тип значения характеристики; valueType при отличии от дефолта (Boolean+String(100)+Number(15,2)+DateTime). + $vtNode = $props.SelectSingleNode('md:Type', $nsm) + if ($vtNode) { + $vtStr = Get-TypeShorthand $vtNode + if ($vtStr -and $vtStr -ne 'Boolean + String(100) + Number(15,2) + DateTime') { $dsl['valueType'] = $vtStr } + } +} # Короткая форма поля: ..StandardAttribute.X / .Attribute.X → StandardAttribute.X / Attribute.X # (Expand-DataPath компилятора разворачивает частичную форму обратно — dogfood резолвера). @@ -535,6 +553,10 @@ $stdProfileByType = @{ 'Description' = @{ fillChecking = 'ShowError' } 'Code' = @{ fillChecking = 'ShowError' } } + 'ChartOfCharacteristicTypes' = @{ + 'Description' = @{ fillChecking = 'ShowError' } + 'Parent' = @{ fillFromFillingValue = $true } + } } $catStdProfile = if ($stdProfileByType.ContainsKey($objType)) { $stdProfileByType[$objType] } else { @{} } # Фикс-список стандартных реквизитов типа (зеркало standardAttributesByType компилятора) — чтобы отличать @@ -542,11 +564,12 @@ $catStdProfile = if ($stdProfileByType.ContainsKey($objType)) { $stdProfileByTyp $stdFixedByType = @{ 'Catalog' = @('PredefinedDataName','Predefined','Ref','DeletionMark','IsFolder','Owner','Parent','Description','Code') 'ExchangePlan' = @('Ref','DeletionMark','Code','Description','ThisNode','SentNo','ReceivedNo') + 'ChartOfCharacteristicTypes' = @('PredefinedDataName','Predefined','Ref','DeletionMark','Description','Code','Parent','ValueType') } $stdFixed = if ($stdFixedByType.ContainsKey($objType)) { $stdFixedByType[$objType] } else { @() } # Условные типы: блок эмитим-как-триггер даже пустым (материализуется при отклонении ≥1 реквизита от schema-default; # у ExchangePlan это почти всегда — Description/Code=ShowError; редкий all-default EP блок опускает). -$stdConditionalTypes = @('Catalog', 'ExchangePlan') +$stdConditionalTypes = @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes') $saNode = $props.SelectSingleNode('md:StandardAttributes', $nsm) if ($saNode) { $saMap = [ordered]@{} @@ -703,20 +726,25 @@ if (Test-Path -LiteralPath $predefPath) { # ВАЖНО: обернуть весь if в @(), иначе PS распаковывает одноэлементный @(...) из if-блока # обратно в узел → $kids.Count = $null → папки с ОДНИМ ребёнком теряют его. $kids = @(if ($childContainer) { $childContainer.SelectNodes("*[local-name()='Item']") } else { @() }) + # Type — тип значения предопределённой характеристики (ПВХ). Наличие → object-форма (в строку не влезает). + # Наличие узла (даже пустого ) → object-форма с ключом type ('' для пустого); нет узла (Catalog) → без. + $typeEl = $itemEl.SelectSingleNode("*[local-name()='Type']") + $typeStr = if ($typeEl) { Get-TypeShorthand $typeEl } else { $null } $auto = Split-CamelWords $name - if (-not $isFolder -and $kids.Count -eq 0) { - # Плоский → компактная строка. + if (-not $isFolder -and $kids.Count -eq 0 -and $null -eq $typeEl) { + # Плоский без типа → компактная строка. $s = if ($code) { "($code) $name" } else { $name } if ($desc -eq '') { $s = "$s []" } elseif ($desc -ne $auto) { $s = "$s [$desc]" } return $s } - # Группа/иерархия → объект. + # Группа/иерархия/с типом → объект. $o = [ordered]@{ name = $name } if ($code) { $o['code'] = $code } if ($desc -eq '') { $o['description'] = '' } elseif ($desc -ne $auto) { $o['description'] = $desc } + if ($null -ne $typeStr) { $o['type'] = $typeStr } if ($isFolder) { $o['isFolder'] = $true } if ($kids.Count -gt 0) { $sub = [System.Collections.ArrayList]@() diff --git a/docs/meta-dsl-spec.md b/docs/meta-dsl-spec.md index 5a29ad8c..37d35566 100644 --- a/docs/meta-dsl-spec.md +++ b/docs/meta-dsl-spec.md @@ -619,6 +619,32 @@ omit-on-empty. Поля пишутся частичной формой (`Standar ключ `standardAttributes`. Опциональный легаси-реквизит `ExchangeDate` (часть планов) поддержан как «доп.» член `standardAttributes` (эмитится по факту наличия ключа, вне фикс-списка). +### 7.2b ChartOfCharacteristicTypes (План видов характеристик) + +Иерархический ссылочный тип (папки+элементы, без уровней/подчинения). Общий с Catalog слой: `synonym`, `comment`, +`useStandardCommands`, `includeHelpInContents`, `hierarchical`/`foldersOnTop`, коды (`codeLength`/`codeAllowedLength`/ +`descriptionLength`/`checkUnique`/`autonumbering`), `defaultPresentation`, `standardAttributes` (§7.1.1), +`characteristics` (§7.1.4), `inputByString` (§7.1.5), формы (вкл. `*Folder*`), `basedOn`, `dataLockFields`, презентации, +`predefined` (§7.1.2) — предопределённые виды характеристик. + +| Поле JSON | Умолчание | XML элемент | +|-----------|----------|-------------| +| `valueType` | *(любой примитив)* | Type (тип значения характеристики, составной — строка `"A + B"` или массив `valueTypes`) | +| `characteristicExtValues` | пусто | CharacteristicExtValues (ссылка на справочник доп. значений) | +| `createOnInput` | `DontUse` | CreateOnInput *(≠ Catalog `Use`)* | +| `dataLockControlMode` | `Managed` | DataLockControlMode *(≠ Catalog `Automatic`)* | +| `codeSeries` | `WholeCharacteristicKind` | CodeSeries *(≠ Catalog `WholeCatalog`)* | +| `checkUnique` | `true` | CheckUnique *(≠ Catalog `false`)* | +| `descriptionLength` | `100` | DescriptionLength *(≠ Catalog `25`)* | +| `dataHistory` + `updateDataHistoryImmediatelyAfterWrite` + `executeAfterWriteDataHistoryVersionProcessing` | `DontUse`/`false`/`false` | DataHistory-триплет | + +Стандартные реквизиты ПВХ: PredefinedDataName, Predefined, Ref, DeletionMark, Description, Code, Parent, ValueType +(профиль: Наименование → FillChecking=ShowError, Родитель → FillFromFillingValue=true). Блок **условный** (`standardAttributes`). + +**Предопределённые виды** несут **тип значения на элемент** — ключ `type` в объектной форме `predefined`-элемента +(строка `"A + B"` или массив; `""` → пустой ``; отсутствие ключа → без блока). Пример: +`{"name": "Цвет", "code": "000001", "type": "CatalogRef.Цвета"}`. + ### 7.3 Enum | Поле JSON | Умолчание | XML элемент | diff --git a/tests/skills/cases/meta-compile/chart-of-characteristic-types.json b/tests/skills/cases/meta-compile/chart-of-characteristic-types.json index cddf38b1..30fec671 100644 --- a/tests/skills/cases/meta-compile/chart-of-characteristic-types.json +++ b/tests/skills/cases/meta-compile/chart-of-characteristic-types.json @@ -4,8 +4,15 @@ "type": "ChartOfCharacteristicTypes", "name": "ДополнительныеРеквизитыИСведения", "descriptionLength": 100, + "hierarchical": true, "valueTypes": ["String(200)", "Number(15,2)", "Boolean", "Date"], - "attributes": ["НаборСвойств: String(100)"] + "standardAttributes": { "Description": { "synonym": "Свойство" } }, + "attributes": ["НаборСвойств: String(100)"], + "predefined": [ + { "name": "Цвет", "code": "000001", "type": "CatalogRef.ЗначенияСвойств" }, + { "name": "Размер", "code": "000002", "type": "String(50) + Number(3,0)" }, + { "name": "Группа", "code": "000003", "isFolder": true, "type": "" } + ] }, "validatePath": "ChartsOfCharacteristicTypes/ДополнительныеРеквизитыИСведения", "expect": { diff --git a/tests/skills/cases/meta-compile/snapshots/chart-of-characteristic-types/ChartsOfCharacteristicTypes/ДополнительныеРеквизитыИСведения.xml b/tests/skills/cases/meta-compile/snapshots/chart-of-characteristic-types/ChartsOfCharacteristicTypes/ДополнительныеРеквизитыИСведения.xml index 96f9fb02..322dd164 100644 --- a/tests/skills/cases/meta-compile/snapshots/chart-of-characteristic-types/ChartsOfCharacteristicTypes/ДополнительныеРеквизитыИСведения.xml +++ b/tests/skills/cases/meta-compile/snapshots/chart-of-characteristic-types/ChartsOfCharacteristicTypes/ДополнительныеРеквизитыИСведения.xml @@ -18,7 +18,7 @@ UUID-008 UUID-009 - + UUID-010 UUID-011 @@ -37,12 +37,7 @@ true - 9 - Variable - 100 - false - true - AsDescription + false xs:string @@ -62,8 +57,15 @@ Date - false + true true + 9 + Variable + 100 + WholeCharacteristicKind + true + true + AsDescription @@ -171,7 +173,7 @@ - DontCheck + ShowError false false Auto @@ -187,7 +189,12 @@ Use false - + + + ru + Свойство + + Use @@ -225,7 +232,7 @@ DontCheck false - false + true Auto @@ -283,9 +290,11 @@ ChartOfCharacteristicTypes.ДополнительныеРеквизитыИСведения.StandardAttribute.Description ChartOfCharacteristicTypes.ДополнительныеРеквизитыИСведения.StandardAttribute.Code + DontUse Begin - DontUse Directly + DontUse + Auto @@ -296,18 +305,15 @@ - false - Automatic + Managed Use - DontUse - Auto DontUse false false @@ -340,6 +346,8 @@ false + false + DontCheck Items @@ -349,8 +357,10 @@ Auto + ForItem DontIndex Use + Use diff --git a/tests/skills/cases/meta-compile/snapshots/chart-of-characteristic-types/ChartsOfCharacteristicTypes/ДополнительныеРеквизитыИСведения/Ext/Predefined.xml b/tests/skills/cases/meta-compile/snapshots/chart-of-characteristic-types/ChartsOfCharacteristicTypes/ДополнительныеРеквизитыИСведения/Ext/Predefined.xml new file mode 100644 index 00000000..897a99bb --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/chart-of-characteristic-types/ChartsOfCharacteristicTypes/ДополнительныеРеквизитыИСведения/Ext/Predefined.xml @@ -0,0 +1,38 @@ + + + + Цвет + 000001 + Цвет + + d5p1:CatalogRef.ЗначенияСвойств + + false + + + Размер + 000002 + Размер + + xs:string + + 50 + Variable + + xs:decimal + + 3 + 0 + Any + + + false + + + Группа + 000003 + Группа + + true + +