@lokascript/htmx-adapter 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 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/v3.3.0...HEAD
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
@@ -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/htmx/es.js"></script>
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 is **not** the same thing as hyperfixi's embedded htmx-compat layer
29
- (`packages/core/src/htmx/` — the `hyperfixi-hx*.js` bundles), which
30
- _reimplements_ htmx attributes on hyperfixi's own runtime. This adapter drives
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
- All three consumers share one vocabulary source: the generated modules under
34
- [`packages/core/vocab/htmx/`](../core/vocab/htmx), derived from
35
- `@lokascript/semantic` profiles + `@lokascript/i18n` dictionaries. `click` is
36
- `clic` everywhere.
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 also runs hyperfixi's embedded layer, registrations
106
- fan out to both registries.
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/htmx/es.js"></script>
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 includes a reuse guard that loads every generated
211
- `packages/core/vocab/htmx/{lang}.js` module against this adapter's registry, so
212
- generator drift fails here rather than in a browser.
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
@@ -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 (packages/core/vocab/htmx/${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);})();
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