djust 0.9.7rc1

Pre-releaseReleased

This is a pre-release. djust 0.9.7 has shipped since: read the djust 0.9.7 release notes.

Changed

  • Bundle init-order lint now does a deferral-pattern-aware depth-N call-graph walk (#1449, #1406).scripts/check-bundle-init-order.mjs previously caught only direct top-level reads of late-declared let/const. The walker now descends through synchronously-called function bodies (default depth 8) to catch the transitive TDZ class that PR #1370 hit — djustInit() → mountHooks() → _ensureHooksInit() → _activeHooks (read at top level via a transitive call chain, declared later in lexicographic concat order). Models deferral sites (addEventListener/removeEventListener, setTimeout/setInterval/setImmediate, requestAnimationFrame/queueMicrotask/requestIdleCallback, Promise .then/.catch/.finally, new XxxObserver(...)) so callbacks passed to those APIs are correctly treated as non-top-level. The walker uses an "effective-line" model: identifiers reached transitively through a top-level call at bundle line L are flagged only if decl.bundleLine > L, which eliminates the 16 false positives the naive depth-N version produced (per #1449). New CLI flags: --max-depth=N (default 8), --shallow-only (preserves v0.9.5 behavior). New env-var override BUNDLE_SRC_DIR for synthetic-bundle tests. The runtime regression test tests/js/bundle-init-no-tdz.test.js remains the simulate-bundle-init safety net — the two checks are complementary. Current main bundle is clean at default depth.

Tests

  • Wire-protocol snapshots: 12 final frames pinned (#1456 Batch 3 — closes #1456).noop (with optional appends), rate_limit_exceeded, pong, error.message variant (wire-distinct from error.error), navigate, upload_registered, upload_progress, reload, hvr-applied (kebab-case type — the only one in the protocol), presence_event (presence.py), streaming.patch, streaming.html_update, streaming.stream. 14 new tests, 39 total. Across the 4 PRs (#1457 starter + #1461 Batch 1 + #1462 Batch 2 + this), the entire send_json wire surface is now pinned.

  • Wire-protocol snapshots: 5 optional-feature frames pinned (#1456 Batch 2, follow-up to Batch 1 PR #1461).i18n, accessibility, focus, html_update (minimal + with reset_form/event_name conditional appends), connect. 6 new tests, 25 total in python/djust/tests/test_wire_protocol_snapshots.py. Closes Batch 2 of 3 in #1456; remaining ~12 shapes tracked there for Batch 3 (uploads, reload variants, control plane, presence, streaming).

  • Wire-protocol snapshots: 5 lifecycle frames pinned (#1456 Batch 1, follow-up to PR #1457). Extends python/djust/tests/test_wire_protocol_snapshots.py with mount_batch (envelope + optional navigate append), child_update, sticky_update, sticky_hold (with views + empty-list drop-all signal), and embedded_update. 7 new tests, 19 total. Closes Batch 1 of 3 in #1456; remaining ~17 shapes tracked there for Batches 2-3.

  • Wire-protocol JSON snapshot pinning for 8 highest-value Python-emitted frame shapes (#1448 starter, follow-up to PR #1444). Generalizes PR #1444's Rust-side Patch/VNode snapshot pinning to the Python send_json emit sites. python/djust/tests/test_wire_protocol_snapshots.py pins push_event, flash, page_metadata, patch (envelope), mount (with + without public_state), layout, navigation (inner-type-to-action promotion), and error against literal JSON strings. A field rename or default-value change at any of the 8 emit sites silently breaks deployed clients running older bundles — these snapshot tests catch it at test time. Key-order pinning is deliberate: mount.public_state and patch.html are appended after the initial dict literal, and Python 3.7+ preserves dict insertion order, so the JSON order is deterministic. The actual wire surface is ~30+ shapes; follow-up #1456 tracks the remaining ~22 in 2-3 grouped batches.

  • VDOM cluster carryovers — 24 new tests across 5 files (#1413, #1416, #1417, #1418, #1420). Five P3 hardeners extending crates/djust_vdom/tests/common/mod.rs (the harness from #1421). Test-only; no production code changes; none surfaced regressions on main. Test count: djust_vdom 248 → 272.

    • #1413proptest_round_trip_with_sync.rs: randomized counterpart to #1412's hand-crafted scenarios. 1 proptest fn × 64 cases × 5-20 steps of dj-if boundary toggles + inner mutations, asserts assert_handles_resolve invariant on every cycle.
    • #1416torture_html_round_trip.rs: 8 scenarios exercising the live VDOM → to_html → parse_html round-trip (plain/nested elements, text, dj-if single + nested, dj-key keyed children, dj-update="ignore" subtrees, mixed attrs incl. data-/aria-/role/href entities, text-with-entities).
    • #1417test_dj_update_ignore_dj_if_sync_ids_1417.rs: 3 scenarios for the dj-update="ignore" × dj-if × sync_ids three-way interaction. Verifies sync_ids preserves the ignored subtree's dj-ids across boundary swap-out → swap-in cycles.
    • #1418torture_deep_cascade_dj_if_1418.rs: 4 scenarios with 10/12/15 levels of nested dj-if boundaries at start/middle/end positions of the children list. Toggles deepest boundary across cycles.
    • #1420torture_patch_batch_ordering_1420.rs: 7 invariant scenarios + 1 snapshot. The canonical "SetAttr on kept child + RemoveChild on removed sibling" snapshot asserts RemoveChild comes at-or-after SetAttr in the batch (so any future emitter regression that reordered Remove ahead of Set would trip the test).

All releases · Atom feed