diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1
index 483a1bcf..e821095d 100644
--- a/.claude/skills/form-compile/scripts/form-compile.ps1
+++ b/.claude/skills/form-compile/scripts/form-compile.ps1
@@ -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 "$indenttrue" }
}
+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$($el.path)" }
- 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 "$innertrue" }
if ($el.markIncomplete -eq $true) { X "$innertrue" }
if ($el.skipOnInput -eq $true) { X "$innertrue" }
- if ($el.autoMaxWidth -eq $false) { X "$innerfalse" }
+ $hasAmw = $el.PSObject.Properties.Name -contains 'autoMaxWidth'
+ if ($hasAmw) {
+ if ($el.autoMaxWidth -eq $false) { X "$innerfalse" }
+ } elseif ($el.multiLine -eq $true) {
+ X "$innerfalse"
+ }
if ($el.autoMaxHeight -eq $false) { X "$innerfalse" }
if ($el.width) { X "$inner$($el.width)" }
if ($el.height) { X "$inner$($el.height)" }
@@ -2052,12 +2084,11 @@ function Emit-Check {
if ($el.path) { X "$inner$($el.path)" }
- 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$($el.titleLocation)"
- }
+ $tl = if ($el.titleLocation) { "$($el.titleLocation)" } else { "Right" }
+ X "$inner$tl"
# Companions
Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner
@@ -2074,12 +2105,13 @@ function Emit-Label {
X "$indent"
$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"
X "$inner`t"
X "$inner`t`tru"
- X "$inner`t`t$(Esc-Xml "$($el.title)")"
+ X "$inner`t`t$(Esc-Xml "$labelTitle")"
X "$inner`t"
X "$inner"
}
@@ -2109,7 +2141,7 @@ function Emit-LabelField {
if ($el.path) { X "$inner$($el.path)" }
- 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 "$innertrue" }
@@ -2131,7 +2163,7 @@ function Emit-Table {
if ($el.path) { X "$inner$($el.path)" }
- 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"
$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 "$innertrue" }
@@ -2369,7 +2402,7 @@ function Emit-Calendar {
if ($el.path) { X "$inner$($el.path)" }
- 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"
$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"
$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 "$innertrue"
}
- 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 "$innertrue"
}
if ($attr.fillChecking) {
@@ -2539,8 +2577,9 @@ function Emit-Commands {
X "$indent`t"
$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) {
diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py
index 54f41a86..9dc4bc35 100644
--- a/.claude/skills/form-compile/scripts/form-compile.py
+++ b/.claude/skills/form-compile/scripts/form-compile.py
@@ -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}true")
-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}{el["path"]}')
- 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}true')
if el.get('skipOnInput') is True:
lines.append(f'{inner}true')
- if el.get('autoMaxWidth') is False:
+ if 'autoMaxWidth' in el:
+ if el['autoMaxWidth'] is False:
+ lines.append(f'{inner}false')
+ elif el.get('multiLine') is True:
lines.append(f'{inner}false')
if el.get('autoMaxHeight') is False:
lines.append(f'{inner}false')
@@ -1768,11 +1792,11 @@ def emit_check(lines, el, name, eid, indent):
if el.get('path'):
lines.append(f'{inner}{el["path"]}')
- 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}{el["titleLocation"]}')
+ tl = el.get('titleLocation') or 'Right'
+ lines.append(f'{inner}{tl}')
# 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}')
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}')
lines.append(f'{inner}\t')
lines.append(f'{inner}\t\tru')
- lines.append(f'{inner}\t\t{esc_xml(str(el["title"]))}')
+ lines.append(f'{inner}\t\t{esc_xml(str(label_title))}')
lines.append(f'{inner}\t')
lines.append(f'{inner}')
@@ -1825,7 +1850,7 @@ def emit_label_field(lines, el, name, eid, indent):
if el.get('path'):
lines.append(f'{inner}{el["path"]}')
- 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}{el["path"]}')
- 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}')
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}Form.StandardCommand.{sc}')
- 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}{el["path"]}')
- 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}')
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')
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}true')
- 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}true')
if attr.get('fillChecking'):
lines.append(f'{inner}{attr["fillChecking"]}')
@@ -2219,8 +2251,9 @@ def emit_commands(lines, cmds, indent):
lines.append(f'{indent}\t')
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}{cmd["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:
diff --git a/tests/skills/README.md b/tests/skills/README.md
index cadf6aa1..feb94049 100644
--- a/tests/skills/README.md
+++ b/tests/skills/README.md
@@ -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 `)
@@ -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/
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/accumreg-list-simple/AccumulationRegisters/ДенежныеСредства/Forms/ФормаСписка/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/accumreg-list-simple/AccumulationRegisters/ДенежныеСредства/Forms/ФормаСписка/Ext/Form.xml
index 54ff8a38..e468df18 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/accumreg-list-simple/AccumulationRegisters/ДенежныеСредства/Forms/ФормаСписка/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/accumreg-list-simple/AccumulationRegisters/ДенежныеСредства/Forms/ФормаСписка/Ext/Form.xml
@@ -6,11 +6,13 @@
Денежные средства
+ false
Список
None
+ Список.DefaultPicture
false
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/catalog-item-simple/Catalogs/Валюты/Forms/ФормаЭлемента/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/catalog-item-simple/Catalogs/Валюты/Forms/ФормаЭлемента/Ext/Form.xml
index 222ebb09..d1433d96 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/catalog-item-simple/Catalogs/Валюты/Forms/ФормаЭлемента/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/catalog-item-simple/Catalogs/Валюты/Forms/ФормаЭлемента/Ext/Form.xml
@@ -6,6 +6,7 @@
Валюты
+ false
@@ -34,6 +35,7 @@
Объект.ЗагружаетсяИзИнтернета
+ Right
@@ -80,6 +82,7 @@
cfg:CatalogObject.Валюты
true
+ true
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/catalog-list-simple/Catalogs/Валюты/Forms/ФормаСписка/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/catalog-list-simple/Catalogs/Валюты/Forms/ФормаСписка/Ext/Form.xml
index ac356343..62d0f1c7 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/catalog-list-simple/Catalogs/Валюты/Forms/ФормаСписка/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/catalog-list-simple/Catalogs/Валюты/Forms/ФормаСписка/Ext/Form.xml
@@ -6,6 +6,7 @@
Валюты
+ false
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/ccoct-item-simple/ChartsOfCharacteristicTypes/ВидыНоменклатуры/Forms/ФормаЭлемента/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/ccoct-item-simple/ChartsOfCharacteristicTypes/ВидыНоменклатуры/Forms/ФормаЭлемента/Ext/Form.xml
index a0314456..d0e0ce02 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/ccoct-item-simple/ChartsOfCharacteristicTypes/ВидыНоменклатуры/Forms/ФормаЭлемента/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/ccoct-item-simple/ChartsOfCharacteristicTypes/ВидыНоменклатуры/Forms/ФормаЭлемента/Ext/Form.xml
@@ -6,6 +6,7 @@
Виды номенклатуры
+ false
@@ -50,6 +51,7 @@
cfg:ChartOfCharacteristicTypesObject.ВидыНоменклатуры
true
+ true
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/chartofaccounts-item-simple/ChartsOfAccounts/Хозрасчетный/Forms/ФормаСчета/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/chartofaccounts-item-simple/ChartsOfAccounts/Хозрасчетный/Forms/ФормаСчета/Ext/Form.xml
index fabbb749..3597f6cf 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/chartofaccounts-item-simple/ChartsOfAccounts/Хозрасчетный/Forms/ФормаСчета/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/chartofaccounts-item-simple/ChartsOfAccounts/Хозрасчетный/Forms/ФормаСчета/Ext/Form.xml
@@ -6,6 +6,7 @@
Хозрасчетный
+ false
@@ -53,6 +54,7 @@
Объект.OffBalance
+ Right
@@ -68,11 +70,13 @@
Объект.Валютный
+ Right
Объект.Количественный
+ Right
@@ -93,16 +97,19 @@
Объект.ExtDimensionTypes.TurnoversOnly
+ Right
Объект.ExtDimensionTypes.Валютный
+ Right
Объект.ExtDimensionTypes.Количественный
+ Right
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/chartofaccounts-list-simple/ChartsOfAccounts/Хозрасчетный/Forms/ФормаСписка/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/chartofaccounts-list-simple/ChartsOfAccounts/Хозрасчетный/Forms/ФормаСписка/Ext/Form.xml
index af82121a..43224411 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/chartofaccounts-list-simple/ChartsOfAccounts/Хозрасчетный/Forms/ФормаСписка/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/chartofaccounts-list-simple/ChartsOfAccounts/Хозрасчетный/Forms/ФормаСписка/Ext/Form.xml
@@ -6,6 +6,7 @@
Хозрасчетный
+ false
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/document-item-medium/Documents/АктВыполненныхВнутреннихРабот/Forms/ФормаДокумента/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/document-item-medium/Documents/АктВыполненныхВнутреннихРабот/Forms/ФормаДокумента/Ext/Form.xml
index b42de34b..2853805a 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/document-item-medium/Documents/АктВыполненныхВнутреннихРабот/Forms/ФормаДокумента/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/document-item-medium/Documents/АктВыполненныхВнутреннихРабот/Forms/ФормаДокумента/Ext/Form.xml
@@ -111,6 +111,7 @@
Объект.Исправление
+ Right
@@ -242,6 +243,7 @@
cfg:DocumentObject.АктВыполненныхВнутреннихРабот
true
+ true
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/document-list-medium/Documents/АктВыполненныхВнутреннихРабот/Forms/ФормаСписка/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/document-list-medium/Documents/АктВыполненныхВнутреннихРабот/Forms/ФормаСписка/Ext/Form.xml
index 314dfea3..f05414f2 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/document-list-medium/Documents/АктВыполненныхВнутреннихРабот/Forms/ФормаСписка/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/document-list-medium/Documents/АктВыполненныхВнутреннихРабот/Forms/ФормаСписка/Ext/Form.xml
@@ -6,11 +6,13 @@
Акт выполненных внутренних работ
+ false
Список
None
+ Список.DefaultPicture
false
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/exchangeplan-item-simple/ExchangePlans/ОбменДанными/Forms/ФормаЭлемента/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/exchangeplan-item-simple/ExchangePlans/ОбменДанными/Forms/ФормаЭлемента/Ext/Form.xml
index b07d0630..18a0546b 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/exchangeplan-item-simple/ExchangePlans/ОбменДанными/Forms/ФормаЭлемента/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/exchangeplan-item-simple/ExchangePlans/ОбменДанными/Forms/ФормаЭлемента/Ext/Form.xml
@@ -6,6 +6,7 @@
Обмен данными
+ false
@@ -67,6 +68,7 @@
cfg:ExchangePlanObject.ОбменДанными
true
+ true
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/inforeg-list-periodic/InformationRegisters/ЦеныНоменклатуры/Forms/ФормаСписка/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/inforeg-list-periodic/InformationRegisters/ЦеныНоменклатуры/Forms/ФормаСписка/Ext/Form.xml
index 0e1d23ef..e9e718db 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/inforeg-list-periodic/InformationRegisters/ЦеныНоменклатуры/Forms/ФормаСписка/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/inforeg-list-periodic/InformationRegisters/ЦеныНоменклатуры/Forms/ФормаСписка/Ext/Form.xml
@@ -6,11 +6,13 @@
Цены номенклатуры
+ false
Список
None
+ Список.DefaultPicture
false
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/inforeg-record-nonperiodic/InformationRegisters/АдресаМагазинов/Forms/ФормаЗаписи/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/inforeg-record-nonperiodic/InformationRegisters/АдресаМагазинов/Forms/ФормаЗаписи/Ext/Form.xml
index e0df2b8b..fb1644b8 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/inforeg-record-nonperiodic/InformationRegisters/АдресаМагазинов/Forms/ФормаЗаписи/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/inforeg-record-nonperiodic/InformationRegisters/АдресаМагазинов/Forms/ФормаЗаписи/Ext/Form.xml
@@ -6,6 +6,7 @@
Адреса магазинов
+ false
LockOwnerWindow
diff --git a/tests/skills/cases/form-compile-from-object/snapshots/inforeg-record-periodic/InformationRegisters/КурсыВалют/Forms/ФормаЗаписи/Ext/Form.xml b/tests/skills/cases/form-compile-from-object/snapshots/inforeg-record-periodic/InformationRegisters/КурсыВалют/Forms/ФормаЗаписи/Ext/Form.xml
index f497c3df..6b67a02a 100644
--- a/tests/skills/cases/form-compile-from-object/snapshots/inforeg-record-periodic/InformationRegisters/КурсыВалют/Forms/ФормаЗаписи/Ext/Form.xml
+++ b/tests/skills/cases/form-compile-from-object/snapshots/inforeg-record-periodic/InformationRegisters/КурсыВалют/Forms/ФормаЗаписи/Ext/Form.xml
@@ -6,6 +6,7 @@
Курсы валют
+ false
LockOwnerWindow
diff --git a/tests/skills/cases/form-compile/snapshots/attributes-types/DataProcessors/Типы/Forms/Форма/Ext/Form.xml b/tests/skills/cases/form-compile/snapshots/attributes-types/DataProcessors/Типы/Forms/Форма/Ext/Form.xml
index 182aea4d..2916c692 100644
--- a/tests/skills/cases/form-compile/snapshots/attributes-types/DataProcessors/Типы/Forms/Форма/Ext/Form.xml
+++ b/tests/skills/cases/form-compile/snapshots/attributes-types/DataProcessors/Типы/Forms/Форма/Ext/Form.xml
@@ -6,6 +6,7 @@
Разные типы
+ false
@@ -37,6 +38,12 @@
true
+
+
+ ru
+ Строка
+
+
xs:string
@@ -46,6 +53,12 @@
+
+
+ ru
+ Число
+
+
xs:decimal
@@ -56,6 +69,12 @@
+
+
+ ru
+ Дата
+
+
xs:dateTime
@@ -64,6 +83,12 @@
+
+
+ ru
+ Булево
+
+
xs:boolean
diff --git a/tests/skills/cases/form-compile/snapshots/auto-cmd-bar/Catalogs/Бригады/Forms/ФормаСписка/Ext/Form.xml b/tests/skills/cases/form-compile/snapshots/auto-cmd-bar/Catalogs/Бригады/Forms/ФормаСписка/Ext/Form.xml
index a4fb4c16..80a0188a 100644
--- a/tests/skills/cases/form-compile/snapshots/auto-cmd-bar/Catalogs/Бригады/Forms/ФормаСписка/Ext/Form.xml
+++ b/tests/skills/cases/form-compile/snapshots/auto-cmd-bar/Catalogs/Бригады/Forms/ФормаСписка/Ext/Form.xml
@@ -6,6 +6,7 @@
Бригады
+ false