fix(meta-edit): modify-property Type — структурный дескриптор типа, guard от порчи

Корневой modify-property Type у ПВХ/Константы расплющивал структурный <Type>
(<v8:Type> + квалификаторы) в скалярный текст, а meta-validate это пропускал.

meta-edit (v1.21): modify-property Type перестраивает дескриптор через готовый
build_value_type_xml (составной тип, квалификаторы, ref-типы); прочие структурные
свойства с дочерними узлами → ошибка до записи файла вместо тихой порчи.

meta-validate (v1.10): корневой <Type> со скалярным текстом без <v8:Type>/<v8:TypeSet>
теперь ошибка (был false negative).

Порты PS1/PY синхронны. Регрессионные кейсы: modify-property-type-pvh (структурный
Type + ref), error-scalar-root-type (детект порчи).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-19 15:47:59 +03:00
co-authored by Claude Opus 4.8
parent 6318018bc1
commit fbdf07e18a
15 changed files with 691 additions and 4 deletions
@@ -14,6 +14,16 @@
Свойство можно задать, даже если оно ещё не выставлено у объекта (например `FullTextSearch`, `DataHistory`).
Опечатка в имени свойства → ошибка (правка не теряется молча). Допустимы имена свойств соответствующего типа объекта.
### Type — тип значения (Константа, ПВХ)
`Type=...` перестраивает дескриптор типа значения. Значение — тип 1С в том же синтаксисе,
что у реквизитов: составной через `+`, с квалификаторами и ссылочными типами:
```powershell
-Operation modify-property -Value "Type=String(100) + Number(15,2) + CatalogRef.Номенклатура"
```
Структурные свойства (со вложенными узлами) в скалярный текст не превращаются: попытка задать
такое свойство обычным `Ключ=Значение` (кроме `Type`) завершается ошибкой до записи файла.
## Свойства-списки
Свойства, значение которых — список ссылок. Управляются через inline `add-*` / `remove-*` / `set-*` и через JSON `modify.properties`.
+27 -1
View File
@@ -1,4 +1,4 @@
# meta-edit v1.20 — Edit existing 1C metadata object XML (+add-predefined предопределённые Ext/Predefined.xml)
# meta-edit v1.21 — Edit existing 1C metadata object XML (+modify-property Type: структурный дескриптор, guard от порчи)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$DefinitionFile,
@@ -2041,6 +2041,32 @@ function Modify-Properties($propsDef) {
$valueStr = if ($propValue) { "true" } else { "false" }
}
# Structural value-type property (корневой <Type> у Константы, ПВХ) —
# перестроить дескриптор типа через Build-ValueTypeXml (не расплющивать в скаляр)
if ($propName -ceq "Type") {
$typeIndent = Get-ChildIndent $script:propertiesEl
$newTypeXml = Build-ValueTypeXml $typeIndent $valueStr
$newTypeNodes = Import-Fragment $newTypeXml
if ($newTypeNodes.Count -gt 0) {
# ReplaceChild сохраняет whitespace до/после узла на месте (без склейки отступов)
$script:propertiesEl.ReplaceChild($newTypeNodes[0], $propEl) | Out-Null
Info "Modified property: Type = $valueStr"
$script:modifyCount++
}
return
}
# Guard: не расплющивать структурное свойство (с дочерними узлами) в скалярный текст —
# это молча повредит XML. Завершаем ошибкой ДО записи файла.
$hasChildElements = $false
foreach ($ch in $propEl.ChildNodes) {
if ($ch.NodeType -eq 'Element') { $hasChildElements = $true; break }
}
if ($hasChildElements) {
Write-Error "modify-property: свойство '$propName' структурное (содержит дочерние узлы) — установка скалярного текста повредит XML; не поддерживается"
exit 1
}
$propEl.InnerText = $valueStr
Info "Modified property: $propName = $valueStr"
$script:modifyCount++
+22 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# meta-edit v1.20 — Edit existing 1C metadata object XML (+add-predefined предопределённые Ext/Predefined.xml)
# meta-edit v1.21 — Edit existing 1C metadata object XML (+modify-property Type: структурный дескриптор, guard от порчи)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -1915,6 +1915,27 @@ def modify_properties(props_def):
if isinstance(prop_value, bool):
value_str = "true" if prop_value else "false"
# Structural value-type property (корневой <Type> у Константы, ПВХ) —
# перестроить дескриптор типа через build_value_type_xml (не расплющивать в скаляр)
if prop_name == "Type":
type_indent = get_child_indent(properties_el)
new_type_xml = build_value_type_xml(type_indent, value_str)
new_type_nodes = import_fragment(new_type_xml)
if new_type_nodes:
type_idx = list(properties_el).index(prop_el)
new_type_nodes[0].tail = prop_el.tail
properties_el.insert(type_idx + 1, new_type_nodes[0])
remove_node_with_whitespace(prop_el)
info(f"Modified property: Type = {value_str}")
modify_count += 1
continue
# Guard: не расплющивать структурное свойство (с дочерними узлами) в скалярный текст —
# это молча повредит XML. Завершаем ошибкой ДО записи файла.
if len(list(prop_el)) > 0:
print(f"meta-edit: modify-property: свойство '{prop_name}' структурное (содержит дочерние узлы) — установка скалярного текста повредит XML; не поддерживается", file=sys.stderr)
sys.exit(1)
# Set inner text — clear children first, set text
for ch in list(prop_el):
prop_el.remove(ch)
@@ -1,4 +1,4 @@
# meta-validate v1.9 — Validate 1C metadata object structure
# meta-validate v1.10 — Validate 1C metadata object structure (+корневой <Type>: скаляр без структуры = ошибка)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -558,6 +558,26 @@ if ($propsNode) {
}
}
# Корневой <Type> (дескриптор типа значения — Константа, ПВХ) должен быть структурным:
# <v8:Type>/<v8:TypeSet>, а не скалярный текст. Скаляр = повреждённый тип (напр. после
# старого meta-edit modify-property Type). См. issue #42.
$rootTypeEl = $propsNode.SelectSingleNode("md:Type", $ns)
if ($rootTypeEl) {
$v8Types = $rootTypeEl.SelectNodes("v8:Type", $ns)
$v8TypeSets = $rootTypeEl.SelectNodes("v8:TypeSet", $ns)
$scalarText = ""
foreach ($cn in $rootTypeEl.ChildNodes) {
if ($cn.NodeType -eq 'Text' -or $cn.NodeType -eq 'CDATA') {
$t = $cn.Value.Trim()
if ($t) { $scalarText = $t; break }
}
}
if ($v8Types.Count -eq 0 -and $v8TypeSets.Count -eq 0 -and $scalarText) {
Report-Error "4. Property <Type> содержит скалярный текст '$scalarText' без структуры типа (<v8:Type>/<v8:TypeSet>) — повреждённый дескриптор типа значения"
$check4Ok = $false
}
}
if ($check4Ok) {
Report-OK "4. Property values: $enumChecked enum properties checked"
}
@@ -1,4 +1,4 @@
# meta-validate v1.9 — Validate 1C metadata object structure (Python port)
# meta-validate v1.10 — Validate 1C metadata object structure (Python port) (+корневой <Type>: скаляр без структуры = ошибка)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
@@ -555,6 +555,18 @@ if props_node is not None:
check4_ok = False
enum_checked += 1
# Корневой <Type> (дескриптор типа значения — Константа, ПВХ) должен быть структурным:
# <v8:Type>/<v8:TypeSet>, а не скалярный текст. Скаляр = повреждённый тип (напр. после
# старого meta-edit modify-property Type). См. issue #42.
root_type_el = find(props_node, "md:Type")
if root_type_el is not None:
scalar_text = inner_text(root_type_el).strip()
v8_types = find_all(root_type_el, "v8:Type")
v8_type_sets = find_all(root_type_el, "v8:TypeSet")
if len(v8_types) == 0 and len(v8_type_sets) == 0 and scalar_text:
report_error(f"4. Property <Type> содержит скалярный текст '{scalar_text}' без структуры типа (<v8:Type>/<v8:TypeSet>) — повреждённый дескриптор типа значения")
check4_ok = False
if check4_ok:
report_ok(f"4. Property values: {enum_checked} enum properties checked")
else: