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>
454 lines
25 KiB
Markdown
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
|