mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-13 22:35:16 +03:00
feat(meta-compile,meta-decompile): объектная форма табличной части (синоним/подсказка/комментарий ТЧ) (v1.23/v0.8)
Раундтрип-находка: синоним ТЧ кастомный/мультиязычный у 84% (корпус 1728 ТЧ: multi 1032, custom-ru 417,
auto лишь 279), ToolTip у 24% (413). Компилятор хардкодил синоним=Split-CamelCase, Comment/ToolTip пусто.
DSL: значение ТЧ — массив колонок (синоним авто) ЛИБО объект {synonym, tooltip, comment, attributes/columns}
(по образцу реквизита: shorthand vs object). synonym/tooltip — ML.
- meta-compile (дуал-порт): нормализация ТЧ → {columns, synonym, tooltip, comment}; Emit-TabularSection
параметризован (synonym через Emit-MLText, Comment/ToolTip из DSL).
- meta-decompile: ТЧ → объектная форма при кастомном синониме/подсказке/комментарии, иначе массив.
- spec §5.
Валидация: PS==PY; TS-категории ~0 (item 4566→6, ToolTip 2188→44); −10067 (89687→79620); регресс 37/37;
1С-cert зелёный. Остаток TabularSection>Synonym (~50) — станд. реквизит LineNumber ТЧ (отдельная категория).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1078,7 +1078,7 @@ function Emit-Attribute {
|
||||
# --- 9. TabularSection emitter ---
|
||||
|
||||
function Emit-TabularSection {
|
||||
param([string]$indent, [string]$tsName, $columns, [string]$objectType, [string]$objectName)
|
||||
param([string]$indent, [string]$tsName, $columns, [string]$objectType, [string]$objectName, $tsSynonymArg = $null, $tsTooltip = $null, $tsComment = $null)
|
||||
$uuid = New-Guid-String
|
||||
X "$indent<TabularSection uuid=`"$uuid`">"
|
||||
|
||||
@@ -1097,13 +1097,13 @@ function Emit-TabularSection {
|
||||
X "$indent`t`t</xr:GeneratedType>"
|
||||
X "$indent`t</InternalInfo>"
|
||||
|
||||
$tsSynonym = Split-CamelCase $tsName
|
||||
$tsSynonym = if ($null -ne $tsSynonymArg) { $tsSynonymArg } else { Split-CamelCase $tsName }
|
||||
|
||||
X "$indent`t<Properties>"
|
||||
X "$indent`t`t<Name>$(Esc-Xml $tsName)</Name>"
|
||||
Emit-MLText "$indent`t`t" "Synonym" $tsSynonym
|
||||
X "$indent`t`t<Comment/>"
|
||||
X "$indent`t`t<ToolTip/>"
|
||||
if ($tsComment) { X "$indent`t`t<Comment>$(Esc-XmlText $tsComment)</Comment>" } else { X "$indent`t`t<Comment/>" }
|
||||
Emit-MLText "$indent`t`t" "ToolTip" $tsTooltip
|
||||
X "$indent`t`t<FillChecking>DontCheck</FillChecking>"
|
||||
Emit-TabularStandardAttributes "$indent`t`t"
|
||||
# Use=ForItem only for Catalog tabular sections (Document does not have Use)
|
||||
@@ -2880,17 +2880,19 @@ if ($objType -in $typesWithAttrTS) {
|
||||
}
|
||||
$tsSections = [ordered]@{}
|
||||
if ($def.tabularSections) {
|
||||
# Normalize array format: [{name:"X", attributes:[...]}, ...] → {"X": [...]}
|
||||
# Значение ТЧ: массив колонок (синоним авто) ЛИБО объект {attributes/columns, synonym, tooltip, comment}.
|
||||
# Нормализуем в $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 }
|
||||
}
|
||||
$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 } }
|
||||
}
|
||||
if ($def.tabularSections -is [array] -or $def.tabularSections.GetType().Name -eq "Object[]") {
|
||||
foreach ($ts in $def.tabularSections) {
|
||||
$tsName = $ts.name
|
||||
$tsCols = if ($ts.attributes) { @($ts.attributes) } else { @() }
|
||||
$tsSections[$tsName] = $tsCols
|
||||
}
|
||||
foreach ($ts in $def.tabularSections) { $tsSections[$ts.name] = New-TsEntry $ts }
|
||||
} else {
|
||||
$def.tabularSections.PSObject.Properties | ForEach-Object {
|
||||
$tsSections[$_.Name] = @($_.Value)
|
||||
}
|
||||
$def.tabularSections.PSObject.Properties | ForEach-Object { $tsSections[$_.Name] = New-TsEntry $_.Value }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2923,8 +2925,8 @@ if ($objType -in $typesWithAttrTS) {
|
||||
Emit-Attribute "`t`t`t" $a $context
|
||||
}
|
||||
foreach ($tsName in $tsSections.Keys) {
|
||||
$columns = $tsSections[$tsName]
|
||||
Emit-TabularSection "`t`t`t" $tsName $columns $objType $objName
|
||||
$tsE = $tsSections[$tsName]
|
||||
Emit-TabularSection "`t`t`t" $tsName $tsE.columns $objType $objName $tsE.synonym $tsE.tooltip $tsE.comment
|
||||
}
|
||||
foreach ($af in $acctFlags) {
|
||||
$afName = if ($af.name) { $af.name } else { "$af" }
|
||||
|
||||
@@ -1066,7 +1066,7 @@ def emit_attribute(indent, parsed, context):
|
||||
# 9. TabularSection emitter
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def emit_tabular_section(indent, ts_name, columns, object_type, object_name):
|
||||
def emit_tabular_section(indent, ts_name, columns, object_type, object_name, ts_synonym_arg=None, ts_tooltip=None, ts_comment=None):
|
||||
uid = new_uuid()
|
||||
X(f'{indent}<TabularSection uuid="{uid}">')
|
||||
type_prefix = f'{object_type}TabularSection'
|
||||
@@ -1081,12 +1081,15 @@ def emit_tabular_section(indent, ts_name, columns, object_type, object_name):
|
||||
X(f'{indent}\t\t\t<xr:ValueId>{new_uuid()}</xr:ValueId>')
|
||||
X(f'{indent}\t\t</xr:GeneratedType>')
|
||||
X(f'{indent}\t</InternalInfo>')
|
||||
ts_synonym = split_camel_case(ts_name)
|
||||
ts_synonym = ts_synonym_arg if ts_synonym_arg is not None else split_camel_case(ts_name)
|
||||
X(f'{indent}\t<Properties>')
|
||||
X(f'{indent}\t\t<Name>{esc_xml(ts_name)}</Name>')
|
||||
emit_mltext(f'{indent}\t\t', 'Synonym', ts_synonym)
|
||||
X(f'{indent}\t\t<Comment/>')
|
||||
X(f'{indent}\t\t<ToolTip/>')
|
||||
if ts_comment:
|
||||
X(f'{indent}\t\t<Comment>{esc_xml_text(ts_comment)}</Comment>')
|
||||
else:
|
||||
X(f'{indent}\t\t<Comment/>')
|
||||
emit_mltext(f'{indent}\t\t', 'ToolTip', ts_tooltip)
|
||||
X(f'{indent}\t\t<FillChecking>DontCheck</FillChecking>')
|
||||
emit_tabular_standard_attributes(f'{indent}\t\t')
|
||||
if object_type == 'Catalog':
|
||||
@@ -2598,15 +2601,20 @@ if obj_type in types_with_attr_ts:
|
||||
ts_order = []
|
||||
if defn.get('tabularSections'):
|
||||
ts_data = defn['tabularSections']
|
||||
# Значение ТЧ: массив колонок (синоним авто) ЛИБО объект {attributes/columns, synonym, tooltip, comment}.
|
||||
def new_ts_entry(val):
|
||||
if isinstance(val, list):
|
||||
return {'columns': val, 'synonym': None, 'tooltip': None, 'comment': 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}
|
||||
if isinstance(ts_data, list):
|
||||
for ts in ts_data:
|
||||
ts_name = ts['name']
|
||||
ts_cols = _as_list(ts.get('attributes', []))
|
||||
ts_sections[ts_name] = ts_cols
|
||||
ts_order.append(ts_name)
|
||||
ts_sections[ts['name']] = new_ts_entry(ts)
|
||||
ts_order.append(ts['name'])
|
||||
else:
|
||||
for k, v in ts_data.items():
|
||||
ts_sections[k] = _as_list(v)
|
||||
ts_sections[k] = new_ts_entry(v)
|
||||
ts_order.append(k)
|
||||
# ChartOfAccounts: AccountingFlags + ExtDimensionAccountingFlags
|
||||
acct_flags = []
|
||||
@@ -2637,8 +2645,8 @@ if obj_type in types_with_attr_ts:
|
||||
for a in attrs:
|
||||
emit_attribute('\t\t\t', a, context)
|
||||
for ts_name in ts_order:
|
||||
columns = ts_sections[ts_name]
|
||||
emit_tabular_section('\t\t\t', ts_name, columns, obj_type, obj_name)
|
||||
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'])
|
||||
for af in acct_flags:
|
||||
af_name = af['name'] if isinstance(af, dict) else str(af)
|
||||
emit_accounting_flag('\t\t\t', af_name)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# meta-decompile v0.7 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
|
||||
# meta-decompile v0.8 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
#
|
||||
# Пилот: только Catalog. Инверс meta-compile (omit-on-default: ключ эмитим только
|
||||
@@ -325,7 +325,23 @@ if ($childObjs) {
|
||||
$tco = $ts.SelectSingleNode('md:ChildObjects', $nsm)
|
||||
$cols = [System.Collections.ArrayList]@()
|
||||
if ($tco) { foreach ($ca in @($tco.SelectNodes('md:Attribute', $nsm))) { [void]$cols.Add((Attr-ToDsl $ca)) } }
|
||||
$tsMap[$tsName] = $cols
|
||||
# Синоним/подсказка/комментарий ТЧ. Кастом → объектная форма {synonym?, tooltip?, comment?, attributes}.
|
||||
$tsSyn = Get-MLValue ($tsp.SelectSingleNode('md:Synonym', $nsm))
|
||||
$tsSynCustom = $false
|
||||
if ($tsSyn -is [string]) { if ($tsSyn -ne (Split-CamelWords $tsName)) { $tsSynCustom = $true } }
|
||||
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 { '' }
|
||||
if ($tsSynCustom -or ($null -ne $tsTt) -or $tsCmt) {
|
||||
$to = [ordered]@{}
|
||||
if ($tsSynCustom) { $to['synonym'] = $tsSyn }
|
||||
if ($null -ne $tsTt) { $to['tooltip'] = $tsTt }
|
||||
if ($tsCmt) { $to['comment'] = $tsCmt }
|
||||
$to['attributes'] = $cols
|
||||
$tsMap[$tsName] = $to
|
||||
} else {
|
||||
$tsMap[$tsName] = $cols
|
||||
}
|
||||
}
|
||||
$dsl['tabularSections'] = $tsMap
|
||||
}
|
||||
|
||||
+13
-1
@@ -213,7 +213,19 @@ JSON DSL для описания объектов метаданных конф
|
||||
}
|
||||
```
|
||||
|
||||
Ключ — имя табличной части, значение — массив реквизитов (в строковой или объектной форме).
|
||||
Ключ — имя табличной части, значение — **массив реквизитов** (в строковой или объектной форме; синоним ТЧ авто из имени) ЛИБО **объект** с собственными свойствами ТЧ:
|
||||
|
||||
```json
|
||||
"tabularSections": {
|
||||
"Представления": {
|
||||
"synonym": { "ru": "Представления", "en": "Presentations" },
|
||||
"tooltip": "Локализованные представления",
|
||||
"attributes": [ "КодЯзыка: String(10) | index", "Наименование: String(150)" ]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Свойства объектной формы ТЧ: `synonym` (ML; нет ключа → авто из имени), `tooltip` (ML), `comment` (строка), `attributes` (колонки; синоним `columns`).
|
||||
|
||||
Для Catalog добавляется `<Use>ForItem</Use>` в Properties табличной части. Для Document Use не применяется.
|
||||
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
"attributes": [
|
||||
{ "name": "Штрихкод", "type": "String", "length": 128 }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Характеристики",
|
||||
"synonym": { "ru": "Характеристики", "en": "Features" },
|
||||
"tooltip": "Дополнительные характеристики товара",
|
||||
"comment": "ТЧ характеристик",
|
||||
"attributes": [ "Свойство: String(100)", "Значение: String(200)" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -227,6 +227,152 @@
|
||||
</Attribute>
|
||||
</ChildObjects>
|
||||
</TabularSection>
|
||||
<TabularSection uuid="UUID-019">
|
||||
<InternalInfo>
|
||||
<xr:GeneratedType name="CatalogTabularSection.Товары.Характеристики" category="TabularSection">
|
||||
<xr:TypeId>UUID-020</xr:TypeId>
|
||||
<xr:ValueId>UUID-021</xr:ValueId>
|
||||
</xr:GeneratedType>
|
||||
<xr:GeneratedType name="CatalogTabularSectionRow.Товары.Характеристики" category="TabularSectionRow">
|
||||
<xr:TypeId>UUID-022</xr:TypeId>
|
||||
<xr:ValueId>UUID-023</xr:ValueId>
|
||||
</xr:GeneratedType>
|
||||
</InternalInfo>
|
||||
<Properties>
|
||||
<Name>Характеристики</Name>
|
||||
<Synonym>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Характеристики</v8:content>
|
||||
</v8:item>
|
||||
<v8:item>
|
||||
<v8:lang>en</v8:lang>
|
||||
<v8:content>Features</v8:content>
|
||||
</v8:item>
|
||||
</Synonym>
|
||||
<Comment>ТЧ характеристик</Comment>
|
||||
<ToolTip>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Дополнительные характеристики товара</v8:content>
|
||||
</v8:item>
|
||||
</ToolTip>
|
||||
<FillChecking>DontCheck</FillChecking>
|
||||
<StandardAttributes>
|
||||
<xr:StandardAttribute name="LineNumber">
|
||||
<xr:LinkByType/>
|
||||
<xr:FillChecking>DontCheck</xr:FillChecking>
|
||||
<xr:MultiLine>false</xr:MultiLine>
|
||||
<xr:FillFromFillingValue>false</xr:FillFromFillingValue>
|
||||
<xr:CreateOnInput>Auto</xr:CreateOnInput>
|
||||
<xr:MaxValue xsi:nil="true"/>
|
||||
<xr:ToolTip/>
|
||||
<xr:ExtendedEdit>false</xr:ExtendedEdit>
|
||||
<xr:Format/>
|
||||
<xr:ChoiceForm/>
|
||||
<xr:QuickChoice>Auto</xr:QuickChoice>
|
||||
<xr:ChoiceHistoryOnInput>Auto</xr:ChoiceHistoryOnInput>
|
||||
<xr:EditFormat/>
|
||||
<xr:PasswordMode>false</xr:PasswordMode>
|
||||
<xr:DataHistory>Use</xr:DataHistory>
|
||||
<xr:MarkNegatives>false</xr:MarkNegatives>
|
||||
<xr:MinValue xsi:nil="true"/>
|
||||
<xr:Synonym/>
|
||||
<xr:Comment/>
|
||||
<xr:FullTextSearch>Use</xr:FullTextSearch>
|
||||
<xr:ChoiceParameterLinks/>
|
||||
<xr:FillValue xsi:nil="true"/>
|
||||
<xr:Mask/>
|
||||
<xr:ChoiceParameters/>
|
||||
</xr:StandardAttribute>
|
||||
</StandardAttributes>
|
||||
<Use>ForItem</Use>
|
||||
</Properties>
|
||||
<ChildObjects>
|
||||
<Attribute uuid="UUID-024">
|
||||
<Properties>
|
||||
<Name>Свойство</Name>
|
||||
<Synonym>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Свойство</v8:content>
|
||||
</v8:item>
|
||||
</Synonym>
|
||||
<Comment/>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
<v8:Length>100</v8:Length>
|
||||
<v8:AllowedLength>Variable</v8:AllowedLength>
|
||||
</v8:StringQualifiers>
|
||||
</Type>
|
||||
<PasswordMode>false</PasswordMode>
|
||||
<Format/>
|
||||
<EditFormat/>
|
||||
<ToolTip/>
|
||||
<MarkNegatives>false</MarkNegatives>
|
||||
<Mask/>
|
||||
<MultiLine>false</MultiLine>
|
||||
<ExtendedEdit>false</ExtendedEdit>
|
||||
<MinValue xsi:nil="true"/>
|
||||
<MaxValue xsi:nil="true"/>
|
||||
<FillChecking>DontCheck</FillChecking>
|
||||
<ChoiceFoldersAndItems>Items</ChoiceFoldersAndItems>
|
||||
<ChoiceParameterLinks/>
|
||||
<ChoiceParameters/>
|
||||
<QuickChoice>Auto</QuickChoice>
|
||||
<CreateOnInput>Auto</CreateOnInput>
|
||||
<ChoiceForm/>
|
||||
<LinkByType/>
|
||||
<ChoiceHistoryOnInput>Auto</ChoiceHistoryOnInput>
|
||||
<Indexing>DontIndex</Indexing>
|
||||
<FullTextSearch>Use</FullTextSearch>
|
||||
<DataHistory>Use</DataHistory>
|
||||
</Properties>
|
||||
</Attribute>
|
||||
<Attribute uuid="UUID-025">
|
||||
<Properties>
|
||||
<Name>Значение</Name>
|
||||
<Synonym>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Значение</v8:content>
|
||||
</v8:item>
|
||||
</Synonym>
|
||||
<Comment/>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
<v8:Length>200</v8:Length>
|
||||
<v8:AllowedLength>Variable</v8:AllowedLength>
|
||||
</v8:StringQualifiers>
|
||||
</Type>
|
||||
<PasswordMode>false</PasswordMode>
|
||||
<Format/>
|
||||
<EditFormat/>
|
||||
<ToolTip/>
|
||||
<MarkNegatives>false</MarkNegatives>
|
||||
<Mask/>
|
||||
<MultiLine>false</MultiLine>
|
||||
<ExtendedEdit>false</ExtendedEdit>
|
||||
<MinValue xsi:nil="true"/>
|
||||
<MaxValue xsi:nil="true"/>
|
||||
<FillChecking>DontCheck</FillChecking>
|
||||
<ChoiceFoldersAndItems>Items</ChoiceFoldersAndItems>
|
||||
<ChoiceParameterLinks/>
|
||||
<ChoiceParameters/>
|
||||
<QuickChoice>Auto</QuickChoice>
|
||||
<CreateOnInput>Auto</CreateOnInput>
|
||||
<ChoiceForm/>
|
||||
<LinkByType/>
|
||||
<ChoiceHistoryOnInput>Auto</ChoiceHistoryOnInput>
|
||||
<Indexing>DontIndex</Indexing>
|
||||
<FullTextSearch>Use</FullTextSearch>
|
||||
<DataHistory>Use</DataHistory>
|
||||
</Properties>
|
||||
</Attribute>
|
||||
</ChildObjects>
|
||||
</TabularSection>
|
||||
</ChildObjects>
|
||||
</Catalog>
|
||||
</MetaDataObject>
|
||||
|
||||
Reference in New Issue
Block a user