mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-21 02:29:42 +03:00
feat(mxl-compile,mxl-decompile): формат самой строки
У строки есть собственный формат: платформа хранит в нём скрытие (17 423 вхождения
в корпусе), шрифт (9 216), фон, выравнивания, защиту. Мы писали туда только высоту,
всё остальное теряли.
Разбор на контролируемом стенде показал, что это два разных случая, а не один.
Оформление, применённое к строке целиком, платформа пишет И строке, И каждой
ячейке (backColor: 13 899 ячеек повторяют против 96). Скрытие — только строке
(24 026 против 62 856). Поэтому одного правила «rowStyle красит ячейки» мало.
Теперь rowStyle — стиль строки: по умолчанию ложится и на строку, и на ячейки,
как это делает платформа. Объектная форма { style, apply } задаёт исключения:
"row" — только строке, "cells" — только ячейкам. Модификатор нужен раундтрипу,
в описании DSL его нет.
Скрытие и высота — собственные свойства строки, ключами рядом: у ячейки таких
свойств не бывает, и в её оформление они не попадают.
На пилоте категория row[].formatIndex упала с 1964 до 201 потерянного факта.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ccbd488d63
commit
ba25aa4a00
@@ -1,4 +1,4 @@
|
||||
# mxl-decompile v1.12 — Decompile 1C spreadsheet to JSON
|
||||
# mxl-decompile v1.13 — Decompile 1C spreadsheet to JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -499,6 +499,30 @@ foreach ($r in $rowData.Values) {
|
||||
}
|
||||
}
|
||||
|
||||
# Оформление строки без её собственных свойств: скрытие уезжает инлайном к height,
|
||||
# поэтому в именованный стиль попадать не должно.
|
||||
function Get-RowStyleFmt {
|
||||
param($fmt)
|
||||
if (-not $fmt) { return $null }
|
||||
$props = Get-StyleProps $fmt
|
||||
$props.Remove('hidden') | Out-Null
|
||||
if ($props.Count -eq 0) { return $null }
|
||||
$reduced = [ordered]@{}
|
||||
foreach ($tag in $fmt.Props.Keys) {
|
||||
if ($tag -cne 'hidden') { $reduced[$tag] = $fmt.Props[$tag] }
|
||||
}
|
||||
return @{ FontIdx = $fmt.FontIdx; Width = 0; Height = 0; FillType = ""; Props = $reduced }
|
||||
}
|
||||
|
||||
# Строка — тоже владелец формата: её оформление становится именованным стилем.
|
||||
foreach ($rd in $rowData.Values) {
|
||||
if ($rd.FormatIdx -le 0) { continue }
|
||||
$rf = Get-RowStyleFmt (Get-Format $rd.FormatIdx)
|
||||
if (-not $rf) { continue }
|
||||
$key = Get-StyleKey $rf
|
||||
if (-not $styleKeys.Contains($key)) { $styleKeys[$key] = $rf }
|
||||
}
|
||||
|
||||
# Колонка — третий владелец формата, её оформление тоже становится именованным стилем.
|
||||
foreach ($cs in $columnSets) {
|
||||
foreach ($fi in $cs.FmtIdx.Values) {
|
||||
@@ -740,11 +764,13 @@ foreach ($area in $blocks) {
|
||||
|
||||
$dslRow = [ordered]@{}
|
||||
|
||||
# Row height
|
||||
if ($rd.FormatIdx -gt 0) {
|
||||
$rowFmt = Get-Format $rd.FormatIdx
|
||||
if ($rowFmt -and $rowFmt.Height -gt 0) { $dslRow["height"] = $rowFmt.Height }
|
||||
}
|
||||
# Формат самой строки: высота и скрытие — её собственные свойства (у ячейки таких
|
||||
# нет), остальное — оформление, оно же может лежать и на ячейках.
|
||||
$rowFmt = if ($rd.FormatIdx -gt 0) { Get-Format $rd.FormatIdx } else { $null }
|
||||
$rowOwn = if ($rowFmt) { Get-StyleProps $rowFmt } else { [ordered]@{} }
|
||||
$rowHidden = ($rowOwn['hidden'] -eq $true)
|
||||
if ($rowFmt -and $rowFmt.Height -gt 0) { $dslRow["height"] = $rowFmt.Height }
|
||||
if ($rowHidden) { $dslRow["hidden"] = $true }
|
||||
|
||||
# Separate content cells from gap-fill cells
|
||||
$contentCells = @()
|
||||
@@ -780,7 +806,25 @@ foreach ($area in $blocks) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($rowStyleName -and $rowStyleName -ne "default") { $dslRow["rowStyle"] = $rowStyleName }
|
||||
# Стиль строки и стиль ячеек — независимые вещи: платформа их часто, но не всегда
|
||||
# пишет одинаковыми. Один ключ с модификатором apply покрывает все три случая.
|
||||
$ownFmt = Get-RowStyleFmt $rowFmt
|
||||
$ownKey = if ($ownFmt) { Get-StyleKey $ownFmt } else { $null }
|
||||
$ownName = if ($ownKey -and $styleNames.Contains($ownKey)) { $styleNames[$ownKey] } else { $null }
|
||||
$cellsName = if ($rowStyleName -and $rowStyleName -ne "default") { $rowStyleName } else { $null }
|
||||
|
||||
if ($ownName -and $cellsName -and $ownKey -ceq $rowStyleKey) {
|
||||
$dslRow["rowStyle"] = $ownName
|
||||
} elseif ($ownName -and -not $cellsName) {
|
||||
$dslRow["rowStyle"] = [ordered]@{ style = $ownName; apply = "row" }
|
||||
} elseif ($cellsName -and -not $ownName) {
|
||||
$dslRow["rowStyle"] = [ordered]@{ style = $cellsName; apply = "cells" }
|
||||
} elseif ($ownName -and $cellsName) {
|
||||
# Стили разные — строке своё, ячейкам своё; ячейкам стиль раздаётся поячеечно.
|
||||
$dslRow["rowStyle"] = [ordered]@{ style = $ownName; apply = "row" }
|
||||
$rowStyleName = $null
|
||||
$rowStyleKey = $null
|
||||
}
|
||||
|
||||
# Build cell list
|
||||
$dslCells = @()
|
||||
@@ -938,7 +982,10 @@ foreach ($a in $dslAreas) {
|
||||
# Строка может быть массивом (короткая форма) — у неё нет свойства cells, и без этой
|
||||
# ветки стиль, использованный только внутри такой строки, вырезался как «неиспользуемый».
|
||||
$cellList = if ($r -is [array]) { $r } else { $r.cells }
|
||||
if ($r -isnot [array] -and $r.rowStyle) { $usedStyles[$r.rowStyle] = $true }
|
||||
if ($r -isnot [array] -and $r.rowStyle) {
|
||||
$rs = $r.rowStyle
|
||||
$usedStyles[$(if ($rs -is [System.Collections.IDictionary]) { $rs['style'] } else { $rs })] = $true
|
||||
}
|
||||
if ($cellList) { foreach ($c in $cellList) { if ($c -isnot [string] -and $c.style) { $usedStyles[$c.style] = $true } } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# mxl-decompile v1.12 — Decompile 1C spreadsheet to JSON
|
||||
# mxl-decompile v1.13 — Decompile 1C spreadsheet to JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
@@ -659,6 +659,31 @@ def main():
|
||||
style_keys[key] = fmt
|
||||
format_to_style_key[cell["FormatIdx"]] = key
|
||||
|
||||
def row_style_fmt(fmt):
|
||||
"""Оформление строки без её собственных свойств: скрытие уезжает инлайном к height,
|
||||
поэтому в именованный стиль попадать не должно."""
|
||||
if not fmt:
|
||||
return None
|
||||
props = style_props(fmt)
|
||||
props.pop("hidden", None)
|
||||
if not props:
|
||||
return None
|
||||
reduced = OrderedDict()
|
||||
for tag, raw in fmt["Props"].items():
|
||||
if tag != "hidden":
|
||||
reduced[tag] = raw
|
||||
return {"FontIdx": fmt["FontIdx"], "Width": 0, "Height": 0,
|
||||
"FillType": "", "Props": reduced}
|
||||
|
||||
# Строка — тоже владелец формата: её оформление становится именованным стилем.
|
||||
for rd in row_data.values():
|
||||
rf = row_style_fmt(get_format(rd["FormatIdx"])) if rd["FormatIdx"] > 0 else None
|
||||
if not rf:
|
||||
continue
|
||||
key = get_style_key(rf)
|
||||
if key not in style_keys:
|
||||
style_keys[key] = rf
|
||||
|
||||
# Колонка — третий владелец формата, её оформление тоже становится именованным стилем.
|
||||
for cs in column_sets:
|
||||
for fi in cs["FmtIdx"].values():
|
||||
@@ -870,11 +895,15 @@ def main():
|
||||
|
||||
dsl_row = OrderedDict()
|
||||
|
||||
# Row height
|
||||
if rd["FormatIdx"] > 0:
|
||||
row_fmt = get_format(rd["FormatIdx"])
|
||||
if row_fmt and row_fmt["Height"] > 0:
|
||||
dsl_row["height"] = row_fmt["Height"]
|
||||
# Формат самой строки: высота и скрытие — её собственные свойства (у ячейки
|
||||
# таких нет), остальное — оформление, оно же может лежать и на ячейках.
|
||||
row_fmt = get_format(rd["FormatIdx"]) if rd["FormatIdx"] > 0 else None
|
||||
row_own = style_props(row_fmt) if row_fmt else OrderedDict()
|
||||
row_hidden = row_own.pop("hidden", False)
|
||||
if row_fmt and row_fmt["Height"] > 0:
|
||||
dsl_row["height"] = row_fmt["Height"]
|
||||
if row_hidden:
|
||||
dsl_row["hidden"] = True
|
||||
|
||||
# Separate content cells from gap-fill cells
|
||||
content_cells = []
|
||||
@@ -904,8 +933,25 @@ def main():
|
||||
if row_style_key in style_names:
|
||||
row_style_name = style_names[row_style_key]
|
||||
|
||||
if row_style_name and row_style_name != "default":
|
||||
dsl_row["rowStyle"] = row_style_name
|
||||
# Стиль строки и стиль ячеек — независимые вещи: платформа их часто, но не всегда
|
||||
# пишет одинаковыми. Один ключ с модификатором apply покрывает все три случая.
|
||||
own_fmt = row_style_fmt(row_fmt)
|
||||
own_key = get_style_key(own_fmt) if own_fmt else None
|
||||
own_name = style_names.get(own_key) if own_key else None
|
||||
cells_name = row_style_name if row_style_name and row_style_name != "default" else None
|
||||
|
||||
if own_name and cells_name and own_key == row_style_key:
|
||||
dsl_row["rowStyle"] = own_name
|
||||
elif own_name and not cells_name:
|
||||
dsl_row["rowStyle"] = OrderedDict([("style", own_name), ("apply", "row")])
|
||||
elif cells_name and not own_name:
|
||||
dsl_row["rowStyle"] = OrderedDict([("style", cells_name), ("apply", "cells")])
|
||||
elif own_name and cells_name:
|
||||
# Стили разные — строке своё, ячейкам своё; ячейкам стиль раздаётся ниже
|
||||
# поячеечно, поэтому здесь пишем только строку.
|
||||
dsl_row["rowStyle"] = OrderedDict([("style", own_name), ("apply", "row")])
|
||||
row_style_name = None
|
||||
row_style_key = None
|
||||
|
||||
# Build cell list
|
||||
dsl_cells = []
|
||||
@@ -1075,7 +1121,8 @@ def main():
|
||||
cell_list = r
|
||||
else:
|
||||
if "rowStyle" in r:
|
||||
used_styles.add(r["rowStyle"])
|
||||
rs = r["rowStyle"]
|
||||
used_styles.add(rs["style"] if isinstance(rs, dict) else rs)
|
||||
cell_list = r.get("cells") or []
|
||||
# Список ячеек может быть позиционным: строки, None и маркеры стиля не несут,
|
||||
# стиль бывает только у объектного элемента.
|
||||
|
||||
Reference in New Issue
Block a user