@hyperfixi/patterns-reference 3.1.1 → 3.3.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +186 -1
  2. package/README.md +47 -36
  3. package/data/engine-verification.json +58 -65
  4. package/data/patterns.db +0 -0
  5. package/data/patterns.db.stamp +1 -0
  6. package/dist/api/index.d.mts +2 -2
  7. package/dist/api/index.d.ts +2 -2
  8. package/dist/api/index.js +198 -98
  9. package/dist/api/index.mjs +197 -100
  10. package/dist/{index-6GkHj5yJ.d.mts → index-CoDUfq2P.d.mts} +39 -3
  11. package/dist/{index-6GkHj5yJ.d.ts → index-CoDUfq2P.d.ts} +39 -3
  12. package/dist/index.d.mts +87 -13
  13. package/dist/index.d.ts +87 -13
  14. package/dist/index.js +261 -144
  15. package/dist/index.mjs +258 -146
  16. package/dist/{llm-B5nGz8V1.d.mts → llm-CCCSw-yp.d.ts} +21 -10
  17. package/dist/{llm-rEdJQScF.d.ts → llm-PxnriEZ_.d.mts} +21 -10
  18. package/dist/sync/index.d.mts +1 -1
  19. package/dist/sync/index.d.ts +1 -1
  20. package/dist/sync/index.js +4 -1
  21. package/dist/sync/index.mjs +4 -1
  22. package/package.json +16 -16
  23. package/src/adapters/llm-adapter.ts +64 -42
  24. package/src/api/engine-filter.ts +37 -0
  25. package/src/api/llm.ts +54 -64
  26. package/src/api/patterns.ts +92 -30
  27. package/src/api/roles.ts +6 -4
  28. package/src/api/translations.ts +34 -27
  29. package/src/database/connection.ts +16 -4
  30. package/src/html-snippets.ts +39 -10
  31. package/src/index.ts +12 -2
  32. package/src/registry/patterns-provider.ts +3 -1
  33. package/src/sync/db-stamp.ts +7 -4
  34. package/src/sync/markup-attributes.ts +15 -0
  35. package/src/sync/verify-parses.ts +42 -0
  36. package/src/types/better-sqlite3.d.ts +2 -0
  37. package/src/types/index.ts +44 -2
  38. package/src/sync/span-mask.ts +0 -166
  39. package/src/sync/translation-checks.ts +0 -282
