@dom-expressions/tagged-jsx 0.50.0-next.15
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 +96 -0
- package/LICENSE +21 -0
- package/README.md +259 -0
- package/dist/index.d.mts +12544 -0
- package/dist/index.mjs +2 -0
- package/package.json +32 -0
- package/src/index.ts +2 -0
- package/src/parse.ts +257 -0
- package/src/tagged-jsx.ts +247 -0
- package/src/tokenize.ts +260 -0
- package/src/types.ts +69 -0
- package/tests/core.ts +27 -0
- package/tests/parse.test.ts +971 -0
- package/tests/tagged-jsx.test.ts +1119 -0
- package/tests/tokenize.test.ts +1019 -0
- package/tsconfig.json +15 -0
- package/tsdown.config.mjs +5 -0
- package/vitest.config.ts +13 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# tagged-jsx-dom-expressions
|
|
2
|
+
|
|
3
|
+
## 0.50.0-next.15
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 402ead1: Rename the prerelease `sld-dom-expressions` package to `tagged-jsx-dom-expressions`, with matching public API names: `createTaggedJSXRuntime`, `TaggedJSXInstance`, and the `.jsx` self-reference tag.
|
|
8
|
+
- df03fb8: Move all packages under the `@dom-expressions` npm scope with new names:
|
|
9
|
+
- `dom-expressions` → `@dom-expressions/runtime`
|
|
10
|
+
- `babel-plugin-jsx-dom-expressions` → `@dom-expressions/babel-plugin-jsx`
|
|
11
|
+
- `jsx-dom-expressions-compiler` → `@dom-expressions/jsx-compiler`
|
|
12
|
+
- `hyper-dom-expressions` → `@dom-expressions/hyperscript`
|
|
13
|
+
- `tagged-jsx-dom-expressions` → `@dom-expressions/tagged-jsx`
|
|
14
|
+
|
|
15
|
+
The old unscoped names stop receiving `next` prereleases and remain in use
|
|
16
|
+
only by the Solid 1.x maintenance line published from `main`.
|
|
17
|
+
|
|
18
|
+
`lit-dom-expressions` is dropped from the prerelease line; it has been
|
|
19
|
+
superseded by `@dom-expressions/tagged-jsx`.
|
|
20
|
+
|
|
21
|
+
`@dom-expressions/jsx-compiler` now distributes prebuilt native binaries
|
|
22
|
+
through per-platform packages (`@dom-expressions/jsx-compiler-darwin-x64`,
|
|
23
|
+
`-darwin-arm64`, `-linux-x64-gnu`, `-linux-arm64-gnu`, `-win32-x64-msvc`)
|
|
24
|
+
resolved automatically via `optionalDependencies`, instead of shipping a
|
|
25
|
+
binary inside the main package.
|
|
26
|
+
|
|
27
|
+
## 0.50.0-next.14
|
|
28
|
+
|
|
29
|
+
## 0.50.0-next.13
|
|
30
|
+
|
|
31
|
+
## 0.50.0-next.12
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- 54880f4: Fix SLD templates so top-level element siblings each get their own template, allowing adjacent top-level expressions to update and clean up correctly.
|
|
36
|
+
|
|
37
|
+
## 0.50.0-next.11
|
|
38
|
+
|
|
39
|
+
### Patch Changes
|
|
40
|
+
|
|
41
|
+
- d5cd499: Remove `on:` namespace event support from compiler, runtime, JSX types, and renderer packages.
|
|
42
|
+
|
|
43
|
+
## 0.50.0-next.10
|
|
44
|
+
|
|
45
|
+
## 0.50.0-next.9
|
|
46
|
+
|
|
47
|
+
### Patch Changes
|
|
48
|
+
|
|
49
|
+
- 9994328: Support line and block comments inside SLD tags.
|
|
50
|
+
|
|
51
|
+
## 0.50.0-next.8
|
|
52
|
+
|
|
53
|
+
## 0.50.0-next.7
|
|
54
|
+
|
|
55
|
+
## 0.50.0-next.6
|
|
56
|
+
|
|
57
|
+
### Patch Changes
|
|
58
|
+
|
|
59
|
+
- a843315: Fix SLD `<template>` rendering so dynamic expressions are inserted into inert template content.
|
|
60
|
+
- a8a8f81: Inline `csstype` in the `sld-dom-expressions` build output so the published type declarations do not require consumers to resolve that transitive JSX type dependency separately.
|
|
61
|
+
|
|
62
|
+
## 0.50.0-next.5
|
|
63
|
+
|
|
64
|
+
## 0.50.0-next.4
|
|
65
|
+
|
|
66
|
+
## 0.50.0-next.3
|
|
67
|
+
|
|
68
|
+
### Patch Changes
|
|
69
|
+
|
|
70
|
+
- 8f56bc8: Add `sld-dom-expressions`: an AST-based tagged-template runtime that avoids runtime code generation (CSP-safe) and supports a named component registry for tooling-friendly templates.
|
|
71
|
+
- 4dae801: Normalize the `repository` field in every package to the standard npm
|
|
72
|
+
convention: a `git+https://github.com/ryansolid/dom-expressions.git` URL
|
|
73
|
+
with a `directory` pointing at the package within the monorepo. Restores
|
|
74
|
+
"View source" / "Open in repo" links on the npm registry and unblocks
|
|
75
|
+
tooling that resolves source from package metadata.
|
|
76
|
+
- 5463c56: `createSLDRuntime(runtime)` now returns a ready-to-use tag directly (with an empty component registry) instead of a factory that needs a second call. Components are registered via `.define({ ... })` on the returned tag, which already existed for derivation. This removes the awkward `createSLDRuntime(r)({})` for the no-components case and makes the runtime-binding step single-purpose.
|
|
77
|
+
|
|
78
|
+
Migration:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
// before
|
|
82
|
+
const sld = createSLDRuntime(runtime)({ For, Show });
|
|
83
|
+
|
|
84
|
+
// after
|
|
85
|
+
const sld = createSLDRuntime(runtime).define({ For, Show });
|
|
86
|
+
|
|
87
|
+
// no components case
|
|
88
|
+
const sld = createSLDRuntime(runtime);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- f32587f: Apply the single-node flatten uniformly so an `sld` template that resolves to one node/value returns it as a scalar (matching the existing behaviour of templateless paths). This lets downstream `insert` take the fast scalar path instead of reconciling a one-element array. The tag's return type is updated to `JSX.Element` to reflect the actual scalar-or-array shape; consumers that iterate or spread should normalize via `Array.isArray(result) ? result : [result]`.
|
|
92
|
+
- bacbd0c: Expose `Runtime`, `ComponentRegistry`, and `FunctionComponent` from the
|
|
93
|
+
package entry so consumers wiring a custom reactive core can type their
|
|
94
|
+
runtime object. Fix `Runtime.spread`'s `skipChildren` parameter type from
|
|
95
|
+
`Boolean` to `boolean`. Mark the package as `sideEffects: false` so
|
|
96
|
+
bundlers can tree-shake unused exports.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018-2019 Ryan Carniato
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# @dom-expressions/tagged-jsx
|
|
2
|
+
|
|
3
|
+
A tagged-template runtime for fine-grained signals libraries such as Solid.js.
|
|
4
|
+
Any signals library can be hooked into `html` by implementing a `Runtime` adapter.
|
|
5
|
+
|
|
6
|
+
`html` parses templates at runtime and installs reactive bindings against the
|
|
7
|
+
resulting DOM. Component references are real JavaScript values — either a name
|
|
8
|
+
registered via `.define()` or an expression hole — never a string parsed at
|
|
9
|
+
render time.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install @dom-expressions/tagged-jsx
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Tooling
|
|
18
|
+
|
|
19
|
+
For editor support, the
|
|
20
|
+
[Tagged JSX Tools VS Code extension](https://marketplace.visualstudio.com/items?itemName=DanielRKling.tagged-jsx-vscode)
|
|
21
|
+
provides syntax highlighting, formatting, conversion commands, and TypeScript
|
|
22
|
+
diagnostics for JSX inside tagged template literals.
|
|
23
|
+
|
|
24
|
+
## Quick start
|
|
25
|
+
|
|
26
|
+
`createTaggedJSXRuntime(runtime)` returns a ready-to-use tag bound to the runtime of a signals library.
|
|
27
|
+
Components are registered via `.define({ ... })`, which returns a new tag with the
|
|
28
|
+
combined registry.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { createTaggedJSXRuntime } from "@dom-expressions/tagged-jsx";
|
|
32
|
+
|
|
33
|
+
// In this example, we will specifically connect Solid.js to tagged JSX, but any
|
|
34
|
+
// signals-style library could export a compatible interface.
|
|
35
|
+
import * as web from "@solidjs/web";
|
|
36
|
+
|
|
37
|
+
import { For, Show, createSignal } from "solid-js";
|
|
38
|
+
import { render } from "@solidjs/web";
|
|
39
|
+
|
|
40
|
+
// This creates a tagged JSX template tag that is reactive specifically to
|
|
41
|
+
// Solid.js signals by passing in the Solid.js web runtime, and registers
|
|
42
|
+
// two components for use via PascalCase tag names inside of the template
|
|
43
|
+
// strings.
|
|
44
|
+
const html = createTaggedJSXRuntime(web).define({ For, Show });
|
|
45
|
+
|
|
46
|
+
function Counter() {
|
|
47
|
+
const [count, setCount] = createSignal(0);
|
|
48
|
+
|
|
49
|
+
// Finally, write reactive templates!
|
|
50
|
+
return html`
|
|
51
|
+
<button onClick=${() => setCount(c => c + 1)}>
|
|
52
|
+
Count: ${count}
|
|
53
|
+
</button>
|
|
54
|
+
|
|
55
|
+
<For each=${...}>
|
|
56
|
+
...
|
|
57
|
+
</For>
|
|
58
|
+
|
|
59
|
+
<Show when=${...}>
|
|
60
|
+
...
|
|
61
|
+
</Show>
|
|
62
|
+
`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
render(Counter, document.body);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The returned tag can be assigned to any local variable, but `html` matches the
|
|
69
|
+
default editor tooling configuration. If you wrap or rename the tag, the `.jsx`
|
|
70
|
+
self-reference below gives tooling a stable tag name to recognize.
|
|
71
|
+
|
|
72
|
+
## API
|
|
73
|
+
|
|
74
|
+
### `createTaggedJSXRuntime(runtime): TaggedJSXInstance<{}>`
|
|
75
|
+
|
|
76
|
+
Binds the runtime once and returns a tag with an empty component registry (`{}`).
|
|
77
|
+
The `runtime` object provides the reactive primitives and HTML facts the tag
|
|
78
|
+
needs at render time. When using `@solidjs/web`, the module's exports (the `web` in
|
|
79
|
+
`import * as web from "@solidjs/web"`) satisfy the shape.
|
|
80
|
+
|
|
81
|
+
The exported `Runtime` type can be implemented by any signals-style library for use
|
|
82
|
+
with `html` templates:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { type Runtime } from "@dom-expressions/tagged-jsx";
|
|
86
|
+
|
|
87
|
+
import { ... } from '@preact/signals'; // For example, make tagged JSX work with Preact Signals
|
|
88
|
+
|
|
89
|
+
const preactTaggedJSXRuntime: Runtime = {
|
|
90
|
+
// ...implement the required shape for tagged JSX compatibility, using
|
|
91
|
+
// Preact Signals primitives...
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const html = createTaggedJSXRuntime(preactTaggedJSXRuntime);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The `Runtime` shape is:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
interface Runtime {
|
|
101
|
+
insert(parent: Node, accessor: any, marker?: Node | null, init?: any): any;
|
|
102
|
+
spread(node: Element, accessor: any, skipChildren?: boolean): void;
|
|
103
|
+
createComponent(Comp: (props: any) => any, props: any): any;
|
|
104
|
+
mergeProps(...sources: unknown[]): any;
|
|
105
|
+
SVGElements: Set<string>;
|
|
106
|
+
MathMLElements: Set<string>;
|
|
107
|
+
VoidElements: Set<string>;
|
|
108
|
+
RawTextElements: Set<string>;
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `tag.define(components): TaggedJSXInstance<PreviousComponents & NewComponents>`
|
|
113
|
+
|
|
114
|
+
Returns a new tag with the supplied components merged into the registry.
|
|
115
|
+
The original tag is unchanged.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const base = createTaggedJSXRuntime(web);
|
|
119
|
+
const withFor = base.define({ For });
|
|
120
|
+
const withForAndShow = withFor.define({ Show });
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### `tag.jsx`
|
|
124
|
+
|
|
125
|
+
A self-reference. This makes it possible to write templates through a `.jsx`
|
|
126
|
+
tag regardless of which local variable name was used to reference the instance.
|
|
127
|
+
That gives codemods, syntax highlighters, and formatters a stable tag name to
|
|
128
|
+
recognize.
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
const withForAndShow = withFor.define({ Show }); // from above
|
|
132
|
+
|
|
133
|
+
console.log(withForAndShow === withForAndShow.jsx) // true
|
|
134
|
+
|
|
135
|
+
// Both of these are functionally equivalent, but the second one
|
|
136
|
+
// helps tooling that specifically looks for "jsx" in code.
|
|
137
|
+
|
|
138
|
+
withForAndShow`
|
|
139
|
+
<For each=${...}>
|
|
140
|
+
...
|
|
141
|
+
</For>
|
|
142
|
+
|
|
143
|
+
<Show when=${...}>
|
|
144
|
+
...
|
|
145
|
+
</Show>
|
|
146
|
+
`
|
|
147
|
+
|
|
148
|
+
withForAndShow.jsx`
|
|
149
|
+
<For each=${...}>
|
|
150
|
+
...
|
|
151
|
+
</For>
|
|
152
|
+
|
|
153
|
+
<Show when=${...}>
|
|
154
|
+
...
|
|
155
|
+
</Show>
|
|
156
|
+
`
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `tag.components`
|
|
160
|
+
|
|
161
|
+
The current registry, as a plain object.
|
|
162
|
+
|
|
163
|
+
## Template syntax
|
|
164
|
+
|
|
165
|
+
### Elements and components
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
html`<div />`; // self-closing
|
|
169
|
+
html`<div></div>`; // matched
|
|
170
|
+
html`<MyComponent />`; // registered component (capitalized)
|
|
171
|
+
html`<${MyComponent} />`; // inline component via expression hole
|
|
172
|
+
html`<${MyComponent}>...<//>`; // shorthand close for inline component (see Limitations)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- Tag names start with `a-zA-Z$_` and may contain `a-zA-Z0-9$.:-_`.
|
|
176
|
+
- Capitalized tag names are looked up in the registry. An unregistered
|
|
177
|
+
capitalized name throws.
|
|
178
|
+
- Lowercase tag names are HTML/SVG/MathML elements; namespace is inferred
|
|
179
|
+
from the element name and walked into nested children.
|
|
180
|
+
|
|
181
|
+
### Text and whitespace
|
|
182
|
+
|
|
183
|
+
- Text content is decoded as HTML (`©` → `©`, `>` → `>`).
|
|
184
|
+
- Pure-whitespace runs between elements are dropped from the AST.
|
|
185
|
+
- Leading and trailing whitespace inside an element is dropped when the
|
|
186
|
+
element contains at least one expression hole.
|
|
187
|
+
- When in doubt, use an expression: `` html`<p>${" exact spaces "}</p>` ``.
|
|
188
|
+
|
|
189
|
+
### Attributes and properties
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
html`<input value="hi" />` // static string attribute
|
|
193
|
+
html`<input disabled />` // static boolean attribute
|
|
194
|
+
html`<input value=${val} />` // dynamic attribute or property (auto)
|
|
195
|
+
html`<input prop:value=${val} />` // forced DOM property
|
|
196
|
+
html`<input attr:foo=${val} />` // forced HTML attribute
|
|
197
|
+
html`<input ...${props} />` // spread
|
|
198
|
+
html`<input ref=${el => ...} />` // ref (not reactive)
|
|
199
|
+
html`<input onClick=${handler} />` // delegated event when supported by the runtime
|
|
200
|
+
html`<input onclick=${handler} />` // bound listener (legacy lowercase)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`children` as an attribute is honored only when the element has no template
|
|
204
|
+
children, matching JSX behavior.
|
|
205
|
+
|
|
206
|
+
### Reactivity
|
|
207
|
+
|
|
208
|
+
A function passed to a non-event, non-`ref` attribute is auto-wrapped as a
|
|
209
|
+
getter if it takes zero arguments. Both forms below are reactive and
|
|
210
|
+
equivalent:
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
const [count] = createSignal(0);
|
|
214
|
+
|
|
215
|
+
html`<button count=${() => count()} />`;
|
|
216
|
+
html`<button count=${count} />`;
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
If the value you want to pass is itself a zero-arg function and you don't
|
|
220
|
+
want it auto-wrapped, wrap it again to break the heuristic:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
html`<Route component=${() => Counter} />`;
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
`on*` and `ref` props are never auto-wrapped — they're passed as-is.
|
|
227
|
+
|
|
228
|
+
## JSX vs `html`
|
|
229
|
+
|
|
230
|
+
| Feature | Solid JSX | `html` tagged template |
|
|
231
|
+
| :----------------- | :-------------------------------------- | :------------------------------------------------------- |
|
|
232
|
+
| **Fragments** | Required: `<>...</>` for multiple roots | None needed: returns a node, or array of nodes |
|
|
233
|
+
| **Spread** | `<div {...props} />` | `<div ...${props} />` |
|
|
234
|
+
| **Comments** | `{/* ... */}` | `<!-- ... -->` (stripped) |
|
|
235
|
+
| **Raw-text tags** | `innerHTML` workaround | `<style>` / `<script>` bodies are raw text |
|
|
236
|
+
| **Whitespace** | JSX-style stripping | Trims between tags; preserves inside text |
|
|
237
|
+
| **Reactivity** | Signals auto-wrapped | Zero-arg functions auto-wrapped (use `() =>` to opt out) |
|
|
238
|
+
| **Component refs** | Identifier in scope | Registered name (`<Foo />`) or expression (`<${Foo} />`) |
|
|
239
|
+
|
|
240
|
+
Because `html` returns a `JSX.Element` — which can be a single node when the template
|
|
241
|
+
resolves to one root, or an array when it resolves to many — consumers that
|
|
242
|
+
need to iterate or spread should normalize the result:
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
const result = html`<div />`; // div
|
|
246
|
+
const nodes = [result].flat(); // [div]
|
|
247
|
+
```
|
|
248
|
+
```ts
|
|
249
|
+
const result = html`
|
|
250
|
+
<div />
|
|
251
|
+
<span />
|
|
252
|
+
`; // [div, span]
|
|
253
|
+
|
|
254
|
+
const nodes = [result].flat(); // [div, span]
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## License
|
|
258
|
+
|
|
259
|
+
You've got a license to build awesome apps: MIT
|