mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-10 16:14:54 +03:00
fix(meta-remove): add reference check before deletion and fix PS 5.1 variable interpolation
Block deletion when object has references in attributes, code, or forms.
Add -Force parameter to override. Exclude ConfigDumpInfo.xml from ref check.
Fix ${objType}.${objName} syntax for PS 5.1 compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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**: убирает `<Type>Name</Type>` из `<ChildObjects>`
|
||||
3. **Очищает подсистемы**: рекурсивно обходит все `Subsystems/` и удаляет `<v8:Value>Type.Name</v8:Value>` из `<Content>`
|
||||
4. **Удаляет файлы**: XML-файл и каталог объекта
|
||||
1. **Находит файлы объекта**: `{TypePlural}/{Name}.xml` и `{TypePlural}/{Name}/`
|
||||
2. **Проверяет ссылки** (блокирует при наличии, если нет `-Force`):
|
||||
- XML-типы в реквизитах других объектов: `CatalogRef.Имя`, `DocumentRef.Имя` и т.д.
|
||||
- BSL-код: `Справочники.Имя`, `Catalogs.Имя`, вызовы общих модулей
|
||||
- Журналы документов, подписки на события, определяемые типы
|
||||
3. **Удаляет из Configuration.xml**: убирает из `<ChildObjects>`
|
||||
4. **Очищает подсистемы**: рекурсивно удаляет из `<Content>`
|
||||
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 <Catalog>Устаревший</Catalog> 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" <ConfigDir>`
|
||||
[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.` (вызовы методов), `<Handler>Name.`, `<MethodName>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
|
||||
|
||||
|
||||
@@ -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 <v8:Type> 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 += "<Handler>$objName."
|
||||
$searchPatterns += "<MethodName>$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 <v8:Value>Type.Name</v8:Value>
|
||||
$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 ---"
|
||||
|
||||
Reference in New Issue
Block a user