feat(meta-edit): структурные свойства реквизита Format/EditFormat/ToolTip/ChoiceForm (Фаза 2 Шаг 2, v1.13)

modify-attribute/-dimension/-resource теперь умеют задавать структурные свойства
реквизита (не только скаляры): Format/EditFormat/ToolTip (ML-строки через
существующий Build-MLTextXml) + ChoiceForm. Ветки-диспетчеры в switch перед default,
по образцу ветки type (replace-or-create). Отсутствующее свойство создаётся в
канонической позиции (Insert-PropertyInOrder из Шага 1). Ключи — PascalCase
XML-имена (консистентно с существующей modify-конвенцией CodeLength/Indexing).

Побочный фикс: Set-AttrPropertyElement (ps1) через InsertBefore+RemoveChild вместо
InsertAfter+Remove-NodeWithWhitespace — последний склеивал (</PasswordMode><Format>),
т.к. в XmlDocument ведущий whitespace — отдельный узел; py (tail-модель) был корректен.

Cert: verify-snapshots --case modify-attribute-structural — Format/EditFormat/ToolTip/
ChoiceForm (с реальной формой через form-add preRun) грузятся в 1С. meta-edit 14/14
ps1+py; byte-паритет ps1==py (после нормализации раннера).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-11 22:34:47 +03:00
co-authored by Claude Opus 4.8
parent 0e68421f50
commit c31cff5ada
11 changed files with 636 additions and 2 deletions
+41 -1
View File
@@ -1,4 +1,4 @@
# meta-edit v1.12 — Edit existing 1C metadata object XML (inline mode + complex properties + TS attribute ops + modify-ts + create-if-missing свойств)
# meta-edit v1.13 — Edit existing 1C metadata object XML (inline + complex props + TS ops + modify-ts + create-if-missing + structural attr props Format/EditFormat/ToolTip/ChoiceForm)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$DefinitionFile,
@@ -2240,6 +2240,26 @@ function Modify-ChildElements($modifyDef, [string]$childType) {
Info "Changed synonym of $xmlTag '$elemName': $changeValue"
$script:modifyCount++
}
"Format" {
if (Set-AttrPropertyElement $propsEl "Format" (Build-MLTextXml (Get-ChildIndent $propsEl) "Format" "$changeValue")) {
Info "Set $xmlTag '$elemName'.Format"; $script:modifyCount++
}
}
"EditFormat" {
if (Set-AttrPropertyElement $propsEl "EditFormat" (Build-MLTextXml (Get-ChildIndent $propsEl) "EditFormat" "$changeValue")) {
Info "Set $xmlTag '$elemName'.EditFormat"; $script:modifyCount++
}
}
"ToolTip" {
if (Set-AttrPropertyElement $propsEl "ToolTip" (Build-MLTextXml (Get-ChildIndent $propsEl) "ToolTip" "$changeValue")) {
Info "Set $xmlTag '$elemName'.ToolTip"; $script:modifyCount++
}
}
"ChoiceForm" {
if (Set-AttrPropertyElement $propsEl "ChoiceForm" "<ChoiceForm>$(Esc-Xml "$changeValue")</ChoiceForm>") {
Info "Set $xmlTag '$elemName'.ChoiceForm"; $script:modifyCount++
}
}
default {
# Scalar property change (Indexing, FillChecking, Use, etc.)
$scalarEl = $null
@@ -2380,6 +2400,26 @@ function Insert-PropertyInOrder($propsEl, $newNode, $orderArray, $propName) {
Insert-BeforeElement $propsEl $newNode $refNode $childIndent
}
# Заменить существующий элемент свойства реквизита новым фрагментом (по образцу ветки type),
# либо создать в канонической позиции, если его нет. Возвращает $true при успехе.
function Set-AttrPropertyElement($propsEl, $propName, $fragmentXml) {
$newNodes = Import-Fragment $fragmentXml
if ($newNodes.Count -eq 0) { return $false }
$existing = $null
foreach ($ch in $propsEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq $propName) { $existing = $ch; break }
}
if ($existing) {
# InsertBefore+RemoveChild сохраняет ведущий/хвостовой whitespace позиции existing
# (InsertAfter+Remove-NodeWithWhitespace склеил бы: удаляет ведущий ws как отдельный узел).
$propsEl.InsertBefore($newNodes[0], $existing) | Out-Null
$propsEl.RemoveChild($existing) | Out-Null
} else {
Insert-PropertyInOrder $propsEl $newNodes[0] $script:attrPropOrder $propName
}
return $true
}
function Find-PropertyElement([string]$propName) {
foreach ($child in $script:propertiesEl.ChildNodes) {
if ($child.NodeType -eq 'Element' -and $child.LocalName -eq $propName) {
+38 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# meta-edit v1.12 — Edit existing 1C metadata object XML (inline mode + complex properties + TS attribute ops + modify-ts + create-if-missing свойств)
# meta-edit v1.13 — Edit existing 1C metadata object XML (inline + complex props + TS ops + modify-ts + create-if-missing + structural attr props Format/EditFormat/ToolTip/ChoiceForm)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -2089,6 +2089,23 @@ def modify_child_elements(modify_def, child_type):
info(f"Changed synonym of {xml_tag} '{elem_name}': {change_value}")
modify_count += 1
elif change_prop == "Format":
if set_attr_property_element(props_el, "Format", build_mltext_xml(get_child_indent(props_el), "Format", str(change_value))):
info(f"Set {xml_tag} '{elem_name}'.Format")
modify_count += 1
elif change_prop == "EditFormat":
if set_attr_property_element(props_el, "EditFormat", build_mltext_xml(get_child_indent(props_el), "EditFormat", str(change_value))):
info(f"Set {xml_tag} '{elem_name}'.EditFormat")
modify_count += 1
elif change_prop == "ToolTip":
if set_attr_property_element(props_el, "ToolTip", build_mltext_xml(get_child_indent(props_el), "ToolTip", str(change_value))):
info(f"Set {xml_tag} '{elem_name}'.ToolTip")
modify_count += 1
elif change_prop == "ChoiceForm":
if set_attr_property_element(props_el, "ChoiceForm", f"<ChoiceForm>{esc_xml(str(change_value))}</ChoiceForm>"):
info(f"Set {xml_tag} '{elem_name}'.ChoiceForm")
modify_count += 1
else:
# Scalar property change (Indexing, FillChecking, Use, etc.)
scalar_el = None
@@ -2213,6 +2230,26 @@ def insert_property_in_order(props_el, new_node, order_array, prop_name):
insert_before_element(props_el, new_node, ref_node, child_indent)
def set_attr_property_element(props_el, prop_name, fragment_xml):
"""Заменить существующий элемент свойства реквизита новым фрагментом, либо создать в позиции."""
new_nodes = import_fragment(fragment_xml)
if not new_nodes:
return False
existing = None
for ch in props_el:
if localname(ch) == prop_name:
existing = ch
break
if existing is not None:
idx = list(props_el).index(existing)
new_nodes[0].tail = existing.tail
props_el.insert(idx + 1, new_nodes[0])
remove_node_with_whitespace(existing)
else:
insert_property_in_order(props_el, new_nodes[0], attr_prop_order, prop_name)
return True
def find_property_element(prop_name):
for child in properties_el:
if localname(child) == prop_name: