diff --git a/.claude/skills/meta-remove/SKILL.md b/.claude/skills/meta-remove/SKILL.md index 0196387c..a531fff8 100644 --- a/.claude/skills/meta-remove/SKILL.md +++ b/.claude/skills/meta-remove/SKILL.md @@ -11,7 +11,7 @@ allowed-tools: # /meta-remove — удаление объекта метаданных -Удаляет объект из XML-выгрузки конфигурации: файлы, регистрацию в Configuration.xml, ссылки в подсистемах. +Безопасно удаляет объект из XML-выгрузки конфигурации. Перед удалением проверяет ссылки на объект в реквизитах, коде и других метаданных. Если ссылки найдены — удаление блокируется. ## Использование @@ -27,6 +27,7 @@ allowed-tools: | Object | да | Тип и имя объекта: `Catalog.Товары`, `Document.Заказ` и т.д. | | DryRun | нет | Только показать что будет удалено, без изменений | | KeepFiles | нет | Не удалять файлы, только дерегистрировать | +| Force | нет | Удалить несмотря на найденные ссылки | ## Команда @@ -36,16 +37,20 @@ powershell.exe -NoProfile -File .claude\skills\meta-remove\scripts\meta-remove.p ## Что делает -1. **Находит файлы объекта**: `{TypePlural}/{Name}.xml` и `{TypePlural}/{Name}/` (каталог с модулями, формами, макетами) -2. **Удаляет из Configuration.xml**: убирает `Name` из `` -3. **Очищает подсистемы**: рекурсивно обходит все `Subsystems/` и удаляет `Type.Name` из `` -4. **Удаляет файлы**: XML-файл и каталог объекта +1. **Находит файлы объекта**: `{TypePlural}/{Name}.xml` и `{TypePlural}/{Name}/` +2. **Проверяет ссылки** (блокирует при наличии, если нет `-Force`): + - XML-типы в реквизитах других объектов: `CatalogRef.Имя`, `DocumentRef.Имя` и т.д. + - BSL-код: `Справочники.Имя`, `Catalogs.Имя`, вызовы общих модулей + - Журналы документов, подписки на события, определяемые типы +3. **Удаляет из Configuration.xml**: убирает из `` +4. **Очищает подсистемы**: рекурсивно удаляет из `` +5. **Удаляет файлы**: XML-файл и каталог объекта ## Поддерживаемые типы Catalog, Document, Enum, Constant, InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes, BusinessProcess, Task, ExchangePlan, DocumentJournal, Report, DataProcessor, CommonModule, ScheduledJob, EventSubscription, HTTPService, WebService, DefinedType, Role, Subsystem, CommonForm, CommonTemplate, CommonPicture, CommonAttribute, SessionParameter, FunctionalOption, FunctionalOptionsParameter, Sequence, FilterCriterion, SettingsStorage, XDTOPackage, WSReference, StyleItem, Language -## Вывод +## Вывод (объект без ссылок) ``` === meta-remove: Catalog.Устаревший === @@ -53,39 +58,70 @@ Catalog, Document, Enum, Constant, InformationRegister, AccumulationRegister, Ac [FOUND] Catalogs/Устаревший.xml [FOUND] Catalogs/Устаревший/ (8 files) +--- Reference check --- +[OK] No references found + --- Configuration.xml --- [OK] Removed Устаревший from ChildObjects [OK] Configuration.xml saved --- Subsystems --- [OK] Removed from subsystem 'Справочники' -[OK] Removed from subsystem 'НСИ' --- Files --- [OK] Deleted directory: Catalogs/Устаревший/ [OK] Deleted file: Catalogs/Устаревший.xml -=== Done: 4 actions performed (2 subsystem references removed) === +=== Done: 4 actions performed (1 subsystem references removed) === ``` -Код возврата: 0 = успешно, 1 = ошибки. +## Вывод (объект со ссылками — блокировка) -## Безопасность +``` +=== meta-remove: Catalog.Валюты === -- **Рекомендуется**: сначала запустить с `-DryRun` для проверки -- **ВАЖНО**: перед удалением убедитесь что на объект нет ссылок в коде (типы реквизитов, запросы, вызовы модулей) -- Скрипт НЕ проверяет ссылки из кода — только структурные (Configuration.xml, подсистемы) -- Для проверки ссылок из кода используйте поиск по конфигурации: `grep -r "Type.Name" ` +[FOUND] Catalogs/Валюты.xml +[FOUND] Catalogs/Валюты/ (4 files) + +--- Reference check --- +[WARN] Found 3 reference(s) to Catalog.Валюты: + + Documents/СчетНаОплату.xml + pattern: CatalogRef.Валюты + InformationRegisters/КурсыВалют.xml + pattern: CatalogRef.Валюты + CommonModules/РаботаСВалютами/Ext/Module.bsl + pattern: Справочники.Валюты + +[ERROR] Cannot remove: object has 3 reference(s). + Use -Force to remove anyway, or fix references first. +``` + +Код возврата: 0 = успешно, 1 = ошибки или найдены ссылки. + +## Проверяемые ссылки + +| Категория | Паттерны поиска | +|-----------|----------------| +| XML-типы реквизитов | `CatalogRef.Name`, `DocumentRef.Name`, `EnumRef.Name` и др. | +| BSL-код (рус.) | `Справочники.Name`, `Документы.Name`, `Перечисления.Name` и др. | +| BSL-код (англ.) | `Catalogs.Name`, `Documents.Name`, `Enums.Name` и др. | +| Общие модули | `Name.` (вызовы методов), `Name.`, `Name.` | + +Ссылки из Configuration.xml, ConfigDumpInfo.xml и подсистем НЕ считаются блокирующими — они очищаются автоматически. ## Примеры ```powershell -# Dry run — посмотреть что будет удалено +# Проверка ссылок + dry run ... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Catalog.Устаревший" -DryRun -# Удалить объект полностью +# Удалить объект без ссылок ... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Catalog.Устаревший" +# Принудительно удалить несмотря на ссылки +... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Catalog.Устаревший" -Force + # Только дерегистрировать (файлы оставить) ... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Report.Старый" -KeepFiles diff --git a/.claude/skills/meta-remove/scripts/meta-remove.ps1 b/.claude/skills/meta-remove/scripts/meta-remove.ps1 index 193b0c5e..84ec96fd 100644 --- a/.claude/skills/meta-remove/scripts/meta-remove.ps1 +++ b/.claude/skills/meta-remove/scripts/meta-remove.ps1 @@ -1,4 +1,4 @@ -# meta-remove v1.0 — Remove metadata object from 1C configuration dump +# meta-remove v1.1 — Remove metadata object from 1C configuration dump # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -9,7 +9,9 @@ param( [switch]$DryRun, - [switch]$KeepFiles + [switch]$KeepFiles, + + [switch]$Force ) $ErrorActionPreference = "Stop" @@ -94,7 +96,7 @@ if (-not $typePluralMap.ContainsKey($objType)) { $typePlural = $typePluralMap[$objType] -Write-Host "=== meta-remove: $objType.$objName ===" +Write-Host "=== meta-remove: ${objType}.${objName} ===" Write-Host "" if ($DryRun) { @@ -125,7 +127,171 @@ if (-not $hasXml -and -not $hasDir) { } } -# --- 2. Remove from Configuration.xml ChildObjects --- +# --- 2. Reference check --- + +Write-Host "" +Write-Host "--- Reference check ---" + +# Build search patterns based on object type + +# Type → reference type name (used in XML elements) +$typeRefNames = @{ + "Catalog" = @("CatalogRef","CatalogObject") + "Document" = @("DocumentRef","DocumentObject") + "Enum" = @("EnumRef") + "ExchangePlan" = @("ExchangePlanRef","ExchangePlanObject") + "ChartOfAccounts" = @("ChartOfAccountsRef","ChartOfAccountsObject") + "ChartOfCharacteristicTypes" = @("ChartOfCharacteristicTypesRef","ChartOfCharacteristicTypesObject") + "ChartOfCalculationTypes" = @("ChartOfCalculationTypesRef","ChartOfCalculationTypesObject") + "BusinessProcess" = @("BusinessProcessRef","BusinessProcessObject") + "Task" = @("TaskRef","TaskObject") +} + +# Type → Russian manager name (used in BSL code: Справочники.Товары) +$typeRuManager = @{ + "Catalog" = "Справочники" + "Document" = "Документы" + "Enum" = "Перечисления" + "Constant" = "Константы" + "InformationRegister" = "РегистрыСведений" + "AccumulationRegister" = "РегистрыНакопления" + "AccountingRegister" = "РегистрыБухгалтерии" + "CalculationRegister" = "РегистрыРасчета" + "ChartOfAccounts" = "ПланыСчетов" + "ChartOfCharacteristicTypes" = "ПланыВидовХарактеристик" + "ChartOfCalculationTypes" = "ПланыВидовРасчета" + "BusinessProcess" = "БизнесПроцессы" + "Task" = "Задачи" + "ExchangePlan" = "ПланыОбмена" + "Report" = "Отчеты" + "DataProcessor" = "Обработки" + "DocumentJournal" = "ЖурналыДокументов" + "CommonModule" = $null +} + +$searchPatterns = @() + +# 1) XML type references: CatalogRef.Name, CatalogObject.Name +if ($typeRefNames.ContainsKey($objType)) { + foreach ($refName in $typeRefNames[$objType]) { + $searchPatterns += "$refName.$objName" + } +} + +# 2) BSL code references: Справочники.Name, Catalogs.Name +$ruMgr = $typeRuManager[$objType] +if ($ruMgr) { + $searchPatterns += "$ruMgr.$objName" +} +# English manager = plural directory name +$searchPatterns += "$typePlural.$objName" + +# 3) CommonModule: method calls in BSL (ModuleName.) +if ($objType -eq "CommonModule") { + $searchPatterns += "$objName." +} + +# 4) ScheduledJob/EventSubscription handler references +if ($objType -eq "CommonModule") { + $searchPatterns += "$objName." + $searchPatterns += "$objName." +} + +# Exclude object's own files from search +$excludeDirs = @() +if ($hasDir) { $excludeDirs += $objDir } +$excludeFile = "" +if ($hasXml) { $excludeFile = $objXml } + +# Search all XML and BSL files +$references = @() +$searchExtensions = @("*.xml", "*.bsl") + +foreach ($ext in $searchExtensions) { + $files = @(Get-ChildItem $ConfigDir -Filter $ext -Recurse -File -ErrorAction SilentlyContinue) + foreach ($file in $files) { + # Skip own files + if ($excludeFile -and $file.FullName -eq $excludeFile) { continue } + if ($excludeDirs.Count -gt 0) { + $skip = $false + foreach ($ed in $excludeDirs) { + if ($file.FullName.StartsWith($ed)) { $skip = $true; break } + } + if ($skip) { continue } + } + + $content = [System.IO.File]::ReadAllText($file.FullName, [System.Text.Encoding]::UTF8) + foreach ($pat in $searchPatterns) { + if ($content.Contains($pat)) { + $relPath = $file.FullName.Substring($ConfigDir.Length + 1) + $references += @{ File = $relPath; Pattern = $pat } + break # one match per file is enough + } + } + } +} + +# Also check for Type.Name references (subsystem content, doc journal, etc.) — but NOT in own files +$typeNameRef = "${objType}.${objName}" +$files = @(Get-ChildItem $ConfigDir -Filter "*.xml" -Recurse -File -ErrorAction SilentlyContinue) +foreach ($file in $files) { + if ($excludeFile -and $file.FullName -eq $excludeFile) { continue } + if ($excludeDirs.Count -gt 0) { + $skip = $false + foreach ($ed in $excludeDirs) { + if ($file.FullName.StartsWith($ed)) { $skip = $true; break } + } + if ($skip) { continue } + } + # Skip Configuration.xml and Subsystems — they will be cleaned automatically + $relPath = $file.FullName.Substring($ConfigDir.Length + 1) + if ($relPath -eq "Configuration.xml") { continue } + if ($relPath -eq "ConfigDumpInfo.xml") { continue } + if ($relPath.StartsWith("Subsystems")) { continue } + + $content = [System.IO.File]::ReadAllText($file.FullName, [System.Text.Encoding]::UTF8) + if ($content.Contains($typeNameRef)) { + # Check it's not already in references + $alreadyFound = $false + foreach ($r in $references) { + if ($r.File -eq $relPath) { $alreadyFound = $true; break } + } + if (-not $alreadyFound) { + $references += @{ File = $relPath; Pattern = $typeNameRef } + } + } +} + +if ($references.Count -gt 0) { + Write-Host "[WARN] Found $($references.Count) reference(s) to ${objType}.${objName}:" + Write-Host "" + $shown = 0 + foreach ($ref in $references) { + Write-Host " $($ref.File)" + Write-Host " pattern: $($ref.Pattern)" + $shown++ + if ($shown -ge 20) { + $remaining = $references.Count - $shown + if ($remaining -gt 0) { + Write-Host " ... and $remaining more" + } + break + } + } + Write-Host "" + + if (-not $Force) { + Write-Host "[ERROR] Cannot remove: object has $($references.Count) reference(s)." + Write-Host " Use -Force to remove anyway, or fix references first." + exit 1 + } else { + Write-Host "[WARN] -Force specified, proceeding despite references" + } +} else { + Write-Host "[OK] No references found" +} + +# --- 3. Remove from Configuration.xml ChildObjects --- Write-Host "" Write-Host "--- Configuration.xml ---" @@ -178,7 +344,7 @@ if (-not $cfgNode) { } } -# --- 3. Remove from subsystem Content --- +# --- 4. Remove from subsystem Content --- Write-Host "" Write-Host "--- Subsystems ---" @@ -213,7 +379,7 @@ function Remove-FromSubsystems { $ssName = if ($ssNameNode) { $ssNameNode.InnerText } else { $xmlFile.BaseName } # Content items are Type.Name - $targetRef = "$objType.$objName" + $targetRef = "${objType}.${objName}" $modified = $false foreach ($item in @($contentNode.ChildNodes)) { @@ -260,7 +426,7 @@ if (Test-Path $subsystemsDir -PathType Container) { Write-Host "[OK] No Subsystems directory" } -# --- 4. Delete object files --- +# --- 5. Delete object files --- Write-Host "" Write-Host "--- Files ---"