diff --git a/.claude/skills/skd-compile/scripts/skd-compile.ps1 b/.claude/skills/skd-compile/scripts/skd-compile.ps1
index 2668c83b..2104925a 100644
--- a/.claude/skills/skd-compile/scripts/skd-compile.ps1
+++ b/.claude/skills/skd-compile/scripts/skd-compile.ps1
@@ -1,4 +1,4 @@
-# skd-compile v1.32 — Compile 1C DCS from JSON
+# skd-compile v1.33 — Compile 1C DCS from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$DefinitionFile,
@@ -1603,6 +1603,28 @@ function Emit-CellAppearance {
X "`t`t`t`t"
}
+# Cell может быть string ("text"/"{param}"/"|"/">"/null) или объектом {value, style}.
+# Helpers извлекают значение и эффективный стиль ячейки.
+function Get-CellValue {
+ param($cell)
+ if ($null -eq $cell) { return $null }
+ if ($cell -is [string]) { return $cell }
+ if ($cell.PSObject -and $cell.PSObject.Properties['value']) { return $cell.value }
+ return $null
+}
+
+function Get-CellStyleOrDefault {
+ param($cell, $defaultStyle)
+ if ($null -ne $cell -and -not ($cell -is [string]) -and $cell.PSObject -and $cell.PSObject.Properties['style']) {
+ $sName = "$($cell.style)"
+ if ($script:areaStylePresets.ContainsKey($sName)) {
+ return $script:areaStylePresets[$sName]
+ }
+ Write-Warning "Unknown cell style preset '$sName', falling back to template default"
+ }
+ return $defaultStyle
+}
+
function Emit-AreaTemplateDSL {
param($t)
$styleName = if ($t.style) { "$($t.style)" } else { "data" }
@@ -1622,10 +1644,8 @@ function Emit-AreaTemplateDSL {
for ($r = $rows.Count - 1; $r -ge 1; $r--) {
$vMerge[$r] = @{}
for ($c = 0; $c -lt $colCount; $c++) {
- $cellVal = $rows[$r][$c]
- if ($cellVal -is [string] -and $cellVal -eq '|') {
- $vMerge[$r][$c] = $true
- }
+ $cellValStr = Get-CellValue $rows[$r][$c]
+ if ($cellValStr -eq '|') { $vMerge[$r][$c] = $true }
}
}
if (-not $vMerge.ContainsKey(0)) { $vMerge[0] = @{} }
@@ -1635,10 +1655,8 @@ function Emit-AreaTemplateDSL {
for ($r = 0; $r -lt $rows.Count; $r++) {
$hMerge[$r] = @{}
for ($c = 0; $c -lt $colCount; $c++) {
- $cellVal = $rows[$r][$c]
- if ($cellVal -is [string] -and $cellVal -eq '>') {
- $hMerge[$r][$c] = $true
- }
+ $cellValStr = Get-CellValue $rows[$r][$c]
+ if ($cellValStr -eq '>') { $hMerge[$r][$c] = $true }
}
}
@@ -1657,17 +1675,19 @@ function Emit-AreaTemplateDSL {
for ($r = 0; $r -lt $rows.Count; $r++) {
X "`t`t`t"
for ($c = 0; $c -lt $colCount; $c++) {
- $cellVal = $rows[$r][$c]
+ $cellRaw = $rows[$r][$c]
+ $cellVal = Get-CellValue $cellRaw
+ $cellStyle = Get-CellStyleOrDefault $cellRaw $style
$w = if ($c -lt $widths.Count) { [double]$widths[$c] } else { 0 }
$isVMerged = $vMerge[$r][$c] -eq $true
$isHMerged = $hMerge[$r][$c] -eq $true
X "`t`t`t`t"
if ($isVMerged) {
# Vertically merged cell — only appearance with vMerge flag + width
- Emit-CellAppearance $style $w $true
+ Emit-CellAppearance $cellStyle $w $true
} elseif ($isHMerged) {
# Horizontally merged cell — only appearance with hMerge flag + width
- Emit-CellAppearance $style $w $false $true
+ Emit-CellAppearance $cellStyle $w $false $true
} else {
# Cell value
if ($null -ne $cellVal -and $cellVal -ne '') {
@@ -1700,7 +1720,7 @@ function Emit-AreaTemplateDSL {
# Appearance
$h = if ($r -eq 0) { $minHeight } else { 0 }
if (-not $cellExtraItems) { $cellExtraItems = @() }
- Emit-CellAppearance $style $w $false $false $h $cellExtraItems
+ Emit-CellAppearance $cellStyle $w $false $false $h $cellExtraItems
$cellExtraItems = @()
}
X "`t`t`t`t"
diff --git a/.claude/skills/skd-compile/scripts/skd-compile.py b/.claude/skills/skd-compile/scripts/skd-compile.py
index c97fc6f1..3df68cd6 100644
--- a/.claude/skills/skd-compile/scripts/skd-compile.py
+++ b/.claude/skills/skd-compile/scripts/skd-compile.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# skd-compile v1.32 — Compile 1C DCS from JSON
+# skd-compile v1.33 — Compile 1C DCS from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import json
@@ -1325,6 +1325,26 @@ def _emit_cell_appearance(lines, style, width=0, v_merge=False, h_merge=False, m
lines.append('\t\t\t\t')
+# Cell может быть string ("text"/"{param}"/"|"/">"/null) или объектом {value, style}.
+def _get_cell_value(cell):
+ if cell is None:
+ return None
+ if isinstance(cell, str):
+ return cell
+ if isinstance(cell, dict) and 'value' in cell:
+ return cell['value']
+ return None
+
+
+def _get_cell_style_or_default(cell, default_style):
+ if isinstance(cell, dict) and 'style' in cell:
+ s_name = str(cell['style'])
+ if s_name in AREA_STYLE_PRESETS:
+ return AREA_STYLE_PRESETS[s_name]
+ print(f"Warning: Unknown cell style preset '{s_name}', falling back to template default", file=sys.stderr)
+ return default_style
+
+
def _emit_area_template_dsl(lines, t):
style_name = str(t.get('style', '')) or 'data'
if style_name not in AREA_STYLE_PRESETS:
@@ -1342,8 +1362,8 @@ def _emit_area_template_dsl(lines, t):
for r in range(len(rows) - 1, 0, -1):
v_merge[r] = {}
for c in range(col_count):
- cell_val = rows[r][c] if c < len(rows[r]) else None
- if isinstance(cell_val, str) and cell_val == '|':
+ cell_val = _get_cell_value(rows[r][c]) if c < len(rows[r]) else None
+ if cell_val == '|':
v_merge[r][c] = True
if 0 not in v_merge:
v_merge[0] = {}
@@ -1353,8 +1373,8 @@ def _emit_area_template_dsl(lines, t):
for r in range(len(rows)):
h_merge[r] = {}
for c in range(col_count):
- cell_val = rows[r][c] if c < len(rows[r]) else None
- if isinstance(cell_val, str) and cell_val == '>':
+ cell_val = _get_cell_value(rows[r][c]) if c < len(rows[r]) else None
+ if cell_val == '>':
h_merge[r][c] = True
# Build drilldown map: param_name -> drilldown_value
@@ -1371,15 +1391,17 @@ def _emit_area_template_dsl(lines, t):
for r in range(len(rows)):
lines.append('\t\t\t')
for c in range(col_count):
- cell_val = rows[r][c] if c < len(rows[r]) else None
+ cell_raw = rows[r][c] if c < len(rows[r]) else None
+ cell_val = _get_cell_value(cell_raw)
+ cell_style = _get_cell_style_or_default(cell_raw, style)
w = float(widths[c]) if c < len(widths) else 0
is_v_merged = v_merge.get(r, {}).get(c, False)
is_h_merged = h_merge.get(r, {}).get(c, False)
lines.append('\t\t\t\t')
if is_v_merged:
- _emit_cell_appearance(lines, style, w, True)
+ _emit_cell_appearance(lines, cell_style, w, True)
elif is_h_merged:
- _emit_cell_appearance(lines, style, w, h_merge=True)
+ _emit_cell_appearance(lines, cell_style, w, h_merge=True)
else:
cell_extra_items = []
if cell_val is not None and str(cell_val) != '':
@@ -1407,7 +1429,7 @@ def _emit_area_template_dsl(lines, t):
emit_mltext(lines, '\t\t\t\t\t\t', 'dcsat:value', cell_str)
lines.append('\t\t\t\t\t')
h = min_height if r == 0 else 0
- _emit_cell_appearance(lines, style, w, False, False, h, cell_extra_items or None)
+ _emit_cell_appearance(lines, cell_style, w, False, False, h, cell_extra_items or None)
lines.append('\t\t\t\t')
lines.append('\t\t\t')
diff --git a/.claude/skills/skd-decompile/scripts/skd-decompile.ps1 b/.claude/skills/skd-decompile/scripts/skd-decompile.ps1
index e639cd77..99356821 100644
--- a/.claude/skills/skd-decompile/scripts/skd-decompile.ps1
+++ b/.claude/skills/skd-decompile/scripts/skd-decompile.ps1
@@ -1,4 +1,4 @@
-# skd-decompile v0.15 — Decompile 1C DCS Template.xml to JSON DSL (draft)
+# skd-decompile v0.16 — Decompile 1C DCS Template.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -933,9 +933,8 @@ function Build-Template {
$rows = @()
$widths = $null
$minHeight = $null
- $detectedStyle = $null
- $styleMismatch = $false
- $hasAnyNonEmptyFp = $false # true если хоть одна ячейка имеет стилевые атрибуты
+ $cellStyleMap = @{} # "r,c" → имя стиля для конкретной ячейки (null для merge/no-style)
+ $hasAnyStyledCell = $false
$drilldownByParam = @{} # param name → field name (X from Расшифровка_X)
$rowIdx = 0
@@ -950,23 +949,17 @@ function Build-Template {
$perCell = Get-CellPerCellAttrs $appNode
$content = Get-CellContent $cellNode $perCell
- # Style detection (skip empty cells with no appearance, and merge cells)
+ # Style detection (skip merge cells)
if ($appNode -and -not $perCell.mergeV -and -not $perCell.mergeH) {
$cellPreset = Extract-CellPreset $appNode
if ($null -ne $cellPreset) {
- # Ячейка имеет стилевые атрибуты — match против effectivePresets, иначе аллоцируем custom
- $hasAnyNonEmptyFp = $true
$matched = Match-PresetByShape $cellPreset
if ($null -eq $matched) {
$matched = Allocate-CustomStyle $cellPreset
}
- if ($null -eq $detectedStyle) {
- $detectedStyle = $matched
- } elseif ($matched -ne $detectedStyle) {
- $styleMismatch = $true
- }
+ $cellStyleMap["$rowIdx,$colIdx"] = $matched
+ $hasAnyStyledCell = $true
}
- # Если cellPreset = $null — ячейка без стилевых атрибутов (только per-cell width/merge), не контрибутирует.
}
# Drilldown attachment
@@ -987,6 +980,42 @@ function Build-Template {
$rowIdx++
}
+ # Template default = наиболее частый стиль ячеек.
+ $templateDefault = $null
+ if ($hasAnyStyledCell) {
+ $counts = @{}
+ foreach ($k in $cellStyleMap.Keys) {
+ $name = $cellStyleMap[$k]
+ if (-not $counts.ContainsKey($name)) { $counts[$name] = 0 }
+ $counts[$name]++
+ }
+ $maxCount = 0
+ foreach ($name in $counts.Keys) {
+ if ($counts[$name] -gt $maxCount) {
+ $maxCount = $counts[$name]
+ $templateDefault = $name
+ }
+ }
+ }
+
+ # Если есть ячейки со стилем, отличным от template default — оборачиваем их в object form.
+ if ($templateDefault) {
+ $rowsOut = @()
+ for ($r = 0; $r -lt $rows.Count; $r++) {
+ $newRow = @()
+ for ($c = 0; $c -lt $rows[$r].Count; $c++) {
+ $key = "$r,$c"
+ if ($cellStyleMap.ContainsKey($key) -and $cellStyleMap[$key] -ne $templateDefault) {
+ $newRow += [ordered]@{ value = $rows[$r][$c]; style = $cellStyleMap[$key] }
+ } else {
+ $newRow += $rows[$r][$c]
+ }
+ }
+ $rowsOut += ,$newRow
+ }
+ $rows = $rowsOut
+ }
+
# Template parameters (and drilldown folding)
$paramNodes = $templateNode.SelectNodes("r:parameter", $ns)
$exprParams = [ordered]@{}
@@ -1014,14 +1043,11 @@ function Build-Template {
}
# Decide output form
- if ($detectedStyle -and -not $styleMismatch) {
- $tmplObj['style'] = $detectedStyle
- } elseif (-not $hasAnyNonEmptyFp -and $rows.Count -gt 0) {
+ if ($templateDefault) {
+ $tmplObj['style'] = $templateDefault
+ } elseif ($rows.Count -gt 0) {
# Все ячейки без стилевых атрибутов — это шаблон "без стиля"
$tmplObj['style'] = 'none'
- } elseif ($styleMismatch -or ($null -eq $detectedStyle -and $hasAnyNonEmptyFp)) {
- # Couldn't unify style — emit sentinel
- $tmplObj['__unsupported__'] = (New-Sentinel -kind 'TemplateStyleMismatch' -loc $loc -detail 'Шаблон содержит ячейки с непокрытым/неоднородным оформлением (Кольцо 2)')['__unsupported__']
}
if ($widths) { $tmplObj['widths'] = $widths }
if ($minHeight) { $tmplObj['minHeight'] = $minHeight }
diff --git a/tests/skills/cases/skd-decompile/snapshots/template-inline-cell-style/Template.xml b/tests/skills/cases/skd-decompile/snapshots/template-inline-cell-style/Template.xml
new file mode 100644
index 00000000..1669953b
--- /dev/null
+++ b/tests/skills/cases/skd-decompile/snapshots/template-inline-cell-style/Template.xml
@@ -0,0 +1,228 @@
+
+
+
+ ИсточникДанных1
+ Local
+
+
+ Тест
+
+ Поле
+ Поле
+
+ xs:string
+
+ 0
+ Variable
+
+
+
+ ИсточникДанных1
+ ВЫБРАТЬ * ИЗ Справочник.Сотрудники
+
+
+ СмешанныйМакет
+
+
+
+
+
+
+ ru
+ A
+
+
+
+
+
+ ЦветФона
+ d8p1:ReportGroup1BackColor
+
+
+ ЦветГраницы
+ d8p1:ReportLineColor
+
+
+ СтильГраницы
+
+ None
+
+
+ СтильГраницы.Слева
+
+ Solid
+
+
+
+ СтильГраницы.Сверху
+
+ Solid
+
+
+
+ СтильГраницы.Справа
+
+ Solid
+
+
+
+ СтильГраницы.Снизу
+
+ Solid
+
+
+
+
+ Шрифт
+
+
+
+
+
+
+
+
+ ru
+ B
+
+
+
+
+
+ ЦветФона
+ d8p1:ReportHeaderBackColor
+
+
+ ЦветГраницы
+ d8p1:ReportLineColor
+
+
+ СтильГраницы
+
+ None
+
+
+ СтильГраницы.Слева
+
+ Solid
+
+
+
+ СтильГраницы.Сверху
+
+ Solid
+
+
+
+ СтильГраницы.Справа
+
+ Solid
+
+
+
+ СтильГраницы.Снизу
+
+ Solid
+
+
+
+
+ Шрифт
+
+
+
+ ГоризонтальноеПоложение
+ Center
+
+
+ Размещение
+ Wrap
+
+
+
+
+
+
+
+ ru
+ C
+
+
+
+
+
+ ЦветФона
+ d8p1:ReportGroup1BackColor
+
+
+ ЦветГраницы
+ d8p1:ReportLineColor
+
+
+ СтильГраницы
+
+ None
+
+
+ СтильГраницы.Слева
+
+ Solid
+
+
+
+ СтильГраницы.Сверху
+
+ Solid
+
+
+
+ СтильГраницы.Справа
+
+ Solid
+
+
+
+ СтильГраницы.Снизу
+
+ Solid
+
+
+
+
+ Шрифт
+
+
+
+
+
+
+
+
+ Основной
+
+
+ ru
+ Основной
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/skills/cases/skd-decompile/snapshots/template-inline-cell-style/decompiled.json b/tests/skills/cases/skd-decompile/snapshots/template-inline-cell-style/decompiled.json
new file mode 100644
index 00000000..ba6fd4f1
--- /dev/null
+++ b/tests/skills/cases/skd-decompile/snapshots/template-inline-cell-style/decompiled.json
@@ -0,0 +1,27 @@
+{
+ "dataSets": [
+ {
+ "name": "Тест",
+ "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники",
+ "fields": [
+ "Поле: string"
+ ]
+ }
+ ],
+ "templates": [
+ {
+ "name": "СмешанныйМакет",
+ "style": "data",
+ "rows": [
+ [
+ "A",
+ {
+ "value": "B",
+ "style": "header"
+ },
+ "C"
+ ]
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/skills/cases/skd-decompile/template-inline-cell-style.json b/tests/skills/cases/skd-decompile/template-inline-cell-style.json
new file mode 100644
index 00000000..7b32c298
--- /dev/null
+++ b/tests/skills/cases/skd-decompile/template-inline-cell-style.json
@@ -0,0 +1,28 @@
+{
+ "name": "Шаблон с inline cell style (data + per-cell override)",
+ "preRun": [
+ {
+ "script": "skd-compile/scripts/skd-compile",
+ "input": {
+ "dataSets": [{
+ "name": "Тест",
+ "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники",
+ "fields": ["Поле: string"]
+ }],
+ "templates": [
+ {
+ "name": "СмешанныйМакет",
+ "style": "data",
+ "rows": [
+ ["A", { "value": "B", "style": "header" }, "C"]
+ ]
+ }
+ ]
+ },
+ "args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "Template.xml" },
+ "cwd": "{workDir}"
+ }
+ ],
+ "params": { "templatePath": "Template.xml" },
+ "outputPath": "decompiled.json"
+}