mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-23 21:21:04 +03:00
feat(form-decompile,form-compile): Chart design-time Settings из ring-3 (Фаза 2 кластера Chart-Settings)
Реквизит-диаграмма несёт <Settings xsi:type="d4p1:Chart"> — встроенный конфиг
(~110-130 версионно-вариативных полей: тип/серии/легенда/заголовок/шкалы/цвета/
оси, глубокая вложенность с повторяющимися именами). Корпус 8.3.24: 5 форм.
Подход (с пользователем): ГЕНЕРИК-движок. Ключ chart на реквизите; рекурсивный
захват/эмит поддерева d4p1, ключи = локальные имена тегов, порядок ключей =
порядок эмиссии → раундтрип ЛЮБОЙ версии/набора полей бит-в-бит (платформа
добавляет поля, не переставляет). Структуры распознаются по форме узла
(line {width,gap,style} / border {width,style} / font {kind} / ML / области
{left,right,top,bottom} / серии-массивы); малые name-set'ы: ML-поля, серии,
attrs-узлы (gaugeQualityBands). Расширяемость: любое из ~127 свойств — по
каноничному имени.
Авторинг с нуля: декомпиль рабочей диаграммы как шаблон + правка ядра
(chartType/серии/легенда/цвета). Default-fill через merge НЕ делаем — конфликт
с байт-точностью неполных форм (см. docs/form-dsl-spec.md).
Результат: 4 из 5 форм корпуса — байт-в-байт (включая версионно-вариативные).
5-я (точки/оси realPointData/realDataItems с типизир. значениями xsi:type,
xsi:nil, ML с префиксом d4p1:) → честный fail-ring3 (редкий вариант, не
поддержан генериком). Снят fail-ring3 для d4p1:Chart (GanttChart — Фаза 3).
Заодно фикс: d5p1:Dendrogram отсутствовал в specialTypeNs (ps1+py).
Декомпилятор ps1-only (генерик-рекурсия); компилятор зеркало py (ps1==py
байт-в-байт). Кейс chart-settings (полная диаграмма из эталона
ПроверкаКонтрагента) сертифицирован загрузкой в 1С. Регресс 42/42.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f534add7b4
commit
1333e09ff8
@@ -1,4 +1,4 @@
|
||||
# form-decompile v0.81 — Decompile 1C managed Form.xml to JSON DSL (draft)
|
||||
# form-decompile v0.82 — Decompile 1C managed Form.xml to JSON DSL (draft)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
|
||||
param(
|
||||
@@ -152,9 +152,15 @@ foreach ($el in $xmlDoc.SelectNodes("//*[local-name()='ConditionalAppearance']/*
|
||||
# (встроенная конфигурация диаграммы) пока НЕ воспроизводим → честный скип, чтобы не потерять молча.
|
||||
foreach ($s in $xmlDoc.SelectNodes("//*[local-name()='Attribute']/*[local-name()='Settings']")) {
|
||||
$st = $s.GetAttribute("type", $NS_XSI)
|
||||
if ($st -and $st -notmatch 'TypeDescription$' -and $st -notmatch 'DynamicList$' -and $st -notmatch 'Planner$') {
|
||||
if ($st -and $st -notmatch 'TypeDescription$' -and $st -notmatch 'DynamicList$' -and $st -notmatch 'Planner$' -and $st -notmatch 'd4p1:Chart$') {
|
||||
Fail-Ring3 -kind "Attribute>Settings типа '$st' (design-time конфигурация, напр. диаграмма)" -loc "Attribute/Settings"
|
||||
}
|
||||
# Chart с точками/осями (realPointData/realDataItems): типизированные значения (xsi:type),
|
||||
# xsi:nil и ML с префиксом d4p1: (а не v8:) генерик-движок не сохраняет → честный скип.
|
||||
# Частые дашборд-диаграммы (серии/легенда/оформление) поддержаны.
|
||||
elseif ($st -match 'd4p1:Chart$' -and ($s.OuterXml -match '<d4p1:\w+ xsi:type=' -or $s.OuterXml -match '<d4p1:\w+ xsi:nil=' -or $s.OuterXml -match '<d4p1:item[ >]')) {
|
||||
Fail-Ring3 -kind "Attribute>Settings d4p1:Chart с точками/осями (типизированные значения/d4p1-ML)" -loc "Attribute/Settings"
|
||||
}
|
||||
}
|
||||
|
||||
# --- 1c. Compact JSON serializer (созвучно skd-decompile: 2-проб. indent, inline в пределах lineLimit) ---
|
||||
@@ -2002,6 +2008,69 @@ function Build-PlannerSettings {
|
||||
return $pl
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Chart design-time <Settings xsi:type="d4p1:Chart"> → объект chart. Генерик-движок:
|
||||
# рекурсивный захват поддерева d4p1; структуры (line/border/font/ML/области/серии)
|
||||
# детектируются по форме узла. Малые name-set'ы: ML-поля (даже ru-only/пустые → ML),
|
||||
# серии (всегда массив), attrs-узлы. Порядок ключей JSON = порядок XML (раундтрип).
|
||||
$CHART_ML_FIELDS = @{ 'title'=1;'lbFormat'=1;'lbpFormat'=1;'vsFormat'=1;'dtFormat'=1;'dataSourceDescription'=1;'labelFormat'=1;'text'=1 }
|
||||
$CHART_SERIES_FIELDS = @{ 'realSeriesData'=1;'realExSeriesData'=1;'realPointData'=1;'realDataItems'=1 }
|
||||
$CHART_ATTR_FIELDS = @{ 'gaugeQualityBands'=1 }
|
||||
function Conv-ChartScalar {
|
||||
param([string]$v)
|
||||
if ($v -eq 'true') { return $true }
|
||||
if ($v -eq 'false') { return $false }
|
||||
return $v
|
||||
}
|
||||
function Build-ChartNode {
|
||||
param($n, [string]$name)
|
||||
# ML-поле → строка/мапа/"" (даже ru-only форсим в ML на эмите по имени)
|
||||
if ($CHART_ML_FIELDS.Contains($name)) {
|
||||
$ml = Get-LangText $n
|
||||
if ($null -eq $ml) { return '' } else { return $ml }
|
||||
}
|
||||
$kids = @($n.SelectNodes("*"))
|
||||
if ($kids.Count -eq 0) {
|
||||
# лист: attrs-only (шрифт/gaugeQualityBands) или текст
|
||||
$attrs = @($n.Attributes | Where-Object { $_.Name -ne 'xmlns' -and -not $_.Name.StartsWith('xmlns:') -and $_.Name -ne 'xsi:type' -and $_.Name -ne 'xsi:nil' })
|
||||
if ($attrs.Count -gt 0) {
|
||||
$o = [ordered]@{}; foreach ($a in $attrs) { $o[$a.Name] = (Conv-ChartScalar $a.Value) }; return $o
|
||||
}
|
||||
return (Conv-ChartScalar $n.InnerText)
|
||||
}
|
||||
# line/border: дочерний v8ui:style (+ width[/gap])
|
||||
$styleChild = $n.SelectSingleNode("*[local-name()='style']")
|
||||
if ($styleChild) {
|
||||
$o = [ordered]@{}
|
||||
$w = $n.GetAttribute('width'); if ($w -ne '') { $o['width'] = [int]$w }
|
||||
$g = $n.GetAttribute('gap'); if ($g -ne '') { $o['gap'] = ($g -eq 'true') }
|
||||
$o['style'] = $styleChild.InnerText
|
||||
return $o
|
||||
}
|
||||
# вложенный объект d4p1 (область/шкала/titleArea/серия): группируем детей по имени
|
||||
$o = [ordered]@{}
|
||||
foreach ($c in $kids) {
|
||||
$ln = $c.LocalName
|
||||
$val = Build-ChartNode $c $ln
|
||||
if ($CHART_SERIES_FIELDS.Contains($ln)) {
|
||||
if (-not $o.Contains($ln)) { $o[$ln] = New-Object System.Collections.ArrayList }
|
||||
[void]$o[$ln].Add($val)
|
||||
} elseif ($o.Contains($ln)) {
|
||||
if ($o[$ln] -isnot [System.Collections.IList]) { $tmp = New-Object System.Collections.ArrayList; [void]$tmp.Add($o[$ln]); $o[$ln] = $tmp }
|
||||
[void]$o[$ln].Add($val)
|
||||
} else {
|
||||
$o[$ln] = $val
|
||||
}
|
||||
}
|
||||
# нормализуем ArrayList → @() для сериализации
|
||||
foreach ($k in @($o.Keys)) { if ($o[$k] -is [System.Collections.ArrayList]) { $o[$k] = @($o[$k]) } }
|
||||
return $o
|
||||
}
|
||||
function Build-ChartSettings {
|
||||
param($setNode)
|
||||
return (Build-ChartNode $setNode '')
|
||||
}
|
||||
|
||||
# --- 5. Form-level assembly ---
|
||||
$dsl = [ordered]@{}
|
||||
|
||||
@@ -2137,6 +2206,10 @@ if ($attrsNode) {
|
||||
elseif ($setNode -and $setNode.GetAttribute("type", $NS_XSI) -match 'Planner$') {
|
||||
$ao['planner'] = Build-PlannerSettings $setNode
|
||||
}
|
||||
# Chart design-time <Settings xsi:type="d4p1:Chart"> → объект chart (генерик-захват).
|
||||
elseif ($setNode -and $setNode.GetAttribute("type", $NS_XSI) -match 'd4p1:Chart$') {
|
||||
$ao['chart'] = Build-ChartSettings $setNode
|
||||
}
|
||||
if ((Get-Child $a 'MainAttribute') -eq 'true') { $ao['main'] = $true }
|
||||
elseif ($suppressMainName -and $ao['name'] -eq $suppressMainName) { $ao['main'] = $false }
|
||||
$vw = Decompile-XrFlag $a 'View'; if ($null -ne $vw) { $ao['view'] = $vw }
|
||||
|
||||
Reference in New Issue
Block a user