feat(meta-compile,meta-decompile): поддержка SessionParameter/CommonCommand/CommandGroup/CommonAttribute/FunctionalOptionsParameter/WSReference (v1.59/v0.50)

Группа B (простые служебные типы), 25-30-й типы, 1269 объектов acc+erp. Все НОВЫЕ.
ПОЛНЫЙ КОРПУС 1269/1269 byte-exact, TOTAL 0, 0 крашей. Регресс 68/68 ps1+py, ps1==py identical.

- SessionParameter — параметр сеанса (тип значения). FunctionalOptionsParameter — Use(MDObjectRef).
  WSReference — LocationURL +InternalInfo Manager. CommandGroup — Representation/Picture/Category.
- CommonCommand — общая команда (Group/Representation/Picture/CommandParameterType/ParameterUseMode/…)
  + заготовка Ext/CommandModule.bsl. Переиспользован Emit-CommandPicture.
- **CommonAttribute** (сложный) — богатый реквизит + Content(состав объектов {metadata,use,conditionalSeparation})
  + 9 свойств разделения данных + Indexing/FullTextSearch/DataHistory. **Ловушки:** (1) дефолт типа String(0)
  (не $def.type — это тип метаобъекта); (2) FillValue тип-зависим (String→typed-empty, Number→0), но системный
  реквизит-разделитель ОбластьДанных имеет nil на Number → маркер `fillValue:{nil:true}` (аналог emptyRef).
  Прощающий ввод состава — Normalize-MDObjectRef.

