@hyperfixi/engine 3.3.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +199 -1
- package/README.md +66 -40
- package/dist/common.js +1 -1
- package/dist/common.min.js +1 -1
- package/dist/core.js +1 -1
- package/dist/core.min.js +1 -1
- package/dist/expressions-extra.d.ts +15 -0
- package/dist/full.js +29 -10
- package/dist/full.min.js +14 -14
- package/dist/hyperfixi-hs.dev.js +29 -10
- package/dist/hyperfixi-hs.js +14 -14
- package/dist/index.d.ts +1 -0
- package/dist/index.js +30 -10
- package/dist/minimal.js +1 -1
- package/dist/minimal.min.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,202 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [4.0.1] - 2026-10-05
|
|
11
|
+
|
|
12
|
+
Fixes for 4.0.0: the per-language adapter bundles read every language again, and the MCP server's
|
|
13
|
+
documentation and core's metadata describe the 4.0 engine.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **`@lokascript/hyperscript-adapter`: the self-contained per-language and regional bundles read
|
|
18
|
+
German, French, Quechua and Chinese again.** `hyperscript-i18n-<lang>.global.js` and the regional
|
|
19
|
+
bundles installed a generate-only pattern generator over the one `@lokascript/semantic/core`
|
|
20
|
+
provides, discarding its hand-crafted patterns: in de, fr, qu and zh even
|
|
21
|
+
`on click toggle .active` stayed untranslated (the host then rejected it), and other languages
|
|
22
|
+
lost shapes such as `toggle … on #target`; 1106 of the corpus's 3772 translations read
|
|
23
|
+
differently from the full package. Published 3.x and 4.0.0 bundles alike; the all-languages
|
|
24
|
+
`hyperscript-i18n.global.js` was unaffected. The bundles now keep `/core`'s generator (sizes
|
|
25
|
+
unchanged: the ~23 KB 4.0.0 added was this generator, unused until now). Their English renderer
|
|
26
|
+
also drops only an implicit `me` now, so `put "x" into me` no longer renders as the
|
|
27
|
+
engine-invalid `put "x"` in every language. New gate: every built bundle runs translated
|
|
28
|
+
handlers on the engine (`test/adapter-iife.test.ts`).
|
|
29
|
+
- **`@hyperfixi/mcp-server`'s documentation resources teach upstream's spelling.**
|
|
30
|
+
`hyperscript://docs/commands`, `/expressions`, `/events` and `hyperscript://examples/common` still
|
|
31
|
+
taught core 3.x: `on submit.prevent`, `on input.debounce(300ms)`, `on keydown.enter`,
|
|
32
|
+
`swap #t innerHTML`, `while …`, a bare `[attr]` selector, a `parent` keyword, `you` as the event
|
|
33
|
+
target. The engine rejects those, or reads them as something else (`on click.prevent` listens for
|
|
34
|
+
an event named `click.prevent`). A test now parses every example on the engine. The repo's
|
|
35
|
+
`hyperfixi-developer` skill, generated from them, follows (`generate:skills` had been writing to
|
|
36
|
+
the wrong directory).
|
|
37
|
+
- **`@hyperfixi/core/metadata` describes 4.0.** `packageInfo.description` still said "Modern
|
|
38
|
+
hyperscript engine with fixi/htmx integration" and `compatibility` "~85% official _hyperscript",
|
|
39
|
+
both 3.x claims. `packageInfo.upstreamSuite` (`{ version, passed, total }`) now publishes the
|
|
40
|
+
engine's result on upstream _hyperscript's own test suite (1401 of 1467 in 0.9.93), and
|
|
41
|
+
`compatibility` is derived from it; `verify:reference` fails when it disagrees with
|
|
42
|
+
`packages/engine/upstream-suite/known-failures.json`. `ecosystem` drops "212 LLM examples".
|
|
43
|
+
|
|
44
|
+
## [4.0.0] - 2026-10-04
|
|
45
|
+
|
|
46
|
+
`@hyperfixi/core`'s own hyperscript engine is gone: its root re-exports `@hyperfixi/engine`, and
|
|
47
|
+
its `hyperfixi.js` is the engine's 34 KB script-tag bundle where core's ~352 KB bundle used to be.
|
|
48
|
+
The engine follows upstream `_hyperscript`'s grammar and is gated by upstream's own test suite, so
|
|
49
|
+
scripts in core-only syntax need upstream's spelling (two additions stay: `new X()` and
|
|
50
|
+
`toggle <element>`). Core's other bundles, its htmx layer, the core-era plugin packages and the
|
|
51
|
+
AOT compiler retire: htmx 4 or fixi supply hypermedia attributes beside the engine, and
|
|
52
|
+
`@lokascript/hyperscript-adapter` runs hyperscript written in other languages. Every package moves
|
|
53
|
+
to 4.0.0 together. Everything under **Removed** is breaking, as is each **Changed** item marked ⚠;
|
|
54
|
+
[MIGRATION.md](MIGRATION.md) names each replacement.
|
|
55
|
+
|
|
56
|
+
### Removed
|
|
57
|
+
|
|
58
|
+
- **Core's engine and its API** (#1368). These root exports had no engine counterpart:
|
|
59
|
+
`hyperscript` (`compile`, `compileSync`, `compileAsync`, `eval`, `validate`), `lokascript`,
|
|
60
|
+
`Runtime`, `RuntimeBase`, `createContext` and the element-scope helpers, `installPlugin`,
|
|
61
|
+
`getParserExtensionRegistry`, `setGlobal`, `DebugController`, `validatePartialContent` and its
|
|
62
|
+
helpers, `fromCoreAST` / `toCoreAST`. `parse` is now the engine's. The root is ESM-only, like the
|
|
63
|
+
engine: `dist/index.cjs` and the UMD `dist/index.min.js` (`LokaScriptCore`) are gone, though the
|
|
64
|
+
kept subpaths still ship CommonJS.
|
|
65
|
+
- **21 of core's 29 entry points**: `/commands`, `/expressions`, `/parser/*`, `/behaviors`,
|
|
66
|
+
`/bundle-generator`, `/registry/*`, `/lse`, and `/browser/` `hybrid-complete`, `hybrid-hx`,
|
|
67
|
+
`hybrid-hx-v4`, `multilingual`, `modular` (#1343–#1368). Instead of `/commands`, import the
|
|
68
|
+
grammar modules from the root: `import { toggle } from '@hyperfixi/core'`.
|
|
69
|
+
- **Core's browser bundles** (#1348, #1350, #1352, #1368): `hyperfixi-hx.js`,
|
|
70
|
+
`hyperfixi-hx-v4.js`, `hyperfixi-hybrid-complete.js`, `hyperfixi-multilingual.js`,
|
|
71
|
+
`hyperfixi-classic-i18n.js` and the code-split `hyperfixi.mjs`, plus every alias
|
|
72
|
+
(`hyperfixi-browser.js`, `hyperfixi-hybrid-hx.js`, each `lokascript-*.js`). Only
|
|
73
|
+
`hyperfixi.js` remains. CDN URLs pinned to 3.x keep working.
|
|
74
|
+
- **Core's embedded htmx layer** (#1342, #1348, #1350): `hx-*` and fixi `fx-*` on core's runtime,
|
|
75
|
+
`hx-live`, `sse-connect` / `sse-swap`, `ws-connect` / `ws-send`. Load htmx 4 or fixi beside the
|
|
76
|
+
engine. `hx-live` becomes the engine's `live` block, and SSE and WebSockets are htmx 4's
|
|
77
|
+
`hx-sse` / `hx-ws`.
|
|
78
|
+
- **Core-only members of `window.hyperfixi`**: `compile`, `compileSync`, `execute`, `setLocale`,
|
|
79
|
+
`evalLSENode`, `debugControl`, `semanticDebug`, the `hyperfixi:semantic-parse` event,
|
|
80
|
+
`hyperfixi:debug` logging, `_hyperscript.behaviors.resolve`, and the deprecated
|
|
81
|
+
`window.lokascript` (#1352, #1355).
|
|
82
|
+
- **Core-only hyperscript syntax** (#1346, #1363, #1365). The engine rejects `has` / `have`,
|
|
83
|
+
`prepend`, `copy`, `push url` / `replace url`, `process partials`, the `pseudo` keyword, prefix
|
|
84
|
+
`unless`, bare `beep`, `a ? b : c`, core's `swap <strategy> of X with Y`, `set @a to v on X`,
|
|
85
|
+
`.debounce(n)` / `.throttle(n)`, `my?.x` and `tell X to …`. A few forms still parse but no longer
|
|
86
|
+
do what they did, such as `toggle .a on this` and `go forward`. MIGRATION.md gives each form's
|
|
87
|
+
upstream spelling. The multilingual reader still accepts them all.
|
|
88
|
+
- **`@hyperfixi/core/multilingual`'s class API** (#1345, #1368): `MultilingualHyperscript` (with
|
|
89
|
+
`parseToAST`, `getAllTranslations`, …), `getMultilingual`, `multilingual`, `LanguageInfo`,
|
|
90
|
+
`schemaRoleInferrer`. The entry is three async functions: `parse`, `render`, `translate`.
|
|
91
|
+
- **The AOT compiler** (#1364). Its output ran only on a runtime that was never published.
|
|
92
|
+
`@lokascript/compilation-service` loses `compile()`, `POST /compile`, `CompileResponse`, the
|
|
93
|
+
compile cache (`SemanticCache`, `getCacheStats`, `clearCache`, `/cache`), `generateTests`'
|
|
94
|
+
`executionMode` and `generate()`'s `'js'` target. `generate()` now requires `target`
|
|
95
|
+
(`react` | `vue` | `svelte` | `intent-element`). `@hyperfixi/mcp-server` loses
|
|
96
|
+
`compile_hyperscript`, `execute_lse`, `lse_to_hyperscript`'s `compile` option and
|
|
97
|
+
`generate_tests`' `executionMode`, leaving 106 tools. The loop is now `validate_and_compile`
|
|
98
|
+
(name kept), then repair, then the hyperscript as is in `_="…"`.
|
|
99
|
+
- **`@hyperfixi/vite-plugin`'s compile mode** (#1360). `mode: 'compile'` warns and builds the
|
|
100
|
+
engine bundle. The exports `CompiledHandler`, `CompileOptions` and
|
|
101
|
+
`set/clear/hasSemanticParser` are removed.
|
|
102
|
+
- **Smaller removals.** `@hyperfixi/core/reference` loses `availability`, `BundleAvailability`
|
|
103
|
+
and `getCommandsByAvailability` (#1363). `@hyperfixi/speech` loses `speechPlugin`,
|
|
104
|
+
`speakCommand`, `askCommand` and `answerCommand`; the engine has `ask` / `answer` (#1358).
|
|
105
|
+
`@hyperfixi/intent-element` loses its `evalLSENode` fallback (#1356).
|
|
106
|
+
`@hyperfixi/patterns-reference` loses four rows that held only retired htmx attributes, and
|
|
107
|
+
`hx-live-with-mutator` is renamed `live-with-handler` (#1348). Of the never-published VS Code
|
|
108
|
+
extensions, the LokaScript one loses its debugger and the standalone `_hyperscript` one is
|
|
109
|
+
retired (#1361).
|
|
110
|
+
|
|
111
|
+
### Deprecated
|
|
112
|
+
|
|
113
|
+
- **`@hyperfixi/reactivity`, `@hyperfixi/realtime`, `@hyperfixi/components`**: deprecated on npm,
|
|
114
|
+
last version 3.3.0 (#1358). Use the engine's built-in `live` / `when` / `bind`, htmx 4's
|
|
115
|
+
`hx-sse` / `hx-ws`, and upstream's component extension.
|
|
116
|
+
- **`@hyperfixi/types-browser`'s `LokaScriptCoreAPI`**: a deprecated alias of `HyperfixiAPI`
|
|
117
|
+
(#1356).
|
|
118
|
+
|
|
119
|
+
### Changed
|
|
120
|
+
|
|
121
|
+
- ⚠ **`@hyperfixi/core` is the engine plus tooling** (#1368). The root is
|
|
122
|
+
`export * from '@hyperfixi/engine'` and `VERSION`: `register`, `everything` and each grammar
|
|
123
|
+
module, `api`, `parse`, `evaluate`, `processNode`, `boot`, and the AST types. The engine stays
|
|
124
|
+
external, so both packages share one grammar. Kept: `/multilingual`, `/ast-utils`,
|
|
125
|
+
`/reference`, `/metadata`, `/lsp-metadata`, `/browser`.
|
|
126
|
+
- ⚠ **`hyperfixi.js` (`@hyperfixi/core/browser`) is the engine's `hyperfixi-hs.js`**, byte for
|
|
127
|
+
byte: 34 KB gzipped instead of ~352 KB (#1355). `window.hyperfixi` is `window._hyperscript`,
|
|
128
|
+
upstream-shaped (`evaluate`, `parse`, `process`, `use`, `config`, `addSourceTransform`). Parse
|
|
129
|
+
errors are a `hyperscript:parse-error` event on the element plus a `console.error` (#1354).
|
|
130
|
+
- ⚠ **Runtime semantics follow upstream** wherever core's differed. `swap #a with #b` exchanges
|
|
131
|
+
the elements; `show` / `hide … with *opacity` honour the strategy; `tell` binds `you`, not `me`;
|
|
132
|
+
`set` on a selector sets every match; and `no ""` is true. MIGRATION.md has the full list.
|
|
133
|
+
- ⚠ **`@hyperfixi/vite-plugin` emits a bundle on `@hyperfixi/engine`** (#1343). There is one
|
|
134
|
+
tier: the grammar modules the scan finds. It weighs 17.9 KB gzipped for three commands (3.x lite:
|
|
135
|
+
3.9 KB) and 34.4 KB for everything; 3.x fell back to 352 KB on `fetch`. htmx is not bundled.
|
|
136
|
+
Non-English scripts are translated as the engine reads them. `devFallback: 'everything'` is new,
|
|
137
|
+
and `'full'` / `'hybrid-complete'` mean the same. The plugin no longer depends on core.
|
|
138
|
+
- ⚠ **`@hyperfixi/behaviors` runs on the engine** (peer `@hyperfixi/engine`; upstream works too).
|
|
139
|
+
Each behavior is defined with `host.evaluate(source)` and written in upstream's idioms.
|
|
140
|
+
Toggleable's `target` parameter is now `targetEl`. `LokaScriptInstance` / `LokaScriptWindow`
|
|
141
|
+
are now `HyperscriptHost` / `HyperscriptWindow` (#1338).
|
|
142
|
+
- ⚠ **`@hyperfixi/speech` is an engine module** (#1358). Install it with
|
|
143
|
+
`register(...everything, speak)`. It is ESM-only and peers on the engine. `speak` takes
|
|
144
|
+
upstream's syntax (`speak <text> [with voice|rate|pitch|volume <x>]…`) and waits for the
|
|
145
|
+
utterance to end.
|
|
146
|
+
- ⚠ **The localized htmx vocabulary moved** from `@hyperfixi/core/vocab/htmx/{lang}.js` to
|
|
147
|
+
`@lokascript/htmx-adapter/vocab/{lang}.js`; the data is unchanged (#1349).
|
|
148
|
+
- **`@hyperfixi/intent-element`** renders an intent to English with the page's semantic bundle
|
|
149
|
+
and runs it through the host's `evaluate` (`NO_RENDERER` without one). It peers on
|
|
150
|
+
`@hyperfixi/engine` and `@lokascript/semantic` (#1339, #1356).
|
|
151
|
+
- **`@lokascript/semantic` writes upstream's spelling in English** for core-only forms (#1346).
|
|
152
|
+
For example, `has` becomes `matches`, `prepend` becomes `put … at start of`, and swap strategies
|
|
153
|
+
become `put … into` / `before` / `after`. This reaches `translate(…, 'en')`,
|
|
154
|
+
`render(node, 'en')`, both adapters and MCP `translate_to_english`. In `fromSemanticAST`, a
|
|
155
|
+
handler's `then` chain is now its body (#1359).
|
|
156
|
+
- **The language tools read the engine's parse** (#1356, #1359, #1365).
|
|
157
|
+
`@lokascript/language-server` and MCP `validate_hyperscript` report the engine's errors
|
|
158
|
+
(`source: 'engine'`). Hover and symbols come from `@lokascript/semantic`, and some long handlers
|
|
159
|
+
show fewer commands than in 3.x. Hyperscript mode flags exactly `new X()` and `toggle <element>`.
|
|
160
|
+
`@lokascript/compilation-service` rejects natural-language input the engine cannot read
|
|
161
|
+
(`ENGINE_PARSE_ERROR`), and its generated Playwright tests load `hyperfixi-hs.js`. The language
|
|
162
|
+
server, the MCP server and the compilation service now peer on `@hyperfixi/engine`.
|
|
163
|
+
- **MCP**: `get_bundle_config` recommends `hyperfixi-hs.js`, plus an `adapter` field for
|
|
164
|
+
non-English. `analyze_complexity` / `analyze_metrics` no longer count every comparison as a
|
|
165
|
+
decision. The `debug_*` tools point to `log` and `breakpoint`. `UNSUPPORTED_QUERY_LITERAL` is
|
|
166
|
+
gone (#1350, #1352, #1359, #1361, #1364).
|
|
167
|
+
- **`@hyperfixi/core/reference`, `/lsp-metadata`, `/metadata` describe the engine** (#1355,
|
|
168
|
+
#1363). They cover its 53 commands, adding `for`, `ask`, `answer` and `beep!`. Examples are in
|
|
169
|
+
upstream spelling and each is checked to parse; descriptions of core-only semantics (`pick`,
|
|
170
|
+
`beep`, `swap`) are fixed. `FEATURE_KEYWORDS` gains `install`, `when`, `live` and `bind`, and
|
|
171
|
+
`bundleInfo` holds one row.
|
|
172
|
+
- **Dependencies.** `@lokascript/i18n`, `@hyperfixi/testing-framework`, `@hyperfixi/vite-plugin`,
|
|
173
|
+
`@hyperfixi/behaviors`, `@hyperfixi/speech` and `@hyperfixi/intent-element` no longer depend
|
|
174
|
+
on core. Core drops `@lokascript/intent`, morphlex, tslib and its optional peers. Versions are
|
|
175
|
+
lockstep, so upgrade `@hyperfixi/*` and `@lokascript/*` together. `@hyperfixi/mcp-server`,
|
|
176
|
+
`@lokascript/framework` (tests) and `@hyperfixi/server-bridge` (tests) range on
|
|
177
|
+
`@lokascript/domains ^3.0.1`, the first domains release whose peers accept framework,
|
|
178
|
+
semantic and intent 4.x (`^3.1.0 || ^4.0.0`).
|
|
179
|
+
|
|
180
|
+
### Added
|
|
181
|
+
|
|
182
|
+
- **`@hyperfixi/engine` exports `expr`**, so a grammar module can live in another package
|
|
183
|
+
(#1358).
|
|
184
|
+
- **`@hyperfixi/core/ast-utils`'s `withEnginePositions`** gives interchange nodes the source
|
|
185
|
+
spans of the engine's parse (#1359).
|
|
186
|
+
|
|
187
|
+
### Fixed
|
|
188
|
+
|
|
189
|
+
- **`@hyperfixi/engine`** accepts upstream's `beep!` command (`beep! a, b`); 3.3.0 rejected it
|
|
190
|
+
(#1362).
|
|
191
|
+
- **`@hyperfixi/types-browser`** types `window.hyperfixi` / `window._hyperscript` as the engine's
|
|
192
|
+
`HyperfixiAPI`. 3.3.0 re-exported a `./globals` it never emitted, so `window.hyperfixi` was
|
|
193
|
+
untyped (#1356).
|
|
194
|
+
- **Semantic browser bundles** (#1351). Single-language and regional bundles (es, ja,
|
|
195
|
+
east-asian, …) registered no English, so the hyperscript adapter left scripts untranslated. They
|
|
196
|
+
now register it (+~2.2 KB gzipped) and export `translate`. The lite adapter finds any
|
|
197
|
+
`LokaScriptSemantic*` global.
|
|
198
|
+
- **`@lokascript/semantic`** (#1338, #1343, #1347). `/core` plus a language module no longer
|
|
199
|
+
throws "No patterns registered". `on click from (x or me)` parses in th and zh. A `js … end`
|
|
200
|
+
block no longer ends its handler in ja / ko / hi / tr / qu / bn. An options object's `}` is no
|
|
201
|
+
longer read as an SOV event name.
|
|
202
|
+
- **Language server and MCP** (#1359, #1363, #1365). `beep!` has hover docs. `set X to`
|
|
203
|
+
completions offer values. Hyperscript-mode errors land on the form, not line 0. Hover no longer
|
|
204
|
+
shows a second `on click`.
|
|
205
|
+
|
|
10
206
|
## [3.3.0] - 2026-10-02
|
|
11
207
|
|
|
12
208
|
The first publication of `@hyperfixi/engine`, the hyperscript engine meant to replace the one
|
|
@@ -899,7 +1095,9 @@ _Synchronized version release. See git history for details._
|
|
|
899
1095
|
- npm access token stored in GitHub Secrets
|
|
900
1096
|
- 2FA recommended for npm organization
|
|
901
1097
|
|
|
902
|
-
[Unreleased]: https://github.com/codetalcott/hyperfixi/compare/
|
|
1098
|
+
[Unreleased]: https://github.com/codetalcott/hyperfixi/compare/v4.0.1...HEAD
|
|
1099
|
+
[4.0.1]: https://github.com/codetalcott/hyperfixi/compare/v4.0.0...v4.0.1
|
|
1100
|
+
[4.0.0]: https://github.com/codetalcott/hyperfixi/compare/v3.3.0...v4.0.0
|
|
903
1101
|
[3.3.0]: https://github.com/codetalcott/hyperfixi/compare/v3.2.0...v3.3.0
|
|
904
1102
|
[3.2.0]: https://github.com/codetalcott/hyperfixi/compare/v3.1.0...v3.2.0
|
|
905
1103
|
[3.1.0]: https://github.com/codetalcott/hyperfixi/compare/v3.0.0...v3.1.0
|
package/README.md
CHANGED
|
@@ -5,9 +5,9 @@ upstream's own test suite as the acceptance oracle. It is typed (`tsc --strict`,
|
|
|
5
5
|
synchronous until a script really waits on something, and built from modules, so a bundle
|
|
6
6
|
contains the commands it registers and nothing else.
|
|
7
7
|
|
|
8
|
-
It
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
It replaced the engine in `packages/core` in 4.0: `@hyperfixi/core`'s root re-exports it, and
|
|
9
|
+
core's `dist/hyperfixi.js` is this package's `hyperfixi-hs.js`. It is also published on its own
|
|
10
|
+
(since 2026-10-02).
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
@@ -39,6 +39,12 @@ feature, or an optional expression kind. A rule that is not registered does not
|
|
|
39
39
|
script that uses it fails with a parse error that names the token. `src/bundles/full.ts` is the
|
|
40
40
|
list of every module.
|
|
41
41
|
|
|
42
|
+
A module can live in another package. `@hyperfixi/speech` is one (upstream's `speak`): it imports
|
|
43
|
+
`expr` and the `Grammar` / `Cmd` / `Expr` types from here, sets `g.commands.speak` to a rule that
|
|
44
|
+
reads its operands off the `Parser` it is handed, and returns a node whose `run` may return a
|
|
45
|
+
promise. `register(...everything, speak)` builds an engine with it. (The script-tag bundle is a
|
|
46
|
+
fixed list; nothing adds a module to a page's `hyperfixi-hs.js` after it loads.)
|
|
47
|
+
|
|
42
48
|
The public object is shaped like upstream's `_hyperscript` (`evaluate`, `parse`, `process`,
|
|
43
49
|
`config`, `use(plugin)`, `addBeforeProcessHook`), so a plugin written for upstream's public API
|
|
44
50
|
can be used on it; the multilingual adapter is. It adds one hook upstream lacks:
|
|
@@ -120,14 +126,15 @@ after the upstream suite.
|
|
|
120
126
|
|
|
121
127
|
**The shipped-sources gates**, also in `packages/testing-framework`:
|
|
122
128
|
|
|
123
|
-
- `shipped-sources-engine.test.ts` lists the sources this repository ships (`examples/`,
|
|
124
|
-
trees) that `
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
- `shipped-sources-engine.test.ts` lists the English sources this repository ships (`examples/`,
|
|
130
|
+
the doc trees) that this engine rejects (`baselines/shipped-sources-engine.json`). A new one
|
|
131
|
+
fails; so does a listed one that now parses. It is empty. (Until Phase C4 it counted only the
|
|
132
|
+
sources `packages/core` compiled clean.) A source written in another language is
|
|
133
|
+
`shipped-sources-localized.test.ts`'s: it must translate to English both engines parse.
|
|
134
|
+
- `shipped-examples-execution.test.ts`: every example handler upstream accepts is run on
|
|
135
|
+
upstream and on this engine, in jsdom, and the DOM effects must match. Measured 2026-10-04:
|
|
136
|
+
128 handlers, none different, 44 with no effect on either. (`packages/core`'s lane, which
|
|
137
|
+
differed on 31 at first, left with its engine in Phase C4.)
|
|
131
138
|
|
|
132
139
|
## Measured (2026-10-01, upstream 0.9.93)
|
|
133
140
|
|
|
@@ -149,19 +156,31 @@ commands) 18.4 KB, `full` 34.1 KB, `core` (no commands) 13.8 KB.
|
|
|
149
156
|
`dist/hyperfixi-hs.js` (minified, 34.1 KB gzipped; `hyperfixi-hs.dev.js` is the readable build) is the first product on this engine:
|
|
150
157
|
hyperscript and nothing else, every module, no htmx attributes, English only. It installs
|
|
151
158
|
`window._hyperscript`, as upstream does, and the same object as `window.hyperfixi`. The name
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
paired with core's `hyperfixi-hx.js` (hyperscript plus htmx, retired in Phase C3). Since C-R4b
|
|
160
|
+
`@hyperfixi/core` ships this same file as `dist/hyperfixi.js` (copied by core's
|
|
161
|
+
`scripts/copy-engine-bundle.mjs`), where core's own everything-bundle used to be.
|
|
162
|
+
|
|
163
|
+
Every tracked gallery page loads it instead of `packages/core/dist/hyperfixi.js`
|
|
164
|
+
(2026-10-03: forty-seven pages; the error-path page for core's htmx layer was deleted with that
|
|
165
|
+
layer). Thirty-two by a script tag; fifteen through the examples' loader, `data-default="hs"`,
|
|
166
|
+
so that `?bundle=` still switches them. Core's Playwright suites run them, and the bundle is a
|
|
167
|
+
column of the bundle-compatibility matrix (`?bundle=hs` in the examples' loader). No page needed
|
|
168
|
+
an API shim: `processNode` is upstream's name too, and the other `hyperfixi.*` calls were core
|
|
169
|
+
debugging code. The multilingual demo pages are among them: their handlers are English, and what
|
|
170
|
+
they translate for display comes from the i18n or semantic bundle, loaded beside the engine. The
|
|
171
|
+
behavior pages load `@hyperfixi/behaviors`' bundle beside it, which defines its eleven behaviors
|
|
172
|
+
on the engine with `evaluate` (the package peers on this engine since 2026-10-03; its sources
|
|
173
|
+
are in upstream's idioms and run on upstream too). The intent-element pages load the semantic
|
|
174
|
+
English bundle beside it: `<lse-intent>` renders its LSE JSON to hyperscript text and hands it
|
|
175
|
+
to the host's `evaluate`, the `lse_to_hyperscript` direction (core's `evalLSENode` was the AST
|
|
176
|
+
path). The history pages write `call history.pushState(null, '', X)` / `replaceState`
|
|
177
|
+
(upstream's spelling; the owner decided against a `push url` addition) and define their
|
|
178
|
+
`HistorySwap` behavior in the page. The htmx pages (`examples/hx-v4/`, `hx-v4-i18n/`) are the
|
|
179
|
+
two stacks that replace core's embedded htmx layer (retired by owner decision, 2026-10-03): the
|
|
180
|
+
engine's own `live` / `bind` blocks where no request is involved, and REAL htmx 4 (vendored under
|
|
181
|
+
`examples/vendor/`) with its `hx-sse` / `hx-ws` extensions and `@lokascript/htmx-adapter` for
|
|
182
|
+
localized attribute names beside the engine where one is. Core's own debug pages left the
|
|
183
|
+
gallery for `packages/core/test-pages/`. One behavior of core's is not in this engine, by decision
|
|
165
184
|
(2026-10-02): `increment #count` on core counts in the element's text, where upstream and this
|
|
166
185
|
engine want `increment #count's textContent`. The examples write the second, which every
|
|
167
186
|
bundle runs to the same count (the bundle matrix's Counter row).
|
|
@@ -178,30 +197,37 @@ As a host for the multilingual text path (semantic renders a translation, the ad
|
|
|
178
197
|
- **Value matrix.** 4,205 cells. English on this engine gives the oracle's value in every cell.
|
|
179
198
|
Through the adapter in 23 languages, 96,640 of 96,643 (cell, language) pairs do, and the two
|
|
180
199
|
hosts agree on every pair: the three that miss are the accepted Italian `di` ambiguity, and
|
|
181
|
-
they miss on upstream too. (`packages/core`
|
|
182
|
-
|
|
200
|
+
they miss on upstream too. (`packages/core` missed 8 cells in English; its lanes retired in
|
|
201
|
+
Phases C2 and C4.)
|
|
183
202
|
- **Parser parity.** Of the 273 distinct English strings the canonical-validity gates put to
|
|
184
203
|
upstream's parser, the two parsers disagree on none.
|
|
185
|
-
- Of the
|
|
186
|
-
engine only.
|
|
187
|
-
`
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
204
|
+
- Of the 164 corpus rows, 152 parse on both engines and 12 on neither, measured on each
|
|
205
|
+
row's raw source (2026-10-04); none parses on one engine only. Ten of the 12 are markup or
|
|
206
|
+
extension rows (five components; `live-with-handler`, markup whose `_` sources parse on
|
|
207
|
+
both; sockets, workers, event sources, `intercept`), one is valid nowhere (`async-block`),
|
|
208
|
+
and one is syntax only `packages/core` has: `swap … using view transition`
|
|
209
|
+
(swap-view-transition). Ten more were core-only until the rows were rewritten in upstream's
|
|
210
|
+
spelling on 2026-10-01 and (fetch-formdata, `new FormData(…)` in a `js` block) on
|
|
211
|
+
2026-10-03; five rows of core's htmx v4 attributes left with `hyperfixi-hx-v4.js` (Phase C3).
|
|
191
212
|
- **The adapter's plugin** in six languages: the script runs and the attribute stays as
|
|
192
213
|
written. On upstream the plugin has to rewrite the attribute.
|
|
193
214
|
|
|
194
215
|
## Against what this repository ships
|
|
195
216
|
|
|
196
|
-
`npx tsx packages/engine/tools/shipped-sources.mts` puts every hyperscript source in
|
|
197
|
-
`examples/` and the doc trees (the shipped-sources gate's collection
|
|
198
|
-
|
|
217
|
+
`npx tsx packages/engine/tools/shipped-sources.mts` puts every English hyperscript source in
|
|
218
|
+
`examples/` and the doc trees (the shipped-sources gate's collection) to upstream's parser and
|
|
219
|
+
this engine's. Measured 2026-10-04: 315 distinct, upstream accepts 281, this engine all 315;
|
|
220
|
+
the 34 they disagree on are this engine's two additions (`new X()`, `toggle <element>`).
|
|
221
|
+
|
|
222
|
+
Until Phase C4 `packages/core` was a third parser, and the question was what replacing it would
|
|
223
|
+
break. Measured 2026-10-01 (386 sources, 336 distinct): upstream accepted 272, this engine 309,
|
|
224
|
+
`packages/core` 320;
|
|
199
225
|
|
|
200
|
-
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
226
|
+
- **12 sources that core accepted were rejected here**: the eleven handlers that used core's
|
|
227
|
+
history commands (`push url`, `replace url`), rewritten as `call history.pushState(…)` on
|
|
228
|
+
2026-10-03, and the `hyperfixi-hx.js` example in `docs/BROWSER_BUNDLES.md`, written in the
|
|
229
|
+
hybrid parser's own dialect (`on click.debounce(300)`, `me has .loading`), which went with
|
|
230
|
+
that bundle in Phase C3 (2026-10-04). None is left.
|
|
205
231
|
|
|
206
232
|
It was 78 when first measured. The examples and docs were moved to upstream's spellings where
|
|
207
233
|
upstream has one (`put … into` for core's `swap` strategies, `debounced at 300ms`,
|
package/dist/common.js
CHANGED
|
@@ -2733,7 +2733,7 @@
|
|
|
2733
2733
|
cleanup,
|
|
2734
2734
|
/** The part of upstream's `internals` that pages and tests reach for. */
|
|
2735
2735
|
internals: { runtime: { cleanup, processNode } },
|
|
2736
|
-
version: false ? "dev" : "
|
|
2736
|
+
version: false ? "dev" : "4.0.1"
|
|
2737
2737
|
});
|
|
2738
2738
|
function boot() {
|
|
2739
2739
|
Object.assign(globalThis, { _hyperscript: api });
|
package/dist/common.min.js
CHANGED
|
@@ -14,4 +14,4 @@
|
|
|
14
14
|
|
|
15
15
|
`+st(i)+s)}else F(e,"exception",{error:i}),console.error("hyperscript errors were found on the following element:",e,`
|
|
16
16
|
|
|
17
|
-
`,i)}}var dn=[],fn=[];function we(e){if(!(e instanceof Element||e instanceof Document||e instanceof DocumentFragment))return;for(let n of dn)n(e);let t=un().map(n=>`[${n}]`).join(", ")+", [type='text/hyperscript']";e instanceof Element&&e.matches(t)&&nn(e),e.querySelectorAll(t).forEach(nn);for(let n of fn)n(e)}function Me(e){let t=oe(e);if(t){F(e,"hyperscript:before:cleanup");for(let{target:n,event:r,handler:o}of t.listeners??[])n.removeEventListener(r,o);for(let n of t.observers??[])n.disconnect();for(let n of t.timers??[])clearTimeout(n);k.stop(e),e.querySelectorAll("[data-hyperscript-powered]").forEach(Me),F(e,"hyperscript:after:cleanup"),e.removeAttribute("data-hyperscript-powered"),ut(e)}}U.process=we;function rr(e){try{let t=an(e);return t.kind==="features"?{...t.program,errors:[]}:{...t.kind==="commands"?t.commands[0]:t.expression,errors:[]}}catch(t){if(t instanceof ee)return{errors:[t]};throw t}}var mn=Object.assign(tn,{config:Object.assign(J,{conversions:Object.assign(qe,{dynamicResolvers:De})}),use(e){e(mn)},addBeforeProcessHook:e=>void dn.push(e),addAfterProcessHook:e=>void fn.push(e),addSourceTransform:e=>void ln.push(e),evaluate:tn,parse:rr,process:we,processNode:we,cleanup:Me,internals:{runtime:{cleanup:Me,processNode:we}},version:"
|
|
17
|
+
`,i)}}var dn=[],fn=[];function we(e){if(!(e instanceof Element||e instanceof Document||e instanceof DocumentFragment))return;for(let n of dn)n(e);let t=un().map(n=>`[${n}]`).join(", ")+", [type='text/hyperscript']";e instanceof Element&&e.matches(t)&&nn(e),e.querySelectorAll(t).forEach(nn);for(let n of fn)n(e)}function Me(e){let t=oe(e);if(t){F(e,"hyperscript:before:cleanup");for(let{target:n,event:r,handler:o}of t.listeners??[])n.removeEventListener(r,o);for(let n of t.observers??[])n.disconnect();for(let n of t.timers??[])clearTimeout(n);k.stop(e),e.querySelectorAll("[data-hyperscript-powered]").forEach(Me),F(e,"hyperscript:after:cleanup"),e.removeAttribute("data-hyperscript-powered"),ut(e)}}U.process=we;function rr(e){try{let t=an(e);return t.kind==="features"?{...t.program,errors:[]}:{...t.kind==="commands"?t.commands[0]:t.expression,errors:[]}}catch(t){if(t instanceof ee)return{errors:[t]};throw t}}var mn=Object.assign(tn,{config:Object.assign(J,{conversions:Object.assign(qe,{dynamicResolvers:De})}),use(e){e(mn)},addBeforeProcessHook:e=>void dn.push(e),addAfterProcessHook:e=>void fn.push(e),addSourceTransform:e=>void ln.push(e),evaluate:tn,parse:rr,process:we,processNode:we,cleanup:Me,internals:{runtime:{cleanup:Me,processNode:we}},version:"4.0.1"});function pn(){if(Object.assign(globalThis,{_hyperscript:mn}),typeof document>"u")return;let e=()=>{we(document.documentElement),document.dispatchEvent(new Event("hyperscript:ready"))};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e):setTimeout(e)}function or(e,t){if(typeof e!="object"||e===null)return{queue:[],executing:!1};let n=X(e).eventQueues??=new Map,r=n.get(t);return r||n.set(t,r={queue:[],executing:!1}),r}function it(e,t){let n=or(e.me,t);if(n.executing&&!t.every){if(t.queue==="none"||t.queue==="first"&&n.queue.length>0)return;t.queue!=="all"&&(n.queue.length=0),n.queue.push(e);return}n.executing=!0;let r=o=>{n.executing=!1;let i=n.queue.shift();if(i&&setTimeout(()=>it(i,t),1),o){let{error:s}=o;console.error(v(s,"message")??s),console.error(v(s,"stack")),F(e.me,"exception",{error:s})}};ue(()=>x(pt(e,t.body,t),()=>r()),o=>r({error:o}))}function sr(e,t){if(!W(t))return;let n=X(t),r=n.listeners??=[],o=n.observers??=[],i=n.timers??=new Set;for(let s of e.events){let u={execCount:0},a=s.elsewhere?[document]:s.from?s.from.ev(pe(t,e,t,null)):[t];C(a,l=>{if(!W(l)){console.warn("'%s' feature ignored because target does not exists:",e.displayName,t);return}let c=s.on;if(s.mutationSpec&&l instanceof Node){c="hyperscript:mutation";let f=new MutationObserver(d=>F(l,c,{mutationList:d,observer:f}));f.observe(l,s.mutationSpec),o.push(f)}if(s.intersectionSpec&&l instanceof Element){c="hyperscript:intersection";let f=new IntersectionObserver(d=>{for(let m of d)F(l,c,{observer:f,entry:m,intersecting:m.isIntersecting,isIntersecting:m.isIntersecting,intersectionRatio:m.intersectionRatio})},s.intersectionSpec);f.observe(l),o.push(f)}if(s.resizeSpec&&l instanceof Element){c="hyperscript:resize";let f=new ResizeObserver(d=>{for(let m of d){let{width:h,height:E}=m.contentRect;F(l,c,{width:h,height:E,contentRect:m.contentRect,entry:m})}});f.observe(l),o.push(f)}let p=f=>{if(t instanceof Node&&l!==t&&!t.isConnected){l.removeEventListener(c,p);return}let d=pe(t,e,t,f);if(!(s.elsewhere&&t instanceof Node&&f.target instanceof Node&&t.contains(f.target))){s.from&&(d.result=l);for(let m of s.args){let h=v(f,m);h!==void 0?d.locals[m]=h:d.detail!=null&&(d.locals[m]=v(d.detail,m))}if(s.filter){d.meta.context=f;try{if(!s.filter.ev(d))return}finally{d.meta.context=void 0}}if(s.inExpr?.css){let m=f.target instanceof Element?f.target:null;for(;m&&!m.matches(s.inExpr.css);)m=m.parentElement;if(!m)return;d.result=m}if(u.execCount++,s.startCount){let m=u.execCount;if(s.endCount?m<s.startCount||m>s.endCount:s.unbounded?m<s.startCount:m!==s.startCount)return}if(s.debounceTime){u.debounced&&(clearTimeout(u.debounced),i.delete(u.debounced)),i.add(u.debounced=setTimeout(()=>it(d,e),s.debounceTime));return}if(s.throttleTime){if(u.lastExec&&Date.now()<u.lastExec+s.throttleTime)return;u.lastExec=Date.now()}it(d,e)}};l.addEventListener(c,p),r.push({target:l,event:c,handler:p})})}}function ir(e){if(!e.match("of"))return{attributes:!0,characterData:!0,childList:!0,attributeOldValue:!0,characterDataOldValue:!0};let t={};do if(e.match("anything"))Object.assign(t,{attributes:!0,subtree:!0,characterData:!0,childList:!0});else if(e.match("childList"))t.childList=!0;else if(e.match("attributes"))t.attributes=!0;else if(e.match("subtree"))t.subtree=!0;else if(e.match("characterData"))t.characterData=!0;else if(e.cur().type==="ATTRIBUTE_REF"){let n=e.consume().value;n.startsWith("@")||e.err("Only shorthand attribute references are allowed here"),(t.attributeFilter??=[]).push(n.substring(1))}else e.err("Unknown mutation config specification");while(e.match("or"));return(t.attributes||t.attributeFilter)&&(t.attributeOldValue=!0),t.characterData&&(t.characterDataOldValue=!0),t}function ar(e){let t={};if(e.match("with")){let n=ye(g(e));n instanceof Element&&(t.root=n)}if(e.match("having"))do e.match("margin")?t.rootMargin=Tt(e):e.match("threshold")?t.threshold=Number(ye(g(e))):e.err("Unknown intersection config specification");while(e.match("and"));return t}function ur(e,t){let n=K(e),r=Le(e),o;e.matchOp("[")&&(o=g(e),e.reqOp("]"));let i,s,u=!1;t?i=1:e.cur().type==="NUMBER"&&(i=parseInt(e.consume().value),e.match("to")?s=parseInt(e.consume().value):e.match("and")&&(u=!0,e.req("on")));let a={on:n,args:r,filter:o,startCount:i,endCount:s,unbounded:u,elsewhere:!1,resizeSpec:n==="resize"};n==="intersection"?a.intersectionSpec=ar(e):n==="mutation"&&(a.mutationSpec=ir(e)),e.match("from")&&(e.match("elsewhere")?a.elsewhere=!0:a.from=e.withFollow(["or"],()=>g(e))),!a.from&&!a.elsewhere&&e.match("elsewhere")&&(a.elsewhere=!0),e.match("in")&&(a.inExpr=z(e));let l=()=>(e.req("at"),Number(ye(z(e))));return e.match("debounced")?a.debounceTime=l():e.match("throttled")&&(a.throttleTime=l()),a}function hn(e){e.features.on=(t,n)=>{let r=!!t.match("every"),o=!r&&!!t.match("first"),i=[];do i.push(ur(t,o));while(t.match("or"));let s="last";!r&&t.match("queue")&&(t.match("all")?s="all":t.match("first")?s="first":t.match("none")?s="none":t.req("last"));let u=Y(t),a={type:"onFeature",displayName:"on "+i.map(l=>l.on).join(" or "),events:i,body:u,every:r,queue:s,...It(t),start:n,end:t.endPos(),install:l=>sr(a,l)};return a}}on(hn,jt,Gt,$t,Ut,Zt,Kt,Jt,Lt,Ft,Vt,Bt,zt,Qt,Yt);pn();})();
|
package/dist/core.js
CHANGED
|
@@ -1903,7 +1903,7 @@
|
|
|
1903
1903
|
cleanup,
|
|
1904
1904
|
/** The part of upstream's `internals` that pages and tests reach for. */
|
|
1905
1905
|
internals: { runtime: { cleanup, processNode } },
|
|
1906
|
-
version: false ? "dev" : "
|
|
1906
|
+
version: false ? "dev" : "4.0.1"
|
|
1907
1907
|
});
|
|
1908
1908
|
function boot() {
|
|
1909
1909
|
Object.assign(globalThis, { _hyperscript: api });
|
package/dist/core.min.js
CHANGED
|
@@ -14,4 +14,4 @@
|
|
|
14
14
|
|
|
15
15
|
`+Ce(i)+s)}else N(e,"exception",{error:i}),console.error("hyperscript errors were found on the following element:",e,`
|
|
16
16
|
|
|
17
|
-
`,i)}}var kt=[],Tt=[];function re(e){if(!(e instanceof Element||e instanceof Document||e instanceof DocumentFragment))return;for(let n of kt)n(e);let t=Et().map(n=>`[${n}]`).join(", ")+", [type='text/hyperscript']";e instanceof Element&&e.matches(t)&&ht(e),e.querySelectorAll(t).forEach(ht);for(let n of Tt)n(e)}function pe(e){let t=$(e);if(t){N(e,"hyperscript:before:cleanup");for(let{target:n,event:r,handler:o}of t.listeners??[])n.removeEventListener(r,o);for(let n of t.observers??[])n.disconnect();for(let n of t.timers??[])clearTimeout(n);w.stop(e),e.querySelectorAll("[data-hyperscript-powered]").forEach(pe),N(e,"hyperscript:after:cleanup"),e.removeAttribute("data-hyperscript-powered"),De(e)}}Y.process=re;function hn(e){try{let t=wt(e);return t.kind==="features"?{...t.program,errors:[]}:{...t.kind==="commands"?t.commands[0]:t.expression,errors:[]}}catch(t){if(t instanceof M)return{errors:[t]};throw t}}var Pt=Object.assign(pt,{config:Object.assign(ae,{conversions:Object.assign(ge,{dynamicResolvers:ye})}),use(e){e(Pt)},addBeforeProcessHook:e=>void kt.push(e),addAfterProcessHook:e=>void Tt.push(e),addSourceTransform:e=>void xt.push(e),evaluate:pt,parse:hn,process:re,processNode:re,cleanup:pe,internals:{runtime:{cleanup:pe,processNode:re}},version:"
|
|
17
|
+
`,i)}}var kt=[],Tt=[];function re(e){if(!(e instanceof Element||e instanceof Document||e instanceof DocumentFragment))return;for(let n of kt)n(e);let t=Et().map(n=>`[${n}]`).join(", ")+", [type='text/hyperscript']";e instanceof Element&&e.matches(t)&&ht(e),e.querySelectorAll(t).forEach(ht);for(let n of Tt)n(e)}function pe(e){let t=$(e);if(t){N(e,"hyperscript:before:cleanup");for(let{target:n,event:r,handler:o}of t.listeners??[])n.removeEventListener(r,o);for(let n of t.observers??[])n.disconnect();for(let n of t.timers??[])clearTimeout(n);w.stop(e),e.querySelectorAll("[data-hyperscript-powered]").forEach(pe),N(e,"hyperscript:after:cleanup"),e.removeAttribute("data-hyperscript-powered"),De(e)}}Y.process=re;function hn(e){try{let t=wt(e);return t.kind==="features"?{...t.program,errors:[]}:{...t.kind==="commands"?t.commands[0]:t.expression,errors:[]}}catch(t){if(t instanceof M)return{errors:[t]};throw t}}var Pt=Object.assign(pt,{config:Object.assign(ae,{conversions:Object.assign(ge,{dynamicResolvers:ye})}),use(e){e(Pt)},addBeforeProcessHook:e=>void kt.push(e),addAfterProcessHook:e=>void Tt.push(e),addSourceTransform:e=>void xt.push(e),evaluate:pt,parse:hn,process:re,processNode:re,cleanup:pe,internals:{runtime:{cleanup:pe,processNode:re}},version:"4.0.1"});function Nt(){if(Object.assign(globalThis,{_hyperscript:Pt}),typeof document>"u")return;let e=()=>{re(document.documentElement),document.dispatchEvent(new Event("hyperscript:ready"))};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e):setTimeout(e)}function gn(e,t){if(typeof e!="object"||e===null)return{queue:[],executing:!1};let n=U(e).eventQueues??=new Map,r=n.get(t);return r||n.set(t,r={queue:[],executing:!1}),r}function Fe(e,t){let n=gn(e.me,t);if(n.executing&&!t.every){if(t.queue==="none"||t.queue==="first"&&n.queue.length>0)return;t.queue!=="all"&&(n.queue.length=0),n.queue.push(e);return}n.executing=!0;let r=o=>{n.executing=!1;let i=n.queue.shift();if(i&&setTimeout(()=>Fe(i,t),1),o){let{error:s}=o;console.error(g(s,"message")??s),console.error(g(s,"stack")),N(e.me,"exception",{error:s})}};V(()=>E(Qe(e,t.body,t),()=>r()),o=>r({error:o}))}function yn(e,t){if(!B(t))return;let n=U(t),r=n.listeners??=[],o=n.observers??=[],i=n.timers??=new Set;for(let s of e.events){let c={execCount:0},a=s.elsewhere?[document]:s.from?s.from.ev(ee(t,e,t,null)):[t];P(a,l=>{if(!B(l)){console.warn("'%s' feature ignored because target does not exists:",e.displayName,t);return}let u=s.on;if(s.mutationSpec&&l instanceof Node){u="hyperscript:mutation";let m=new MutationObserver(d=>N(l,u,{mutationList:d,observer:m}));m.observe(l,s.mutationSpec),o.push(m)}if(s.intersectionSpec&&l instanceof Element){u="hyperscript:intersection";let m=new IntersectionObserver(d=>{for(let y of d)N(l,u,{observer:m,entry:y,intersecting:y.isIntersecting,isIntersecting:y.isIntersecting,intersectionRatio:y.intersectionRatio})},s.intersectionSpec);m.observe(l),o.push(m)}if(s.resizeSpec&&l instanceof Element){u="hyperscript:resize";let m=new ResizeObserver(d=>{for(let y of d){let{width:I,height:j}=y.contentRect;N(l,u,{width:I,height:j,contentRect:y.contentRect,entry:y})}});m.observe(l),o.push(m)}let p=m=>{if(t instanceof Node&&l!==t&&!t.isConnected){l.removeEventListener(u,p);return}let d=ee(t,e,t,m);if(!(s.elsewhere&&t instanceof Node&&m.target instanceof Node&&t.contains(m.target))){s.from&&(d.result=l);for(let y of s.args){let I=g(m,y);I!==void 0?d.locals[y]=I:d.detail!=null&&(d.locals[y]=g(d.detail,y))}if(s.filter){d.meta.context=m;try{if(!s.filter.ev(d))return}finally{d.meta.context=void 0}}if(s.inExpr?.css){let y=m.target instanceof Element?m.target:null;for(;y&&!y.matches(s.inExpr.css);)y=y.parentElement;if(!y)return;d.result=y}if(c.execCount++,s.startCount){let y=c.execCount;if(s.endCount?y<s.startCount||y>s.endCount:s.unbounded?y<s.startCount:y!==s.startCount)return}if(s.debounceTime){c.debounced&&(clearTimeout(c.debounced),i.delete(c.debounced)),i.add(c.debounced=setTimeout(()=>Fe(d,e),s.debounceTime));return}if(s.throttleTime){if(c.lastExec&&Date.now()<c.lastExec+s.throttleTime)return;c.lastExec=Date.now()}Fe(d,e)}};l.addEventListener(u,p),r.push({target:l,event:u,handler:p})})}}function vn(e){if(!e.match("of"))return{attributes:!0,characterData:!0,childList:!0,attributeOldValue:!0,characterDataOldValue:!0};let t={};do if(e.match("anything"))Object.assign(t,{attributes:!0,subtree:!0,characterData:!0,childList:!0});else if(e.match("childList"))t.childList=!0;else if(e.match("attributes"))t.attributes=!0;else if(e.match("subtree"))t.subtree=!0;else if(e.match("characterData"))t.characterData=!0;else if(e.cur().type==="ATTRIBUTE_REF"){let n=e.consume().value;n.startsWith("@")||e.err("Only shorthand attribute references are allowed here"),(t.attributeFilter??=[]).push(n.substring(1))}else e.err("Unknown mutation config specification");while(e.match("or"));return(t.attributes||t.attributeFilter)&&(t.attributeOldValue=!0),t.characterData&&(t.characterDataOldValue=!0),t}function wn(e){let t={};if(e.match("with")){let n=ne(x(e));n instanceof Element&&(t.root=n)}if(e.match("having"))do e.match("margin")?t.rootMargin=ot(e):e.match("threshold")?t.threshold=Number(ne(x(e))):e.err("Unknown intersection config specification");while(e.match("and"));return t}function En(e,t){let n=ut(e),r=mt(e),o;e.matchOp("[")&&(o=x(e),e.reqOp("]"));let i,s,c=!1;t?i=1:e.cur().type==="NUMBER"&&(i=parseInt(e.consume().value),e.match("to")?s=parseInt(e.consume().value):e.match("and")&&(c=!0,e.req("on")));let a={on:n,args:r,filter:o,startCount:i,endCount:s,unbounded:c,elsewhere:!1,resizeSpec:n==="resize"};n==="intersection"?a.intersectionSpec=wn(e):n==="mutation"&&(a.mutationSpec=vn(e)),e.match("from")&&(e.match("elsewhere")?a.elsewhere=!0:a.from=e.withFollow(["or"],()=>x(e))),!a.from&&!a.elsewhere&&e.match("elsewhere")&&(a.elsewhere=!0),e.match("in")&&(a.inExpr=D(e));let l=()=>(e.req("at"),Number(ne(D(e))));return e.match("debounced")?a.debounceTime=l():e.match("throttled")&&(a.throttleTime=l()),a}function St(e){e.features.on=(t,n)=>{let r=!!t.match("every"),o=!r&&!!t.match("first"),i=[];do i.push(En(t,o));while(t.match("or"));let s="last";!r&&t.match("queue")&&(t.match("all")?s="all":t.match("first")?s="first":t.match("none")?s="none":t.req("last"));let c=W(t),a={type:"onFeature",displayName:"on "+i.map(l=>l.on).join(" or "),events:i,body:c,every:r,queue:s,...dt(t),start:n,end:t.endPos(),install:l=>yn(a,l)};return a}}yt(St);Nt();})();
|
|
@@ -1,2 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The less common expression kinds, as one optional module: positional
|
|
3
|
+
* (`first`, `last`, `random`), relative (`next`, `previous`), `closest`,
|
|
4
|
+
* collection operators (`where`, `sorted by`, `mapped to`, `split by`,
|
|
5
|
+
* `joined by`), `some`, block literals, type checks and `beep!` (the expression
|
|
6
|
+
* and, as upstream has it, the command `beep! a, b`).
|
|
7
|
+
*
|
|
8
|
+
* Follows upstream `parsetree/expressions/{positional,existentials,postfix}.js`,
|
|
9
|
+
* the collection half of `expressions.js`, and `BeepCommand`.
|
|
10
|
+
*/
|
|
11
|
+
import type { Cmd, Expr } from './ast';
|
|
1
12
|
import type { Grammar } from './parser';
|
|
13
|
+
export interface BeepNode extends Cmd {
|
|
14
|
+
type: 'beepCommand';
|
|
15
|
+
values: Expr[];
|
|
16
|
+
}
|
|
2
17
|
export declare function expressionsExtra(g: Grammar): void;
|
package/dist/full.js
CHANGED
|
@@ -2026,7 +2026,7 @@
|
|
|
2026
2026
|
cleanup,
|
|
2027
2027
|
/** The part of upstream's `internals` that pages and tests reach for. */
|
|
2028
2028
|
internals: { runtime: { cleanup, processNode } },
|
|
2029
|
-
version: false ? "dev" : "
|
|
2029
|
+
version: false ? "dev" : "4.0.1"
|
|
2030
2030
|
});
|
|
2031
2031
|
function boot() {
|
|
2032
2032
|
Object.assign(globalThis, { _hyperscript: api });
|
|
@@ -4512,6 +4512,17 @@ return { ${functions.map((name) => `${name}:${name}`).join(",")} } `
|
|
|
4512
4512
|
};
|
|
4513
4513
|
return node;
|
|
4514
4514
|
}
|
|
4515
|
+
function beepValue(ctx, expression, source, value) {
|
|
4516
|
+
if (triggerEvent(ctx.me, "hyperscript:beep", { element: ctx.me, expression, value })) {
|
|
4517
|
+
const typeName = value == null ? "object (null)" : get(get(value, "constructor"), "name") ?? "unknown";
|
|
4518
|
+
const shown = typeof value === "string" ? `"${value}"` : shouldAutoIterate(value) ? Array.from(value) : value;
|
|
4519
|
+
console.log(
|
|
4520
|
+
`///_ BEEP! The expression (${source}) evaluates to:`,
|
|
4521
|
+
shown,
|
|
4522
|
+
"of type " + typeName
|
|
4523
|
+
);
|
|
4524
|
+
}
|
|
4525
|
+
}
|
|
4515
4526
|
function beep(p) {
|
|
4516
4527
|
const start = p.pos();
|
|
4517
4528
|
if (!p.match("beep!")) return;
|
|
@@ -4523,23 +4534,31 @@ return { ${functions.map((name) => `${name}:${name}`).join(",")} } `
|
|
|
4523
4534
|
start,
|
|
4524
4535
|
root,
|
|
4525
4536
|
(value, ctx) => {
|
|
4526
|
-
|
|
4527
|
-
const typeName = value == null ? "object (null)" : get(get(value, "constructor"), "name") ?? "unknown";
|
|
4528
|
-
const shown = typeof value === "string" ? `"${value}"` : shouldAutoIterate(value) ? Array.from(value) : value;
|
|
4529
|
-
console.log(
|
|
4530
|
-
`///_ BEEP! The expression (${source}) evaluates to:`,
|
|
4531
|
-
shown,
|
|
4532
|
-
"of type " + typeName
|
|
4533
|
-
);
|
|
4534
|
-
}
|
|
4537
|
+
beepValue(ctx, root, source, value);
|
|
4535
4538
|
return value;
|
|
4536
4539
|
},
|
|
4537
4540
|
false
|
|
4538
4541
|
);
|
|
4539
4542
|
}
|
|
4543
|
+
function beepCommand(p, _keyword, start) {
|
|
4544
|
+
const values2 = [expr(p)];
|
|
4545
|
+
while (p.matchOp(",")) values2.push(expr(p));
|
|
4546
|
+
const sources = values2.map((v) => p.text(v));
|
|
4547
|
+
return {
|
|
4548
|
+
type: "beepCommand",
|
|
4549
|
+
values: values2,
|
|
4550
|
+
start,
|
|
4551
|
+
end: p.endPos(),
|
|
4552
|
+
run: (ctx) => all(
|
|
4553
|
+
values2.map((v) => v.ev(ctx)),
|
|
4554
|
+
(vals) => vals.forEach((value, i) => beepValue(ctx, values2[i], sources[i], value))
|
|
4555
|
+
)
|
|
4556
|
+
};
|
|
4557
|
+
}
|
|
4540
4558
|
function expressionsExtra(g) {
|
|
4541
4559
|
g.leaves.push(closest, some, blockLiteral);
|
|
4542
4560
|
g.unaries.push(beep, relative, positional);
|
|
4561
|
+
g.commands["beep!"] = beepCommand;
|
|
4543
4562
|
g.postfixes.push(typeCheckPostfix);
|
|
4544
4563
|
g.collections.push(collectionOp);
|
|
4545
4564
|
}
|