Files
rose-ash/spec/tests/hyperscript-feature-audit.md
giles 7492ceac4e Restore hyperscript work on stable site base (908f4f80)
Reset to last known-good state (908f4f80) where links, stepper, and
islands all work, then recovered all hyperscript implementation,
conformance tests, behavioral tests, Playwright specs, site sandbox,
IO-aware server loading, and upstream test suite from f271c88a.

Excludes runtime changes (VM resolve hook, VmSuspended browser handler,
sx_ref.ml guard recovery) that need careful re-integration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 19:29:56 +00:00

454 lines
25 KiB
Markdown

# _hyperscript Feature Audit
Comprehensive audit of our SX _hyperscript implementation vs the upstream reference.
**Implementation files:**
- `lib/hyperscript/tokenizer.sx` — lexer (129 keywords, 17 token types)
- `lib/hyperscript/parser.sx` — parser (67 internal functions, ~3450 lines)
- `lib/hyperscript/compiler.sx` — compiler (AST to SX, ~100 dispatch cases)
- `lib/hyperscript/runtime.sx` — runtime shims (49 functions)
**Test files:**
- `spec/tests/test-hyperscript-behavioral.sx` — 381 conformance tests (from upstream)
- `spec/tests/test-hyperscript-conformance.sx` — 184 additional conformance tests
- `spec/tests/test-hyperscript-tokenizer.sx` — 43 tokenizer tests
- `spec/tests/test-hyperscript-parser.sx` — 93 parser tests
- `spec/tests/test-hyperscript-compiler.sx` — 44 compiler tests
- `spec/tests/test-hyperscript-runtime.sx` — 26 runtime tests
- `spec/tests/test-hyperscript-integration.sx` — 12 integration tests
**Upstream reference:** `spec/tests/hyperscript-upstream-tests.json` — 831 tests from upstream master+dev
---
## Upstream Test Breakdown
| Complexity | Count | Description |
|-----------|-------|-------------|
| simple | 469 | DOM-based tests, simplest to translate |
| run-eval | 83 | Eval-only tests (no DOM setup) |
| evaluate | 125 | Full browser eval with DOM interaction |
| promise | 57 | Async/promise-based tests |
| eval-only | 39 | Pure expression evaluation |
| script-tag | 36 | Tests using `<script type="text/hyperscript">` |
| sinon | 17 | Tests requiring sinon mock (fetch) |
| dialog | 5 | Dialog-specific tests |
Of the 469 simple tests, **454 are "clean"** (no `[@`, `${`, `{css}`, or `<sel/>` patterns that our tokenizer doesn't handle).
Our **381 behavioral tests** were generated from the simple upstream tests and represent features that parse + compile + execute correctly in our sandbox environment.
---
## Feature-by-Feature Audit
### Legend
- **IMPL+TEST** = Implemented in all four layers (tokenizer/parser/compiler/runtime) AND tested
- **PARTIAL** = Compiles but not all sub-features work, or only basic forms tested
- **NOT IMPL** = Parser/compiler doesn't handle it at all
- **IMPL-UNTESTED** = Code exists in implementation but no test coverage
---
## COMMANDS
### Core assignment/mutation
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `set ... to ...` | IMPL+TEST | 24+ | Properties, locals, globals, attrs, styles, indirect. `parse-set-cmd` + `emit-set` |
| `put ... into/before/after ...` | IMPL+TEST | 37+ | Full positional insertion. `parse-put-cmd` + `emit-set`/`hs-put!` |
| `get` | IMPL+TEST | 5 | Parsed as expression (property access); call-cmd dispatch also handles `get` |
| `increment` | IMPL+TEST | 20 | Variables, attributes, properties, arrays, possessives, style refs. `parse-inc-cmd` + `emit-inc` |
| `decrement` | IMPL+TEST | 20 | Mirror of increment. `parse-dec-cmd` + `emit-dec` |
| `append ... to ...` | IMPL+TEST | 13 | `parse-append-cmd` -> `dom-append` |
| `default` | IMPL+TEST | 9 | Array elements, style refs, preserves zero/false. (Tested in behavioral) |
| `empty`/`clear` | IMPL+TEST | 12 | Elements, inputs, textareas, checkboxes, forms. (Tested in behavioral) |
| `swap` | IMPL+TEST | 4 | Variable/property/array swaps. (Tested in behavioral) |
### Class manipulation
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `add .class` | IMPL+TEST | 14+ | Single, multiple, double-dash, colons. `parse-add-cmd` -> `dom-add-class` |
| `add .class to <target>` | IMPL+TEST | 14+ | Target resolution for classes |
| `add [@attr="val"]` | NOT IMPL | 0 | Tokenizer doesn't emit `[@` as attribute-set token. 4 upstream tests skipped |
| `add {css-props}` | NOT IMPL | 0 | CSS property block syntax not tokenized. 2 upstream tests skipped |
| `remove .class` | IMPL+TEST | 10+ | `parse-remove-cmd` -> `dom-remove-class` |
| `remove` (elements) | IMPL+TEST | 5 | Remove self, other, parent elements |
| `remove [@attr]` | NOT IMPL | 0 | Same tokenizer limitation as `add [@]` |
| `remove {css}` | NOT IMPL | 0 | CSS block removal not implemented |
| `toggle .class` | IMPL+TEST | 28+ | Single, multiple, timed, between two classes. `parse-toggle-cmd` -> `hs-toggle-class!`/`hs-toggle-between!` |
| `toggle .class for <duration>` | IMPL+TEST | 1 | Timed toggle |
| `toggle .class until <event>` | IMPL+TEST | 1 | Event-gated toggle |
| `toggle between .a and .b` | IMPL+TEST | 1 | `hs-toggle-between!` runtime function |
| `toggle [@attr]` | NOT IMPL | 0 | Attribute toggle not implemented |
| `toggle {css}` | NOT IMPL | 0 | CSS block toggle not implemented |
| `take .class` | IMPL+TEST | 12 | From siblings, for others, multiple classes. `parse-take-cmd` -> `hs-take!` |
| `take [@attr]` | IMPL+TEST | 10 | Attribute take from siblings. (Tested in behavioral) |
### Control flow
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `if ... then ... end` | IMPL+TEST | 18+ | With else, else if, otherwise, triple nesting. `parse-if-cmd` |
| `if ... else ...` | IMPL+TEST | 18+ | Naked else, else end, multiple commands |
| `repeat ... times ... end` | IMPL+TEST | 23+ | Fixed count, expression count, forever, while, for-in. `parse-repeat-cmd` + `hs-repeat-times`/`hs-repeat-forever` |
| `repeat forever` | IMPL+TEST | 1+ | `hs-repeat-forever` |
| `repeat while` | IMPL+TEST | 1+ | While condition in repeat mode |
| `repeat for x in collection` | IMPL+TEST | 5+ | For-in loop mode |
| `for x in collection ... end` | IMPL+TEST | 5+ | `parse-for-cmd` + `emit-for` -> `for-each` |
| `for x in ... index i` | IMPL+TEST | 2 | Index variable support |
| `return` | IMPL+TEST | varies | `parse-return-cmd`, bare and with expression |
| `throw` | IMPL+TEST | varies | `parse-throw-cmd` -> `raise` |
| `catch` | IMPL+TEST | 14 | Exception handling in on blocks. (Tested in behavioral) |
| `finally` | IMPL+TEST | 6 | Finally blocks. (Tested in behavioral) |
| `break` | PARTIAL | 0 | Keyword recognized by tokenizer, but no dedicated parser/compiler path |
| `continue` | PARTIAL | 0 | Keyword recognized by tokenizer, but no dedicated parser/compiler path |
| `unless` | PARTIAL | 0 | Keyword recognized but no dedicated parser path (falls through) |
### Async/timing
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `wait <duration>` | IMPL+TEST | 7 | Duration parsing (ms, s). `parse-wait-cmd` -> `hs-wait` using `perform` |
| `wait for <event>` | IMPL+TEST | 7 | Wait for DOM event. `hs-wait-for` using `perform` |
| `wait for <event> from <source>` | IMPL+TEST | 1 | Source-specific event wait |
| `wait for <event> or <timeout>` | IMPL+TEST | 2 | Timeout variant |
| `settle` | IMPL+TEST | 1 | `hs-settle` using `perform`. Compiler emits `(hs-settle me)` |
| Async transparency | IMPL+TEST | varies | `perform`/IO suspension provides true pause semantics |
### Events/messaging
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `send <event>` | IMPL+TEST | 8 | `parse-send-cmd` -> `dom-dispatch`. Dots, colons, args |
| `send <event> to <target>` | IMPL+TEST | 8 | With detail dict, target expression |
| `trigger <event>` | IMPL+TEST | varies | `parse-trigger-cmd` -> `dom-dispatch` |
### Navigation/display
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `go to <url>` | IMPL+TEST | 3 | `parse-go-cmd` -> `hs-navigate!` |
| `hide` | IMPL+TEST | 14 | Multiple strategies (display:none, opacity:0, visibility:hidden). Custom strategies. (Tested in behavioral) |
| `show` | IMPL+TEST | 2 | `parse-show-cmd`. (Tested in behavioral) |
| `transition ... to ... over ...` | IMPL+TEST | 22 | Properties, custom duration, other elements, style refs. `parse-transition-cmd` + `hs-transition` |
| `log` | IMPL+TEST | 4 | `parse-log-cmd` -> `console-log` |
| `halt` | IMPL+TEST | 6 | Event propagation/default prevention. (Tested in behavioral) |
| `halt the event` | IMPL+TEST | 2 | Stops propagation, continues execution |
| `halt bubbling` | IMPL+TEST | 1 | Only stops propagation |
| `halt default` | IMPL+TEST | 1 | Only prevents default |
### Function/behavior
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `call fn(args)` | IMPL+TEST | 5 | `parse-call-cmd`, global and instance functions |
| `call obj.method(args)` | IMPL+TEST | varies | Method call dispatch via `hs-method-call` |
| `def fn(params) ... end` | IMPL+TEST | 3 | `parse-def-feat` -> `define` |
| `behavior Name(params) ... end` | IMPL+TEST | varies | `parse-behavior-feat` + `emit-behavior` |
| `install BehaviorName` | IMPL+TEST | 2 | `parse-install-cmd` -> `hs-install` |
| `make a <Type>` | IMPL+TEST | varies | `parse-make-cmd` + `emit-make` -> `hs-make`. Called keyword support |
| `render <component>` | IMPL+TEST | varies | `parse-render-cmd` with kwargs, position, target. Bridges to SX component system |
### DOM/IO
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `fetch <url>` | IMPL+TEST | 6 | `parse-fetch-cmd` -> `hs-fetch`. JSON/text/HTML formats. URL keyword deprecated but parsed |
| `fetch ... as json/text/html` | IMPL+TEST | 6 | Format dispatch in runtime |
| `measure` | IMPL+TEST | varies | `parse-measure-cmd` -> `hs-measure` using `perform` |
| `focus` | NOT IMPL | 0 | No parser, 3 upstream tests (all evaluate complexity) |
| `scroll` | NOT IMPL | 0 | No parser, 8 upstream tests (all evaluate complexity) |
| `select` | NOT IMPL | 0 | No parser, 4 upstream tests (all evaluate complexity) |
| `reset` | IMPL+TEST | 8 | Forms, inputs, checkboxes, textareas, selects. (Tested in behavioral) |
| `morph` | IMPL+TEST | 4 | (Tested in behavioral, simple complexity) |
| `dialog` (show/open/close) | IMPL+TEST | 5 | Modal dialogs, details elements. (Tested in behavioral) |
### Other commands
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `tell <target> ... end` | IMPL+TEST | 10 | `parse-tell-cmd`. Scoping (you/your/yourself), attribute access, me restoration. (Tested in behavioral) |
| `js ... end` | PARTIAL | 1 | Keyword recognized, `parse-atom` handles `eval` keyword -> `sx-eval`, but inline JS blocks not fully supported |
| `pick` | NOT IMPL | 0 | 7 upstream tests (all eval-only complexity). No parser path |
| `beep!` | IMPL+TEST | 1 | Debug passthrough. `parse-atom` recognizes `beep!`, runtime `hs-beep` is identity |
---
## FEATURES (Event handlers / lifecycle)
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `on <event> ... end` | IMPL+TEST | 59+ | `parse-on-feat` + `emit-on` -> `hs-on`. Dots, colons, dashes in names |
| `on <event> from <source>` | IMPL+TEST | 5+ | Source-specific listeners |
| `every <event>` | IMPL+TEST | 1+ | `hs-on-every` — no queuing |
| `on ... [<filter>]` | IMPL+TEST | 3+ | Event filtering in on blocks |
| Event destructuring | IMPL+TEST | 1+ | `can pick detail/event properties` |
| `on <event> count N` / range | IMPL+TEST | 4 | Count filter, range filter, unbounded range |
| `on mutation` | IMPL+TEST | 10 | Attribute, childList, characterData mutations. Cross-element. (Tested in behavioral) |
| `on first <event>` | IMPL+TEST | 1 | One-shot handler |
| `on load` | IMPL+TEST | 1 | Load pseudo-event |
| Queue modes (queue, first, last, all, none) | IMPL+TEST | 5 | Event queuing strategies |
| `init ... end` | IMPL+TEST | 1+ | `parse-init-feat` -> `hs-init` |
| `def name(params) ... end` | IMPL+TEST | 3+ | Feature-level function definitions |
| `behavior Name(params) ... end` | IMPL+TEST | varies | Feature-level behavior definition |
| `on <event> debounce <dur>` | NOT IMPL | 0 | Debounce modifier not parsed |
| `on <event> throttle <dur>` | NOT IMPL | 0 | Throttle modifier not parsed |
| `connect` | NOT IMPL | 0 | No parser path |
| `disconnect` | NOT IMPL | 0 | No parser path |
| `worker` | NOT IMPL | 0 | No parser path |
| `socket` | NOT IMPL | 0 | 4 upstream tests (all eval-only). No parser path |
| `bind` | PARTIAL | 1 | Keyword in tokenizer. 44 upstream tests (mostly promise/evaluate). 1 simple test in behavioral. Parser doesn't have dedicated bind command |
| `when` (reactive) | IMPL+TEST | 5 | Reactive `when` handler. (Tested in behavioral) |
| `live` | NOT IMPL | 0 | 23 upstream tests (evaluate/promise). No parser path |
| `resize` | NOT IMPL | 0 | 3 upstream tests (evaluate). No parser path |
| `intersect` | NOT IMPL | 0 | No upstream tests. No parser path |
| `every N seconds` (polling) | NOT IMPL | 0 | Time-based polling pseudo-feature not parsed |
---
## EXPRESSIONS
### Literals & references
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| Number literals | IMPL+TEST | Yes | Integer and float |
| String literals | IMPL+TEST | Yes | Single and double quoted |
| Boolean literals (`true`/`false`) | IMPL+TEST | Yes | |
| `null`/`undefined` | IMPL+TEST | Yes | Both produce `(null-literal)` |
| `me`/`I`/`my` | IMPL+TEST | Yes | Self-reference. `my` triggers possessive tail |
| `it`/`its` | IMPL+TEST | Yes | Result reference. `its` triggers possessive tail |
| `event` | IMPL+TEST | Yes | Event object reference |
| `target` | IMPL+TEST | Yes | `event.target` |
| `detail` | IMPL+TEST | Yes | `event.detail` |
| `sender` | IMPL+TEST | Yes | Event sender reference |
| `result` | IMPL+TEST | Yes | Implicit result |
| `the` | IMPL+TEST | Yes | Article prefix, triggers `parse-the-expr` |
| `you`/`your`/`yourself` | IMPL+TEST | Yes | Tell-scoping references |
| Local variables (`:name`) | IMPL+TEST | Yes | Tokenizer emits `local` type |
| Template literals | IMPL+TEST | Yes | `${expr}` and `$ident` interpolation. Compiler handles nested parsing |
| Array literals `[a, b, c]` | IMPL+TEST | Yes | `parse-array-lit` |
| Object literals `{key: val}` | IMPL+TEST | Yes | `parse-atom` -> `object-literal` |
| Block literals `\ param -> expr` | IMPL+TEST | Yes | Lambda syntax in parse-atom |
### Property access
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| Dot notation (`obj.prop`) | IMPL+TEST | Yes | `parse-prop-chain`. Chained access |
| Method calls (`obj.method(args)`) | IMPL+TEST | Yes | `parse-prop-chain` + `method-call` AST node |
| Bracket access (`arr[i]`) | IMPL+TEST | Yes | `parse-poss` handles `bracket-open` -> `array-index` |
| Array slicing (`arr[i..j]`) | IMPL+TEST | Yes | `array-slice` AST node -> `hs-slice` |
| Possessive (`obj's prop`) | IMPL+TEST | Yes | `parse-poss` + `parse-poss-tail` |
| `of` syntax (`prop of obj`) | IMPL+TEST | Yes | In `parse-cmp` -> `(of ...)` AST |
| Attribute ref (`@attr`) | IMPL+TEST | Yes | Tokenizer emits `attr` type. Compiler -> `dom-get-attr`/`dom-set-attr` |
| Style ref (`*prop`) | IMPL+TEST | Yes | Tokenizer emits `style` type. Compiler -> `dom-get-style`/`dom-set-style` |
| Class ref (`.class`) | IMPL+TEST | Yes | Tokenizer emits `class` type |
| ID ref (`#id`) | IMPL+TEST | Yes | Tokenizer emits `id` type -> `(query "#id")` |
| Selector ref (`<sel/>`) | IMPL+TEST | Yes | Tokenizer emits `selector` type -> `(query sel)`. 8 upstream simple tests use this |
| `[@attr="val"]` set syntax | NOT IMPL | 0 | Tokenizer doesn't handle `[@` — attribute SET inside `add`/`remove`/`toggle` |
### Comparison operators
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `is` / `is not` | IMPL+TEST | Yes | `parse-cmp`. Equality and negation |
| `is equal to` / `is not equal to` | IMPL+TEST | Yes | Strict equality |
| `is really` / `is not really` | IMPL+TEST | Yes | `type-check-strict` / strict type check |
| `is a/an <Type>` | IMPL+TEST | Yes | Type checking with `a`/`an` article |
| `is not a/an <Type>` | IMPL+TEST | Yes | Negated type check |
| `is empty` / `is not empty` | IMPL+TEST | Yes | `hs-empty?` runtime |
| `exists` / `does not exist` | IMPL+TEST | Yes | `exists?` AST node |
| `matches` / `does not match` | IMPL+TEST | Yes | `hs-matches?` runtime |
| `contains` / `does not contain` | IMPL+TEST | Yes | `hs-contains?` runtime |
| `includes` / `does not include` | IMPL+TEST | Yes | Aliases for contains |
| `<`, `>`, `<=`, `>=` | IMPL+TEST | Yes | Standard operators in `parse-cmp` and `parse-arith` |
| `less than` / `greater than` | IMPL+TEST | Yes | English word forms |
| `less than or equal to` | IMPL+TEST | Yes | Full English form |
| `greater than or equal to` | IMPL+TEST | Yes | Full English form |
| `==`, `!=` | IMPL+TEST | Yes | Op tokens in `parse-cmp` |
| `===`, `!==` | IMPL+TEST | Yes | Strict equality ops -> `strict-eq` |
| `between` | PARTIAL | 0 | Keyword recognized in tokenizer but no dedicated parser path in `parse-cmp` |
| `starts with` / `ends with` | NOT IMPL | 0 | No parser path |
| `precedes` / `follows` | NOT IMPL | 0 | No parser path |
| `is <prop>` (property truthiness) | IMPL+TEST | Yes | `prop-is` AST -> `hs-prop-is` |
### Logical operators
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `and` | IMPL+TEST | Yes | `parse-logical` |
| `or` | IMPL+TEST | Yes | `parse-logical` |
| `not` | IMPL+TEST | Yes | `parse-atom` prefix |
| `no` | IMPL+TEST | Yes | `parse-atom` prefix -> `(no expr)` -> `hs-falsy?` |
### Math operators
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `+`, `-`, `*`, `/` | IMPL+TEST | Yes | `parse-arith` |
| `%` (modulo) | IMPL+TEST | Yes | `parse-arith` handles `%` and `mod` keyword -> `modulo` |
| `mod` | IMPL+TEST | Yes | Keyword alias for `%` |
| Unary `-` | IMPL+TEST | Yes | In `parse-atom` |
| CSS unit postfix (`10px`, `50%`) | IMPL+TEST | Yes | `string-postfix` AST node |
### String operations
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `split by` | IMPL+TEST | Yes | `parse-collection` -> `coll-split` -> `hs-split-by` |
| `joined by` | IMPL+TEST | Yes | `parse-collection` -> `coll-joined` -> `hs-joined-by` |
### Type coercion
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `as String` | IMPL+TEST | Yes | `parse-cmp` handles `as` keyword -> `hs-coerce` |
| `as Int` / `as Float` | IMPL+TEST | Yes | Numeric coercion |
| `as Array` | IMPL+TEST | Yes | Collection coercion |
| `as Object` | IMPL+TEST | Yes | Object coercion |
| `as JSON` | IMPL+TEST | Yes | JSON serialization/parse |
| `as HTML` / `as Fragment` | IMPL+TEST | Yes | HTML/DOM coercion |
| `as Date` | IMPL+TEST | Yes | Date coercion |
| `as Number` | IMPL+TEST | Yes | Number coercion |
| `as Values` | IMPL+TEST | Yes | Form values coercion |
| Custom type coercion (`:param`) | IMPL+TEST | Yes | `as Type:param` syntax parsed |
| `as response` | IMPL+TEST | 1 | (Tested in behavioral fetch tests) |
### Positional / traversal expressions
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `first` | IMPL+TEST | Yes | `parse-pos-kw` -> `hs-query-first` / `hs-first` |
| `last` | IMPL+TEST | Yes | `parse-pos-kw` -> `hs-query-last` / `hs-last` |
| `first ... in ...` | IMPL+TEST | Yes | Scoped first |
| `last ... in ...` | IMPL+TEST | Yes | Scoped last |
| `next` | IMPL+TEST | Yes | `parse-trav` -> `hs-next`. Class, ID, wildcard selectors |
| `previous` | IMPL+TEST | Yes | `parse-trav` -> `hs-previous` |
| `closest` | IMPL+TEST | Yes | `parse-trav` -> `dom-closest`. (Tested in behavioral) |
| `random` | PARTIAL | 0 | Keyword recognized but no dedicated parser/compiler path |
### Collection expressions
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `where <condition>` | IMPL+TEST | Yes | `parse-collection` -> `coll-where` -> `filter` with `it` binding |
| `sorted by <key>` | IMPL+TEST | Yes | `parse-collection` -> `coll-sorted` -> `hs-sorted-by` |
| `sorted by <key> descending` | IMPL+TEST | Yes | `coll-sorted-desc` -> `hs-sorted-by-desc` |
| `mapped to <expr>` | IMPL+TEST | Yes | `parse-collection` -> `coll-mapped` -> `map` |
| `split by <sep>` | IMPL+TEST | Yes | In `parse-collection` |
| `joined by <sep>` | IMPL+TEST | Yes | In `parse-collection` |
| `some x in coll with <pred>` | IMPL+TEST | Yes | Quantifier in `parse-atom` -> `(some ...)` |
| `every x in coll with <pred>` | IMPL+TEST | Yes | Quantifier in `parse-atom` -> `(every ...)` |
| `filter` (standalone) | NOT IMPL | 0 | No standalone filter command |
| `reduce` | NOT IMPL | 0 | No reduce in collection expressions |
| `in` (membership) | IMPL+TEST | Yes | `is in` / `is not in` in `parse-cmp` -> `in?` / `not-in?` |
### Special forms
| Feature | Status | Tests | Notes |
|---------|--------|-------|-------|
| `eval` / SX interop | IMPL+TEST | Yes | `parse-atom` handles `eval` -> `(sx-eval ...)`. Inline SX from parens or expression |
| Component refs (`~name`) | IMPL+TEST | Yes | Tokenizer emits `component` type. Compiler resolves to SX component call |
| `new` keyword | PARTIAL | 0 | Keyword recognized but no dedicated constructor path |
---
## FEATURES NOT IMPLEMENTED (by upstream category)
These upstream test categories have **zero** coverage in our implementation:
| Category | Upstream Tests | Complexity | Why Missing |
|----------|---------------|------------|-------------|
| `askAnswer` | 5 | dialog | `ask`/`answer` dialog commands not parsed |
| `asExpression` | 17 | eval-only/run-eval | `as` expression standalone evaluation — partially covered by `as` in comparisons |
| `asyncError` | 2 | evaluate/promise | Async error propagation edge cases |
| `attributeRef` | 1 | evaluate | `@attr` as standalone assignable |
| `cookies` | 1 | eval-only | Cookie access not implemented |
| `evalStatically` | 8 | eval-only | Static evaluation optimization |
| `focus` | 3 | evaluate | `focus` command not implemented |
| `in` | 1 | run-eval | Standalone `in` expression |
| `live` | 23 | evaluate/promise | `live` event sources not implemented |
| `logicalOperator` | 3 | eval-only | Standalone logical operator eval (covered by inline use) |
| `mathOperator` | 5 | run-eval | Standalone math eval (covered by inline use) |
| `measure` | 2 | evaluate | `measure` runtime needs real DOM |
| `objectLiteral` | 1 | run-eval | Standalone object literal eval (implemented, just no dedicated run-eval test) |
| `pick` | 7 | eval-only | `pick` command not parsed |
| `queryRef` | 1 | evaluate | `<sel/>` standalone (implemented but test requires DOM) |
| `reactive-properties` | 4 | evaluate/promise/run-eval | Reactive property observation |
| `relativePositionalExpression` | 4 | eval-only/evaluate | Relative position expressions (next/previous as standalone) |
| `resize` | 3 | evaluate | `resize` pseudo-event not implemented |
| `scroll` | 8 | evaluate | `scroll` command not implemented |
| `select` | 4 | evaluate | `select` command not implemented |
| `settle` | 1 | simple | `settle` command exists but upstream test is DOM-dependent |
| `socket` | 4 | eval-only | WebSocket feature not implemented |
| `splitJoin` | 7 | run-eval | Split/join standalone eval (implemented, tests are run-eval complexity) |
---
## DOM-SCOPE (^var) — Extended feature
Our implementation includes the full dom-scope (`^var`) feature:
| Feature | Status | Tests |
|---------|--------|-------|
| `^var` read from ancestor | IMPL+TEST | 23 |
| `^var` write propagates to ancestor | IMPL+TEST | 23 |
| `isolated` stops resolution | IMPL+TEST | 1 |
| `closest` ancestor wins (shadowing) | IMPL+TEST | 1 |
| `when` reacts to `^var` changes | IMPL+TEST | 2 |
| `bind` with `^var` | IMPL+TEST | 1 |
---
## COMPONENT feature (web components)
| Feature | Status | Tests |
|---------|--------|-------|
| `<template>` component registration | IMPL+TEST | 14 |
| `#if` conditionals in templates | IMPL+TEST | 2 |
| Named and default slots | IMPL+TEST | 2 |
| Component `^var` isolation | IMPL+TEST | 1 |
| Multiple independent instances | IMPL+TEST | 1 |
---
## Summary Statistics
| Category | Count |
|----------|-------|
| Features fully implemented + tested | ~55 |
| Features partially implemented | ~8 |
| Features not implemented | ~18 |
| Total upstream tests | 831 |
| Tests translated to SX (behavioral) | 381 (46%) |
| Additional SX conformance tests | 184 |
| Tests skippable (non-simple complexity) | 362 (44%) |
| Simple tests blocked by HTML patterns | 15 (2%) |
| Clean simple tests available | 454 |
| Gap: clean simple not yet translated | ~73 |
### What blocks the remaining 73 clean simple tests
These tests exist in clean simple upstream but are not in our 381 behavioral tests. They likely involve features that:
1. Require real DOM interaction (hide with strategies, fetch with network)
2. Were added to upstream after our test generation
3. Involve categories we partially support (halt, dialog, reset, morph, liveTemplate)
### Top priorities for implementation
1. **`[@attr="val"]` syntax** (tokenizer) — 4 simple upstream tests blocked
2. **`{css-props}` block syntax** (tokenizer) — 2 simple upstream tests blocked
3. **`debounce`/`throttle` event modifiers** — Common real-world usage
4. **`scroll` command** — 8 upstream tests
5. **`focus` command** — 3 upstream tests
6. **`select` command** — 4 upstream tests
7. **`pick` command** — 7 upstream tests
8. **`live` feature** — 23 upstream tests, key for reactive data
9. **`between` comparison** — Keyword exists, needs parser/compiler path
10. **`starts with`/`ends with`** — Common string comparisons