feat(cfe-borrow): условное оформление формы переносится, как у Конфигуратора

Навык терял условное оформление заимствованной формы: писал <Attributes/>
(или только основной реквизит). Конфигуратор копирует <ConditionalAppearance>
как есть в обе части формы, внутрь <Attributes> после реквизитов — и без
основного реквизита тоже. Ссылки оформления на незаимствованные реквизиты
формы остаются, платформа их принимает. Элементы стиля из оформления
заимствуются, даже если больше нигде в форме не упомянуты; регэксп сбора
стилей не видел закрывающий тег с префиксом (<dcscor:value>style:X</…>).

Порядок заимствования стилей — порядок первого упоминания в обоих портах
(в PS был порядок хеша, в Python — множество). Оба порта, v1.42.

Эталоны Конфигуратора совпадают построчно в обоих портах: УТ StdPic,
StdPic_WithMain, CAStyle (включая набор стилей), УНФ Номенклатура.ФормаЭлемента —
она теперь совпадает целиком; прежние пять форм (link, TypeLink*, LinkOnly)
не сдвинулись. Кейсы form-conditional-appearance и -main; на v1.41 падали.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-09-27 19:25:26 +03:00
co-authored by Claude Opus 5.5
parent bdf7902e6a
commit 39f08563b2
39 changed files with 2056 additions and 22 deletions
@@ -1,4 +1,4 @@
# cfe-borrow v1.41 — Borrow objects from configuration into extension (CFE)
# cfe-borrow v1.42 — Borrow objects from configuration into extension (CFE)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
[CmdletBinding(PositionalBinding=$false)]
param(
@@ -1059,6 +1059,11 @@ function Borrow-Form {
$srcMainInfo = Get-MainAttributeInfo $srcFormEl $nsStripPattern
$srcMainAttrName = if ($srcMainInfo) { $srcMainInfo.Name } else { "" }
$formAttrIds = Get-FormAttributeIds $srcFormEl
# Условное оформление формы Конфигуратор копирует как есть в обе части, внутрь <Attributes>
# после реквизитов — и без основного реквизита тоже; ссылки на незаимствованные реквизиты формы
# платформа принимает (эталоны УТ StdPic, StdPic_WithMain, CAStyle, УНФ Номенклатура)
$srcCondAppearance = $srcFormEl.SelectSingleNode("*[local-name()='Attributes']/*[local-name()='ConditionalAppearance']")
$srcCondAppearanceXml = if ($srcCondAppearance) { [regex]::Replace($srcCondAppearance.OuterXml, $nsStripPattern, '') } else { "" }
$mainAttrInfo = if ($BorrowMainAttr) { $srcMainInfo } else { $null }
$mainAttrName = if ($mainAttrInfo) { $mainAttrInfo.Name } else { "" }
if ($BorrowMainAttr -and -not $mainAttrInfo) {
@@ -1191,13 +1196,17 @@ function Borrow-Form {
}
}
# Auto-borrow StyleItems referenced in 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.
$referencedStyles = @{}
$styleRefs1 = [regex]::Matches($childItemsXml, 'ref="style:(\w+)"[^>]*kind="StyleItem"')
# Порядок первого упоминания — как в 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 }
$styleRefs2 = [regex]::Matches($childItemsXml, '>style:(\w+)</\w+>')
# Закрывающий тег может быть с префиксом: в оформлении значение — <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) {
@@ -1333,10 +1342,12 @@ function Borrow-Form {
$formXmlSb.Append("`t$childItemsXml") | Out-Null
$formXmlSb.Append("`r`n") | Out-Null
}
# Attributes: empty or with MainAttribute when BorrowMainAttr
if ($BorrowMainAttr -and $mainAttrInfo) {
# Attributes: основной реквизит (с -BorrowMainAttribute) и условное оформление формы — после него
$withMainAttr = $BorrowMainAttr -and $mainAttrInfo
if ($withMainAttr -or $srcCondAppearanceXml) {
$formXmlSb.Append("`t<Attributes>`r`n") | Out-Null
$formXmlSb.Append("`t`t$($mainAttrInfo.Xml)`r`n") | Out-Null
if ($withMainAttr) { $formXmlSb.Append("`t`t$($mainAttrInfo.Xml)`r`n") | Out-Null }
if ($srcCondAppearanceXml) { $formXmlSb.Append("`t`t$srcCondAppearanceXml`r`n") | Out-Null }
$formXmlSb.Append("`t</Attributes>") | Out-Null
} else {
$formXmlSb.Append("`t<Attributes/>") | Out-Null
@@ -1359,10 +1370,11 @@ function Borrow-Form {
}
# BaseForm Attributes: same as main section
if ($BorrowMainAttr -and $mainAttrInfo) {
if ($withMainAttr -or $srcCondAppearanceXml) {
$formXmlSb.Append("`t`t<Attributes>`r`n") | Out-Null
# В BaseForm та же секция на уровень глубже — сдвиг тот же, что у ChildItems
$formXmlSb.Append((Get-BaseFormIndented $mainAttrInfo.Xml "`t`t`t") + "`r`n") | Out-Null
if ($withMainAttr) { $formXmlSb.Append((Get-BaseFormIndented $mainAttrInfo.Xml "`t`t`t") + "`r`n") | Out-Null }
if ($srcCondAppearanceXml) { $formXmlSb.Append((Get-BaseFormIndented $srcCondAppearanceXml "`t`t`t") + "`r`n") | Out-Null }
$formXmlSb.Append("`t`t</Attributes>") | Out-Null
} else {
$formXmlSb.Append("`t`t<Attributes/>") | Out-Null
+35 -12
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# cfe-borrow v1.41 — Borrow objects from configuration into extension (CFE)
# cfe-borrow v1.42 — Borrow objects from configuration into extension (CFE)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -2078,6 +2078,18 @@ def main():
src_main_info = get_main_attribute_info(src_form_el, ns_strip_pattern)
src_main_attr_name = src_main_info["Name"] if src_main_info else ""
form_attr_ids = get_form_attribute_ids(src_form_el)
# Условное оформление формы Конфигуратор копирует как есть в обе части, внутрь <Attributes>
# после реквизитов — и без основного реквизита тоже; ссылки на незаимствованные реквизиты формы
# платформа принимает (эталоны УТ StdPic, StdPic_WithMain, CAStyle, УНФ Номенклатура)
src_cond_appearance_xml = ""
for attrs_el in src_form_el:
if isinstance(attrs_el.tag, str) and localname(attrs_el) == "Attributes":
for ca_el in attrs_el:
if isinstance(ca_el.tag, str) and localname(ca_el) == "ConditionalAppearance":
src_cond_appearance_xml = ns_strip_pattern.sub("", decode_numeric_entities(
etree.tostring(ca_el, encoding="unicode", with_tail=False)))
break
break
# Основной реквизит исходной формы: его имя — корень путей к данным, которые нужно сохранить
# («Объект.» у формы объекта, «Список.» у формы списка, «Запись.» у формы записи регистра)
@@ -2201,12 +2213,16 @@ 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
referenced_styles = set()
for m in re.finditer(r'ref="style:(\w+)"[^>]*kind="StyleItem"', child_items_xml):
referenced_styles.add(m.group(1))
for m in re.finditer(r'>style:(\w+)</\w+>', child_items_xml):
referenced_styles.add(m.group(1))
# 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):
@@ -2325,10 +2341,14 @@ def main():
if child_items_xml:
parts.append(f"\t{child_items_xml}\r\n")
# Attributes: empty or with MainAttribute when borrow_main_attr
if borrow_main_attr and main_attr_info:
# Attributes: основной реквизит (с -BorrowMainAttribute) и условное оформление формы — после него
with_main_attr = bool(borrow_main_attr and main_attr_info)
if with_main_attr or src_cond_appearance_xml:
parts.append("\t<Attributes>\r\n")
parts.append(f"\t\t{main_attr_info['Xml']}\r\n")
if with_main_attr:
parts.append(f"\t\t{main_attr_info['Xml']}\r\n")
if src_cond_appearance_xml:
parts.append(f"\t\t{src_cond_appearance_xml}\r\n")
parts.append("\t</Attributes>")
else:
parts.append("\t<Attributes/>")
@@ -2346,10 +2366,13 @@ def main():
parts.append(indent_for_base_form(child_items_xml, "\t\t") + "\r\n")
# BaseForm Attributes: same as main section
if borrow_main_attr and main_attr_info:
if with_main_attr or src_cond_appearance_xml:
parts.append("\t\t<Attributes>\r\n")
# В BaseForm та же секция на уровень глубже — сдвиг тот же, что у ChildItems
parts.append(indent_for_base_form(main_attr_info['Xml'], "\t\t\t") + "\r\n")
if with_main_attr:
parts.append(indent_for_base_form(main_attr_info['Xml'], "\t\t\t") + "\r\n")
if src_cond_appearance_xml:
parts.append(indent_for_base_form(src_cond_appearance_xml, "\t\t\t") + "\r\n")
parts.append("\t\t</Attributes>")
else:
parts.append("\t\t<Attributes/>")