From 9620c3846a879ff184cf3118924d94fa132c11c4 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 5 Apr 2026 16:39:17 +0300 Subject: [PATCH] =?UTF-8?q?fix(subsystem):=20normalize=20content=20refs=20?= =?UTF-8?q?=E2=80=94=20plural/Russian=20to=20singular=20English?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit subsystem-compile and subsystem-edit now auto-normalize content type prefixes (Catalogs→Catalog, Справочник→Catalog, Справочники→Catalog). subsystem-validate detects plural forms as errors in check #6. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../scripts/subsystem-compile.ps1 | 166 +++++++++++++++++- .../scripts/subsystem-compile.py | 95 +++++++++- .../subsystem-edit/scripts/subsystem-edit.ps1 | 86 ++++++++- .../subsystem-edit/scripts/subsystem-edit.py | 87 ++++++++- .../scripts/subsystem-validate.ps1 | 22 ++- .../scripts/subsystem-validate.py | 18 +- .../snapshots/basic/Subsystems/Склад.xml | 2 +- .../synonym-objects/Subsystems/Склад.xml | 2 +- .../snapshots/valid/Subsystems/Склад.xml | 2 +- 9 files changed, 465 insertions(+), 15 deletions(-) diff --git a/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 b/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 index 3e7e5b30..5580fa7b 100644 --- a/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 +++ b/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 @@ -1,4 +1,4 @@ -# subsystem-compile v1.1 — Create 1C subsystem from JSON definition +# subsystem-compile v1.2 — Create 1C subsystem from JSON definition # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$DefinitionFile, @@ -85,7 +85,155 @@ function New-Guid-String { return [System.Guid]::NewGuid().ToString() } -# --- 3. Resolve defaults --- +# --- 3. Content type normalization (plural→singular, Russian→English) --- +$script:contentTypeMap = @{ + # Plural English → Singular + "Catalogs" = "Catalog" + "Documents" = "Document" + "Enums" = "Enum" + "Constants" = "Constant" + "Reports" = "Report" + "DataProcessors" = "DataProcessor" + "InformationRegisters" = "InformationRegister" + "AccumulationRegisters" = "AccumulationRegister" + "AccountingRegisters" = "AccountingRegister" + "CalculationRegisters" = "CalculationRegister" + "ChartsOfAccounts" = "ChartOfAccounts" + "ChartsOfCharacteristicTypes" = "ChartOfCharacteristicTypes" + "ChartsOfCalculationTypes" = "ChartOfCalculationTypes" + "BusinessProcesses" = "BusinessProcess" + "Tasks" = "Task" + "ExchangePlans" = "ExchangePlan" + "DocumentJournals" = "DocumentJournal" + "CommonModules" = "CommonModule" + "CommonCommands" = "CommonCommand" + "CommonForms" = "CommonForm" + "CommonPictures" = "CommonPicture" + "CommonTemplates" = "CommonTemplate" + "CommonAttributes" = "CommonAttribute" + "CommandGroups" = "CommandGroup" + "Roles" = "Role" + "SessionParameters" = "SessionParameter" + "FilterCriteria" = "FilterCriterion" + "XDTOPackages" = "XDTOPackage" + "WebServices" = "WebService" + "HTTPServices" = "HTTPService" + "WSReferences" = "WSReference" + "EventSubscriptions" = "EventSubscription" + "ScheduledJobs" = "ScheduledJob" + "SettingsStorages" = "SettingsStorage" + "FunctionalOptions" = "FunctionalOption" + "FunctionalOptionsParameters" = "FunctionalOptionsParameter" + "DefinedTypes" = "DefinedType" + "DocumentNumerators" = "DocumentNumerator" + "Sequences" = "Sequence" + "Subsystems" = "Subsystem" + "StyleItems" = "StyleItem" + "IntegrationServices" = "IntegrationService" + # Russian singular → English + "Справочник" = "Catalog" + "Каталог" = "Catalog" + "Документ" = "Document" + "Перечисление" = "Enum" + "Константа" = "Constant" + "Отчёт" = "Report" + "Отчет" = "Report" + "Обработка" = "DataProcessor" + "РегистрСведений" = "InformationRegister" + "РегистрНакопления" = "AccumulationRegister" + "РегистрБухгалтерии" = "AccountingRegister" + "РегистрРасчёта" = "CalculationRegister" + "РегистрРасчета" = "CalculationRegister" + "ПланСчетов" = "ChartOfAccounts" + "ПланВидовХарактеристик" = "ChartOfCharacteristicTypes" + "ПланВидовРасчёта" = "ChartOfCalculationTypes" + "ПланВидовРасчета" = "ChartOfCalculationTypes" + "БизнесПроцесс" = "BusinessProcess" + "Задача" = "Task" + "ПланОбмена" = "ExchangePlan" + "ЖурналДокументов" = "DocumentJournal" + "ОбщийМодуль" = "CommonModule" + "ОбщаяКоманда" = "CommonCommand" + "ОбщаяФорма" = "CommonForm" + "ОбщаяКартинка" = "CommonPicture" + "ОбщийМакет" = "CommonTemplate" + "ОбщийРеквизит" = "CommonAttribute" + "ГруппаКоманд" = "CommandGroup" + "Роль" = "Role" + "ПараметрСеанса" = "SessionParameter" + "КритерийОтбора" = "FilterCriterion" + "ПакетXDTO" = "XDTOPackage" + "ВебСервис" = "WebService" + "HTTPСервис" = "HTTPService" + "WSСсылка" = "WSReference" + "ПодпискаНаСобытие" = "EventSubscription" + "РегламентноеЗадание" = "ScheduledJob" + "ХранилищеНастроек" = "SettingsStorage" + "ФункциональнаяОпция" = "FunctionalOption" + "ПараметрФункциональныхОпций" = "FunctionalOptionsParameter" + "ОпределяемыйТип" = "DefinedType" + "НумераторДокументов" = "DocumentNumerator" + "Последовательность" = "Sequence" + "Подсистема" = "Subsystem" + "ЭлементСтиля" = "StyleItem" + "СервисИнтеграции" = "IntegrationService" + # Russian plural → English + "Справочники" = "Catalog" + "Документы" = "Document" + "Перечисления" = "Enum" + "Константы" = "Constant" + "Отчёты" = "Report" + "Отчеты" = "Report" + "Обработки" = "DataProcessor" + "РегистрыСведений" = "InformationRegister" + "РегистрыНакопления" = "AccumulationRegister" + "РегистрыБухгалтерии" = "AccountingRegister" + "РегистрыРасчёта" = "CalculationRegister" + "РегистрыРасчета" = "CalculationRegister" + "ПланыСчетов" = "ChartOfAccounts" + "ПланыВидовХарактеристик" = "ChartOfCharacteristicTypes" + "ПланыВидовРасчёта" = "ChartOfCalculationTypes" + "ПланыВидовРасчета" = "ChartOfCalculationTypes" + "БизнесПроцессы" = "BusinessProcess" + "Задачи" = "Task" + "ПланыОбмена" = "ExchangePlan" + "ЖурналыДокументов" = "DocumentJournal" + "ОбщиеМодули" = "CommonModule" + "ОбщиеКоманды" = "CommonCommand" + "ОбщиеФормы" = "CommonForm" + "ОбщиеКартинки" = "CommonPicture" + "ОбщиеМакеты" = "CommonTemplate" + "ОбщиеРеквизиты" = "CommonAttribute" + "ГруппыКоманд" = "CommandGroup" + "Роли" = "Role" + "ПараметрыСеанса" = "SessionParameter" + "КритерииОтбора" = "FilterCriterion" + "ПакетыXDTO" = "XDTOPackage" + "ВебСервисы" = "WebService" + "HTTPСервисы" = "HTTPService" + "WSСсылки" = "WSReference" + "ПодпискиНаСобытия" = "EventSubscription" + "РегламентныеЗадания" = "ScheduledJob" + "ХранилищаНастроек" = "SettingsStorage" + "ФункциональныеОпции" = "FunctionalOption" + "ОпределяемыеТипы" = "DefinedType" + "Подсистемы" = "Subsystem" + "ЭлементыСтиля" = "StyleItem" + "СервисыИнтеграции" = "IntegrationService" +} + +function Normalize-ContentRef([string]$ref) { + if (-not $ref -or -not $ref.Contains('.')) { return $ref } + $dotIdx = $ref.IndexOf('.') + $typePart = $ref.Substring(0, $dotIdx) + $namePart = $ref.Substring($dotIdx + 1) + if ($script:contentTypeMap.ContainsKey($typePart)) { + $typePart = $script:contentTypeMap[$typePart] + } + return "$typePart.$namePart" +} + +# --- 4. Resolve defaults --- $synonym = if ($def.synonym) { "$($def.synonym)" } else { Split-CamelCase $objName } $comment = if ($def.comment) { "$($def.comment)" } else { "" } $includeHelpInContents = "true" @@ -98,8 +246,20 @@ $picture = if ($def.picture) { "$($def.picture)" } else { "" } if (-not $def.content -and $def.objects) { $def | Add-Member -NotePropertyName content -NotePropertyValue $def.objects } $contentItems = @() +$normalizedCount = 0 if ($def.content) { - foreach ($c in $def.content) { $contentItems += "$c" } + foreach ($c in $def.content) { + $raw = "$c" + $normalized = Normalize-ContentRef $raw + if ($normalized -ne $raw) { + Write-Host "[NORM] Content: $raw -> $normalized" + $normalizedCount++ + } + $contentItems += $normalized + } +} +if ($normalizedCount -gt 0) { + Write-Host "[INFO] Normalized $normalizedCount content reference(s) to singular English form" } $children = @() diff --git a/.claude/skills/subsystem-compile/scripts/subsystem-compile.py b/.claude/skills/subsystem-compile/scripts/subsystem-compile.py index 9e081421..031a1ad0 100644 --- a/.claude/skills/subsystem-compile/scripts/subsystem-compile.py +++ b/.claude/skills/subsystem-compile/scripts/subsystem-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# subsystem-compile v1.1 — Create 1C subsystem from JSON definition +# subsystem-compile v1.2 — Create 1C subsystem from JSON definition # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json @@ -88,7 +88,88 @@ def main(): if not os.path.isabs(output_dir): output_dir = os.path.join(os.getcwd(), output_dir) - # --- 2. Resolve defaults --- + # --- 2. Content type normalization (plural→singular, Russian→English) --- + CONTENT_TYPE_MAP = { + # Plural English → Singular + 'Catalogs': 'Catalog', 'Documents': 'Document', 'Enums': 'Enum', + 'Constants': 'Constant', 'Reports': 'Report', 'DataProcessors': 'DataProcessor', + 'InformationRegisters': 'InformationRegister', 'AccumulationRegisters': 'AccumulationRegister', + 'AccountingRegisters': 'AccountingRegister', 'CalculationRegisters': 'CalculationRegister', + 'ChartsOfAccounts': 'ChartOfAccounts', 'ChartsOfCharacteristicTypes': 'ChartOfCharacteristicTypes', + 'ChartsOfCalculationTypes': 'ChartOfCalculationTypes', + 'BusinessProcesses': 'BusinessProcess', 'Tasks': 'Task', + 'ExchangePlans': 'ExchangePlan', 'DocumentJournals': 'DocumentJournal', + 'CommonModules': 'CommonModule', 'CommonCommands': 'CommonCommand', + 'CommonForms': 'CommonForm', 'CommonPictures': 'CommonPicture', + 'CommonTemplates': 'CommonTemplate', 'CommonAttributes': 'CommonAttribute', + 'CommandGroups': 'CommandGroup', 'Roles': 'Role', + 'SessionParameters': 'SessionParameter', 'FilterCriteria': 'FilterCriterion', + 'XDTOPackages': 'XDTOPackage', 'WebServices': 'WebService', + 'HTTPServices': 'HTTPService', 'WSReferences': 'WSReference', + 'EventSubscriptions': 'EventSubscription', 'ScheduledJobs': 'ScheduledJob', + 'SettingsStorages': 'SettingsStorage', 'FunctionalOptions': 'FunctionalOption', + 'FunctionalOptionsParameters': 'FunctionalOptionsParameter', + 'DefinedTypes': 'DefinedType', 'DocumentNumerators': 'DocumentNumerator', + 'Sequences': 'Sequence', 'Subsystems': 'Subsystem', + 'StyleItems': 'StyleItem', 'IntegrationServices': 'IntegrationService', + # Russian singular → English + 'Справочник': 'Catalog', 'Каталог': 'Catalog', 'Документ': 'Document', + 'Перечисление': 'Enum', 'Константа': 'Constant', + 'Отчёт': 'Report', 'Отчет': 'Report', 'Обработка': 'DataProcessor', + 'РегистрСведений': 'InformationRegister', 'РегистрНакопления': 'AccumulationRegister', + 'РегистрБухгалтерии': 'AccountingRegister', + 'РегистрРасчёта': 'CalculationRegister', 'РегистрРасчета': 'CalculationRegister', + 'ПланСчетов': 'ChartOfAccounts', 'ПланВидовХарактеристик': 'ChartOfCharacteristicTypes', + 'ПланВидовРасчёта': 'ChartOfCalculationTypes', 'ПланВидовРасчета': 'ChartOfCalculationTypes', + 'БизнесПроцесс': 'BusinessProcess', 'Задача': 'Task', + 'ПланОбмена': 'ExchangePlan', 'ЖурналДокументов': 'DocumentJournal', + 'ОбщийМодуль': 'CommonModule', 'ОбщаяКоманда': 'CommonCommand', + 'ОбщаяФорма': 'CommonForm', 'ОбщаяКартинка': 'CommonPicture', + 'ОбщийМакет': 'CommonTemplate', 'ОбщийРеквизит': 'CommonAttribute', + 'ГруппаКоманд': 'CommandGroup', 'Роль': 'Role', + 'ПараметрСеанса': 'SessionParameter', 'КритерийОтбора': 'FilterCriterion', + 'ПакетXDTO': 'XDTOPackage', 'ВебСервис': 'WebService', + 'HTTPСервис': 'HTTPService', 'WSСсылка': 'WSReference', + 'ПодпискаНаСобытие': 'EventSubscription', 'РегламентноеЗадание': 'ScheduledJob', + 'ХранилищеНастроек': 'SettingsStorage', 'ФункциональнаяОпция': 'FunctionalOption', + 'ПараметрФункциональныхОпций': 'FunctionalOptionsParameter', + 'ОпределяемыйТип': 'DefinedType', 'НумераторДокументов': 'DocumentNumerator', + 'Последовательность': 'Sequence', 'Подсистема': 'Subsystem', + 'ЭлементСтиля': 'StyleItem', 'СервисИнтеграции': 'IntegrationService', + # Russian plural → English + 'Справочники': 'Catalog', 'Документы': 'Document', 'Перечисления': 'Enum', + 'Константы': 'Constant', 'Отчёты': 'Report', 'Отчеты': 'Report', + 'Обработки': 'DataProcessor', 'РегистрыСведений': 'InformationRegister', + 'РегистрыНакопления': 'AccumulationRegister', 'РегистрыБухгалтерии': 'AccountingRegister', + 'РегистрыРасчёта': 'CalculationRegister', 'РегистрыРасчета': 'CalculationRegister', + 'ПланыСчетов': 'ChartOfAccounts', 'ПланыВидовХарактеристик': 'ChartOfCharacteristicTypes', + 'ПланыВидовРасчёта': 'ChartOfCalculationTypes', 'ПланыВидовРасчета': 'ChartOfCalculationTypes', + 'БизнесПроцессы': 'BusinessProcess', 'Задачи': 'Task', + 'ПланыОбмена': 'ExchangePlan', 'ЖурналыДокументов': 'DocumentJournal', + 'ОбщиеМодули': 'CommonModule', 'ОбщиеКоманды': 'CommonCommand', + 'ОбщиеФормы': 'CommonForm', 'ОбщиеКартинки': 'CommonPicture', + 'ОбщиеМакеты': 'CommonTemplate', 'ОбщиеРеквизиты': 'CommonAttribute', + 'ГруппыКоманд': 'CommandGroup', 'Роли': 'Role', + 'ПараметрыСеанса': 'SessionParameter', 'КритерииОтбора': 'FilterCriterion', + 'ПакетыXDTO': 'XDTOPackage', 'ВебСервисы': 'WebService', + 'HTTPСервисы': 'HTTPService', 'WSСсылки': 'WSReference', + 'ПодпискиНаСобытия': 'EventSubscription', 'РегламентныеЗадания': 'ScheduledJob', + 'ХранилищаНастроек': 'SettingsStorage', 'ФункциональныеОпции': 'FunctionalOption', + 'ОпределяемыеТипы': 'DefinedType', 'Подсистемы': 'Subsystem', + 'ЭлементыСтиля': 'StyleItem', 'СервисыИнтеграции': 'IntegrationService', + } + + def normalize_content_ref(ref): + if not ref or '.' not in ref: + return ref + dot_idx = ref.index('.') + type_part = ref[:dot_idx] + name_part = ref[dot_idx + 1:] + if type_part in CONTENT_TYPE_MAP: + type_part = CONTENT_TYPE_MAP[type_part] + return f'{type_part}.{name_part}' + + # --- 3. Resolve defaults --- synonym = str(defn['synonym']) if defn.get('synonym') else split_camel_case(obj_name) comment = str(defn['comment']) if defn.get('comment') else '' include_help_in_contents = 'true' @@ -102,9 +183,17 @@ def main(): defn['content'] = defn['objects'] content_items = [] + normalized_count = 0 if defn.get('content'): for c in defn['content']: - content_items.append(str(c)) + raw = str(c) + normalized = normalize_content_ref(raw) + if normalized != raw: + print(f'[NORM] Content: {raw} -> {normalized}') + normalized_count += 1 + content_items.append(normalized) + if normalized_count > 0: + print(f'[INFO] Normalized {normalized_count} content reference(s) to singular English form') children = [] if defn.get('children'): diff --git a/.claude/skills/subsystem-edit/scripts/subsystem-edit.ps1 b/.claude/skills/subsystem-edit/scripts/subsystem-edit.ps1 index ff108342..bfcaa1fc 100644 --- a/.claude/skills/subsystem-edit/scripts/subsystem-edit.ps1 +++ b/.claude/skills/subsystem-edit/scripts/subsystem-edit.ps1 @@ -1,4 +1,4 @@ -# subsystem-edit v1.0 — Edit existing 1C subsystem XML +# subsystem-edit v1.1 — Edit existing 1C subsystem XML # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)][string]$SubsystemPath, @@ -12,6 +12,86 @@ param( $ErrorActionPreference = "Stop" [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 +# --- Content type normalization (plural→singular, Russian→English) --- +$script:contentTypeMap = @{ + "Catalogs"="Catalog"; "Documents"="Document"; "Enums"="Enum"; "Constants"="Constant" + "Reports"="Report"; "DataProcessors"="DataProcessor" + "InformationRegisters"="InformationRegister"; "AccumulationRegisters"="AccumulationRegister" + "AccountingRegisters"="AccountingRegister"; "CalculationRegisters"="CalculationRegister" + "ChartsOfAccounts"="ChartOfAccounts"; "ChartsOfCharacteristicTypes"="ChartOfCharacteristicTypes" + "ChartsOfCalculationTypes"="ChartOfCalculationTypes" + "BusinessProcesses"="BusinessProcess"; "Tasks"="Task" + "ExchangePlans"="ExchangePlan"; "DocumentJournals"="DocumentJournal" + "CommonModules"="CommonModule"; "CommonCommands"="CommonCommand" + "CommonForms"="CommonForm"; "CommonPictures"="CommonPicture" + "CommonTemplates"="CommonTemplate"; "CommonAttributes"="CommonAttribute" + "CommandGroups"="CommandGroup"; "Roles"="Role" + "SessionParameters"="SessionParameter"; "FilterCriteria"="FilterCriterion" + "XDTOPackages"="XDTOPackage"; "WebServices"="WebService" + "HTTPServices"="HTTPService"; "WSReferences"="WSReference" + "EventSubscriptions"="EventSubscription"; "ScheduledJobs"="ScheduledJob" + "SettingsStorages"="SettingsStorage"; "FunctionalOptions"="FunctionalOption" + "FunctionalOptionsParameters"="FunctionalOptionsParameter" + "DefinedTypes"="DefinedType"; "DocumentNumerators"="DocumentNumerator" + "Sequences"="Sequence"; "Subsystems"="Subsystem" + "StyleItems"="StyleItem"; "IntegrationServices"="IntegrationService" + # Russian singular + "Справочник"="Catalog"; "Каталог"="Catalog"; "Документ"="Document" + "Перечисление"="Enum"; "Константа"="Constant" + "Отчёт"="Report"; "Отчет"="Report"; "Обработка"="DataProcessor" + "РегистрСведений"="InformationRegister"; "РегистрНакопления"="AccumulationRegister" + "РегистрБухгалтерии"="AccountingRegister" + "РегистрРасчёта"="CalculationRegister"; "РегистрРасчета"="CalculationRegister" + "ПланСчетов"="ChartOfAccounts"; "ПланВидовХарактеристик"="ChartOfCharacteristicTypes" + "ПланВидовРасчёта"="ChartOfCalculationTypes"; "ПланВидовРасчета"="ChartOfCalculationTypes" + "БизнесПроцесс"="BusinessProcess"; "Задача"="Task" + "ПланОбмена"="ExchangePlan"; "ЖурналДокументов"="DocumentJournal" + "ОбщийМодуль"="CommonModule"; "ОбщаяКоманда"="CommonCommand" + "ОбщаяФорма"="CommonForm"; "ОбщаяКартинка"="CommonPicture" + "ОбщийМакет"="CommonTemplate"; "ОбщийРеквизит"="CommonAttribute" + "ГруппаКоманд"="CommandGroup"; "Роль"="Role" + "ПараметрСеанса"="SessionParameter"; "КритерийОтбора"="FilterCriterion" + "ПакетXDTO"="XDTOPackage"; "ВебСервис"="WebService" + "HTTPСервис"="HTTPService"; "WSСсылка"="WSReference" + "ПодпискаНаСобытие"="EventSubscription"; "РегламентноеЗадание"="ScheduledJob" + "ХранилищеНастроек"="SettingsStorage"; "ФункциональнаяОпция"="FunctionalOption" + "ПараметрФункциональныхОпций"="FunctionalOptionsParameter" + "ОпределяемыйТип"="DefinedType"; "Подсистема"="Subsystem" + "ЭлементСтиля"="StyleItem"; "СервисИнтеграции"="IntegrationService" + # Russian plural + "Справочники"="Catalog"; "Документы"="Document"; "Перечисления"="Enum" + "Константы"="Constant"; "Отчёты"="Report"; "Отчеты"="Report" + "Обработки"="DataProcessor"; "РегистрыСведений"="InformationRegister" + "РегистрыНакопления"="AccumulationRegister"; "РегистрыБухгалтерии"="AccountingRegister" + "РегистрыРасчёта"="CalculationRegister"; "РегистрыРасчета"="CalculationRegister" + "ПланыСчетов"="ChartOfAccounts"; "ПланыВидовХарактеристик"="ChartOfCharacteristicTypes" + "ПланыВидовРасчёта"="ChartOfCalculationTypes"; "ПланыВидовРасчета"="ChartOfCalculationTypes" + "БизнесПроцессы"="BusinessProcess"; "Задачи"="Task" + "ПланыОбмена"="ExchangePlan"; "ЖурналыДокументов"="DocumentJournal" + "ОбщиеМодули"="CommonModule"; "ОбщиеКоманды"="CommonCommand" + "ОбщиеФормы"="CommonForm"; "ОбщиеКартинки"="CommonPicture" + "ОбщиеМакеты"="CommonTemplate"; "ОбщиеРеквизиты"="CommonAttribute" + "ГруппыКоманд"="CommandGroup"; "Роли"="Role" + "ПараметрыСеанса"="SessionParameter"; "КритерииОтбора"="FilterCriterion" + "ПакетыXDTO"="XDTOPackage"; "ВебСервисы"="WebService" + "HTTPСервисы"="HTTPService"; "WSСсылки"="WSReference" + "ПодпискиНаСобытия"="EventSubscription"; "РегламентныеЗадания"="ScheduledJob" + "ХранилищаНастроек"="SettingsStorage"; "ФункциональныеОпции"="FunctionalOption" + "ОпределяемыеТипы"="DefinedType"; "Подсистемы"="Subsystem" + "ЭлементыСтиля"="StyleItem"; "СервисыИнтеграции"="IntegrationService" +} + +function Normalize-ContentRef([string]$ref) { + if (-not $ref -or -not $ref.Contains('.')) { return $ref } + $dotIdx = $ref.IndexOf('.') + $typePart = $ref.Substring(0, $dotIdx) + $namePart = $ref.Substring($dotIdx + 1) + if ($script:contentTypeMap.ContainsKey($typePart)) { + $typePart = $script:contentTypeMap[$typePart] + } + return "$typePart.$namePart" +} + # --- Mode validation --- if ($DefinitionFile -and $Operation) { Write-Error "Cannot use both -DefinitionFile and -Operation"; exit 1 } if (-not $DefinitionFile -and -not $Operation) { Write-Error "Either -DefinitionFile or -Operation is required"; exit 1 } @@ -194,7 +274,9 @@ function Do-AddContent([string[]]$items) { $contentIndent = Get-ChildIndent $contentEl } - foreach ($item in $items) { + foreach ($rawItem in $items) { + $item = Normalize-ContentRef $rawItem + if ($item -ne $rawItem) { Write-Host "[NORM] Content: $rawItem -> $item" } if ($item -in $existing) { Warn "Content already contains: $item" continue diff --git a/.claude/skills/subsystem-edit/scripts/subsystem-edit.py b/.claude/skills/subsystem-edit/scripts/subsystem-edit.py index 36158da3..ed2ddbfc 100644 --- a/.claude/skills/subsystem-edit/scripts/subsystem-edit.py +++ b/.claude/skills/subsystem-edit/scripts/subsystem-edit.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# subsystem-edit v1.0 — Edit existing 1C subsystem XML +# subsystem-edit v1.1 — Edit existing 1C subsystem XML # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -24,6 +24,86 @@ NSMAP_WRAPPER = { } +CONTENT_TYPE_MAP = { + 'Catalogs': 'Catalog', 'Documents': 'Document', 'Enums': 'Enum', + 'Constants': 'Constant', 'Reports': 'Report', 'DataProcessors': 'DataProcessor', + 'InformationRegisters': 'InformationRegister', 'AccumulationRegisters': 'AccumulationRegister', + 'AccountingRegisters': 'AccountingRegister', 'CalculationRegisters': 'CalculationRegister', + 'ChartsOfAccounts': 'ChartOfAccounts', 'ChartsOfCharacteristicTypes': 'ChartOfCharacteristicTypes', + 'ChartsOfCalculationTypes': 'ChartOfCalculationTypes', + 'BusinessProcesses': 'BusinessProcess', 'Tasks': 'Task', + 'ExchangePlans': 'ExchangePlan', 'DocumentJournals': 'DocumentJournal', + 'CommonModules': 'CommonModule', 'CommonCommands': 'CommonCommand', + 'CommonForms': 'CommonForm', 'CommonPictures': 'CommonPicture', + 'CommonTemplates': 'CommonTemplate', 'CommonAttributes': 'CommonAttribute', + 'CommandGroups': 'CommandGroup', 'Roles': 'Role', + 'SessionParameters': 'SessionParameter', 'FilterCriteria': 'FilterCriterion', + 'XDTOPackages': 'XDTOPackage', 'WebServices': 'WebService', + 'HTTPServices': 'HTTPService', 'WSReferences': 'WSReference', + 'EventSubscriptions': 'EventSubscription', 'ScheduledJobs': 'ScheduledJob', + 'SettingsStorages': 'SettingsStorage', 'FunctionalOptions': 'FunctionalOption', + 'FunctionalOptionsParameters': 'FunctionalOptionsParameter', + 'DefinedTypes': 'DefinedType', 'DocumentNumerators': 'DocumentNumerator', + 'Sequences': 'Sequence', 'Subsystems': 'Subsystem', + 'StyleItems': 'StyleItem', 'IntegrationServices': 'IntegrationService', + # Russian singular + 'Справочник': 'Catalog', 'Каталог': 'Catalog', 'Документ': 'Document', + 'Перечисление': 'Enum', 'Константа': 'Constant', + 'Отчёт': 'Report', 'Отчет': 'Report', 'Обработка': 'DataProcessor', + 'РегистрСведений': 'InformationRegister', 'РегистрНакопления': 'AccumulationRegister', + 'РегистрБухгалтерии': 'AccountingRegister', + 'РегистрРасчёта': 'CalculationRegister', 'РегистрРасчета': 'CalculationRegister', + 'ПланСчетов': 'ChartOfAccounts', 'ПланВидовХарактеристик': 'ChartOfCharacteristicTypes', + 'ПланВидовРасчёта': 'ChartOfCalculationTypes', 'ПланВидовРасчета': 'ChartOfCalculationTypes', + 'БизнесПроцесс': 'BusinessProcess', 'Задача': 'Task', + 'ПланОбмена': 'ExchangePlan', 'ЖурналДокументов': 'DocumentJournal', + 'ОбщийМодуль': 'CommonModule', 'ОбщаяКоманда': 'CommonCommand', + 'ОбщаяФорма': 'CommonForm', 'ОбщаяКартинка': 'CommonPicture', + 'ОбщийМакет': 'CommonTemplate', 'ОбщийРеквизит': 'CommonAttribute', + 'ГруппаКоманд': 'CommandGroup', 'Роль': 'Role', + 'ПараметрСеанса': 'SessionParameter', 'КритерийОтбора': 'FilterCriterion', + 'ПакетXDTO': 'XDTOPackage', 'ВебСервис': 'WebService', + 'HTTPСервис': 'HTTPService', 'WSСсылка': 'WSReference', + 'ПодпискаНаСобытие': 'EventSubscription', 'РегламентноеЗадание': 'ScheduledJob', + 'ХранилищеНастроек': 'SettingsStorage', 'ФункциональнаяОпция': 'FunctionalOption', + 'ПараметрФункциональныхОпций': 'FunctionalOptionsParameter', + 'ОпределяемыйТип': 'DefinedType', 'Подсистема': 'Subsystem', + 'ЭлементСтиля': 'StyleItem', 'СервисИнтеграции': 'IntegrationService', + # Russian plural + 'Справочники': 'Catalog', 'Документы': 'Document', 'Перечисления': 'Enum', + 'Константы': 'Constant', 'Отчёты': 'Report', 'Отчеты': 'Report', + 'Обработки': 'DataProcessor', 'РегистрыСведений': 'InformationRegister', + 'РегистрыНакопления': 'AccumulationRegister', 'РегистрыБухгалтерии': 'AccountingRegister', + 'РегистрыРасчёта': 'CalculationRegister', 'РегистрыРасчета': 'CalculationRegister', + 'ПланыСчетов': 'ChartOfAccounts', 'ПланыВидовХарактеристик': 'ChartOfCharacteristicTypes', + 'ПланыВидовРасчёта': 'ChartOfCalculationTypes', 'ПланыВидовРасчета': 'ChartOfCalculationTypes', + 'БизнесПроцессы': 'BusinessProcess', 'Задачи': 'Task', + 'ПланыОбмена': 'ExchangePlan', 'ЖурналыДокументов': 'DocumentJournal', + 'ОбщиеМодули': 'CommonModule', 'ОбщиеКоманды': 'CommonCommand', + 'ОбщиеФормы': 'CommonForm', 'ОбщиеКартинки': 'CommonPicture', + 'ОбщиеМакеты': 'CommonTemplate', 'ОбщиеРеквизиты': 'CommonAttribute', + 'ГруппыКоманд': 'CommandGroup', 'Роли': 'Role', + 'ПараметрыСеанса': 'SessionParameter', 'КритерииОтбора': 'FilterCriterion', + 'ПакетыXDTO': 'XDTOPackage', 'ВебСервисы': 'WebService', + 'HTTPСервисы': 'HTTPService', 'WSСсылки': 'WSReference', + 'ПодпискиНаСобытия': 'EventSubscription', 'РегламентныеЗадания': 'ScheduledJob', + 'ХранилищаНастроек': 'SettingsStorage', 'ФункциональныеОпции': 'FunctionalOption', + 'ОпределяемыеТипы': 'DefinedType', 'Подсистемы': 'Subsystem', + 'ЭлементыСтиля': 'StyleItem', 'СервисыИнтеграции': 'IntegrationService', +} + + +def normalize_content_ref(ref): + if not ref or '.' not in ref: + return ref + dot_idx = ref.index('.') + type_part = ref[:dot_idx] + name_part = ref[dot_idx + 1:] + if type_part in CONTENT_TYPE_MAP: + type_part = CONTENT_TYPE_MAP[type_part] + return f'{type_part}.{name_part}' + + def localname(el): return etree.QName(el.tag).localname @@ -239,7 +319,10 @@ def main(): expand_self_closing(content_el, props_indent) content_indent = get_child_indent(content_el) - for item in items: + for raw_item in items: + item = normalize_content_ref(raw_item) + if item != raw_item: + print(f'[NORM] Content: {raw_item} -> {item}') if item in existing: warn(f"Content already contains: {item}") continue diff --git a/.claude/skills/subsystem-validate/scripts/subsystem-validate.ps1 b/.claude/skills/subsystem-validate/scripts/subsystem-validate.ps1 index 7245d66c..e9620a53 100644 --- a/.claude/skills/subsystem-validate/scripts/subsystem-validate.ps1 +++ b/.claude/skills/subsystem-validate/scripts/subsystem-validate.ps1 @@ -1,4 +1,4 @@ -# subsystem-validate v1.1 — Validate 1C subsystem XML structure +# subsystem-validate v1.2 — Validate 1C subsystem XML structure # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)][string]$SubsystemPath, @@ -65,6 +65,19 @@ function Report-Warn([string]$msg) { $guidPattern = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' $identPattern = '^[A-Za-z\u0410-\u042F\u0401\u0430-\u044F\u0451_][A-Za-z0-9\u0410-\u042F\u0401\u0430-\u044F\u0451_]*$' +# Known plural forms that are NOT valid in subsystem Content (platform expects singular) +$knownPluralTypes = @( + "Catalogs","Documents","Enums","Constants","Reports","DataProcessors" + "InformationRegisters","AccumulationRegisters","AccountingRegisters","CalculationRegisters" + "ChartsOfAccounts","ChartsOfCharacteristicTypes","ChartsOfCalculationTypes" + "BusinessProcesses","Tasks","ExchangePlans","DocumentJournals" + "CommonModules","CommonCommands","CommonForms","CommonPictures","CommonTemplates" + "CommonAttributes","CommandGroups","Roles","SessionParameters","FilterCriteria" + "XDTOPackages","WebServices","HTTPServices","WSReferences","EventSubscriptions" + "ScheduledJobs","SettingsStorages","FunctionalOptions","FunctionalOptionsParameters" + "DefinedTypes","DocumentNumerators","Sequences","Subsystems","StyleItems","IntegrationServices" +) + # --- 1. XML well-formedness + root structure --- $xmlDoc = $null try { @@ -190,6 +203,13 @@ if (-not $script:stopped) { Report-Error "6. Content item `"$text`": invalid format (expected Type.Name or UUID)" $contentOk = $false } + if ($text -match '^([A-Za-z]+)\.') { + $typePart = $Matches[1] + if ($typePart -in $knownPluralTypes) { + Report-Error "6. Content item `"$text`": uses plural form `"$typePart`" (platform requires singular, e.g. Catalog not Catalogs)" + $contentOk = $false + } + } } if ($contentOk) { Report-OK "6. Content: $($xrItems.Count) items, all valid MDObjectRef format" } } else { diff --git a/.claude/skills/subsystem-validate/scripts/subsystem-validate.py b/.claude/skills/subsystem-validate/scripts/subsystem-validate.py index 1db00fbe..91e7c350 100644 --- a/.claude/skills/subsystem-validate/scripts/subsystem-validate.py +++ b/.claude/skills/subsystem-validate/scripts/subsystem-validate.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# subsystem-validate v1.1 — Validate 1C subsystem XML structure +# subsystem-validate v1.2 — Validate 1C subsystem XML structure # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills """Validates subsystem XML file structure, properties, content items, child objects.""" import sys, os, argparse, re @@ -20,6 +20,18 @@ IDENT_PATTERN = re.compile( r'[A-Za-z0-9\u0410-\u042F\u0401\u0430-\u044F\u0451_]*$' ) +KNOWN_PLURAL_TYPES = { + 'Catalogs', 'Documents', 'Enums', 'Constants', 'Reports', 'DataProcessors', + 'InformationRegisters', 'AccumulationRegisters', 'AccountingRegisters', 'CalculationRegisters', + 'ChartsOfAccounts', 'ChartsOfCharacteristicTypes', 'ChartsOfCalculationTypes', + 'BusinessProcesses', 'Tasks', 'ExchangePlans', 'DocumentJournals', + 'CommonModules', 'CommonCommands', 'CommonForms', 'CommonPictures', 'CommonTemplates', + 'CommonAttributes', 'CommandGroups', 'Roles', 'SessionParameters', 'FilterCriteria', + 'XDTOPackages', 'WebServices', 'HTTPServices', 'WSReferences', 'EventSubscriptions', + 'ScheduledJobs', 'SettingsStorages', 'FunctionalOptions', 'FunctionalOptionsParameters', + 'DefinedTypes', 'DocumentNumerators', 'Sequences', 'Subsystems', 'StyleItems', 'IntegrationServices', +} + class Reporter: def __init__(self, max_errors, detailed=False): @@ -234,6 +246,10 @@ def main(): if not re.match(r'^[A-Za-z]+\..+$', text) and not GUID_PATTERN.match(text): r.error(f'6. Content item "{text}": invalid format (expected Type.Name or UUID)') content_ok = False + m = re.match(r'^([A-Za-z]+)\.', text) + if m and m.group(1) in KNOWN_PLURAL_TYPES: + r.error(f'6. Content item "{text}": uses plural form "{m.group(1)}" (platform requires singular, e.g. Catalog not Catalogs)') + content_ok = False if content_ok: r.ok(f'6. Content: {len(xr_items)} items, all valid MDObjectRef format') else: diff --git a/tests/skills/cases/subsystem-compile/snapshots/basic/Subsystems/Склад.xml b/tests/skills/cases/subsystem-compile/snapshots/basic/Subsystems/Склад.xml index 5b1bbf3c..e86fdb0b 100644 --- a/tests/skills/cases/subsystem-compile/snapshots/basic/Subsystems/Склад.xml +++ b/tests/skills/cases/subsystem-compile/snapshots/basic/Subsystems/Склад.xml @@ -16,7 +16,7 @@ - Catalogs.Товары + Catalog.Товары diff --git a/tests/skills/cases/subsystem-compile/snapshots/synonym-objects/Subsystems/Склад.xml b/tests/skills/cases/subsystem-compile/snapshots/synonym-objects/Subsystems/Склад.xml index 5b1bbf3c..e86fdb0b 100644 --- a/tests/skills/cases/subsystem-compile/snapshots/synonym-objects/Subsystems/Склад.xml +++ b/tests/skills/cases/subsystem-compile/snapshots/synonym-objects/Subsystems/Склад.xml @@ -16,7 +16,7 @@ - Catalogs.Товары + Catalog.Товары diff --git a/tests/skills/cases/subsystem-validate/snapshots/valid/Subsystems/Склад.xml b/tests/skills/cases/subsystem-validate/snapshots/valid/Subsystems/Склад.xml index 5b1bbf3c..e86fdb0b 100644 --- a/tests/skills/cases/subsystem-validate/snapshots/valid/Subsystems/Склад.xml +++ b/tests/skills/cases/subsystem-validate/snapshots/valid/Subsystems/Склад.xml @@ -16,7 +16,7 @@ - Catalogs.Товары + Catalog.Товары