sigmx 0.1.1 → 0.2.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/README.md +10 -10
- package/dist/kernel/compile.d.ts +8 -9
- package/dist/kernel/compile.js +102 -67
- package/dist/kernel/compile.js.map +2 -2
- package/dist/kernel/contracts.d.ts +11 -5
- package/dist/kernel/index.d.ts +2 -2
- package/dist/kernel/index.js +5 -6
- package/dist/kernel/index.js.map +2 -2
- package/dist/kernel/precompile.d.ts +8 -10
- package/dist/kernel/precompile.js +25 -75
- package/dist/kernel/precompile.js.map +2 -2
- package/dist/kernel/precompiled.d.ts +7 -4
- package/dist/kernel/precompiled.js +5 -5
- package/dist/kernel/precompiled.js.map +2 -2
- package/dist/kernel/reactive.d.ts +8 -2
- package/dist/kernel/reactive.js +91 -62
- package/dist/kernel/reactive.js.map +3 -3
- package/dist/kernel/runtime.js +78 -68
- package/dist/kernel/runtime.js.map +3 -3
- package/dist/kernel/scan.d.ts +1 -1
- package/dist/kernel/scan.js +3 -3
- package/dist/kernel/scan.js.map +2 -2
- package/dist/kernel/state.d.ts +4 -3
- package/dist/kernel/state.js +91 -80
- package/dist/kernel/state.js.map +2 -2
- package/dist/kernel/strict-csp.d.ts +0 -5
- package/dist/kernel/strict-csp.js +2 -2
- package/dist/kernel/strict-csp.js.map +2 -2
- package/dist/lib/casing.d.ts +4 -1
- package/dist/lib/casing.js +8 -1
- package/dist/lib/casing.js.map +2 -2
- package/dist/lib/objects.d.ts +5 -3
- package/dist/lib/objects.js +10 -5
- package/dist/lib/objects.js.map +2 -2
- package/dist/lib/schedule.d.ts +3 -3
- package/dist/lib/schedule.js +12 -10
- package/dist/lib/schedule.js.map +2 -2
- package/dist/lib/sse.d.ts +10 -0
- package/dist/lib/sse.js +32 -29
- package/dist/lib/sse.js.map +2 -2
- package/dist/plugins/def.d.ts +5 -0
- package/dist/plugins/def.js +22 -0
- package/dist/plugins/def.js.map +7 -0
- package/dist/plugins/directives/attribute-sync.js +8 -12
- package/dist/plugins/directives/attribute-sync.js.map +2 -2
- package/dist/plugins/directives/boost.d.ts +1 -1
- package/dist/plugins/directives/boost.js +34 -31
- package/dist/plugins/directives/boost.js.map +2 -2
- package/dist/plugins/directives/busy-flag.js +13 -16
- package/dist/plugins/directives/busy-flag.js.map +2 -2
- package/dist/plugins/directives/class-toggle.js +17 -16
- package/dist/plugins/directives/class-toggle.js.map +2 -2
- package/dist/plugins/directives/cloak.js +2 -7
- package/dist/plugins/directives/cloak.js.map +2 -2
- package/dist/plugins/directives/collapse.js +36 -37
- package/dist/plugins/directives/collapse.js.map +2 -2
- package/dist/plugins/directives/declare.js +5 -8
- package/dist/plugins/directives/declare.js.map +2 -2
- package/dist/plugins/directives/derive.js +9 -18
- package/dist/plugins/directives/derive.js.map +2 -2
- package/dist/plugins/directives/element-ref.js +8 -8
- package/dist/plugins/directives/element-ref.js.map +2 -2
- package/dist/plugins/directives/event-listener.js +18 -26
- package/dist/plugins/directives/event-listener.js.map +2 -2
- package/dist/plugins/directives/frame-loop.js +9 -14
- package/dist/plugins/directives/frame-loop.js.map +2 -2
- package/dist/plugins/directives/html.js +6 -7
- package/dist/plugins/directives/html.js.map +2 -2
- package/dist/plugins/directives/inline-style.js +17 -20
- package/dist/plugins/directives/inline-style.js.map +2 -2
- package/dist/plugins/directives/mask.js +19 -23
- package/dist/plugins/directives/mask.js.map +2 -2
- package/dist/plugins/directives/media-query.d.ts +4 -1
- package/dist/plugins/directives/media-query.js +13 -13
- package/dist/plugins/directives/media-query.js.map +2 -2
- package/dist/plugins/directives/on-mount.js +4 -12
- package/dist/plugins/directives/on-mount.js.map +2 -2
- package/dist/plugins/directives/patch-listener.js +24 -19
- package/dist/plugins/directives/patch-listener.js.map +2 -2
- package/dist/plugins/directives/remove-me.js +7 -8
- package/dist/plugins/directives/remove-me.js.map +2 -2
- package/dist/plugins/directives/scroll-to.d.ts +4 -1
- package/dist/plugins/directives/scroll-to.js +8 -14
- package/dist/plugins/directives/scroll-to.js.map +2 -2
- package/dist/plugins/directives/size-watch.js +7 -12
- package/dist/plugins/directives/size-watch.js.map +2 -2
- package/dist/plugins/directives/state-dump.js +6 -10
- package/dist/plugins/directives/state-dump.js.map +2 -2
- package/dist/plugins/directives/storage-sync.js +13 -9
- package/dist/plugins/directives/storage-sync.js.map +2 -2
- package/dist/plugins/directives/teleport.js +8 -14
- package/dist/plugins/directives/teleport.js.map +2 -2
- package/dist/plugins/directives/text-content.js +6 -7
- package/dist/plugins/directives/text-content.js.map +2 -2
- package/dist/plugins/directives/timer.js +7 -13
- package/dist/plugins/directives/timer.js.map +2 -2
- package/dist/plugins/directives/transition.d.ts +1 -2
- package/dist/plugins/directives/transition.js +32 -34
- package/dist/plugins/directives/transition.js.map +2 -2
- package/dist/plugins/directives/tween.d.ts +2 -2
- package/dist/plugins/directives/tween.js +34 -50
- package/dist/plugins/directives/tween.js.map +2 -2
- package/dist/plugins/directives/two-way-bind.d.ts +1 -1
- package/dist/plugins/directives/two-way-bind.js +70 -97
- package/dist/plugins/directives/two-way-bind.js.map +2 -2
- package/dist/plugins/directives/url-params.js +35 -59
- package/dist/plugins/directives/url-params.js.map +3 -3
- package/dist/plugins/directives/url-replace.js +6 -7
- package/dist/plugins/directives/url-replace.js.map +2 -2
- package/dist/plugins/directives/validity.js +6 -9
- package/dist/plugins/directives/validity.js.map +2 -2
- package/dist/plugins/directives/viewport.js +18 -26
- package/dist/plugins/directives/viewport.js.map +2 -2
- package/dist/plugins/directives/visibility.js +9 -14
- package/dist/plugins/directives/visibility.js.map +2 -2
- package/dist/plugins/directives/watch.js +2 -8
- package/dist/plugins/directives/watch.js.map +2 -2
- package/dist/plugins/functions/bulk-set.js +7 -6
- package/dist/plugins/functions/bulk-set.js.map +2 -2
- package/dist/plugins/functions/bulk-toggle.js +7 -6
- package/dist/plugins/functions/bulk-toggle.js.map +2 -2
- package/dist/plugins/functions/confirm.js +2 -2
- package/dist/plugins/functions/confirm.js.map +2 -2
- package/dist/plugins/functions/copy-text.js +5 -5
- package/dist/plugins/functions/copy-text.js.map +2 -2
- package/dist/plugins/functions/dispatch.js +5 -5
- package/dist/plugins/functions/dispatch.js.map +2 -2
- package/dist/plugins/functions/locale-format.d.ts +4 -1
- package/dist/plugins/functions/locale-format.js +9 -16
- package/dist/plugins/functions/locale-format.js.map +2 -2
- package/dist/plugins/functions/range-map.js +6 -6
- package/dist/plugins/functions/range-map.js.map +2 -2
- package/dist/plugins/functions/request.d.ts +7 -3
- package/dist/plugins/functions/request.js +77 -86
- package/dist/plugins/functions/request.js.map +2 -2
- package/dist/plugins/functions/untracked-read.js +3 -2
- package/dist/plugins/functions/untracked-read.js.map +2 -2
- package/dist/plugins/functions/websocket.d.ts +3 -3
- package/dist/plugins/functions/websocket.js +13 -24
- package/dist/plugins/functions/websocket.js.map +2 -2
- package/dist/plugins/index.d.ts +0 -2
- package/dist/plugins/index.js +0 -4
- package/dist/plugins/index.js.map +2 -2
- package/dist/plugins/server-events/apply-elements.d.ts +1 -1
- package/dist/plugins/server-events/apply-elements.js +41 -43
- package/dist/plugins/server-events/apply-elements.js.map +2 -2
- package/dist/plugins/server-events/apply-state.js +9 -12
- package/dist/plugins/server-events/apply-state.js.map +2 -2
- package/dist/plugins/server-events/morph.js +46 -66
- package/dist/plugins/server-events/morph.js.map +3 -3
- package/dist/presets/all.js +0 -4
- package/dist/presets/all.js.map +2 -2
- package/dist/server.d.ts +10 -4
- package/dist/server.js +42 -14
- package/dist/server.js.map +2 -2
- package/dist/sigmx.standalone.js +1 -1
- package/dist/vite.js +17 -7
- package/dist/vite.js.map +2 -2
- package/package.json +4 -2
- package/dist/plugins/directives/transition-name.d.ts +0 -1
- package/dist/plugins/directives/transition-name.js +0 -11
- package/dist/plugins/directives/transition-name.js.map +0 -7
- package/dist/plugins/directives/trap.d.ts +0 -5
- package/dist/plugins/directives/trap.js +0 -54
- package/dist/plugins/directives/trap.js.map +0 -7
package/README.md
CHANGED
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
|
|
9
9
|
Your server renders HTML, as it always has. The browser asks for more of it with `@get` and `@post`, and sigmx merges the response into the page with a morph that keeps focus, typed input and scroll position. When you want live updates, the same request can return a stream of patches instead. Signals, two-way binding and reactive attributes cover the client-side state. You write `data-*` attributes and register only the plugins you use.
|
|
10
10
|
|
|
11
|
-
- **Tiny.** 4.
|
|
11
|
+
- **Tiny.** 4.5 KB core, 9.0 KB with the essentials, 11.5 KB with all 50 plugins (brotli). Zero runtime dependencies.
|
|
12
12
|
- **Server-driven.** Return plain HTML from any endpoint and it is morphed into the page by id, or targeted with a header. Return JSON to merge signals, or an event stream to push many patches over one request, with `Last-Event-ID` reconnects.
|
|
13
13
|
- **Reactive where it matters.** Signals declared in markup; `bind`, `show`, `class`, computed values and effects keep the page in step. No component model, no virtual DOM.
|
|
14
14
|
- **Pay for what you use.** Every directive and function is an opt-in plugin, and auto mode scans your source to bundle exactly the set it finds.
|
|
15
|
-
- **Batteries from the ecosystem.** The Alpine plugins (`collapse`, `mask`, `
|
|
15
|
+
- **Batteries from the ecosystem.** The Alpine plugins (`collapse`, `mask`, `teleport`, …) and htmx extensions (`boost`, `ws`, `remove-me`, …) people bolt on are built in as plugins.
|
|
16
16
|
- **Datastar-compatible markup.** Existing Datastar templates run unchanged.
|
|
17
17
|
|
|
18
18
|
```html
|
|
@@ -53,7 +53,7 @@ Attributes are `data-<plugin>[:key][__modifier.arg]="expression"`. Expressions a
|
|
|
53
53
|
<button data-on:click__debounce.300ms="@get('/search')">Search</button>
|
|
54
54
|
<li data-class:active="$page === 3"></li>
|
|
55
55
|
<input data-bind:user.email />
|
|
56
|
-
<p data-text="`${$items.length} items, ${@intl('
|
|
56
|
+
<p data-text="`${$items.length} items, ${@intl('NumberFormat', $total, { style: 'currency', currency: 'EUR' })}`"></p>
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
State is one JSON-like store addressed by dotted paths and patched with merge-patch semantics: objects merge, `null` removes, arrays notify on `push`. Requests send the store (minus `_`-prefixed paths) and apply whatever comes back, decided by the response's content type:
|
|
@@ -81,10 +81,10 @@ data: elements <li>Validating…</li>
|
|
|
81
81
|
| kind | plugins |
|
|
82
82
|
| --------- | -------------------------------------------------------------------------------------------------------------- |
|
|
83
83
|
| state | `signals` `computed` `effect` `ref` `persist` `query-string` |
|
|
84
|
-
| rendering | `text` `html` `show` `class` `style` `attr` `animate` `transition` `collapse` `
|
|
84
|
+
| rendering | `text` `html` `show` `class` `style` `attr` `animate` `transition` `collapse` `cloak` |
|
|
85
85
|
| forms | `bind` `custom-validity` `mask` |
|
|
86
86
|
| events | `on` `init` `on-interval` `on-intersect` `on-resize` `on-raf` `on-signal-patch` `match-media` |
|
|
87
|
-
| layout | `teleport` `
|
|
87
|
+
| layout | `teleport` `scroll-into-view` `remove-me` |
|
|
88
88
|
| server | `@get` `@post` `@put` `@patch` `@delete` `@ws` `boost` `indicator` `patch-elements` `patch-signals` |
|
|
89
89
|
| utilities | `@peek` `@setAll` `@toggleAll` `@fit` `@clipboard` `@intl` `@dispatch` `@confirm` `json-signals` `replace-url` |
|
|
90
90
|
|
|
@@ -96,14 +96,14 @@ Brotli, measured from the real source by `npm run size` and `npm run compare` (n
|
|
|
96
96
|
|
|
97
97
|
| | brotli |
|
|
98
98
|
| ----------------------------------------------------------- | ------: |
|
|
99
|
-
| sigmx core | 4.
|
|
100
|
-
| sigmx essentials (state, rendering, forms, requests, morph) |
|
|
101
|
-
| sigmx everything,
|
|
99
|
+
| sigmx core | 4.5 KB |
|
|
100
|
+
| sigmx essentials (state, rendering, forms, requests, morph) | 9.0 KB |
|
|
101
|
+
| sigmx everything, 50 plugins | 11.5 KB |
|
|
102
102
|
| htmx 2.0.10 | 14.6 KB |
|
|
103
|
-
| Datastar 1.0.3
|
|
103
|
+
| Datastar 1.0.3 (23 plugins) | 11.8 KB |
|
|
104
104
|
| Alpine.js 3.17.1 | 17.6 KB |
|
|
105
105
|
|
|
106
|
-
Precompiling expressions at build time removes the runtime compiler and any use of `new Function`, taking the core to 3.
|
|
106
|
+
Precompiling expressions at build time removes the runtime compiler and any use of `new Function`, taking the core to 3.8 KB and making strict CSP trivial.
|
|
107
107
|
|
|
108
108
|
## Auto mode
|
|
109
109
|
|
package/dist/kernel/compile.d.ts
CHANGED
|
@@ -2,15 +2,14 @@ import type { ExpressionCompiler } from './contracts.js';
|
|
|
2
2
|
export type Compiler = (params: string[], body: string) => (...args: any[]) => any;
|
|
3
3
|
/** Default compiler: `new Function`. Not usable under a strict CSP; see `cspCompiler`. */
|
|
4
4
|
export declare const functionCompiler: Compiler;
|
|
5
|
-
/**
|
|
6
|
-
export declare const
|
|
7
|
-
/** Split on top-level semicolons. */
|
|
8
|
-
export declare const splitStatements: (src: string) => string[];
|
|
5
|
+
/** `$count + @fit($x)` → `$.count + __a.fit($.x)`; strings, template text, comments and regexes untouched. */
|
|
6
|
+
export declare const transform: (src: string) => string;
|
|
9
7
|
/**
|
|
10
|
-
* Compile
|
|
11
|
-
*
|
|
12
|
-
* last statement is returned, so `$a = 1; $a * 2` works. Compiled functions are cached by source.
|
|
8
|
+
* Compile `src` with `compiler` as `($, __a, ...params) => any`, returning the body that compiled
|
|
9
|
+
* together with the function. Shared by the runtime and the build-time precompiler.
|
|
13
10
|
*/
|
|
14
|
-
export declare const
|
|
15
|
-
/**
|
|
11
|
+
export declare const compileBody: (compiler: Compiler, src: string, params: string[]) => [string, (...args: any[]) => any];
|
|
12
|
+
/** Compile with a cache keyed by parameter names and source. */
|
|
13
|
+
export declare const compile: (compiler: Compiler, src: string, params: string[]) => ((...args: any[]) => any);
|
|
14
|
+
/** The default pipeline: compile at runtime with `compiler` (`new Function` or the CSP compiler). */
|
|
16
15
|
export declare const runtimeExpressions: (compiler: Compiler) => ExpressionCompiler;
|
package/dist/kernel/compile.js
CHANGED
|
@@ -1,96 +1,131 @@
|
|
|
1
1
|
const functionCompiler = (params, body) => Function(...params, body);
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
2
|
+
const START = /[A-Za-z_$]/;
|
|
3
|
+
const IDENT = /[\w$]/;
|
|
4
|
+
const BEFORE_REGEX = /(^|[(,=:[!&|?{};+\-*%<>~^]|\b(?:return|typeof|case|in|of|do|else|void|delete|throw|new))$/;
|
|
5
|
+
const rewrite = (src, from, hole) => {
|
|
6
|
+
let out = "";
|
|
7
|
+
let i = from;
|
|
8
|
+
let depth = 0;
|
|
6
9
|
const n = src.length;
|
|
10
|
+
const code = () => out.trimEnd();
|
|
7
11
|
while (i < n) {
|
|
8
12
|
const c = src[i];
|
|
9
|
-
const
|
|
10
|
-
if (c === '"' || c === "'"
|
|
13
|
+
const d = src[i + 1];
|
|
14
|
+
if (c === '"' || c === "'") {
|
|
11
15
|
let j = i + 1;
|
|
12
16
|
while (j < n && src[j] !== c) j += src[j] === "\\" ? 2 : 1;
|
|
13
|
-
|
|
17
|
+
out += src.slice(i, j + 1);
|
|
14
18
|
i = j + 1;
|
|
15
|
-
} else if (c === "
|
|
19
|
+
} else if (c === "`") {
|
|
20
|
+
out += c;
|
|
21
|
+
i++;
|
|
22
|
+
while (i < n && src[i] !== "`") {
|
|
23
|
+
if (src[i] === "\\") {
|
|
24
|
+
out += src.slice(i, i + 2);
|
|
25
|
+
i += 2;
|
|
26
|
+
} else if (src[i] === "$" && src[i + 1] === "{") {
|
|
27
|
+
const [inner, j] = rewrite(src, i + 2, true);
|
|
28
|
+
out += `\${${inner}}`;
|
|
29
|
+
i = j;
|
|
30
|
+
} else out += src[i++];
|
|
31
|
+
}
|
|
32
|
+
out += "`";
|
|
33
|
+
i++;
|
|
34
|
+
} else if (c === "/" && d === "/") {
|
|
16
35
|
const j = src.indexOf("\n", i);
|
|
17
36
|
i = j < 0 ? n : j;
|
|
18
|
-
} else if (c === "/" &&
|
|
37
|
+
} else if (c === "/" && d === "*") {
|
|
19
38
|
const j = src.indexOf("*/", i + 2);
|
|
20
39
|
i = j < 0 ? n : j + 2;
|
|
21
|
-
} else {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
} else if (c === "/" && BEFORE_REGEX.test(code())) {
|
|
41
|
+
let j = i + 1;
|
|
42
|
+
let cls = false;
|
|
43
|
+
for (; j < n && (cls || src[j] !== "/"); j++) {
|
|
44
|
+
if (src[j] === "\\") j++;
|
|
45
|
+
else if (src[j] === "[") cls = true;
|
|
46
|
+
else if (src[j] === "]") cls = false;
|
|
47
|
+
}
|
|
48
|
+
for (j++; j < n && /[a-z]/i.test(src[j]); j++) ;
|
|
49
|
+
out += src.slice(i, j);
|
|
50
|
+
i = j;
|
|
51
|
+
} else if (hole && (c === "{" || c === "}")) {
|
|
52
|
+
if (c === "{") depth++;
|
|
53
|
+
else if (depth) depth--;
|
|
54
|
+
else return [out, i + 1];
|
|
55
|
+
out += c;
|
|
56
|
+
i++;
|
|
57
|
+
} else if (c === "$" && START.test(d ?? "") && d !== "$" && !IDENT.test(out.at(-1) ?? "")) {
|
|
58
|
+
const before = code();
|
|
59
|
+
if (before.endsWith(".") && !before.endsWith("...")) {
|
|
60
|
+
out += c;
|
|
61
|
+
i++;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
let j = i + 1;
|
|
65
|
+
while (j < n && IDENT.test(src[j])) j++;
|
|
66
|
+
out += `$.${src.slice(i + 1, j)}`;
|
|
67
|
+
i = j;
|
|
68
|
+
} else if (c === "@" && START.test(d ?? "")) {
|
|
31
69
|
let j = i + 1;
|
|
32
|
-
while (j <
|
|
70
|
+
while (j < n && IDENT.test(src[j])) j++;
|
|
33
71
|
let k = j;
|
|
34
|
-
while (k <
|
|
35
|
-
if (
|
|
72
|
+
while (k < n && /\s/.test(src[k])) k++;
|
|
73
|
+
if (src[k] === "(") {
|
|
36
74
|
out += `__a.${src.slice(i + 1, j)}(`;
|
|
37
|
-
|
|
75
|
+
i = k + 1;
|
|
76
|
+
} else {
|
|
77
|
+
out += c;
|
|
78
|
+
i++;
|
|
38
79
|
}
|
|
80
|
+
} else {
|
|
81
|
+
out += c;
|
|
82
|
+
i++;
|
|
39
83
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return out;
|
|
84
|
+
}
|
|
85
|
+
return [out, i];
|
|
43
86
|
};
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
parts.push(src.slice(start, i));
|
|
54
|
-
start = i + 1;
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
parts.push(src.slice(start));
|
|
58
|
-
return parts.filter((p) => p.trim());
|
|
87
|
+
const transform = (src) => rewrite(src, 0, false)[0];
|
|
88
|
+
const candidates = (code) => {
|
|
89
|
+
const out = [`return(${code}
|
|
90
|
+
)`];
|
|
91
|
+
for (let i = code.lastIndexOf(";"); i >= 0; i = code.lastIndexOf(";", i - 1))
|
|
92
|
+
out.push(`${code.slice(0, i)};return(${code.slice(i + 1)}
|
|
93
|
+
)`);
|
|
94
|
+
out.push(code);
|
|
95
|
+
return out.map((b) => `"use strict";${b}`);
|
|
59
96
|
};
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
if (hit) return hit;
|
|
64
|
-
const code = rewriteActions(src.trim());
|
|
65
|
-
const make = (body) => compiler(["$", "__a", ...params], `with($.scope){${body}
|
|
66
|
-
}`);
|
|
67
|
-
let fn;
|
|
68
|
-
if (!returns) {
|
|
69
|
-
fn = make(code);
|
|
70
|
-
} else {
|
|
97
|
+
const compileBody = (compiler, src, params) => {
|
|
98
|
+
let error;
|
|
99
|
+
for (const body of candidates(transform(src.trim()))) {
|
|
71
100
|
try {
|
|
72
|
-
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
const parts = splitStatements(code);
|
|
76
|
-
const last = parts.pop() ?? "";
|
|
77
|
-
try {
|
|
78
|
-
fn = make(`${parts.join(";")};return(${last}
|
|
79
|
-
)`);
|
|
80
|
-
} catch {
|
|
81
|
-
fn = make(code);
|
|
82
|
-
}
|
|
101
|
+
return [body, compiler(["$", "__a", ...params], body)];
|
|
102
|
+
} catch (e) {
|
|
103
|
+
error = e;
|
|
83
104
|
}
|
|
84
105
|
}
|
|
85
|
-
|
|
106
|
+
throw error;
|
|
107
|
+
};
|
|
108
|
+
const cache = /* @__PURE__ */ new Map();
|
|
109
|
+
const CACHE_LIMIT = 2e3;
|
|
110
|
+
const compile = (compiler, src, params) => {
|
|
111
|
+
const key = `${params.join()}|${src}`;
|
|
112
|
+
let fn = cache.get(key);
|
|
113
|
+
if (!fn) {
|
|
114
|
+
fn = compileBody(compiler, src, params)[1];
|
|
115
|
+
if (cache.size >= CACHE_LIMIT) cache.delete(cache.keys().next().value);
|
|
116
|
+
cache.set(key, fn);
|
|
117
|
+
}
|
|
86
118
|
return fn;
|
|
87
119
|
};
|
|
88
|
-
const runtimeExpressions = (compiler) => (src, params
|
|
120
|
+
const runtimeExpressions = (compiler) => (src, params) => {
|
|
121
|
+
const fn = compile(compiler, src, params);
|
|
122
|
+
return (store, actions, ...rest) => fn(store.$, actions, ...rest);
|
|
123
|
+
};
|
|
89
124
|
export {
|
|
90
125
|
compile,
|
|
126
|
+
compileBody,
|
|
91
127
|
functionCompiler,
|
|
92
|
-
rewriteActions,
|
|
93
128
|
runtimeExpressions,
|
|
94
|
-
|
|
129
|
+
transform
|
|
95
130
|
};
|
|
96
131
|
//# sourceMappingURL=compile.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/kernel/compile.ts"],
|
|
4
|
-
"sourcesContent": ["// Expression compiler.
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["// Expression compiler. An attribute expression is rewritten once, `$name` \u2192 `$.name` and\n// `@name(` \u2192 `__a.name(`, then compiled as a strict-mode function of `($, __a, el, evt, ...args)`\n// where `$` is the store's root proxy. The build-time precompiler emits exactly the same bodies,\n// so precompiled and runtime expressions behave identically.\n\nimport type { ExpressionCompiler } from './contracts.js';\n\nexport type Compiler = (params: string[], body: string) => (...args: any[]) => any;\n\n/** Default compiler: `new Function`. Not usable under a strict CSP; see `cspCompiler`. */\nexport const functionCompiler: Compiler = (params, body) => Function(...params, body) as (...args: any[]) => any;\n\nconst START = /[A-Za-z_$]/;\nconst IDENT = /[\\w$]/;\n/** After these a `/` starts a regular expression rather than a division. */\nconst BEFORE_REGEX = /(^|[(,=:[!&|?{};+\\-*%<>~^]|\\b(?:return|typeof|case|in|of|do|else|void|delete|throw|new))$/;\n\n/**\n * Tokenizer-based rewrite. Copies string literals, template text, and regular expressions verbatim,\n * drops comments, recurses into `${\u2026}` holes, and rewrites signals and actions in code. In hole\n * mode it stops at the unmatched `}` and reports the index after it.\n */\nconst rewrite = (src: string, from: number, hole: boolean): [string, number] => {\n let out = '';\n let i = from;\n let depth = 0;\n const n = src.length;\n const code = () => out.trimEnd();\n while (i < n) {\n const c = src[i];\n const d = src[i + 1];\n if (c === '\"' || c === \"'\") {\n let j = i + 1;\n while (j < n && src[j] !== c) j += src[j] === '\\\\' ? 2 : 1;\n out += src.slice(i, j + 1);\n i = j + 1;\n } else if (c === '`') {\n out += c;\n i++;\n while (i < n && src[i] !== '`') {\n if (src[i] === '\\\\') {\n out += src.slice(i, i + 2);\n i += 2;\n } else if (src[i] === '$' && src[i + 1] === '{') {\n const [inner, j] = rewrite(src, i + 2, true);\n out += `\\${${inner}}`;\n i = j;\n } else out += src[i++];\n }\n out += '`';\n i++;\n } else if (c === '/' && d === '/') {\n const j = src.indexOf('\\n', i);\n i = j < 0 ? n : j;\n } else if (c === '/' && d === '*') {\n const j = src.indexOf('*/', i + 2);\n i = j < 0 ? n : j + 2;\n } else if (c === '/' && BEFORE_REGEX.test(code())) {\n let j = i + 1;\n let cls = false;\n for (; j < n && (cls || src[j] !== '/'); j++) {\n if (src[j] === '\\\\') j++;\n else if (src[j] === '[') cls = true;\n else if (src[j] === ']') cls = false;\n }\n for (j++; j < n && /[a-z]/i.test(src[j]); j++);\n out += src.slice(i, j);\n i = j;\n } else if (hole && (c === '{' || c === '}')) {\n if (c === '{') depth++;\n else if (depth) depth--;\n else return [out, i + 1];\n out += c;\n i++;\n } else if (c === '$' && START.test(d ?? '') && d !== '$' && !IDENT.test(out.at(-1) ?? '')) {\n const before = code();\n // `obj.$x` is a member access and stays; `...$x` is a spread and is a signal.\n if (before.endsWith('.') && !before.endsWith('...')) {\n out += c;\n i++;\n continue;\n }\n let j = i + 1;\n while (j < n && IDENT.test(src[j])) j++;\n out += `$.${src.slice(i + 1, j)}`;\n i = j;\n } else if (c === '@' && START.test(d ?? '')) {\n let j = i + 1;\n while (j < n && IDENT.test(src[j])) j++;\n let k = j;\n while (k < n && /\\s/.test(src[k])) k++;\n if (src[k] === '(') {\n out += `__a.${src.slice(i + 1, j)}(`;\n i = k + 1;\n } else {\n out += c;\n i++;\n }\n } else {\n out += c;\n i++;\n }\n }\n return [out, i];\n};\n\n/** `$count + @fit($x)` \u2192 `$.count + __a.fit($.x)`; strings, template text, comments and regexes untouched. */\nexport const transform = (src: string): string => rewrite(src, 0, false)[0];\n\n/**\n * The strict-mode bodies to try, best first: the whole source as an expression, then each split at a\n * top-level-looking `;` from the end (statements followed by a returned value), then plain statements.\n * A split inside a string or bracket does not compile and the next candidate is tried.\n */\nconst candidates = (code: string): string[] => {\n const out = [`return(${code}\\n)`];\n for (let i = code.lastIndexOf(';'); i >= 0; i = code.lastIndexOf(';', i - 1))\n out.push(`${code.slice(0, i)};return(${code.slice(i + 1)}\\n)`);\n out.push(code);\n return out.map((b) => `\"use strict\";${b}`);\n};\n\n/**\n * Compile `src` with `compiler` as `($, __a, ...params) => any`, returning the body that compiled\n * together with the function. Shared by the runtime and the build-time precompiler.\n */\nexport const compileBody = (compiler: Compiler, src: string, params: string[]): [string, (...args: any[]) => any] => {\n let error: unknown;\n for (const body of candidates(transform(src.trim()))) {\n try {\n return [body, compiler(['$', '__a', ...params], body)];\n } catch (e) {\n error = e;\n }\n }\n throw error;\n};\n\nconst cache = new Map<string, (...args: any[]) => any>();\nconst CACHE_LIMIT = 2000; // a long-lived page streaming unique expressions must not grow without bound\n\n/** Compile with a cache keyed by parameter names and source. */\nexport const compile = (compiler: Compiler, src: string, params: string[]): ((...args: any[]) => any) => {\n const key = `${params.join()}|${src}`;\n let fn = cache.get(key);\n if (!fn) {\n fn = compileBody(compiler, src, params)[1];\n if (cache.size >= CACHE_LIMIT) cache.delete(cache.keys().next().value as string);\n cache.set(key, fn);\n }\n return fn;\n};\n\n/** The default pipeline: compile at runtime with `compiler` (`new Function` or the CSP compiler). */\nexport const runtimeExpressions =\n (compiler: Compiler): ExpressionCompiler =>\n (src, params) => {\n const fn = compile(compiler, src, params);\n return (store, actions, ...rest) => fn(store.$, actions, ...rest);\n };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -6,7 +6,7 @@ export type Mods = Map<string, string[]>;
|
|
|
6
6
|
/** A compiled attribute expression. `store` is the instance store; `actions` resolves `@name(...)`. */
|
|
7
7
|
export type Evaluator = (store: Store, actions: any, el: El, evt: Event | undefined, ...args: any[]) => any;
|
|
8
8
|
/** Turns expression source into an evaluator. The runtime compiler and the precompiled table both implement this. */
|
|
9
|
-
export type ExpressionCompiler = (src: string, params: string[]
|
|
9
|
+
export type ExpressionCompiler = (src: string, params: string[]) => Evaluator;
|
|
10
10
|
export interface Runtime {
|
|
11
11
|
/** Attribute prefixes being scanned; the first is primary. */
|
|
12
12
|
readonly prefixes: readonly string[];
|
|
@@ -42,8 +42,11 @@ export interface Ctx {
|
|
|
42
42
|
effect(fn: () => void): void;
|
|
43
43
|
/** addEventListener with automatic removal on cleanup. */
|
|
44
44
|
listen(target: EventTarget, type: string, fn: (e: any) => void, options?: AddEventListenerOptions): void;
|
|
45
|
-
|
|
45
|
+
/** Run `fn` when the attribute unmounts. Returns a function that unregisters it (for work that finished early). */
|
|
46
|
+
cleanup(fn: () => void): () => void;
|
|
46
47
|
error(message: string, extra?: Record<string, unknown>): Error;
|
|
48
|
+
/** Route an error that happened later (a callback, a promise) to `onError` with this attribute's info. */
|
|
49
|
+
report(error: unknown): void;
|
|
47
50
|
store: Store;
|
|
48
51
|
runtime: Runtime;
|
|
49
52
|
}
|
|
@@ -53,8 +56,10 @@ export interface ActionCtx {
|
|
|
53
56
|
store: Store;
|
|
54
57
|
runtime: Runtime;
|
|
55
58
|
error(message: string, extra?: Record<string, unknown>): Error;
|
|
56
|
-
/**
|
|
57
|
-
|
|
59
|
+
/** Route an error that happened later (a callback, a promise) to `onError` with this attribute's info. */
|
|
60
|
+
report(error: unknown): void;
|
|
61
|
+
/** Run when the attribute that invoked the action is torn down. Returns a function that unregisters it. */
|
|
62
|
+
cleanup(fn: () => void): () => void;
|
|
58
63
|
}
|
|
59
64
|
export interface AttributePlugin {
|
|
60
65
|
type: 'attribute';
|
|
@@ -62,7 +67,8 @@ export interface AttributePlugin {
|
|
|
62
67
|
key?: 'required' | 'forbidden';
|
|
63
68
|
value?: 'required' | 'forbidden';
|
|
64
69
|
/** Whether the expression yields a value (default) or is a statement body. */
|
|
65
|
-
|
|
70
|
+
/** The value is a literal (a mask, a selector, a delay) rather than an expression; `__dynamic` makes it one. */
|
|
71
|
+
literal?: boolean;
|
|
66
72
|
/** Extra parameter names the expression can reference, in the order passed to `evaluate`. */
|
|
67
73
|
args?: string[];
|
|
68
74
|
mount(ctx: Ctx): void | (() => void);
|
package/dist/kernel/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { camel, kebab, pascal, recase, snake } from '../lib/casing.js';
|
|
2
2
|
export type { Filter } from '../lib/objects.js';
|
|
3
3
|
export { expand, isPlain, toPredicate } from '../lib/objects.js';
|
|
4
|
-
export { debounce, delay, throttle, toMs, withTiming
|
|
4
|
+
export { debounce, delay, throttle, toMs, withTiming } from '../lib/schedule.js';
|
|
5
5
|
export type { Compiler } from './compile.js';
|
|
6
|
-
export { compile,
|
|
6
|
+
export { compile, compileBody, functionCompiler, runtimeExpressions, transform } from './compile.js';
|
|
7
7
|
export type * from './contracts.js';
|
|
8
8
|
export type { ExpressionTable } from './precompiled.js';
|
|
9
9
|
export { expressionKey, precompiled } from './precompiled.js';
|
package/dist/kernel/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { camel, kebab, pascal, recase, snake } from "../lib/casing.js";
|
|
2
2
|
import { expand, isPlain, toPredicate } from "../lib/objects.js";
|
|
3
|
-
import { debounce, delay, throttle, toMs, withTiming
|
|
4
|
-
import { compile,
|
|
3
|
+
import { debounce, delay, throttle, toMs, withTiming } from "../lib/schedule.js";
|
|
4
|
+
import { compile, compileBody, functionCompiler, runtimeExpressions, transform } from "./compile.js";
|
|
5
5
|
import { expressionKey, precompiled } from "./precompiled.js";
|
|
6
6
|
import { batch, Computed, computed, effect, flush, onSettled, Signal, signal, untracked } from "./reactive.js";
|
|
7
7
|
import { createRuntime, parseAttr } from "./runtime.js";
|
|
@@ -23,6 +23,7 @@ export {
|
|
|
23
23
|
batch,
|
|
24
24
|
camel,
|
|
25
25
|
compile,
|
|
26
|
+
compileBody,
|
|
26
27
|
computed,
|
|
27
28
|
createRuntime,
|
|
28
29
|
createSigmx,
|
|
@@ -42,16 +43,14 @@ export {
|
|
|
42
43
|
pascal,
|
|
43
44
|
precompiled,
|
|
44
45
|
recase,
|
|
45
|
-
rewriteActions,
|
|
46
46
|
runtimeExpressions,
|
|
47
47
|
signal,
|
|
48
48
|
snake,
|
|
49
|
-
splitStatements,
|
|
50
49
|
throttle,
|
|
51
50
|
toMs,
|
|
52
51
|
toPredicate,
|
|
52
|
+
transform,
|
|
53
53
|
untracked,
|
|
54
|
-
withTiming
|
|
55
|
-
withViewTransition
|
|
54
|
+
withTiming
|
|
56
55
|
};
|
|
57
56
|
//# sourceMappingURL=index.js.map
|
package/dist/kernel/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/kernel/index.ts"],
|
|
4
|
-
"sourcesContent": ["export { camel, kebab, pascal, recase, snake } from '../lib/casing.js';\nexport type { Filter } from '../lib/objects.js';\nexport { expand, isPlain, toPredicate } from '../lib/objects.js';\nexport { debounce, delay, throttle, toMs, withTiming
|
|
5
|
-
"mappings": "AAAA,SAAS,OAAO,OAAO,QAAQ,QAAQ,aAAa;AAEpD,SAAS,QAAQ,SAAS,mBAAmB;AAC7C,SAAS,UAAU,OAAO,UAAU,MAAM,
|
|
4
|
+
"sourcesContent": ["export { camel, kebab, pascal, recase, snake } from '../lib/casing.js';\nexport type { Filter } from '../lib/objects.js';\nexport { expand, isPlain, toPredicate } from '../lib/objects.js';\nexport { debounce, delay, throttle, toMs, withTiming } from '../lib/schedule.js';\nexport type { Compiler } from './compile.js';\nexport { compile, compileBody, functionCompiler, runtimeExpressions, transform } from './compile.js';\nexport type * from './contracts.js';\nexport type { ExpressionTable } from './precompiled.js';\nexport { expressionKey, precompiled } from './precompiled.js';\nexport { batch, Computed, computed, effect, flush, onSettled, Signal, signal, untracked } from './reactive.js';\nexport { createRuntime, parseAttr } from './runtime.js';\nexport type { Patch, Store } from './state.js';\nexport { createStore } from './state.js';\n\nimport { functionCompiler, runtimeExpressions } from './compile.js';\nimport type { ActionPlugin, AttributePlugin, HandlerPlugin, Sigmx, SigmxOptions } from './contracts.js';\nimport { createRuntime } from './runtime.js';\n\n/** Create an instance. Expressions compile at runtime unless you pass `expressions` (see `precompiled`). */\nexport const createSigmx = (options: SigmxOptions = {}): Sigmx =>\n createRuntime({\n ...options,\n expressions: options.expressions ?? runtimeExpressions(options.compile ?? functionCompiler),\n });\n\nexport const attribute = (p: Omit<AttributePlugin, 'type'>): AttributePlugin => ({ type: 'attribute', ...p });\nexport const action = (p: Omit<ActionPlugin, 'type'>): ActionPlugin => ({ type: 'action', ...p });\nexport const handler = (p: Omit<HandlerPlugin, 'type'>): HandlerPlugin => ({ type: 'handler', ...p });\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,OAAO,OAAO,QAAQ,QAAQ,aAAa;AAEpD,SAAS,QAAQ,SAAS,mBAAmB;AAC7C,SAAS,UAAU,OAAO,UAAU,MAAM,kBAAkB;AAE5D,SAAS,SAAS,aAAa,kBAAkB,oBAAoB,iBAAiB;AAGtF,SAAS,eAAe,mBAAmB;AAC3C,SAAS,OAAO,UAAU,UAAU,QAAQ,OAAO,WAAW,QAAQ,QAAQ,iBAAiB;AAC/F,SAAS,eAAe,iBAAiB;AAEzC,SAAS,mBAAmB;AAE5B,SAAS,oBAAAA,mBAAkB,sBAAAC,2BAA0B;AAErD,SAAS,iBAAAC,sBAAqB;AAGvB,MAAM,cAAc,CAAC,UAAwB,CAAC,MACnDA,eAAc;AAAA,EACZ,GAAG;AAAA,EACH,aAAa,QAAQ,eAAeD,oBAAmB,QAAQ,WAAWD,iBAAgB;AAC5F,CAAC;AAEI,MAAM,YAAY,CAAC,OAAuD,EAAE,MAAM,aAAa,GAAG,EAAE;AACpG,MAAM,SAAS,CAAC,OAAiD,EAAE,MAAM,UAAU,GAAG,EAAE;AACxF,MAAM,UAAU,CAAC,OAAmD,EAAE,MAAM,WAAW,GAAG,EAAE;",
|
|
6
6
|
"names": ["functionCompiler", "runtimeExpressions", "createRuntime"]
|
|
7
7
|
}
|
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rewrite `$name` and `$a.b` into `$.name` / `$.a.b` so the expression runs in strict mode without
|
|
3
|
-
* `with`. Skips strings and comments, recurses into template-literal interpolations, and leaves
|
|
4
|
-
* `$` alone, `$[...]` alone, and `obj.$prop` alone.
|
|
5
|
-
*/
|
|
6
|
-
export declare const rewriteSignals: (src: string) => string;
|
|
7
|
-
export declare const compileBody: (src: string, returns: boolean) => string;
|
|
8
1
|
export type Extracted = {
|
|
9
2
|
src: string;
|
|
10
3
|
params: string[];
|
|
11
|
-
returns: boolean;
|
|
12
4
|
};
|
|
13
5
|
export declare const generateTable: (items: Extracted[]) => string;
|
|
14
6
|
export type PluginMeta = {
|
|
15
7
|
name: string;
|
|
16
|
-
returns?: boolean;
|
|
17
8
|
args?: string[];
|
|
9
|
+
literal?: boolean;
|
|
18
10
|
};
|
|
19
11
|
/**
|
|
20
12
|
* Find directive attributes with literal values in template source. Values must be plain quoted
|
|
21
|
-
* strings; anything interpolated at render time is left to the runtime fallback.
|
|
13
|
+
* strings; anything interpolated at render time is left to the runtime fallback. Plugins whose value
|
|
14
|
+
* is a literal (mask, teleport, …) are skipped unless the attribute carries `__dynamic`.
|
|
22
15
|
*/
|
|
23
16
|
export declare const extractExpressions: (source: string, plugins: PluginMeta[], prefixes?: string[]) => Extracted[];
|
|
17
|
+
/**
|
|
18
|
+
* Keyed directive attributes whose key contains an uppercase letter. HTML lowercases attribute names,
|
|
19
|
+
* so `data-bind:firstName` reaches the runtime as `firstname`: write `data-bind:first-name`.
|
|
20
|
+
*/
|
|
21
|
+
export declare const lintSource: (source: string, prefixes?: string[]) => string[];
|
|
@@ -1,80 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { compileBody, functionCompiler } from "./compile.js";
|
|
2
2
|
import { expressionKey } from "./precompiled.js";
|
|
3
|
-
const ident = /[A-Za-z0-9_$]/;
|
|
4
|
-
const rewriteSignals = (src) => {
|
|
5
|
-
let out = "";
|
|
6
|
-
let i = 0;
|
|
7
|
-
const n = src.length;
|
|
8
|
-
const prevCode = () => {
|
|
9
|
-
for (let j = out.length - 1; j >= 0; j--) if (!/\s/.test(out[j])) return out[j];
|
|
10
|
-
return "";
|
|
11
|
-
};
|
|
12
|
-
while (i < n) {
|
|
13
|
-
const c = src[i];
|
|
14
|
-
const next = src[i + 1];
|
|
15
|
-
if (c === '"' || c === "'") {
|
|
16
|
-
let j = i + 1;
|
|
17
|
-
while (j < n && src[j] !== c) j += src[j] === "\\" ? 2 : 1;
|
|
18
|
-
out += src.slice(i, j + 1);
|
|
19
|
-
i = j + 1;
|
|
20
|
-
} else if (c === "`") {
|
|
21
|
-
out += c;
|
|
22
|
-
i++;
|
|
23
|
-
while (i < n && src[i] !== "`") {
|
|
24
|
-
if (src[i] === "\\") {
|
|
25
|
-
out += src.slice(i, i + 2);
|
|
26
|
-
i += 2;
|
|
27
|
-
} else if (src[i] === "$" && src[i + 1] === "{") {
|
|
28
|
-
let depth = 1;
|
|
29
|
-
let j = i + 2;
|
|
30
|
-
while (j < n && depth) {
|
|
31
|
-
if (src[j] === "{") depth++;
|
|
32
|
-
else if (src[j] === "}") depth--;
|
|
33
|
-
if (depth) j++;
|
|
34
|
-
}
|
|
35
|
-
out += `\${${rewriteSignals(src.slice(i + 2, j))}}`;
|
|
36
|
-
i = j + 1;
|
|
37
|
-
} else out += src[i++];
|
|
38
|
-
}
|
|
39
|
-
out += "`";
|
|
40
|
-
i++;
|
|
41
|
-
} else if (c === "/" && next === "/") {
|
|
42
|
-
const j = src.indexOf("\n", i);
|
|
43
|
-
i = j < 0 ? n : j;
|
|
44
|
-
} else if (c === "/" && next === "*") {
|
|
45
|
-
const j = src.indexOf("*/", i + 2);
|
|
46
|
-
i = j < 0 ? n : j + 2;
|
|
47
|
-
} else if (c === "$" && next !== void 0 && ident.test(next) && next !== "$" && prevCode() !== "." && !ident.test(out[out.length - 1] ?? "")) {
|
|
48
|
-
let j = i + 1;
|
|
49
|
-
while (j < n && ident.test(src[j])) j++;
|
|
50
|
-
out += `$.${src.slice(i + 1, j)}`;
|
|
51
|
-
i = j;
|
|
52
|
-
} else {
|
|
53
|
-
out += c;
|
|
54
|
-
i++;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return out;
|
|
58
|
-
};
|
|
59
|
-
const compileBody = (src, returns) => {
|
|
60
|
-
const code = rewriteSignals(rewriteActions(src.trim()));
|
|
61
|
-
if (!returns) return code;
|
|
62
|
-
const parts = splitStatements(code);
|
|
63
|
-
const last = parts.pop() ?? "";
|
|
64
|
-
return `${parts.length ? `${parts.join(";")};` : ""}return (${last}
|
|
65
|
-
)`;
|
|
66
|
-
};
|
|
67
3
|
const generateTable = (items) => {
|
|
68
4
|
const seen = /* @__PURE__ */ new Set();
|
|
69
5
|
const lines = [];
|
|
70
|
-
for (const { src, params
|
|
71
|
-
const key = expressionKey(src
|
|
6
|
+
for (const { src, params } of items) {
|
|
7
|
+
const key = expressionKey(src);
|
|
72
8
|
if (seen.has(key)) continue;
|
|
73
9
|
seen.add(key);
|
|
74
10
|
let body;
|
|
75
11
|
try {
|
|
76
|
-
body = compileBody(src,
|
|
77
|
-
Function("$", "__a", ...params, body);
|
|
12
|
+
[body] = compileBody(functionCompiler, src, params);
|
|
78
13
|
} catch {
|
|
79
14
|
continue;
|
|
80
15
|
}
|
|
@@ -93,7 +28,15 @@ const entities = {
|
|
|
93
28
|
">": ">",
|
|
94
29
|
"&": "&"
|
|
95
30
|
};
|
|
96
|
-
const decode = (s) => s.replace(
|
|
31
|
+
const decode = (s) => s.replace(
|
|
32
|
+
/&(?:quot|apos|lt|gt|amp|#\d+|#x[\da-f]+);/gi,
|
|
33
|
+
(m) => m[1] === "#" ? String.fromCodePoint(
|
|
34
|
+
Number.parseInt(
|
|
35
|
+
m[2] === "x" || m[2] === "X" ? m.slice(3, -1) : m.slice(2, -1),
|
|
36
|
+
m[2] === "x" || m[2] === "X" ? 16 : 10
|
|
37
|
+
)
|
|
38
|
+
) : entities[m.toLowerCase()] ?? m
|
|
39
|
+
);
|
|
97
40
|
const extractExpressions = (source, plugins, prefixes = ["data-"]) => {
|
|
98
41
|
const byName = new Map(plugins.map((p) => [p.name, p]));
|
|
99
42
|
const out = [];
|
|
@@ -103,16 +46,23 @@ const extractExpressions = (source, plugins, prefixes = ["data-"]) => {
|
|
|
103
46
|
const value = decode(m[2] ?? m[3] ?? "");
|
|
104
47
|
const prefix = prefixes.find((p) => attr.startsWith(p));
|
|
105
48
|
if (!prefix || !value.trim()) continue;
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
49
|
+
const [head, ...mods] = attr.slice(prefix.length).split("__");
|
|
50
|
+
const plugin = byName.get(head.split(":")[0]);
|
|
51
|
+
if (!plugin || plugin.literal && !mods.some((x) => x.split(".")[0] === "dynamic")) continue;
|
|
52
|
+
out.push({ src: value, params: ["el", "evt", ...plugin.args ?? []] });
|
|
109
53
|
}
|
|
110
54
|
return out;
|
|
111
55
|
};
|
|
56
|
+
const lintSource = (source, prefixes = ["data-"]) => {
|
|
57
|
+
const out = [];
|
|
58
|
+
for (const p of prefixes)
|
|
59
|
+
for (const m of source.matchAll(new RegExp(`(?<![\\w-])(${p}[a-z-]+:[^\\s="'<>]*[A-Z][^\\s="'<>]*)`, "g")))
|
|
60
|
+
out.push(`${m[1]}: attribute names are lowercased by HTML; write the key in kebab-case`);
|
|
61
|
+
return out;
|
|
62
|
+
};
|
|
112
63
|
export {
|
|
113
|
-
compileBody,
|
|
114
64
|
extractExpressions,
|
|
115
65
|
generateTable,
|
|
116
|
-
|
|
66
|
+
lintSource
|
|
117
67
|
};
|
|
118
68
|
//# sourceMappingURL=precompile.js.map
|