Hyperscript compiler/runtime:
- query target support in set/fire/put commands
- hs-set-prolog-hook! / hs-prolog-hook / hs-prolog in runtime
- runtime log-capture cleanup
Scripts: sx-loops-up/down, sx-hs-e-up/down, sx-primitives-down
Plans: datalog, elixir, elm, go, koka, minikanren, ocaml, hs-bucket-f,
designs (breakpoint, null-safety, step-limit, tell, cookies, eval,
plugin-system)
lib/prolog/hs-bridge.sx: initial hook-based bridge draft
lib/common-lisp/tests/runtime.sx: CL runtime tests
WASM: regenerate sx_browser.bc.js from updated hs sources
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.2 KiB
F5 — Cookie API (+5)
Suite: hs-upstream-expressions/cookies
Target: All 5 tests are SKIP (untranslated).
1. The 5 tests
From upstream test/expressions/cookies.js:
| Test | What it checks |
|---|---|
length is 0 when no cookies are set |
cookies.length == 0 with no cookies set |
basic set cookie values work |
set cookies.name to "value" then cookies.name == "value" |
update cookie values work |
set, then set again, value updates |
basic clear cookie values work |
set cookies.name to "value" then clear cookies.name, then cookies.name == undefined |
iterate cookies values work |
for name in cookies iterates cookie names |
2. HyperScript cookie syntax
cookies is a special global expression in HyperScript backed by document.cookie. The upstream implementation wraps document.cookie in a proxy:
cookies.name→ read cookie by name (returns string orundefined)set cookies.name to val→ write cookie (setsdocument.cookie = "name=val")clear cookies.name→ delete cookie (sets max-age=-1)cookies.length→ number of cookies setfor name in cookies→ iterate over cookie names
3. Test runner mock
All 5 tests are untranslated — no SX test bodies exist yet. The generator needs patterns for the cookie expressions, and hs-run-filtered.js needs a document.cookie mock.
Mock in tests/hs-run-filtered.js
Add a simple in-memory cookie store to the dom mock:
let _cookieStore = {};
Object.defineProperty(global.document, 'cookie', {
get() {
return Object.entries(_cookieStore)
.map(([k,v]) => `${k}=${v}`)
.join('; ');
},
set(str) {
const [pair, ...attrs] = str.split(';');
const [name, val] = pair.split('=').map(s => s.trim());
const maxAge = attrs.find(a => a.trim().startsWith('max-age='));
if (maxAge && parseInt(maxAge.split('=')[1]) < 0) {
delete _cookieStore[name];
} else {
_cookieStore[name] = val;
}
},
configurable: true
});
Add _cookieStore = {} reset to hs-cleanup! equivalent in the runner.
4. SX runtime additions in lib/hyperscript/runtime.sx
HS needs a cookies special expression that the compiler resolves. Two approaches:
Option A (simpler): Treat cookies as a built-in variable bound to a proxy dict at runtime. When property access cookies.name is evaluated, dispatch to cookie read/write helpers.
Option B (upstream-faithful): Parse cookies as a special primary expression, emit runtime calls hs-cookie-get, hs-cookie-set, hs-cookie-delete, hs-cookie-length, hs-cookie-names.
Option A is less invasive. The runtime env gets a cookies binding pointing to a special object; property access and assignment on it dispatch to the cookie helpers, which call (platform-cookie-get name) / (platform-cookie-set name val) / (platform-cookie-delete name).
Platform cookie operations map to document.cookie reads/writes in JS.
5. Generator patterns (tests/playwright/generate-sx-tests.py)
The upstream tests use patterns like:
await page.evaluate(() => { _hyperscript.evaluate("set cookies.foo to 'bar'") });
expect(await page.evaluate(() => _hyperscript.evaluate("cookies.foo"))).toBe("bar");
In our SX harness these become direct eval-hs calls. Since all 5 tests are untranslated, hand-write them rather than extending the generator (similar to E39).
6. Translated test bodies
(deftest "length is 0 when no cookies are set"
(hs-cleanup!)
(assert= (eval-hs "cookies.length") 0))
(deftest "basic set cookie values work"
(hs-cleanup!)
(eval-hs "set cookies.foo to 'bar'")
(assert= (eval-hs "cookies.foo") "bar"))
(deftest "update cookie values work"
(hs-cleanup!)
(eval-hs "set cookies.foo to 'bar'")
(eval-hs "set cookies.foo to 'baz'")
(assert= (eval-hs "cookies.foo") "baz"))
(deftest "basic clear cookie values work"
(hs-cleanup!)
(eval-hs "set cookies.foo to 'bar'")
(eval-hs "clear cookies.foo")
(assert= (eval-hs "cookies.foo") nil))
(deftest "iterate cookies values work"
(hs-cleanup!)
(eval-hs "set cookies.a to '1'")
(eval-hs "set cookies.b to '2'")
(let ((names (eval-hs "for name in cookies collect name")))
(assert (contains? names "a"))
(assert (contains? names "b"))))
7. Implementation checklist
- Add cookie mock to
tests/hs-run-filtered.js. Wire reset into test cleanup. - Add
hs-cookie-get,hs-cookie-set,hs-cookie-delete,hs-cookie-length,hs-cookie-namestolib/hyperscript/runtime.sx. - Add
cookiesas a special expression in the HS parser/evaluator that dispatches to the above. - Replace 5
SKIPbodies inspec/tests/test-hyperscript-behavioral.sxwith translated test bodies above. - Run
hs_test_run suite="hs-upstream-expressions/cookies"— expect 5/5. - Run smoke 0–195 — no regressions.
- Commit:
HS: cookie API — document.cookie proxy + 5 tests
8. Risk
Medium. The mock is simple. The main risk is the cookies expression integration in the parser — it needs to hook into property-access and assignment paths that are already well-exercised. Keep the implementation thin: cookies is a runtime value with a special type, not a new parse form.