mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-18 01:00:24 +03:00
fix(19 навыков): единая финализация XML — стиль исходника и корректный CDATA (#57)
Три остатка волны #57, все в одной точке — блоке записи XML. 1. Порты расходились по EOL. PS гонял документ через XmlWriter с дефолтным NewLineHandling.Replace и принудительно переводил весь файл в CRLF, а py сохранял стиль исходника: role-compile на LF-ном Configuration.xml давал 10311 байт против 10062. Ещё в пяти навыках None стоял, но финальной нормализации не было, и на LF-исходнике выходил смешанный EOL (meta-edit: 40 CRLF + 136 одиночных LF) — та же форма, что у исходного дефекта #57. Приведено к форме cf-edit.ps1: None + канонизация к LF + целевой перевод строки (стиль файла-назначения, для создаваемого файла — канон CRLF). Replace не годится как замена: он превращает переводы строк внутри значений атрибутов в . 2. Гард `if (-notmatch CDATA)` не обрабатывал CDATA, а отказывался от канона во всём файле — то есть деградировал до «не сделал ничего». Заменён альтернацией: участки CDATA и комментариев возвращаются как есть, замена идёт только вне них. На реальных данных поведение не меняется — в корпусе из 476 942 XML нет ни одного CDATA и ни одного комментария. 3. py: три реализации одного правила детекта EOL сведены к одной. Мажоритарное правило в role-compile/subsystem-compile давало ДРУГОЙ ответ на смешанном входе. Дефолты _finalize_xml_bytes для нового файла приведены к канону (UTF-8, CRLF, без хвостового перевода); meta-edit срезает хвост в обеих ветках, а не только при создании файла. Попутно, найдено байтовой сверкой портов: - py вставлял <Role>/<Form>/<Subsystem> с пятью табами вместо трёх — подстановка по голому </ChildObjects> удваивала отступ строки; снэпшоты этого не видели, так как схлопывают пробелы между тегами; - py-порты xdto-* писали XML-декларацию одинарными кавычками (так отдаёт lxml), платформа и PS пишут двойные. Регресс: runner 647/647 ps1, 644/647 py (3 skipped), дрейфа снэпшотов нет. Корпусный раундтрип метаданных: 4897 объектов, match 100%, совпадает с эталонами захода #57. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
750ba3bb13
commit
3ef0d74158
@@ -1,4 +1,4 @@
|
||||
# role-compile v1.15 — Compile 1C role from JSON
|
||||
# role-compile v1.16 — Compile 1C role from JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -856,6 +856,7 @@ if (Test-Path $configXmlPath) {
|
||||
$cfgSettings = New-Object System.Xml.XmlWriterSettings
|
||||
$cfgSettings.Encoding = New-Object System.Text.UTF8Encoding($true)
|
||||
$cfgSettings.Indent = $false
|
||||
$cfgSettings.NewLineHandling = [System.Xml.NewLineHandling]::None
|
||||
# Через MemoryStream, а не прямо в файл: нужен шаг пост-обработки строки.
|
||||
$memStream = New-Object System.IO.MemoryStream
|
||||
$writer = [System.Xml.XmlWriter]::Create($memStream, $cfgSettings)
|
||||
@@ -866,10 +867,14 @@ if (Test-Path $configXmlPath) {
|
||||
$memStream.Close()
|
||||
if ($cfgText.Length -gt 0 -and $cfgText[0] -eq [char]0xFEFF) { $cfgText = $cfgText.Substring(1) }
|
||||
$cfgText = $cfgText.Replace('encoding="utf-8"', 'encoding="UTF-8"')
|
||||
# Пустой элемент: XmlWriter отдаёт `<a />`, Конфигуратор пишет `<a/>`. Гард на
|
||||
# CDATA/комментарии: только там `>` не экранируется, и ` />` может быть
|
||||
# содержимым, а не концом тега.
|
||||
if ($cfgText -notmatch '<!\[CDATA\[|<!--') { $cfgText = [regex]::Replace($cfgText, '(?<=\S) />', '/>') }
|
||||
# Пустой элемент: XmlWriter отдаёт `<a />`, Конфигуратор пишет `<a/>`. Внутри
|
||||
# CDATA/комментария ` />` может быть содержимым (там `>` не экранируется),
|
||||
# поэтому они идут первыми ветками альтернации и возвращаются как есть.
|
||||
$cfgText = [regex]::Replace($cfgText, '(?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 $configXmlPath) -and ([System.IO.File]::ReadAllText($configXmlPath) -notmatch "`r`n")) { "`n" } else { "`r`n" }
|
||||
$cfgText = ($cfgText -replace "`r`n", "`n") -replace "`n", $targetEol
|
||||
[System.IO.File]::WriteAllText($configXmlPath, $cfgText, (New-Object System.Text.UTF8Encoding($true)))
|
||||
|
||||
$regResult = "added"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# role-compile v1.15 — Compile 1C role from JSON
|
||||
# role-compile v1.16 — Compile 1C role from JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import json
|
||||
@@ -206,8 +206,10 @@ def detect_format_version(d):
|
||||
def detect_eol(text):
|
||||
# Перевод строки ВСТАВКИ берём из самого файла: канон CRLF относится к файлам,
|
||||
# которые мы создаём, а правка существующего сохраняет его стиль (#44/#46/#47).
|
||||
crlf = text.count('\r\n')
|
||||
return '\r\n' if crlf and crlf >= text.count('\n') - crlf else '\n'
|
||||
# Семантика та же, что у _detect_xml_style в остальных портах: есть CRLF → CRLF.
|
||||
# Мажоритарное правило здесь было расхождением — на смешанном входе оно давало
|
||||
# другой ответ, чем канон, при том же назначении.
|
||||
return '\r\n' if '\r\n' in text else '\n'
|
||||
|
||||
def esc_xml(s):
|
||||
"""Экранирование ТЕКСТА элемента: только & < > . Кавычки платформа в тексте не экранирует
|
||||
@@ -820,7 +822,12 @@ def main():
|
||||
raw_text = raw_text[:insert_pos] + eol + f'\t\t\t{new_role_tag}' + raw_text[insert_pos:]
|
||||
else:
|
||||
# No existing roles — insert before </ChildObjects>
|
||||
raw_text = raw_text.replace('</ChildObjects>', f'\t\t\t{new_role_tag}' + eol + '\t\t</ChildObjects>')
|
||||
# Отступ вставки берём у закрывающего тега +1 уровень: подстановка
|
||||
# по голому '</ChildObjects>' удваивала бы уже присутствующий отступ
|
||||
# строки (получалось 5 табов вместо 3 — PS-порт через DOM даёт 3).
|
||||
raw_text = re.sub(r'([ \t]*)</ChildObjects>',
|
||||
lambda m: m.group(1) + '\t' + new_role_tag + eol + m.group(1) + '</ChildObjects>',
|
||||
raw_text, count=1)
|
||||
|
||||
write_utf8_bom(config_xml_path, raw_text)
|
||||
reg_result = 'added'
|
||||
|
||||
Reference in New Issue
Block a user