mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-10 16:14:54 +03:00
Add form-validate skill for structural validation of Form.xml
Checks: unique IDs (per pool), companion elements, DataPath→attribute refs, button→command refs, event handlers, command actions, MainAttribute. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
---
|
||||
name: form-validate
|
||||
description: Валидация структурной корректности управляемой формы 1С (Form.xml)
|
||||
argument-hint: <FormPath>
|
||||
allowed-tools:
|
||||
- Bash
|
||||
- Read
|
||||
- Glob
|
||||
---
|
||||
|
||||
# /form-validate — Валидатор формы
|
||||
|
||||
Проверяет Form.xml управляемой формы на структурные ошибки: уникальность ID, наличие companion-элементов, корректность ссылок DataPath и команд.
|
||||
|
||||
## Использование
|
||||
|
||||
```
|
||||
/form-validate <FormPath>
|
||||
```
|
||||
|
||||
## Параметры
|
||||
|
||||
| Параметр | Обязательный | По умолчанию | Описание |
|
||||
|-----------|:------------:|--------------|-----------------------------|
|
||||
| FormPath | да | — | Путь к файлу Form.xml |
|
||||
| MaxErrors | нет | 30 | Остановиться после N ошибок |
|
||||
|
||||
## Команда
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -File .claude\skills\form-validate\scripts\form-validate.ps1 -FormPath "<путь>"
|
||||
```
|
||||
|
||||
## Выполняемые проверки
|
||||
|
||||
| # | Проверка | Серьёзность |
|
||||
|---|---|---|
|
||||
| 1 | Корневой элемент `<Form>`, version="2.17" | ERROR / WARN |
|
||||
| 2 | `<AutoCommandBar>` присутствует, id="-1" | ERROR |
|
||||
| 3 | Уникальность ID элементов (отдельный пул) | ERROR |
|
||||
| 4 | Уникальность ID реквизитов (отдельный пул) | ERROR |
|
||||
| 5 | Уникальность ID команд (отдельный пул) | ERROR |
|
||||
| 6 | Companion-элементы (ContextMenu, ExtendedTooltip, и др.) | ERROR |
|
||||
| 7 | DataPath → ссылается на существующий реквизит | ERROR |
|
||||
| 8 | CommandName кнопок → ссылается на существующую команду | ERROR |
|
||||
| 9 | События имеют непустые имена обработчиков | ERROR |
|
||||
| 10 | Команды имеют Action (обработчик) | ERROR |
|
||||
| 11 | Не более одного MainAttribute | ERROR |
|
||||
|
||||
## Вывод
|
||||
|
||||
```
|
||||
=== Validation: ФормаДокумента ===
|
||||
|
||||
[OK] Root element: Form version=2.17
|
||||
[OK] AutoCommandBar: name='ФормаКоманднаяПанель', id=-1
|
||||
[OK] Unique element IDs: 96 elements
|
||||
[OK] Unique attribute IDs: 38 entries
|
||||
[OK] Unique command IDs: 5 entries
|
||||
[OK] Companion elements: 86 elements checked
|
||||
[OK] DataPath references: 53 paths checked
|
||||
[OK] Command references: 2 buttons checked
|
||||
[OK] Event handlers: 41 events checked
|
||||
[OK] Command actions: 5 commands checked
|
||||
[OK] MainAttribute: 1 main attribute
|
||||
|
||||
---
|
||||
Total: 96 elements, 38 attributes, 5 commands
|
||||
All checks passed.
|
||||
```
|
||||
|
||||
Код возврата: 0 = все проверки пройдены, 1 = есть ошибки.
|
||||
|
||||
## Когда использовать
|
||||
|
||||
- **После `/form-compile`**: проверить корректность сгенерированной формы
|
||||
- **После ручного редактирования Form.xml**: убедиться что ID уникальны, companions на месте, ссылки валидны
|
||||
- **При отладке**: выявить ошибки в структуре формы до сборки EPF
|
||||
@@ -0,0 +1,486 @@
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string]$FormPath,
|
||||
|
||||
[int]$MaxErrors = 30
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# --- Load XML ---
|
||||
|
||||
if (-not (Test-Path $FormPath)) {
|
||||
Write-Error "File not found: $FormPath"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$xmlDoc = New-Object System.Xml.XmlDocument
|
||||
$xmlDoc.PreserveWhitespace = $false
|
||||
try {
|
||||
$xmlDoc.Load((Resolve-Path $FormPath).Path)
|
||||
} catch {
|
||||
Write-Host "[ERROR] XML parse error: $($_.Exception.Message)"
|
||||
Write-Host ""
|
||||
Write-Host "---"
|
||||
Write-Host "Errors: 1, Warnings: 0"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$nsMgr = New-Object System.Xml.XmlNamespaceManager($xmlDoc.NameTable)
|
||||
$nsMgr.AddNamespace("f", "http://v8.1c.ru/8.3/xcf/logform")
|
||||
$nsMgr.AddNamespace("v8", "http://v8.1c.ru/8.1/data/core")
|
||||
|
||||
$root = $xmlDoc.DocumentElement
|
||||
|
||||
# --- Counters ---
|
||||
|
||||
$errors = 0
|
||||
$warnings = 0
|
||||
$stopped = $false
|
||||
|
||||
function Report-OK {
|
||||
param([string]$msg)
|
||||
Write-Host "[OK] $msg"
|
||||
}
|
||||
|
||||
function Report-Error {
|
||||
param([string]$msg)
|
||||
$script:errors++
|
||||
Write-Host "[ERROR] $msg"
|
||||
if ($script:errors -ge $MaxErrors) {
|
||||
$script:stopped = $true
|
||||
}
|
||||
}
|
||||
|
||||
function Report-Warn {
|
||||
param([string]$msg)
|
||||
$script:warnings++
|
||||
Write-Host "[WARN] $msg"
|
||||
}
|
||||
|
||||
# --- Form name from path ---
|
||||
|
||||
$formName = [System.IO.Path]::GetFileNameWithoutExtension($FormPath)
|
||||
$parentDir = [System.IO.Path]::GetDirectoryName($FormPath)
|
||||
if ($parentDir) {
|
||||
$extDir = [System.IO.Path]::GetFileName($parentDir)
|
||||
if ($extDir -eq "Ext") {
|
||||
$formDir = [System.IO.Path]::GetDirectoryName($parentDir)
|
||||
if ($formDir) { $formName = [System.IO.Path]::GetFileName($formDir) }
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "=== Validation: $formName ==="
|
||||
Write-Host ""
|
||||
|
||||
# --- Check 1: Root element and version ---
|
||||
|
||||
if ($root.LocalName -ne "Form") {
|
||||
Report-Error "Root element is '$($root.LocalName)', expected 'Form'"
|
||||
} else {
|
||||
$version = $root.GetAttribute("version")
|
||||
if ($version -eq "2.17") {
|
||||
Report-OK "Root element: Form version=$version"
|
||||
} elseif ($version) {
|
||||
Report-Warn "Form version='$version' (expected 2.17)"
|
||||
} else {
|
||||
Report-Warn "Form version attribute missing"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Check 2: AutoCommandBar ---
|
||||
|
||||
if (-not $stopped) {
|
||||
$acb = $root.SelectSingleNode("f:AutoCommandBar", $nsMgr)
|
||||
if ($acb) {
|
||||
$acbName = $acb.GetAttribute("name")
|
||||
$acbId = $acb.GetAttribute("id")
|
||||
if ($acbId -eq "-1") {
|
||||
Report-OK "AutoCommandBar: name='$acbName', id=$acbId"
|
||||
} else {
|
||||
Report-Error "AutoCommandBar id='$acbId', expected '-1'"
|
||||
}
|
||||
} else {
|
||||
Report-Error "AutoCommandBar element missing"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Collect all elements with IDs ---
|
||||
|
||||
$elementIds = @{} # id -> name (element ID pool)
|
||||
$allElements = @() # @{Name; Tag; Id; ParentName; Node}
|
||||
|
||||
function Collect-Elements {
|
||||
param($node, [string]$parentName)
|
||||
|
||||
foreach ($child in $node.ChildNodes) {
|
||||
if ($child.NodeType -ne 'Element') { continue }
|
||||
|
||||
$name = $child.GetAttribute("name")
|
||||
$id = $child.GetAttribute("id")
|
||||
|
||||
if ($name -and $id) {
|
||||
$tag = $child.LocalName
|
||||
|
||||
$script:allElements += @{
|
||||
Name = $name
|
||||
Tag = $tag
|
||||
Id = $id
|
||||
ParentName = $parentName
|
||||
Node = $child
|
||||
}
|
||||
|
||||
# Track element IDs (skip AutoCommandBar which has -1)
|
||||
if ($id -ne "-1") {
|
||||
if ($elementIds.ContainsKey($id)) {
|
||||
Report-Error "Duplicate element id=${id}: '$name' and '$($elementIds[$id])'"
|
||||
} else {
|
||||
$elementIds[$id] = $name
|
||||
}
|
||||
}
|
||||
|
||||
# Recurse into ChildItems
|
||||
$childItems = $child.SelectSingleNode("f:ChildItems", $nsMgr)
|
||||
if ($childItems) {
|
||||
Collect-Elements -node $childItems -parentName $name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Collect from ChildItems
|
||||
$childItemsRoot = $root.SelectSingleNode("f:ChildItems", $nsMgr)
|
||||
if ($childItemsRoot) {
|
||||
Collect-Elements -node $childItemsRoot -parentName "(root)"
|
||||
}
|
||||
|
||||
# Also collect from AutoCommandBar's ChildItems
|
||||
$acb = $root.SelectSingleNode("f:AutoCommandBar", $nsMgr)
|
||||
if ($acb) {
|
||||
$acbChildren = $acb.SelectSingleNode("f:ChildItems", $nsMgr)
|
||||
if ($acbChildren) {
|
||||
Collect-Elements -node $acbChildren -parentName "ФормаКоманднаяПанель"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Check 3: Unique element IDs ---
|
||||
|
||||
if (-not $stopped) {
|
||||
$dupCount = ($allElements | Group-Object { $_.Id } | Where-Object { $_.Count -gt 1 -and $_.Name -ne "-1" }).Count
|
||||
if ($dupCount -eq 0) {
|
||||
Report-OK "Unique element IDs: $($elementIds.Count) elements"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Collect attributes (separate ID pool) ---
|
||||
|
||||
$attrMap = @{} # name -> node
|
||||
$attrIds = @{} # id -> name
|
||||
$attrNodes = $root.SelectNodes("f:Attributes/f:Attribute", $nsMgr)
|
||||
foreach ($attr in $attrNodes) {
|
||||
$attrName = $attr.GetAttribute("name")
|
||||
$attrId = $attr.GetAttribute("id")
|
||||
if ($attrName) {
|
||||
$attrMap[$attrName] = $attr
|
||||
}
|
||||
if ($attrId -and $attrId -ne "") {
|
||||
if ($attrIds.ContainsKey($attrId)) {
|
||||
Report-Error "Duplicate attribute id=${attrId}: '$attrName' and '$($attrIds[$attrId])'"
|
||||
} else {
|
||||
$attrIds[$attrId] = $attrName
|
||||
}
|
||||
}
|
||||
|
||||
# Column IDs are a separate sub-pool per attribute — check uniqueness within parent
|
||||
$colIds = @{}
|
||||
foreach ($col in $attr.SelectNodes("f:Columns/f:Column", $nsMgr)) {
|
||||
$colId = $col.GetAttribute("id")
|
||||
$colName = $col.GetAttribute("name")
|
||||
if ($colId -and $colId -ne "") {
|
||||
if ($colIds.ContainsKey($colId)) {
|
||||
Report-Error "Duplicate column id=${colId} in '$attrName': '$colName' and '$($colIds[$colId])'"
|
||||
} else {
|
||||
$colIds[$colId] = $colName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $stopped) {
|
||||
$attrDupCount = ($attrIds.GetEnumerator() | Group-Object Value | Where-Object { $_.Count -gt 1 }).Count
|
||||
if ($attrDupCount -eq 0 -and $attrIds.Count -gt 0) {
|
||||
Report-OK "Unique attribute IDs: $($attrIds.Count) entries"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Collect commands (separate ID pool) ---
|
||||
|
||||
$cmdMap = @{} # name -> node
|
||||
$cmdIds = @{} # id -> name
|
||||
$cmdNodes = $root.SelectNodes("f:Commands/f:Command", $nsMgr)
|
||||
foreach ($cmd in $cmdNodes) {
|
||||
$cmdName = $cmd.GetAttribute("name")
|
||||
$cmdId = $cmd.GetAttribute("id")
|
||||
if ($cmdName) {
|
||||
$cmdMap[$cmdName] = $cmd
|
||||
}
|
||||
if ($cmdId -and $cmdId -ne "") {
|
||||
if ($cmdIds.ContainsKey($cmdId)) {
|
||||
Report-Error "Duplicate command id=${cmdId}: '$cmdName' and '$($cmdIds[$cmdId])'"
|
||||
} else {
|
||||
$cmdIds[$cmdId] = $cmdName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $stopped) {
|
||||
if ($cmdIds.Count -gt 0) {
|
||||
$cmdDupCount = ($cmdIds.GetEnumerator() | Group-Object Value | Where-Object { $_.Count -gt 1 }).Count
|
||||
if ($cmdDupCount -eq 0) {
|
||||
Report-OK "Unique command IDs: $($cmdIds.Count) entries"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- Check 4: Companion elements ---
|
||||
|
||||
# Define required companions per element type
|
||||
$companionRules = @{
|
||||
"InputField" = @("ContextMenu", "ExtendedTooltip")
|
||||
"CheckBoxField" = @("ContextMenu", "ExtendedTooltip")
|
||||
"LabelDecoration" = @("ContextMenu", "ExtendedTooltip")
|
||||
"LabelField" = @("ContextMenu", "ExtendedTooltip")
|
||||
"PictureDecoration" = @("ContextMenu", "ExtendedTooltip")
|
||||
"PictureField" = @("ContextMenu", "ExtendedTooltip")
|
||||
"CalendarField" = @("ContextMenu", "ExtendedTooltip")
|
||||
"UsualGroup" = @("ExtendedTooltip")
|
||||
"Pages" = @("ExtendedTooltip")
|
||||
"Page" = @("ExtendedTooltip")
|
||||
"Button" = @("ExtendedTooltip")
|
||||
"Table" = @("ContextMenu", "AutoCommandBar", "SearchStringAddition", "ViewStatusAddition", "SearchControlAddition")
|
||||
}
|
||||
|
||||
if (-not $stopped) {
|
||||
$companionErrors = 0
|
||||
$companionChecked = 0
|
||||
|
||||
foreach ($el in $allElements) {
|
||||
if ($stopped) { break }
|
||||
$tag = $el.Tag
|
||||
$elName = $el.Name
|
||||
$node = $el.Node
|
||||
|
||||
if (-not $companionRules.ContainsKey($tag)) { continue }
|
||||
|
||||
$required = $companionRules[$tag]
|
||||
$companionChecked++
|
||||
|
||||
foreach ($compTag in $required) {
|
||||
$compNode = $node.SelectSingleNode("f:$compTag", $nsMgr)
|
||||
if (-not $compNode) {
|
||||
Report-Error "[$tag] '$elName': missing companion <$compTag>"
|
||||
$companionErrors++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($companionErrors -eq 0 -and $companionChecked -gt 0) {
|
||||
Report-OK "Companion elements: $companionChecked elements checked"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Check 5: DataPath -> Attribute references ---
|
||||
|
||||
if (-not $stopped) {
|
||||
$pathErrors = 0
|
||||
$pathChecked = 0
|
||||
|
||||
foreach ($el in $allElements) {
|
||||
if ($stopped) { break }
|
||||
$tag = $el.Tag
|
||||
$elName = $el.Name
|
||||
$node = $el.Node
|
||||
|
||||
# Skip companion elements
|
||||
if ($tag -in @("ContextMenu", "ExtendedTooltip", "AutoCommandBar", "SearchStringAddition", "ViewStatusAddition", "SearchControlAddition")) {
|
||||
continue
|
||||
}
|
||||
|
||||
$dpNode = $node.SelectSingleNode("f:DataPath", $nsMgr)
|
||||
if (-not $dpNode) { continue }
|
||||
|
||||
$dataPath = $dpNode.InnerText.Trim()
|
||||
if (-not $dataPath) { continue }
|
||||
|
||||
$pathChecked++
|
||||
|
||||
# Extract root segment of path, strip array indices like [0]
|
||||
$cleanPath = $dataPath -replace '\[\d+\]', ''
|
||||
$segments = $cleanPath -split '\.'
|
||||
$rootAttr = $segments[0]
|
||||
|
||||
if (-not $attrMap.ContainsKey($rootAttr)) {
|
||||
Report-Error "[$tag] '$elName': DataPath='$dataPath' — attribute '$rootAttr' not found"
|
||||
$pathErrors++
|
||||
}
|
||||
}
|
||||
|
||||
if ($pathErrors -eq 0 -and $pathChecked -gt 0) {
|
||||
Report-OK "DataPath references: $pathChecked paths checked"
|
||||
} elseif ($pathChecked -eq 0) {
|
||||
Report-OK "DataPath references: none"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Check 6: Button command references ---
|
||||
|
||||
if (-not $stopped) {
|
||||
$cmdErrors = 0
|
||||
$cmdChecked = 0
|
||||
|
||||
foreach ($el in $allElements) {
|
||||
if ($stopped) { break }
|
||||
$tag = $el.Tag
|
||||
$elName = $el.Name
|
||||
$node = $el.Node
|
||||
|
||||
if ($tag -ne "Button") { continue }
|
||||
|
||||
$cmdNode = $node.SelectSingleNode("f:CommandName", $nsMgr)
|
||||
if (-not $cmdNode) { continue }
|
||||
|
||||
$cmdRef = $cmdNode.InnerText.Trim()
|
||||
if (-not $cmdRef) { continue }
|
||||
|
||||
# Form.Command.XXX -> check command XXX exists
|
||||
if ($cmdRef -match '^Form\.Command\.(.+)$') {
|
||||
$cmdName = $Matches[1]
|
||||
$cmdChecked++
|
||||
if (-not $cmdMap.ContainsKey($cmdName)) {
|
||||
Report-Error "[Button] '$elName': CommandName='$cmdRef' — command '$cmdName' not found in Commands"
|
||||
$cmdErrors++
|
||||
}
|
||||
}
|
||||
# Form.StandardCommand.XXX — skip, standard commands always exist
|
||||
}
|
||||
|
||||
if ($cmdErrors -eq 0 -and $cmdChecked -gt 0) {
|
||||
Report-OK "Command references: $cmdChecked buttons checked"
|
||||
} elseif ($cmdChecked -eq 0) {
|
||||
Report-OK "Command references: none"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Check 7: Events have handler names ---
|
||||
|
||||
if (-not $stopped) {
|
||||
$eventErrors = 0
|
||||
$eventChecked = 0
|
||||
|
||||
# Form-level events
|
||||
$formEvents = $root.SelectSingleNode("f:Events", $nsMgr)
|
||||
if ($formEvents) {
|
||||
foreach ($evt in $formEvents.SelectNodes("f:Event", $nsMgr)) {
|
||||
$evtName = $evt.GetAttribute("name")
|
||||
$handler = $evt.InnerText.Trim()
|
||||
$eventChecked++
|
||||
if (-not $handler) {
|
||||
Report-Error "Form event '$evtName': empty handler name"
|
||||
$eventErrors++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Element-level events
|
||||
foreach ($el in $allElements) {
|
||||
if ($stopped) { break }
|
||||
$tag = $el.Tag
|
||||
$elName = $el.Name
|
||||
$node = $el.Node
|
||||
|
||||
$eventsNode = $node.SelectSingleNode("f:Events", $nsMgr)
|
||||
if (-not $eventsNode) { continue }
|
||||
|
||||
foreach ($evt in $eventsNode.SelectNodes("f:Event", $nsMgr)) {
|
||||
$evtName = $evt.GetAttribute("name")
|
||||
$handler = $evt.InnerText.Trim()
|
||||
$eventChecked++
|
||||
if (-not $handler) {
|
||||
Report-Error "[$tag] '$elName' event '$evtName': empty handler name"
|
||||
$eventErrors++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($eventErrors -eq 0 -and $eventChecked -gt 0) {
|
||||
Report-OK "Event handlers: $eventChecked events checked"
|
||||
} elseif ($eventChecked -eq 0) {
|
||||
Report-OK "Event handlers: none"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Check 8: Command actions ---
|
||||
|
||||
if (-not $stopped) {
|
||||
$actionErrors = 0
|
||||
$actionChecked = 0
|
||||
|
||||
foreach ($cmd in $cmdNodes) {
|
||||
if ($stopped) { break }
|
||||
$cmdName = $cmd.GetAttribute("name")
|
||||
$actionNode = $cmd.SelectSingleNode("f:Action", $nsMgr)
|
||||
$actionChecked++
|
||||
if (-not $actionNode -or -not $actionNode.InnerText.Trim()) {
|
||||
Report-Error "Command '$cmdName': missing or empty Action"
|
||||
$actionErrors++
|
||||
}
|
||||
}
|
||||
|
||||
if ($actionErrors -eq 0 -and $actionChecked -gt 0) {
|
||||
Report-OK "Command actions: $actionChecked commands checked"
|
||||
} elseif ($actionChecked -eq 0) {
|
||||
Report-OK "Command actions: none"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Check 9: MainAttribute count ---
|
||||
|
||||
if (-not $stopped) {
|
||||
$mainCount = 0
|
||||
foreach ($attr in $attrNodes) {
|
||||
$mainNode = $attr.SelectSingleNode("f:MainAttribute", $nsMgr)
|
||||
if ($mainNode -and $mainNode.InnerText -eq "true") {
|
||||
$mainCount++
|
||||
}
|
||||
}
|
||||
|
||||
if ($mainCount -le 1) {
|
||||
$mainInfo = if ($mainCount -eq 1) { "1 main attribute" } else { "no main attribute" }
|
||||
Report-OK "MainAttribute: $mainInfo"
|
||||
} else {
|
||||
Report-Error "Multiple MainAttribute=true ($mainCount found, expected 0 or 1)"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Summary ---
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "---"
|
||||
Write-Host "Total: $($allElements.Count) elements, $($attrNodes.Count) attributes, $($cmdNodes.Count) commands"
|
||||
|
||||
if ($stopped) {
|
||||
Write-Host "Stopped after $MaxErrors errors. Fix and re-run."
|
||||
}
|
||||
|
||||
if ($errors -eq 0 -and $warnings -eq 0) {
|
||||
Write-Host "All checks passed."
|
||||
} else {
|
||||
Write-Host "Errors: $errors, Warnings: $warnings"
|
||||
}
|
||||
|
||||
if ($errors -gt 0) {
|
||||
exit 1
|
||||
} else {
|
||||
exit 0
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
|--------|--------|----------|------|
|
||||
| Внешние обработки (EPF) | 10 навыков `/epf-*` | Создание, модификация, сборка обработок из XML-исходников | [Подробнее](docs/epf-guide.md) |
|
||||
| Табличный документ (MXL) | 4 навыка `/mxl-*` | Анализ, создание, компиляция макетов печатных форм | [Подробнее](docs/mxl-guide.md) |
|
||||
| Управляемые формы (Form) | 2 навыка `/form-*` | Анализ и генерация управляемых форм из XML-исходников | [Подробнее](docs/form-guide.md) |
|
||||
| Управляемые формы (Form) | 3 навыка `/form-*` | Анализ, генерация, валидация управляемых форм | [Подробнее](docs/form-guide.md) |
|
||||
| Утилиты | `/img-grid` | Наложение сетки на изображение для определения пропорций колонок | — |
|
||||
|
||||
## Требования
|
||||
@@ -59,6 +59,7 @@
|
||||
├── mxl-decompile/ # Декомпиляция макета в JSON
|
||||
├── form-info/ # Анализ структуры управляемой формы
|
||||
├── form-compile/ # Компиляция формы из JSON
|
||||
├── form-validate/ # Валидация формы
|
||||
└── img-grid/ # Сетка для анализа изображений
|
||||
docs/
|
||||
├── epf-guide.md # Гайд: внешние обработки
|
||||
|
||||
+10
-6
@@ -1,6 +1,6 @@
|
||||
# Управляемые формы (Form)
|
||||
|
||||
Навыки группы `/form-*` позволяют анализировать и генерировать управляемые формы 1С:Предприятия 8.3 из XML-исходников, не читая тысячи строк XML.
|
||||
Навыки группы `/form-*` позволяют анализировать, генерировать и валидировать управляемые формы 1С:Предприятия 8.3 из XML-исходников, не читая тысячи строк XML.
|
||||
|
||||
## Навыки
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|-------|-----------|----------|
|
||||
| `/form-info` | `<FormPath>` | Компактная сводка: дерево элементов, реквизиты, команды, события |
|
||||
| `/form-compile` | `<JsonPath> <OutputPath>` | Генерация Form.xml из компактного JSON-определения |
|
||||
| `/form-validate` | `<FormPath>` | Валидация: уникальность ID, companions, DataPath, команды |
|
||||
|
||||
## Сценарии использования
|
||||
|
||||
@@ -157,13 +158,14 @@ Claude создаст JSON-определение и вызовет `/form-compi
|
||||
|
||||
### Верификация результата
|
||||
|
||||
После компиляции используйте `/form-info` для проверки:
|
||||
После компиляции используйте `/form-validate` и `/form-info` для проверки:
|
||||
|
||||
```
|
||||
> /form-validate src/МояОбработка/Forms/Форма/Ext/Form.xml
|
||||
> /form-info src/МояОбработка/Forms/Форма/Ext/Form.xml
|
||||
```
|
||||
|
||||
Структура в сводке должна совпадать с определением в JSON.
|
||||
`/form-validate` проверит структурную корректность (ID, companions, ссылки), `/form-info` покажет результат в виде компактной сводки.
|
||||
|
||||
## Примеры слеш-команд
|
||||
|
||||
@@ -171,16 +173,18 @@ Claude создаст JSON-определение и вызовет `/form-compi
|
||||
> /form-info upload/acc_8.3.24/Documents/РеализацияТоваровУслуг/Forms/ФормаДокумента/Ext/Form.xml
|
||||
> /form-info src/МояОбработка/Forms/Форма/Ext/Form.xml
|
||||
> /form-compile src/form.json src/МояОбработка/Forms/Форма/Ext/Form.xml
|
||||
> /form-validate src/МояОбработка/Forms/Форма/Ext/Form.xml
|
||||
```
|
||||
|
||||
## Связь с EPF-навыками
|
||||
|
||||
`/form-info` и `/form-compile` работают с формами из любых источников — конфигурации и внешних обработок. При работе с обработками:
|
||||
Навыки `/form-*` работают с формами из любых источников — конфигурации и внешних обработок. При работе с обработками:
|
||||
|
||||
1. `/epf-add-form` — создать форму (каркас)
|
||||
2. `/form-compile` — сгенерировать Form.xml из JSON-определения
|
||||
3. `/form-info` — проверить результат
|
||||
4. `/epf-build` — собрать EPF
|
||||
3. `/form-validate` — проверить корректность
|
||||
4. `/form-info` — проанализировать результат
|
||||
5. `/epf-build` — собрать EPF
|
||||
|
||||
## Спецификации
|
||||
|
||||
|
||||
Reference in New Issue
Block a user