fix(cfe-borrow): тип у ранее заимствованной константы; стили оформления и без ChildItems

Найдено ревью main...dev:
- константа, заимствованная раньше оболочкой (-Object Constant.X), при заимствовании
  общей формы с набором констант оставалась без <Type>: тип дописывался только
  новой константе. Теперь дописывается и в существующую, если его там нет —
  как слияние реквизитов в уже заимствованный объект. Кейс
  common-form-constants-reborrow (на прежнем коде падал);
- стили из условного оформления заимствовались только у формы с ChildItems:
  сбор стилей стоял внутри блока элементов. Вынесен на уровень формы.
Оба порта.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-09-27 20:59:51 +03:00
co-authored by Claude Opus 5.5
parent 113070826d
commit 32aaf3bad7
29 changed files with 1107 additions and 74 deletions
@@ -1253,41 +1253,6 @@ function Borrow-Form {
}
}
# Auto-borrow StyleItems referenced in ChildItems and in the form's conditional appearance
# (стиль только из оформления Конфигуратор тоже заимствует — эталон УТ CAStyle)
# Pattern 1: <Font ref="style:XXX" kind="StyleItem"/>, <TitleFont ref="style:XXX" ... kind="StyleItem"/>
# Pattern 2: <BackColor>style:XXX</BackColor>, <TextColor>style:XXX</TextColor>, etc.
# Порядок первого упоминания — как в Python-порте (от него зависит порядок в ChildObjects)
$styleScanXml = $childItemsXml + $srcCondAppearanceXml
$referencedStyles = [ordered]@{}
$styleRefs1 = [regex]::Matches($styleScanXml, 'ref="style:(\w+)"[^>]*kind="StyleItem"')
foreach ($m in $styleRefs1) { $referencedStyles[$m.Groups[1].Value] = $true }
# Закрывающий тег может быть с префиксом: в оформлении значение — <dcscor:value>style:X</dcscor:value>
$styleRefs2 = [regex]::Matches($styleScanXml, '>style:(\w+)</[\w:]+>')
foreach ($m in $styleRefs2) { $referencedStyles[$m.Groups[1].Value] = $true }
foreach ($styleName in $referencedStyles.Keys) {
if (-not (Test-ObjectBorrowed "StyleItem" $styleName)) {
$styleSrcFile = Join-Path (Join-Path $cfgDir "StyleItems") "${styleName}.xml"
if (Test-Path $styleSrcFile) {
$src = Read-SourceObject "StyleItem" $styleName
$borrowedXml = Build-BorrowedObjectXml "StyleItem" $styleName $src.Uuid $src.Properties
$targetDir = Join-Path $extDir "StyleItems"
if (-not (Test-Path $targetDir)) {
New-Item -ItemType Directory -Path $targetDir -Force | Out-Null
}
$targetFile = Join-Path $targetDir "${styleName}.xml"
$encBom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($targetFile, $borrowedXml, $encBom)
Add-ToChildObjects "StyleItem" $styleName
$script:borrowedFiles += $targetFile
Info " Auto-borrowed: StyleItem.${styleName}"
}
# Файла нет — встроенный стиль платформы (ImportantColor, AccentColor…): заимствовать
# нечего, пропускаем молча. Пользовательский стиль, на который ссылается форма, в
# валидном источнике существует всегда — предупреждение было только шумом.
}
}
# Auto-borrow Enums + EnumValues referenced via DesignTimeRef in ChoiceParameters
# Collect Enum -> [EnumValue names] map
$dtRefs = [regex]::Matches($childItemsXml, 'xr:DesignTimeRef">Enum\.(\w+)\.EnumValue\.(\w+)')
@@ -1363,6 +1328,42 @@ function Borrow-Form {
}
}
# Вне блока ChildItems: стили нужны и оформлению формы без элементов
# Auto-borrow StyleItems referenced in ChildItems and in the form's conditional appearance
# (стиль только из оформления Конфигуратор тоже заимствует — эталон УТ CAStyle)
# Pattern 1: <Font ref="style:XXX" kind="StyleItem"/>, <TitleFont ref="style:XXX" ... kind="StyleItem"/>
# Pattern 2: <BackColor>style:XXX</BackColor>, <TextColor>style:XXX</TextColor>, etc.
# Порядок первого упоминания — как в Python-порте (от него зависит порядок в ChildObjects)
$styleScanXml = $childItemsXml + $srcCondAppearanceXml
$referencedStyles = [ordered]@{}
$styleRefs1 = [regex]::Matches($styleScanXml, 'ref="style:(\w+)"[^>]*kind="StyleItem"')
foreach ($m in $styleRefs1) { $referencedStyles[$m.Groups[1].Value] = $true }
# Закрывающий тег может быть с префиксом: в оформлении значение — <dcscor:value>style:X</dcscor:value>
$styleRefs2 = [regex]::Matches($styleScanXml, '>style:(\w+)</[\w:]+>')
foreach ($m in $styleRefs2) { $referencedStyles[$m.Groups[1].Value] = $true }
foreach ($styleName in $referencedStyles.Keys) {
if (-not (Test-ObjectBorrowed "StyleItem" $styleName)) {
$styleSrcFile = Join-Path (Join-Path $cfgDir "StyleItems") "${styleName}.xml"
if (Test-Path $styleSrcFile) {
$src = Read-SourceObject "StyleItem" $styleName
$borrowedXml = Build-BorrowedObjectXml "StyleItem" $styleName $src.Uuid $src.Properties
$targetDir = Join-Path $extDir "StyleItems"
if (-not (Test-Path $targetDir)) {
New-Item -ItemType Directory -Path $targetDir -Force | Out-Null
}
$targetFile = Join-Path $targetDir "${styleName}.xml"
$encBom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($targetFile, $borrowedXml, $encBom)
Add-ToChildObjects "StyleItem" $styleName
$script:borrowedFiles += $targetFile
Info " Auto-borrowed: StyleItem.${styleName}"
}
# Файла нет — встроенный стиль платформы (ImportantColor, AccentColor…): заимствовать
# нечего, пропускаем молча. Пользовательский стиль, на который ссылается форма, в
# валидном источнике существует всегда — предупреждение было только шумом.
}
}
# Открывающий тег <Form ...> берём из исходной формы — ради её объявлений пространств имён,
# но version подставляем СВОЮ: форма обязана нести версию расширения, иначе платформа
# отвергает импорт (форма 2.13 внутри расширения 2.17). Раньше тег копировался целиком,
@@ -2296,18 +2297,29 @@ function Borrow-FormConstants {
$cTypeNode = $cDoc.SelectSingleNode("//*[local-name()='Constant']/*[local-name()='Properties']/*[local-name()='Type']")
$cTypeXml = if ($cTypeNode) { ([regex]::Replace($cTypeNode.OuterXml, '\s+xmlns(?::\w+)?="[^"]*"', '') -replace "`r?`n", "`r`n") } else { "" }
if ($cTypeXml) { $typeXmls += $cTypeXml }
# Тип — последним свойством, после ExtendedConfigurationObject (как у Конфигуратора)
$addType = {
param([string]$xml)
([regex]'(?<ind>[ \t]*)<ExtendedConfigurationObject>[^<]*</ExtendedConfigurationObject>').Replace($xml, {
param($mm) $mm.Value + "`r`n" + $mm.Groups['ind'].Value + $cTypeXml
}, 1)
}
if (Test-ObjectBorrowed "Constant" $cName) {
Info " Already borrowed: Constant.${cName}"
# Заимствованная раньше оболочкой (-Object Constant.X) — без типа: дописываем, как при
# слиянии реквизитов в уже заимствованный объект
$extCFile = Join-Path (Join-Path $extDir "Constants") "${cName}.xml"
$extCText = [System.IO.File]::ReadAllText($extCFile, $encBom)
if ($cTypeXml -and $extCText -cnotmatch '<Type>') {
[System.IO.File]::WriteAllText($extCFile, (& $addType $extCText), $encBom)
Info " Added type: Constant.${cName}"
} else {
Info " Already borrowed: Constant.${cName}"
}
continue
}
$src = Read-SourceObject "Constant" $cName
$borrowedXml = Build-BorrowedObjectXml "Constant" $cName $src.Uuid $src.Properties
if ($cTypeXml) {
# Тип — последним свойством, после ExtendedConfigurationObject (как у Конфигуратора)
$borrowedXml = ([regex]'(?<ind>[ \t]*)<ExtendedConfigurationObject>[^<]*</ExtendedConfigurationObject>').Replace($borrowedXml, {
param($mm) $mm.Value + "`r`n" + $mm.Groups['ind'].Value + $cTypeXml
}, 1)
}
if ($cTypeXml) { $borrowedXml = & $addType $borrowedXml }
$targetDir = Join-Path $extDir "Constants"
if (-not (Test-Path $targetDir)) { New-Item -ItemType Directory -Path $targetDir -Force | Out-Null }
$targetFile = Join-Path $targetDir "${cName}.xml"
+44 -32
View File
@@ -1865,15 +1865,26 @@ def main():
c_type_xml = re.sub(r'\s+xmlns(?::\w+)?="[^"]*"', '', tm.group(1)).replace("\r\n", "\n") if tm else ""
if c_type_xml:
type_xmls.append(c_type_xml)
def add_type(xml):
# Тип — последним свойством, после ExtendedConfigurationObject (как у Конфигуратора)
return re.sub(r'(?P<ind>[ \t]*)<ExtendedConfigurationObject>[^<]*</ExtendedConfigurationObject>',
lambda mm: mm.group(0) + "\n" + mm.group('ind') + c_type_xml, xml, count=1)
if test_object_borrowed("Constant", c_name):
info(f" Already borrowed: Constant.{c_name}")
# Заимствованная раньше оболочкой (-Object Constant.X) — без типа: дописываем, как при
# слиянии реквизитов в уже заимствованный объект
ext_c_file = os.path.join(ext_dir, "Constants", f"{c_name}.xml")
with open(ext_c_file, "r", encoding="utf-8-sig", newline="") as fh:
ext_c_text = fh.read()
if c_type_xml and '<Type>' not in ext_c_text:
write_xml_file(ext_c_file, add_type(ext_c_text.replace("\r\n", "\n")))
info(f" Added type: Constant.{c_name}")
else:
info(f" Already borrowed: Constant.{c_name}")
continue
src = read_source_object("Constant", c_name)
borrowed_xml = build_borrowed_object_xml("Constant", c_name, src["Uuid"], src["Properties"])
if c_type_xml:
# Тип — последним свойством, после ExtendedConfigurationObject (как у Конфигуратора)
borrowed_xml = re.sub(r'(?P<ind>[ \t]*)<ExtendedConfigurationObject>[^<]*</ExtendedConfigurationObject>',
lambda mm: mm.group(0) + "\n" + mm.group('ind') + c_type_xml, borrowed_xml, count=1)
borrowed_xml = add_type(borrowed_xml)
target_dir = os.path.join(ext_dir, "Constants")
os.makedirs(target_dir, exist_ok=True)
target_file = os.path.join(target_dir, f"{c_name}.xml")
@@ -2364,34 +2375,6 @@ def main():
if cp_name not in borrowed_pic_set:
auto_cmd_xml = auto_cmd_xml[:pm.start()] + auto_cmd_xml[pm.end():]
# Auto-borrow StyleItems referenced in ChildItems and in the form's conditional appearance
# (стиль только из оформления Конфигуратор тоже заимствует — эталон УТ CAStyle).
# Порядок первого упоминания — как в PS-порте (от него зависит порядок в ChildObjects)
style_scan_xml = child_items_xml + src_cond_appearance_xml
referenced_styles = {}
for m in re.finditer(r'ref="style:(\w+)"[^>]*kind="StyleItem"', style_scan_xml):
referenced_styles[m.group(1)] = True
# Закрывающий тег может быть с префиксом: в оформлении значение — <dcscor:value>style:X</dcscor:value>
for m in re.finditer(r'>style:(\w+)</[\w:]+>', style_scan_xml):
referenced_styles[m.group(1)] = True
for style_name in referenced_styles:
if not test_object_borrowed("StyleItem", style_name):
style_src_file = os.path.join(cfg_dir, "StyleItems", f"{style_name}.xml")
if os.path.isfile(style_src_file):
src = read_source_object("StyleItem", style_name)
borrowed_xml = build_borrowed_object_xml("StyleItem", style_name, src["Uuid"], src["Properties"])
target_dir = os.path.join(ext_dir, "StyleItems")
os.makedirs(target_dir, exist_ok=True)
target_file = os.path.join(target_dir, f"{style_name}.xml")
write_xml_file(target_file, borrowed_xml)
add_to_child_objects("StyleItem", style_name)
borrowed_files.append(target_file)
info(f" Auto-borrowed: StyleItem.{style_name}")
# Файла нет — встроенный стиль платформы (ImportantColor, AccentColor…): заимствовать
# нечего, пропускаем молча. Пользовательский стиль, на который ссылается форма, в
# валидном источнике существует всегда — предупреждение было только шумом.
# Auto-borrow Enums + EnumValues referenced via DesignTimeRef
referenced_enum_values = {} # enum_name -> set of value_names
for m in re.finditer(r'xr:DesignTimeRef">Enum\.(\w+)\.EnumValue\.(\w+)', child_items_xml):
@@ -2456,6 +2439,35 @@ def main():
else:
warn(f" Enum.{enum_name} not found in source config")
# Вне блока ChildItems: стили нужны и оформлению формы без элементов
# Auto-borrow StyleItems referenced in ChildItems and in the form's conditional appearance
# (стиль только из оформления Конфигуратор тоже заимствует — эталон УТ CAStyle).
# Порядок первого упоминания — как в PS-порте (от него зависит порядок в ChildObjects)
style_scan_xml = child_items_xml + src_cond_appearance_xml
referenced_styles = {}
for m in re.finditer(r'ref="style:(\w+)"[^>]*kind="StyleItem"', style_scan_xml):
referenced_styles[m.group(1)] = True
# Закрывающий тег может быть с префиксом: в оформлении значение — <dcscor:value>style:X</dcscor:value>
for m in re.finditer(r'>style:(\w+)</[\w:]+>', style_scan_xml):
referenced_styles[m.group(1)] = True
for style_name in referenced_styles:
if not test_object_borrowed("StyleItem", style_name):
style_src_file = os.path.join(cfg_dir, "StyleItems", f"{style_name}.xml")
if os.path.isfile(style_src_file):
src = read_source_object("StyleItem", style_name)
borrowed_xml = build_borrowed_object_xml("StyleItem", style_name, src["Uuid"], src["Properties"])
target_dir = os.path.join(ext_dir, "StyleItems")
os.makedirs(target_dir, exist_ok=True)
target_file = os.path.join(target_dir, f"{style_name}.xml")
write_xml_file(target_file, borrowed_xml)
add_to_child_objects("StyleItem", style_name)
borrowed_files.append(target_file)
info(f" Auto-borrowed: StyleItem.{style_name}")
# Файла нет — встроенный стиль платформы (ImportantColor, AccentColor…): заимствовать
# нечего, пропускаем молча. Пользовательский стиль, на который ссылается форма, в
# валидном источнике существует всегда — предупреждение было только шумом.
# Открывающий тег <Form ...> берём из исходной формы — ради её объявлений пространств
# имён, но version подставляем СВОЮ: форма обязана нести версию расширения, иначе
# платформа отвергает импорт (форма 2.13 внутри расширения 2.17). Раньше тег