diff --git a/.claude/skills/meta-edit/scripts/meta-edit.ps1 b/.claude/skills/meta-edit/scripts/meta-edit.ps1
index cad03079..a5ae63c3 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.14 — Edit existing 1C metadata object XML (+structural attr props Format/EditFormat/ToolTip/ChoiceForm/MinValue/MaxValue)
+# meta-edit v1.15 — Edit existing 1C metadata object XML (+structural attr props Format/EditFormat/ToolTip/ChoiceForm/MinValue/MaxValue/LinkByType/ChoiceParameterLinks)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$DefinitionFile,
@@ -2270,6 +2270,16 @@ function Modify-ChildElements($modifyDef, [string]$childType) {
Info "Set $xmlTag '$elemName'.MaxValue"; $script:modifyCount++
}
}
+ "LinkByType" {
+ if (Set-AttrPropertyElement $propsEl "LinkByType" (Build-LinkByTypeXml (Get-ChildIndent $propsEl) $changeValue)) {
+ Info "Set $xmlTag '$elemName'.LinkByType"; $script:modifyCount++
+ }
+ }
+ "ChoiceParameterLinks" {
+ if (Set-AttrPropertyElement $propsEl "ChoiceParameterLinks" (Build-ChoiceParameterLinksXml (Get-ChildIndent $propsEl) $changeValue)) {
+ Info "Set $xmlTag '$elemName'.ChoiceParameterLinks"; $script:modifyCount++
+ }
+ }
default {
# Scalar property change (Indexing, FillChecking, Use, etc.)
$scalarEl = $null
@@ -2437,6 +2447,103 @@ function Build-MinMaxValueXml([string]$tag, $val) {
return "<$tag xsi:type=`"$t`">$(Esc-Xml "$val")$tag>"
}
+# --- Порт из meta-compile: развёртка путей данных + связи выбора / тип по ссылке (structural modify) ---
+
+# Свойство из dict/PSCustomObject по списку синонимов (первый найденный, иначе $null).
+function Get-ChElProp($obj, [string[]]$names) {
+ if ($null -eq $obj) { return $null }
+ foreach ($n in $names) {
+ if ($obj -is [System.Collections.IDictionary]) { if ($obj.Contains($n)) { return $obj[$n] } }
+ elseif ($obj.PSObject -and $obj.PSObject.Properties[$n]) { return $obj.PSObject.Properties[$n].Value }
+ }
+ return $null
+}
+
+# Стандартный реквизит рус/англ → английский (для Catalog/Document); использует существующие reserved-карты.
+function Resolve-StdAttrEn([string]$name) {
+ $ctx = switch ("$script:objType") { 'Catalog' { 'catalog' } 'Document' { 'document' } default { $null } }
+ if (-not $ctx) { return $null }
+ $stdSet = $script:reservedByContext[$ctx]
+ foreach ($en in $stdSet) {
+ $ru = $script:reservedAttrNames[$en]
+ if (($name -ieq $en) -or ($ru -and $name -ieq $ru)) { return $en }
+ }
+ return $null
+}
+
+# Прощающий ввод пути данных: короткое имя реквизита → полный путь объекта (порт Expand-DataPath).
+function Expand-DataPath([string]$dp) {
+ if (-not $dp) { return $dp }
+ $s = "$dp"
+ if ($s -match '[:/]') { return $s }
+ if ($s -match '^-?\d+$') { return $s }
+ if ($s -match '^(StandardAttribute|Attribute)\.') { return "$($script:objType).$($script:objName).$s" }
+ if (-not $s.Contains('.')) {
+ $en = Resolve-StdAttrEn $s
+ if ($en) { return "$($script:objType).$($script:objName).StandardAttribute.$en" }
+ return "$($script:objType).$($script:objName).Attribute.$s"
+ }
+ return $s
+}
+
+# Shorthand "name=path" | "name=path:Clear|DontChange" → {name, dataPath, valueChange?}.
+function ConvertFrom-ChLinkShorthand([string]$s) {
+ $eq = $s.IndexOf('=')
+ if ($eq -lt 0) { return @{ name = $s.Trim() } }
+ $o = @{ name = $s.Substring(0, $eq).Trim() }; $rest = $s.Substring($eq + 1).Trim()
+ if ($rest -match '^(.*):(?i:(Clear|DontChange|очистить|неизменять))$') { $o['dataPath'] = $matches[1].Trim(); $o['valueChange'] = $matches[2] }
+ else { $o['dataPath'] = $rest }
+ return $o
+}
+
+# LinkByType — {dataPath, linkItem?} (порт Emit-LinkByType). Строка → dataPath, linkItem=0.
+function Build-LinkByTypeXml([string]$indent, $spec) {
+ if (-not $spec) { return "$indent" }
+ if ($spec -is [string]) { $dp = "$spec"; $li = 0 }
+ else {
+ $dp = "$(Get-ChElProp $spec @('dataPath','path','путь'))"
+ $liRaw = Get-ChElProp $spec @('linkItem','элементСвязи')
+ $li = if ($null -ne $liRaw) { $liRaw } else { 0 }
+ }
+ if (-not $dp) { return "$indent" }
+ $dp = Expand-DataPath $dp
+ $lines = @(
+ "$indent"
+ "$indent`t$(Esc-Xml "$dp")"
+ "$indent`t$li"
+ "$indent"
+ )
+ return $lines -join "`r`n"
+}
+
+# ChoiceParameterLinks — [{name, dataPath, valueChange?}] (порт Emit-ChoiceParameterLinks). valueChange дефолт Clear.
+function Build-ChoiceParameterLinksXml([string]$indent, $cpl) {
+ if (-not $cpl -or @($cpl).Count -eq 0) { return "$indent" }
+ $sb = New-Object System.Text.StringBuilder
+ $sb.Append("$indent") | Out-Null
+ foreach ($lk in @($cpl)) {
+ if ($lk -is [string]) { $lk = ConvertFrom-ChLinkShorthand $lk }
+ $name = Get-ChElProp $lk @('name','имя')
+ $dp = Expand-DataPath (Get-ChElProp $lk @('dataPath','path','путь'))
+ $vcRaw = Get-ChElProp $lk @('valueChange','режимИзменения')
+ $vc = 'Clear'
+ if ($vcRaw) {
+ $vc = switch -Regex ("$vcRaw".ToLower()) {
+ '^(clear|очистить|очистка)$' { 'Clear'; break }
+ '^(dontchange|неизменять|неменять|нет)$' { 'DontChange'; break }
+ default { "$vcRaw" }
+ }
+ }
+ $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$vc") | Out-Null
+ $sb.Append("`r`n$indent`t") | Out-Null
+ }
+ $sb.Append("`r`n$indent") | Out-Null
+ return $sb.ToString()
+}
+
function Find-PropertyElement([string]$propName) {
foreach ($child in $script:propertiesEl.ChildNodes) {
if ($child.NodeType -eq 'Element' -and $child.LocalName -eq $propName) {
diff --git a/.claude/skills/meta-edit/scripts/meta-edit.py b/.claude/skills/meta-edit/scripts/meta-edit.py
index 713a08c7..037a3927 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.14 — Edit existing 1C metadata object XML (+structural attr props Format/EditFormat/ToolTip/ChoiceForm/MinValue/MaxValue)
+# meta-edit v1.15 — Edit existing 1C metadata object XML (+structural attr props Format/EditFormat/ToolTip/ChoiceForm/MinValue/MaxValue/LinkByType/ChoiceParameterLinks)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -2113,6 +2113,14 @@ def modify_child_elements(modify_def, child_type):
if set_attr_property_element(props_el, "MaxValue", build_min_max_value_xml("MaxValue", change_value)):
info(f"Set {xml_tag} '{elem_name}'.MaxValue")
modify_count += 1
+ elif change_prop == "LinkByType":
+ if set_attr_property_element(props_el, "LinkByType", build_link_by_type_xml(get_child_indent(props_el), change_value)):
+ info(f"Set {xml_tag} '{elem_name}'.LinkByType")
+ modify_count += 1
+ elif change_prop == "ChoiceParameterLinks":
+ if set_attr_property_element(props_el, "ChoiceParameterLinks", build_choice_parameter_links_xml(get_child_indent(props_el), change_value)):
+ info(f"Set {xml_tag} '{elem_name}'.ChoiceParameterLinks")
+ modify_count += 1
else:
# Scalar property change (Indexing, FillChecking, Use, etc.)
@@ -2266,6 +2274,128 @@ def build_min_max_value_xml(tag, val):
return f'<{tag} xsi:type="{t}">{esc_xml(str(val))}{tag}>'
+# --- Порт из meta-compile: развёртка путей данных + связи выбора / тип по ссылке (structural modify) ---
+
+def get_ch_el_prop(obj, names):
+ """Свойство из dict по списку синонимов (первый найденный, иначе None)."""
+ if obj is None:
+ return None
+ if isinstance(obj, dict):
+ for n in names:
+ if n in obj:
+ return obj[n]
+ return None
+
+
+# Пары EN↔RU стандартных реквизитов Catalog/Document (для resolve_std_attr_en; py-карты плоские, восстанавливаем).
+_STD_ATTR_BY_CTX = {
+ 'Catalog': [('Ref', 'Ссылка'), ('DeletionMark', 'ПометкаУдаления'), ('Predefined', 'Предопределенный'),
+ ('PredefinedDataName', 'ИмяПредопределенныхДанных'), ('Code', 'Код'), ('Description', 'Наименование'),
+ ('Owner', 'Владелец'), ('Parent', 'Родитель'), ('IsFolder', 'ЭтоГруппа')],
+ 'Document': [('Ref', 'Ссылка'), ('DeletionMark', 'ПометкаУдаления'), ('Date', 'Дата'),
+ ('Number', 'Номер'), ('Posted', 'Проведен')],
+}
+
+
+def resolve_std_attr_en(name):
+ """Стандартный реквизит рус/англ → английский (Catalog/Document)."""
+ pairs = _STD_ATTR_BY_CTX.get(obj_type)
+ if not pairs:
+ return None
+ nl = str(name).lower()
+ for en, ru in pairs:
+ if nl == en.lower() or nl == ru.lower():
+ return en
+ return None
+
+
+def expand_data_path(dp):
+ """Прощающий ввод пути данных: короткое имя реквизита → полный путь объекта (порт Expand-DataPath)."""
+ if not dp:
+ return dp
+ s = str(dp)
+ if re.search(r'[:/]', s):
+ return s
+ if re.match(r'^-?\d+$', s):
+ return s
+ if re.match(r'^(StandardAttribute|Attribute)\.', s):
+ return f"{obj_type}.{obj_name}.{s}"
+ if '.' not in s:
+ en = resolve_std_attr_en(s)
+ if en:
+ return f"{obj_type}.{obj_name}.StandardAttribute.{en}"
+ return f"{obj_type}.{obj_name}.Attribute.{s}"
+ return s
+
+
+def convert_from_ch_link_shorthand(s):
+ """Shorthand "name=path" | "name=path:Clear|DontChange" → {name, dataPath, valueChange?}."""
+ eq = s.find('=')
+ if eq < 0:
+ return {'name': s.strip()}
+ o = {'name': s[:eq].strip()}
+ rest = s[eq + 1:].strip()
+ m = re.match(r'^(.*):(Clear|DontChange|очистить|неизменять)$', rest, re.IGNORECASE)
+ if m:
+ o['dataPath'] = m.group(1).strip()
+ o['valueChange'] = m.group(2)
+ else:
+ o['dataPath'] = rest
+ return o
+
+
+def build_link_by_type_xml(indent, spec):
+ """LinkByType — {dataPath, linkItem?} (порт Emit-LinkByType)."""
+ if not spec:
+ return f"{indent}"
+ if isinstance(spec, str):
+ dp = spec
+ li = 0
+ else:
+ dp = str(get_ch_el_prop(spec, ['dataPath', 'path', 'путь']) or '')
+ li_raw = get_ch_el_prop(spec, ['linkItem', 'элементСвязи'])
+ li = li_raw if li_raw is not None else 0
+ if not dp:
+ return f"{indent}"
+ dp = expand_data_path(dp)
+ return "\r\n".join([
+ f"{indent}",
+ f"{indent}\t{esc_xml(str(dp))}",
+ f"{indent}\t{li}",
+ f"{indent}",
+ ])
+
+
+def build_choice_parameter_links_xml(indent, cpl):
+ """ChoiceParameterLinks — [{name, dataPath, valueChange?}] (порт Emit-ChoiceParameterLinks)."""
+ items = cpl if isinstance(cpl, list) else ([cpl] if cpl else [])
+ if not items:
+ return f"{indent}"
+ parts = [f"{indent}"]
+ for lk in items:
+ if isinstance(lk, str):
+ lk = convert_from_ch_link_shorthand(lk)
+ name = get_ch_el_prop(lk, ['name', 'имя'])
+ dp = expand_data_path(get_ch_el_prop(lk, ['dataPath', 'path', 'путь']))
+ vc_raw = get_ch_el_prop(lk, ['valueChange', 'режимИзменения'])
+ vc = 'Clear'
+ if vc_raw:
+ low = str(vc_raw).lower()
+ if re.match(r'^(clear|очистить|очистка)$', low):
+ vc = 'Clear'
+ elif re.match(r'^(dontchange|неизменять|неменять|нет)$', low):
+ vc = 'DontChange'
+ 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{vc}")
+ parts.append(f"{indent}\t")
+ parts.append(f"{indent}")
+ return "\r\n".join(parts)
+
+
def find_property_element(prop_name):
for child in properties_el:
if localname(child) == prop_name:
diff --git a/tests/skills/cases/meta-edit/modify-attribute-structural.json b/tests/skills/cases/meta-edit/modify-attribute-structural.json
index 758d0c3d..92003953 100644
--- a/tests/skills/cases/meta-edit/modify-attribute-structural.json
+++ b/tests/skills/cases/meta-edit/modify-attribute-structural.json
@@ -17,7 +17,11 @@
"modify": {
"attributes": {
"Дата": { "Format": "ДФ=dd.MM.yyyy", "EditFormat": "ДФ=dd.MM.yyyy", "ToolTip": "Дата документа" },
- "Контр": { "ChoiceForm": "Catalog.Спр.Form.ФормаВыбора" },
+ "Контр": {
+ "ChoiceForm": "Catalog.Спр.Form.ФормаВыбора",
+ "ChoiceParameterLinks": ["Отбор.Владелец=Ссылка"],
+ "LinkByType": { "dataPath": "Ссылка", "linkItem": 0 }
+ },
"Сумма": { "MinValue": 0, "MaxValue": 1000000 }
}
}
diff --git a/tests/skills/cases/meta-edit/snapshots/modify-attribute-structural/Catalogs/Спр.xml b/tests/skills/cases/meta-edit/snapshots/modify-attribute-structural/Catalogs/Спр.xml
index a081af85..536ab406 100644
--- a/tests/skills/cases/meta-edit/snapshots/modify-attribute-structural/Catalogs/Спр.xml
+++ b/tests/skills/cases/meta-edit/snapshots/modify-attribute-structural/Catalogs/Спр.xml
@@ -172,12 +172,21 @@
DontCheck
Items
-
+
+
+ Отбор.Владелец
+ Catalog.Спр.StandardAttribute.Ref
+ Clear
+
+
Auto
Auto
Catalog.Спр.Form.ФормаВыбора
-
+
+ Catalog.Спр.StandardAttribute.Ref
+ 0
+
Auto
DontIndex