From a9e59265dd3cbdcdb4ad2b19b37584626ae63a33 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Mon, 9 Feb 2026 14:40:23 +0300 Subject: [PATCH] Fix ID scanning in form-add and title emission in form-compile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit form-add: Scan column IDs (same pool as attribute IDs) to prevent duplicate ID collisions. Use XPath .//*[@id] instead of ChildItems recursion to capture companion element IDs (ExtendedTooltip, ContextMenu). form-compile: Extract title from properties and route through Emit-MLText instead of generic Emit-Properties, which produced plain text rejected by 1C XDTO schema. Found during E2E testing of full pipeline (epf-init → form-compile → form-add → epf-build). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --- .claude/skills/form-add/scripts/form-add.ps1 | 44 +++++++++---------- .../form-compile/scripts/form-compile.ps1 | 24 +++++++--- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/.claude/skills/form-add/scripts/form-add.ps1 b/.claude/skills/form-add/scripts/form-add.ps1 index 7f73b800..53a0527c 100644 --- a/.claude/skills/form-add/scripts/form-add.ps1 +++ b/.claude/skills/form-add/scripts/form-add.ps1 @@ -63,37 +63,37 @@ $script:nextElemId = 0 $script:nextAttrId = 0 $script:nextCmdId = 0 -function Scan-ElementIds($node) { - foreach ($child in $node.ChildNodes) { - if ($child.NodeType -ne 'Element') { continue } - $id = $child.GetAttribute("id") - if ($id -and $id -ne "" -and $id -ne "-1") { - try { - $intId = [int]$id - if ($intId -gt $script:nextElemId) { $script:nextElemId = $intId } - } catch {} +# Scan ALL element IDs via XPath (includes companions like ExtendedTooltip, ContextMenu) +$rootCI = $root.SelectSingleNode("f:ChildItems", $nsMgr) +if ($rootCI) { + foreach ($elem in $rootCI.SelectNodes(".//*[@id]")) { + $id = $elem.GetAttribute("id") + if ($id -and $id -ne "-1") { + try { $intId = [int]$id; if ($intId -gt $script:nextElemId) { $script:nextElemId = $intId } } catch {} } - $ci = $child.SelectSingleNode("f:ChildItems", $nsMgr) - if ($ci) { Scan-ElementIds $ci } + } +} +$acb = $root.SelectSingleNode("f:AutoCommandBar", $nsMgr) +if ($acb) { + $id = $acb.GetAttribute("id") + if ($id -and $id -ne "-1") { + try { $intId = [int]$id; if ($intId -gt $script:nextElemId) { $script:nextElemId = $intId } } catch {} } } -$rootCI = $root.SelectSingleNode("f:ChildItems", $nsMgr) -if ($rootCI) { Scan-ElementIds $rootCI } - -# Also scan AutoCommandBar children -$acb = $root.SelectSingleNode("f:AutoCommandBar", $nsMgr) -if ($acb) { - $acbCI = $acb.SelectSingleNode("f:ChildItems", $nsMgr) - if ($acbCI) { Scan-ElementIds $acbCI } -} - -# Scan attribute IDs +# Scan attribute IDs (including column IDs — same pool) foreach ($attr in $root.SelectNodes("f:Attributes/f:Attribute", $nsMgr)) { $id = $attr.GetAttribute("id") if ($id) { try { $intId = [int]$id; if ($intId -gt $script:nextAttrId) { $script:nextAttrId = $intId } } catch {} } + # Column IDs are in the same pool as attribute IDs + foreach ($col in $attr.SelectNodes("f:Columns/f:Column", $nsMgr)) { + $colId = $col.GetAttribute("id") + if ($colId) { + try { $intColId = [int]$colId; if ($intColId -gt $script:nextAttrId) { $script:nextAttrId = $intColId } } catch {} + } + } } # Scan command IDs diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index c10d1acf..bb5bb426 100644 --- a/.claude/skills/form-compile/scripts/form-compile.ps1 +++ b/.claude/skills/form-compile/scripts/form-compile.ps1 @@ -978,13 +978,27 @@ $script:nextId = 1 X '<?xml version="1.0" encoding="UTF-8"?>' X '<Form xmlns="http://v8.1c.ru/8.3/xcf/logform" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core" xmlns:dcssch="http://v8.1c.ru/8.1/data-composition-system/schema" xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings" 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: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">' -# 12a. Title -if ($def.title) { - Emit-MLText -tag "Title" -text "$($def.title)" -indent "`t" +# 12a. Title (from def.title or properties.title — must be multilingual XML) +$formTitle = $def.title +if (-not $formTitle -and $def.properties -and $def.properties.title) { + $formTitle = $def.properties.title +} +if ($formTitle) { + Emit-MLText -tag "Title" -text "$formTitle" -indent "`t" } -# 12b. Properties -Emit-Properties -props $def.properties -indent "`t" +# 12b. Properties (skip 'title' — handled above as multilingual) +if ($def.properties) { + $propsClone = New-Object PSObject + foreach ($p in $def.properties.PSObject.Properties) { + if ($p.Name -ne "title") { + $propsClone | Add-Member -NotePropertyName $p.Name -NotePropertyValue $p.Value + } + } + Emit-Properties -props $propsClone -indent "`t" +} else { + Emit-Properties -props $null -indent "`t" +} # 12c. CommandSet (excluded commands) if ($def.excludedCommands -and $def.excludedCommands.Count -gt 0) {