diff --git a/.claude/skills/form-edit/scripts/form-edit.ps1 b/.claude/skills/form-edit/scripts/form-edit.ps1 index 4bbff2e9..ae684300 100644 --- a/.claude/skills/form-edit/scripts/form-edit.ps1 +++ b/.claude/skills/form-edit/scripts/form-edit.ps1 @@ -1,4 +1,4 @@ -# form-edit v1.5 — Edit 1C managed form elements +# form-edit v1.6 — Edit 1C managed form elements # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -270,8 +270,11 @@ function X { } function Esc-Xml { + # Экранирование ТЕКСТА элемента: только & < > . Кавычки в тексте платформа НЕ экранирует — + # пишет литерально (проверено: 92142 сырых кавычки на корпус, ни одной "). " платформа + # принимает, но при выгрузке нормализует обратно в кавычку → лишний шум в роундтрипе. param([string]$s) - return $s.Replace('&','&').Replace('<','<').Replace('>','>').Replace('"','"') + return $s.Replace('&','&').Replace('<','<').Replace('>','>') } function Emit-MLText { diff --git a/.claude/skills/form-edit/scripts/form-edit.py b/.claude/skills/form-edit/scripts/form-edit.py index 943cdf6b..5e684077 100644 --- a/.claude/skills/form-edit/scripts/form-edit.py +++ b/.claude/skills/form-edit/scripts/form-edit.py @@ -1,4 +1,4 @@ -# form-edit v1.5 — Edit 1C managed form elements (Python port) +# form-edit v1.6 — Edit 1C managed form elements (Python port) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json @@ -226,7 +226,9 @@ def local_name(node): # ── helpers ────────────────────────────────────────────────── def esc_xml(s): - return s.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') + """Экранирование ТЕКСТА элемента: только & < > . Кавычки платформа в тексте не экранирует + (92142 сырых кавычки на корпус, ни одной "); " она принимает, но нормализует обратно.""" + return s.replace('&', '&').replace('<', '<').replace('>', '>') # ── 1. Load Form.xml ──────────────────────────────────────── diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index f36cdac1..517788a8 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -1,4 +1,4 @@ -# meta-compile v1.74 — Compile 1C metadata object from JSON +# meta-compile v1.75 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -1785,7 +1785,10 @@ function Emit-Characteristics { if ([string]::IsNullOrEmpty($tfvN.Text)) { X "$indent`t`t`t" } else { X "$indent`t`t`t$(Esc-XmlText $tfvN.Text)" } } - X "$indent`t`t`t$(Esc-XmlText (Expand-CharField "$dpf" $tFrom))" + # Числовое значение (обычно -1 или 0) — как есть; разворачивать через Expand-CharField нельзя, + # оно примет "0" за короткое имя поля и выдаст ".Attribute.0". + $dpfOut = if ("$dpf" -match '^-?\d+$') { "$dpf" } else { Esc-XmlText (Expand-CharField "$dpf" $tFrom) } + X "$indent`t`t`t$dpfOut" X "$indent`t`t`t$mvu" X "$indent`t`t" X "$indent`t`t" diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index 830e2fc2..12129632 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# meta-compile v1.74 — Compile 1C metadata object from JSON +# meta-compile v1.75 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -1822,10 +1822,14 @@ def resolve_char_std_en(name): return None def char_int_field(obj, names): + """Поле-флаг Characteristics — дефолт -1. ПОЛИМОРФНО: обычно число, но DataPathField в + некоторых конфигурациях содержит ПУТЬ к полю — тогда возвращаем строку как есть.""" v = ch_el_prop(obj, names) if v is None or str(v) == '': return -1 - return int(v) + if re.fullmatch(r'-?\d+', str(v)): + return int(v) + return str(v) def expand_char_field(field, from_): s = str(field or '') @@ -1875,7 +1879,10 @@ def emit_characteristics(indent, chars): X(f'{indent}\t\t\t') else: X(f'{indent}\t\t\t{esc_xml_text(tfv_tx)}') - X(f'{indent}\t\t\t{dpf}') + # Числовое значение (обычно -1 или 0) — как есть; expand_char_field примет "0" за короткое + # имя поля и выдаст ".Attribute.0". + dpf_out = str(dpf) if re.fullmatch(r'-?\d+', str(dpf)) else esc_xml_text(expand_char_field(str(dpf), t_from)) + X(f'{indent}\t\t\t{dpf_out}') X(f'{indent}\t\t\t{mvu}') X(f'{indent}\t\t') X(f'{indent}\t\t') diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 index 4d31f5b0..c84af042 100644 --- a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 +++ b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 @@ -1,4 +1,4 @@ -# meta-decompile v0.62 — XML объекта метаданных 1С → JSON-черновик формата meta-compile +# meta-decompile v0.63 — XML объекта метаданных 1С → JSON-черновик формата meta-compile # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # # Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document, diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.py b/.claude/skills/meta-decompile/scripts/meta-decompile.py index 9f99ed2a..e1fe8cd7 100644 --- a/.claude/skills/meta-decompile/scripts/meta-decompile.py +++ b/.claude/skills/meta-decompile/scripts/meta-decompile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# meta-decompile v0.61 — XML объекта метаданных 1С → JSON-черновик формата meta-compile +# meta-decompile v0.63 — XML объекта метаданных 1С → JSON-черновик формата meta-compile # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # # Зеркало meta-decompile.ps1 (КАНОН). Структура 1:1 — те же имена функций, порядок, комментарии. @@ -1519,9 +1519,13 @@ def build_dsl(): 'filterField': shorten_char_field(gt('TypesFilterField', ct), t_from), 'filterValue': None if tfv_nil == 'true' else convert_ch_scalar_node(tfv_node), } - dpf = giv('DataPathField', ct) - if dpf != -1: - types['dataPathField'] = dpf + # DataPathField полиморфно: обычно -1, но встречается ПУТЬ к полю (8 случаев на + # корпус). Жёсткое int() на нём роняло декомпиляцию всего объекта. + dpf_node = _lx1(ct, "*[local-name()='DataPathField']") + dpf_txt = _text(dpf_node) if dpf_node is not None else '' + if dpf_txt != '' and dpf_txt != '-1': + types['dataPathField'] = (int(dpf_txt) if re.fullmatch(r'-?\d+', dpf_txt) + else shorten_char_field(dpf_txt, t_from)) mvu = giv('MultipleValuesUseField', ct) if mvu != -1: types['multipleValuesUseField'] = mvu diff --git a/.claude/skills/meta-edit/scripts/meta-edit.ps1 b/.claude/skills/meta-edit/scripts/meta-edit.ps1 index c543cea0..464a1226 100644 --- a/.claude/skills/meta-edit/scripts/meta-edit.ps1 +++ b/.claude/skills/meta-edit/scripts/meta-edit.ps1 @@ -1,4 +1,4 @@ -# meta-edit v1.23 — Edit existing 1C metadata object XML +# meta-edit v1.24 — Edit existing 1C metadata object XML # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$DefinitionFile, @@ -601,7 +601,7 @@ function Build-MLTextXml { "$indent<$tag>" "$indent`t" "$indent`t`tru" - "$indent`t`t$(Esc-Xml $text)" + "$indent`t`t$(Esc-XmlText $text)" "$indent`t" "$indent" ) @@ -941,7 +941,7 @@ function Build-AttributeFragment { $sb.AppendLine("$indent") | Out-Null $sb.AppendLine("$indent`t") | Out-Null - $sb.AppendLine("$indent`t`t$(Esc-Xml $parsed.name)") | Out-Null + $sb.AppendLine("$indent`t`t$(Esc-XmlText $parsed.name)") | Out-Null $sb.AppendLine($(Build-MLTextXml "$indent`t`t" "Synonym" $parsed.synonym)) | Out-Null $sb.AppendLine("$indent`t`t") | Out-Null @@ -1038,7 +1038,7 @@ function Build-TabularSectionFragment { # Properties $sb.AppendLine("$indent`t") | Out-Null - $sb.AppendLine("$indent`t`t$(Esc-Xml $tsName)") | Out-Null + $sb.AppendLine("$indent`t`t$(Esc-XmlText $tsName)") | Out-Null $sb.AppendLine($(Build-MLTextXml "$indent`t`t" "Synonym" $tsSynonym)) | Out-Null $sb.AppendLine("$indent`t`t") | Out-Null $sb.AppendLine("$indent`t`t") | Out-Null @@ -1112,7 +1112,7 @@ function Build-DimensionFragment { $sb.AppendLine("$indent") | Out-Null $sb.AppendLine("$indent`t") | Out-Null - $sb.AppendLine("$indent`t`t$(Esc-Xml $parsed.name)") | Out-Null + $sb.AppendLine("$indent`t`t$(Esc-XmlText $parsed.name)") | Out-Null $sb.AppendLine($(Build-MLTextXml "$indent`t`t" "Synonym" $parsed.synonym)) | Out-Null $sb.AppendLine("$indent`t`t") | Out-Null @@ -1203,7 +1203,7 @@ function Build-ResourceFragment { $sb.AppendLine("$indent") | Out-Null $sb.AppendLine("$indent`t") | Out-Null - $sb.AppendLine("$indent`t`t$(Esc-Xml $parsed.name)") | Out-Null + $sb.AppendLine("$indent`t`t$(Esc-XmlText $parsed.name)") | Out-Null $sb.AppendLine($(Build-MLTextXml "$indent`t`t" "Synonym" $parsed.synonym)) | Out-Null $sb.AppendLine("$indent`t`t") | Out-Null @@ -1276,7 +1276,7 @@ function Build-EnumValueFragment { $sb = New-Object System.Text.StringBuilder $sb.AppendLine("$indent") | Out-Null $sb.AppendLine("$indent`t") | Out-Null - $sb.AppendLine("$indent`t`t$(Esc-Xml $parsed.name)") | Out-Null + $sb.AppendLine("$indent`t`t$(Esc-XmlText $parsed.name)") | Out-Null $sb.AppendLine($(Build-MLTextXml "$indent`t`t" "Synonym" $parsed.synonym)) | Out-Null $sb.AppendLine("$indent`t`t") | Out-Null $sb.AppendLine("$indent`t") | Out-Null @@ -1306,14 +1306,14 @@ function Build-ColumnFragment { $sb = New-Object System.Text.StringBuilder $sb.AppendLine("$indent") | Out-Null $sb.AppendLine("$indent`t") | Out-Null - $sb.AppendLine("$indent`t`t$(Esc-Xml $name)") | Out-Null + $sb.AppendLine("$indent`t`t$(Esc-XmlText $name)") | Out-Null $sb.AppendLine($(Build-MLTextXml "$indent`t`t" "Synonym" $synonym)) | Out-Null $sb.AppendLine("$indent`t`t") | Out-Null $sb.AppendLine("$indent`t`t$indexing") | Out-Null if ($references.Count -gt 0) { $sb.AppendLine("$indent`t`t") | Out-Null foreach ($ref in $references) { - $sb.AppendLine("$indent`t`t`t$(Esc-Xml (Normalize-MDObjectRef "$ref"))") | Out-Null + $sb.AppendLine("$indent`t`t`t$(Esc-XmlText (Normalize-MDObjectRef "$ref"))") | Out-Null } $sb.AppendLine("$indent`t`t") | Out-Null } else { @@ -1332,7 +1332,7 @@ function Build-SimpleChildFragment { $sb = New-Object System.Text.StringBuilder $sb.AppendLine("$indent<$tagName uuid=`"$uuid`">") | Out-Null $sb.AppendLine("$indent`t") | Out-Null - $sb.AppendLine("$indent`t`t$(Esc-Xml $name)") | Out-Null + $sb.AppendLine("$indent`t`t$(Esc-XmlText $name)") | Out-Null $sb.AppendLine($(Build-MLTextXml "$indent`t`t" "Synonym" $synonym)) | Out-Null $sb.AppendLine("$indent`t`t") | Out-Null # Forms get additional properties @@ -2316,7 +2316,7 @@ function Modify-ChildElements($modifyDef, [string]$childType) { } } "ChoiceForm" { - if (Set-AttrPropertyElement $propsEl "ChoiceForm" "$(Esc-Xml "$changeValue")") { + if (Set-AttrPropertyElement $propsEl "ChoiceForm" "$(Esc-XmlText "$changeValue")") { Info "Set $xmlTag '$elemName'.ChoiceForm"; $script:modifyCount++ } } @@ -2380,7 +2380,7 @@ function Modify-ChildElements($modifyDef, [string]$childType) { } else { $valueStr = Normalize-EnumValue $changeProp $valueStr } - $newNodes = Import-Fragment "<$changeProp>$(Esc-Xml $valueStr)" + $newNodes = Import-Fragment "<$changeProp>$(Esc-XmlText $valueStr)" if ($newNodes.Count -gt 0) { Insert-PropertyInOrder $propsEl $newNodes[0] $script:attrPropOrder $changeProp Info "Created $xmlTag '$elemName'.$changeProp = $valueStr" @@ -2559,7 +2559,7 @@ function Set-AttrPropertyElement($propsEl, $propName, $fragmentXml) { function Build-MinMaxValueXml([string]$tag, $val) { if ($null -eq $val -or "$val" -eq '') { return "<$tag xsi:nil=`"true`"/>" } $t = if ($val -is [string]) { 'xs:string' } else { 'xs:decimal' } - return "<$tag xsi:type=`"$t`">$(Esc-Xml "$val")" + return "<$tag xsi:type=`"$t`">$(Esc-XmlText "$val")" } # --- Порт из meta-compile: развёртка путей данных + связи выбора / тип по ссылке (structural modify) --- @@ -2624,7 +2624,7 @@ function Build-LinkByTypeXml([string]$indent, $spec) { $dp = Expand-DataPath $dp $lines = @( "$indent" - "$indent`t$(Esc-Xml "$dp")" + "$indent`t$(Esc-XmlText "$dp")" "$indent`t$li" "$indent" ) @@ -2650,8 +2650,8 @@ function Build-ChoiceParameterLinksXml([string]$indent, $cpl) { } } $sb.Append("`r`n$indent`t") | Out-Null - $sb.Append("`r`n$indent`t`t$(Esc-Xml "$name")") | Out-Null - $sb.Append("`r`n$indent`t`t$(Esc-Xml "$dp")") | Out-Null + $sb.Append("`r`n$indent`t`t$(Esc-XmlText "$name")") | Out-Null + $sb.Append("`r`n$indent`t`t$(Esc-XmlText "$dp")") | Out-Null $sb.Append("`r`n$indent`t`t$vc") | Out-Null $sb.Append("`r`n$indent`t") | Out-Null } @@ -2792,13 +2792,13 @@ function Build-ChoiceParametersXml([string]$indent, $cp) { foreach ($v in $val) { $norm = Normalize-ChoiceValueT $v $ptype if ([string]::IsNullOrEmpty($norm.Text)) { $sb.Append("`r`n$indent`t`t`t") | Out-Null } - else { $sb.Append("`r`n$indent`t`t`t$(Esc-Xml $norm.Text)") | Out-Null } + else { $sb.Append("`r`n$indent`t`t`t$(Esc-XmlText $norm.Text)") | Out-Null } } $sb.Append("`r`n$indent`t`t") | Out-Null } else { $norm = Normalize-ChoiceValueT $val $ptype if ([string]::IsNullOrEmpty($norm.Text)) { $sb.Append("`r`n$indent`t`t") | Out-Null } - else { $sb.Append("`r`n$indent`t`t$(Esc-Xml $norm.Text)") | Out-Null } + else { $sb.Append("`r`n$indent`t`t$(Esc-XmlText $norm.Text)") | Out-Null } } $sb.Append("`r`n$indent`t") | Out-Null } @@ -2950,9 +2950,9 @@ function Add-ComplexPropertyItem([string]$propertyName, [string[]]$values) { $tag = $mapEntry.tag $attrStr = $mapEntry.attr if ($attrStr) { - $fragXml = "<$tag $attrStr>$(Esc-Xml $val)" + $fragXml = "<$tag $attrStr>$(Esc-XmlText $val)" } else { - $fragXml = "<$tag>$(Esc-Xml $val)" + $fragXml = "<$tag>$(Esc-XmlText $val)" } $nodes = Import-Fragment $fragXml foreach ($node in $nodes) { @@ -3037,9 +3037,9 @@ function Set-ComplexProperty([string]$propertyName, [string[]]$values) { $tag = $mapEntry.tag $attrStr = $mapEntry.attr if ($attrStr) { - $fragXml = "<$tag $attrStr>$(Esc-Xml $val)" + $fragXml = "<$tag $attrStr>$(Esc-XmlText $val)" } else { - $fragXml = "<$tag>$(Esc-Xml $val)" + $fragXml = "<$tag>$(Esc-XmlText $val)" } $nodes = Import-Fragment $fragXml foreach ($node in $nodes) { diff --git a/.claude/skills/meta-edit/scripts/meta-edit.py b/.claude/skills/meta-edit/scripts/meta-edit.py index 01989867..62811a41 100644 --- a/.claude/skills/meta-edit/scripts/meta-edit.py +++ b/.claude/skills/meta-edit/scripts/meta-edit.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# meta-edit v1.23 — Edit existing 1C metadata object XML +# meta-edit v1.24 — Edit existing 1C metadata object XML # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -565,7 +565,7 @@ def build_mltext_xml(indent, tag, text): f"{indent}<{tag}>", f"{indent}\t", f"{indent}\t\tru", - f"{indent}\t\t{esc_xml(text)}", + f"{indent}\t\t{esc_xml_text(text)}", f"{indent}\t", f"{indent}", ] @@ -925,7 +925,7 @@ def build_attribute_fragment(parsed, context, indent): lines.append(f'{indent}') lines.append(f"{indent}\t") - lines.append(f"{indent}\t\t{esc_xml(parsed['name'])}") + lines.append(f"{indent}\t\t{esc_xml_text(parsed['name'])}") lines.append(build_mltext_xml(f"{indent}\t\t", "Synonym", parsed["synonym"])) lines.append(f"{indent}\t\t") @@ -1021,7 +1021,7 @@ def build_tabular_section_fragment(ts_def, indent): # Properties lines.append(f"{indent}\t") - lines.append(f"{indent}\t\t{esc_xml(ts_name)}") + lines.append(f"{indent}\t\t{esc_xml_text(ts_name)}") lines.append(build_mltext_xml(f"{indent}\t\t", "Synonym", ts_synonym)) lines.append(f"{indent}\t\t") lines.append(f"{indent}\t\t") @@ -1095,7 +1095,7 @@ def build_dimension_fragment(parsed, register_type, indent): lines.append(f'{indent}') lines.append(f"{indent}\t") - lines.append(f"{indent}\t\t{esc_xml(parsed['name'])}") + lines.append(f"{indent}\t\t{esc_xml_text(parsed['name'])}") lines.append(build_mltext_xml(f"{indent}\t\t", "Synonym", parsed["synonym"])) lines.append(f"{indent}\t\t") @@ -1182,7 +1182,7 @@ def build_resource_fragment(parsed, register_type, indent): lines.append(f'{indent}') lines.append(f"{indent}\t") - lines.append(f"{indent}\t\t{esc_xml(parsed['name'])}") + lines.append(f"{indent}\t\t{esc_xml_text(parsed['name'])}") lines.append(build_mltext_xml(f"{indent}\t\t", "Synonym", parsed["synonym"])) lines.append(f"{indent}\t\t") @@ -1251,7 +1251,7 @@ def build_enum_value_fragment(parsed, indent): lines = [] lines.append(f'{indent}') lines.append(f"{indent}\t") - lines.append(f"{indent}\t\t{esc_xml(parsed['name'])}") + lines.append(f"{indent}\t\t{esc_xml_text(parsed['name'])}") lines.append(build_mltext_xml(f"{indent}\t\t", "Synonym", parsed["synonym"])) lines.append(f"{indent}\t\t") lines.append(f"{indent}\t") @@ -1281,14 +1281,14 @@ def build_column_fragment(col_def, indent): lines = [] lines.append(f'{indent}') lines.append(f"{indent}\t") - lines.append(f"{indent}\t\t{esc_xml(name)}") + lines.append(f"{indent}\t\t{esc_xml_text(name)}") lines.append(build_mltext_xml(f"{indent}\t\t", "Synonym", synonym)) lines.append(f"{indent}\t\t") lines.append(f"{indent}\t\t{indexing}") if references: lines.append(f"{indent}\t\t") for ref in references: - lines.append(f'{indent}\t\t\t{esc_xml(normalize_md_object_ref(str(ref)))}') + lines.append(f'{indent}\t\t\t{esc_xml_text(normalize_md_object_ref(str(ref)))}') lines.append(f"{indent}\t\t") else: lines.append(f"{indent}\t\t") @@ -1304,7 +1304,7 @@ def build_simple_child_fragment(tag_name, name, indent): lines = [] lines.append(f'{indent}<{tag_name} uuid="{uid}">') lines.append(f"{indent}\t") - lines.append(f"{indent}\t\t{esc_xml(name)}") + lines.append(f"{indent}\t\t{esc_xml_text(name)}") lines.append(build_mltext_xml(f"{indent}\t\t", "Synonym", synonym)) lines.append(f"{indent}\t\t") # Forms get additional properties @@ -2153,7 +2153,7 @@ def modify_child_elements(modify_def, child_type): info(f"Set {xml_tag} '{elem_name}'.ToolTip") modify_count += 1 elif change_prop == "ChoiceForm": - if set_attr_property_element(props_el, "ChoiceForm", f"{esc_xml(str(change_value))}"): + if set_attr_property_element(props_el, "ChoiceForm", f"{esc_xml_text(str(change_value))}"): info(f"Set {xml_tag} '{elem_name}'.ChoiceForm") modify_count += 1 elif change_prop == "MinValue": @@ -2210,7 +2210,7 @@ def modify_child_elements(modify_def, child_type): value_str = "true" if change_value else "false" else: value_str = normalize_enum_value(change_prop, value_str) - new_nodes = import_fragment(f"<{change_prop}>{esc_xml(value_str)}") + new_nodes = import_fragment(f"<{change_prop}>{esc_xml_text(value_str)}") if new_nodes: insert_property_in_order(props_el, new_nodes[0], attr_prop_order, change_prop) info(f"Created {xml_tag} '{elem_name}'.{change_prop} = {value_str}") @@ -2375,7 +2375,7 @@ def build_min_max_value_xml(tag, val): if val is None or str(val) == '': return f'<{tag} xsi:nil="true"/>' t = 'xs:string' if isinstance(val, str) else 'xs:decimal' - return f'<{tag} xsi:type="{t}">{esc_xml(str(val))}' + return f'<{tag} xsi:type="{t}">{esc_xml_text(str(val))}' # --- Порт из meta-compile: развёртка путей данных + связи выбора / тип по ссылке (structural modify) --- @@ -2464,7 +2464,7 @@ def build_link_by_type_xml(indent, spec): dp = expand_data_path(dp) return "\r\n".join([ f"{indent}", - f"{indent}\t{esc_xml(str(dp))}", + f"{indent}\t{esc_xml_text(str(dp))}", f"{indent}\t{li}", f"{indent}", ]) @@ -2492,8 +2492,8 @@ def build_choice_parameter_links_xml(indent, cpl): else: vc = str(vc_raw) parts.append(f"{indent}\t") - parts.append(f"{indent}\t\t{esc_xml(str(name) if name is not None else '')}") - parts.append(f'{indent}\t\t{esc_xml(str(dp) if dp is not None else "")}') + parts.append(f"{indent}\t\t{esc_xml_text(str(name) if name is not None else '')}") + parts.append(f'{indent}\t\t{esc_xml_text(str(dp) if dp is not None else "")}') parts.append(f"{indent}\t\t{vc}") parts.append(f"{indent}\t") parts.append(f"{indent}") @@ -2662,14 +2662,14 @@ def build_choice_parameters_xml(indent, cp): if not norm['Text']: parts.append(f'{indent}\t\t\t') else: - parts.append(f'{indent}\t\t\t{esc_xml(norm["Text"])}') + parts.append(f'{indent}\t\t\t{esc_xml_text(norm["Text"])}') parts.append(f'{indent}\t\t') else: norm = normalize_choice_value_t(val, ptype) if not norm['Text']: parts.append(f'{indent}\t\t') else: - parts.append(f'{indent}\t\t{esc_xml(norm["Text"])}') + parts.append(f'{indent}\t\t{esc_xml_text(norm["Text"])}') parts.append(f'{indent}\t') parts.append(f"{indent}") return "\r\n".join(parts) @@ -2848,9 +2848,9 @@ def add_complex_property_item(property_name, values): tag = map_entry["tag"] attr_str = map_entry["attr"] if attr_str: - frag_xml = f"<{tag} {attr_str}>{esc_xml(val)}" + frag_xml = f"<{tag} {attr_str}>{esc_xml_text(val)}" else: - frag_xml = f"<{tag}>{esc_xml(val)}" + frag_xml = f"<{tag}>{esc_xml_text(val)}" nodes = import_fragment(frag_xml) for node in nodes: insert_before_element(prop_el, node, None, child_indent) @@ -2928,9 +2928,9 @@ def set_complex_property(property_name, values): tag = map_entry["tag"] attr_str = map_entry["attr"] if attr_str: - frag_xml = f"<{tag} {attr_str}>{esc_xml(val)}" + frag_xml = f"<{tag} {attr_str}>{esc_xml_text(val)}" else: - frag_xml = f"<{tag}>{esc_xml(val)}" + frag_xml = f"<{tag}>{esc_xml_text(val)}" nodes = import_fragment(frag_xml) for node in nodes: insert_before_element(prop_el, node, None, child_indent) diff --git a/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 b/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 index 9a229067..6797e8b3 100644 --- a/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 +++ b/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 @@ -1,4 +1,4 @@ -# mxl-compile v1.4 — Compile 1C spreadsheet from JSON +# mxl-compile v1.5 — Compile 1C spreadsheet from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -437,8 +437,11 @@ foreach ($col in ($colWidthMap.Keys | Sort-Object)) { # Helper: escape XML special characters function Esc-Xml { + # Экранирование ТЕКСТА элемента: только & < > . Кавычки в тексте платформа НЕ экранирует — + # пишет литерально (проверено: 92142 сырых кавычки на корпус, ни одной "). " платформа + # принимает, но при выгрузке нормализует обратно в кавычку → лишний шум в роундтрипе. param([string]$s) - return $s.Replace('&','&').Replace('<','<').Replace('>','>').Replace('"','"') + return $s.Replace('&','&').Replace('<','<').Replace('>','>') } # Helper: determine fillType from cell content diff --git a/.claude/skills/mxl-compile/scripts/mxl-compile.py b/.claude/skills/mxl-compile/scripts/mxl-compile.py index 383d59c2..87cc377c 100644 --- a/.claude/skills/mxl-compile/scripts/mxl-compile.py +++ b/.claude/skills/mxl-compile/scripts/mxl-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# mxl-compile v1.4 — Compile 1C spreadsheet from JSON +# mxl-compile v1.5 — Compile 1C spreadsheet from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json @@ -188,7 +188,9 @@ def assert_edit_allowed(target_path, require): def esc_xml(s): - return s.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') + """Экранирование ТЕКСТА элемента: только & < > . Кавычки платформа в тексте не экранирует + (92142 сырых кавычки на корпус, ни одной "); " она принимает, но нормализует обратно.""" + return s.replace('&', '&').replace('<', '<').replace('>', '>') def write_utf8_bom(path, content): diff --git a/.claude/skills/role-compile/scripts/role-compile.ps1 b/.claude/skills/role-compile/scripts/role-compile.ps1 index 1ad8e824..4e17d92f 100644 --- a/.claude/skills/role-compile/scripts/role-compile.ps1 +++ b/.claude/skills/role-compile/scripts/role-compile.ps1 @@ -1,4 +1,4 @@ -# role-compile v1.8 — Compile 1C role from JSON +# role-compile v1.9 — Compile 1C role from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -171,8 +171,11 @@ function X { } function Esc-Xml { + # Экранирование ТЕКСТА элемента: только & < > . Кавычки в тексте платформа НЕ экранирует — + # пишет литерально (проверено: 92142 сырых кавычки на корпус, ни одной "). " платформа + # принимает, но при выгрузке нормализует обратно в кавычку → лишний шум в роундтрипе. param([string]$s) - return $s.Replace('&','&').Replace('<','<').Replace('>','>').Replace('"','"') + return $s.Replace('&','&').Replace('<','<').Replace('>','>') } # --- 3. Russian synonyms → canonical English names --- diff --git a/.claude/skills/role-compile/scripts/role-compile.py b/.claude/skills/role-compile/scripts/role-compile.py index 990bd9bd..0181c0b1 100644 --- a/.claude/skills/role-compile/scripts/role-compile.py +++ b/.claude/skills/role-compile/scripts/role-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# role-compile v1.8 — Compile 1C role from JSON +# role-compile v1.9 — Compile 1C role from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json @@ -204,7 +204,9 @@ def detect_format_version(d): def esc_xml(s): - return s.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') + """Экранирование ТЕКСТА элемента: только & < > . Кавычки платформа в тексте не экранирует + (92142 сырых кавычки на корпус, ни одной "); " она принимает, но нормализует обратно.""" + return s.replace('&', '&').replace('<', '<').replace('>', '>') def emit_mltext(lines, indent, tag, text): diff --git a/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 b/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 index fa318f6e..04c0b6c4 100644 --- a/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 +++ b/.claude/skills/subsystem-compile/scripts/subsystem-compile.ps1 @@ -1,4 +1,4 @@ -# subsystem-compile v1.9 — Create 1C subsystem from JSON definition +# subsystem-compile v1.10 — Create 1C subsystem from JSON definition # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$DefinitionFile, @@ -189,7 +189,9 @@ function X([string]$text) { } function Esc-Xml([string]$s) { - return $s.Replace('&','&').Replace('<','<').Replace('>','>').Replace('"','"') + # Экранирование ТЕКСТА элемента: только & < > . Кавычки в тексте платформа НЕ экранирует — + # пишет литерально (92142 сырых кавычки на корпус, ни одной "). + return $s.Replace('&','&').Replace('<','<').Replace('>','>') } function Split-CamelCase([string]$name) { diff --git a/.claude/skills/subsystem-compile/scripts/subsystem-compile.py b/.claude/skills/subsystem-compile/scripts/subsystem-compile.py index c604ecb5..4ccf9c93 100644 --- a/.claude/skills/subsystem-compile/scripts/subsystem-compile.py +++ b/.claude/skills/subsystem-compile/scripts/subsystem-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# subsystem-compile v1.9 — Create 1C subsystem from JSON definition +# subsystem-compile v1.10 — Create 1C subsystem from JSON definition # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json @@ -205,7 +205,9 @@ def detect_format_version(d): def esc_xml(s): - return s.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') + """Экранирование ТЕКСТА элемента: только & < > . Кавычки платформа в тексте не экранирует + (92142 сырых кавычки на корпус, ни одной "); " она принимает, но нормализует обратно.""" + return s.replace('&', '&').replace('<', '<').replace('>', '>') def emit_mltext(lines, indent, tag, text): diff --git a/.claude/skills/subsystem-edit/scripts/subsystem-edit.ps1 b/.claude/skills/subsystem-edit/scripts/subsystem-edit.ps1 index 6d1c60d9..56e15bc2 100644 --- a/.claude/skills/subsystem-edit/scripts/subsystem-edit.ps1 +++ b/.claude/skills/subsystem-edit/scripts/subsystem-edit.ps1 @@ -1,4 +1,4 @@ -# subsystem-edit v1.7 — Edit existing 1C subsystem XML +# subsystem-edit v1.8 — Edit existing 1C subsystem XML # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)][Alias('Path')][string]$SubsystemPath, @@ -303,7 +303,9 @@ Info "Subsystem: $($script:objName)" # --- XML manipulation helpers (from meta-edit pattern) --- function Esc-Xml([string]$s) { - return $s.Replace('&','&').Replace('<','<').Replace('>','>').Replace('"','"') + # Экранирование ТЕКСТА элемента: только & < > . Кавычки в тексте платформа НЕ экранирует — + # пишет литерально (92142 сырых кавычки на корпус, ни одной "). + return $s.Replace('&','&').Replace('<','<').Replace('>','>') } function New-Guid-String { diff --git a/.claude/skills/subsystem-edit/scripts/subsystem-edit.py b/.claude/skills/subsystem-edit/scripts/subsystem-edit.py index 0a4bb35f..67f63264 100644 --- a/.claude/skills/subsystem-edit/scripts/subsystem-edit.py +++ b/.claude/skills/subsystem-edit/scripts/subsystem-edit.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# subsystem-edit v1.7 — Edit existing 1C subsystem XML +# subsystem-edit v1.8 — Edit existing 1C subsystem XML # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -193,7 +193,9 @@ def new_uuid(): def esc_xml(s): - return s.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') + """Экранирование ТЕКСТА элемента: только & < > . Кавычки платформа в тексте не экранирует + (92142 сырых кавычки на корпус, ни одной "); " она принимает, но нормализует обратно.""" + return s.replace('&', '&').replace('<', '<').replace('>', '>') def write_utf8_bom(path, content): diff --git a/tests/skills/cases/role-compile/snapshots/with-rls/Roles/ЧтениеДокументовПоОрганизации/Ext/Rights.xml b/tests/skills/cases/role-compile/snapshots/with-rls/Roles/ЧтениеДокументовПоОрганизации/Ext/Rights.xml index 4369e416..86f25651 100644 --- a/tests/skills/cases/role-compile/snapshots/with-rls/Roles/ЧтениеДокументовПоОрганизации/Ext/Rights.xml +++ b/tests/skills/cases/role-compile/snapshots/with-rls/Roles/ЧтениеДокументовПоОрганизации/Ext/Rights.xml @@ -27,7 +27,7 @@ Read true - #ДляОбъекта("") + #ДляОбъекта("") diff --git a/tests/skills/cases/role-info/snapshots/with-rls/Roles/ОграниченноеЧтение/Ext/Rights.xml b/tests/skills/cases/role-info/snapshots/with-rls/Roles/ОграниченноеЧтение/Ext/Rights.xml index 940e2f6d..a864aa0d 100644 --- a/tests/skills/cases/role-info/snapshots/with-rls/Roles/ОграниченноеЧтение/Ext/Rights.xml +++ b/tests/skills/cases/role-info/snapshots/with-rls/Roles/ОграниченноеЧтение/Ext/Rights.xml @@ -27,7 +27,7 @@ Read true - #ПоОрганизации("") + #ПоОрганизации("") diff --git a/tests/skills/cases/role-validate/snapshots/with-rls/Roles/СОграничениями/Ext/Rights.xml b/tests/skills/cases/role-validate/snapshots/with-rls/Roles/СОграничениями/Ext/Rights.xml index e2062796..9aaab22c 100644 --- a/tests/skills/cases/role-validate/snapshots/with-rls/Roles/СОграничениями/Ext/Rights.xml +++ b/tests/skills/cases/role-validate/snapshots/with-rls/Roles/СОграничениями/Ext/Rights.xml @@ -12,7 +12,7 @@ Read true - #Шаблон("") + #Шаблон("")