From 9b5908c3b223d61c47804f085b50d60e65c2b7d5 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sat, 11 Jul 2026 21:05:51 +0300 Subject: [PATCH] =?UTF-8?q?feat(meta-validate):=20=D0=B1=D0=B0=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=8F=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BD=D0=B5=D1=80=D0=B0=D1=81=D0=BF=D0=BE=D0=B7=D0=BD?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D1=82=D0=B8=D0=BF=D0=BE=D0=B2=20+=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=89=D0=B0=D1=8E=D1=89=D0=B8=D0=B9=20=D0=B2?= =?UTF-8?q?=D0=B2=D0=BE=D0=B4=20=D0=BF=D0=BB=D0=BE=D1=81=D0=BA=D0=B8=D1=85?= =?UTF-8?q?=20=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA=D1=82=D0=BE=D0=B2=20(=D0=A4?= =?UTF-8?q?=D0=B0=D0=B7=D0=B0=201.4,=20v1.9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 20 валидных типов метаданных без глубоких правил (Subsystem/Role/CommonForm/ CommonCommand/CommandGroup/CommonAttribute/CommonTemplate/CommonPicture/ SessionParameter/SettingsStorage/FilterCriterion/FunctionalOption/ FunctionalOptionsParameter/Language/Style/StyleItem/WSReference/XDTOPackage/ DocumentNumerator/Sequence) раньше падали как "Unrecognized" + exit 1 — ложная ошибка на валидном объекте. Теперь для них базовая структурная проверка (root/uuid + Name-идентификатор) с ранним выходом, без type-specific правил. Имена типов взяты из LocalName реальных файлов корпуса. По-настоящему неизвестный тип по-прежнему отвергается. Побочно: прощающий ввод для плоских объектов (один .xml без папки — SessionParameter, CommonAttribute, DefinedType, ...) — раньше не находились по голому имени Dir/Name (fallback покрывал только папочные Dir/Name/Name.xml), добавлено дописывание .xml. Тесты (фикстуры не самописные): valid-sessionparameter-basic (meta-compile preRun) + real-erp-sessionparameter (external, скип на Mac) + error-unknown-type (реальный каталог корпуса с переименованным корневым тип-элементом). meta-validate 21/21 ps1+py. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../meta-validate/scripts/meta-validate.ps1 | 33 ++++++- .../meta-validate/scripts/meta-validate.py | 30 +++++- .../meta-validate/error-unknown-type.json | 6 ++ .../unknown-type/Catalogs/Неизвестный.xml | 91 +++++++++++++++++++ .../real-erp-sessionparameter.json | 9 ++ .../valid-sessionparameter-basic.json | 16 ++++ 6 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 tests/skills/cases/meta-validate/error-unknown-type.json create mode 100644 tests/skills/cases/meta-validate/fixtures/unknown-type/Catalogs/Неизвестный.xml create mode 100644 tests/skills/cases/meta-validate/real-erp-sessionparameter.json create mode 100644 tests/skills/cases/meta-validate/valid-sessionparameter-basic.json diff --git a/.claude/skills/meta-validate/scripts/meta-validate.ps1 b/.claude/skills/meta-validate/scripts/meta-validate.ps1 index 82acae13..f0b2ba66 100644 --- a/.claude/skills/meta-validate/scripts/meta-validate.ps1 +++ b/.claude/skills/meta-validate/scripts/meta-validate.ps1 @@ -1,4 +1,4 @@ -# meta-validate v1.8 — Validate 1C metadata object structure +# meta-validate v1.9 — Validate 1C metadata object structure # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -65,6 +65,12 @@ if (Test-Path $ObjectPath -PathType Container) { } } +# File not found — прощающий ввод для плоских объектов (SessionParameter, CommonAttribute, +# DefinedType, WSReference, … — один .xml без папки): дописать .xml к голому имени +if (-not (Test-Path $ObjectPath) -and -not [System.IO.Path]::HasExtension($ObjectPath)) { + if (Test-Path "$ObjectPath.xml") { $ObjectPath = "$ObjectPath.xml" } +} + # File not found — check Dir/Name/Name.xml → Dir/Name.xml if (-not (Test-Path $ObjectPath)) { $fileName = [System.IO.Path]::GetFileNameWithoutExtension($ObjectPath) @@ -162,6 +168,15 @@ $validTypes = @( "HTTPService","WebService","DefinedType" ) +# Валидные типы метаданных без глубоких правил валидации — раньше падали как "Unrecognized" +# (ложная ошибка на валидном объекте). Для них выполняется базовая структурная проверка (root/uuid/Name). +$structuralOnlyTypes = @( + "Subsystem","Role","CommonForm","CommonCommand","CommandGroup","CommonAttribute", + "CommonTemplate","CommonPicture","SessionParameter","SettingsStorage","FilterCriterion", + "FunctionalOption","FunctionalOptionsParameter","Language","Style","StyleItem", + "WSReference","XDTOPackage","DocumentNumerator","Sequence" +) + # GeneratedType categories by type $generatedTypeCategories = @{ "Catalog" = @("Object","Ref","Selection","List","Manager") @@ -355,7 +370,7 @@ if ($childElements.Count -eq 0) { $typeNode = $childElements[0] $mdType = $typeNode.LocalName -if ($validTypes -notcontains $mdType) { +if (($validTypes -notcontains $mdType) -and ($structuralOnlyTypes -notcontains $mdType)) { Report-Error "1. Unrecognized metadata type: $mdType" & $finalize exit 1 @@ -383,6 +398,20 @@ if ($check1Ok) { Report-OK "1. Root structure: MetaDataObject/$mdType, version $version" } +# --- Structural-only types: базовая проверка (Name), без type-specific правил --- +if ($structuralOnlyTypes -contains $mdType) { + if ($objName -eq "(unknown)") { + Report-Error "3. Properties: missing or empty Name" + } elseif ($objName -notmatch $identPattern) { + Report-Error "3. Properties: Name '$objName' is not a valid 1C identifier" + } else { + Report-OK "3. Properties: Name=`"$objName`" (базовая структурная проверка для $mdType)" + } + & $finalize + if ($script:errors -gt 0) { exit 1 } + exit 0 +} + if ($script:stopped) { & $finalize; exit 1 } # --- Check 2: InternalInfo --- diff --git a/.claude/skills/meta-validate/scripts/meta-validate.py b/.claude/skills/meta-validate/scripts/meta-validate.py index e800d269..083b201d 100644 --- a/.claude/skills/meta-validate/scripts/meta-validate.py +++ b/.claude/skills/meta-validate/scripts/meta-validate.py @@ -1,4 +1,4 @@ -# meta-validate v1.8 — Validate 1C metadata object structure (Python port) +# meta-validate v1.9 — Validate 1C metadata object structure (Python port) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import os @@ -70,6 +70,12 @@ if os.path.isdir(object_path): print(f"[ERROR] No XML file found in directory: {object_path}") sys.exit(1) +# File not found -- прощающий ввод для плоских объектов (SessionParameter, CommonAttribute, +# DefinedType, WSReference, ... -- один .xml без папки): дописать .xml к голому имени +if not os.path.exists(object_path) and not os.path.splitext(object_path)[1]: + if os.path.exists(object_path + ".xml"): + object_path = object_path + ".xml" + # File not found -- check Dir/Name/Name.xml -> Dir/Name.xml if not os.path.exists(object_path): file_name = os.path.splitext(os.path.basename(object_path))[0] @@ -162,6 +168,15 @@ valid_types = ( "HTTPService", "WebService", "DefinedType", ) +# Валидные типы метаданных без глубоких правил валидации — раньше падали как "Unrecognized" +# (ложная ошибка на валидном объекте). Для них выполняется базовая структурная проверка (root/uuid/Name). +structural_only_types = ( + "Subsystem", "Role", "CommonForm", "CommonCommand", "CommandGroup", "CommonAttribute", + "CommonTemplate", "CommonPicture", "SessionParameter", "SettingsStorage", "FilterCriterion", + "FunctionalOption", "FunctionalOptionsParameter", "Language", "Style", "StyleItem", + "WSReference", "XDTOPackage", "DocumentNumerator", "Sequence", +) + # GeneratedType categories by type generated_type_categories = { "Catalog": ["Object", "Ref", "Selection", "List", "Manager"], @@ -379,7 +394,7 @@ elif len(child_elements) > 1: type_node = child_elements[0] md_type = local_name(type_node) -if md_type not in valid_types: +if md_type not in valid_types and md_type not in structural_only_types: report_error(f"1. Unrecognized metadata type: {md_type}") finalize() sys.exit(1) @@ -404,6 +419,17 @@ output_lines.insert(0, f"=== Validation: {md_type}.{obj_name} ===") if check1_ok: report_ok(f"1. Root structure: MetaDataObject/{md_type}, version {version}") +# ── Structural-only types: базовая проверка (Name), без type-specific правил ── +if md_type in structural_only_types: + if obj_name == "(unknown)": + report_error("3. Properties: missing or empty Name") + elif not ident_pattern.match(obj_name): + report_error(f"3. Properties: Name '{obj_name}' is not a valid 1C identifier") + else: + report_ok(f'3. Properties: Name="{obj_name}" (базовая структурная проверка для {md_type})') + finalize() + sys.exit(1 if errors > 0 else 0) + if stopped: finalize() sys.exit(1) diff --git a/tests/skills/cases/meta-validate/error-unknown-type.json b/tests/skills/cases/meta-validate/error-unknown-type.json new file mode 100644 index 00000000..708e41e8 --- /dev/null +++ b/tests/skills/cases/meta-validate/error-unknown-type.json @@ -0,0 +1,6 @@ +{ + "name": "Валидатор всё ещё ловит по-настоящему неизвестный тип метаданных (гейт не стал слепым)", + "setup": "fixture:unknown-type", + "params": { "objectPath": "Catalogs/Неизвестный.xml" }, + "expectError": true +} diff --git a/tests/skills/cases/meta-validate/fixtures/unknown-type/Catalogs/Неизвестный.xml b/tests/skills/cases/meta-validate/fixtures/unknown-type/Catalogs/Неизвестный.xml new file mode 100644 index 00000000..f3100ab9 --- /dev/null +++ b/tests/skills/cases/meta-validate/fixtures/unknown-type/Catalogs/Неизвестный.xml @@ -0,0 +1,91 @@ + + + <НесуществующийТип uuid="82f554e2-86f6-4bf9-8c7d-d1499fc88bc4"> + + + d394a75c-51d2-457e-a698-e16a37831b71 + 0d654e63-ef5d-4c55-86e8-6775655ae10a + + + e486d1d3-8e16-40d1-902d-ae6ec9ac0740 + 07c1b906-d491-4175-bc52-69819c08049e + + + f1d3d2ef-8043-4aad-a124-9d747aa8b45c + 29896634-18fc-4101-a767-26a1c5755b08 + + + 930a4a7f-c496-4c5c-964a-5d80fb5636c3 + 09212a77-1293-4cca-9e15-3951959ecfcc + + + d2a75006-e316-4837-9179-fa2385a20203 + f4c7d49d-69fd-4f35-9aa9-51b70bc97b9b + + + + РолиКонтактныхЛиц + + + ru + Роли контактных лиц + + + + false + HierarchyFoldersAndItems + false + 2 + true + true + + ToItems + 9 + 50 + String + Fixed + WholeCatalog + true + true + AsDescription + + Auto + InList + false + BothWays + + Catalog.РолиКонтактныхЛиц.StandardAttribute.Description + Catalog.РолиКонтактныхЛиц.StandardAttribute.Code + + Begin + DontUse + Directly + + + + + + + + + + + false + + + Automatic + Use + + + + + + Use + Auto + DontUse + false + false + + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-validate/real-erp-sessionparameter.json b/tests/skills/cases/meta-validate/real-erp-sessionparameter.json new file mode 100644 index 00000000..6aac6a05 --- /dev/null +++ b/tests/skills/cases/meta-validate/real-erp-sessionparameter.json @@ -0,0 +1,9 @@ +{ + "name": "Валидация реального SessionParameter ERP (базовая структурная проверка)", + "setup": "external:C:/WS/tasks/cfsrc/erp_8.3.24", + "params": { "objectPath": "SessionParameters/АвторизованныйПользователь" }, + "args_extra": ["-Detailed"], + "expect": { + "stdoutContains": "базовая структурная проверка" + } +} diff --git a/tests/skills/cases/meta-validate/valid-sessionparameter-basic.json b/tests/skills/cases/meta-validate/valid-sessionparameter-basic.json new file mode 100644 index 00000000..24ea45f1 --- /dev/null +++ b/tests/skills/cases/meta-validate/valid-sessionparameter-basic.json @@ -0,0 +1,16 @@ +{ + "name": "meta-compile создаёт SessionParameter → meta-validate проходит базовую проверку, а не Unrecognized (Фаза 1.4)", + "setup": "empty-config", + "preRun": [ + { + "script": "meta-compile/scripts/meta-compile", + "input": { "type": "SessionParameter", "name": "ТекущийПользователь", "valueType": "CatalogRef.Пользователи" }, + "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } + } + ], + "params": { "objectPath": "SessionParameters/ТекущийПользователь" }, + "args_extra": ["-Detailed"], + "expect": { + "stdoutContains": "базовая структурная проверка" + } +}