From 1c21bef26c12f16ce3079bb455d2470530b5e0b1 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 14 Jun 2026 13:16:28 +0300 Subject: [PATCH] =?UTF-8?q?feat(form-compile):=20drop-on-miss=20warn=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20enum=20=D0=BE=D1=80=D0=B8=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D1=86=D0=B8=D0=B8/behavior=20+=20=D0=B2=D1=8B?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BD=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=BF=D0=BE=D1=80=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Нераспознанное значение ориентации (group/columnGroup/page) и behavior теперь даёт WARN с авторским набором допустимых значений — раньше промах по карте молча не эмитил тег (тихая потеря). pass-through-ключи не трогаем (там verbatim, потери нет). Заодно выровнен регистр enum-резолва ориентации между портами: py был case-sensitive у columnGroup/page, ps1 (switch) — нет; теперь оба нечувствительны. v1.172. Регресс form-compile 43/43 (ps1+py), form-validate 10/10. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../form-compile/scripts/form-compile.ps1 | 13 ++++++++- .../form-compile/scripts/form-compile.py | 27 ++++++++++++++----- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index 19368529..7a1b3c1d 100644 --- a/.claude/skills/form-compile/scripts/form-compile.ps1 +++ b/.claude/skills/form-compile/scripts/form-compile.ps1 @@ -1,4 +1,4 @@ -# form-compile v1.171 — Compile 1C managed form from JSON or object metadata +# form-compile v1.172 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -3719,6 +3719,12 @@ function Emit-TitleLocation { } } +function Warn-Unrecognized { + # drop-on-miss enum: значение не распознано → тег не эмитится. Громко, чтобы автор увидел потерю. + param([string]$key, $raw, [string[]]$valid, [string]$owner) + Write-Warning "Unrecognized $key '$raw' on '$owner'. Valid values: $($valid -join ', '). Value ignored." +} + function Emit-Group { param($el, [string]$name, [int]$id, [string]$indent) @@ -3739,6 +3745,7 @@ function Emit-Group { default { $null } } if ($orientation) { X "$inner$orientation" } + elseif ($groupVal) { Warn-Unrecognized 'group orientation' $el.group @('vertical','horizontalIfPossible','alwaysHorizontal') $name } # Behavior: ключ behavior (usual/collapsible/popup) → ; отсутствие = Авто (не эмитим). # Legacy: group:'collapsible' эквивалентно behavior:'collapsible'. @@ -3746,6 +3753,8 @@ function Emit-Group { $bmap = @{ "usual"="Usual"; "collapsible"="Collapsible"; "popup"="PopUp" } if ($behaviorVal -and $bmap.ContainsKey($behaviorVal)) { X "$inner$($bmap[$behaviorVal])" + } elseif ($el.behavior -and -not $bmap.ContainsKey($behaviorVal)) { + Warn-Unrecognized 'behavior' $el.behavior @('collapsible','popup') $name } # Collapsed — у Collapsible и PopUp (не привязано к одному behavior) if ($el.collapsed -eq $true) { X "$innertrue" } @@ -3815,6 +3824,7 @@ function Emit-ColumnGroup { default { $null } } if ($orientation) { X "$inner$orientation" } + elseif ($groupVal) { Warn-Unrecognized 'columnGroup orientation' $el.columnGroup @('vertical','horizontal','inCell') $name } if ($null -ne $el.showTitle) { X "$inner$(if ($el.showTitle){'true'}else{'false'})" } # showInHeader эмитится общим Emit-CommonElementProps (через Emit-Layout) @@ -4698,6 +4708,7 @@ function Emit-Page { default { $null } } if ($orientation) { X "$inner$orientation" } + else { Warn-Unrecognized 'page group orientation' $el.group @('vertical','horizontalIfPossible','alwaysHorizontal') $name } } if ($null -ne $el.showTitle) { X "$inner$(if ($el.showTitle){'true'}else{'false'})" } # Формат значения пути к данным заголовка (; парный к titleDataPath страницы) diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index af439151..8b4ec95c 100644 --- a/.claude/skills/form-compile/scripts/form-compile.py +++ b/.claude/skills/form-compile/scripts/form-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# form-compile v1.171 — Compile 1C managed form from JSON or object metadata +# form-compile v1.172 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy @@ -3827,6 +3827,11 @@ def emit_element(lines, el, indent, in_cmd_bar=False): emitter(lines, el, name, eid, indent) +def _warn_unrecognized(key, raw, valid, owner): + # drop-on-miss enum: значение не распознано → тег не эмитится. Громко, чтобы автор увидел потерю. + print(f"[WARN] Unrecognized {key} '{raw}' on '{owner}'. Valid values: {', '.join(valid)}. Value ignored.") + + def emit_group(lines, el, name, eid, indent): lines.append(f'{indent}') inner = f'{indent}\t' @@ -3847,12 +3852,16 @@ def emit_group(lines, el, name, eid, indent): orientation = orientation_map.get(group_val) if orientation: lines.append(f'{inner}{orientation}') + elif group_val: + _warn_unrecognized('group orientation', el.get('group'), ('vertical', 'horizontalIfPossible', 'alwaysHorizontal'), name) # Behavior: ключ behavior (usual/collapsible/popup) → ; отсутствие = Авто (не эмитим). behavior_val = str(el['behavior']).lower() if el.get('behavior') else ('collapsible' if group_val == 'collapsible' else None) bmap = {'usual': 'Usual', 'collapsible': 'Collapsible', 'popup': 'PopUp'} if behavior_val and behavior_val in bmap: lines.append(f'{inner}{bmap[behavior_val]}') + elif el.get('behavior') and behavior_val not in bmap: + _warn_unrecognized('behavior', el.get('behavior'), ('collapsible', 'popup'), name) # Collapsed — у Collapsible и PopUp (не привязано к одному behavior) if el.get('collapsed') is True: lines.append(f'{inner}true') @@ -3914,15 +3923,17 @@ def emit_column_group(lines, el, name, eid, indent): emit_title(lines, el, name, inner) - group_val = str(el.get('columnGroup', '')) + group_val = str(el.get('columnGroup', '')).lower() orientation_map = { 'horizontal': 'Horizontal', 'vertical': 'Vertical', - 'inCell': 'InCell', + 'incell': 'InCell', } orientation = orientation_map.get(group_val) if orientation: lines.append(f'{inner}{orientation}') + elif group_val: + _warn_unrecognized('columnGroup orientation', el.get('columnGroup'), ('vertical', 'horizontal', 'inCell'), name) if el.get('showTitle') is not None: lines.append(f'{inner}{"true" if el["showTitle"] else "false"}') @@ -4428,13 +4439,15 @@ def emit_page(lines, el, name, eid, indent): orientation_map = { 'horizontal': 'Horizontal', 'vertical': 'Vertical', - 'alwaysHorizontal': 'AlwaysHorizontal', - 'alwaysVertical': 'AlwaysVertical', - 'horizontalIfPossible': 'HorizontalIfPossible', + 'alwayshorizontal': 'AlwaysHorizontal', + 'alwaysvertical': 'AlwaysVertical', + 'horizontalifpossible': 'HorizontalIfPossible', } - orientation = orientation_map.get(str(el['group'])) + orientation = orientation_map.get(str(el['group']).lower()) if orientation: lines.append(f'{inner}{orientation}') + else: + _warn_unrecognized('page group orientation', el['group'], ('vertical', 'horizontalIfPossible', 'alwaysHorizontal'), name) if el.get('showTitle') is not None: lines.append(f'{inner}{"true" if el["showTitle"] else "false"}') # Формат значения пути к данным заголовка (; парный к titleDataPath страницы)