@lokascript/htmx-adapter 3.2.0 → 4.0.0
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 +203 -1
- package/README.md +19 -14
- package/dist/htmx-i18n.global.js +1 -1
- package/dist/htmx-i18n.global.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -9
- package/dist/index.d.ts +7 -9
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/src/browser.ts +6 -6
- package/src/index.ts +1 -2
- package/src/lang-resolver.ts +2 -3
- package/src/registry.ts +6 -7
- package/vocab/ar.js +62 -0
- package/vocab/bn.js +65 -0
- package/vocab/de.js +83 -0
- package/vocab/en.js +24 -0
- package/vocab/es.js +79 -0
- package/vocab/fr.js +79 -0
- package/vocab/he.js +61 -0
- package/vocab/hi.js +81 -0
- package/vocab/id.js +76 -0
- package/vocab/it.js +79 -0
- package/vocab/ja.js +85 -0
- package/vocab/ko.js +81 -0
- package/vocab/ms.js +58 -0
- package/vocab/pl.js +80 -0
- package/vocab/pt.js +81 -0
- package/vocab/qu.js +83 -0
- package/vocab/ru.js +82 -0
- package/vocab/sw.js +79 -0
- package/vocab/th.js +67 -0
- package/vocab/tl.js +56 -0
- package/vocab/tr.js +86 -0
- package/vocab/uk.js +82 -0
- package/vocab/vi.js +59 -0
- package/vocab/zh.js +79 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,206 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [4.0.0] - 2026-10-04
|
|
11
|
+
|
|
12
|
+
`@hyperfixi/core`'s own hyperscript engine is gone: its root re-exports `@hyperfixi/engine`, and
|
|
13
|
+
its `hyperfixi.js` is the engine's 34 KB script-tag bundle where core's ~352 KB bundle used to be.
|
|
14
|
+
The engine follows upstream `_hyperscript`'s grammar and is gated by upstream's own test suite, so
|
|
15
|
+
scripts in core-only syntax need upstream's spelling (two additions stay: `new X()` and
|
|
16
|
+
`toggle <element>`). Core's other bundles, its htmx layer, the core-era plugin packages and the
|
|
17
|
+
AOT compiler retire: htmx 4 or fixi supply hypermedia attributes beside the engine, and
|
|
18
|
+
`@lokascript/hyperscript-adapter` runs hyperscript written in other languages. Every package moves
|
|
19
|
+
to 4.0.0 together. Everything under **Removed** is breaking, as is each **Changed** item marked ⚠;
|
|
20
|
+
[MIGRATION.md](MIGRATION.md) names each replacement.
|
|
21
|
+
|
|
22
|
+
### Removed
|
|
23
|
+
|
|
24
|
+
- **Core's engine and its API** (#1368). These root exports had no engine counterpart:
|
|
25
|
+
`hyperscript` (`compile`, `compileSync`, `compileAsync`, `eval`, `validate`), `lokascript`,
|
|
26
|
+
`Runtime`, `RuntimeBase`, `createContext` and the element-scope helpers, `installPlugin`,
|
|
27
|
+
`getParserExtensionRegistry`, `setGlobal`, `DebugController`, `validatePartialContent` and its
|
|
28
|
+
helpers, `fromCoreAST` / `toCoreAST`. `parse` is now the engine's. The root is ESM-only, like the
|
|
29
|
+
engine: `dist/index.cjs` and the UMD `dist/index.min.js` (`LokaScriptCore`) are gone, though the
|
|
30
|
+
kept subpaths still ship CommonJS.
|
|
31
|
+
- **21 of core's 29 entry points**: `/commands`, `/expressions`, `/parser/*`, `/behaviors`,
|
|
32
|
+
`/bundle-generator`, `/registry/*`, `/lse`, and `/browser/` `hybrid-complete`, `hybrid-hx`,
|
|
33
|
+
`hybrid-hx-v4`, `multilingual`, `modular` (#1343–#1368). Instead of `/commands`, import the
|
|
34
|
+
grammar modules from the root: `import { toggle } from '@hyperfixi/core'`.
|
|
35
|
+
- **Core's browser bundles** (#1348, #1350, #1352, #1368): `hyperfixi-hx.js`,
|
|
36
|
+
`hyperfixi-hx-v4.js`, `hyperfixi-hybrid-complete.js`, `hyperfixi-multilingual.js`,
|
|
37
|
+
`hyperfixi-classic-i18n.js` and the code-split `hyperfixi.mjs`, plus every alias
|
|
38
|
+
(`hyperfixi-browser.js`, `hyperfixi-hybrid-hx.js`, each `lokascript-*.js`). Only
|
|
39
|
+
`hyperfixi.js` remains. CDN URLs pinned to 3.x keep working.
|
|
40
|
+
- **Core's embedded htmx layer** (#1342, #1348, #1350): `hx-*` and fixi `fx-*` on core's runtime,
|
|
41
|
+
`hx-live`, `sse-connect` / `sse-swap`, `ws-connect` / `ws-send`. Load htmx 4 or fixi beside the
|
|
42
|
+
engine. `hx-live` becomes the engine's `live` block, and SSE and WebSockets are htmx 4's
|
|
43
|
+
`hx-sse` / `hx-ws`.
|
|
44
|
+
- **Core-only members of `window.hyperfixi`**: `compile`, `compileSync`, `execute`, `setLocale`,
|
|
45
|
+
`evalLSENode`, `debugControl`, `semanticDebug`, the `hyperfixi:semantic-parse` event,
|
|
46
|
+
`hyperfixi:debug` logging, `_hyperscript.behaviors.resolve`, and the deprecated
|
|
47
|
+
`window.lokascript` (#1352, #1355).
|
|
48
|
+
- **Core-only hyperscript syntax** (#1346, #1363, #1365). The engine rejects `has` / `have`,
|
|
49
|
+
`prepend`, `copy`, `push url` / `replace url`, `process partials`, the `pseudo` keyword, prefix
|
|
50
|
+
`unless`, bare `beep`, `a ? b : c`, core's `swap <strategy> of X with Y`, `set @a to v on X`,
|
|
51
|
+
`.debounce(n)` / `.throttle(n)`, `my?.x` and `tell X to …`. A few forms still parse but no longer
|
|
52
|
+
do what they did, such as `toggle .a on this` and `go forward`. MIGRATION.md gives each form's
|
|
53
|
+
upstream spelling. The multilingual reader still accepts them all.
|
|
54
|
+
- **`@hyperfixi/core/multilingual`'s class API** (#1345, #1368): `MultilingualHyperscript` (with
|
|
55
|
+
`parseToAST`, `getAllTranslations`, …), `getMultilingual`, `multilingual`, `LanguageInfo`,
|
|
56
|
+
`schemaRoleInferrer`. The entry is three async functions: `parse`, `render`, `translate`.
|
|
57
|
+
- **The AOT compiler** (#1364). Its output ran only on a runtime that was never published.
|
|
58
|
+
`@lokascript/compilation-service` loses `compile()`, `POST /compile`, `CompileResponse`, the
|
|
59
|
+
compile cache (`SemanticCache`, `getCacheStats`, `clearCache`, `/cache`), `generateTests`'
|
|
60
|
+
`executionMode` and `generate()`'s `'js'` target. `generate()` now requires `target`
|
|
61
|
+
(`react` | `vue` | `svelte` | `intent-element`). `@hyperfixi/mcp-server` loses
|
|
62
|
+
`compile_hyperscript`, `execute_lse`, `lse_to_hyperscript`'s `compile` option and
|
|
63
|
+
`generate_tests`' `executionMode`, leaving 106 tools. The loop is now `validate_and_compile`
|
|
64
|
+
(name kept), then repair, then the hyperscript as is in `_="…"`.
|
|
65
|
+
- **`@hyperfixi/vite-plugin`'s compile mode** (#1360). `mode: 'compile'` warns and builds the
|
|
66
|
+
engine bundle. The exports `CompiledHandler`, `CompileOptions` and
|
|
67
|
+
`set/clear/hasSemanticParser` are removed.
|
|
68
|
+
- **Smaller removals.** `@hyperfixi/core/reference` loses `availability`, `BundleAvailability`
|
|
69
|
+
and `getCommandsByAvailability` (#1363). `@hyperfixi/speech` loses `speechPlugin`,
|
|
70
|
+
`speakCommand`, `askCommand` and `answerCommand`; the engine has `ask` / `answer` (#1358).
|
|
71
|
+
`@hyperfixi/intent-element` loses its `evalLSENode` fallback (#1356).
|
|
72
|
+
`@hyperfixi/patterns-reference` loses four rows that held only retired htmx attributes, and
|
|
73
|
+
`hx-live-with-mutator` is renamed `live-with-handler` (#1348). Of the never-published VS Code
|
|
74
|
+
extensions, the LokaScript one loses its debugger and the standalone `_hyperscript` one is
|
|
75
|
+
retired (#1361).
|
|
76
|
+
|
|
77
|
+
### Deprecated
|
|
78
|
+
|
|
79
|
+
- **`@hyperfixi/reactivity`, `@hyperfixi/realtime`, `@hyperfixi/components`**: deprecated on npm,
|
|
80
|
+
last version 3.3.0 (#1358). Use the engine's built-in `live` / `when` / `bind`, htmx 4's
|
|
81
|
+
`hx-sse` / `hx-ws`, and upstream's component extension.
|
|
82
|
+
- **`@hyperfixi/types-browser`'s `LokaScriptCoreAPI`**: a deprecated alias of `HyperfixiAPI`
|
|
83
|
+
(#1356).
|
|
84
|
+
|
|
85
|
+
### Changed
|
|
86
|
+
|
|
87
|
+
- ⚠ **`@hyperfixi/core` is the engine plus tooling** (#1368). The root is
|
|
88
|
+
`export * from '@hyperfixi/engine'` and `VERSION`: `register`, `everything` and each grammar
|
|
89
|
+
module, `api`, `parse`, `evaluate`, `processNode`, `boot`, and the AST types. The engine stays
|
|
90
|
+
external, so both packages share one grammar. Kept: `/multilingual`, `/ast-utils`,
|
|
91
|
+
`/reference`, `/metadata`, `/lsp-metadata`, `/browser`.
|
|
92
|
+
- ⚠ **`hyperfixi.js` (`@hyperfixi/core/browser`) is the engine's `hyperfixi-hs.js`**, byte for
|
|
93
|
+
byte: 34 KB gzipped instead of ~352 KB (#1355). `window.hyperfixi` is `window._hyperscript`,
|
|
94
|
+
upstream-shaped (`evaluate`, `parse`, `process`, `use`, `config`, `addSourceTransform`). Parse
|
|
95
|
+
errors are a `hyperscript:parse-error` event on the element plus a `console.error` (#1354).
|
|
96
|
+
- ⚠ **Runtime semantics follow upstream** wherever core's differed. `swap #a with #b` exchanges
|
|
97
|
+
the elements; `show` / `hide … with *opacity` honour the strategy; `tell` binds `you`, not `me`;
|
|
98
|
+
`set` on a selector sets every match; and `no ""` is true. MIGRATION.md has the full list.
|
|
99
|
+
- ⚠ **`@hyperfixi/vite-plugin` emits a bundle on `@hyperfixi/engine`** (#1343). There is one
|
|
100
|
+
tier: the grammar modules the scan finds. It weighs 17.9 KB gzipped for three commands (3.x lite:
|
|
101
|
+
3.9 KB) and 34.4 KB for everything; 3.x fell back to 352 KB on `fetch`. htmx is not bundled.
|
|
102
|
+
Non-English scripts are translated as the engine reads them. `devFallback: 'everything'` is new,
|
|
103
|
+
and `'full'` / `'hybrid-complete'` mean the same. The plugin no longer depends on core.
|
|
104
|
+
- ⚠ **`@hyperfixi/behaviors` runs on the engine** (peer `@hyperfixi/engine`; upstream works too).
|
|
105
|
+
Each behavior is defined with `host.evaluate(source)` and written in upstream's idioms.
|
|
106
|
+
Toggleable's `target` parameter is now `targetEl`. `LokaScriptInstance` / `LokaScriptWindow`
|
|
107
|
+
are now `HyperscriptHost` / `HyperscriptWindow` (#1338).
|
|
108
|
+
- ⚠ **`@hyperfixi/speech` is an engine module** (#1358). Install it with
|
|
109
|
+
`register(...everything, speak)`. It is ESM-only and peers on the engine. `speak` takes
|
|
110
|
+
upstream's syntax (`speak <text> [with voice|rate|pitch|volume <x>]…`) and waits for the
|
|
111
|
+
utterance to end.
|
|
112
|
+
- ⚠ **The localized htmx vocabulary moved** from `@hyperfixi/core/vocab/htmx/{lang}.js` to
|
|
113
|
+
`@lokascript/htmx-adapter/vocab/{lang}.js`; the data is unchanged (#1349).
|
|
114
|
+
- **`@hyperfixi/intent-element`** renders an intent to English with the page's semantic bundle
|
|
115
|
+
and runs it through the host's `evaluate` (`NO_RENDERER` without one). It peers on
|
|
116
|
+
`@hyperfixi/engine` and `@lokascript/semantic` (#1339, #1356).
|
|
117
|
+
- **`@lokascript/semantic` writes upstream's spelling in English** for core-only forms (#1346).
|
|
118
|
+
For example, `has` becomes `matches`, `prepend` becomes `put … at start of`, and swap strategies
|
|
119
|
+
become `put … into` / `before` / `after`. This reaches `translate(…, 'en')`,
|
|
120
|
+
`render(node, 'en')`, both adapters and MCP `translate_to_english`. In `fromSemanticAST`, a
|
|
121
|
+
handler's `then` chain is now its body (#1359).
|
|
122
|
+
- **The language tools read the engine's parse** (#1356, #1359, #1365).
|
|
123
|
+
`@lokascript/language-server` and MCP `validate_hyperscript` report the engine's errors
|
|
124
|
+
(`source: 'engine'`). Hover and symbols come from `@lokascript/semantic`, and some long handlers
|
|
125
|
+
show fewer commands than in 3.x. Hyperscript mode flags exactly `new X()` and `toggle <element>`.
|
|
126
|
+
`@lokascript/compilation-service` rejects natural-language input the engine cannot read
|
|
127
|
+
(`ENGINE_PARSE_ERROR`), and its generated Playwright tests load `hyperfixi-hs.js`. The language
|
|
128
|
+
server, the MCP server and the compilation service now peer on `@hyperfixi/engine`.
|
|
129
|
+
- **MCP**: `get_bundle_config` recommends `hyperfixi-hs.js`, plus an `adapter` field for
|
|
130
|
+
non-English. `analyze_complexity` / `analyze_metrics` no longer count every comparison as a
|
|
131
|
+
decision. The `debug_*` tools point to `log` and `breakpoint`. `UNSUPPORTED_QUERY_LITERAL` is
|
|
132
|
+
gone (#1350, #1352, #1359, #1361, #1364).
|
|
133
|
+
- **`@hyperfixi/core/reference`, `/lsp-metadata`, `/metadata` describe the engine** (#1355,
|
|
134
|
+
#1363). They cover its 53 commands, adding `for`, `ask`, `answer` and `beep!`. Examples are in
|
|
135
|
+
upstream spelling and each is checked to parse; descriptions of core-only semantics (`pick`,
|
|
136
|
+
`beep`, `swap`) are fixed. `FEATURE_KEYWORDS` gains `install`, `when`, `live` and `bind`, and
|
|
137
|
+
`bundleInfo` holds one row.
|
|
138
|
+
- **Dependencies.** `@lokascript/i18n`, `@hyperfixi/testing-framework`, `@hyperfixi/vite-plugin`,
|
|
139
|
+
`@hyperfixi/behaviors`, `@hyperfixi/speech` and `@hyperfixi/intent-element` no longer depend
|
|
140
|
+
on core. Core drops `@lokascript/intent`, morphlex, tslib and its optional peers. Versions are
|
|
141
|
+
lockstep, so upgrade `@hyperfixi/*` and `@lokascript/*` together. `@hyperfixi/mcp-server`,
|
|
142
|
+
`@lokascript/framework` (tests) and `@hyperfixi/server-bridge` (tests) range on
|
|
143
|
+
`@lokascript/domains ^3.0.1`, the first domains release whose peers accept framework,
|
|
144
|
+
semantic and intent 4.x (`^3.1.0 || ^4.0.0`).
|
|
145
|
+
|
|
146
|
+
### Added
|
|
147
|
+
|
|
148
|
+
- **`@hyperfixi/engine` exports `expr`**, so a grammar module can live in another package
|
|
149
|
+
(#1358).
|
|
150
|
+
- **`@hyperfixi/core/ast-utils`'s `withEnginePositions`** gives interchange nodes the source
|
|
151
|
+
spans of the engine's parse (#1359).
|
|
152
|
+
|
|
153
|
+
### Fixed
|
|
154
|
+
|
|
155
|
+
- **`@hyperfixi/engine`** accepts upstream's `beep!` command (`beep! a, b`); 3.3.0 rejected it
|
|
156
|
+
(#1362).
|
|
157
|
+
- **`@hyperfixi/types-browser`** types `window.hyperfixi` / `window._hyperscript` as the engine's
|
|
158
|
+
`HyperfixiAPI`. 3.3.0 re-exported a `./globals` it never emitted, so `window.hyperfixi` was
|
|
159
|
+
untyped (#1356).
|
|
160
|
+
- **Semantic browser bundles** (#1351). Single-language and regional bundles (es, ja,
|
|
161
|
+
east-asian, …) registered no English, so the hyperscript adapter left scripts untranslated. They
|
|
162
|
+
now register it (+~2.2 KB gzipped) and export `translate`. The lite adapter finds any
|
|
163
|
+
`LokaScriptSemantic*` global.
|
|
164
|
+
- **`@lokascript/semantic`** (#1338, #1343, #1347). `/core` plus a language module no longer
|
|
165
|
+
throws "No patterns registered". `on click from (x or me)` parses in th and zh. A `js … end`
|
|
166
|
+
block no longer ends its handler in ja / ko / hi / tr / qu / bn. An options object's `}` is no
|
|
167
|
+
longer read as an SOV event name.
|
|
168
|
+
- **Language server and MCP** (#1359, #1363, #1365). `beep!` has hover docs. `set X to`
|
|
169
|
+
completions offer values. Hyperscript-mode errors land on the form, not line 0. Hover no longer
|
|
170
|
+
shows a second `on click`.
|
|
171
|
+
|
|
172
|
+
## [3.3.0] - 2026-10-02
|
|
173
|
+
|
|
174
|
+
The first publication of `@hyperfixi/engine`, the hyperscript engine meant to replace the one
|
|
175
|
+
in `@hyperfixi/core`, and the example gallery moved onto it.
|
|
176
|
+
|
|
177
|
+
### Added
|
|
178
|
+
|
|
179
|
+
- **`@hyperfixi/engine` is published.** A hyperscript engine written against upstream
|
|
180
|
+
`_hyperscript`'s source, with upstream's own test suite as the acceptance oracle (1,401 of
|
|
181
|
+
1,467 tests; the 66 known failures are upstream's internal API, sockets and workers). It
|
|
182
|
+
ships `dist/hyperfixi-hs.js`, a script-tag bundle of hyperscript and nothing else, 34.1 KB
|
|
183
|
+
gzipped, which 36 of the repository's example pages now load instead of `hyperfixi.js`. It
|
|
184
|
+
keeps two forms upstream lacks, `new X(...)` and `toggle <element>`; the other hyperfixi-only
|
|
185
|
+
forms are not in it. It is typed (`tsc --strict`, no `any`), built from modules, and exposes
|
|
186
|
+
upstream's public API shape plus one hook, `addSourceTransform`, which
|
|
187
|
+
`@lokascript/hyperscript-adapter` uses to run the 24 languages on it.
|
|
188
|
+
|
|
189
|
+
### Changed
|
|
190
|
+
|
|
191
|
+
- **Examples and docs are written in upstream `_hyperscript`'s spelling** wherever upstream has
|
|
192
|
+
one: `put Y into X` for the `swap` strategies, `debounced at 300ms`, `matches`, `set X's @a`,
|
|
193
|
+
`increment #count's textContent` (core counted in a bare `#count`; upstream does not),
|
|
194
|
+
`on mutation of childList from #x`, `my offsetLeft` in place of `measure x`. The multilingual
|
|
195
|
+
reader still accepts the old forms; the renderer writes upstream's. Corpus rows follow.
|
|
196
|
+
- **`@lokascript/semantic` renders `repeat for x in xs index i`** (was `with index`) and
|
|
197
|
+
`tell X show` (was `tell X to show`), upstream's spellings.
|
|
198
|
+
- **The examples' bundle loader** takes a per-page default (`data-default="hs"`), and `?bundle=hs`
|
|
199
|
+
switches any page to the engine bundle.
|
|
200
|
+
|
|
201
|
+
### Fixed
|
|
202
|
+
|
|
203
|
+
- **`@hyperfixi/core`**: `toggle *display of X` parsed and then threw.
|
|
204
|
+
- **Hybrid bundles (`hyperfixi-hx.js`)**: `increment` / `decrement` of a possessive wrote only
|
|
205
|
+
style properties; `increment #count's textContent` evaluated to the text and threw on
|
|
206
|
+
`querySelectorAll('0')`. They now write the property.
|
|
207
|
+
- **`@lokascript/semantic`**: a template-literal URL in a Korean handler was read as a custom
|
|
208
|
+
event name.
|
|
209
|
+
|
|
10
210
|
## [3.2.0] - 2026-09-30
|
|
11
211
|
|
|
12
212
|
A correctness release for multilingual hyperscript. The semantic parser behind
|
|
@@ -861,7 +1061,9 @@ _Synchronized version release. See git history for details._
|
|
|
861
1061
|
- npm access token stored in GitHub Secrets
|
|
862
1062
|
- 2FA recommended for npm organization
|
|
863
1063
|
|
|
864
|
-
[Unreleased]: https://github.com/codetalcott/hyperfixi/compare/v3.
|
|
1064
|
+
[Unreleased]: https://github.com/codetalcott/hyperfixi/compare/v3.3.0...HEAD
|
|
1065
|
+
[3.3.0]: https://github.com/codetalcott/hyperfixi/compare/v3.2.0...v3.3.0
|
|
1066
|
+
[3.2.0]: https://github.com/codetalcott/hyperfixi/compare/v3.1.0...v3.2.0
|
|
865
1067
|
[3.1.0]: https://github.com/codetalcott/hyperfixi/compare/v3.0.0...v3.1.0
|
|
866
1068
|
[2.10.0]: https://github.com/codetalcott/hyperfixi/compare/v2.9.0...v2.10.0
|
|
867
1069
|
[2.9.0]: https://github.com/codetalcott/hyperfixi/compare/v2.8.0...v2.9.0
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ attributes in 24 languages against the stock htmx library.
|
|
|
6
6
|
```html
|
|
7
7
|
<script src="htmx-i18n.global.js"></script>
|
|
8
8
|
<!-- this adapter (2.3 KB gz) -->
|
|
9
|
-
<script src="vocab/
|
|
9
|
+
<script src="vocab/es.js"></script>
|
|
10
10
|
<!-- vocab module(s) -->
|
|
11
11
|
<script src="htmx.js"></script>
|
|
12
12
|
<!-- upstream htmx v4 -->
|
|
@@ -25,15 +25,18 @@ This package is the htmx analog of
|
|
|
25
25
|
[`@lokascript/hyperscript-adapter`](../hyperscript-adapter) (which adapts
|
|
26
26
|
upstream `_hyperscript`), built on the hook/vocab pattern from
|
|
27
27
|
[loka-js](https://github.com/wmtalcott/loka-js) (which adapts the fixiproject
|
|
28
|
-
family). It
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
family). It replaces hyperfixi's embedded htmx-compat layer (the
|
|
29
|
+
`hyperfixi-hx*.js` bundles of `@hyperfixi/core` 3.x, retired in 4.0), which
|
|
30
|
+
_reimplemented_ htmx attributes on hyperfixi's own runtime. This adapter drives
|
|
31
31
|
the **real htmx** library.
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
The vocabulary is the generated modules in [`vocab/`](vocab), one
|
|
34
|
+
self-registering script per language, derived from `@lokascript/semantic`
|
|
35
|
+
profiles + `@lokascript/i18n` dictionaries (so `click` is `clic` here as in
|
|
36
|
+
hyperscript) plus a hand-authored table for the attributes that are not
|
|
37
|
+
hyperscript keywords. They ship in this package: from a CDN,
|
|
38
|
+
`https://unpkg.com/@lokascript/htmx-adapter/vocab/es.js`. (Until 4.0 they
|
|
39
|
+
shipped in `@hyperfixi/core`, as `vocab/htmx/{lang}.js`.)
|
|
37
40
|
|
|
38
41
|
## Mechanism
|
|
39
42
|
|
|
@@ -102,8 +105,8 @@ import {
|
|
|
102
105
|
|
|
103
106
|
The browser IIFE does all the wiring automatically and installs
|
|
104
107
|
`window.__hyperfixi_i18n.register` so the generated vocab modules
|
|
105
|
-
self-register. If the page
|
|
106
|
-
fan out to both
|
|
108
|
+
self-register. If the page already has a registry (core 3.x's
|
|
109
|
+
`hyperfixi-hx.js`), registrations fan out to both.
|
|
107
110
|
|
|
108
111
|
## Hyperscript `hx-on:` bodies (executor mode, opt-in)
|
|
109
112
|
|
|
@@ -122,7 +125,7 @@ wires itself:
|
|
|
122
125
|
<script src="hyperscript-i18n-es.global.js"></script>
|
|
123
126
|
<!-- translator: HyperscriptI18n.preprocess -->
|
|
124
127
|
<script src="htmx-i18n.global.js"></script>
|
|
125
|
-
<script src="vocab/
|
|
128
|
+
<script src="vocab/es.js"></script>
|
|
126
129
|
<script src="htmx.js"></script>
|
|
127
130
|
|
|
128
131
|
<section lang="es">
|
|
@@ -207,9 +210,11 @@ npm test --prefix packages/htmx-adapter # vitest, jsdom
|
|
|
207
210
|
npm run test:browser --prefix packages/htmx-adapter # Playwright e2e (build dist first)
|
|
208
211
|
```
|
|
209
212
|
|
|
210
|
-
The unit suite
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
The unit suite loads every generated `vocab/{lang}.js` module against this
|
|
214
|
+
adapter's registry, and its drift gate (`test/vocab-generator.test.ts`, also
|
|
215
|
+
`npm run check:vocab`) fails when a committed module differs from what the
|
|
216
|
+
generator emits — so a profile or dictionary change that moves a name fails
|
|
217
|
+
here rather than in a browser.
|
|
213
218
|
|
|
214
219
|
The Playwright suite drives **real vendored libraries** — htmx `4.0.0`,
|
|
215
220
|
htmx `2.0.10`, `_hyperscript` `0.9.93` (`test/browser/vendor/`) — verifying the
|
package/dist/htmx-i18n.global.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var HtmxI18n=(()=>{var B=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var ue=Object.getOwnPropertyNames;var fe=Object.prototype.hasOwnProperty;var de=(e,t)=>{for(var n in t)B(e,n,{get:t[n],enumerable:!0})},ge=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ue(t))!fe.call(e,o)&&o!==n&&B(e,o,{get:()=>t[o],enumerable:!(r=ce(t,o))||r.enumerable});return e};var pe=e=>ge(B({},"__esModule",{value:!0}),e);var ke={};de(ke,{EXTENSION_NAME:()=>m,canonicalizeElement:()=>R,canonicalizeTree:()=>p,installAutoSweep:()=>U,installResolverMode:()=>ne,langOf:()=>b,normLang:()=>g,register:()=>O,registerWith:()=>M,setBodyExecutor:()=>V,setBodyTranslator:()=>$,setNeutralizeOnClaim:()=>y,translateTriggerValue:()=>S});function g(e){return e?e.split(/[-_]/)[0].toLowerCase():"en"}function b(e){let t=e.getAttribute?.("data-hyperfixi-lang");if(t)return g(t);let n=e.closest?.("[data-hyperfixi-lang]");if(n)return g(n.getAttribute("data-hyperfixi-lang"));let r=e.closest?.("[lang]");return r?g(r.getAttribute("lang")):"en"}var A=new Map,_=new Set,T=new Set;function O(e,t){let n=g(e);A.set(n,t?.hyperfixi??{}),_.delete(n);for(let r of T)r()}function w(e){return A.get(e)}var K=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),me=e=>e.replace(/[A-Z]+/g,t=>t.toLowerCase()),X=new WeakMap;function h(e,t){if(K(e,t))return e[t];let n=X.get(e);if(!n){n=new Map;for(let r of Object.keys(e)){let o=me(r);o!==r&&!K(e,o)&&!n.has(o)&&n.set(o,e[r])}X.set(e,n)}return n.get(t)}function G(){return A.size>0}function Y(){return[...A.keys()]}function C(e){return T.add(e),()=>{T.delete(e)}}function Z(e){_.has(e)||(_.add(e),typeof console<"u"&&console.warn(`[htmx-i18n] No vocab registered for lang="${e}". Elements in this language scope keep their localized attribute names and htmx will not see them. Load the ${e} vocab module (
|
|
1
|
+
"use strict";var HtmxI18n=(()=>{var B=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var ue=Object.getOwnPropertyNames;var fe=Object.prototype.hasOwnProperty;var de=(e,t)=>{for(var n in t)B(e,n,{get:t[n],enumerable:!0})},ge=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ue(t))!fe.call(e,o)&&o!==n&&B(e,o,{get:()=>t[o],enumerable:!(r=ce(t,o))||r.enumerable});return e};var pe=e=>ge(B({},"__esModule",{value:!0}),e);var ke={};de(ke,{EXTENSION_NAME:()=>m,canonicalizeElement:()=>R,canonicalizeTree:()=>p,installAutoSweep:()=>U,installResolverMode:()=>ne,langOf:()=>b,normLang:()=>g,register:()=>O,registerWith:()=>M,setBodyExecutor:()=>V,setBodyTranslator:()=>$,setNeutralizeOnClaim:()=>y,translateTriggerValue:()=>S});function g(e){return e?e.split(/[-_]/)[0].toLowerCase():"en"}function b(e){let t=e.getAttribute?.("data-hyperfixi-lang");if(t)return g(t);let n=e.closest?.("[data-hyperfixi-lang]");if(n)return g(n.getAttribute("data-hyperfixi-lang"));let r=e.closest?.("[lang]");return r?g(r.getAttribute("lang")):"en"}var A=new Map,_=new Set,T=new Set;function O(e,t){let n=g(e);A.set(n,t?.hyperfixi??{}),_.delete(n);for(let r of T)r()}function w(e){return A.get(e)}var K=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),me=e=>e.replace(/[A-Z]+/g,t=>t.toLowerCase()),X=new WeakMap;function h(e,t){if(K(e,t))return e[t];let n=X.get(e);if(!n){n=new Map;for(let r of Object.keys(e)){let o=me(r);o!==r&&!K(e,o)&&!n.has(o)&&n.set(o,e[r])}X.set(e,n)}return n.get(t)}function G(){return A.size>0}function Y(){return[...A.keys()]}function C(e){return T.add(e),()=>{T.delete(e)}}function Z(e){_.has(e)||(_.add(e),typeof console<"u"&&console.warn(`[htmx-i18n] No vocab registered for lang="${e}". Elements in this language scope keep their localized attribute names and htmx will not see them. Load the ${e} vocab module (@lokascript/htmx-adapter/vocab/${e}.js) before htmx processes the page.`))}var v=null,L=null,z=new Set,N=new WeakMap,k=!0;function y(e){k=e}function V(e){v=e;for(let t of z)t()}function $(e){L=e}function j(){return v!==null}function J(e){return z.add(e),()=>{z.delete(e)}}function W(e){let t=new Set,n=N.get(e);if(n)for(let r of n.values())t.add(r.attrName);return t}function Q(e){let t=0;for(let n of W(e))n.startsWith("hx-on:")&&e.hasAttribute(n)&&(e.removeAttribute(n),t++);return t}function xe(e,t){return e.startsWith(":")?`htmx${e}`:h(t,e)??e}function D(e,t,n,r,o={}){if(!v)return!1;let i=t.indexOf(":");if(i<=0)return!1;let s=xe(t.slice(i+1),r),f=t.startsWith("hx-on:"),u=e.getAttribute(t)??"",c=N.get(e),a=c?.get(s);if(a)return a.attrName===t?(a.body!==u&&(a.body=u,a.translated=null),f&&k&&e.hasAttribute(t)?(e.removeAttribute(t),!0):!1):f&&(o.adapterCreated||k)&&e.hasAttribute(t)?(e.removeAttribute(t),!0):!1;let l={attrName:t,lang:n,body:u,translated:null};return e.addEventListener(s,d=>{if(v){l.translated===null&&(l.translated=l.lang!=="en"&&L?L(l.body,l.lang):l.body);try{v(l.translated,e,d)}catch(E){typeof console<"u"&&console.error(`[htmx-i18n] hx-on body execution failed (${t} \u2192 ${s})`,E)}}}),c||(c=new Map,N.set(e,c)),c.set(s,l),f&&k&&e.removeAttribute(t),!0}function P(e){let t=e;if(!v&&typeof t._hyperscript=="function"){let n=t._hyperscript;V((r,o,i)=>typeof n.evaluate=="function"?n.evaluate(r,{me:o,event:i}):n(r))}if(!L&&typeof t.HyperscriptI18n?.preprocess=="function"){let n=t.HyperscriptI18n.preprocess;$((r,o)=>n(r,o))}}var I=!1;function te(){return I}function be(e,t){let n=b(e);if(n==="en")return null;let r=w(n)?.attrs;if(!r)return null;for(let[o,i]of Object.entries(r))if(i===t&&e.hasAttribute?.(o))return o;return null}function ee(){let e=new Set;for(let t of Y()){let n=w(t)?.attrs??{};for(let[r,o]of Object.entries(n))o!=="hx-on"&&e.add(`[${r}]`)}return[...e]}function ne(e){if(!e?.config)throw new Error("[htmx-i18n] installResolverMode: htmx.config not found");let t=e.config;t.attributeResolver=be,t.additionalAttributeSelectors=ee();let n=C(()=>{t.additionalAttributeSelectors=ee()});return I=!0,()=>{n(),t.attributeResolver=null,t.additionalAttributeSelectors=[],I=!1}}var he=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),re=/^(?:hx|sse|ws)-/,ve=/,(?![^\[]*\])(?![^(]*\))(?![^<]*\/>)(?=(?:[^"']|"[^"]*"|'[^']*')*$)/,ie=e=>e.split(ve),se=ie;function ae(e){se=e??ie}function oe(e){return e==="hx-trigger"||e.startsWith("hx-trigger:")}function S(e,t){return se(e).map(n=>n.replace(/^(\s*)([^[\s]+)/,(r,o,i)=>he(t,i)?o+t[i]:r)).join(",")}var F=new WeakMap;function ye(e,t){let n=F.get(e);n||(n=new Set,F.set(e,n)),n.add(t)}function Ee(e,t){return F.get(e)?.has(t)??!1}function R(e){if(!e.attributes||e.attributes.length===0)return!1;let t=!1;for(let c of Array.from(e.attributes))if(re.test(c.name)){t=!0;break}if(!t)return!1;let n=j(),r=b(e);if(r==="en"&&!n)return!1;let o=w(r);if(r!=="en"&&!o&&(Z(r),!n))return!1;let i=o?.attrs??{},s=o?.events??{},f=!1;for(let c in s){f=!0;break}let u=!1;for(let c of Array.from(e.attributes)){let a=c.name;if(!re.test(a))continue;if(n&&a.startsWith("hx-on:")){D(e,a,r,s,{adapterCreated:Ee(e,a)})&&(u=!0);continue}if(oe(a)){if(f){let x=S(c.value,s);x!==c.value&&(e.setAttribute(a,x),u=!0)}continue}let l=h(i,a),d;if(!l){let x=a.indexOf(":");if(x>0){let le=a.slice(0,x);if(d=h(i,le),d){let H=a.slice(x+1);l=d==="hx-on"?`${d}:${h(s,H)??H}`:`${d}:${H}`}}}if(!l)continue;if(n&&d==="hx-on"){D(e,a,r,s)&&(u=!0);continue}if(l===a||e.hasAttribute(l))continue;let E=c.value;oe(l)&&(E=S(E,s)),e.setAttribute(l,E),ye(e,l),u=!0}return u}function p(e){if(!e||te()||!G()&&!j())return 0;let t=0;if(e instanceof Element&&R(e)&&t++,typeof e.querySelectorAll=="function")for(let n of Array.from(e.querySelectorAll("*")))R(n)&&t++;return t}var m="lokascript-i18n";function we(e,t,n){for(let r of t)if(e===r||e.startsWith(r)&&e.charAt(r.length)===n)return!0;return!1}function Ae(e){let t=e?.config,n=t&&"prefix"in t?t.prefix??"":"data-hx-",r=t?.metaCharacter||":",o=n?["hx-on",n+"on"]:["hx-on"];return{init(i){let s=i?.HCON?.split;typeof s=="function"&&ae(s.bind(i.HCON))},htmx_before_process(i){p(i)},htmx_before_process_node(i){p(i)},htmx_before_on_init(i){let s=W(i);if(s.size===0)return;let f=!1;for(let u of Array.from(i.attributes)){let c=u.name;if(!s.has(c)&&we(c,o,r)){f=!0;break}}if(!f)return!1;Q(i)},onEvent(i,s){if(i!=="htmx:beforeProcessNode")return;let u=s?.detail?.elt??(s?.target instanceof Element?s.target:null);u&&p(u)}}}function M(e){if(!e)return null;let t=Ae(e);return typeof e.registerExtension=="function"?e.registerExtension(m,t)===!1?(typeof console<"u"&&console.warn(`[htmx-i18n] htmx.registerExtension("${m}") returned false \u2014 the extension is not registered. If htmx.config.extensions (the <meta name="htmx-config"> allowlist) is set, add "${m}" to it. Swapped-in content will not be canonicalized; executor-mode claims fall back to removing canonical hx-on:* attrs.`),y(!0),null):(y(!1),"v4"):typeof e.defineExtension=="function"?(e.defineExtension(m,t),y(!0),"v2"):null}function U(e=document){let t=()=>{p(e.body??e.documentElement)},n=e.readyState==="complete",r=null;if(n)t();else{let s=()=>{n||(n=!0,r?.(),t())},f=e.defaultView;e.addEventListener("DOMContentLoaded",s),f?.addEventListener("load",s),r=()=>{e.removeEventListener("DOMContentLoaded",s),f?.removeEventListener("load",s)}}let o=C(()=>{n&&t()}),i=J(()=>{n&&t()});return()=>{r?.(),o(),i()}}var q="__hyperfixi_i18n";function Oe(){if(typeof window>"u")return;let e=window,t=e[q];if(t){let n=t.register.bind(t);e[q]={register:(r,o)=>{n(r,o),O(r,o)}};return}e[q]={register:O}}function Ce(){if(typeof window>"u"||typeof document>"u")return;let e=window;P(window),M(e.htmx)||document.addEventListener("DOMContentLoaded",()=>{!M(e.htmx)&&!e.htmx&&typeof console<"u"&&console.warn(`[htmx-i18n] window.htmx not found \u2014 the "${m}" extension was not registered. Dynamically swapped content will not be canonicalized (the initial document sweep still ran). Load htmx on this page.`)},{once:!0}),document.addEventListener("DOMContentLoaded",()=>P(window),{once:!0}),U(document)}Oe();Ce();return pe(ke);})();
|
|
2
2
|
//# sourceMappingURL=htmx-i18n.global.js.map
|