- Tests: replace conditional `if response.status_code == 200` guards
with unconditional `assert response.status_code == 200` so failures
are not silently swallowed
- dotToNested: guard finalKey write with `if (i < parts.length)` to
prevent empty-string key pollution when tail-matching consumed all
parts
- Extract normalizeFormDataForConfig() helper from handlePluginConfigSubmit
and call it from both handlePluginConfigSubmit and syncFormToJson so
the JSON tab sync uses the same robust FormData processing (including
_data JSON inputs, bracket-notation checkboxes, array-of-objects,
file-upload widgets, checkbox DOM detection, and unchecked boolean
handling via collectBooleanFields)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ensure_array_defaults: replace None nodes with {} so recursion
proceeds into nested objects (was skipping when key existed as None)
- dotToNested: add tail-matching that checks the full remaining dotted
tail against the current schema level before greedy intermediate
matching, preventing leaf dotted keys from being split
- syncFormToJson: replace naive key.split('.') reconstruction with
dotToNested(flatConfig, schema) and schema-aware getSchemaProperty()
so the JSON tab save path produces the same correct nesting as the
form submit path
- Add regression tests for dotted-key array normalization and None
array default replacement
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The soccer plugin uses dotted keys like "eng.1" for league identifiers.
PR #260 fixed backend helpers but the JS frontend still corrupted these
keys by naively splitting on dots. This fixes both the JS and remaining
Python code paths:
- JS getSchemaProperty(): greedy longest-match for dotted property names
- JS dotToNested(): schema-aware key grouping to preserve "eng.1" as one key
- Python fix_array_structures(): remove broken prefix re-navigation in recursion
- Python ensure_array_defaults(): same prefix navigation fix
Closes#254
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>