mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-15 10:24:57 +03:00
feat(skd-decompile): авто-генерация skd-styles.json для custom appearance
Категория C — закрыта для однородных шаблонов с custom appearance. Refactor fingerprint → preset shape (11 полей: font/fontSize/bold/italic/ hAlign/vAlign/wrap/bgColor/textColor/borderColor/borders). vAlign теперь учитывается в matching (раньше игнорировался). Алгоритм: 1. При -OutputPath загружается existing skd-styles.json рядом (если есть); user presets накладываются на built-in по той же логике что и compile. 2. Каждая ячейка → Extract-CellPreset → Match-PresetByShape против effectivePresets (built-in + user). 3. Если не match — Allocate-CustomStyle: новый customN, регистрируется в effectivePresets и accumulator. 4. По окончании Save-UserStyles пишет skd-styles.json рядом с outputPath (preserved existing + новые customN). 5. Compile подхватит файл по своим search-путям (cwd/dirname/scan-up). В SKILL.md не добавляем (custom стили — для round-trip, не для написания модель с нуля; built-in `data/header/subheader/total/none` остаются основным интерфейсом для модели). - runner.mjs: новый preRun step `writeFile` для подготовки fixture-файлов в workDir (нужен для теста с предзаписанным skd-styles.json). - Новый тест template-custom-style: preRun пишет myHeader preset, скомпилирует темплейт, decompile reverse'ит → переиспользует имя myHeader (не создаёт customN). - v0.14 → v0.15. Метрики: - ERP-сэмпл 30: 24 → 0 sentinel'ов, clean 26 → 30/30 - Целевой корпус 40 отчётов: 39 → 25 sentinel'ов (часть закрыта), clean 19 → 20/40. Остаточные — шаблоны с разными стилями в разных ячейках одного шаблона (нужно per-cell style override — отдельная задача).
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# skd-decompile v0.14 — Decompile 1C DCS Template.xml to JSON DSL (draft)
|
||||
# skd-decompile v0.15 — Decompile 1C DCS Template.xml to JSON DSL (draft)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -646,126 +646,203 @@ function Render-Parameter {
|
||||
return $obj
|
||||
}
|
||||
|
||||
# --- 3b. Built-in style fingerprints ---
|
||||
# --- 3b. Built-in style presets (preset-shape: 11 полей) ---
|
||||
|
||||
# Fingerprints for built-in styles (header/data/subheader/total).
|
||||
# Each is the set of "shape-defining" appearance items the style emits.
|
||||
# Width/Height/merge flags are excluded — they're per-cell.
|
||||
$script:builtinStyleFingerprints = @{
|
||||
'header' = @{
|
||||
ЦветФона = 'd8p1:ReportHeaderBackColor'
|
||||
ЦветГраницы = 'd8p1:ReportLineColor'
|
||||
СтильГраницы = 'None|0'
|
||||
'СтильГраницы.Слева' = 'Solid|1'
|
||||
'СтильГраницы.Сверху' = 'Solid|1'
|
||||
'СтильГраницы.Справа' = 'Solid|1'
|
||||
'СтильГраницы.Снизу' = 'Solid|1'
|
||||
Шрифт = 'Arial|10|false|false|false|false'
|
||||
ГоризонтальноеПоложение = 'Center'
|
||||
Размещение = 'Wrap'
|
||||
# Имена 5 встроенных стилей. Совпадает с compile presets.
|
||||
$script:builtinPresetNames = @('none','data','header','subheader','total')
|
||||
|
||||
# Преобразовать compile-style preset hashtable в наш canonical preset shape.
|
||||
# Canonical поля: font, fontSize, bold, italic, hAlign, vAlign, wrap, bgColor, textColor, borderColor, borders.
|
||||
$script:builtinPresets = @{
|
||||
'none' = @{
|
||||
font = $null; fontSize = $null; bold = $false; italic = $false
|
||||
hAlign = $null; vAlign = $null; wrap = $false
|
||||
bgColor = $null; textColor = $null
|
||||
borderColor = $null; borders = $false
|
||||
}
|
||||
'data' = @{
|
||||
ЦветФона = 'd8p1:ReportGroup1BackColor'
|
||||
ЦветГраницы = 'd8p1:ReportLineColor'
|
||||
СтильГраницы = 'None|0'
|
||||
'СтильГраницы.Слева' = 'Solid|1'
|
||||
'СтильГраницы.Сверху' = 'Solid|1'
|
||||
'СтильГраницы.Справа' = 'Solid|1'
|
||||
'СтильГраницы.Снизу' = 'Solid|1'
|
||||
Шрифт = 'Arial|10|false|false|false|false'
|
||||
font = 'Arial'; fontSize = 10; bold = $false; italic = $false
|
||||
hAlign = $null; vAlign = $null; wrap = $false
|
||||
bgColor = 'style:ReportGroup1BackColor'; textColor = $null
|
||||
borderColor = 'style:ReportLineColor'; borders = $true
|
||||
}
|
||||
'header' = @{
|
||||
font = 'Arial'; fontSize = 10; bold = $false; italic = $false
|
||||
hAlign = 'Center'; vAlign = $null; wrap = $true
|
||||
bgColor = 'style:ReportHeaderBackColor'; textColor = $null
|
||||
borderColor = 'style:ReportLineColor'; borders = $true
|
||||
}
|
||||
'subheader' = @{
|
||||
ЦветГраницы = 'd8p1:ReportLineColor'
|
||||
СтильГраницы = 'None|0'
|
||||
'СтильГраницы.Слева' = 'Solid|1'
|
||||
'СтильГраницы.Сверху' = 'Solid|1'
|
||||
'СтильГраницы.Справа' = 'Solid|1'
|
||||
'СтильГраницы.Снизу' = 'Solid|1'
|
||||
Шрифт = 'Arial|10|false|false|false|false'
|
||||
ГоризонтальноеПоложение = 'Center'
|
||||
font = 'Arial'; fontSize = 10; bold = $false; italic = $false
|
||||
hAlign = 'Center'; vAlign = $null; wrap = $true
|
||||
bgColor = $null; textColor = $null
|
||||
borderColor = 'style:ReportLineColor'; borders = $true
|
||||
}
|
||||
'total' = @{
|
||||
ЦветГраницы = 'd8p1:ReportLineColor'
|
||||
СтильГраницы = 'None|0'
|
||||
'СтильГраницы.Слева' = 'Solid|1'
|
||||
'СтильГраницы.Сверху' = 'Solid|1'
|
||||
'СтильГраницы.Справа' = 'Solid|1'
|
||||
'СтильГраницы.Снизу' = 'Solid|1'
|
||||
Шрифт = 'Arial|10|false|false|false|false'
|
||||
font = 'Arial'; fontSize = 10; bold = $false; italic = $false
|
||||
hAlign = $null; vAlign = $null; wrap = $false
|
||||
bgColor = $null; textColor = $null
|
||||
borderColor = 'style:ReportLineColor'; borders = $true
|
||||
}
|
||||
}
|
||||
|
||||
# Normalize an <dcsat:appearance> node to a hashtable of "shape" keys (excluding
|
||||
# per-cell items: widths, heights, merge flags, drilldown). Used for style matching.
|
||||
function Get-AppearanceFingerprint {
|
||||
# effectivePresets = built-in + любые user-переопределения, загруженные из skd-styles.json
|
||||
$script:effectivePresets = @{}
|
||||
foreach ($k in $script:builtinPresets.Keys) {
|
||||
$copy = @{}
|
||||
foreach ($f in $script:builtinPresets[$k].Keys) { $copy[$f] = $script:builtinPresets[$k][$f] }
|
||||
$script:effectivePresets[$k] = $copy
|
||||
}
|
||||
|
||||
# existingUserPresetsRaw — копия загруженного skd-styles.json (PSCustomObject) для merge при записи.
|
||||
$script:existingUserPresetsRaw = $null
|
||||
|
||||
# customStylesAccumulator — новые customN, накопленные в текущем прогоне, для записи в skd-styles.json.
|
||||
$script:customStylesAccumulator = [ordered]@{}
|
||||
|
||||
# Счётчик customN
|
||||
$script:customStyleCounter = 0
|
||||
|
||||
# Normalize color value: 'd8p1:ReportHeaderBackColor' → 'style:ReportHeaderBackColor'
|
||||
function Normalize-Color {
|
||||
param($valNode)
|
||||
if (-not $valNode) { return $null }
|
||||
$txt = $valNode.InnerText
|
||||
if ($txt -match '^d\d+p\d+:(.+)$') { return 'style:' + $matches[1] }
|
||||
return $txt
|
||||
}
|
||||
|
||||
# Build preset hashtable (11 полей) из <dcsat:appearance>.
|
||||
# Возвращает $null если у ячейки нет ни одного стилевого атрибута (только per-cell).
|
||||
function Extract-CellPreset {
|
||||
param($appNode)
|
||||
$fp = @{}
|
||||
if (-not $appNode) { return $fp }
|
||||
# Top-level dcscor:item children
|
||||
if (-not $appNode) { return $null }
|
||||
$preset = @{
|
||||
font = $null; fontSize = $null; bold = $false; italic = $false
|
||||
hAlign = $null; vAlign = $null; wrap = $false
|
||||
bgColor = $null; textColor = $null
|
||||
borderColor = $null; borders = $false
|
||||
}
|
||||
$hasAnyStyle = $false
|
||||
foreach ($it in $appNode.SelectNodes("dcscor:item", $ns)) {
|
||||
$pName = Get-Text $it "dcscor:parameter"
|
||||
$val = $it.SelectSingleNode("dcscor:value", $ns)
|
||||
if (-not $pName -or -not $val) { continue }
|
||||
# Skip per-cell keys
|
||||
if (-not $pName) { continue }
|
||||
if ($pName -in @('МинимальнаяШирина','МаксимальнаяШирина','МинимальнаяВысота','ОбъединятьПоВертикали','ОбъединятьПоГоризонтали','Расшифровка')) { continue }
|
||||
$valType = Get-LocalXsiType $val
|
||||
switch ($valType) {
|
||||
'Color' { $fp[$pName] = $val.InnerText }
|
||||
'Line' {
|
||||
$w = $val.GetAttribute("width")
|
||||
$styleNode = $val.SelectSingleNode("v8ui:style", $ns)
|
||||
$lineStyle = if ($styleNode) { $styleNode.InnerText } else { '' }
|
||||
$fp[$pName] = "$lineStyle|$w"
|
||||
switch ($pName) {
|
||||
'Шрифт' {
|
||||
if ($val) {
|
||||
$preset.font = $val.GetAttribute("faceName")
|
||||
$h = $val.GetAttribute("height")
|
||||
if ($h) { $preset.fontSize = [int]$h }
|
||||
$preset.bold = ($val.GetAttribute("bold") -eq 'true')
|
||||
$preset.italic = ($val.GetAttribute("italic") -eq 'true')
|
||||
$hasAnyStyle = $true
|
||||
}
|
||||
}
|
||||
'Font' {
|
||||
$face = $val.GetAttribute("faceName")
|
||||
$h = $val.GetAttribute("height")
|
||||
$b = $val.GetAttribute("bold")
|
||||
$i = $val.GetAttribute("italic")
|
||||
$u = $val.GetAttribute("underline")
|
||||
$s = $val.GetAttribute("strikeout")
|
||||
$fp[$pName] = "$face|$h|$b|$i|$u|$s"
|
||||
}
|
||||
default { $fp[$pName] = $val.InnerText }
|
||||
}
|
||||
# Nested sub-items under СтильГраницы (left/top/right/bottom)
|
||||
foreach ($sub in $it.SelectNodes("dcscor:item", $ns)) {
|
||||
$subName = Get-Text $sub "dcscor:parameter"
|
||||
$subVal = $sub.SelectSingleNode("dcscor:value", $ns)
|
||||
if (-not $subName -or -not $subVal) { continue }
|
||||
$subType = Get-LocalXsiType $subVal
|
||||
if ($subType -eq 'Line') {
|
||||
$w = $subVal.GetAttribute("width")
|
||||
$styleNode = $subVal.SelectSingleNode("v8ui:style", $ns)
|
||||
$lineStyle = if ($styleNode) { $styleNode.InnerText } else { '' }
|
||||
$fp[$subName] = "$lineStyle|$w"
|
||||
'ЦветФона' { if ($val) { $preset.bgColor = Normalize-Color $val; $hasAnyStyle = $true } }
|
||||
'ЦветТекста' { if ($val) { $preset.textColor = Normalize-Color $val; $hasAnyStyle = $true } }
|
||||
'ЦветГраницы' { if ($val) { $preset.borderColor = Normalize-Color $val; $hasAnyStyle = $true } }
|
||||
'СтильГраницы' {
|
||||
# borders = true если есть sub-items для 4 сторон со style=Solid
|
||||
$sidesFound = 0
|
||||
foreach ($sub in $it.SelectNodes("dcscor:item", $ns)) {
|
||||
$subName = Get-Text $sub "dcscor:parameter"
|
||||
if ($subName -match '^СтильГраницы\.(Слева|Сверху|Справа|Снизу)$') { $sidesFound++ }
|
||||
}
|
||||
if ($sidesFound -gt 0) { $preset.borders = $true; $hasAnyStyle = $true }
|
||||
}
|
||||
'ГоризонтальноеПоложение' { if ($val) { $preset.hAlign = $val.InnerText; $hasAnyStyle = $true } }
|
||||
'ВертикальноеПоложение' { if ($val) { $preset.vAlign = $val.InnerText; $hasAnyStyle = $true } }
|
||||
'Размещение' { if ($val -and $val.InnerText -eq 'Wrap') { $preset.wrap = $true; $hasAnyStyle = $true } }
|
||||
}
|
||||
}
|
||||
# Translate d8p1: colors to canonical "d8p1:Name" form (InnerText already contains prefix)
|
||||
return $fp
|
||||
if (-not $hasAnyStyle) { return $null }
|
||||
return $preset
|
||||
}
|
||||
|
||||
# Check if appearance fingerprint matches a built-in style.
|
||||
# Returns style name or $null.
|
||||
function Match-BuiltinStyle {
|
||||
param($fp)
|
||||
foreach ($styleName in $script:builtinStyleFingerprints.Keys) {
|
||||
$expected = $script:builtinStyleFingerprints[$styleName]
|
||||
$match = $true
|
||||
# All expected keys must be present with matching value
|
||||
foreach ($k in $expected.Keys) {
|
||||
if (-not $fp.ContainsKey($k) -or $fp[$k] -ne $expected[$k]) { $match = $false; break }
|
||||
}
|
||||
if (-not $match) { continue }
|
||||
# Must not have extra keys that aren't in the expected fingerprint
|
||||
$extras = @($fp.Keys | Where-Object { -not $expected.ContainsKey($_) })
|
||||
if ($extras.Count -ne 0) { continue }
|
||||
return $styleName
|
||||
# Deep-equality двух preset hashtables (11 полей).
|
||||
function Compare-Preset {
|
||||
param($a, $b)
|
||||
foreach ($key in @('font','fontSize','bold','italic','hAlign','vAlign','wrap','bgColor','textColor','borderColor','borders')) {
|
||||
if ($a[$key] -ne $b[$key]) { return $false }
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
# Найти имя preset'а в effectivePresets по shape. Возвращает имя или $null.
|
||||
function Match-PresetByShape {
|
||||
param($cellPreset)
|
||||
if (-not $cellPreset) { return $null }
|
||||
foreach ($name in $script:effectivePresets.Keys) {
|
||||
if (Compare-Preset $cellPreset $script:effectivePresets[$name]) { return $name }
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
# Аллокация customN для нового, не-matched preset'а. Регистрирует в effectivePresets+accumulator.
|
||||
function Allocate-CustomStyle {
|
||||
param($cellPreset)
|
||||
# Поиск свободного customN
|
||||
$script:customStyleCounter++
|
||||
$name = "custom$($script:customStyleCounter)"
|
||||
while ($script:effectivePresets.ContainsKey($name)) {
|
||||
$script:customStyleCounter++
|
||||
$name = "custom$($script:customStyleCounter)"
|
||||
}
|
||||
$script:effectivePresets[$name] = $cellPreset
|
||||
$script:customStylesAccumulator[$name] = $cellPreset
|
||||
return $name
|
||||
}
|
||||
|
||||
# Загрузка skd-styles.json рядом с outputPath (если есть) и наслоение на effectivePresets.
|
||||
function Load-UserStyles {
|
||||
param([string]$dirPath)
|
||||
if (-not $dirPath) { return }
|
||||
$stylesPath = Join-Path $dirPath 'skd-styles.json'
|
||||
if (-not (Test-Path $stylesPath)) { return }
|
||||
$raw = Get-Content -Raw -Encoding UTF8 $stylesPath | ConvertFrom-Json
|
||||
$script:existingUserPresetsRaw = $raw
|
||||
foreach ($prop in $raw.PSObject.Properties) {
|
||||
# Compile-логика: data defaults → built-in if name match → user keys
|
||||
$preset = @{}
|
||||
foreach ($k in $script:builtinPresets['data'].Keys) { $preset[$k] = $script:builtinPresets['data'][$k] }
|
||||
if ($script:builtinPresets.ContainsKey($prop.Name)) {
|
||||
foreach ($k in $script:builtinPresets[$prop.Name].Keys) { $preset[$k] = $script:builtinPresets[$prop.Name][$k] }
|
||||
}
|
||||
foreach ($up in $prop.Value.PSObject.Properties) {
|
||||
$preset[$up.Name] = $up.Value
|
||||
}
|
||||
$script:effectivePresets[$prop.Name] = $preset
|
||||
}
|
||||
}
|
||||
|
||||
# Запись skd-styles.json: preserved existing user presets + новые customN.
|
||||
function Save-UserStyles {
|
||||
param([string]$dirPath)
|
||||
if (-not $dirPath) { return }
|
||||
if ($script:customStylesAccumulator.Count -eq 0 -and -not $script:existingUserPresetsRaw) { return }
|
||||
$stylesPath = Join-Path $dirPath 'skd-styles.json'
|
||||
$out = [ordered]@{}
|
||||
# Сначала existing (preserve порядок и значения)
|
||||
if ($script:existingUserPresetsRaw) {
|
||||
foreach ($prop in $script:existingUserPresetsRaw.PSObject.Properties) {
|
||||
$out[$prop.Name] = $prop.Value
|
||||
}
|
||||
}
|
||||
# Потом новые customN
|
||||
foreach ($name in $script:customStylesAccumulator.Keys) {
|
||||
if ($out.Contains($name)) { continue }
|
||||
$out[$name] = $script:customStylesAccumulator[$name]
|
||||
}
|
||||
if ($out.Count -eq 0) { return }
|
||||
$json = $out | ConvertTo-Json -Depth 8
|
||||
$json = [regex]::Replace($json, '\\u([0-9a-fA-F]{4})', { param($m) [char][int]("0x" + $m.Groups[1].Value) })
|
||||
$enc = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($stylesPath, $json, $enc)
|
||||
[Console]::Error.WriteLine("Saved skd-styles.json (custom styles: $($script:customStylesAccumulator.Count))")
|
||||
}
|
||||
|
||||
# Extract per-cell width/minHeight/merge from appearance.
|
||||
function Get-CellPerCellAttrs {
|
||||
param($appNode)
|
||||
@@ -875,18 +952,21 @@ function Build-Template {
|
||||
|
||||
# Style detection (skip empty cells with no appearance, and merge cells)
|
||||
if ($appNode -and -not $perCell.mergeV -and -not $perCell.mergeH) {
|
||||
$fp = Get-AppearanceFingerprint $appNode
|
||||
if ($fp.Count -gt 0) {
|
||||
# Ячейка имеет стилевые атрибуты — пробуем match с built-in
|
||||
$cellPreset = Extract-CellPreset $appNode
|
||||
if ($null -ne $cellPreset) {
|
||||
# Ячейка имеет стилевые атрибуты — match против effectivePresets, иначе аллоцируем custom
|
||||
$hasAnyNonEmptyFp = $true
|
||||
$matched = Match-BuiltinStyle $fp
|
||||
$matched = Match-PresetByShape $cellPreset
|
||||
if ($null -eq $matched) {
|
||||
$matched = Allocate-CustomStyle $cellPreset
|
||||
}
|
||||
if ($null -eq $detectedStyle) {
|
||||
$detectedStyle = $matched
|
||||
} elseif ($matched -ne $detectedStyle) {
|
||||
$styleMismatch = $true
|
||||
}
|
||||
}
|
||||
# Пустой fp (только per-cell width/merge) — ячейка без стиля, не контрибутирует.
|
||||
# Если cellPreset = $null — ячейка без стилевых атрибутов (только per-cell width/merge), не контрибутирует.
|
||||
}
|
||||
|
||||
# Drilldown attachment
|
||||
@@ -1448,6 +1528,16 @@ function Try-StructureShorthand {
|
||||
|
||||
# --- 4. dataSources ---
|
||||
|
||||
# Резолв outputPath и загрузка user-стилей до обработки шаблонов
|
||||
$script:outputDir = $null
|
||||
if ($OutputPath) {
|
||||
if (-not [System.IO.Path]::IsPathRooted($OutputPath)) {
|
||||
$OutputPath = Join-Path (Get-Location).Path $OutputPath
|
||||
}
|
||||
$script:outputDir = [System.IO.Path]::GetDirectoryName($OutputPath)
|
||||
Load-UserStyles -dirPath $script:outputDir
|
||||
}
|
||||
|
||||
$dataSources = @()
|
||||
$dsourceNodes = $root.SelectNodes("r:dataSource", $ns)
|
||||
foreach ($dsn in $dsourceNodes) {
|
||||
@@ -1716,11 +1806,9 @@ $json = [regex]::Replace($json, '\\u([0-9a-fA-F]{4})', {
|
||||
})
|
||||
|
||||
if ($OutputPath) {
|
||||
if (-not [System.IO.Path]::IsPathRooted($OutputPath)) {
|
||||
$OutputPath = Join-Path (Get-Location).Path $OutputPath
|
||||
}
|
||||
$enc = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($OutputPath, $json, $enc)
|
||||
Save-UserStyles -dirPath $script:outputDir
|
||||
|
||||
if ($script:warnings.Count -gt 0) {
|
||||
$wPath = [System.IO.Path]::ChangeExtension($OutputPath, $null).TrimEnd('.') + '.warnings.md'
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<DataCompositionSchema xmlns="http://v8.1c.ru/8.1/data-composition-system/schema"
|
||||
xmlns:dcscom="http://v8.1c.ru/8.1/data-composition-system/common"
|
||||
xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core"
|
||||
xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings"
|
||||
xmlns:v8="http://v8.1c.ru/8.1/data/core"
|
||||
xmlns:v8ui="http://v8.1c.ru/8.1/data/ui"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<dataSource>
|
||||
<name>ИсточникДанных1</name>
|
||||
<dataSourceType>Local</dataSourceType>
|
||||
</dataSource>
|
||||
<dataSet xsi:type="DataSetQuery">
|
||||
<name>Тест</name>
|
||||
<field xsi:type="DataSetFieldField">
|
||||
<dataPath>Поле</dataPath>
|
||||
<field>Поле</field>
|
||||
<valueType>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
<v8:Length>0</v8:Length>
|
||||
<v8:AllowedLength>Variable</v8:AllowedLength>
|
||||
</v8:StringQualifiers>
|
||||
</valueType>
|
||||
</field>
|
||||
<dataSource>ИсточникДанных1</dataSource>
|
||||
<query>ВЫБРАТЬ * ИЗ Справочник.Сотрудники</query>
|
||||
</dataSet>
|
||||
<template>
|
||||
<name>Заголовок</name>
|
||||
<template xmlns:dcsat="http://v8.1c.ru/8.1/data-composition-system/area-template" xsi:type="dcsat:AreaTemplate">
|
||||
<dcsat:item xsi:type="dcsat:TableRow">
|
||||
<dcsat:tableCell>
|
||||
<dcsat:item xsi:type="dcsat:Field">
|
||||
<dcsat:value xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>A</v8:content>
|
||||
</v8:item>
|
||||
</dcsat:value>
|
||||
</dcsat:item>
|
||||
<dcsat:appearance>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>ЦветФона</dcscor:parameter>
|
||||
<dcscor:value xmlns:d8p1="http://v8.1c.ru/8.1/data/ui/style" xsi:type="v8ui:Color">d8p1:ReportHeaderBackColor</dcscor:value>
|
||||
</dcscor:item>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>ЦветГраницы</dcscor:parameter>
|
||||
<dcscor:value xmlns:d8p1="http://v8.1c.ru/8.1/data/ui/style" xsi:type="v8ui:Color">d8p1:ReportLineColor</dcscor:value>
|
||||
</dcscor:item>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>СтильГраницы</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8ui:Line" width="0" gap="false">
|
||||
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentCellLineType">None</v8ui:style>
|
||||
</dcscor:value>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>СтильГраницы.Слева</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8ui:Line" width="1" gap="false">
|
||||
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentCellLineType">Solid</v8ui:style>
|
||||
</dcscor:value>
|
||||
</dcscor:item>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>СтильГраницы.Сверху</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8ui:Line" width="1" gap="false">
|
||||
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentCellLineType">Solid</v8ui:style>
|
||||
</dcscor:value>
|
||||
</dcscor:item>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>СтильГраницы.Справа</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8ui:Line" width="1" gap="false">
|
||||
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentCellLineType">Solid</v8ui:style>
|
||||
</dcscor:value>
|
||||
</dcscor:item>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>СтильГраницы.Снизу</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8ui:Line" width="1" gap="false">
|
||||
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentCellLineType">Solid</v8ui:style>
|
||||
</dcscor:value>
|
||||
</dcscor:item>
|
||||
</dcscor:item>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>Шрифт</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8ui:Font" faceName="Calibri" height="11" bold="false" italic="false" underline="false" strikeout="false" kind="Absolute" scale="100"/>
|
||||
</dcscor:item>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>ГоризонтальноеПоложение</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8ui:HorizontalAlign">Center</dcscor:value>
|
||||
</dcscor:item>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>ВертикальноеПоложение</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8ui:VerticalAlign">Center</dcscor:value>
|
||||
</dcscor:item>
|
||||
</dcsat:appearance>
|
||||
</dcsat:tableCell>
|
||||
</dcsat:item>
|
||||
</template>
|
||||
</template>
|
||||
<settingsVariant>
|
||||
<dcsset:name>Основной</dcsset:name>
|
||||
<dcsset:presentation xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Основной</v8:content>
|
||||
</v8:item>
|
||||
</dcsset:presentation>
|
||||
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
|
||||
<dcsset:selection>
|
||||
</dcsset:selection>
|
||||
<dcsset:item xsi:type="dcsset:StructureItemGroup">
|
||||
<dcsset:order>
|
||||
<dcsset:item xsi:type="dcsset:OrderItemAuto"/>
|
||||
</dcsset:order>
|
||||
<dcsset:selection>
|
||||
<dcsset:item xsi:type="dcsset:SelectedItemAuto"/>
|
||||
</dcsset:selection>
|
||||
</dcsset:item>
|
||||
</dcsset:settings>
|
||||
</settingsVariant>
|
||||
</DataCompositionSchema>
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"dataSets": [
|
||||
{
|
||||
"name": "Тест",
|
||||
"query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники",
|
||||
"fields": [
|
||||
"Поле: string"
|
||||
]
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
"name": "Заголовок",
|
||||
"style": "myHeader",
|
||||
"rows": [
|
||||
[
|
||||
"A"
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"myHeader": {
|
||||
"font": "Calibri",
|
||||
"fontSize": 11,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"hAlign": "Center",
|
||||
"vAlign": "Center",
|
||||
"wrap": false,
|
||||
"bgColor": "style:ReportHeaderBackColor",
|
||||
"textColor": null,
|
||||
"borderColor": "style:ReportLineColor",
|
||||
"borders": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "Шаблон с custom стилем (Calibri 11) — переиспользование user preset из skd-styles.json",
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "skd-styles.json",
|
||||
"content": {
|
||||
"myHeader": {
|
||||
"font": "Calibri",
|
||||
"fontSize": 11,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"hAlign": "Center",
|
||||
"vAlign": "Center",
|
||||
"wrap": false,
|
||||
"bgColor": "style:ReportHeaderBackColor",
|
||||
"textColor": null,
|
||||
"borderColor": "style:ReportLineColor",
|
||||
"borders": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"script": "skd-compile/scripts/skd-compile",
|
||||
"input": {
|
||||
"dataSets": [{
|
||||
"name": "Тест",
|
||||
"query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники",
|
||||
"fields": ["Поле: string"]
|
||||
}],
|
||||
"templates": [
|
||||
{ "name": "Заголовок", "style": "myHeader", "rows": [["A"]] }
|
||||
]
|
||||
},
|
||||
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "Template.xml" },
|
||||
"cwd": "{workDir}"
|
||||
}
|
||||
],
|
||||
"params": { "templatePath": "Template.xml" },
|
||||
"outputPath": "decompiled.json"
|
||||
}
|
||||
@@ -517,6 +517,15 @@ async function runCaseAsync(testCase, opts) {
|
||||
// Pre-run steps
|
||||
if (caseData.preRun) {
|
||||
for (const step of caseData.preRun) {
|
||||
// writeFile step — записать произвольный файл в workDir перед запуском скрипта
|
||||
if (step.writeFile) {
|
||||
const wfPath = join(workDir, step.writeFile.path);
|
||||
const wfContent = typeof step.writeFile.content === 'string'
|
||||
? step.writeFile.content
|
||||
: JSON.stringify(step.writeFile.content, null, 2);
|
||||
writeFileSync(wfPath, wfContent, 'utf8');
|
||||
continue;
|
||||
}
|
||||
const preScript = resolveScript(step.script, opts.runtime);
|
||||
const preArgs = [];
|
||||
for (const [flag, value] of Object.entries(step.args || {})) {
|
||||
|
||||
Reference in New Issue
Block a user