mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-19 17:19:42 +03:00
feat(form-validate): резолв Items.<Table>.CurrentData.* и ~<Attr>.* в DataPath
В Check 5 раньше брался первый сегмент DataPath и искался в attrMap, из-за чего ложно ругались реальные формы ERP/БП с путями вида Items.<TableName>.CurrentData.<Field> (подвалы, инфо-панели) и ~<DynamicListAttr>.<Field> (текущая строка списка). Теперь: - ведущий ~ стрипается перед разбором сегментов; - для Items.<Table>.CurrentData.* находим элемент-таблицу по name, берём её <DataPath> (атрибут DynamicList/TableSection) и проверяем его в attrMap. Если таблицы нет — Error; если третий сегмент не CurrentData — Warn. Добавлен тест-кейс datapath-currentdata, версия скриптов v1.4 → v1.5. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
ac3047cf55
commit
54cbc69a59
@@ -1,4 +1,4 @@
|
|||||||
# form-validate v1.4 — Validate 1C managed form
|
# form-validate v1.5 — Validate 1C managed form
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -370,9 +370,40 @@ if (-not $stopped) {
|
|||||||
|
|
||||||
# Extract root segment of path, strip array indices like [0]
|
# Extract root segment of path, strip array indices like [0]
|
||||||
$cleanPath = $dataPath -replace '\[\d+\]', ''
|
$cleanPath = $dataPath -replace '\[\d+\]', ''
|
||||||
|
# Strip leading '~' (current row of DynamicList: ~Список.Поле)
|
||||||
|
if ($cleanPath.StartsWith('~')) { $cleanPath = $cleanPath.Substring(1) }
|
||||||
$segments = $cleanPath -split '\.'
|
$segments = $cleanPath -split '\.'
|
||||||
$rootAttr = $segments[0]
|
$rootAttr = $segments[0]
|
||||||
|
|
||||||
|
# Resolve Items.<TableName>.CurrentData.<Field>... — table element, not attribute
|
||||||
|
if ($rootAttr -eq 'Items') {
|
||||||
|
if ($segments.Count -lt 3 -or $segments[2] -ne 'CurrentData') {
|
||||||
|
Report-Warn "[$tag] '$elName': DataPath='$dataPath' — unknown Items.* shape, expected Items.<Table>.CurrentData.*"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
$tableName = $segments[1]
|
||||||
|
$tableEl = $null
|
||||||
|
foreach ($candidate in $allElements) {
|
||||||
|
if ($candidate.Tag -eq 'Table' -and $candidate.Name -eq $tableName) {
|
||||||
|
$tableEl = $candidate
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-not $tableEl) {
|
||||||
|
Report-Error "[$tag] '$elName': DataPath='$dataPath' — table element '$tableName' not found"
|
||||||
|
$pathErrors++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
$tableDpNode = $tableEl.Node.SelectSingleNode("f:DataPath", $nsMgr)
|
||||||
|
if (-not $tableDpNode -or -not $tableDpNode.InnerText.Trim()) {
|
||||||
|
# Table without DataPath — can't resolve further, accept silently
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
$tableDp = $tableDpNode.InnerText.Trim() -replace '\[\d+\]', ''
|
||||||
|
if ($tableDp.StartsWith('~')) { $tableDp = $tableDp.Substring(1) }
|
||||||
|
$rootAttr = ($tableDp -split '\.')[0]
|
||||||
|
}
|
||||||
|
|
||||||
if (-not $attrMap.ContainsKey($rootAttr)) {
|
if (-not $attrMap.ContainsKey($rootAttr)) {
|
||||||
Report-Error "[$tag] '$elName': DataPath='$dataPath' — attribute '$rootAttr' not found"
|
Report-Error "[$tag] '$elName': DataPath='$dataPath' — attribute '$rootAttr' not found"
|
||||||
$pathErrors++
|
$pathErrors++
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# form-validate v1.4 — Validate 1C managed form
|
# form-validate v1.5 — Validate 1C managed form
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -379,9 +379,35 @@ def main():
|
|||||||
path_checked += 1
|
path_checked += 1
|
||||||
|
|
||||||
clean_path = re.sub(r'\[\d+\]', '', data_path)
|
clean_path = re.sub(r'\[\d+\]', '', data_path)
|
||||||
|
# Strip leading '~' (current row of DynamicList: ~\u0421\u043f\u0438\u0441\u043e\u043a.\u041f\u043e\u043b\u0435)
|
||||||
|
if clean_path.startswith('~'):
|
||||||
|
clean_path = clean_path[1:]
|
||||||
segments = clean_path.split(".")
|
segments = clean_path.split(".")
|
||||||
root_attr = segments[0]
|
root_attr = segments[0]
|
||||||
|
|
||||||
|
# Resolve Items.<TableName>.CurrentData.<Field>... \u2014 table element, not attribute
|
||||||
|
if root_attr == 'Items':
|
||||||
|
if len(segments) < 3 or segments[2] != 'CurrentData':
|
||||||
|
report_warn(f"[{tag}] '{el_name}': DataPath='{data_path}' \u2014 unknown Items.* shape, expected Items.<Table>.CurrentData.*")
|
||||||
|
continue
|
||||||
|
table_name = segments[1]
|
||||||
|
table_el = None
|
||||||
|
for candidate in all_elements:
|
||||||
|
if candidate["Tag"] == 'Table' and candidate["Name"] == table_name:
|
||||||
|
table_el = candidate
|
||||||
|
break
|
||||||
|
if table_el is None:
|
||||||
|
report_error(f"[{tag}] '{el_name}': DataPath='{data_path}' \u2014 table element '{table_name}' not found")
|
||||||
|
path_errors += 1
|
||||||
|
continue
|
||||||
|
table_dp_node = table_el["Node"].find(f"{{{F_NS}}}DataPath")
|
||||||
|
if table_dp_node is None or not (table_dp_node.text or "").strip():
|
||||||
|
continue
|
||||||
|
table_dp = re.sub(r'\[\d+\]', '', (table_dp_node.text or "").strip())
|
||||||
|
if table_dp.startswith('~'):
|
||||||
|
table_dp = table_dp[1:]
|
||||||
|
root_attr = table_dp.split(".")[0]
|
||||||
|
|
||||||
if root_attr not in attr_map:
|
if root_attr not in attr_map:
|
||||||
report_error(f"[{tag}] '{el_name}': DataPath='{data_path}' \u2014 attribute '{root_attr}' not found")
|
report_error(f"[{tag}] '{el_name}': DataPath='{data_path}' \u2014 attribute '{root_attr}' not found")
|
||||||
path_errors += 1
|
path_errors += 1
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "DataPath с Items.<Table>.CurrentData и ~Атрибут не вызывают ложных ошибок",
|
||||||
|
"setup": "fixture:datapath-currentdata",
|
||||||
|
"params": { "formPath": "DataProcessors/Spec/Forms/Форма" }
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Form xmlns="http://v8.1c.ru/8.3/xcf/logform" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
|
||||||
|
<Title>
|
||||||
|
<v8:item>
|
||||||
|
<v8:lang>ru</v8:lang>
|
||||||
|
<v8:content>Тест</v8:content>
|
||||||
|
</v8:item>
|
||||||
|
</Title>
|
||||||
|
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||||
|
<ChildItems>
|
||||||
|
<Table name="Список" id="1">
|
||||||
|
<DataPath>Список</DataPath>
|
||||||
|
<ContextMenu name="СписокКонтекстноеМеню" id="2"/>
|
||||||
|
<AutoCommandBar name="СписокКоманднаяПанель" id="3"/>
|
||||||
|
<SearchStringAddition name="СписокСтрокаПоиска" id="4"/>
|
||||||
|
<ViewStatusAddition name="СписокСостояниеПросмотра" id="5"/>
|
||||||
|
<SearchControlAddition name="СписокУправлениеПоиском" id="6"/>
|
||||||
|
<ChildItems>
|
||||||
|
<InputField name="Ссылка" id="7">
|
||||||
|
<DataPath>Список.Ссылка</DataPath>
|
||||||
|
<ContextMenu name="СсылкаКонтекстноеМеню" id="8"/>
|
||||||
|
<ExtendedTooltip name="СсылкаРасширеннаяПодсказка" id="9"/>
|
||||||
|
</InputField>
|
||||||
|
</ChildItems>
|
||||||
|
</Table>
|
||||||
|
<InputField name="ТекущаяСсылка" id="10">
|
||||||
|
<DataPath>Items.Список.CurrentData.Ссылка</DataPath>
|
||||||
|
<ContextMenu name="ТекущаяСсылкаКонтекстноеМеню" id="11"/>
|
||||||
|
<ExtendedTooltip name="ТекущаяСсылкаРасширеннаяПодсказка" id="12"/>
|
||||||
|
</InputField>
|
||||||
|
<InputField name="ВыбраннаяСсылка" id="13">
|
||||||
|
<DataPath>~Список.Ссылка</DataPath>
|
||||||
|
<ContextMenu name="ВыбраннаяСсылкаКонтекстноеМеню" id="14"/>
|
||||||
|
<ExtendedTooltip name="ВыбраннаяСсылкаРасширеннаяПодсказка" id="15"/>
|
||||||
|
</InputField>
|
||||||
|
</ChildItems>
|
||||||
|
<Attributes>
|
||||||
|
<Attribute name="Список" id="16">
|
||||||
|
<Type>
|
||||||
|
<v8:Type>cfg:DynamicList</v8:Type>
|
||||||
|
</Type>
|
||||||
|
<MainAttribute>true</MainAttribute>
|
||||||
|
</Attribute>
|
||||||
|
</Attributes>
|
||||||
|
</Form>
|
||||||
Reference in New Issue
Block a user