5.8 KiB
E39 — WebWorker plugin
Cluster 39 of plans/hs-conformance-to-100.md. Goal: +1 test.
1. The 1 failing test
Suite hs-upstream-worker, test:
raises a helpful error when the worker plugin is not installed
Translated upstream (test/features/worker.js) — currently emitted as
SKIP (untranslated) in spec/tests/test-hyperscript-behavioral.sx path
(117 2 2):
(deftest "raises a helpful error when the worker plugin is not installed"
(error "SKIP (untranslated): raises a helpful ..."))
Upstream assertion:
const msg = await error("worker MyWorker def noop() end end")
expect(msg).toContain('worker plugin')
expect(msg).toContain('hyperscript.org/features/worker')
Two substring checks on the error produced by compiling the source.
2. Upstream worker syntax
From https://hyperscript.org/features/worker/:
worker <name>[(<external-script-url>*)]
(<def-feature> | <js-block>)+
end
- Declared at top level alongside
on,init,def,behavior. - Body restricted to
deffunctions andjs ... endblocks; no DOM /windowaccess. - Callers invoke as
WorkerName.fn(args)from the main thread; calls return promises but are async-transparent. - Stock
_hyperscriptships only a stub in the core bundle — the real implementation is in theworkerext. Without the ext loaded, parsing must fail with a message mentioning bothworker pluginandhyperscript.org/features/worker.
3. Proposed SX shape
We ship the stub only. Full runtime is out of scope for a 1-test cluster.
Parser addition (lib/hyperscript/parser.sx, parse-feat)
Extend the feature-dispatch cond (around line 2620) with one branch
before the fallthrough to parse-cmd-list:
((= val "worker") (parse-worker-stub))
parse-worker-stub raises immediately — it does not consume tokens,
does not need to recognise the body grammar. The error string contains
both required substrings:
"worker plugin is not installed — see https://hyperscript.org/features/worker"
(error ...) at parser scope is the existing failure channel (used by
Expected 'of' or 'from' at position … etc.), so this slots in without
changes to the error plumbing.
Compile output
None. The stub never returns an AST; the error propagates out of
hs-compile and through hs-to-sx-from-source, surfacing to the test
runner as a caught exception.
4. Runtime architecture
For the 1 test: no runtime. Parsing fails, so runtime.sx never sees
a worker form. No Worker class needed in the hs-run-filtered.js
mock. Nothing touches the DOM shim.
For a hypothetical full implementation (explicitly out of scope):
- Server would bind
WorkerNamein the HS top-level env to a record{:worker-handle H :exports (list ...)}. WorkerName.fn(args)would compile via the existing property-access path to(hs-method-call WorkerName "fn" args), which would detect the worker handle and dispatch over apostMessagechannel.- Mock env would need a
Workerclass constructor + a serialisable message loop driving the worker script's own tiny SX interpreter. Deferred until the 7 skipped upstream tests become a target cluster.
5. Test delta estimate
+1 test. Feasibility: high. Two substring checks. Implementation
is a single cond branch plus a 2-line error string. Generator patch
to un-skip the test is mechanical.
6. Risks
- Drift from future real plugin — if we later implement the plugin,
the stub must be replaced, not shadowed. Mitigation: the stub lives
inline in
parse-feat; adding the real plugin means deleting the stub branch and replacing it with(parse-worker-feat). Single site. - In-browser vs mock divergence — none in this cluster. The stub errors identically in both hosts because it's pure parser logic.
- Message serialisation — N/A until full plugin.
- Error-message phrasing drift — the upstream test only checks for
two substrings. We must keep
worker pluginandhyperscript.org/features/workerverbatim; change-detector tests should reference this design if the wording is ever touched. - Generator mis-translation — the upstream JS uses
await error(src)which the SX generator currently bails on (return None), producing theSKIP (untranslated). We can either (a) teach the generator to translateawait error(src)+ twotoContainchecks, or (b) hand- write the test. Recommend (b) for one test: less generator churn.
7. Implementation checklist (single commit)
sx_replace_by_patterninlib/hyperscript/parser.sx— insert the((= val "worker") ...)branch insideparse-feat'scond. Body:(error "worker plugin is not installed — see https://hyperscript.org/features/worker").sx_replace_nodeinspec/tests/test-hyperscript-behavioral.sxpath(117 2)— replace theSKIP (untranslated)body with:(deftest "raises a helpful error when the worker plugin is not installed" (let ((result (guard (e (true (if (string? e) e (str e)))) (hs-compile "worker MyWorker def noop() end end") ""))) (assert (contains? result "worker plugin")) (assert (contains? result "hyperscript.org/features/worker"))))sx_validateon both files.- Run
node tests/hs-run-filtered.jswithHS_SUITE=hs-upstream-worker. Expect 1/1. - Run full suite smoke (0–195) — expect no regressions (pure additive
branch in
parse-feat;"worker"was previously caught by the fallthroughparse-cmd-list, which would have errored anyway on an unknown identifier — confirm by checking baseline). - Commit:
HS: E39 WebWorker plugin stub (+1 test).
Non-goals
- Any worker runtime. Any real
Workerobject. Any message passing. - The 7 sibling
test.skip(...)cases upstream — they remain skipped. - Generator patches — the test is hand-written per §6 above.