mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-02 08:20:49 +03:00
feat(skills): порядок объектов метаданных в ChildObjects
Навыки-создатели дописывали новый объект в конец группы своего вида, а стандарт требует порядка по имени (АПК:1108). Замеры на 8 боевых выгрузках: 103 385 объектов лежат по алфавиту, нарушают его ровно дописки в хвост. Стенд подтвердил, что беспорядок вечен: платформа нормализует порядок ВИДОВ (возвращает канонический), но порядок имён внутри вида не трогает. Настройка newObjectPosition в .v8-project.json (end по умолчанию | byName) — решение проекта, а не вызова: читают её meta-compile, role-compile, xdto-compile, cfe-borrow и cf-edit add-childObject. Компаратор при этом константа, моделирующая дерево Конфигуратора: ключ «ранг+символ» без культурных таблиц, одинаковый в обоих портах на любой ОС. На корпусе он даёт 4 нарушения на 125 088 пар против 2866 у ordinal-сравнения, которым cf-edit и cfe-borrow сортировали до сих пор. Subsystem не упорядочивается автоматически нигде: пока подсистемы не перечислены в <SubsystemsOrder>, порядок дерева задаёт порядок разделов в панели, а платформа этот список сама не заводит. Настройка не чинит накопленное, поэтому cf-edit получил операцию sort-childObjects (вся конфигурация или названные виды). Она переставляет значения узлов, а не узлы, поэтому диф — чистая перестановка строк. Имя вида принимается в любом регистре, во множественном числе и по-русски; неизвестный вид — отказ со списком допустимых. Попутно: - PS-порты создателей переведены с DOM-сериализации на текстовую вставку: на выгрузке не в каноне Конфигуратора они переписывали заголовок без просьбы; - PS-сторона семьи detect_xml_style/finalize_xml_bytes закрыта в cf-edit и cfe-borrow — правка чужого файла наследует его BOM/EOL/заголовок; - xdto-compile присоединён к семье Register-InChildObjects вместо инлайн-копии; - закрыт ложный успех в py subsystem-compile: <ChildObjects /> с пробелом ET разбирает, а текстовые ветки не находили — файл писался без вставки; - cfe-borrow py не импортировал json, из-за чего резолвер молча возвращал end; - cf-edit add-childObject ставил объект в конец блока, за пределы своей группы, когда видов старше в файле не было. Проверки: 906/906 на PowerShell и 903/906 на Python, 10 гардов, верификация эталонов платформой без падений, раундтрип отсортированной конфигурации на 8.3.24 и 8.3.27, сортировка боевой выгрузки ACC (1,4 МБ) и расширения из корпуса. Задачу принёс PR #85; часть кода взята оттуда. Co-Authored-By: Sergei Pleshanov <72200277+Abacadabras@users.noreply.github.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QoAJmoNbgWKobA7JGgN5S3
This commit is contained in:
co-authored by
Sergei Pleshanov
Claude Opus 5
parent
7409bacd47
commit
c7b0dce151
@@ -1,4 +1,4 @@
|
||||
# subsystem-compile v1.30 — Create 1C subsystem from JSON definition
|
||||
# subsystem-compile v1.31 — Create 1C subsystem from JSON definition
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
[CmdletBinding(PositionalBinding=$false)]
|
||||
param(
|
||||
@@ -690,77 +690,32 @@ function Register-InChildObjects([string]$ParentXmlPath, [string]$ParentTag, [st
|
||||
$childObjects = $doc.SelectSingleNode("//md:$ParentTag/md:ChildObjects", $ns)
|
||||
if (-not $childObjects) { return "no-childobj" }
|
||||
|
||||
# Check for self-closing tag
|
||||
$isSelfClosing = (-not $childObjects.HasChildNodes) -or ($childObjects.IsEmpty)
|
||||
|
||||
# Check if already registered
|
||||
foreach ($child in $childObjects.ChildNodes) {
|
||||
if ($child.NodeType -eq 'Element' -and $child.LocalName -eq $ChildTag -and $child.InnerText -eq $ChildName) {
|
||||
return "already"
|
||||
}
|
||||
}
|
||||
|
||||
$newEl = $doc.CreateElement($ChildTag, "http://v8.1c.ru/8.3/MDClasses")
|
||||
$newEl.InnerText = $ChildName
|
||||
# Правка по сырому тексту, зеркально py-порту: сериализация DOM переписала бы файл целиком
|
||||
# (регистр encoding, `<a />` вместо `<a/>`), а текстовая вставка хранит его байт-в-байт.
|
||||
# Правим чужой файл, значит наследуем его стиль (#44/#46/#47). DOM выше — только на чтение.
|
||||
$rawText = [System.IO.File]::ReadAllText($ParentXmlPath, (New-Object System.Text.UTF8Encoding($false)))
|
||||
$eol = if ($rawText.Contains("`r`n")) { "`r`n" } else { "`n" }
|
||||
$entry = "<$ChildTag>$(Esc-XmlText $ChildName)</$ChildTag>"
|
||||
|
||||
if ($isSelfClosing) {
|
||||
# Expand self-closing tag
|
||||
$parentIndent = ""
|
||||
$prev = $childObjects.PreviousSibling
|
||||
if ($prev -and ($prev.NodeType -eq 'Whitespace' -or $prev.NodeType -eq 'SignificantWhitespace')) {
|
||||
if ($prev.Value -match '(\t+)$') { $parentIndent = $Matches[1] }
|
||||
}
|
||||
$childIndent = "$parentIndent`t"
|
||||
$ws1 = $doc.CreateWhitespace("`r`n$childIndent")
|
||||
$ws2 = $doc.CreateWhitespace("`r`n$parentIndent")
|
||||
$childObjects.AppendChild($ws1) | Out-Null
|
||||
$childObjects.AppendChild($newEl) | Out-Null
|
||||
$childObjects.AppendChild($ws2) | Out-Null
|
||||
$empty = [regex]::Match($rawText, '<ChildObjects\s*/>')
|
||||
if ($empty.Success) {
|
||||
$replacement = "<ChildObjects>$eol`t`t`t$entry$eol`t`t</ChildObjects>"
|
||||
$rawText = $rawText.Substring(0, $empty.Index) + $replacement + $rawText.Substring($empty.Index + $empty.Length)
|
||||
} else {
|
||||
# Insert before trailing whitespace
|
||||
$childIndent = "`t`t`t"
|
||||
foreach ($child in $childObjects.ChildNodes) {
|
||||
if ($child.NodeType -eq 'Whitespace' -or $child.NodeType -eq 'SignificantWhitespace') {
|
||||
if ($child.Value -match '^\r?\n(\t+)') { $childIndent = $Matches[1]; break }
|
||||
}
|
||||
}
|
||||
$trailing = $childObjects.LastChild
|
||||
$ws = $doc.CreateWhitespace("`r`n$childIndent")
|
||||
if ($trailing -and ($trailing.NodeType -eq 'Whitespace' -or $trailing.NodeType -eq 'SignificantWhitespace')) {
|
||||
$childObjects.InsertBefore($ws, $trailing) | Out-Null
|
||||
$childObjects.InsertBefore($newEl, $trailing) | Out-Null
|
||||
} else {
|
||||
$childObjects.AppendChild($ws) | Out-Null
|
||||
$childObjects.AppendChild($newEl) | Out-Null
|
||||
}
|
||||
# Отступ вставки берём у закрывающего тега +1 уровень: подстановка по голому
|
||||
# '</ChildObjects>' удваивала бы уже присутствующий отступ строки.
|
||||
$cm = [regex]::Match($rawText, '([ ]*)</ChildObjects>')
|
||||
if (-not $cm.Success) { return "no-childobj" }
|
||||
$rawText = $rawText.Substring(0, $cm.Index) + $cm.Groups[1].Value + "`t" + $entry + $eol + $cm.Groups[1].Value + "</ChildObjects>" + $rawText.Substring($cm.Index + $cm.Length)
|
||||
}
|
||||
|
||||
# Save parent XML
|
||||
$settings = New-Object System.Xml.XmlWriterSettings
|
||||
$settings.Encoding = New-Object System.Text.UTF8Encoding($true)
|
||||
$settings.Indent = $false
|
||||
$settings.NewLineHandling = [System.Xml.NewLineHandling]::None
|
||||
|
||||
$memStream = New-Object System.IO.MemoryStream
|
||||
$writer = [System.Xml.XmlWriter]::Create($memStream, $settings)
|
||||
$doc.Save($writer)
|
||||
$writer.Flush(); $writer.Close()
|
||||
|
||||
$bytes = $memStream.ToArray()
|
||||
$memStream.Close()
|
||||
$text = [System.Text.Encoding]::UTF8.GetString($bytes)
|
||||
if ($text.Length -gt 0 -and $text[0] -eq [char]0xFEFF) { $text = $text.Substring(1) }
|
||||
$text = $text.Replace('encoding="utf-8"', 'encoding="UTF-8"')
|
||||
# Пустой элемент: XmlWriter отдаёт `<a />`, Конфигуратор пишет `<a/>`. Внутри
|
||||
# CDATA/комментария ` />` может быть содержимым (там `>` не экранируется),
|
||||
# поэтому они идут первыми ветками альтернации и возвращаются как есть.
|
||||
$text = [regex]::Replace($text, '(?s)<!\[CDATA\[.*?\]\]>|<!--.*?-->|(?<=\S) />', { param($m) if ($m.Value -eq ' />') { '/>' } else { $m.Value } })
|
||||
# Целевой перевод строки: стиль файла-назначения — правка наследует его (#44/#46/#47),
|
||||
# новый файл получает канон выгрузки CRLF. Зеркало _detect_xml_style в py-порту.
|
||||
$targetEol = if ((Test-Path -LiteralPath $ParentXmlPath) -and ([System.IO.File]::ReadAllText($ParentXmlPath) -notmatch "`r`n")) { "`n" } else { "`r`n" }
|
||||
$text = ($text -replace "`r`n", "`n") -replace "`n", $targetEol
|
||||
[System.IO.File]::WriteAllText($ParentXmlPath, $text, (New-Object System.Text.UTF8Encoding($true)))
|
||||
|
||||
[System.IO.File]::WriteAllText($ParentXmlPath, $rawText, (New-Object System.Text.UTF8Encoding($true)))
|
||||
return "added"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user