Files

563 lines
24 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# xdto-edit v1.0 — Point edits of a 1C XDTO package
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory=$true)]
[Alias('Path')]
[string]$PackagePath,
[Parameter(Mandatory=$true)]
[ValidateSet("add-property", "replace-property", "remove-property",
"add-type", "remove-type", "add-enum", "add-import",
"rename", "set-synonym", "set-comment", "set-namespace")]
[string]$Operation,
[string]$Target,
[string]$Value,
[switch]$NoValidate
)
$ErrorActionPreference = "Stop"
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$XDTO_NS = "http://v8.1c.ru/8.1/xdto"
$XS_NS = "http://www.w3.org/2001/XMLSchema"
$MD_NS = "http://v8.1c.ru/8.3/MDClasses"
$V8_NS = "http://v8.1c.ru/8.1/data/core"
# --- Support guard (Ext/ParentConfigurations.bin) ---
# See docs/1c-support-state-spec.md. Blocks edits of vendor objects "на замке" /
# read-only configs unless allowed. Trigger = bin present; reaction from
# .v8-project.json editingAllowedCheck (deny|warn|off, default deny). Never
# throws — guard errors degrade to allow.
function Test-ExternalObjectRoot([string]$xmlPath) {
if (-not (Test-Path $xmlPath)) { return $false }
try {
[xml]$mx = Get-Content -Path $xmlPath -Encoding UTF8
$el = $mx.DocumentElement.FirstChild
while ($el -and $el.NodeType -ne 'Element') { $el = $el.NextSibling }
if ($el) { return @('ExternalDataProcessor','ExternalReport') -contains $el.get_LocalName() }
} catch {}
return $false
}
function Find-V8Project([string]$startDir) {
$d = $startDir
for ($i = 0; $i -lt 20 -and $d; $i++) {
$pj = Join-Path $d ".v8-project.json"
if (Test-Path $pj) { return $pj }
$parent = [System.IO.Path]::GetDirectoryName($d)
if ($parent -eq $d) { break }
$d = $parent
}
return $null
}
function Get-EditMode([string]$cfgDir) {
$mode = "deny"
try {
$pj = Find-V8Project $cfgDir
if ($pj) {
$cfg = Get-Content -Path $pj -Raw -Encoding UTF8 | ConvertFrom-Json
if ($cfg.PSObject.Properties.Name -contains 'editingAllowedCheck' -and $cfg.editingAllowedCheck) {
$mode = [string]$cfg.editingAllowedCheck
}
}
} catch {}
return $mode
}
function Assert-EditAllowed([string]$targetPath) {
try {
$d = $targetPath
for ($i = 0; $i -lt 20 -and $d; $i++) {
foreach ($x in @(Get-ChildItem -Path $d -Filter "*.xml" -File -ErrorAction SilentlyContinue)) {
if (Test-ExternalObjectRoot $x.FullName) { return }
}
$cfgXml = Join-Path $d "Configuration.xml"
$supportBin = Join-Path (Join-Path $d "Ext") "ParentConfigurations.bin"
if (Test-Path $cfgXml) {
if (Test-Path $supportBin) {
$mode = Get-EditMode $d
if ($mode -eq "off") { return }
$msg = "Конфигурация находится на поддержке (Ext/ParentConfigurations.bin). Правка может быть запрещена."
if ($mode -eq "warn") { Write-Warning $msg; return }
throw "$msg Снимите с поддержки (/support-edit) или задайте editingAllowedCheck в .v8-project.json."
}
return
}
$parent = [System.IO.Path]::GetDirectoryName($d)
if ($parent -eq $d) { break }
$d = $parent
}
} catch [System.Management.Automation.RuntimeException] {
throw
} catch {}
}
# --- Resolve package ------------------------------------------------------------
if (-not [System.IO.Path]::IsPathRooted($PackagePath)) {
$PackagePath = Join-Path (Get-Location).Path $PackagePath
}
$pkgDir = $null
if (Test-Path $PackagePath -PathType Container) {
if (Test-Path (Join-Path (Join-Path $PackagePath "Ext") "Package.bin")) { $pkgDir = $PackagePath }
} elseif ((Test-Path $PackagePath -PathType Leaf) -and ([System.IO.Path]::GetFileName($PackagePath) -eq "Package.bin")) {
$pkgDir = Split-Path (Split-Path $PackagePath -Parent) -Parent
} elseif ($PackagePath.EndsWith(".xml")) {
$stem = [System.IO.Path]::Combine([System.IO.Path]::GetDirectoryName($PackagePath),
[System.IO.Path]::GetFileNameWithoutExtension($PackagePath))
if (Test-Path (Join-Path (Join-Path $stem "Ext") "Package.bin")) { $pkgDir = $stem }
}
if (-not $pkgDir) { throw "Не найден пакет XDTO по пути: $PackagePath" }
$pkgName = [System.IO.Path]::GetFileName($pkgDir)
$xdtoRoot = Split-Path $pkgDir -Parent
$configRoot = Split-Path $xdtoRoot -Parent
$binFile = Join-Path (Join-Path $pkgDir "Ext") "Package.bin"
$mdFile = Join-Path $xdtoRoot "$pkgName.xml"
$configXml = Join-Path $configRoot "Configuration.xml"
# -Value "@путь" — содержимое берётся из файла. Передавать XSD-фрагмент инлайном
# через powershell.exe -File ненадёжно: вложенные кавычки схлопываются на границе
# процессов, и вместо понятной ошибки получается сырой сбой разбора XML.
if ($Value -and $Value.StartsWith("@")) {
$valueFile = $Value.Substring(1)
if (-not [System.IO.Path]::IsPathRooted($valueFile)) {
$valueFile = Join-Path (Get-Location).Path $valueFile
}
if (-not (Test-Path $valueFile -PathType Leaf)) { throw "Файл значения не найден: $valueFile" }
$Value = [System.IO.File]::ReadAllText($valueFile).Trim()
}
Assert-EditAllowed $pkgDir
$encBom = New-Object System.Text.UTF8Encoding($true)
# --- Sibling skills -------------------------------------------------------------
# Правка идёт через уже проверенный round-trip: пакет выгружается в XSD, операция
# применяется к схеме, пакет собирается обратно. Второго эмиттера не заводим —
# байт-точность для всего нетронутого достаётся от компилятора.
$decompileScript = Join-Path (Join-Path $PSScriptRoot "..\..\xdto-decompile") "scripts\xdto-decompile.ps1"
$compileScript = Join-Path (Join-Path $PSScriptRoot "..\..\xdto-compile") "scripts\xdto-compile.ps1"
$validateScript = Join-Path (Join-Path $PSScriptRoot "..\..\xdto-validate") "scripts\xdto-validate.ps1"
# Исключение из автономности навыков, сделанное осознанно: конвертер XSD ↔ модель
# нельзя скопировать буквально (xdto-compile — скрипт со сквозным потоком, не библиотека),
# а вторая его реализация разошлась бы с первой. Обещание «правка не меняет ни байта
# в нетронутом» держится именно на том, что код тот же самый.
# Проверяем комплектность заранее, чтобы не падать на середине правки.
function Assert-SiblingsPresent([string]$operation) {
$needed = @{}
if (@("rename", "set-synonym", "set-comment") -notcontains $operation) {
$needed["xdto-decompile"] = $decompileScript
$needed["xdto-compile"] = $compileScript
}
$missing = @()
foreach ($k in $needed.Keys) { if (-not (Test-Path $needed[$k])) { $missing += $k } }
if ($missing.Count -gt 0) {
$skillsRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
throw ("Навык неработоспособен: рядом нет " + ($missing -join ", ") + ".`n" +
"Операция `"$operation`" выполняется через " +
$(if ($missing.Count -gt 1) { "них" } else { "него" }) + ".`n" +
"Ожидаются в каталоге навыков: $skillsRoot")
}
}
function Invoke-Sibling([string]$script, [string[]]$argList, [string]$what) {
if (-not (Test-Path $script)) { throw "Не найден навык $what по пути: $script" }
$out = & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $script @argList 2>&1
if ($LASTEXITCODE -ne 0) { throw "$what завершился с ошибкой:`n$($out -join "`n")" }
return $out
}
# --- Metadata object edits ------------------------------------------------------
function Edit-Metadata([string]$field, [string]$newValue) {
$doc = New-Object System.Xml.XmlDocument
$doc.PreserveWhitespace = $true
$doc.Load($mdFile)
$nsm = New-Object System.Xml.XmlNamespaceManager($doc.NameTable)
$nsm.AddNamespace("md", $MD_NS)
$nsm.AddNamespace("v8", $V8_NS)
$props = $doc.SelectSingleNode("//md:XDTOPackage/md:Properties", $nsm)
if (-not $props) { throw "В объекте метаданных не найден блок <Properties>" }
switch ($field) {
"Name" {
$n = $props.SelectSingleNode("md:Name", $nsm)
if (-not $n) { throw "В объекте метаданных нет <Name>" }
$n.InnerText = $newValue
}
"Comment" {
$c = $props.SelectSingleNode("md:Comment", $nsm)
if (-not $c) {
$c = $doc.CreateElement("Comment", $MD_NS)
$props.AppendChild($c) | Out-Null
}
$c.InnerText = $newValue
}
"Namespace" {
$ns = $props.SelectSingleNode("md:Namespace", $nsm)
if (-not $ns) { throw "В объекте метаданных нет <Namespace>" }
$ns.InnerText = $newValue
}
"Synonym" {
$syn = $props.SelectSingleNode("md:Synonym", $nsm)
if (-not $syn) {
$syn = $doc.CreateElement("Synonym", $MD_NS)
$props.AppendChild($syn) | Out-Null
}
$item = $syn.SelectSingleNode("v8:item[v8:lang='ru']", $nsm)
if (-not $item) {
$item = $doc.CreateElement("v8", "item", $V8_NS)
$lang = $doc.CreateElement("v8", "lang", $V8_NS); $lang.InnerText = "ru"
$cont = $doc.CreateElement("v8", "content", $V8_NS)
$item.AppendChild($lang) | Out-Null
$item.AppendChild($cont) | Out-Null
$syn.AppendChild($item) | Out-Null
}
$item.SelectSingleNode("v8:content", $nsm).InnerText = $newValue
}
}
$settings = New-Object System.Xml.XmlWriterSettings
$settings.Encoding = $encBom
$settings.Indent = $false
$stream = New-Object System.IO.FileStream($mdFile, [System.IO.FileMode]::Create)
$writer = [System.Xml.XmlWriter]::Create($stream, $settings)
$doc.Save($writer)
$writer.Close(); $stream.Close()
}
function Rename-Package([string]$newName) {
if ($newName -notmatch '^[\wЀ-ӿ]+$' -or $newName -match '^\d') {
throw "`"$newName`" не является допустимым идентификатором 1С"
}
$newMd = Join-Path $xdtoRoot "$newName.xml"
$newDir = Join-Path $xdtoRoot $newName
if ((Test-Path $newMd) -or (Test-Path $newDir)) { throw "Имя `"$newName`" уже занято другим пакетом" }
Edit-Metadata "Name" $newName
Move-Item $mdFile $newMd
Move-Item $pkgDir $newDir
if (Test-Path $configXml) {
$cfg = New-Object System.Xml.XmlDocument
$cfg.PreserveWhitespace = $true
$cfg.Load($configXml)
$nsm = New-Object System.Xml.XmlNamespaceManager($cfg.NameTable)
$nsm.AddNamespace("md", $MD_NS)
$found = $false
foreach ($e in $cfg.SelectNodes("//md:Configuration/md:ChildObjects/md:XDTOPackage", $nsm)) {
if ($e.InnerText -eq $pkgName) { $e.InnerText = $newName; $found = $true; break }
}
if ($found) {
$s = New-Object System.Xml.XmlWriterSettings
$s.Encoding = $encBom; $s.Indent = $false
$st = New-Object System.IO.FileStream($configXml, [System.IO.FileMode]::Create)
$w = [System.Xml.XmlWriter]::Create($st, $s)
$cfg.Save($w); $w.Close(); $st.Close()
Write-Host " Configuration.xml: <XDTOPackage> переименован в $newName"
} else {
Write-Warning "В Configuration.xml не найдена запись <XDTOPackage>$pkgName</XDTOPackage> — зарегистрируйте пакет вручную"
}
}
Write-Host "✓ Пакет переименован: $pkgName$newName"
Write-Host " Перемещены: $newName.xml, $newName/"
}
# --- Model edits through the XSD round-trip -------------------------------------
$XSD_DECL = @{ "add-property" = "element"; "replace-property" = "element"; "remove-property" = "element" }
function Get-SchemaChildren([System.Xml.XmlElement]$el, [string]$local) {
$res = New-Object System.Collections.ArrayList
foreach ($c in $el.ChildNodes) {
if ($c.NodeType -eq [System.Xml.XmlNodeType]::Element -and $c.NamespaceURI -eq $XS_NS -and $c.get_LocalName() -eq $local) { [void]$res.Add($c) }
}
return ,$res
}
function Get-SchemaFirst([System.Xml.XmlElement]$el, [string]$local) {
$r = Get-SchemaChildren $el $local
if ($r.Count -gt 0) { return $r[0] }
return $null
}
function Find-TypeElement($schema, [string]$typeName) {
foreach ($kind in @("complexType", "simpleType")) {
foreach ($t in (Get-SchemaChildren $schema $kind)) {
if ($t.GetAttribute("name") -eq $typeName) { return $t }
}
}
throw "В пакете нет типа `"$typeName`""
}
# Тело типа: внутрь xs:complexContent/xs:extension, если тип наследуется
function Get-TypeBody([System.Xml.XmlElement]$ct) {
$content = Get-SchemaFirst $ct "complexContent"
if ($content) {
$ext = Get-SchemaFirst $content "extension"
if ($ext) { return $ext }
}
return $ct
}
function Find-Declaration([System.Xml.XmlElement]$body, [string]$propName) {
foreach ($node in $body.SelectNodes(".//*")) {
if ($node.NamespaceURI -ne $XS_NS) { continue }
if (@("element", "attribute") -notcontains $node.get_LocalName()) { continue }
if ($node.GetAttribute("name") -eq $propName) { return $node }
}
return $null
}
# Путь Тип.Свойство[.Вложенное...] — точка безопасна: имена в модели XDTO
# являются идентификаторами 1С и точку содержать не могут
function Resolve-Path($schema, [string]$path) {
$segments = $path.Split(".")
$typeEl = Find-TypeElement $schema $segments[0]
if ($segments.Count -eq 1) { return [pscustomobject]@{ Type = $typeEl; Decl = $null } }
$body = Get-TypeBody $typeEl
$decl = $null
for ($i = 1; $i -lt $segments.Count; $i++) {
$decl = Find-Declaration $body $segments[$i]
if (-not $decl) { throw "По пути `"$path`" не найдено свойство `"$($segments[$i])`"" }
if ($i -lt $segments.Count - 1) {
$inner = Get-SchemaFirst $decl "complexType"
if (-not $inner) { throw "Свойство `"$($segments[$i])`" не содержит вложенного типа — путь дальше не идёт" }
$body = Get-TypeBody $inner
}
}
return [pscustomobject]@{ Type = $typeEl; Decl = $decl }
}
function Import-Fragment($schema, [string]$xml) {
$tmp = New-Object System.Xml.XmlDocument
$nsAttrs = " xmlns:xs=`"$XS_NS`" xmlns:xdto=`"$XDTO_NS`""
$tns = $schema.GetAttribute("targetNamespace")
if ($tns) { $nsAttrs += " xmlns:tns=`"$tns`"" }
foreach ($a in $schema.Attributes) {
if ($a.Prefix -eq "xmlns" -and $a.get_LocalName() -notin @("xs", "xdto", "tns")) {
$nsAttrs += " xmlns:$($a.get_LocalName())=`"$($a.Value)`""
}
}
try { $tmp.LoadXml("<wrap$nsAttrs>$xml</wrap>") }
catch {
throw ("Не удалось разобрать -Value как фрагмент XML-схемы: " + $_.Exception.InnerException.Message + "`n" +
"Получено: " + $xml + "`n" +
"Если фрагмент передан инлайном, кавычки могли схлопнуться на границе процессов — " +
"положите его в файл и укажите -Value `"@путь`".")
}
$res = New-Object System.Collections.ArrayList
foreach ($c in $tmp.DocumentElement.ChildNodes) {
if ($c.NodeType -eq [System.Xml.XmlNodeType]::Element) {
[void]$res.Add($schema.OwnerDocument.ImportNode($c, $true))
}
}
if ($res.Count -eq 0) { throw "Во фрагменте нет ни одного элемента: $xml" }
return ,$res
}
function Apply-ModelOperation($schema) {
switch ($Operation) {
"add-property" {
if (-not $Target) { throw "add-property требует -Target <Тип>" }
$loc = Resolve-Path $schema $Target
$body = Get-TypeBody $(if ($loc.Decl) { Get-SchemaFirst $loc.Decl "complexType" } else { $loc.Type })
foreach ($frag in (Import-Fragment $schema $Value)) {
$kind = $frag.get_LocalName()
if ($kind -eq "attribute") {
$body.AppendChild($frag) | Out-Null
} elseif ($kind -eq "element") {
$particle = Get-SchemaFirst $body "sequence"
if (-not $particle) { $particle = Get-SchemaFirst $body "choice" }
if (-not $particle) { $particle = Get-SchemaFirst $body "all" }
if (-not $particle) {
$particle = $schema.OwnerDocument.CreateElement("xs", "sequence", $XS_NS)
$firstAttr = Get-SchemaFirst $body "attribute"
if ($firstAttr) { $body.InsertBefore($particle, $firstAttr) | Out-Null }
else { $body.AppendChild($particle) | Out-Null }
}
$particle.AppendChild($frag) | Out-Null
} else {
throw "add-property ожидает <xs:element> или <xs:attribute>, получен <xs:$kind>"
}
Write-Host " + $($frag.GetAttribute('name')) в тип $Target"
}
}
"replace-property" {
if (-not $Target) { throw "replace-property требует -Target `"Тип.Свойство`"" }
$loc = Resolve-Path $schema $Target
if (-not $loc.Decl) { throw "replace-property требует путь вида `"Тип.Свойство`"" }
$frags = Import-Fragment $schema $Value
if ($frags.Count -ne 1) { throw "replace-property ожидает ровно одно объявление" }
$loc.Decl.ParentNode.ReplaceChild($frags[0], $loc.Decl) | Out-Null
Write-Host " ~ $Target заменено"
}
"remove-property" {
if (-not $Target) { throw "remove-property требует путь `"Тип.Свойство`"" }
foreach ($one in ($Target -split "\s*;;\s*")) {
if (-not $one) { continue }
$loc = Resolve-Path $schema $one
if (-not $loc.Decl) { throw "remove-property требует путь вида `"Тип.Свойство`", получено `"$one`"" }
$loc.Decl.ParentNode.RemoveChild($loc.Decl) | Out-Null
Write-Host " $one удалено"
}
}
"add-type" {
foreach ($frag in (Import-Fragment $schema $Value)) {
if (@("complexType", "simpleType") -notcontains $frag.get_LocalName()) {
throw "add-type ожидает <xs:complexType> или <xs:simpleType>, получен <xs:$($frag.get_LocalName())>"
}
$schema.AppendChild($frag) | Out-Null
Write-Host " + тип $($frag.GetAttribute('name'))"
}
}
"remove-type" {
if (-not $Target) { throw "remove-type требует -Target <Тип>" }
foreach ($one in ($Target -split "\s*;;\s*")) {
if (-not $one) { continue }
$t = Find-TypeElement $schema $one
$t.ParentNode.RemoveChild($t) | Out-Null
Write-Host " тип $one удалён"
}
}
"add-enum" {
if (-not $Target) { throw "add-enum требует -Target <ТипЗначения>" }
$t = Find-TypeElement $schema $Target
$restriction = Get-SchemaFirst $t "restriction"
if (-not $restriction) { throw "Тип `"$Target`" не является ограничением простого типа" }
foreach ($lit in ($Value -split "\s*;;\s*")) {
if (-not $lit) { continue }
$e = $schema.OwnerDocument.CreateElement("xs", "enumeration", $XS_NS)
$e.SetAttribute("value", $lit)
$restriction.AppendChild($e) | Out-Null
Write-Host " + значение `"$lit`" в тип $Target"
}
}
"add-import" {
foreach ($uri in ($Value -split "\s*;;\s*")) {
if (-not $uri) { continue }
$exists = $false
foreach ($i in (Get-SchemaChildren $schema "import")) {
if ($i.GetAttribute("namespace") -eq $uri) { $exists = $true; break }
}
if ($exists) { Write-Host " = импорт $uri уже объявлен"; continue }
$imp = $schema.OwnerDocument.CreateElement("xs", "import", $XS_NS)
$imp.SetAttribute("namespace", $uri)
$firstOther = $null
foreach ($c in $schema.ChildNodes) {
if ($c.NodeType -eq [System.Xml.XmlNodeType]::Element -and $c.get_LocalName() -notin @("annotation", "import")) { $firstOther = $c; break }
}
if ($firstOther) { $schema.InsertBefore($imp, $firstOther) | Out-Null } else { $schema.AppendChild($imp) | Out-Null }
Write-Host " + импорт $uri"
}
}
"set-namespace" {
if (-not $Value) { throw "set-namespace требует -Value <URI>" }
$old = $schema.GetAttribute("targetNamespace")
# Установка того же значения не отбрасывается: пакет пересобирается вхолостую,
# и это заодно проба точности пути «выгрузить → собрать» на любом пакете
if ($old -eq $Value) { Write-Host " = namespace уже $Value, пакет пересобран без изменений" }
# Меняем и targetNamespace, и объявление префикса, который на него указывал:
# иначе ссылки на собственные типы станут ссылками в чужое пространство имён
$schema.SetAttribute("targetNamespace", $Value)
foreach ($a in @($schema.Attributes)) {
if ($a.Prefix -eq "xmlns" -and $a.Value -eq $old) {
$schema.SetAttribute("xmlns:$($a.get_LocalName())", $Value)
}
}
Write-Host " ~ namespace: $old$Value"
}
}
}
# --- Dispatch -------------------------------------------------------------------
$metaOps = @("rename", "set-synonym", "set-comment")
$touchesModel = ($metaOps -notcontains $Operation)
Assert-SiblingsPresent $Operation
Write-Host "Пакет: $pkgName"
if ($Operation -eq "rename") {
if (-not $Value) { throw "rename требует -Value <НовоеИмя>" }
Rename-Package $Value
$pkgName = $Value
$pkgDir = Join-Path $xdtoRoot $Value
} elseif ($Operation -eq "set-synonym") {
if (-not $Value) { throw "set-synonym требует -Value <текст>" }
Edit-Metadata "Synonym" $Value
Write-Host "✓ Синоним: $Value"
} elseif ($Operation -eq "set-comment") {
Edit-Metadata "Comment" $Value
Write-Host "✓ Комментарий обновлён"
} else {
$tmpDir = Join-Path ([System.IO.Path]::GetTempPath()) ("xdto-edit_" + [guid]::NewGuid().ToString("N").Substring(0, 8))
New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null
try {
$xsdPath = Join-Path $tmpDir "schema.xsd"
Invoke-Sibling $decompileScript @("-PackagePath", $binFile, "-OutFile", $xsdPath) "xdto-decompile" | Out-Null
$doc = New-Object System.Xml.XmlDocument
$doc.PreserveWhitespace = $false
$doc.Load($xsdPath)
$schema = $doc.DocumentElement
$oldNamespace = $schema.GetAttribute("targetNamespace")
Apply-ModelOperation $schema
$doc.Save($xsdPath)
Invoke-Sibling $compileScript @("-XsdPath", $xsdPath, "-OutputDir", $configRoot, "-Name", $pkgName, "-Force") "xdto-compile" | Out-Null
if ($Operation -eq "set-namespace") {
Edit-Metadata "Namespace" $Value
# Зависящие пакеты не трогаем: при версионировании они обязаны продолжать
# смотреть на прежний namespace. Но молчать о них нельзя.
$dependents = @()
foreach ($d in (Get-ChildItem $xdtoRoot -Directory -ErrorAction SilentlyContinue)) {
if ($d.Name -eq $pkgName) { continue }
$ob = Join-Path (Join-Path $d.FullName "Ext") "Package.bin"
if (-not (Test-Path $ob)) { continue }
try {
$od = New-Object System.Xml.XmlDocument
$od.Load($ob)
foreach ($imp in $od.DocumentElement.ChildNodes) {
if ($imp.NodeType -eq [System.Xml.XmlNodeType]::Element -and $imp.get_LocalName() -eq "import" -and
$imp.GetAttribute("namespace") -eq $oldNamespace) { $dependents += $d.Name; break }
}
} catch {}
}
if ($dependents.Count -gt 0) {
Write-Host ""
Write-Warning ("Старый namespace импортируют пакеты ($($dependents.Count)): " + ($dependents -join ", ") +
". Они не изменены — при версионировании это верно; если нет, поправьте их импорты.")
}
}
Write-Host "✓ Пакет пересобран: XDTOPackages/$pkgName/Ext/Package.bin"
} finally {
Remove-Item $tmpDir -Recurse -Force -ErrorAction SilentlyContinue
}
}
# --- Validate -------------------------------------------------------------------
if (-not $NoValidate) {
if (Test-Path $validateScript) {
Write-Host ""
Write-Host "--- xdto-validate ---"
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $validateScript -PackagePath (Join-Path $xdtoRoot $pkgName)
} else {
Write-Host "[SKIP] xdto-validate не найден: $validateScript"
}
}
exit 0