fix: resolve remaining 19 Python test failures — 285/285 on both runtimes

Script logic fixes (PY mirroring PS1):
- skd-compile: fix (?i) regex flag placement for Python 3.11+
- mxl-compile: handle list-of-lists row format (PS1 silently ignores)
- subsystem-compile: add "objects" → "content" synonym alias
- role-compile: add "rights" → "objects" synonym alias
- meta-compile: sort HTTP/Web service method/operation iteration
- form-edit: insert ChildItems after Events/AutoCommandBar (not at end)
- mxl-compile: sort colWidthMap iteration in both PS1 and PY for
  deterministic format indices

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-03-28 20:30:45 +03:00
parent 4565808b77
commit 972cd5061d
10 changed files with 42 additions and 20 deletions
+10 -2
View File
@@ -973,8 +973,16 @@ if elements_list:
target_ci = root_ci target_ci = root_ci
if target_ci is None: if target_ci is None:
# Create ChildItems section in form # Create ChildItems section in form — insert after Events or AutoCommandBar
target_ci = etree.SubElement(root, f"{{{FORM_NS}}}ChildItems") target_ci = etree.Element(f"{{{FORM_NS}}}ChildItems")
insert_after = root.find("f:Events", NS)
if insert_after is None:
insert_after = root.find("f:AutoCommandBar", NS)
if insert_after is not None:
idx = list(root).index(insert_after) + 1
root.insert(idx, target_ci)
else:
root.append(target_ci)
root_ci = target_ci root_ci = target_ci
# Detect indent level # Detect indent level
@@ -2000,7 +2000,7 @@ def emit_url_template(indent, tmpl_name, tmpl_def):
X(f'{indent}\t</Properties>') X(f'{indent}\t</Properties>')
if methods: if methods:
X(f'{indent}\t<ChildObjects>') X(f'{indent}\t<ChildObjects>')
for method_name, http_method in methods.items(): for method_name, http_method in sorted(methods.items()):
method_uuid = new_uuid() method_uuid = new_uuid()
method_synonym = split_camel_case(method_name) method_synonym = split_camel_case(method_name)
handler = f'{tmpl_name}{method_name}' handler = f'{tmpl_name}{method_name}'
@@ -2051,7 +2051,7 @@ def emit_operation(indent, op_name, op_def):
X(f'{indent}\t</Properties>') X(f'{indent}\t</Properties>')
if params: if params:
X(f'{indent}\t<ChildObjects>') X(f'{indent}\t<ChildObjects>')
for param_name, param_def in params.items(): for param_name, param_def in sorted(params.items()):
param_uuid = new_uuid() param_uuid = new_uuid()
param_synonym = split_camel_case(param_name) param_synonym = split_camel_case(param_name)
param_type = 'xs:string' param_type = 'xs:string'
@@ -2312,7 +2312,7 @@ if obj_type == 'HTTPService':
if url_templates: if url_templates:
has_children = True has_children = True
X('\t\t<ChildObjects>') X('\t\t<ChildObjects>')
for tmpl_name in url_tmpl_order: for tmpl_name in sorted(url_tmpl_order):
emit_url_template('\t\t\t', tmpl_name, url_templates[tmpl_name]) emit_url_template('\t\t\t', tmpl_name, url_templates[tmpl_name])
X('\t\t</ChildObjects>') X('\t\t</ChildObjects>')
else: else:
@@ -2329,7 +2329,7 @@ if obj_type == 'WebService':
if operations: if operations:
has_children = True has_children = True
X('\t\t<ChildObjects>') X('\t\t<ChildObjects>')
for op_name in op_order: for op_name in sorted(op_order):
emit_operation('\t\t\t', op_name, operations[op_name]) emit_operation('\t\t\t', op_name, operations[op_name])
X('\t\t</ChildObjects>') X('\t\t</ChildObjects>')
else: else:
@@ -294,7 +294,7 @@ $defaultFormatIndex = Register-Format -key $defaultFormatKey -props @{ Width = $
# 6b. Column width formats # 6b. Column width formats
$colFormatMap = @{} # 1-based col -> format index $colFormatMap = @{} # 1-based col -> format index
foreach ($col in $colWidthMap.Keys) { foreach ($col in ($colWidthMap.Keys | Sort-Object)) {
$w = $colWidthMap[$col] $w = $colWidthMap[$col]
$key = Get-FormatKey -width $w $key = Get-FormatKey -width $w
$idx = Register-Format -key $key -props @{ Width = $w } $idx = Register-Format -key $key -props @{ Width = $w }
@@ -249,7 +249,7 @@ def main():
# 6b. Column width formats # 6b. Column width formats
col_format_map = {} # 1-based col -> format index col_format_map = {} # 1-based col -> format index
for col in col_width_map: for col in sorted(col_width_map):
w = col_width_map[col] w = col_width_map[col]
key = get_format_key(width=w) key = get_format_key(width=w)
idx = register_format(key, {'Width': w}) idx = register_format(key, {'Width': w})
@@ -288,6 +288,9 @@ def main():
# Pre-register all formats from areas # Pre-register all formats from areas
for area in defn['areas']: for area in defn['areas']:
for row in area.get('rows', []): for row in area.get('rows', []):
# Skip list-of-values shorthand rows (treated as empty rows like PS1)
if isinstance(row, list):
continue
# Skip empty row placeholder # Skip empty row placeholder
if row.get('empty'): if row.get('empty'):
continue continue
@@ -356,6 +359,9 @@ def main():
local_row = 0 local_row = 0
for row in area.get('rows', []): for row in area.get('rows', []):
# List-of-values shorthand: treat as row with no properties (like PS1)
if isinstance(row, list):
row = {}
# Empty row placeholder: emit N empty rows # Empty row placeholder: emit N empty rows
if row.get('empty'): if row.get('empty'):
count = int(row['empty']) count = int(row['empty'])
@@ -1,4 +1,4 @@
# role-compile v1.1 — Compile 1C role from JSON # role-compile v1.2 — Compile 1C role from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param( param(
[Parameter(Mandatory)] [Parameter(Mandatory)]
@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# role-compile v1.1 — Compile 1C role from JSON # role-compile v1.2 — Compile 1C role from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse import argparse
import json import json
@@ -455,6 +455,10 @@ def main():
synonym = str(defn['synonym']) if defn.get('synonym') else role_name synonym = str(defn['synonym']) if defn.get('synonym') else role_name
comment = str(defn['comment']) if defn.get('comment') else '' comment = str(defn['comment']) if defn.get('comment') else ''
# Synonym: accept "rights" as alias for "objects"
if not defn.get('objects') and defn.get('rights'):
defn['objects'] = defn['rights']
# --- 2. Parse all object entries --- # --- 2. Parse all object entries ---
parsed_objects = [] parsed_objects = []
if defn.get('objects'): if defn.get('objects'):
@@ -1160,9 +1160,9 @@ def emit_order(lines, items, indent, skip_auto=False):
parts = item.split() parts = item.split()
field = parts[0] field = parts[0]
direction = 'Asc' direction = 'Asc'
if len(parts) > 1 and re.match(r'^(?i)desc$', parts[1]): if len(parts) > 1 and re.match(r'(?i)^desc$', parts[1]):
direction = 'Desc' direction = 'Desc'
elif len(parts) > 1 and re.match(r'^(?i)asc$', parts[1]): elif len(parts) > 1 and re.match(r'(?i)^asc$', parts[1]):
direction = 'Asc' direction = 'Asc'
lines.append(f'{indent}\t<dcsset:item xsi:type="dcsset:OrderItemField">') lines.append(f'{indent}\t<dcsset:item xsi:type="dcsset:OrderItemField">')
lines.append(f'{indent}\t\t<dcsset:field>{esc_xml(field)}</dcsset:field>') lines.append(f'{indent}\t\t<dcsset:field>{esc_xml(field)}</dcsset:field>')
@@ -1369,7 +1369,7 @@ def parse_structure_shorthand(s):
seg = segments[i].strip() seg = segments[i].strip()
group = {'type': 'group'} group = {'type': 'group'}
if re.match(r'^(?i)(details|\u0434\u0435\u0442\u0430\u043b\u0438)$', seg): if re.match(r'(?i)^(details|\u0434\u0435\u0442\u0430\u043b\u0438)$', seg):
group['groupBy'] = [] group['groupBy'] = []
else: else:
group['groupBy'] = [seg] group['groupBy'] = [seg]
@@ -97,6 +97,10 @@ def main():
explanation = str(defn['explanation']) if defn.get('explanation') else '' explanation = str(defn['explanation']) if defn.get('explanation') else ''
picture = str(defn['picture']) if defn.get('picture') else '' picture = str(defn['picture']) if defn.get('picture') else ''
# Synonym: accept "objects" as alias for "content"
if not defn.get('content') and defn.get('objects'):
defn['content'] = defn['objects']
content_items = [] content_items = []
if defn.get('content'): if defn.get('content'):
for c in defn['content']: for c in defn['content']:
@@ -14,7 +14,7 @@
<columnsItem> <columnsItem>
<index>0</index> <index>0</index>
<column> <column>
<formatIndex>4</formatIndex> <formatIndex>2</formatIndex>
</column> </column>
</columnsItem> </columnsItem>
<columnsItem> <columnsItem>
@@ -38,13 +38,13 @@
<columnsItem> <columnsItem>
<index>4</index> <index>4</index>
<column> <column>
<formatIndex>2</formatIndex> <formatIndex>4</formatIndex>
</column> </column>
</columnsItem> </columnsItem>
<columnsItem> <columnsItem>
<index>5</index> <index>5</index>
<column> <column>
<formatIndex>2</formatIndex> <formatIndex>4</formatIndex>
</column> </column>
</columnsItem> </columnsItem>
</columns> </columns>
@@ -147,13 +147,13 @@
<width>20</width> <width>20</width>
</format> </format>
<format> <format>
<width>30</width> <width>10</width>
</format> </format>
<format> <format>
<width>40</width> <width>40</width>
</format> </format>
<format> <format>
<width>10</width> <width>30</width>
</format> </format>
<format> <format>
<font>0</font> <font>0</font>
+2 -2
View File
@@ -356,8 +356,8 @@ function compareSnapshot(workDir, snapshotDir, snapshotConfig) {
file: relFile, file: relFile,
type: 'content', type: 'content',
line: diffLine, line: diffLine,
expected: expectedLines[diffLine - 1]?.substring(0, 120), expected: expectedLines[diffLine - 1]?.substring(0, 600),
actual: actualLines[diffLine - 1]?.substring(0, 120), actual: actualLines[diffLine - 1]?.substring(0, 600),
}); });
} }
} }