package/CHANGELOG.md CHANGED
@@ -7,6 +7,189 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [3.3.0] - 2026-10-02
11
+
12
+ The first publication of `@hyperfixi/engine`, the hyperscript engine meant to replace the one
13
+ in `@hyperfixi/core`, and the example gallery moved onto it.
14
+
15
+ ### Added
16
+
17
+ - **`@hyperfixi/engine` is published.** A hyperscript engine written against upstream
18
+ `_hyperscript`'s source, with upstream's own test suite as the acceptance oracle (1,401 of
19
+ 1,467 tests; the 66 known failures are upstream's internal API, sockets and workers). It
20
+ ships `dist/hyperfixi-hs.js`, a script-tag bundle of hyperscript and nothing else, 34.1 KB
21
+ gzipped, which 36 of the repository's example pages now load instead of `hyperfixi.js`. It
22
+ keeps two forms upstream lacks, `new X(...)` and `toggle <element>`; the other hyperfixi-only
23
+ forms are not in it. It is typed (`tsc --strict`, no `any`), built from modules, and exposes
24
+ upstream's public API shape plus one hook, `addSourceTransform`, which
25
+ `@lokascript/hyperscript-adapter` uses to run the 24 languages on it.
26
+
27
+ ### Changed
28
+
29
+ - **Examples and docs are written in upstream `_hyperscript`'s spelling** wherever upstream has
30
+ one: `put Y into X` for the `swap` strategies, `debounced at 300ms`, `matches`, `set X's @a`,
31
+ `increment #count's textContent` (core counted in a bare `#count`; upstream does not),
32
+ `on mutation of childList from #x`, `my offsetLeft` in place of `measure x`. The multilingual
33
+ reader still accepts the old forms; the renderer writes upstream's. Corpus rows follow.
34
+ - **`@lokascript/semantic` renders `repeat for x in xs index i`** (was `with index`) and
35
+ `tell X show` (was `tell X to show`), upstream's spellings.
36
+ - **The examples' bundle loader** takes a per-page default (`data-default="hs"`), and `?bundle=hs`
37
+ switches any page to the engine bundle.
38
+
39
+ ### Fixed
40
+
41
+ - **`@hyperfixi/core`**: `toggle *display of X` parsed and then threw.
42
+ - **Hybrid bundles (`hyperfixi-hx.js`)**: `increment` / `decrement` of a possessive wrote only
43
+ style properties; `increment #count's textContent` evaluated to the text and threw on
44
+ `querySelectorAll('0')`. They now write the property.
45
+ - **`@lokascript/semantic`**: a template-literal URL in a Korean handler was read as a custom
46
+ event name.
47
+
48
+ ## [3.2.0] - 2026-09-30
49
+
50
+ A correctness release for multilingual hyperscript. The semantic parser behind
51
+ `translate()`, `@lokascript/hyperscript-adapter`, MCP `translate_code` and hyperfixi's
52
+ non-English path now keeps whole programs that it used to shorten or drop: values,
53
+ conditions, loops and handler heads. Every value shape in a generated matrix of 4,205
54
+ (executed in 24 languages, directly and through the adapter, against upstream
55
+ \_hyperscript) now matches upstream, apart from two documented differences. Core
56
+ matches upstream \_hyperscript on more forms.
57
+
58
+ ### Added
59
+
60
+ - **Counted loops are written in each language's own words**: es `repetir 3 veces`,
61
+ fr `répéter 3 fois`, ja `3 回 を 繰り返し`, hi `3 बार को दोहराएं`, where translations
62
+ wrote English `times` in 18 languages and English `repeat` in the SOV six. English
63
+ `times`/`repeat` and each language's other count words (es `vez`, ru `раза`, …) still
64
+ read. 18 i18n dictionaries gain a `temporal.times` word.
65
+ - **Variable names that are words of the target language.** A variable spelled like a
66
+ structure word (es `si`, pl `w`, tr `al`) is written in parentheses, `(si)`, where the
67
+ plain translation would be misread, and read back as the variable. The language server
68
+ warns (`name-collision`, with a rename quick fix), MCP `validate_hyperscript` reports
69
+ `NAME_COLLISION`, and `translate_code` warns when a variable reads as a value word in
70
+ the target (tl `ako` is `me`). `@lokascript/semantic` exports `nameCollision`,
71
+ `findNameCollisions` and `findTranslationCollisions`.
72
+ - Event-handler modifiers (`once`, `debounced at`, `throttled at`, `from`) render in every
73
+ language and are scored by the fidelity signals.
74
+ - `of`-paths and pseudo-commands (`reset() the closest <form/>`) survive translation.
75
+ - `@lokascript/hyperscript-adapter`'s host gate also rejects a translation that reads a
76
+ reference as a handler's event (`on click on me toggle .active`, an empty click handler
77
+ plus a handler for an event named `me`), falling back to the author's text with a
78
+ warning; such a translation used to parse cleanly and do nothing.
79
+ - **Localized htmx attributes: all 23 non-English languages now cover
80
+ every attribute the _Hypermedia Systems_ book's code listings use** —
81
+ `hx-vals`, `hx-select`, `hx-swap-oob` and `hx-sync` join the Contact.app
82
+ twelve (`hx-値`, `hx-valores`, `hx-값`, `hx-werte`, `hx-選択`, `hx-selección`,
83
+ `hx-seçim`, `hx-auswahl`, `hx-sélection`, `hx-选择`, …). tr/de/fr/zh are new
84
+ in the table: the Contact.app seven they lacked (`hx-sil`, `hx-löschen`,
85
+ `hx-supprimer`, `hx-删除`, …) plus audited trigger/swap primaries following
86
+ loka-js (`hx-tetikleyici`, `hx-auslöser`, `hx-déclencheur`, `hx-替换`; the
87
+ profile words `hx-tetikle`, `hx-auslösen`, `hx-déclencher`, `hx-交换` still
88
+ resolve). de gains a lowercase `hx-ziel`: the profile's `hx-Ziel` could never
89
+ match a parsed attribute, since HTML lowercases attribute names. The other
90
+ 15 languages (ar, bn, he, hi, id, it, ms, pl, qu, ru, sw, th, tl, uk, vi)
91
+ are unreviewed drafts, every entry flagged `lowConfidence`; they also gain
92
+ the trigger heads their dictionaries left in English (ms and tl all six,
93
+ vi/he/ar some). id gains `hx-sasaran` for a target that was the English
94
+ identity; tl keeps `hx-target` on purpose. `hx-ext` is left in English on
95
+ purpose: htmx 4 removed it. The vocab table gains an `events` block for
96
+ trigger heads the i18n dictionaries do not name; ja, es, pt and ko author
97
+ the DOM `search` event (`検索`, `buscar`, `검색`), which the book's and
98
+ Contact.app's search box fires. htmx's own trigger words (`revealed`,
99
+ `every`) stay English, like the `delay:` / `from:` modifiers.
100
+ - Adapter-only vocab keys now resolve from the authored table alone, never
101
+ from a semantic profile: 22 profiles carry a `select` keyword that means
102
+ mark/highlight text (de `markieren`, tr `vurgula`), and it would otherwise
103
+ have shipped as `hx-select` in 22 unreviewed languages.
104
+
105
+ - **Localized htmx attributes: ja, es, pt and ko now cover every attribute the
106
+ _Hypermedia Systems_ Contact.app uses** — `hx-post`, `hx-delete`,
107
+ `hx-confirm`, `hx-push-url`, `hx-boost`, `hx-indicator` and `hx-include` join
108
+ the existing five (e.g. `hx-削除`, `hx-eliminar`, `hx-excluir`, `hx-삭제`).
109
+ `hx-indicator` / `hx-include` localize under `@hyperfixi/htmx-adapter` (stock
110
+ htmx implements them; the embedded layer does not).
111
+ - **Vocab aliases.** Several localized names may map to one attribute or event;
112
+ the first is the form to teach, later ones keep already-authored pages
113
+ working. Core's embedded orchestrator now reads whichever form an element
114
+ carries (it previously kept a single name per attribute).
115
+
116
+ ### Changed
117
+
118
+ - **Rendered vocabulary** (owner decisions): `null` is written `null` in ar, hi, id, qu,
119
+ sw, th and tr, where it shared the word for `empty`; hi writes `no` as `कोई नहीं`; qu
120
+ writes `and` as `hinallataq`; tl and tr write `includes` with `contains`' word (both
121
+ engines read the two as one operator).
122
+ - `@lokascript/semantic` exports its real `VERSION` (it was `0.1.0` since the first
123
+ release); browser bundles report `<version>-<bundle>`.
124
+ - MCP `translate_hyperscript` is described accurately: it uses the same semantic engine as
125
+ `translate_code`, without the verification.
126
+ - **Audited primaries for `hx-trigger` / `hx-swap`** in ja (`hx-トリガー`,
127
+ `hx-置換`), es (`hx-disparador`, `hx-intercambio`), pt (`hx-gatilho`,
128
+ `hx-troca`) and ko (`hx-교체`), following loka-js's terminology reviews. The
129
+ names that shipped before (`hx-引き金`, `hx-disparar`, …) still resolve.
130
+ - The vocab modules are regenerated against the current i18n dictionaries.
131
+ **No working name was removed** — 141 retired event names and three attribute
132
+ names are kept as aliases. One name changed meaning with its dictionary: sw
133
+ `panya_juu` is now `mouseup` (was `mouseover`).
134
+
135
+ ### Fixed
136
+
137
+ - **Translations that lost code** (semantic parse and render, in every language):
138
+ - `get` of a literal (`get "hello"`, `get 3`, `get true`) dropped the whole command; an
139
+ object literal after `get` was cut to `get {`.
140
+ - Loops keep their extent and body; `repeat until` stops; a loop keeps its index
141
+ variable, the tail after an `if` inside it, and the command after an empty loop its own
142
+ `end` closes; a count may be any value (a variable, `$n`, `it`, a possessive), where
143
+ some translations read `forever`, a silent infinite loop.
144
+ - Handler heads keep `or` events, filters and event parameters; a translated
145
+ `wait for <event>` waits instead of throwing; behaviors keep their handlers and init
146
+ blocks; an else-if chain shares one `end`.
147
+ - Values keep their comparison phrases (`is equal to`, `includes`, `is an Element`, …),
148
+ `and`/`or`/`not`, `mod`, possessive and `of` chains, object and array literals, every
149
+ conversion core supports (`as Int`, `as Fixed:2`, piped conversions), unary minus and
150
+ property paths; `true`/`false`/`null` keep their meaning.
151
+ - Commands keep `put … into <variable>`, `tell … to show`, fetch's `do not throw` and
152
+ response type, event-source/socket URLs, show/hide `with` strategies, `go`/`scroll`
153
+ positions, `${…}` URLs, core's `has`, and a class query's `in` scope.
154
+ - **`@hyperfixi/core` follows upstream \_hyperscript**:
155
+ - `X of Y` binds as property access, and the X of a null target is null.
156
+ - `increment` reads its amount and counter as upstream does, and writing an object's
157
+ property through `'s`/`of` works.
158
+ - A loop's count reads as upstream's `index < times` does: `"6.5"` loops 7 times and
159
+ `"6abc"` none, in the full runtime and in the hybrid bundles (`hyperfixi-hx.js`,
160
+ plugin bundles), which read `parseInt`.
161
+ - Blocks close at the end of input; `morph … to`; `render … with name: value`; `beep!`
162
+ as an expression; `transition`'s owners, several properties, `from` and `using`; three
163
+ handler forms from _Hypermedia Systems_; four upstream-valid forms that compiled and
164
+ then failed at run time; `.item in #list` keeps its scope; `on click once` fires on
165
+ the first click.
166
+ - htmx: camelCase event names survive an attribute name.
167
+ - MCP: the validators report what the parsers actually did.
168
+ - The AOT compiler (experimental): loops were compiled to `while (true)`; targets,
169
+ property access, scoped queries, `empty` and variable scope now compile to what they
170
+ mean.
171
+ - `@lokascript/hyperscript-adapter` and `@hyperscript-tools/multilingual` READMEs: the
172
+ Japanese quickstart example was a dead button, and the multi-language example loaded
173
+ only the Spanish bundle; the examples are now native and run in a test. Bundle sizes are
174
+ measured.
175
+ - Bare CDN URLs now serve a browser bundle: `unpkg.com/@lokascript/hyperscript-adapter@3` (and
176
+ jsDelivr) served `dist/index.cjs`, which throws in a `<script>` tag. The adapter,
177
+ `@hyperscript-tools/multilingual`, `@lokascript/semantic`, `@hyperfixi/core` and
178
+ `@lokascript/htmx-adapter` declare `unpkg`/`jsdelivr` entries.
179
+ - `hyperfixi-multilingual.js`'s error names the semantic bundle that exists (the full
180
+ `browser.global.js`, the only one that defines `LokaScriptSemantic`).
181
+ - READMEs: `@lokascript/i18n` no longer claims to translate (and its `/lsp` export and CLI,
182
+ which do not exist, are gone); `@lokascript/semantic`, `@hyperfixi/vite-plugin` and
183
+ `@hyperfixi/core` have correct package names, API calls, language lists (24) and measured
184
+ bundle sizes.
185
+ - Dependencies: the js-yaml and smol-toml advisories; Vite 8, vitest 5 and happy-dom 20.14.
186
+ - **Vietnamese `hx-get` / `hx-target` / `hx-swap` / `hx-trigger` / `sse-swap`
187
+ never worked**: the names were emitted with spaces (`hx-lấy giá trị`), which
188
+ HTML reads as three attributes. They are now hyphen-joined
189
+ (`hx-lấy-giá-trị`), like vi's existing `hx-trực-tiếp`.
190
+ - 29 multi-word event names (ar, vi) were removed from the vocab modules: an
191
+ event is a single token of an `hx-trigger` value, so they could never match.
192
+
10
193
  ## [3.1.1] - 2026-09-04
