feat(state): validation + friendly errors on both write and eval paths (item 11)
All checks were successful
Check / eval (push) Successful in 2m56s
All checks were successful
Check / eval (push) Successful in 2m56s
'Never has to master Nix' includes the error messages. The tool grows validate_state (appearance schema = hard errors; settings.* and unknown keys = warnings so menu writers and newer schemas keep working), a read-only `validate` subcommand, and validation BEFORE every write — an invalid set/apply is refused with the on-disk file untouched. JSON syntax errors now say line, column, and fix. theme.nix enforces the same schema at eval time (on the post-defaults state, so sparse/older files still evaluate) and throws a message naming each field, its got-value, and the fix paths — the hand-edit escape hatch no longer ends in a Nix stack trace. Doctor's JSON fix-text points at validate. V1: new checks.theme-sync-validate fixture corpus green (good state, trailing comma, bad hex, bad type, unknown key, refused set with byte-identical file); negative mkFlake eval of a broken scratch downstream shows the friendly throw; good-path template-home builds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
47
flake.nix
47
flake.nix
@@ -184,6 +184,53 @@
|
||||
touch $out
|
||||
'';
|
||||
|
||||
# The state-file friendly-errors contract (item 11): validate
|
||||
# reports broken fixtures by field with a fix, good state
|
||||
# passes, and an invalid `set` is refused BEFORE the write —
|
||||
# the on-disk file must be byte-identical after the attempt.
|
||||
theme-sync-validate = pkgs.runCommand "nomarchy-theme-sync-validate"
|
||||
{ nativeBuildInputs = [ pkgs.python3 pkgs.jq ]; }
|
||||
''
|
||||
set -eu
|
||||
tool=${./pkgs/nomarchy-theme-sync/nomarchy-theme-sync.py}
|
||||
export NOMARCHY_DEFAULT_THEMES=${./themes}
|
||||
|
||||
mkdir good && cp ${./templates/downstream/theme-state.json} good/theme-state.json
|
||||
chmod +w good/theme-state.json
|
||||
NOMARCHY_PATH=$PWD/good python3 "$tool" validate
|
||||
|
||||
mkdir syntax && printf '{ "slug": "x", }' > syntax/theme-state.json
|
||||
if NOMARCHY_PATH=$PWD/syntax python3 "$tool" validate 2>err; then
|
||||
echo "FAIL: syntax fixture accepted"; exit 1; fi
|
||||
grep -q "syntax error at line" err
|
||||
|
||||
mkdir badhex && jq '.colors.accent = "7aa2f7"' \
|
||||
good/theme-state.json > badhex/theme-state.json
|
||||
if NOMARCHY_PATH=$PWD/badhex python3 "$tool" validate 2>err; then
|
||||
echo "FAIL: bad hex accepted"; exit 1; fi
|
||||
grep -q "colors.accent" err && grep -q "fix:" err
|
||||
|
||||
mkdir badtype && jq '.ui.gapsOut = "12"' \
|
||||
good/theme-state.json > badtype/theme-state.json
|
||||
if NOMARCHY_PATH=$PWD/badtype python3 "$tool" validate 2>err; then
|
||||
echo "FAIL: bad type accepted"; exit 1; fi
|
||||
grep -q "ui.gapsOut" err
|
||||
|
||||
mkdir unknown && jq '.extraKey = 1' \
|
||||
good/theme-state.json > unknown/theme-state.json
|
||||
NOMARCHY_PATH=$PWD/unknown python3 "$tool" validate \
|
||||
| grep -q "unknown top-level key"
|
||||
|
||||
cp good/theme-state.json before.json
|
||||
if NOMARCHY_PATH=$PWD/good python3 "$tool" --quiet \
|
||||
set ui.gapsOut '"12"' --no-switch 2>err; then
|
||||
echo "FAIL: invalid set was written"; exit 1; fi
|
||||
grep -q "refusing to write" err
|
||||
cmp good/theme-state.json before.json
|
||||
|
||||
touch $out
|
||||
'';
|
||||
|
||||
# nomarchy-doctor's contract: an induced failed unit flips the
|
||||
# sheet to ✖/exit-1 and names the unit; with the failure
|
||||
# cleared it reports healthy/exit-0. Minimal node (just the
|
||||
|
||||
Reference in New Issue
Block a user