mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-20 01:20:59 +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:
co-authored by
Claude Opus 4.6
parent
151ded9bae
commit
27bb08d127
@@ -11,7 +11,7 @@ allowed-tools:
|
|||||||
|
|
||||||
# /meta-remove — удаление объекта метаданных
|
# /meta-remove — удаление объекта метаданных
|
||||||
|
|
||||||
Удаляет объект из XML-выгрузки конфигурации: файлы, регистрацию в Configuration.xml, ссылки в подсистемах.
|
Безопасно удаляет объект из XML-выгрузки конфигурации. Перед удалением проверяет ссылки на объект в реквизитах, коде и других метаданных. Если ссылки найдены — удаление блокируется.
|
||||||
|
|
||||||
## Использование
|
## Использование
|
||||||
|
|
||||||
@@ -27,6 +27,7 @@ allowed-tools:
|
|||||||
| Object | да | Тип и имя объекта: `Catalog.Товары`, `Document.Заказ` и т.д. |
|
| Object | да | Тип и имя объекта: `Catalog.Товары`, `Document.Заказ` и т.д. |
|
||||||
| DryRun | нет | Только показать что будет удалено, без изменений |
|
| DryRun | нет | Только показать что будет удалено, без изменений |
|
||||||
| KeepFiles | нет | Не удалять файлы, только дерегистрировать |
|
| KeepFiles | нет | Не удалять файлы, только дерегистрировать |
|
||||||
|
| Force | нет | Удалить несмотря на найденные ссылки |
|
||||||
|
|
||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
@@ -36,16 +37,20 @@ powershell.exe -NoProfile -File .claude\skills\meta-remove\scripts\meta-remove.p
|
|||||||
|
|
||||||
## Что делает
|
## Что делает
|
||||||
|
|
||||||
1. **Находит файлы объекта**: `{TypePlural}/{Name}.xml` и `{TypePlural}/{Name}/` (каталог с модулями, формами, макетами)
|
1. **Находит файлы объекта**: `{TypePlural}/{Name}.xml` и `{TypePlural}/{Name}/`
|
||||||
2. **Удаляет из Configuration.xml**: убирает `<Type>Name</Type>` из `<ChildObjects>`
|
2. **Проверяет ссылки** (блокирует при наличии, если нет `-Force`):
|
||||||
3. **Очищает подсистемы**: рекурсивно обходит все `Subsystems/` и удаляет `<v8:Value>Type.Name</v8:Value>` из `<Content>`
|
- XML-типы в реквизитах других объектов: `CatalogRef.Имя`, `DocumentRef.Имя` и т.д.
|
||||||
4. **Удаляет файлы**: XML-файл и каталог объекта
|
- 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
|
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.Устаревший ===
|
=== meta-remove: Catalog.Устаревший ===
|
||||||
@@ -53,39 +58,70 @@ Catalog, Document, Enum, Constant, InformationRegister, AccumulationRegister, Ac
|
|||||||
[FOUND] Catalogs/Устаревший.xml
|
[FOUND] Catalogs/Устаревший.xml
|
||||||
[FOUND] Catalogs/Устаревший/ (8 files)
|
[FOUND] Catalogs/Устаревший/ (8 files)
|
||||||
|
|
||||||
|
--- Reference check ---
|
||||||
|
[OK] No references found
|
||||||
|
|
||||||
--- Configuration.xml ---
|
--- Configuration.xml ---
|
||||||
[OK] Removed <Catalog>Устаревший</Catalog> from ChildObjects
|
[OK] Removed <Catalog>Устаревший</Catalog> from ChildObjects
|
||||||
[OK] Configuration.xml saved
|
[OK] Configuration.xml saved
|
||||||
|
|
||||||
--- Subsystems ---
|
--- Subsystems ---
|
||||||
[OK] Removed from subsystem 'Справочники'
|
[OK] Removed from subsystem 'Справочники'
|
||||||
[OK] Removed from subsystem 'НСИ'
|
|
||||||
|
|
||||||
--- Files ---
|
--- Files ---
|
||||||
[OK] Deleted directory: Catalogs/Устаревший/
|
[OK] Deleted directory: Catalogs/Устаревший/
|
||||||
[OK] Deleted file: Catalogs/Устаревший.xml
|
[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` для проверки
|
[FOUND] Catalogs/Валюты.xml
|
||||||
- **ВАЖНО**: перед удалением убедитесь что на объект нет ссылок в коде (типы реквизитов, запросы, вызовы модулей)
|
[FOUND] Catalogs/Валюты/ (4 files)
|
||||||
- Скрипт НЕ проверяет ссылки из кода — только структурные (Configuration.xml, подсистемы)
|
|
||||||
- Для проверки ссылок из кода используйте поиск по конфигурации: `grep -r "Type.Name" <ConfigDir>`
|
--- 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
|
```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.Устаревший" -DryRun
|
||||||
|
|
||||||
# Удалить объект полностью
|
# Удалить объект без ссылок
|
||||||
... -ConfigDir C:\WS\tasks\cfsrc\acc_8.3.24 -Object "Catalog.Устаревший"
|
... -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
|
... -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
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -9,7 +9,9 @@ param(
|
|||||||
|
|
||||||
[switch]$DryRun,
|
[switch]$DryRun,
|
||||||
|
|
||||||
[switch]$KeepFiles
|
[switch]$KeepFiles,
|
||||||
|
|
||||||
|
[switch]$Force
|
||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
@@ -94,7 +96,7 @@ if (-not $typePluralMap.ContainsKey($objType)) {
|
|||||||
|
|
||||||
$typePlural = $typePluralMap[$objType]
|
$typePlural = $typePluralMap[$objType]
|
||||||
|
|
||||||
Write-Host "=== meta-remove: $objType.$objName ==="
|
Write-Host "=== meta-remove: ${objType}.${objName} ==="
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
|
|
||||||
if ($DryRun) {
|
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 ""
|
||||||
Write-Host "--- Configuration.xml ---"
|
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 ""
|
||||||
Write-Host "--- Subsystems ---"
|
Write-Host "--- Subsystems ---"
|
||||||
@@ -213,7 +379,7 @@ function Remove-FromSubsystems {
|
|||||||
$ssName = if ($ssNameNode) { $ssNameNode.InnerText } else { $xmlFile.BaseName }
|
$ssName = if ($ssNameNode) { $ssNameNode.InnerText } else { $xmlFile.BaseName }
|
||||||
|
|
||||||
# Content items are <v8:Value>Type.Name</v8:Value>
|
# Content items are <v8:Value>Type.Name</v8:Value>
|
||||||
$targetRef = "$objType.$objName"
|
$targetRef = "${objType}.${objName}"
|
||||||
$modified = $false
|
$modified = $false
|
||||||
|
|
||||||
foreach ($item in @($contentNode.ChildNodes)) {
|
foreach ($item in @($contentNode.ChildNodes)) {
|
||||||
@@ -260,7 +426,7 @@ if (Test-Path $subsystemsDir -PathType Container) {
|
|||||||
Write-Host "[OK] No Subsystems directory"
|
Write-Host "[OK] No Subsystems directory"
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- 4. Delete object files ---
|
# --- 5. Delete object files ---
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "--- Files ---"
|
Write-Host "--- Files ---"
|
||||||
|
|||||||
Reference in New Issue
Block a user