11
194
 
12
195
  ### Fixed
@@ -716,7 +899,9 @@ _Synchronized version release. See git history for details._
716
899
  - npm access token stored in GitHub Secrets
717
900
  - 2FA recommended for npm organization
718
901
 
719
- [Unreleased]: https://github.com/codetalcott/hyperfixi/compare/v3.1.0...HEAD
902
+ [Unreleased]: https://github.com/codetalcott/hyperfixi/compare/v3.3.0...HEAD
903
+ [3.3.0]: https://github.com/codetalcott/hyperfixi/compare/v3.2.0...v3.3.0
904
+ [3.2.0]: https://github.com/codetalcott/hyperfixi/compare/v3.1.0...v3.2.0
720
905
  [3.1.0]: https://github.com/codetalcott/hyperfixi/compare/v3.0.0...v3.1.0
721
906
  [2.10.0]: https://github.com/codetalcott/hyperfixi/compare/v2.9.0...v2.10.0
722
907
  [2.9.0]: https://github.com/codetalcott/hyperfixi/compare/v2.8.0...v2.9.0
package/README.md CHANGED
@@ -10,11 +10,16 @@ npm install @hyperfixi/patterns-reference
10
10
 
11
11
  ## Quick Start
12
12
 
13
- The package ships with a **pre-populated SQLite database** containing:
13
+ The package ships with a **pre-populated SQLite database** — built at publish
14
+ time from the released source, the same database CI's gates judge — containing
15
+ (counts as of 2026-09-25):
14
16
 
