mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-15 02:14:57 +03:00
Merge branch 'dev' into feature/web-test-runner
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# form-compile v1.9 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.15 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$JsonPath,
|
||||
@@ -668,6 +668,7 @@ function Generate-DocumentListDSL($meta, [hashtable]$p) {
|
||||
|
||||
$tableEl = [ordered]@{
|
||||
table = "Список"; path = "Список"
|
||||
rowPictureDataPath = "Список.DefaultPicture"
|
||||
commandBarLocation = "None"
|
||||
tableAutofill = $false
|
||||
columns = $columns
|
||||
@@ -1003,6 +1004,7 @@ function Generate-InformationRegisterListDSL($meta, [hashtable]$p) {
|
||||
|
||||
$tableEl = [ordered]@{
|
||||
table = "Список"; path = "Список"
|
||||
rowPictureDataPath = "Список.DefaultPicture"
|
||||
commandBarLocation = "None"
|
||||
tableAutofill = $false
|
||||
columns = $columns
|
||||
@@ -1060,6 +1062,7 @@ function Generate-AccumulationRegisterListDSL($meta, [hashtable]$p) {
|
||||
|
||||
$tableEl = [ordered]@{
|
||||
table = "Список"; path = "Список"
|
||||
rowPictureDataPath = "Список.DefaultPicture"
|
||||
commandBarLocation = "None"
|
||||
tableAutofill = $false
|
||||
columns = $columns
|
||||
@@ -1926,10 +1929,34 @@ function Emit-CommonFlags {
|
||||
if ($el.readOnly -eq $true) { X "$indent<ReadOnly>true</ReadOnly>" }
|
||||
}
|
||||
|
||||
function Title-FromName {
|
||||
param([string]$name)
|
||||
if (-not $name) { return '' }
|
||||
$s = [regex]::Replace($name, '([А-ЯA-Z])([А-ЯA-Z][а-яa-z])', '$1 $2')
|
||||
$s = [regex]::Replace($s, '([а-яa-z0-9])([А-ЯA-Z])', '$1 $2')
|
||||
$parts = $s -split ' '
|
||||
if ($parts.Count -eq 0) { return $s }
|
||||
$out = New-Object System.Collections.ArrayList
|
||||
[void]$out.Add($parts[0])
|
||||
for ($i = 1; $i -lt $parts.Count; $i++) {
|
||||
$p = $parts[$i]
|
||||
if ($p.Length -gt 1 -and $p -ceq $p.ToUpper()) {
|
||||
[void]$out.Add($p)
|
||||
} else {
|
||||
[void]$out.Add($p.ToLower())
|
||||
}
|
||||
}
|
||||
return ($out -join ' ')
|
||||
}
|
||||
|
||||
function Emit-Title {
|
||||
param($el, [string]$name, [string]$indent)
|
||||
if ($el.title) {
|
||||
Emit-MLText -tag "Title" -text "$($el.title)" -indent $indent
|
||||
param($el, [string]$name, [string]$indent, [switch]$auto)
|
||||
$title = $el.title
|
||||
if (-not $title -and $auto -and $name) {
|
||||
$title = Title-FromName -name $name
|
||||
}
|
||||
if ($title) {
|
||||
Emit-MLText -tag "Title" -text "$title" -indent $indent
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2001,7 +2028,7 @@ function Emit-Input {
|
||||
|
||||
if ($el.path) { X "$inner<DataPath>$($el.path)</DataPath>" }
|
||||
|
||||
Emit-Title -el $el -name $name -indent $inner
|
||||
Emit-Title -el $el -name $name -indent $inner -auto:(-not $el.path)
|
||||
Emit-CommonFlags -el $el -indent $inner
|
||||
|
||||
if ($el.titleLocation) {
|
||||
@@ -2024,7 +2051,12 @@ function Emit-Input {
|
||||
if ($el.dropListButton -eq $true) { X "$inner<DropListButton>true</DropListButton>" }
|
||||
if ($el.markIncomplete -eq $true) { X "$inner<AutoMarkIncomplete>true</AutoMarkIncomplete>" }
|
||||
if ($el.skipOnInput -eq $true) { X "$inner<SkipOnInput>true</SkipOnInput>" }
|
||||
if ($el.autoMaxWidth -eq $false) { X "$inner<AutoMaxWidth>false</AutoMaxWidth>" }
|
||||
$hasAmw = $el.PSObject.Properties.Name -contains 'autoMaxWidth'
|
||||
if ($hasAmw) {
|
||||
if ($el.autoMaxWidth -eq $false) { X "$inner<AutoMaxWidth>false</AutoMaxWidth>" }
|
||||
} elseif ($el.multiLine -eq $true) {
|
||||
X "$inner<AutoMaxWidth>false</AutoMaxWidth>"
|
||||
}
|
||||
if ($el.autoMaxHeight -eq $false) { X "$inner<AutoMaxHeight>false</AutoMaxHeight>" }
|
||||
if ($el.width) { X "$inner<Width>$($el.width)</Width>" }
|
||||
if ($el.height) { X "$inner<Height>$($el.height)</Height>" }
|
||||
@@ -2052,12 +2084,11 @@ function Emit-Check {
|
||||
|
||||
if ($el.path) { X "$inner<DataPath>$($el.path)</DataPath>" }
|
||||
|
||||
Emit-Title -el $el -name $name -indent $inner
|
||||
Emit-Title -el $el -name $name -indent $inner -auto:(-not $el.path)
|
||||
Emit-CommonFlags -el $el -indent $inner
|
||||
|
||||
if ($el.titleLocation) {
|
||||
X "$inner<TitleLocation>$($el.titleLocation)</TitleLocation>"
|
||||
}
|
||||
$tl = if ($el.titleLocation) { "$($el.titleLocation)" } else { "Right" }
|
||||
X "$inner<TitleLocation>$tl</TitleLocation>"
|
||||
|
||||
# Companions
|
||||
Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner
|
||||
@@ -2074,12 +2105,13 @@ function Emit-Label {
|
||||
X "$indent<LabelDecoration name=`"$name`" id=`"$id`">"
|
||||
$inner = "$indent`t"
|
||||
|
||||
if ($el.title) {
|
||||
$labelTitle = if ($el.title) { "$($el.title)" } else { Title-FromName -name $name }
|
||||
if ($labelTitle) {
|
||||
$formatted = if ($el.hyperlink -eq $true) { "true" } else { "false" }
|
||||
X "$inner<Title formatted=`"$formatted`">"
|
||||
X "$inner`t<v8:item>"
|
||||
X "$inner`t`t<v8:lang>ru</v8:lang>"
|
||||
X "$inner`t`t<v8:content>$(Esc-Xml "$($el.title)")</v8:content>"
|
||||
X "$inner`t`t<v8:content>$(Esc-Xml "$labelTitle")</v8:content>"
|
||||
X "$inner`t</v8:item>"
|
||||
X "$inner</Title>"
|
||||
}
|
||||
@@ -2109,7 +2141,7 @@ function Emit-LabelField {
|
||||
|
||||
if ($el.path) { X "$inner<DataPath>$($el.path)</DataPath>" }
|
||||
|
||||
Emit-Title -el $el -name $name -indent $inner
|
||||
Emit-Title -el $el -name $name -indent $inner -auto:(-not $el.path)
|
||||
Emit-CommonFlags -el $el -indent $inner
|
||||
|
||||
if ($el.hyperlink -eq $true) { X "$inner<Hyperlink>true</Hyperlink>" }
|
||||
@@ -2131,7 +2163,7 @@ function Emit-Table {
|
||||
|
||||
if ($el.path) { X "$inner<DataPath>$($el.path)</DataPath>" }
|
||||
|
||||
Emit-Title -el $el -name $name -indent $inner
|
||||
Emit-Title -el $el -name $name -indent $inner -auto:(-not $el.path)
|
||||
Emit-CommonFlags -el $el -indent $inner
|
||||
|
||||
if ($el.representation) {
|
||||
@@ -2220,7 +2252,7 @@ function Emit-Page {
|
||||
X "$indent<Page name=`"$name`" id=`"$id`">"
|
||||
$inner = "$indent`t"
|
||||
|
||||
Emit-Title -el $el -name $name -indent $inner
|
||||
Emit-Title -el $el -name $name -indent $inner -auto
|
||||
Emit-CommonFlags -el $el -indent $inner
|
||||
|
||||
if ($el.group) {
|
||||
@@ -2279,7 +2311,8 @@ function Emit-Button {
|
||||
}
|
||||
}
|
||||
|
||||
Emit-Title -el $el -name $name -indent $inner
|
||||
$btnAuto = -not ($el.command -or $el.stdCommand)
|
||||
Emit-Title -el $el -name $name -indent $inner -auto:$btnAuto
|
||||
Emit-CommonFlags -el $el -indent $inner
|
||||
|
||||
if ($el.defaultButton -eq $true) { X "$inner<DefaultButton>true</DefaultButton>" }
|
||||
@@ -2369,7 +2402,7 @@ function Emit-Calendar {
|
||||
|
||||
if ($el.path) { X "$inner<DataPath>$($el.path)</DataPath>" }
|
||||
|
||||
Emit-Title -el $el -name $name -indent $inner
|
||||
Emit-Title -el $el -name $name -indent $inner -auto:(-not $el.path)
|
||||
Emit-CommonFlags -el $el -indent $inner
|
||||
|
||||
# Companions
|
||||
@@ -2409,7 +2442,7 @@ function Emit-Popup {
|
||||
X "$indent<Popup name=`"$name`" id=`"$id`">"
|
||||
$inner = "$indent`t"
|
||||
|
||||
Emit-Title -el $el -name $name -indent $inner
|
||||
Emit-Title -el $el -name $name -indent $inner -auto
|
||||
Emit-CommonFlags -el $el -indent $inner
|
||||
|
||||
if ($el.picture) {
|
||||
@@ -2450,8 +2483,9 @@ function Emit-Attributes {
|
||||
X "$indent`t<Attribute name=`"$attrName`" id=`"$attrId`">"
|
||||
$inner = "$indent`t`t"
|
||||
|
||||
if ($attr.title) {
|
||||
Emit-MLText -tag "Title" -text "$($attr.title)" -indent $inner
|
||||
$attrTitle = if ($attr.title) { "$($attr.title)" } elseif ($attr.main -ne $true) { Title-FromName -name $attrName } else { '' }
|
||||
if ($attrTitle) {
|
||||
Emit-MLText -tag "Title" -text "$attrTitle" -indent $inner
|
||||
}
|
||||
|
||||
# Type
|
||||
@@ -2464,7 +2498,11 @@ function Emit-Attributes {
|
||||
if ($attr.main -eq $true) {
|
||||
X "$inner<MainAttribute>true</MainAttribute>"
|
||||
}
|
||||
if ($attr.savedData -eq $true) {
|
||||
$mainSaved = $false
|
||||
if ($attr.main -eq $true -and $attr.type) {
|
||||
$mainSaved = ("$($attr.type)") -match '^(CatalogObject|DocumentObject|ChartOfAccountsObject|ChartOfCalculationTypesObject|ChartOfCharacteristicTypesObject|ExchangePlanObject|BusinessProcessObject|TaskObject)\.' -or ("$($attr.type)") -match 'RecordManager\.'
|
||||
}
|
||||
if ($attr.savedData -eq $true -or $mainSaved) {
|
||||
X "$inner<SavedData>true</SavedData>"
|
||||
}
|
||||
if ($attr.fillChecking) {
|
||||
@@ -2539,8 +2577,9 @@ function Emit-Commands {
|
||||
X "$indent`t<Command name=`"$($cmd.name)`" id=`"$cmdId`">"
|
||||
$inner = "$indent`t`t"
|
||||
|
||||
if ($cmd.title) {
|
||||
Emit-MLText -tag "Title" -text "$($cmd.title)" -indent $inner
|
||||
$cmdTitle = if ($cmd.title) { "$($cmd.title)" } else { Title-FromName -name "$($cmd.name)" }
|
||||
if ($cmdTitle) {
|
||||
Emit-MLText -tag "Title" -text "$cmdTitle" -indent $inner
|
||||
}
|
||||
|
||||
if ($cmd.action) {
|
||||
@@ -2649,7 +2688,7 @@ function HasCmdBarRecursive {
|
||||
}
|
||||
|
||||
function ApplyDynamicListTableHeuristic {
|
||||
param($el, [string]$listName)
|
||||
param($el, [string]$listName, [bool]$hasMainTable)
|
||||
if ($null -eq $el) { return }
|
||||
if ($el.PSObject.Properties["table"] -and $null -ne $el.table -and "$($el.path)" -eq $listName) {
|
||||
if ($null -eq $el.PSObject.Properties["tableAutofill"]) {
|
||||
@@ -2658,9 +2697,13 @@ function ApplyDynamicListTableHeuristic {
|
||||
if ($null -eq $el.PSObject.Properties["commandBarLocation"]) {
|
||||
$el | Add-Member -NotePropertyName "commandBarLocation" -NotePropertyValue "None" -Force
|
||||
}
|
||||
# DefaultPicture доступен только если у DynamicList есть основная таблица
|
||||
if ($hasMainTable -and ($null -eq $el.PSObject.Properties["rowPictureDataPath"] -or [string]::IsNullOrEmpty("$($el.rowPictureDataPath)"))) {
|
||||
$el | Add-Member -NotePropertyName "rowPictureDataPath" -NotePropertyValue "$listName.DefaultPicture" -Force
|
||||
}
|
||||
}
|
||||
if ($el.PSObject.Properties["children"] -and $el.children) {
|
||||
foreach ($child in $el.children) { ApplyDynamicListTableHeuristic $child $listName }
|
||||
foreach ($child in $el.children) { ApplyDynamicListTableHeuristic $child $listName $hasMainTable }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2749,8 +2792,17 @@ if ($def.attributes -and $def.elements) {
|
||||
if ($attr.main -eq $true) { $mainAttr = $attr; break }
|
||||
}
|
||||
if ($mainAttr -and "$($mainAttr.type)" -eq "DynamicList") {
|
||||
$mt = $null
|
||||
if ($mainAttr.PSObject.Properties["settings"] -and $null -ne $mainAttr.settings) {
|
||||
if ($mainAttr.settings -is [hashtable]) {
|
||||
if ($mainAttr.settings.ContainsKey("mainTable")) { $mt = $mainAttr.settings["mainTable"] }
|
||||
} elseif ($mainAttr.settings.PSObject.Properties["mainTable"]) {
|
||||
$mt = $mainAttr.settings.mainTable
|
||||
}
|
||||
}
|
||||
$hasMt = -not [string]::IsNullOrEmpty("$mt")
|
||||
foreach ($el in $def.elements) {
|
||||
ApplyDynamicListTableHeuristic $el $mainAttr.name
|
||||
ApplyDynamicListTableHeuristic $el $mainAttr.name $hasMt
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2802,17 +2854,26 @@ if ($formTitle) {
|
||||
}
|
||||
|
||||
# 12b. Properties (skip 'title' — handled above as multilingual)
|
||||
# When form-level Title is set, default autoTitle=false (≈95% of ERP forms do this;
|
||||
# otherwise platform appends synonym → "Title: Synonym" double-titles).
|
||||
$propsClone = New-Object PSObject
|
||||
$hasAutoTitle = $false
|
||||
if ($def.properties) {
|
||||
foreach ($p in $def.properties.PSObject.Properties) {
|
||||
if ($p.Name -eq "autoTitle") { $hasAutoTitle = $true }
|
||||
}
|
||||
}
|
||||
if ($formTitle -and -not $hasAutoTitle) {
|
||||
$propsClone | Add-Member -NotePropertyName "autoTitle" -NotePropertyValue $false
|
||||
}
|
||||
if ($def.properties) {
|
||||
$propsClone = New-Object PSObject
|
||||
foreach ($p in $def.properties.PSObject.Properties) {
|
||||
if ($p.Name -ne "title") {
|
||||
$propsClone | Add-Member -NotePropertyName $p.Name -NotePropertyValue $p.Value
|
||||
}
|
||||
}
|
||||
Emit-Properties -props $propsClone -indent "`t"
|
||||
} else {
|
||||
Emit-Properties -props $null -indent "`t"
|
||||
}
|
||||
Emit-Properties -props $propsClone -indent "`t"
|
||||
|
||||
# 12c. CommandSet (excluded commands)
|
||||
if ($def.excludedCommands -and $def.excludedCommands.Count -gt 0) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# form-compile v1.9 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.15 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import copy
|
||||
@@ -625,6 +625,7 @@ def generate_document_list_dsl(meta, p):
|
||||
|
||||
table_el = OrderedDict([
|
||||
('table', '\u0421\u043f\u0438\u0441\u043e\u043a'), ('path', '\u0421\u043f\u0438\u0441\u043e\u043a'),
|
||||
('rowPictureDataPath', '\u0421\u043f\u0438\u0441\u043e\u043a.DefaultPicture'),
|
||||
('commandBarLocation', 'None'),
|
||||
('tableAutofill', False),
|
||||
('columns', columns),
|
||||
@@ -938,6 +939,7 @@ def generate_information_register_list_dsl(meta, p):
|
||||
table_el = OrderedDict([
|
||||
('table', '\u0421\u043f\u0438\u0441\u043e\u043a'),
|
||||
('path', '\u0421\u043f\u0438\u0441\u043e\u043a'),
|
||||
('rowPictureDataPath', '\u0421\u043f\u0438\u0441\u043e\u043a.DefaultPicture'),
|
||||
('commandBarLocation', 'None'),
|
||||
('tableAutofill', False),
|
||||
('columns', columns_list),
|
||||
@@ -996,6 +998,7 @@ def generate_accumulation_register_list_dsl(meta, p):
|
||||
table_el = OrderedDict([
|
||||
('table', '\u0421\u043f\u0438\u0441\u043e\u043a'),
|
||||
('path', '\u0421\u043f\u0438\u0441\u043e\u043a'),
|
||||
('rowPictureDataPath', '\u0421\u043f\u0438\u0441\u043e\u043a.DefaultPicture'),
|
||||
('commandBarLocation', 'None'),
|
||||
('tableAutofill', False),
|
||||
('columns', columns_list),
|
||||
@@ -1414,9 +1417,27 @@ def emit_common_flags(lines, el, indent):
|
||||
lines.append(f"{indent}<ReadOnly>true</ReadOnly>")
|
||||
|
||||
|
||||
def emit_title(lines, el, name, indent):
|
||||
if el.get('title'):
|
||||
emit_mltext(lines, indent, 'Title', str(el['title']))
|
||||
def title_from_name(name):
|
||||
"""СуммаДокумента → 'Сумма документа'. НДСВключен → 'НДС включен'."""
|
||||
if not name:
|
||||
return ''
|
||||
s = re.sub(r'([А-ЯA-Z])([А-ЯA-Z][а-яa-z])', r'\1 \2', name)
|
||||
s = re.sub(r'([а-яa-z0-9])([А-ЯA-Z])', r'\1 \2', s)
|
||||
parts = s.split(' ')
|
||||
if not parts:
|
||||
return s
|
||||
out = [parts[0]]
|
||||
for p in parts[1:]:
|
||||
out.append(p if (len(p) > 1 and p.isupper()) else p.lower())
|
||||
return ' '.join(out)
|
||||
|
||||
|
||||
def emit_title(lines, el, name, indent, auto=False):
|
||||
title = el.get('title')
|
||||
if not title and auto and name:
|
||||
title = title_from_name(name)
|
||||
if title:
|
||||
emit_mltext(lines, indent, 'Title', str(title))
|
||||
|
||||
|
||||
# --- Type emitter ---
|
||||
@@ -1712,7 +1733,7 @@ def emit_input(lines, el, name, eid, indent):
|
||||
if el.get('path'):
|
||||
lines.append(f'{inner}<DataPath>{el["path"]}</DataPath>')
|
||||
|
||||
emit_title(lines, el, name, inner)
|
||||
emit_title(lines, el, name, inner, auto=not el.get('path'))
|
||||
emit_common_flags(lines, el, inner)
|
||||
|
||||
if el.get('titleLocation'):
|
||||
@@ -1736,7 +1757,10 @@ def emit_input(lines, el, name, eid, indent):
|
||||
lines.append(f'{inner}<AutoMarkIncomplete>true</AutoMarkIncomplete>')
|
||||
if el.get('skipOnInput') is True:
|
||||
lines.append(f'{inner}<SkipOnInput>true</SkipOnInput>')
|
||||
if el.get('autoMaxWidth') is False:
|
||||
if 'autoMaxWidth' in el:
|
||||
if el['autoMaxWidth'] is False:
|
||||
lines.append(f'{inner}<AutoMaxWidth>false</AutoMaxWidth>')
|
||||
elif el.get('multiLine') is True:
|
||||
lines.append(f'{inner}<AutoMaxWidth>false</AutoMaxWidth>')
|
||||
if el.get('autoMaxHeight') is False:
|
||||
lines.append(f'{inner}<AutoMaxHeight>false</AutoMaxHeight>')
|
||||
@@ -1768,11 +1792,11 @@ def emit_check(lines, el, name, eid, indent):
|
||||
if el.get('path'):
|
||||
lines.append(f'{inner}<DataPath>{el["path"]}</DataPath>')
|
||||
|
||||
emit_title(lines, el, name, inner)
|
||||
emit_title(lines, el, name, inner, auto=not el.get('path'))
|
||||
emit_common_flags(lines, el, inner)
|
||||
|
||||
if el.get('titleLocation'):
|
||||
lines.append(f'{inner}<TitleLocation>{el["titleLocation"]}</TitleLocation>')
|
||||
tl = el.get('titleLocation') or 'Right'
|
||||
lines.append(f'{inner}<TitleLocation>{tl}</TitleLocation>')
|
||||
|
||||
# Companions
|
||||
emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner)
|
||||
@@ -1787,12 +1811,13 @@ def emit_label(lines, el, name, eid, indent):
|
||||
lines.append(f'{indent}<LabelDecoration name="{name}" id="{eid}">')
|
||||
inner = f'{indent}\t'
|
||||
|
||||
if el.get('title'):
|
||||
label_title = el.get('title') or title_from_name(name)
|
||||
if label_title:
|
||||
formatted = 'true' if el.get('hyperlink') is True else 'false'
|
||||
lines.append(f'{inner}<Title formatted="{formatted}">')
|
||||
lines.append(f'{inner}\t<v8:item>')
|
||||
lines.append(f'{inner}\t\t<v8:lang>ru</v8:lang>')
|
||||
lines.append(f'{inner}\t\t<v8:content>{esc_xml(str(el["title"]))}</v8:content>')
|
||||
lines.append(f'{inner}\t\t<v8:content>{esc_xml(str(label_title))}</v8:content>')
|
||||
lines.append(f'{inner}\t</v8:item>')
|
||||
lines.append(f'{inner}</Title>')
|
||||
|
||||
@@ -1825,7 +1850,7 @@ def emit_label_field(lines, el, name, eid, indent):
|
||||
if el.get('path'):
|
||||
lines.append(f'{inner}<DataPath>{el["path"]}</DataPath>')
|
||||
|
||||
emit_title(lines, el, name, inner)
|
||||
emit_title(lines, el, name, inner, auto=not el.get('path'))
|
||||
emit_common_flags(lines, el, inner)
|
||||
|
||||
if el.get('hyperlink') is True:
|
||||
@@ -1847,7 +1872,7 @@ def emit_table(lines, el, name, eid, indent):
|
||||
if el.get('path'):
|
||||
lines.append(f'{inner}<DataPath>{el["path"]}</DataPath>')
|
||||
|
||||
emit_title(lines, el, name, inner)
|
||||
emit_title(lines, el, name, inner, auto=not el.get('path'))
|
||||
emit_common_flags(lines, el, inner)
|
||||
|
||||
if el.get('representation'):
|
||||
@@ -1935,7 +1960,7 @@ def emit_page(lines, el, name, eid, indent):
|
||||
lines.append(f'{indent}<Page name="{name}" id="{eid}">')
|
||||
inner = f'{indent}\t'
|
||||
|
||||
emit_title(lines, el, name, inner)
|
||||
emit_title(lines, el, name, inner, auto=True)
|
||||
emit_common_flags(lines, el, inner)
|
||||
|
||||
if el.get('group'):
|
||||
@@ -1983,7 +2008,7 @@ def emit_button(lines, el, name, eid, indent):
|
||||
else:
|
||||
lines.append(f'{inner}<CommandName>Form.StandardCommand.{sc}</CommandName>')
|
||||
|
||||
emit_title(lines, el, name, inner)
|
||||
emit_title(lines, el, name, inner, auto=not (el.get('command') or el.get('stdCommand')))
|
||||
emit_common_flags(lines, el, inner)
|
||||
|
||||
if el.get('defaultButton') is True:
|
||||
@@ -2071,7 +2096,7 @@ def emit_calendar(lines, el, name, eid, indent):
|
||||
if el.get('path'):
|
||||
lines.append(f'{inner}<DataPath>{el["path"]}</DataPath>')
|
||||
|
||||
emit_title(lines, el, name, inner)
|
||||
emit_title(lines, el, name, inner, auto=not el.get('path'))
|
||||
emit_common_flags(lines, el, inner)
|
||||
|
||||
# Companions
|
||||
@@ -2106,7 +2131,7 @@ def emit_popup(lines, el, name, eid, indent):
|
||||
lines.append(f'{indent}<Popup name="{name}" id="{eid}">')
|
||||
inner = f'{indent}\t'
|
||||
|
||||
emit_title(lines, el, name, inner)
|
||||
emit_title(lines, el, name, inner, auto=True)
|
||||
emit_common_flags(lines, el, inner)
|
||||
|
||||
if el.get('picture'):
|
||||
@@ -2142,8 +2167,11 @@ def emit_attributes(lines, attrs, indent):
|
||||
lines.append(f'{indent}\t<Attribute name="{attr_name}" id="{attr_id}">')
|
||||
inner = f'{indent}\t\t'
|
||||
|
||||
if attr.get('title'):
|
||||
emit_mltext(lines, inner, 'Title', str(attr['title']))
|
||||
attr_title = attr.get('title')
|
||||
if not attr_title and attr.get('main') is not True:
|
||||
attr_title = title_from_name(attr_name)
|
||||
if attr_title:
|
||||
emit_mltext(lines, inner, 'Title', str(attr_title))
|
||||
|
||||
# Type
|
||||
if attr.get('type'):
|
||||
@@ -2153,7 +2181,11 @@ def emit_attributes(lines, attrs, indent):
|
||||
|
||||
if attr.get('main') is True:
|
||||
lines.append(f'{inner}<MainAttribute>true</MainAttribute>')
|
||||
if attr.get('savedData') is True:
|
||||
main_saved = False
|
||||
if attr.get('main') is True and attr.get('type'):
|
||||
t = str(attr['type'])
|
||||
main_saved = bool(re.match(r'^(CatalogObject|DocumentObject|ChartOfAccountsObject|ChartOfCalculationTypesObject|ChartOfCharacteristicTypesObject|ExchangePlanObject|BusinessProcessObject|TaskObject)\.', t)) or ('RecordManager.' in t)
|
||||
if attr.get('savedData') is True or main_saved:
|
||||
lines.append(f'{inner}<SavedData>true</SavedData>')
|
||||
if attr.get('fillChecking'):
|
||||
lines.append(f'{inner}<FillChecking>{attr["fillChecking"]}</FillChecking>')
|
||||
@@ -2219,8 +2251,9 @@ def emit_commands(lines, cmds, indent):
|
||||
lines.append(f'{indent}\t<Command name="{cmd["name"]}" id="{cmd_id}">')
|
||||
inner = f'{indent}\t\t'
|
||||
|
||||
if cmd.get('title'):
|
||||
emit_mltext(lines, inner, 'Title', str(cmd['title']))
|
||||
cmd_title = cmd.get('title') or title_from_name(str(cmd['name']))
|
||||
if cmd_title:
|
||||
emit_mltext(lines, inner, 'Title', str(cmd_title))
|
||||
|
||||
if cmd.get('action'):
|
||||
lines.append(f'{inner}<Action>{cmd["action"]}</Action>')
|
||||
@@ -2572,7 +2605,7 @@ def main():
|
||||
return True
|
||||
return False
|
||||
|
||||
def _apply_dlist_table_heuristic(el, list_name):
|
||||
def _apply_dlist_table_heuristic(el, list_name, has_main_table):
|
||||
if not isinstance(el, dict):
|
||||
return
|
||||
if el.get('table') is not None and str(el.get('path', '')) == list_name:
|
||||
@@ -2580,9 +2613,12 @@ def main():
|
||||
el['tableAutofill'] = False
|
||||
if 'commandBarLocation' not in el:
|
||||
el['commandBarLocation'] = 'None'
|
||||
# DefaultPicture доступен только если у DynamicList есть основная таблица
|
||||
if has_main_table and not el.get('rowPictureDataPath'):
|
||||
el['rowPictureDataPath'] = f'{list_name}.DefaultPicture'
|
||||
if isinstance(el.get('children'), list):
|
||||
for child in el['children']:
|
||||
_apply_dlist_table_heuristic(child, list_name)
|
||||
_apply_dlist_table_heuristic(child, list_name, has_main_table)
|
||||
|
||||
def _is_object_like_type(t):
|
||||
if not t:
|
||||
@@ -2647,8 +2683,10 @@ def main():
|
||||
if isinstance(defn.get('attributes'), list) and isinstance(defn.get('elements'), list):
|
||||
main_attr = next((a for a in defn['attributes'] if isinstance(a, dict) and a.get('main') is True), None)
|
||||
if main_attr and str(main_attr.get('type', '')) == 'DynamicList':
|
||||
settings = main_attr.get('settings') or {}
|
||||
has_mt = bool(isinstance(settings, dict) and settings.get('mainTable'))
|
||||
for el in defn['elements']:
|
||||
_apply_dlist_table_heuristic(el, main_attr.get('name', ''))
|
||||
_apply_dlist_table_heuristic(el, main_attr.get('name', ''), has_mt)
|
||||
|
||||
# 1b.5: Compute main AutoCommandBar Autofill (B3)
|
||||
def _compute_main_acb_autofill():
|
||||
@@ -2677,9 +2715,16 @@ def main():
|
||||
emit_mltext(lines, '\t', 'Title', str(form_title))
|
||||
|
||||
# Properties (skip 'title' — handled above)
|
||||
if defn.get('properties'):
|
||||
props_clone = {k: v for k, v in defn['properties'].items() if k != 'title'}
|
||||
emit_properties(lines, props_clone, '\t')
|
||||
# When form-level Title is set, default autoTitle=false (≈95% of ERP forms do this;
|
||||
# otherwise platform appends synonym → "Title: Synonym" double-titles).
|
||||
props_src = defn.get('properties') or {}
|
||||
props_clone = OrderedDict()
|
||||
if form_title and 'autoTitle' not in props_src:
|
||||
props_clone['autoTitle'] = False
|
||||
for k, v in props_src.items():
|
||||
if k != 'title':
|
||||
props_clone[k] = v
|
||||
emit_properties(lines, props_clone, '\t')
|
||||
|
||||
# CommandSet (excluded commands)
|
||||
if defn.get('excludedCommands') and len(defn['excludedCommands']) > 0:
|
||||
|
||||
+15
-1
@@ -14,10 +14,23 @@ node tests/skills/runner.mjs --verbose # подробн
|
||||
node tests/skills/runner.mjs --update-snapshots # обновить эталоны
|
||||
node tests/skills/runner.mjs --runtime python # запуск на PY-версиях
|
||||
node tests/skills/runner.mjs --json report.json # JSON-отчёт
|
||||
node tests/skills/runner.mjs --concurrency 4 # ограничить параллельность
|
||||
node tests/skills/runner.mjs --with-validation # + платформенная валидация
|
||||
node tests/skills/runner.mjs --help # полный список опций
|
||||
```
|
||||
|
||||
Exit code: 0 = все прошли, 1 = есть падения.
|
||||
|
||||
### Платформенная верификация снапшотов
|
||||
|
||||
```bash
|
||||
node tests/skills/verify-snapshots.mjs --skill form-compile # один навык
|
||||
node tests/skills/verify-snapshots.mjs --case table # один кейс
|
||||
node tests/skills/verify-snapshots.mjs --help # полный список опций
|
||||
```
|
||||
|
||||
Перепрогоняет навык из DSL кейса и грузит результат в 1С — отлавливает случаи, когда снапшоты обновили, но платформа уже не принимает выход.
|
||||
|
||||
## Что делать при падении
|
||||
|
||||
1. Смотри **case id** в выводе — это путь к файлу кейса (можно перезапустить: `node runner.mjs <case-id>`)
|
||||
@@ -194,7 +207,8 @@ node tests/skills/runner.mjs cases/meta-compile/enum --update-snapshots # од
|
||||
|
||||
```
|
||||
tests/skills/
|
||||
runner.mjs # тест-раннер
|
||||
runner.mjs # тест-раннер (snapshot-сравнение)
|
||||
verify-snapshots.mjs # платформенная верификация снапшотов
|
||||
README.md # этот файл
|
||||
.cache/ # кэш фикстур (в .gitignore)
|
||||
cases/
|
||||
|
||||
+2
@@ -6,11 +6,13 @@
|
||||
<v8:content>Денежные средства</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<Table name="Список" id="1">
|
||||
<DataPath>Список</DataPath>
|
||||
<CommandBarLocation>None</CommandBarLocation>
|
||||
<RowPictureDataPath>Список.DefaultPicture</RowPictureDataPath>
|
||||
<ContextMenu name="СписокКонтекстноеМеню" id="2"/>
|
||||
<AutoCommandBar name="СписокКоманднаяПанель" id="3">
|
||||
<Autofill>false</Autofill>
|
||||
|
||||
+3
@@ -6,6 +6,7 @@
|
||||
<v8:content>Валюты</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<UsualGroup name="ГруппаШапка" id="1">
|
||||
@@ -34,6 +35,7 @@
|
||||
</UsualGroup>
|
||||
<CheckBoxField name="ЗагружаетсяИзИнтернета" id="11">
|
||||
<DataPath>Объект.ЗагружаетсяИзИнтернета</DataPath>
|
||||
<TitleLocation>Right</TitleLocation>
|
||||
<ContextMenu name="ЗагружаетсяИзИнтернетаКонтекстноеМеню" id="12"/>
|
||||
<ExtendedTooltip name="ЗагружаетсяИзИнтернетаРасширеннаяПодсказка" id="13"/>
|
||||
</CheckBoxField>
|
||||
@@ -80,6 +82,7 @@
|
||||
<v8:Type>cfg:CatalogObject.Валюты</v8:Type>
|
||||
</Type>
|
||||
<MainAttribute>true</MainAttribute>
|
||||
<SavedData>true</SavedData>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Form>
|
||||
|
||||
+1
@@ -6,6 +6,7 @@
|
||||
<v8:content>Валюты</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<Table name="Список" id="1">
|
||||
|
||||
+2
@@ -6,6 +6,7 @@
|
||||
<v8:content>Виды номенклатуры</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<UsualGroup name="ГруппаШапка" id="1">
|
||||
@@ -50,6 +51,7 @@
|
||||
<v8:Type>cfg:ChartOfCharacteristicTypesObject.ВидыНоменклатуры</v8:Type>
|
||||
</Type>
|
||||
<MainAttribute>true</MainAttribute>
|
||||
<SavedData>true</SavedData>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Form>
|
||||
|
||||
+7
@@ -6,6 +6,7 @@
|
||||
<v8:content>Хозрасчетный</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<UsualGroup name="ГруппаШапка" id="1">
|
||||
@@ -53,6 +54,7 @@
|
||||
</InputField>
|
||||
<CheckBoxField name="Забалансовый" id="16">
|
||||
<DataPath>Объект.OffBalance</DataPath>
|
||||
<TitleLocation>Right</TitleLocation>
|
||||
<ContextMenu name="ЗабалансовыйКонтекстноеМеню" id="17"/>
|
||||
<ExtendedTooltip name="ЗабалансовыйРасширеннаяПодсказка" id="18"/>
|
||||
</CheckBoxField>
|
||||
@@ -68,11 +70,13 @@
|
||||
<ChildItems>
|
||||
<CheckBoxField name="Валютный" id="21">
|
||||
<DataPath>Объект.Валютный</DataPath>
|
||||
<TitleLocation>Right</TitleLocation>
|
||||
<ContextMenu name="ВалютныйКонтекстноеМеню" id="22"/>
|
||||
<ExtendedTooltip name="ВалютныйРасширеннаяПодсказка" id="23"/>
|
||||
</CheckBoxField>
|
||||
<CheckBoxField name="Количественный" id="24">
|
||||
<DataPath>Объект.Количественный</DataPath>
|
||||
<TitleLocation>Right</TitleLocation>
|
||||
<ContextMenu name="КоличественныйКонтекстноеМеню" id="25"/>
|
||||
<ExtendedTooltip name="КоличественныйРасширеннаяПодсказка" id="26"/>
|
||||
</CheckBoxField>
|
||||
@@ -93,16 +97,19 @@
|
||||
</InputField>
|
||||
<CheckBoxField name="ТолькоОбороты" id="36">
|
||||
<DataPath>Объект.ExtDimensionTypes.TurnoversOnly</DataPath>
|
||||
<TitleLocation>Right</TitleLocation>
|
||||
<ContextMenu name="ТолькоОборотыКонтекстноеМеню" id="37"/>
|
||||
<ExtendedTooltip name="ТолькоОборотыРасширеннаяПодсказка" id="38"/>
|
||||
</CheckBoxField>
|
||||
<CheckBoxField name="Валютный" id="39">
|
||||
<DataPath>Объект.ExtDimensionTypes.Валютный</DataPath>
|
||||
<TitleLocation>Right</TitleLocation>
|
||||
<ContextMenu name="ВалютныйКонтекстноеМеню" id="40"/>
|
||||
<ExtendedTooltip name="ВалютныйРасширеннаяПодсказка" id="41"/>
|
||||
</CheckBoxField>
|
||||
<CheckBoxField name="Количественный" id="42">
|
||||
<DataPath>Объект.ExtDimensionTypes.Количественный</DataPath>
|
||||
<TitleLocation>Right</TitleLocation>
|
||||
<ContextMenu name="КоличественныйКонтекстноеМеню" id="43"/>
|
||||
<ExtendedTooltip name="КоличественныйРасширеннаяПодсказка" id="44"/>
|
||||
</CheckBoxField>
|
||||
|
||||
+1
@@ -6,6 +6,7 @@
|
||||
<v8:content>Хозрасчетный</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<Table name="Список" id="1">
|
||||
|
||||
+2
@@ -111,6 +111,7 @@
|
||||
</InputField>
|
||||
<CheckBoxField name="Исправление" id="46">
|
||||
<DataPath>Объект.Исправление</DataPath>
|
||||
<TitleLocation>Right</TitleLocation>
|
||||
<ContextMenu name="ИсправлениеКонтекстноеМеню" id="47"/>
|
||||
<ExtendedTooltip name="ИсправлениеРасширеннаяПодсказка" id="48"/>
|
||||
</CheckBoxField>
|
||||
@@ -242,6 +243,7 @@
|
||||
<v8:Type>cfg:DocumentObject.АктВыполненныхВнутреннихРабот</v8:Type>
|
||||
</Type>
|
||||
<MainAttribute>true</MainAttribute>
|
||||
<SavedData>true</SavedData>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Form>
|
||||
|
||||
+2
@@ -6,11 +6,13 @@
|
||||
<v8:content>Акт выполненных внутренних работ</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<Table name="Список" id="1">
|
||||
<DataPath>Список</DataPath>
|
||||
<CommandBarLocation>None</CommandBarLocation>
|
||||
<RowPictureDataPath>Список.DefaultPicture</RowPictureDataPath>
|
||||
<ContextMenu name="СписокКонтекстноеМеню" id="2"/>
|
||||
<AutoCommandBar name="СписокКоманднаяПанель" id="3">
|
||||
<Autofill>false</Autofill>
|
||||
|
||||
+2
@@ -6,6 +6,7 @@
|
||||
<v8:content>Обмен данными</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<UsualGroup name="ГруппаШапка" id="1">
|
||||
@@ -67,6 +68,7 @@
|
||||
<v8:Type>cfg:ExchangePlanObject.ОбменДанными</v8:Type>
|
||||
</Type>
|
||||
<MainAttribute>true</MainAttribute>
|
||||
<SavedData>true</SavedData>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Form>
|
||||
|
||||
+2
@@ -6,11 +6,13 @@
|
||||
<v8:content>Цены номенклатуры</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<Table name="Список" id="1">
|
||||
<DataPath>Список</DataPath>
|
||||
<CommandBarLocation>None</CommandBarLocation>
|
||||
<RowPictureDataPath>Список.DefaultPicture</RowPictureDataPath>
|
||||
<ContextMenu name="СписокКонтекстноеМеню" id="2"/>
|
||||
<AutoCommandBar name="СписокКоманднаяПанель" id="3">
|
||||
<Autofill>false</Autofill>
|
||||
|
||||
+1
@@ -6,6 +6,7 @@
|
||||
<v8:content>Адреса магазинов</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<WindowOpeningMode>LockOwnerWindow</WindowOpeningMode>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
|
||||
+1
@@ -6,6 +6,7 @@
|
||||
<v8:content>Курсы валют</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<WindowOpeningMode>LockOwnerWindow</WindowOpeningMode>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
|
||||
+25
@@ -6,6 +6,7 @@
|
||||
<v8:content>Разные типы</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<InputField name="Строка" id="1">
|
||||
@@ -37,6 +38,12 @@
|
||||
<MainAttribute>true</MainAttribute>
|
||||
</Attribute>
|
||||
<Attribute name="Строка" id="14">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Строка</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -46,6 +53,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="Число" id="15">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Число</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:decimal</v8:Type>
|
||||
<v8:NumberQualifiers>
|
||||
@@ -56,6 +69,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="Дата" id="16">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Дата</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:dateTime</v8:Type>
|
||||
<v8:DateQualifiers>
|
||||
@@ -64,6 +83,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="Булево" id="17">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Булево</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:boolean</v8:Type>
|
||||
</Type>
|
||||
|
||||
+8
@@ -6,6 +6,7 @@
|
||||
<v8:content>Бригады</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1">
|
||||
<ChildItems>
|
||||
<Button name="ИзменитьВыделенные" id="1">
|
||||
@@ -19,6 +20,7 @@
|
||||
<Table name="Список" id="3">
|
||||
<DataPath>Список</DataPath>
|
||||
<CommandBarLocation>None</CommandBarLocation>
|
||||
<RowPictureDataPath>Список.DefaultPicture</RowPictureDataPath>
|
||||
<ContextMenu name="СписокКонтекстноеМеню" id="4"/>
|
||||
<AutoCommandBar name="СписокКоманднаяПанель" id="5">
|
||||
<Autofill>false</Autofill>
|
||||
@@ -50,6 +52,12 @@
|
||||
</Attributes>
|
||||
<Commands>
|
||||
<Command name="ИзменитьВыделенные" id="13">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Изменить выделенные</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Action>ИзменитьВыделенные</Action>
|
||||
</Command>
|
||||
</Commands>
|
||||
|
||||
+2
@@ -6,6 +6,7 @@
|
||||
<v8:content>Товар</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<InputField name="Наименование" id="1">
|
||||
@@ -37,6 +38,7 @@
|
||||
<v8:Type>cfg:CatalogObject.Товары</v8:Type>
|
||||
</Type>
|
||||
<MainAttribute>true</MainAttribute>
|
||||
<SavedData>true</SavedData>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Form>
|
||||
|
||||
+14
@@ -6,6 +6,7 @@
|
||||
<v8:content>Форма с командами</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1">
|
||||
<Autofill>false</Autofill>
|
||||
</AutoCommandBar>
|
||||
@@ -27,6 +28,7 @@
|
||||
<DataPath>Результат</DataPath>
|
||||
<ReadOnly>true</ReadOnly>
|
||||
<MultiLine>true</MultiLine>
|
||||
<AutoMaxWidth>false</AutoMaxWidth>
|
||||
<Height>8</Height>
|
||||
<ContextMenu name="РезультатКонтекстноеМеню" id="7"/>
|
||||
<ExtendedTooltip name="РезультатРасширеннаяПодсказка" id="8"/>
|
||||
@@ -40,6 +42,12 @@
|
||||
<MainAttribute>true</MainAttribute>
|
||||
</Attribute>
|
||||
<Attribute name="Результат" id="10">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Результат</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -51,6 +59,12 @@
|
||||
</Attributes>
|
||||
<Commands>
|
||||
<Command name="Выполнить" id="11">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Выполнить</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Action>ВыполнитьОбработка</Action>
|
||||
<Shortcut>Ctrl+Enter</Shortcut>
|
||||
</Command>
|
||||
|
||||
+2
@@ -6,11 +6,13 @@
|
||||
<v8:content>Товары</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<Table name="Список" id="1">
|
||||
<DataPath>Список</DataPath>
|
||||
<CommandBarLocation>None</CommandBarLocation>
|
||||
<RowPictureDataPath>Список.DefaultPicture</RowPictureDataPath>
|
||||
<ContextMenu name="СписокКонтекстноеМеню" id="2"/>
|
||||
<AutoCommandBar name="СписокКоманднаяПанель" id="3">
|
||||
<Autofill>false</Autofill>
|
||||
|
||||
+13
@@ -6,6 +6,7 @@
|
||||
<v8:content>События</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<Events>
|
||||
<Event name="OnCreateAtServer">ПриСозданииНаСервере</Event>
|
||||
@@ -49,6 +50,12 @@
|
||||
<MainAttribute>true</MainAttribute>
|
||||
</Attribute>
|
||||
<Attribute name="Организация" id="11">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Организация</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -58,6 +65,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="Период" id="12">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Период</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:dateTime</v8:Type>
|
||||
<v8:DateQualifiers>
|
||||
|
||||
+26
@@ -38,6 +38,7 @@
|
||||
</InputField>
|
||||
<CheckBoxField name="ПерваяСтрокаЗаголовок" id="6">
|
||||
<DataPath>ПерваяСтрокаЗаголовок</DataPath>
|
||||
<TitleLocation>Right</TitleLocation>
|
||||
<ContextMenu name="ПерваяСтрокаЗаголовокКонтекстноеМеню" id="7"/>
|
||||
<ExtendedTooltip name="ПерваяСтрокаЗаголовокРасширеннаяПодсказка" id="8"/>
|
||||
</CheckBoxField>
|
||||
@@ -53,6 +54,7 @@
|
||||
</Title>
|
||||
<ReadOnly>true</ReadOnly>
|
||||
<MultiLine>true</MultiLine>
|
||||
<AutoMaxWidth>false</AutoMaxWidth>
|
||||
<Height>8</Height>
|
||||
<ContextMenu name="РезультатКонтекстноеМеню" id="10"/>
|
||||
<ExtendedTooltip name="РезультатРасширеннаяПодсказка" id="11"/>
|
||||
@@ -81,6 +83,12 @@
|
||||
<MainAttribute>true</MainAttribute>
|
||||
</Attribute>
|
||||
<Attribute name="ИмяФайла" id="19">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Имя файла</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -90,11 +98,23 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="ПерваяСтрокаЗаголовок" id="20">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Первая строка заголовок</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:boolean</v8:Type>
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="Результат" id="21">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Результат</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -106,6 +126,12 @@
|
||||
</Attributes>
|
||||
<Commands>
|
||||
<Command name="Загрузить" id="22">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Загрузить</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Action>ЗагрузитьОбработка</Action>
|
||||
<Shortcut>Ctrl+Enter</Shortcut>
|
||||
</Command>
|
||||
|
||||
+19
@@ -6,6 +6,7 @@
|
||||
<v8:content>Группы</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1">
|
||||
<Autofill>false</Autofill>
|
||||
</AutoCommandBar>
|
||||
@@ -73,6 +74,12 @@
|
||||
<MainAttribute>true</MainAttribute>
|
||||
</Attribute>
|
||||
<Attribute name="Поле1" id="16">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Поле1</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -82,6 +89,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="Поле2" id="17">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Поле2</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:decimal</v8:Type>
|
||||
<v8:NumberQualifiers>
|
||||
@@ -92,6 +105,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="Поле3" id="18">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Поле3</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:dateTime</v8:Type>
|
||||
<v8:DateQualifiers>
|
||||
|
||||
+39
@@ -6,6 +6,7 @@
|
||||
<v8:content>Поля ввода</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<InputField name="ОбычноеПоле" id="1">
|
||||
@@ -28,6 +29,7 @@
|
||||
</v8:item>
|
||||
</Title>
|
||||
<MultiLine>true</MultiLine>
|
||||
<AutoMaxWidth>false</AutoMaxWidth>
|
||||
<Height>5</Height>
|
||||
<ContextMenu name="МногострочноеПолеКонтекстноеМеню" id="5"/>
|
||||
<ExtendedTooltip name="МногострочноеПолеРасширеннаяПодсказка" id="6"/>
|
||||
@@ -81,6 +83,7 @@
|
||||
<v8:content>Включено</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<TitleLocation>Right</TitleLocation>
|
||||
<ContextMenu name="ФлагКонтекстноеМеню" id="17"/>
|
||||
<ExtendedTooltip name="ФлагРасширеннаяПодсказка" id="18"/>
|
||||
</CheckBoxField>
|
||||
@@ -93,6 +96,12 @@
|
||||
<MainAttribute>true</MainAttribute>
|
||||
</Attribute>
|
||||
<Attribute name="ОбычноеПоле" id="20">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Обычное поле</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -102,6 +111,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="МногострочноеПоле" id="21">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Многострочное поле</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -111,6 +126,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="ПолеПароля" id="22">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Поле пароля</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -120,6 +141,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="ПолеСКнопками" id="23">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Поле с кнопками</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -129,6 +156,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="ПолеПодсказка" id="24">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Поле подсказка</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -138,6 +171,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="Флаг" id="25">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Флаг</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:boolean</v8:Type>
|
||||
</Type>
|
||||
|
||||
+1
@@ -6,5 +6,6 @@
|
||||
<v8:content>Минимальная форма</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
</Form>
|
||||
|
||||
+24
@@ -83,6 +83,12 @@
|
||||
<MainAttribute>true</MainAttribute>
|
||||
</Attribute>
|
||||
<Attribute name="Параметр1" id="20">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Параметр1</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -92,6 +98,12 @@
|
||||
</Type>
|
||||
</Attribute>
|
||||
<Attribute name="Итог" id="21">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Итог</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -103,9 +115,21 @@
|
||||
</Attributes>
|
||||
<Commands>
|
||||
<Command name="Назад" id="22">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Назад</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Action>НазадОбработка</Action>
|
||||
</Command>
|
||||
<Command name="Далее" id="23">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Далее</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Action>ДалееОбработка</Action>
|
||||
</Command>
|
||||
</Commands>
|
||||
|
||||
+19
@@ -6,6 +6,7 @@
|
||||
<v8:content>Тест синонимов</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1">
|
||||
<ChildItems>
|
||||
<Button name="Кн1" id="1">
|
||||
@@ -37,6 +38,12 @@
|
||||
<MainAttribute>true</MainAttribute>
|
||||
</Attribute>
|
||||
<Attribute name="Поле" id="10">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Поле</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
@@ -48,9 +55,21 @@
|
||||
</Attributes>
|
||||
<Commands>
|
||||
<Command name="Кн1" id="11">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Кн1</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Action>Кн1</Action>
|
||||
</Command>
|
||||
<Command name="Кн2" id="12">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Кн2</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Action>Кн2</Action>
|
||||
</Command>
|
||||
</Commands>
|
||||
|
||||
+7
@@ -6,6 +6,7 @@
|
||||
<v8:content>Просмотр данных</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<Table name="Данные" id="1">
|
||||
@@ -43,6 +44,12 @@
|
||||
<MainAttribute>true</MainAttribute>
|
||||
</Attribute>
|
||||
<Attribute name="Данные" id="17">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Данные</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Type>
|
||||
<v8:Type>v8:ValueTable</v8:Type>
|
||||
</Type>
|
||||
|
||||
+23
-1
@@ -18,11 +18,32 @@ const CACHE = resolve(ROOT, '.cache');
|
||||
|
||||
// ─── CLI args ───────────────────────────────────────────────────────────────
|
||||
|
||||
function printHelp() {
|
||||
console.log(`skill-test-runner — Snapshot-based regression tests for 1C skill scripts
|
||||
|
||||
Usage:
|
||||
node tests/skills/runner.mjs [filter] [options]
|
||||
|
||||
Arguments:
|
||||
filter Substring to match case id (e.g. "form-compile" or "form-compile/table")
|
||||
|
||||
Options:
|
||||
--update-snapshots Overwrite snapshot files with current actual output
|
||||
--runtime <ps|python> Which script port to run (default: powershell)
|
||||
--json <path> Write JSON report to <path>
|
||||
--concurrency <N> Number of parallel workers (default: cpu count)
|
||||
--with-validation Run platform validation (1cv8 design checks) after compile
|
||||
-v, --verbose Verbose output
|
||||
-h, --help, /? Show this help and exit
|
||||
`);
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = { filter: null, updateSnapshots: false, runtime: 'powershell', jsonReport: null, verbose: false, concurrency: cpus().length, withValidation: false };
|
||||
const args = { filter: null, updateSnapshots: false, runtime: 'powershell', jsonReport: null, verbose: false, concurrency: cpus().length, withValidation: false, help: false };
|
||||
const rest = argv.slice(2);
|
||||
for (let i = 0; i < rest.length; i++) {
|
||||
const a = rest[i];
|
||||
if (a === '-h' || a === '--help' || a === '/?' || a === '/help' || a === '?') { args.help = true; continue; }
|
||||
if (a === '--update-snapshots') { args.updateSnapshots = true; continue; }
|
||||
if (a === '--runtime' && rest[i + 1]) { args.runtime = rest[++i]; continue; }
|
||||
if (a === '--json' && rest[i + 1]) { args.jsonReport = rest[++i]; continue; }
|
||||
@@ -1042,6 +1063,7 @@ function printIntegrationReport(results, opts) {
|
||||
|
||||
async function main() {
|
||||
const opts = parseArgs(process.argv);
|
||||
if (opts.help) { printHelp(); return; }
|
||||
mkdirSync(CACHE, { recursive: true });
|
||||
|
||||
// Load platform context for platform-dependent tests
|
||||
|
||||
@@ -23,11 +23,30 @@ const REPORT_DIR = resolve(REPO_ROOT, 'debug/snapshot-verify');
|
||||
|
||||
// ─── CLI args ───────────────────────────────────────────────────────────────
|
||||
|
||||
function printHelp() {
|
||||
console.log(`verify-snapshots — Platform verification of skill test snapshots
|
||||
|
||||
Reruns skill scripts from test-case DSL, then loads results into 1C platform.
|
||||
|
||||
Usage:
|
||||
node tests/skills/verify-snapshots.mjs [options]
|
||||
|
||||
Options:
|
||||
--skill <name> Run only cases for the given skill (e.g. form-compile)
|
||||
--case <name> Run only the case with this name
|
||||
--runtime <ps|python> Which script port to run (default: powershell)
|
||||
--keep Keep generated work directories on disk after run
|
||||
-v, --verbose Verbose output
|
||||
-h, --help, /? Show this help and exit
|
||||
`);
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = { skill: null, caseName: null, runtime: 'powershell', keep: false, verbose: false };
|
||||
const args = { skill: null, caseName: null, runtime: 'powershell', keep: false, verbose: false, help: false };
|
||||
const rest = argv.slice(2);
|
||||
for (let i = 0; i < rest.length; i++) {
|
||||
const a = rest[i];
|
||||
if (a === '-h' || a === '--help' || a === '/?' || a === '/help' || a === '?') { args.help = true; continue; }
|
||||
if (a === '--skill' && rest[i + 1]) { args.skill = rest[++i]; continue; }
|
||||
if (a === '--case' && rest[i + 1]) { args.caseName = rest[++i]; continue; }
|
||||
if (a === '--runtime' && rest[i + 1]) { args.runtime = rest[++i]; continue; }
|
||||
@@ -1034,6 +1053,7 @@ function writeReport(results) {
|
||||
|
||||
async function main() {
|
||||
const opts = parseArgs(process.argv);
|
||||
if (opts.help) { printHelp(); return; }
|
||||
|
||||
const v8ctx = loadV8Context();
|
||||
if (!v8ctx) {
|
||||
|
||||
Reference in New Issue
Block a user