spec §7.15f, 6 кейсов. Кросс-дрейфа нет (новые типы). NB: py-декомпилятор отложен.
**Модель meta-compile: 30 типов метаданных.**

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-10 13:46:23 +03:00
co-authored by Claude Opus 4.8
parent 2507437eb2
commit df42f6cc79
35 changed files with 2368 additions and 6 deletions
@@ -1,4 +1,4 @@
# meta-compile v1.58 — Compile 1C metadata object from JSON
# meta-compile v1.59 — Compile 1C metadata object from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -348,7 +348,8 @@ $validTypes = @("Catalog","Document","Enum","Constant","InformationRegister","Ac
"ChartOfCalculationTypes","BusinessProcess","Task","ExchangePlan","DocumentJournal",
"Report","DataProcessor","CommonModule","ScheduledJob","EventSubscription",
"HTTPService","WebService","DefinedType","FunctionalOption",
"Sequence","FilterCriterion","DocumentNumerator","SettingsStorage","CommonForm")
"Sequence","FilterCriterion","DocumentNumerator","SettingsStorage","CommonForm",
"SessionParameter","CommonCommand","CommandGroup","CommonAttribute","FunctionalOptionsParameter","WSReference")
if ($objType -notin $validTypes) {
Write-Error "Unsupported type: $objType. Valid: $($validTypes -join ', ')"
exit 1
@@ -828,6 +829,7 @@ function Emit-FillValue {
}
if ($null -eq $spec) { X "$indent<FillValue xsi:nil=`"true`"/>"; return } # явный nil-override
if ($spec.nil -eq $true) { X "$indent<FillValue xsi:nil=`"true`"/>"; return } # явный nil на типизированном (маркер декомпилятора)
if ($spec.emptyRef -eq $true) { X "$indent<FillValue xsi:type=`"xr:DesignTimeRef`"/>"; return } # пустая ссылка (маркер декомпилятора)
if ($spec -is [bool]) {
X "$indent<FillValue xsi:type=`"xs:boolean`">$(if ($spec) { 'true' } else { 'false' })</FillValue>"; return
@@ -1109,6 +1111,9 @@ $script:generatedTypes = @{
"SettingsStorage" = @(
@{ prefix = "SettingsStorageManager"; category = "Manager" }
)
"WSReference" = @(
@{ prefix = "WSReferenceManager"; category = "Manager" }
)
}
function Emit-InternalInfo {
@@ -2648,6 +2653,140 @@ function Emit-CommonFormProperties {
Emit-MLText $i "Explanation" $def.explanation
}
function Emit-SessionParameterProperties {
param([string]$indent)
$i = $indent
X "$i<Name>$(Esc-Xml $objName)</Name>"
Emit-MLText $i "Synonym" $synonym
if ($def.comment) { X "$i<Comment>$(Esc-XmlText $def.comment)</Comment>" } else { X "$i<Comment/>" }
$vt = if ($def.valueType) { "$($def.valueType)" } elseif ($def.valueTypes) { (@($def.valueTypes) | ForEach-Object { "$_" }) -join ' + ' } else { '' }
if ($vt) { Emit-ValueType $i $vt } else { X "$i<Type/>" }
}
function Emit-FunctionalOptionsParameterProperties {
param([string]$indent)
$i = $indent
X "$i<Name>$(Esc-Xml $objName)</Name>"
Emit-MLText $i "Synonym" $synonym
if ($def.comment) { X "$i<Comment>$(Esc-XmlText $def.comment)</Comment>" } else { X "$i<Comment/>" }
# Use — измерения регистров/реквизиты, к которым привязан параметр (список MDObjectRef).
Emit-MDRefList $i "Use" $def.use
}
function Emit-WSReferenceProperties {
param([string]$indent)
$i = $indent
X "$i<Name>$(Esc-Xml $objName)</Name>"
Emit-MLText $i "Synonym" $synonym
if ($def.comment) { X "$i<Comment>$(Esc-XmlText $def.comment)</Comment>" } else { X "$i<Comment/>" }
$url = if ($def.locationURL) { "$($def.locationURL)" } elseif ($def.locationUrl) { "$($def.locationUrl)" } else { "" }
if ($url) { X "$i<LocationURL>$(Esc-XmlText $url)</LocationURL>" } else { X "$i<LocationURL/>" }
}
function Emit-CommandGroupProperties {
param([string]$indent)
$i = $indent
X "$i<Name>$(Esc-Xml $objName)</Name>"
Emit-MLText $i "Synonym" $synonym
if ($def.comment) { X "$i<Comment>$(Esc-XmlText $def.comment)</Comment>" } else { X "$i<Comment/>" }
X "$i<Representation>$(Get-EnumProp 'Representation' 'representation' 'Auto')</Representation>"
Emit-MLText $i "ToolTip" $def.tooltip
Emit-CommandPicture $i $def
X "$i<Category>$(Get-EnumProp 'Category' 'category' 'NavigationPanel')</Category>"
}
function Emit-CommonCommandProperties {
param([string]$indent)
$i = $indent
X "$i<Name>$(Esc-Xml $objName)</Name>"
Emit-MLText $i "Synonym" $synonym
if ($def.comment) { X "$i<Comment>$(Esc-XmlText $def.comment)</Comment>" } else { X "$i<Comment/>" }
$group = if ($def.group) { "$($def.group)" } else { "" }
if ($group) { X "$i<Group>$(Esc-Xml $group)</Group>" } else { X "$i<Group/>" }
X "$i<Representation>$(Get-EnumProp 'Representation' 'representation' 'Auto')</Representation>"
Emit-MLText $i "ToolTip" $def.tooltip
Emit-CommandPicture $i $def
if ($def.shortcut) { X "$i<Shortcut>$(Esc-Xml "$($def.shortcut)")</Shortcut>" } else { X "$i<Shortcut/>" }
$inclHelp = if (Get-BoolProp "includeHelpInContents" $false) { "true" } else { "false" }
X "$i<IncludeHelpInContents>$inclHelp</IncludeHelpInContents>"
if ($def.commandParameterType) {
X "$i<CommandParameterType>"
Emit-TypeContent "$i`t" "$($def.commandParameterType)"
X "$i</CommandParameterType>"
} else {
X "$i<CommandParameterType/>"
}
X "$i<ParameterUseMode>$(Get-EnumProp 'ParameterUseMode' 'parameterUseMode' 'Single')</ParameterUseMode>"
X "$i<ModifiesData>$(if (Get-BoolProp 'modifiesData' $false) { 'true' } else { 'false' })</ModifiesData>"
X "$i<OnMainServerUnavalableBehavior>$(Get-EnumProp 'OnMainServerUnavalableBehavior' 'onMainServerUnavalableBehavior' 'Auto')</OnMainServerUnavalableBehavior>"
}
function Emit-CommonAttributeProperties {
param([string]$indent)
$i = $indent
X "$i<Name>$(Esc-Xml $objName)</Name>"
Emit-MLText $i "Synonym" $synonym
if ($def.comment) { X "$i<Comment>$(Esc-XmlText $def.comment)</Comment>" } else { X "$i<Comment/>" }
# Дефолт типа — String(0) (переменная длина 0), НЕ $def.type (это тип метаобъекта «CommonAttribute»).
$vt = if ($def.valueType) { "$($def.valueType)" } else { 'String(0)' }
Emit-ValueType $i $vt
X "$i<PasswordMode>$(if (Get-BoolProp 'passwordMode' $false) { 'true' } else { 'false' })</PasswordMode>"
Emit-MLText $i "Format" $def.format
Emit-MLText $i "EditFormat" $def.editFormat
Emit-MLText $i "ToolTip" $def.tooltip
X "$i<MarkNegatives>$(if (Get-BoolProp 'markNegatives' $false) { 'true' } else { 'false' })</MarkNegatives>"
if ($def.mask) { X "$i<Mask>$(Esc-XmlText $def.mask)</Mask>" } else { X "$i<Mask/>" }
X "$i<MultiLine>$(if (Get-BoolProp 'multiLine' $false) { 'true' } else { 'false' })</MultiLine>"
X "$i<ExtendedEdit>$(if (Get-BoolProp 'extendedEdit' $false) { 'true' } else { 'false' })</ExtendedEdit>"
Emit-MinMaxValue $i "MinValue" $def.minValue
Emit-MinMaxValue $i "MaxValue" $def.maxValue
$ffv = if (Get-BoolProp 'fillFromFillingValue' $false) { 'true' } else { 'false' }
X "$i<FillFromFillingValue>$ffv</FillFromFillingValue>"
Emit-FillValue $i $vt $def.fillValue ($null -ne $def.fillValue)
X "$i<FillChecking>$(Get-EnumProp 'FillChecking' 'fillChecking' 'DontCheck')</FillChecking>"
X "$i<ChoiceFoldersAndItems>$(Get-EnumProp 'ChoiceFoldersAndItems' 'choiceFoldersAndItems' 'Items')</ChoiceFoldersAndItems>"
Emit-ChoiceParameterLinks $i $def.choiceParameterLinks
Emit-ChoiceParameters $i $def.choiceParameters
X "$i<QuickChoice>$(Get-EnumProp 'QuickChoice' 'quickChoice' 'Auto')</QuickChoice>"
X "$i<CreateOnInput>$(Get-EnumProp 'CreateOnInput' 'createOnInput' 'Auto')</CreateOnInput>"
if ($def.choiceForm) { X "$i<ChoiceForm>$(Esc-Xml "$($def.choiceForm)")</ChoiceForm>" } else { X "$i<ChoiceForm/>" }
Emit-LinkByType $i $def.linkByType
X "$i<ChoiceHistoryOnInput>$(Get-EnumProp 'ChoiceHistoryOnInput' 'choiceHistoryOnInput' 'Auto')</ChoiceHistoryOnInput>"
# Content — объекты, к которым добавлен общий реквизит: {metadata, use?, conditionalSeparation?}.
$content = @(); if ($def.content) { $content = @($def.content) }
if ($content.Count -gt 0) {
X "$i<Content>"
foreach ($c in $content) {
$md = if ($c -is [string]) { "$c" } else { "$($c.metadata)" }
$use = if ($c -is [string]) { 'Use' } elseif ($c.use) { "$($c.use)" } else { 'Use' }
X "$i`t<xr:Item>"
X "$i`t`t<xr:Metadata>$(Esc-Xml (Normalize-MDObjectRef $md))</xr:Metadata>"
X "$i`t`t<xr:Use>$use</xr:Use>"
$cs = if ($c -isnot [string] -and $c.conditionalSeparation) { "$($c.conditionalSeparation)" } else { "" }
if ($cs) { X "$i`t`t<xr:ConditionalSeparation>$(Esc-Xml $cs)</xr:ConditionalSeparation>" } else { X "$i`t`t<xr:ConditionalSeparation/>" }
X "$i`t</xr:Item>"
}
X "$i</Content>"
} else {
X "$i<Content/>"
}
X "$i<AutoUse>$(Get-EnumProp 'AutoUse' 'autoUse' 'DontUse')</AutoUse>"
X "$i<DataSeparation>$(Get-EnumProp 'DataSeparation' 'dataSeparation' 'DontUse')</DataSeparation>"
X "$i<SeparatedDataUse>$(Get-EnumProp 'SeparatedDataUse' 'separatedDataUse' 'Independently')</SeparatedDataUse>"
$dsv = if ($def.dataSeparationValue) { "$($def.dataSeparationValue)" } else { "" }
if ($dsv) { X "$i<DataSeparationValue>$(Esc-Xml $dsv)</DataSeparationValue>" } else { X "$i<DataSeparationValue/>" }
$dsu = if ($def.dataSeparationUse) { "$($def.dataSeparationUse)" } else { "" }
if ($dsu) { X "$i<DataSeparationUse>$(Esc-Xml $dsu)</DataSeparationUse>" } else { X "$i<DataSeparationUse/>" }
$cs2 = if ($def.conditionalSeparation) { "$($def.conditionalSeparation)" } else { "" }
if ($cs2) { X "$i<ConditionalSeparation>$(Esc-Xml $cs2)</ConditionalSeparation>" } else { X "$i<ConditionalSeparation/>" }
X "$i<UsersSeparation>$(Get-EnumProp 'UsersSeparation' 'usersSeparation' 'DontUse')</UsersSeparation>"
X "$i<AuthenticationSeparation>$(Get-EnumProp 'AuthenticationSeparation' 'authenticationSeparation' 'DontUse')</AuthenticationSeparation>"
X "$i<ConfigurationExtensionsSeparation>$(Get-EnumProp 'ConfigurationExtensionsSeparation' 'configurationExtensionsSeparation' 'DontUse')</ConfigurationExtensionsSeparation>"
X "$i<Indexing>$(Get-EnumProp 'Indexing' 'indexing' 'DontIndex')</Indexing>"
X "$i<FullTextSearch>$(Get-EnumProp 'FullTextSearch' 'fullTextSearch' 'Use')</FullTextSearch>"
X "$i<DataHistory>$(Get-EnumProp 'DataHistory' 'dataHistory' 'Use')</DataHistory>"
}
# Измерение последовательности: Name/Synonym/Comment/Type + DocumentMap/RegisterRecordsMap (списки MDObjectRef —
# соответствие измерения реквизитам документов/движениям регистров).
function Emit-SequenceDimension {
@@ -3756,6 +3895,12 @@ switch ($objType) {
"DocumentNumerator" { Emit-DocumentNumeratorProperties "`t`t`t" }
"SettingsStorage" { Emit-SettingsStorageProperties "`t`t`t" }
"CommonForm" { Emit-CommonFormProperties "`t`t`t" }
"SessionParameter" { Emit-SessionParameterProperties "`t`t`t" }
"CommonCommand" { Emit-CommonCommandProperties "`t`t`t" }
"CommandGroup" { Emit-CommandGroupProperties "`t`t`t" }
"CommonAttribute" { Emit-CommonAttributeProperties "`t`t`t" }
"FunctionalOptionsParameter" { Emit-FunctionalOptionsParameterProperties "`t`t`t" }
"WSReference" { Emit-WSReferenceProperties "`t`t`t" }
"CommonModule" { Emit-CommonModuleProperties "`t`t`t" }
"ScheduledJob" { Emit-ScheduledJobProperties "`t`t`t" }
"EventSubscription" { Emit-EventSubscriptionProperties "`t`t`t" }
@@ -4091,6 +4236,12 @@ $script:typePluralMap = @{
"DocumentNumerator" = "DocumentNumerators"
"SettingsStorage" = "SettingsStorages"
"CommonForm" = "CommonForms"
"SessionParameter" = "SessionParameters"
"CommonCommand" = "CommonCommands"
"CommandGroup" = "CommandGroups"
"CommonAttribute" = "CommonAttributes"
"FunctionalOptionsParameter" = "FunctionalOptionsParameters"
"WSReference" = "WSReferences"
}
$typePlural = $script:typePluralMap[$objType]
@@ -4368,6 +4519,15 @@ if ($objType -in $typesWithModule) {
$modulesCreated += $modulePath
}
}
# CommonCommand — заготовка модуля команды (CommandModule.bsl).
if ($objType -eq "CommonCommand") {
$modulePath = Join-Path $extDir "CommandModule.bsl"
if (-not (Test-Path $modulePath)) {
Ensure-ExtDir
[System.IO.File]::WriteAllText($modulePath, "", $enc)
$modulesCreated += $modulePath
}
}
# CommonForm — заготовка структуры формы под компиляцию: Ext/Form.xml (пустая управляемая форма) + Ext/Form/Module.bsl.
# Содержимое формы наполняет form-compile/form-edit (не перезаписываем существующее).
if ($objType -eq "CommonForm") {
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# meta-compile v1.58 — Compile 1C metadata object from JSON
# meta-compile v1.59 — Compile 1C metadata object from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -464,6 +464,7 @@ valid_types = [
'FunctionalOption',
'Sequence', 'FilterCriterion', 'DocumentNumerator', 'SettingsStorage',
'CommonForm',
'SessionParameter', 'CommonCommand', 'CommandGroup', 'CommonAttribute', 'FunctionalOptionsParameter', 'WSReference',
]
if obj_type not in valid_types:
print(f"Unsupported type: {obj_type}. Valid: {', '.join(valid_types)}", file=sys.stderr)
@@ -854,6 +855,9 @@ def emit_fill_value(indent, type_str, spec, has_spec, type_empty=False):
if spec is None:
X(f'{indent}<FillValue xsi:nil="true"/>') # явный nil-override
return
if isinstance(spec, dict) and spec.get('nil') is True:
X(f'{indent}<FillValue xsi:nil="true"/>') # явный nil на типизированном (маркер декомпилятора)
return
if isinstance(spec, dict) and spec.get('emptyRef') is True:
X(f'{indent}<FillValue xsi:type="xr:DesignTimeRef"/>') # пустая ссылка (маркер декомпилятора)
return
@@ -1128,6 +1132,9 @@ generated_types = {
'SettingsStorage': [
{'prefix': 'SettingsStorageManager', 'category': 'Manager'},
],
'WSReference': [
{'prefix': 'WSReferenceManager', 'category': 'Manager'},
],
}
def emit_internal_info(indent, object_type, object_name):
@@ -2655,6 +2662,153 @@ def emit_common_form_properties(indent):
emit_mltext(i, 'ExtendedPresentation', defn.get('extendedPresentation'))
emit_mltext(i, 'Explanation', defn.get('explanation'))
def _emit_comment(i):
if defn.get('comment'):
X(f'{i}<Comment>{esc_xml_text(str(defn["comment"]))}</Comment>')
else:
X(f'{i}<Comment/>')
def emit_session_parameter_properties(indent):
i = indent
X(f'{i}<Name>{esc_xml(obj_name)}</Name>')
emit_mltext(i, 'Synonym', synonym)
_emit_comment(i)
if defn.get('valueType'):
vt = str(defn['valueType'])
elif defn.get('valueTypes'):
vt = ' + '.join(str(x) for x in defn['valueTypes'])
else:
vt = ''
if vt:
emit_value_type(i, vt)
else:
X(f'{i}<Type/>')
def emit_functional_options_parameter_properties(indent):
i = indent
X(f'{i}<Name>{esc_xml(obj_name)}</Name>')
emit_mltext(i, 'Synonym', synonym)
_emit_comment(i)
emit_md_ref_list(i, 'Use', defn.get('use'))
def emit_ws_reference_properties(indent):
i = indent
X(f'{i}<Name>{esc_xml(obj_name)}</Name>')
emit_mltext(i, 'Synonym', synonym)
_emit_comment(i)
url = str(defn['locationURL']) if defn.get('locationURL') else (str(defn['locationUrl']) if defn.get('locationUrl') else '')
if url:
X(f'{i}<LocationURL>{esc_xml_text(url)}</LocationURL>')
else:
X(f'{i}<LocationURL/>')
def emit_command_group_properties(indent):
i = indent
X(f'{i}<Name>{esc_xml(obj_name)}</Name>')
emit_mltext(i, 'Synonym', synonym)
_emit_comment(i)
X(f'{i}<Representation>{get_enum_prop("Representation", "representation", "Auto")}</Representation>')
emit_mltext(i, 'ToolTip', defn.get('tooltip'))
emit_command_picture(i, defn)
X(f'{i}<Category>{get_enum_prop("Category", "category", "NavigationPanel")}</Category>')
def emit_common_command_properties(indent):
i = indent
X(f'{i}<Name>{esc_xml(obj_name)}</Name>')
emit_mltext(i, 'Synonym', synonym)
_emit_comment(i)
group = str(defn['group']) if defn.get('group') else ''
if group:
X(f'{i}<Group>{esc_xml(group)}</Group>')
else:
X(f'{i}<Group/>')
X(f'{i}<Representation>{get_enum_prop("Representation", "representation", "Auto")}</Representation>')
emit_mltext(i, 'ToolTip', defn.get('tooltip'))
emit_command_picture(i, defn)
if defn.get('shortcut'):
X(f'{i}<Shortcut>{esc_xml(str(defn["shortcut"]))}</Shortcut>')
else:
X(f'{i}<Shortcut/>')
incl_help = 'true' if get_bool_prop('includeHelpInContents', False) else 'false'
X(f'{i}<IncludeHelpInContents>{incl_help}</IncludeHelpInContents>')
if defn.get('commandParameterType'):
X(f'{i}<CommandParameterType>')
emit_type_content(f'{i}\t', str(defn['commandParameterType']))
X(f'{i}</CommandParameterType>')
else:
X(f'{i}<CommandParameterType/>')
X(f'{i}<ParameterUseMode>{get_enum_prop("ParameterUseMode", "parameterUseMode", "Single")}</ParameterUseMode>')
X(f'{i}<ModifiesData>{"true" if get_bool_prop("modifiesData", False) else "false"}</ModifiesData>')
X(f'{i}<OnMainServerUnavalableBehavior>{get_enum_prop("OnMainServerUnavalableBehavior", "onMainServerUnavalableBehavior", "Auto")}</OnMainServerUnavalableBehavior>')
def emit_common_attribute_properties(indent):
i = indent
X(f'{i}<Name>{esc_xml(obj_name)}</Name>')
emit_mltext(i, 'Synonym', synonym)
_emit_comment(i)
vt = str(defn['valueType']) if defn.get('valueType') else 'String(0)'
emit_value_type(i, vt)
X(f'{i}<PasswordMode>{"true" if get_bool_prop("passwordMode", False) else "false"}</PasswordMode>')
emit_mltext(i, 'Format', defn.get('format'))
emit_mltext(i, 'EditFormat', defn.get('editFormat'))
emit_mltext(i, 'ToolTip', defn.get('tooltip'))
X(f'{i}<MarkNegatives>{"true" if get_bool_prop("markNegatives", False) else "false"}</MarkNegatives>')
if defn.get('mask'):
X(f'{i}<Mask>{esc_xml_text(str(defn["mask"]))}</Mask>')
else:
X(f'{i}<Mask/>')
X(f'{i}<MultiLine>{"true" if get_bool_prop("multiLine", False) else "false"}</MultiLine>')
X(f'{i}<ExtendedEdit>{"true" if get_bool_prop("extendedEdit", False) else "false"}</ExtendedEdit>')
emit_min_max_value(i, 'MinValue', defn.get('minValue'))
emit_min_max_value(i, 'MaxValue', defn.get('maxValue'))
X(f'{i}<FillFromFillingValue>{"true" if get_bool_prop("fillFromFillingValue", False) else "false"}</FillFromFillingValue>')
emit_fill_value(i, vt, defn.get('fillValue'), defn.get('fillValue') is not None)
X(f'{i}<FillChecking>{get_enum_prop("FillChecking", "fillChecking", "DontCheck")}</FillChecking>')
X(f'{i}<ChoiceFoldersAndItems>{get_enum_prop("ChoiceFoldersAndItems", "choiceFoldersAndItems", "Items")}</ChoiceFoldersAndItems>')
emit_choice_parameter_links(i, defn.get('choiceParameterLinks'))
emit_choice_parameters(i, defn.get('choiceParameters'))
X(f'{i}<QuickChoice>{get_enum_prop("QuickChoice", "quickChoice", "Auto")}</QuickChoice>')
X(f'{i}<CreateOnInput>{get_enum_prop("CreateOnInput", "createOnInput", "Auto")}</CreateOnInput>')
if defn.get('choiceForm'):
X(f'{i}<ChoiceForm>{esc_xml(str(defn["choiceForm"]))}</ChoiceForm>')
else:
X(f'{i}<ChoiceForm/>')
emit_link_by_type(i, defn.get('linkByType'))
X(f'{i}<ChoiceHistoryOnInput>{get_enum_prop("ChoiceHistoryOnInput", "choiceHistoryOnInput", "Auto")}</ChoiceHistoryOnInput>')
content = list(defn['content']) if defn.get('content') else []
if content:
X(f'{i}<Content>')
for c in content:
md = c if isinstance(c, str) else str(c.get('metadata', ''))
use = 'Use' if isinstance(c, str) else (str(c['use']) if c.get('use') else 'Use')
X(f'{i}\t<xr:Item>')
X(f'{i}\t\t<xr:Metadata>{esc_xml(normalize_md_object_ref(md))}</xr:Metadata>')
X(f'{i}\t\t<xr:Use>{use}</xr:Use>')
cs = '' if isinstance(c, str) else (str(c['conditionalSeparation']) if c.get('conditionalSeparation') else '')
if cs:
X(f'{i}\t\t<xr:ConditionalSeparation>{esc_xml(cs)}</xr:ConditionalSeparation>')
else:
X(f'{i}\t\t<xr:ConditionalSeparation/>')
X(f'{i}\t</xr:Item>')
X(f'{i}</Content>')
else:
X(f'{i}<Content/>')
X(f'{i}<AutoUse>{get_enum_prop("AutoUse", "autoUse", "DontUse")}</AutoUse>')
X(f'{i}<DataSeparation>{get_enum_prop("DataSeparation", "dataSeparation", "DontUse")}</DataSeparation>')
X(f'{i}<SeparatedDataUse>{get_enum_prop("SeparatedDataUse", "separatedDataUse", "Independently")}</SeparatedDataUse>')
dsv = str(defn['dataSeparationValue']) if defn.get('dataSeparationValue') else ''
X(f'{i}<DataSeparationValue>{esc_xml(dsv)}</DataSeparationValue>' if dsv else f'{i}<DataSeparationValue/>')
dsu = str(defn['dataSeparationUse']) if defn.get('dataSeparationUse') else ''
X(f'{i}<DataSeparationUse>{esc_xml(dsu)}</DataSeparationUse>' if dsu else f'{i}<DataSeparationUse/>')
cs2 = str(defn['conditionalSeparation']) if defn.get('conditionalSeparation') else ''
X(f'{i}<ConditionalSeparation>{esc_xml(cs2)}</ConditionalSeparation>' if cs2 else f'{i}<ConditionalSeparation/>')
X(f'{i}<UsersSeparation>{get_enum_prop("UsersSeparation", "usersSeparation", "DontUse")}</UsersSeparation>')
X(f'{i}<AuthenticationSeparation>{get_enum_prop("AuthenticationSeparation", "authenticationSeparation", "DontUse")}</AuthenticationSeparation>')
X(f'{i}<ConfigurationExtensionsSeparation>{get_enum_prop("ConfigurationExtensionsSeparation", "configurationExtensionsSeparation", "DontUse")}</ConfigurationExtensionsSeparation>')
X(f'{i}<Indexing>{get_enum_prop("Indexing", "indexing", "DontIndex")}</Indexing>')
X(f'{i}<FullTextSearch>{get_enum_prop("FullTextSearch", "fullTextSearch", "Use")}</FullTextSearch>')
X(f'{i}<DataHistory>{get_enum_prop("DataHistory", "dataHistory", "Use")}</DataHistory>')
def emit_sequence_dimension(indent, dim_def):
uid = new_uuid()
parsed = parse_attribute_shorthand(dim_def)
@@ -3641,6 +3795,12 @@ property_emitters = {
'DocumentNumerator': emit_document_numerator_properties,
'SettingsStorage': emit_settings_storage_properties,
'CommonForm': emit_common_form_properties,
'SessionParameter': emit_session_parameter_properties,
'CommonCommand': emit_common_command_properties,
'CommandGroup': emit_command_group_properties,
'CommonAttribute': emit_common_attribute_properties,
'FunctionalOptionsParameter': emit_functional_options_parameter_properties,
'WSReference': emit_ws_reference_properties,
'CommonModule': emit_common_module_properties,
'ScheduledJob': emit_scheduled_job_properties,
'EventSubscription': emit_event_subscription_properties,
@@ -3960,6 +4120,12 @@ type_plural_map = {
'DocumentNumerator': 'DocumentNumerators',
'SettingsStorage': 'SettingsStorages',
'CommonForm': 'CommonForms',
'SessionParameter': 'SessionParameters',
'CommonCommand': 'CommonCommands',
'CommandGroup': 'CommandGroups',
'CommonAttribute': 'CommonAttributes',
'FunctionalOptionsParameter': 'FunctionalOptionsParameters',
'WSReference': 'WSReferences',
}
type_plural = type_plural_map[obj_type]
@@ -4033,6 +4199,14 @@ if obj_type in types_with_module:
write_utf8_bom(module_path, '')
modules_created.append(module_path)
# CommonCommand — заготовка модуля команды (CommandModule.bsl).
if obj_type == 'CommonCommand':
module_path = os.path.join(ext_dir, 'CommandModule.bsl')
if not os.path.isfile(module_path):
ensure_ext_dir()
write_utf8_bom(module_path, '')
modules_created.append(module_path)
# CommonForm — заготовка структуры формы под компиляцию (form-compile наполняет содержимое).
if obj_type == 'CommonForm':
ensure_ext_dir()
@@ -1,4 +1,4 @@
# meta-decompile v0.49 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
# meta-decompile v0.50 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
#
# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document,
@@ -92,8 +92,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', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes', 'Document', 'InformationRegister', 'AccumulationRegister', 'AccountingRegister', 'CalculationRegister', 'BusinessProcess', 'Task', 'Enum', 'Report', 'DataProcessor', 'Constant', 'DefinedType', 'FunctionalOption', 'DocumentJournal', 'Sequence', 'FilterCriterion', 'DocumentNumerator', 'SettingsStorage', 'CommonModule', 'EventSubscription', 'ScheduledJob', 'CommonForm')) {
[Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (…, CommonModule, EventSubscription, ScheduledJob, CommonForm)"); exit 3
if ($objType -notin @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes', 'Document', 'InformationRegister', 'AccumulationRegister', 'AccountingRegister', 'CalculationRegister', 'BusinessProcess', 'Task', 'Enum', 'Report', 'DataProcessor', 'Constant', 'DefinedType', 'FunctionalOption', 'DocumentJournal', 'Sequence', 'FilterCriterion', 'DocumentNumerator', 'SettingsStorage', 'CommonModule', 'EventSubscription', 'ScheduledJob', 'CommonForm', 'SessionParameter', 'CommonCommand', 'CommandGroup', 'CommonAttribute', 'FunctionalOptionsParameter', 'WSReference')) {
[Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (…, SessionParameter, CommonCommand, CommandGroup, CommonAttribute, FunctionalOptionsParameter, WSReference)"); exit 3
}
$props = $objNode.SelectSingleNode('md:Properties', $nsm)
@@ -691,6 +691,122 @@ if ($objType -eq 'CommonForm') {
}
$ep = Get-MLValue ($props.SelectSingleNode('md:ExtendedPresentation', $nsm)); if ($null -ne $ep) { $dsl['extendedPresentation'] = $ep }
}
# SessionParameter — параметр сеанса: только тип значения.
if ($objType -eq 'SessionParameter') {
$vt = Get-TypeShorthand ($props.SelectSingleNode('md:Type', $nsm)); if ($vt) { $dsl['valueType'] = $vt }
}
# FunctionalOptionsParameter — параметр функ. опции: Use (список MDObjectRef).
if ($objType -eq 'FunctionalOptionsParameter') {
$un = $props.SelectSingleNode('md:Use', $nsm)
if ($un) { $items = @($un.SelectNodes('xr:Item', $nsm) | ForEach-Object { $_.InnerText }); if ($items.Count -gt 0) { $dsl['use'] = [System.Collections.ArrayList]@($items) } }
}
# WSReference — WS-ссылка: URL расположения WSDL (+InternalInfo Manager).
if ($objType -eq 'WSReference') {
$url = P 'LocationURL'; if ($url) { $dsl['locationURL'] = $url }
}
# Общий захват структурного <Picture> (зеркало Emit-CommandPicture). Пишет в $tgt ключи picture/loadTransparent.
function Get-PictureToDsl { param($propsNode, $tgt)
$refN = $propsNode.SelectSingleNode('md:Picture/xr:Ref', $nsm)
$absN = $propsNode.SelectSingleNode('md:Picture/xr:Abs', $nsm)
if ($refN -or $absN) {
$psrc = if ($refN) { $refN.InnerText } else { "abs:$($absN.InnerText)" }
$ltN = $propsNode.SelectSingleNode('md:Picture/xr:LoadTransparent', $nsm)
$ltFalse = ($ltN -and $ltN.InnerText -eq 'false')
$tpxN = $propsNode.SelectSingleNode('md:Picture/xr:TransparentPixel', $nsm)
if ($tpxN) {
$po = [ordered]@{ src = $psrc }; if ($ltFalse) { $po['loadTransparent'] = $false }
$po['transparentPixel'] = [ordered]@{ x = [int]$tpxN.GetAttribute('x'); y = [int]$tpxN.GetAttribute('y') }
$tgt['picture'] = $po
} else { $tgt['picture'] = $psrc; if ($ltFalse) { $tgt['loadTransparent'] = $false } }
}
}
# CommandGroup — группа команд: представление, подсказка, картинка, категория.
if ($objType -eq 'CommandGroup') {
Add-EnumProp 'representation' 'Representation' 'Auto'
$tt = Get-MLValue ($props.SelectSingleNode('md:ToolTip', $nsm)); if ($null -ne $tt) { $dsl['tooltip'] = $tt }
Get-PictureToDsl $props $dsl
Add-EnumProp 'category' 'Category' 'NavigationPanel'
}
# CommonCommand — общая команда: группа, представление, подсказка, картинка, параметр, режимы.
if ($objType -eq 'CommonCommand') {
$grp = P 'Group'; if ($grp) { $dsl['group'] = $grp }
Add-EnumProp 'representation' 'Representation' 'Auto'
$tt = Get-MLValue ($props.SelectSingleNode('md:ToolTip', $nsm)); if ($null -ne $tt) { $dsl['tooltip'] = $tt }
Get-PictureToDsl $props $dsl
$sc = P 'Shortcut'; if ($sc) { $dsl['shortcut'] = $sc }
$cpt = Get-TypeShorthand ($props.SelectSingleNode('md:CommandParameterType', $nsm)); if ($cpt) { $dsl['commandParameterType'] = $cpt }
Add-EnumProp 'parameterUseMode' 'ParameterUseMode' 'Single'
Add-BoolProp 'modifiesData' 'ModifiesData' $false
Add-EnumProp 'onMainServerUnavalableBehavior' 'OnMainServerUnavalableBehavior' 'Auto'
}
# CommonAttribute — общий реквизит: тип + value-свойства + состав объектов + свойства разделения данных.
if ($objType -eq 'CommonAttribute') {
$vt = Get-TypeShorthand ($props.SelectSingleNode('md:Type', $nsm)); if ($vt -and $vt -ne 'String(0)') { $dsl['valueType'] = $vt }
Add-BoolProp 'passwordMode' 'PasswordMode' $false
foreach ($mlp in @(@('Format','format'), @('EditFormat','editFormat'), @('ToolTip','tooltip'))) {
$mv = Get-MLValue ($props.SelectSingleNode("md:$($mlp[0])", $nsm)); if ($null -ne $mv) { $dsl[$mlp[1]] = $mv }
}
Add-BoolProp 'markNegatives' 'MarkNegatives' $false
$msk = P 'Mask'; if ($msk) { $dsl['mask'] = $msk }
Add-BoolProp 'multiLine' 'MultiLine' $false
Add-BoolProp 'extendedEdit' 'ExtendedEdit' $false
foreach ($mm in @(@('MinValue','minValue'), @('MaxValue','maxValue'))) {
$mn = $props.SelectSingleNode("md:$($mm[0])", $nsm)
if ($mn -and $mn.GetAttribute('nil', 'http://www.w3.org/2001/XMLSchema-instance') -ne 'true') {
$mxt = $mn.GetAttribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
if ($mxt -match 'decimal$') { $dsl[$mm[1]] = if ($mn.InnerText -match '^-?\d+$') { [long]$mn.InnerText } else { [double]$mn.InnerText } } else { $dsl[$mm[1]] = $mn.InnerText }
}
}
Add-BoolProp 'fillFromFillingValue' 'FillFromFillingValue' $false
# FillValue: тип-зависимый дефолт (String→typed-empty, Number→0, прочее→nil). Захват при отклонении.
# nil на String/Number-типе ≠ дефолт → маркер {nil:true} (напр. системный реквизит-разделитель ОбластьДанных).
$catVt = if ($vt) { $vt } else { 'String(0)' }
$fvN = $props.SelectSingleNode('md:FillValue', $nsm)
if ($fvN) {
$fvNil = ($fvN.GetAttribute('nil', 'http://www.w3.org/2001/XMLSchema-instance') -eq 'true')
if ($fvNil) {
if ($catVt -match '^(String|Number)') { $dsl['fillValue'] = [ordered]@{ nil = $true } }
} else {
$fvXt = $fvN.GetAttribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
if ($fvXt -match 'DesignTimeRef$' -and $fvN.InnerText -eq '') { $dsl['fillValue'] = [ordered]@{ emptyRef = $true } }
elseif ($fvXt -match 'decimal$') { if ($fvN.InnerText -ne '0') { $dsl['fillValue'] = if ($fvN.InnerText -match '^-?\d+$') { [long]$fvN.InnerText } else { [double]$fvN.InnerText } } }
elseif (-not [string]::IsNullOrEmpty($fvN.InnerText)) { $dsl['fillValue'] = $fvN.InnerText }
}
}
Add-EnumProp 'fillChecking' 'FillChecking' 'DontCheck'
Add-EnumProp 'choiceFoldersAndItems' 'ChoiceFoldersAndItems' 'Items'
$cpl = Parse-ChoiceParameterLinks $props 'md:ChoiceParameterLinks'; if ($null -ne $cpl) { $dsl['choiceParameterLinks'] = $cpl }
$cp = Parse-ChoiceParameters $props 'md:ChoiceParameters'; if ($null -ne $cp) { $dsl['choiceParameters'] = $cp }
Add-EnumProp 'quickChoice' 'QuickChoice' 'Auto'
Add-EnumProp 'createOnInput' 'CreateOnInput' 'Auto'
$cf = P 'ChoiceForm'; if ($cf) { $dsl['choiceForm'] = $cf }
Add-EnumProp 'choiceHistoryOnInput' 'ChoiceHistoryOnInput' 'Auto'
# Content — объекты, к которым добавлен общий реквизит.
$cn = $props.SelectSingleNode('md:Content', $nsm)
if ($cn) {
$cArr = [System.Collections.ArrayList]@()
foreach ($it in @($cn.SelectNodes('xr:Item', $nsm))) {
$mdN = $it.SelectSingleNode('xr:Metadata', $nsm); $mdv = if ($mdN) { $mdN.InnerText } else { '' }
$useN = $it.SelectSingleNode('xr:Use', $nsm); $usev = if ($useN) { $useN.InnerText } else { 'Use' }
$csN = $it.SelectSingleNode('xr:ConditionalSeparation', $nsm); $csv = if ($csN) { $csN.InnerText } else { '' }
if ($usev -eq 'Use' -and -not $csv) { [void]$cArr.Add($mdv) }
else { $io = [ordered]@{ metadata = $mdv }; if ($usev -ne 'Use') { $io['use'] = $usev }; if ($csv) { $io['conditionalSeparation'] = $csv }; [void]$cArr.Add($io) }
}
if ($cArr.Count -gt 0) { $dsl['content'] = $cArr }
}
Add-EnumProp 'autoUse' 'AutoUse' 'DontUse'
Add-EnumProp 'dataSeparation' 'DataSeparation' 'DontUse'
Add-EnumProp 'separatedDataUse' 'SeparatedDataUse' 'Independently'
$dsv = P 'DataSeparationValue'; if ($dsv) { $dsl['dataSeparationValue'] = $dsv }
$dsu = P 'DataSeparationUse'; if ($dsu) { $dsl['dataSeparationUse'] = $dsu }
$cs2 = P 'ConditionalSeparation'; if ($cs2) { $dsl['conditionalSeparation'] = $cs2 }
Add-EnumProp 'usersSeparation' 'UsersSeparation' 'DontUse'
Add-EnumProp 'authenticationSeparation' 'AuthenticationSeparation' 'DontUse'
Add-EnumProp 'configurationExtensionsSeparation' 'ConfigurationExtensionsSeparation' 'DontUse'
Add-EnumProp 'indexing' 'Indexing' 'DontIndex'
Add-EnumProp 'dataHistory' 'DataHistory' 'Use'
# fullTextSearch покрыт общим блоком (дефолт Use).
}
# ScheduledJob — регламентное задание: метод, ключ, флаги, рестарт.
if ($objType -eq 'ScheduledJob') {
$mn = P 'MethodName'; if ($mn) { $dsl['methodName'] = $mn }