15
- - 164 code examples covering hyperscript commands and real-world UI patterns
16
- - 3,936 translations (164 patterns × 24 languages)
17
- - 648 LLM few-shot examples for code generation
17
+ - 168 code examples covering hyperscript commands and real-world UI patterns,
18
+ each with the engine(s) mechanically verified to run it (`engine`: `both`,
19
+ `lokascript` = hyperfixi, `hyperscript` = upstream _hyperscript)
20
+ - 4,032 translations (168 patterns × 24 languages)
21
+ - ~660 LLM few-shot examples for code generation (an example no engine runs is
22
+ never served)
18
23
 
19
24
  No setup required - just install and use:
20
25
 
@@ -61,12 +66,20 @@ getPatternsByCategory(category: string): Promise<Pattern[]>
61
66
  // Get patterns containing a specific command
62
67
  getPatternsByCommand(command: string): Promise<Pattern[]>
63
68
 
64
- // Full-text search across title, code, and description
69
+ // Full-text search across title, code, and description (and, with
70
+ // `language`, that language's translation)
65
71
  searchPatterns(query: string, options?: SearchOptions): Promise<Pattern[]>
66
72
 
67
73
  // Get all patterns (paginated)
68
74
  getAllPatterns(options?: SearchOptions): Promise<Pattern[]>
