fix(subsystem-edit): write stub XML on add-child operation

Do-AddChild / do_add_child added `<Subsystem>Name</Subsystem>` to the
parent's `<ChildObjects>`, but never wrote the corresponding
`Subsystems/{Parent}/Subsystems/{Name}.xml` file. Same silent-drop
pattern that bit subsystem-compile (aa93031): platform used to swallow
the missing-file reference, `-StrictLog` now surfaces it as "Файл
объекта не существует" and fails add-child on load.

Both ports now mirror the subsystem-compile fix:
- Write-ChildSubsystemStub / write_child_subsystem_stub helpers
  duplicated from subsystem-compile (per memory rule "skills are
  autonomous, duplication acceptable")
- format_version read from loaded XmlDoc root (no need to walk up
  to Configuration.xml — we already have the parent XML in memory)
- Stub creation guarded by Test-Path / os.path.exists so a pre-existing
  real child file is never clobbered

Bumped subsystem-edit.ps1 v1.1→v1.2 and subsystem-edit.py v1.1→v1.2.

Verification:
- verify-snapshots --skill subsystem-edit: 3/4 → 4/4
- runner --filter subsystem-edit (PS1): 4/4
- runner --filter subsystem-edit --runtime python: 4/4 (dual-port drift clean)

With this landed P1 from debug/snapshot-verify/NEXT-STEPS.md is fully
closed: subsystem-compile 7/7, subsystem-edit 4/4, interface-edit 4/4,
role-compile 8/8, meta-compile 30/30.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-04-11 18:49:40 +03:00
parent aa93031a3f
commit 6805b9da02
3 changed files with 138 additions and 2 deletions
@@ -1,4 +1,4 @@
# subsystem-edit v1.1 — Edit existing 1C subsystem XML
# subsystem-edit v1.2 — Edit existing 1C subsystem XML
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)][string]$SubsystemPath,
@@ -119,12 +119,17 @@ if (-not (Test-Path $SubsystemPath)) {
}
if (-not (Test-Path $SubsystemPath)) { Write-Error "File not found: $SubsystemPath"; exit 1 }
$resolvedPath = (Resolve-Path $SubsystemPath).Path
$script:resolvedPath = $resolvedPath
# --- Load XML with PreserveWhitespace ---
$script:xmlDoc = New-Object System.Xml.XmlDocument
$script:xmlDoc.PreserveWhitespace = $true
$script:xmlDoc.Load($resolvedPath)
$script:formatVersion = $script:xmlDoc.DocumentElement.GetAttribute("version")
if (-not $script:formatVersion) { $script:formatVersion = "2.17" }
$script:utf8Bom = New-Object System.Text.UTF8Encoding($true)
$script:addCount = 0
$script:removeCount = 0
$script:modifyCount = 0
@@ -164,6 +169,37 @@ foreach ($child in $script:propsEl.ChildNodes) {
Info "Subsystem: $($script:objName)"
# --- XML manipulation helpers (from meta-edit pattern) ---
function Esc-Xml([string]$s) {
return $s.Replace('&','&amp;').Replace('<','&lt;').Replace('>','&gt;').Replace('"','&quot;')
}
function New-Guid-String {
return [System.Guid]::NewGuid().ToString()
}
function Write-ChildSubsystemStub([string]$childPath, [string]$childName, [string]$formatVersion, [System.Text.Encoding]$utf8Bom) {
$childUuid = New-Guid-String
$sb = New-Object System.Text.StringBuilder 2048
[void]$sb.AppendLine('<?xml version="1.0" encoding="UTF-8"?>')
[void]$sb.AppendLine("<MetaDataObject xmlns=`"http://v8.1c.ru/8.3/MDClasses`" xmlns:app=`"http://v8.1c.ru/8.2/managed-application/core`" xmlns:cfg=`"http://v8.1c.ru/8.1/data/enterprise/current-config`" xmlns:cmi=`"http://v8.1c.ru/8.2/managed-application/cmi`" xmlns:ent=`"http://v8.1c.ru/8.1/data/enterprise`" xmlns:lf=`"http://v8.1c.ru/8.2/managed-application/logform`" xmlns:style=`"http://v8.1c.ru/8.1/data/ui/style`" xmlns:sys=`"http://v8.1c.ru/8.1/data/ui/fonts/system`" xmlns:v8=`"http://v8.1c.ru/8.1/data/core`" xmlns:v8ui=`"http://v8.1c.ru/8.1/data/ui`" xmlns:web=`"http://v8.1c.ru/8.1/data/ui/colors/web`" xmlns:win=`"http://v8.1c.ru/8.1/data/ui/colors/windows`" xmlns:xen=`"http://v8.1c.ru/8.3/xcf/enums`" xmlns:xpr=`"http://v8.1c.ru/8.3/xcf/predef`" xmlns:xr=`"http://v8.1c.ru/8.3/xcf/readable`" xmlns:xs=`"http://www.w3.org/2001/XMLSchema`" xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`" version=`"$formatVersion`">")
[void]$sb.AppendLine("`t<Subsystem uuid=`"$childUuid`">")
[void]$sb.AppendLine("`t`t<Properties>")
[void]$sb.AppendLine("`t`t`t<Name>$(Esc-Xml $childName)</Name>")
[void]$sb.AppendLine("`t`t`t<Synonym/>")
[void]$sb.AppendLine("`t`t`t<Comment/>")
[void]$sb.AppendLine("`t`t`t<IncludeHelpInContents>true</IncludeHelpInContents>")
[void]$sb.AppendLine("`t`t`t<IncludeInCommandInterface>true</IncludeInCommandInterface>")
[void]$sb.AppendLine("`t`t`t<UseOneCommand>false</UseOneCommand>")
[void]$sb.AppendLine("`t`t`t<Explanation/>")
[void]$sb.AppendLine("`t`t`t<Picture/>")
[void]$sb.AppendLine("`t`t`t<Content/>")
[void]$sb.AppendLine("`t`t</Properties>")
[void]$sb.AppendLine("`t`t<ChildObjects/>")
[void]$sb.AppendLine("`t</Subsystem>")
[void]$sb.AppendLine('</MetaDataObject>')
[System.IO.File]::WriteAllText($childPath, $sb.ToString(), $utf8Bom)
}
function Import-Fragment([string]$xmlString) {
$wrapper = "<_W xmlns=`"$($script:mdNs)`" xmlns:xsi=`"$($script:xsiNs)`" xmlns:v8=`"$($script:v8Ns)`" xmlns:xr=`"$($script:xrNs)`" xmlns:xs=`"http://www.w3.org/2001/XMLSchema`">$xmlString</_W>"
$frag = New-Object System.Xml.XmlDocument
@@ -337,6 +373,20 @@ function Do-AddChild([string]$childName) {
Insert-BeforeElement $script:childObjsEl $newEl $null $childIndent
$script:addCount++
Info "Added child subsystem: $childName"
# Write stub XML for the new child if it doesn't exist yet
$parentDir = [System.IO.Path]::GetDirectoryName($script:resolvedPath)
$parentBaseName = [System.IO.Path]::GetFileNameWithoutExtension($script:resolvedPath)
$childSubsDir = Join-Path (Join-Path $parentDir $parentBaseName) "Subsystems"
if (-not (Test-Path $childSubsDir)) {
New-Item -ItemType Directory -Path $childSubsDir -Force | Out-Null
Info "Created directory: $childSubsDir"
}
$childXml = Join-Path $childSubsDir "$childName.xml"
if (-not (Test-Path $childXml)) {
Write-ChildSubsystemStub $childXml $childName $script:formatVersion $script:utf8Bom
Info "Created stub: $childXml"
}
}
function Do-RemoveChild([string]$childName) {
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# subsystem-edit v1.1 — Edit existing 1C subsystem XML
# subsystem-edit v1.2 — Edit existing 1C subsystem XML
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -7,8 +7,64 @@ import json
import os
import subprocess
import sys
import uuid
from lxml import etree
def new_uuid():
return str(uuid.uuid4())
def esc_xml(s):
return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')
def write_utf8_bom(path, content):
with open(path, 'w', encoding='utf-8-sig', newline='') as f:
f.write(content)
def write_child_subsystem_stub(child_path, child_name, format_version):
child_uuid = new_uuid()
lines = []
lines.append('<?xml version="1.0" encoding="UTF-8"?>')
lines.append(
'<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" '
'xmlns:app="http://v8.1c.ru/8.2/managed-application/core" '
'xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" '
'xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" '
'xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" '
'xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" '
'xmlns:style="http://v8.1c.ru/8.1/data/ui/style" '
'xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" '
'xmlns:v8="http://v8.1c.ru/8.1/data/core" '
'xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" '
'xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" '
'xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" '
'xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" '
'xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" '
'xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" '
'xmlns:xs="http://www.w3.org/2001/XMLSchema" '
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
f'version="{format_version}">'
)
lines.append(f'\t<Subsystem uuid="{child_uuid}">')
lines.append('\t\t<Properties>')
lines.append(f'\t\t\t<Name>{esc_xml(child_name)}</Name>')
lines.append('\t\t\t<Synonym/>')
lines.append('\t\t\t<Comment/>')
lines.append('\t\t\t<IncludeHelpInContents>true</IncludeHelpInContents>')
lines.append('\t\t\t<IncludeInCommandInterface>true</IncludeInCommandInterface>')
lines.append('\t\t\t<UseOneCommand>false</UseOneCommand>')
lines.append('\t\t\t<Explanation/>')
lines.append('\t\t\t<Picture/>')
lines.append('\t\t\t<Content/>')
lines.append('\t\t</Properties>')
lines.append('\t\t<ChildObjects/>')
lines.append('\t</Subsystem>')
lines.append('</MetaDataObject>')
write_utf8_bom(child_path, '\n'.join(lines) + '\n')
MD_NS = "http://v8.1c.ru/8.3/MDClasses"
XR_NS = "http://v8.1c.ru/8.3/xcf/readable"
XSI_NS = "http://www.w3.org/2001/XMLSchema-instance"
@@ -264,6 +320,7 @@ def main():
xml_parser = etree.XMLParser(remove_blank_text=False)
tree = etree.parse(resolved_path, xml_parser)
xml_root = tree.getroot()
format_version = xml_root.get("version") or "2.17"
add_count = 0
remove_count = 0
@@ -381,6 +438,18 @@ def main():
add_count += 1
info(f"Added child subsystem: {child_name}")
# Write stub XML for the new child if it doesn't exist yet
parent_dir = os.path.dirname(resolved_path)
parent_base_name = os.path.splitext(os.path.basename(resolved_path))[0]
child_subs_dir = os.path.join(parent_dir, parent_base_name, 'Subsystems')
if not os.path.exists(child_subs_dir):
os.makedirs(child_subs_dir, exist_ok=True)
info(f"Created directory: {child_subs_dir}")
child_xml = os.path.join(child_subs_dir, f'{child_name}.xml')
if not os.path.exists(child_xml):
write_child_subsystem_stub(child_xml, child_name, format_version)
info(f"Created stub: {child_xml}")
def do_remove_child(child_name):
nonlocal remove_count
if child_objs_el is None:
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Subsystem uuid="UUID-001">
<Properties>
<Name>Настройки</Name>
<Synonym/>
<Comment/>
<IncludeHelpInContents>true</IncludeHelpInContents>
<IncludeInCommandInterface>true</IncludeInCommandInterface>
<UseOneCommand>false</UseOneCommand>
<Explanation/>
<Picture/>
<Content/>
</Properties>
<ChildObjects/>
</Subsystem>
</MetaDataObject>