mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-07 10:40:52 +03:00
feat(mxl-compile,mxl-decompile): безымянные блоки и области координатами
Инкремент A кампании mxl-roundtrip. Блочная форма DSL не выражала больше половины корпуса: у 34% макетов ERP есть строки вне именованных областей, у 21% нет ни одной области типа Rows. Декомпилятор такие строки терял, а на макетах целиком из Rectangle отдавал areas: [] — компилятор отвечал "Required field 'areas' is missing". На пилоте из 40 макетов это 10 отказов из 26. Что сделано: - имя у блока стало необязательным. Блок без имени — просто кусок сетки; именованную область он не создаёт. Отдельный «плоский режим» не нужен: макет без выразимых блоков это один безымянный блок; - namedAreas — именованные области координатами, для всего, что блоком не ложится (не-Rows и пересекающиеся). Тип области НЕ указывается: он выводится из заданных осей, ровно как в ТабличныйДокумент.Область() — только строки дают полосу строк, только колонки полосу колонок, обе оси прямоугольник. Так нельзя написать противоречие вроде type: Rows с колоночными координатами; - диапазон записывается уже существующей грамматикой DSL (как ключи columnWidths): число или "N-M". Список через запятую запрещён — область непрерывна, платформа разрывную не хранит; - прощающим вводом принимается платформенный адрес "R1C1:R2C2" и правило «0 значит 1»; в документацию не вынесено; - декомпилятор перестал пропускать области не-Rows (там стоял безусловный continue) и режет сетку на блоки детерминированно: непересекающиеся Rows задают границы, дыры становятся безымянными блоками, остальное уходит в namedAreas. Отдельно: именованные элементы теперь эмитятся отсортированными по имени. Платформа хранит их именно так — на выборке 541 макета с несколькими элементами иного порядка нет ни разу. Сортировка ординальная и регистронезависимая; Sort-Object по умолчанию сортирует по текущей культуре и на кириллице дал бы другой порядок. Отсюда дрейф 13 снэпшотов — чистая перестановка, диффы симметричны, число элементов не изменилось. На пилоте отказы areas: [] закрыты полностью (10 → 0), цикл переживают 24 макета вместо 14. Оставшиеся 16 отказов — колоночные раскладки, это инкремент B. Правка на ps1, зазеркалена в py; вывод портов и в компиляции, и в декомпиляции совпадает байт в байт. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f6a478c85c
commit
720ea05325
@@ -1,4 +1,4 @@
|
||||
# mxl-decompile v1.3 — Decompile 1C spreadsheet to JSON
|
||||
# mxl-decompile v1.4 — Decompile 1C spreadsheet to JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -161,19 +161,29 @@ foreach ($mNode in $root.SelectNodes("d:merge", $ns)) {
|
||||
|
||||
# --- 7. Extract named items ---
|
||||
|
||||
# Захватываем области ВСЕХ типов. Раньше здесь стоял `if ($areaType -ne "Rows") { continue }`,
|
||||
# из-за чего терялись Rectangle и Columns — а они есть у 61% макетов корпуса.
|
||||
$namedAreas = @()
|
||||
foreach ($niNode in $root.SelectNodes("d:namedItem", $ns)) {
|
||||
$xsiType = $niNode.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
if ($xsiType -ne "NamedItemCells") { continue }
|
||||
|
||||
$areaNode = $niNode.SelectSingleNode("d:area", $ns)
|
||||
$areaType = $areaNode.SelectSingleNode("d:type", $ns).InnerText
|
||||
if ($areaType -ne "Rows") { continue }
|
||||
if (-not $areaNode) { continue }
|
||||
$getCoord = {
|
||||
param([string]$tag)
|
||||
$n = $areaNode.SelectSingleNode("d:$tag", $ns)
|
||||
if ($n) { return [int]$n.InnerText }
|
||||
return -1
|
||||
}
|
||||
|
||||
$namedAreas += @{
|
||||
Name = $niNode.SelectSingleNode("d:name", $ns).InnerText
|
||||
BeginRow = [int]$areaNode.SelectSingleNode("d:beginRow", $ns).InnerText
|
||||
EndRow = [int]$areaNode.SelectSingleNode("d:endRow", $ns).InnerText
|
||||
Type = $areaNode.SelectSingleNode("d:type", $ns).InnerText
|
||||
BeginRow = & $getCoord 'beginRow'
|
||||
EndRow = & $getCoord 'endRow'
|
||||
BeginCol = & $getCoord 'beginColumn'
|
||||
EndCol = & $getCoord 'endColumn'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,9 +444,50 @@ function Get-StyleName {
|
||||
|
||||
# --- 12. Build areas ---
|
||||
|
||||
# Сетка нарезается на блоки: непересекающиеся области типа Rows задают границы, строки вне
|
||||
# них становятся БЕЗЫМЯННЫМИ блоками. Раньше строки вне областей просто терялись — в корпусе
|
||||
# такие дыры у 34% макетов, а макетов вовсе без Rows-областей 21%.
|
||||
# Всё, что блоком не выражается (области не-Rows и пересекающиеся Rows), уходит в namedAreas
|
||||
# координатами. Правило детерминированное — иначе раундтрип поехал бы.
|
||||
|
||||
$maxRowIdx = -1
|
||||
foreach ($k in $rowData.Keys) { if ([int]$k -gt $maxRowIdx) { $maxRowIdx = [int]$k } }
|
||||
|
||||
$blockAreas = @()
|
||||
$overlayAreas = @()
|
||||
$claimed = @{} # строка → занята блоком
|
||||
foreach ($a in @($namedAreas | Sort-Object @{ Expression = { $_.BeginRow } }, @{ Expression = { $_.EndRow } })) {
|
||||
$fitsBlock = ($a.Type -eq 'Rows' -and $a.BeginRow -ge 0 -and $a.EndRow -ge $a.BeginRow)
|
||||
if ($fitsBlock) {
|
||||
for ($r = $a.BeginRow; $r -le $a.EndRow; $r++) {
|
||||
if ($claimed.ContainsKey($r)) { $fitsBlock = $false; break }
|
||||
}
|
||||
}
|
||||
if ($fitsBlock) {
|
||||
for ($r = $a.BeginRow; $r -le $a.EndRow; $r++) { $claimed[$r] = $true }
|
||||
$blockAreas += $a
|
||||
} else {
|
||||
$overlayAreas += $a
|
||||
}
|
||||
}
|
||||
|
||||
# Блоки в порядке строк + безымянные заполнители дыр.
|
||||
$blocks = @()
|
||||
$cursor = 0
|
||||
foreach ($a in @($blockAreas | Sort-Object @{ Expression = { $_.BeginRow } })) {
|
||||
if ($a.BeginRow -gt $cursor) {
|
||||
$blocks += @{ Name = $null; BeginRow = $cursor; EndRow = $a.BeginRow - 1 }
|
||||
}
|
||||
$blocks += @{ Name = $a.Name; BeginRow = $a.BeginRow; EndRow = $a.EndRow }
|
||||
$cursor = $a.EndRow + 1
|
||||
}
|
||||
if ($cursor -le $maxRowIdx) {
|
||||
$blocks += @{ Name = $null; BeginRow = $cursor; EndRow = $maxRowIdx }
|
||||
}
|
||||
|
||||
$dslAreas = @()
|
||||
|
||||
foreach ($area in $namedAreas) {
|
||||
foreach ($area in $blocks) {
|
||||
$areaRows = @()
|
||||
|
||||
for ($globalRow = $area.BeginRow; $globalRow -le $area.EndRow; $globalRow++) {
|
||||
@@ -557,10 +608,11 @@ foreach ($area in $namedAreas) {
|
||||
else { $compressedRows += [ordered]@{ empty = $emptyRun } }
|
||||
}
|
||||
|
||||
$dslAreas += [ordered]@{
|
||||
name = $area.Name
|
||||
rows = [array]$compressedRows
|
||||
}
|
||||
$dslBlock = [ordered]@{}
|
||||
# Безымянный блок — просто кусок сетки, ключ name у него не пишем.
|
||||
if (-not [string]::IsNullOrEmpty($area.Name)) { $dslBlock["name"] = $area.Name }
|
||||
$dslBlock["rows"] = [array]$compressedRows
|
||||
$dslAreas += $dslBlock
|
||||
}
|
||||
|
||||
# --- 13. Compress columnWidths ---
|
||||
@@ -632,6 +684,23 @@ $result["fonts"] = $fontsOut
|
||||
$result["styles"] = $styleDefs
|
||||
$result["areas"] = [array]$dslAreas
|
||||
|
||||
# Именованные области, не выразимые блоком, — координатами. Тип не пишем: он выводится
|
||||
# из указанных осей (как в ТабличныйДокумент.Область()). DSL 1-based, XML 0-based.
|
||||
if ($overlayAreas.Count -gt 0) {
|
||||
$naOut = @()
|
||||
foreach ($a in $overlayAreas) {
|
||||
$entry = [ordered]@{ name = $a.Name }
|
||||
if ($a.BeginRow -ge 0) {
|
||||
$entry["rows"] = if ($a.EndRow -gt $a.BeginRow) { "$($a.BeginRow + 1)-$($a.EndRow + 1)" } else { $a.BeginRow + 1 }
|
||||
}
|
||||
if ($a.BeginCol -ge 0) {
|
||||
$entry["cols"] = if ($a.EndCol -gt $a.BeginCol) { "$($a.BeginCol + 1)-$($a.EndCol + 1)" } else { $a.BeginCol + 1 }
|
||||
}
|
||||
$naOut += $entry
|
||||
}
|
||||
$result["namedAreas"] = [array]$naOut
|
||||
}
|
||||
|
||||
# --- 16. Convert to JSON ---
|
||||
|
||||
# Custom JSON serializer — компактный, 2-пробельный indent, массивы примитивов inline.
|
||||
|
||||
Reference in New Issue
Block a user