69
75
 
76
+ // SearchOptions — every filter applies, then the page (limit/offset):
77
+ // category the pattern's category
78
+ // difficulty 'beginner' | 'intermediate' | 'advanced', inferred from the code
79
+ // language patterns usable in that language: a translation that parses
80
+ // there, or markup with no hyperscript to translate
81
+ // engine 'hyperscript' | 'lokascript' | 'both', or null for unverified
82
+
70
83
  // Get pattern statistics
71
84
  getPatternStats(): Promise<PatternStats>
72
85
  ```
@@ -134,8 +147,8 @@ These scripts are for contributors regenerating the database. **End users don't
134
147
  | `npm run db:init:force` | Reinitialize database (overwrites existing) |
135
148
  | `npm run sync:translations` | Generate translations for all 24 languages |
136
149
  | `npm run seed:llm` | Generate LLM few-shot examples |
137
- | `npm run validate` | Validate all patterns parse correctly |
138
- | `npm run validate:fix` | Validate and update verified_parses flag |
150
+ | `npm run verify` | Re-measure `verified_parses` (populate already does) |
151
+ | `npm run verify:engines` | Re-verify `engine` on both engines; commit the JSON |
139
152
  | `npm run build` | Build the package |
140
153
  | `npm test` | Run tests in watch mode |
141
154
  | `npm run test:run` | Run tests once |
@@ -146,42 +159,43 @@ These scripts are for contributors regenerating the database. **End users don't
146
159
 
147
160
  Pattern source code from the hyperscript cookbook.
148
161
 
149
- | Column | Type | Description |
150
- | ----------- | ---- | ------------------------------------- |
151
- | id | TEXT | Unique identifier |
152
- | title | TEXT | Human-readable title |
153
- | raw_code | TEXT | Hyperscript code |
154
- | description | TEXT | Pattern description |
155
- | feature | TEXT | Category (e.g., 'class-manipulation') |
156
- | created_at | TEXT | Creation timestamp |
162
+ | Column | Type | Description |
163
+ | ----------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------- |
164
+ | id | TEXT | Unique identifier |
165
+ | title | TEXT | Human-readable title |
166
+ | raw_code | TEXT | Hyperscript code |
167
+ | description | TEXT | Pattern description |
168
+ | feature | TEXT | Category (e.g., 'class-manipulation') |
169
+ | engine | TEXT | Engines verified to run it: `both`, `lokascript` (hyperfixi), `hyperscript` (upstream), or NULL (neither) — mechanical, CI-checked |
170
+ | created_at | TEXT | Creation timestamp |
157
171
 
158
172
  ### pattern_translations
159
173
 
160
174
  Multilingual translations of patterns.
161
175
 
162
- | Column | Type | Description |
163
- | --------------- | ------- | -------------------------------- |
164
- | id | INTEGER | Auto-increment ID |
165
- | code_example_id | TEXT | Foreign key to code_examples |
166
- | language | TEXT | Language code (en, ja, es, etc.) |
167
- | hyperscript | TEXT | Translated code |
168
- | word_order | TEXT | SVO, SOV, VSO, or V2 |
169
- | confidence | REAL | Translation confidence (0-1) |
170
- | verified_parses | INTEGER | Whether translation parses (0/1) |
176
+ | Column | Type | Description |
177
+ | --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ |
178
+ | id | INTEGER | Auto-increment ID |
179
+ | code_example_id | TEXT | Foreign key to code_examples |
180
+ | language | TEXT | Language code (en, ja, es, etc.) |
181
+ | hyperscript | TEXT | Translated code |
182
+ | word_order | TEXT | SVO, SOV, VSO, or V2 |
183
+ | confidence | REAL | Translation confidence (0-1) |
184
+ | verified_parses | INTEGER | 1 when the semantic parser accepts every hyperscript body of the row in its language (measured at sync; says nothing about fidelity) |
171
185
 
172
186
  ### llm_examples
173
187
 
174
188
  Prompt/completion pairs for few-shot learning.
175
189
 
176
- | Column | Type | Description |
177
- | --------------- | ------- | ---------------------------- |
178
- | id | INTEGER | Auto-increment ID |
179
- | code_example_id | TEXT | Foreign key to code_examples |
180
- | language | TEXT | Language code |
181
- | prompt | TEXT | Natural language prompt |
182
- | completion | TEXT | Hyperscript code |
183
- | quality_score | REAL | Quality rating (0-1) |
184
- | usage_count | INTEGER | Retrieval count |
190
+ | Column | Type | Description |
191
+ | --------------- | ------- | ----------------------------- |
192
+ | id | INTEGER | Auto-increment ID |
193
+ | code_example_id | TEXT | Foreign key to code_examples |
194
+ | language | TEXT | Language code |
195
+ | prompt | TEXT | Natural language prompt |
196
+ | completion | TEXT | Hyperscript code |
197
+ | quality_score | REAL | Quality rating (0-1) |
198
+ | usage_count | INTEGER | Deprecated: reads never count |
185
199
 
186
200
  ## Supported Languages
187
201
 
@@ -249,9 +263,6 @@ npm run populate
249
263
  # Run tests
250
264
  npm test
251
265
 
252
- # Validate translations
253
- npm run validate
254
-
255
266
  # Build
256
267
  npm run build
257
268
  ```