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.
Files changed (165) hide show
  1. package/README.md +10 -10
  2. package/dist/kernel/compile.d.ts +8 -9
  3. package/dist/kernel/compile.js +102 -67
  4. package/dist/kernel/compile.js.map +2 -2
  5. package/dist/kernel/contracts.d.ts +11 -5
  6. package/dist/kernel/index.d.ts +2 -2
  7. package/dist/kernel/index.js +5 -6
  8. package/dist/kernel/index.js.map +2 -2
  9. package/dist/kernel/precompile.d.ts +8 -10
  10. package/dist/kernel/precompile.js +25 -75
  11. package/dist/kernel/precompile.js.map +2 -2
  12. package/dist/kernel/precompiled.d.ts +7 -4
  13. package/dist/kernel/precompiled.js +5 -5
  14. package/dist/kernel/precompiled.js.map +2 -2
  15. package/dist/kernel/reactive.d.ts +8 -2
  16. package/dist/kernel/reactive.js +91 -62
  17. package/dist/kernel/reactive.js.map +3 -3
  18. package/dist/kernel/runtime.js +78 -68
  19. package/dist/kernel/runtime.js.map +3 -3
  20. package/dist/kernel/scan.d.ts +1 -1
  21. package/dist/kernel/scan.js +3 -3
  22. package/dist/kernel/scan.js.map +2 -2
  23. package/dist/kernel/state.d.ts +4 -3
  24. package/dist/kernel/state.js +91 -80
  25. package/dist/kernel/state.js.map +2 -2
  26. package/dist/kernel/strict-csp.d.ts +0 -5
  27. package/dist/kernel/strict-csp.js +2 -2
  28. package/dist/kernel/strict-csp.js.map +2 -2
  29. package/dist/lib/casing.d.ts +4 -1
  30. package/dist/lib/casing.js +8 -1
  31. package/dist/lib/casing.js.map +2 -2
  32. package/dist/lib/objects.d.ts +5 -3
  33. package/dist/lib/objects.js +10 -5
  34. package/dist/lib/objects.js.map +2 -2
  35. package/dist/lib/schedule.d.ts +3 -3
  36. package/dist/lib/schedule.js +12 -10
  37. package/dist/lib/schedule.js.map +2 -2
  38. package/dist/lib/sse.d.ts +10 -0
  39. package/dist/lib/sse.js +32 -29
  40. package/dist/lib/sse.js.map +2 -2
  41. package/dist/plugins/def.d.ts +5 -0
  42. package/dist/plugins/def.js +22 -0
  43. package/dist/plugins/def.js.map +7 -0
  44. package/dist/plugins/directives/attribute-sync.js +8 -12
  45. package/dist/plugins/directives/attribute-sync.js.map +2 -2
  46. package/dist/plugins/directives/boost.d.ts +1 -1
  47. package/dist/plugins/directives/boost.js +34 -31
  48. package/dist/plugins/directives/boost.js.map +2 -2
  49. package/dist/plugins/directives/busy-flag.js +13 -16
  50. package/dist/plugins/directives/busy-flag.js.map +2 -2
  51. package/dist/plugins/directives/class-toggle.js +17 -16
  52. package/dist/plugins/directives/class-toggle.js.map +2 -2
  53. package/dist/plugins/directives/cloak.js +2 -7
  54. package/dist/plugins/directives/cloak.js.map +2 -2
  55. package/dist/plugins/directives/collapse.js +36 -37
  56. package/dist/plugins/directives/collapse.js.map +2 -2
  57. package/dist/plugins/directives/declare.js +5 -8
  58. package/dist/plugins/directives/declare.js.map +2 -2
  59. package/dist/plugins/directives/derive.js +9 -18
  60. package/dist/plugins/directives/derive.js.map +2 -2
  61. package/dist/plugins/directives/element-ref.js +8 -8
  62. package/dist/plugins/directives/element-ref.js.map +2 -2
  63. package/dist/plugins/directives/event-listener.js +18 -26
  64. package/dist/plugins/directives/event-listener.js.map +2 -2
  65. package/dist/plugins/directives/frame-loop.js +9 -14
  66. package/dist/plugins/directives/frame-loop.js.map +2 -2
  67. package/dist/plugins/directives/html.js +6 -7
  68. package/dist/plugins/directives/html.js.map +2 -2
  69. package/dist/plugins/directives/inline-style.js +17 -20
  70. package/dist/plugins/directives/inline-style.js.map +2 -2
  71. package/dist/plugins/directives/mask.js +19 -23
  72. package/dist/plugins/directives/mask.js.map +2 -2
  73. package/dist/plugins/directives/media-query.d.ts +4 -1
  74. package/dist/plugins/directives/media-query.js +13 -13
  75. package/dist/plugins/directives/media-query.js.map +2 -2
  76. package/dist/plugins/directives/on-mount.js +4 -12
  77. package/dist/plugins/directives/on-mount.js.map +2 -2
  78. package/dist/plugins/directives/patch-listener.js +24 -19
  79. package/dist/plugins/directives/patch-listener.js.map +2 -2
  80. package/dist/plugins/directives/remove-me.js +7 -8
  81. package/dist/plugins/directives/remove-me.js.map +2 -2
  82. package/dist/plugins/directives/scroll-to.d.ts +4 -1
  83. package/dist/plugins/directives/scroll-to.js +8 -14
  84. package/dist/plugins/directives/scroll-to.js.map +2 -2
  85. package/dist/plugins/directives/size-watch.js +7 -12
  86. package/dist/plugins/directives/size-watch.js.map +2 -2
  87. package/dist/plugins/directives/state-dump.js +6 -10
  88. package/dist/plugins/directives/state-dump.js.map +2 -2
  89. package/dist/plugins/directives/storage-sync.js +13 -9
  90. package/dist/plugins/directives/storage-sync.js.map +2 -2
  91. package/dist/plugins/directives/teleport.js +8 -14
  92. package/dist/plugins/directives/teleport.js.map +2 -2
  93. package/dist/plugins/directives/text-content.js +6 -7
  94. package/dist/plugins/directives/text-content.js.map +2 -2
  95. package/dist/plugins/directives/timer.js +7 -13
  96. package/dist/plugins/directives/timer.js.map +2 -2
  97. package/dist/plugins/directives/transition.d.ts +1 -2
  98. package/dist/plugins/directives/transition.js +32 -34
  99. package/dist/plugins/directives/transition.js.map +2 -2
  100. package/dist/plugins/directives/tween.d.ts +2 -2
  101. package/dist/plugins/directives/tween.js +34 -50
  102. package/dist/plugins/directives/tween.js.map +2 -2
  103. package/dist/plugins/directives/two-way-bind.d.ts +1 -1
  104. package/dist/plugins/directives/two-way-bind.js +70 -97
  105. package/dist/plugins/directives/two-way-bind.js.map +2 -2
  106. package/dist/plugins/directives/url-params.js +35 -59
  107. package/dist/plugins/directives/url-params.js.map +3 -3
  108. package/dist/plugins/directives/url-replace.js +6 -7
  109. package/dist/plugins/directives/url-replace.js.map +2 -2
  110. package/dist/plugins/directives/validity.js +6 -9
  111. package/dist/plugins/directives/validity.js.map +2 -2
  112. package/dist/plugins/directives/viewport.js +18 -26
  113. package/dist/plugins/directives/viewport.js.map +2 -2
  114. package/dist/plugins/directives/visibility.js +9 -14
  115. package/dist/plugins/directives/visibility.js.map +2 -2
  116. package/dist/plugins/directives/watch.js +2 -8
  117. package/dist/plugins/directives/watch.js.map +2 -2
  118. package/dist/plugins/functions/bulk-set.js +7 -6
  119. package/dist/plugins/functions/bulk-set.js.map +2 -2
  120. package/dist/plugins/functions/bulk-toggle.js +7 -6
  121. package/dist/plugins/functions/bulk-toggle.js.map +2 -2
  122. package/dist/plugins/functions/confirm.js +2 -2
  123. package/dist/plugins/functions/confirm.js.map +2 -2
  124. package/dist/plugins/functions/copy-text.js +5 -5
  125. package/dist/plugins/functions/copy-text.js.map +2 -2
  126. package/dist/plugins/functions/dispatch.js +5 -5
  127. package/dist/plugins/functions/dispatch.js.map +2 -2
  128. package/dist/plugins/functions/locale-format.d.ts +4 -1
  129. package/dist/plugins/functions/locale-format.js +9 -16
  130. package/dist/plugins/functions/locale-format.js.map +2 -2
  131. package/dist/plugins/functions/range-map.js +6 -6
  132. package/dist/plugins/functions/range-map.js.map +2 -2
  133. package/dist/plugins/functions/request.d.ts +7 -3
  134. package/dist/plugins/functions/request.js +77 -86
  135. package/dist/plugins/functions/request.js.map +2 -2
  136. package/dist/plugins/functions/untracked-read.js +3 -2
  137. package/dist/plugins/functions/untracked-read.js.map +2 -2
  138. package/dist/plugins/functions/websocket.d.ts +3 -3
  139. package/dist/plugins/functions/websocket.js +13 -24
  140. package/dist/plugins/functions/websocket.js.map +2 -2
  141. package/dist/plugins/index.d.ts +0 -2
  142. package/dist/plugins/index.js +0 -4
  143. package/dist/plugins/index.js.map +2 -2
  144. package/dist/plugins/server-events/apply-elements.d.ts +1 -1
  145. package/dist/plugins/server-events/apply-elements.js +41 -43
  146. package/dist/plugins/server-events/apply-elements.js.map +2 -2
  147. package/dist/plugins/server-events/apply-state.js +9 -12
  148. package/dist/plugins/server-events/apply-state.js.map +2 -2
  149. package/dist/plugins/server-events/morph.js +46 -66
  150. package/dist/plugins/server-events/morph.js.map +3 -3
  151. package/dist/presets/all.js +0 -4
  152. package/dist/presets/all.js.map +2 -2
  153. package/dist/server.d.ts +10 -4
  154. package/dist/server.js +42 -14
  155. package/dist/server.js.map +2 -2
  156. package/dist/sigmx.standalone.js +1 -1
  157. package/dist/vite.js +17 -7
  158. package/dist/vite.js.map +2 -2
  159. package/package.json +4 -2
  160. package/dist/plugins/directives/transition-name.d.ts +0 -1
  161. package/dist/plugins/directives/transition-name.js +0 -11
  162. package/dist/plugins/directives/transition-name.js.map +0 -7
  163. package/dist/plugins/directives/trap.d.ts +0 -5
  164. package/dist/plugins/directives/trap.js +0 -54
  165. package/dist/plugins/directives/trap.js.map +0 -7
@@ -1,66 +1,59 @@
1
1
  import { recase } from "../lib/casing.js";
2
2
  import { functionCompiler } from "./compile.js";
3
- import { effect } from "./reactive.js";
3
+ import { rootEffect } from "./reactive.js";
4
4
  import { createStore } from "./state.js";
5
5
  const isEl = (n) => n.nodeType === 1;
6
- const tree = (n) => isEl(n) ? [n, ...n.querySelectorAll("*")] : n instanceof ShadowRoot ? [...n.querySelectorAll("*")] : [];
7
- const parsed = /* @__PURE__ */ new Map();
6
+ const tree = (n) => n.querySelectorAll ? [...isEl(n) ? [n] : [], ...n.querySelectorAll("*")] : [];
8
7
  const parseAttr = (raw) => {
9
- let p = parsed.get(raw);
10
- if (!p) {
11
- const [head, ...modParts] = raw.split("__");
12
- const i = head.indexOf(":");
13
- const mods = /* @__PURE__ */ new Map();
14
- for (const m of modParts) {
15
- const [name, ...args] = m.split(".");
16
- mods.set(name, args);
17
- }
18
- p = { plugin: i < 0 ? head : head.slice(0, i), key: i < 0 ? void 0 : head.slice(i + 1), mods };
19
- parsed.set(raw, p);
20
- }
21
- return p;
8
+ const [head, ...modParts] = raw.split("__");
9
+ const [, plugin, key] = /^([^:]*)(?::(.*))?$/.exec(head);
10
+ return {
11
+ plugin,
12
+ key,
13
+ mods: new Map(
14
+ modParts.map((m) => {
15
+ const [name, ...args] = m.split(".");
16
+ return [name, args];
17
+ })
18
+ )
19
+ };
20
+ };
21
+ const cut = (list, s) => {
22
+ for (const p of list) if (s.startsWith(p)) return s.slice(p.length);
22
23
  };
23
- const fail = (message, info) => Object.assign(new Error(message), { info });
24
24
  const createRuntime = (options) => {
25
25
  const prefixes = [].concat(options.prefix ?? "data-");
26
26
  const eventPrefixes = [].concat(options.eventPrefix ?? "sigmx-");
27
27
  const store = options.store ?? createStore();
28
- const compiler = options.compile ?? functionCompiler;
29
28
  const { expressions } = options;
30
29
  const onError = options.onError ?? ((e, info) => console.error(e, info));
31
30
  const attributes = /* @__PURE__ */ Object.create(null);
32
- const actions = /* @__PURE__ */ Object.create(null);
33
- const handlers = /* @__PURE__ */ Object.create(null);
34
31
  const runtime = {
35
32
  prefixes,
36
33
  attr: (name) => prefixes[0] + name,
37
34
  store,
38
- compiler,
35
+ compiler: options.compile ?? functionCompiler,
39
36
  emit: (type, detail) => document.dispatchEvent(new CustomEvent(`sigmx-${type}`, { detail })),
40
37
  call: (name, ctx, args) => {
41
- const a = actions[name];
38
+ const a = runtime.actions[name];
42
39
  if (!a) throw ctx.error(`unknown action @${name}`);
43
40
  return a.call(ctx, ...args);
44
41
  },
45
42
  eventPrefixes,
46
43
  handle: (event, data) => {
47
- const p = eventPrefixes.find((p2) => event.startsWith(p2));
48
- const h = handlers[p ? event.slice(p.length) : event];
44
+ const h = runtime.handlers[cut(eventPrefixes, event) ?? event];
49
45
  h?.handle(runtime, data);
50
46
  return !!h;
51
47
  },
52
48
  attributes,
53
- actions,
54
- handlers
49
+ actions: /* @__PURE__ */ Object.create(null),
50
+ handlers: /* @__PURE__ */ Object.create(null)
55
51
  };
56
52
  const mounted = /* @__PURE__ */ new Map();
57
53
  const roots = /* @__PURE__ */ new Set();
58
- const ignoreSelf = prefixes.map((p) => `[${p}ignore__self]`).join();
59
54
  const ignoreAny = prefixes.map((p) => `[${p}ignore]`).join();
60
- const ignored = (el) => el.matches(ignoreSelf) || !!el.closest(ignoreAny);
61
- const strip = (attr) => {
62
- for (const p of prefixes) if (attr.startsWith(p)) return attr.slice(p.length);
63
- };
55
+ const ignored = (el) => !!el.closest(ignoreAny);
56
+ let destroyed = false;
64
57
  const unmount = (els) => {
65
58
  for (const el of els) {
66
59
  const m = mounted.get(el);
@@ -72,29 +65,30 @@ const createRuntime = (options) => {
72
65
  m?.get(attr)?.();
73
66
  m?.delete(attr);
74
67
  };
75
- const actionsFor = (el, evt, error, cleanup, report) => {
76
- const ctx = { el, evt, store, runtime, error, cleanup };
77
- return new Proxy(
78
- {},
79
- {
80
- get: (_, name) => (...args) => {
81
- const r = runtime.call(name, ctx, args);
82
- if (r instanceof Promise) r.catch(report);
83
- return r;
84
- }
85
- }
86
- );
87
- };
88
68
  const mount = (el, attr, raw, value, only) => {
89
69
  const { plugin: name, key, mods } = parseAttr(raw);
90
70
  const plugin = attributes[name];
91
71
  if (!plugin || only && !only.has(name)) return;
92
72
  unmountAttr(el, attr);
93
73
  const disposers = [];
74
+ const cleanup = (f) => {
75
+ disposers.push(f);
76
+ return () => {
77
+ const i = disposers.indexOf(f);
78
+ if (i >= 0) disposers.splice(i, 1);
79
+ };
80
+ };
94
81
  const info = { plugin: name, el, attr };
95
- const error = (message, extra) => fail(`${prefixes[0]}${name}: ${message}`, { ...info, ...extra });
82
+ const error = (message, extra) => Object.assign(new Error(`${prefixes[0]}${name}: ${message}`), { info: { ...info, ...extra } });
96
83
  const report = (e) => onError(e, info);
97
84
  let fn;
85
+ const watched = /* @__PURE__ */ new WeakSet();
86
+ const watch = (r) => {
87
+ if (r instanceof Promise && !watched.has(r)) {
88
+ watched.add(r);
89
+ r.catch(report);
90
+ }
91
+ };
98
92
  const ctx = {
99
93
  el,
100
94
  plugin: name,
@@ -104,10 +98,27 @@ const createRuntime = (options) => {
104
98
  mods,
105
99
  cased: (style = "camel") => recase(key ?? "", mods.get("case")?.[0] || style),
106
100
  evaluate: (evt, ...args) => {
107
- fn ??= expressions(value, ["el", "evt", ...plugin.args ?? []], plugin.returns ?? true);
108
- return fn(store, actionsFor(el, evt, error, ctx.cleanup, report), el, evt, ...args);
101
+ if (plugin.literal && !mods.has("dynamic")) return value;
102
+ fn ??= expressions(value, ["el", "evt", ...plugin.args ?? []]);
103
+ const actx = { el, evt, store, runtime, error, cleanup, report };
104
+ const actions = new Proxy(
105
+ {},
106
+ {
107
+ get: (_, name2) => (...args2) => {
108
+ const r2 = runtime.call(name2, actx, args2);
109
+ watch(r2);
110
+ return r2;
111
+ }
112
+ }
113
+ );
114
+ const r = fn(store, actions, el, evt, ...args);
115
+ watch(r);
116
+ return r;
117
+ },
118
+ // Root-owned: an attribute mounted from inside another effect must outlive that effect's re-runs.
119
+ effect: (f) => {
120
+ cleanup(rootEffect(f, report));
109
121
  },
110
- effect: (f) => disposers.push(effect(f, report)),
111
122
  listen: (target, type, f, opts) => {
112
123
  const h = (e) => {
113
124
  try {
@@ -117,10 +128,11 @@ const createRuntime = (options) => {
117
128
  }
118
129
  };
119
130
  target.addEventListener(type, h, opts);
120
- disposers.push(() => target.removeEventListener(type, h, opts));
131
+ cleanup(() => target.removeEventListener(type, h, opts));
121
132
  },
122
- cleanup: (f) => disposers.push(f),
133
+ cleanup,
123
134
  error,
135
+ report,
124
136
  store,
125
137
  runtime
126
138
  };
@@ -133,12 +145,16 @@ const createRuntime = (options) => {
133
145
  for (const d of disposers.splice(0)) d();
134
146
  });
135
147
  try {
136
- if (plugin.key === "required" && !key) throw error("needs a key");
137
- if (plugin.key === "forbidden" && key) throw error("takes no key");
138
- if (plugin.value === "required" && !value) throw error("needs a value");
139
- if (plugin.value === "forbidden" && value) throw error("takes no value");
148
+ for (const [k, v] of [
149
+ ["key", key],
150
+ ["value", value]
151
+ ]) {
152
+ const rule = plugin[k];
153
+ if (rule && rule === "required" === !v) throw error(`${rule === "required" ? "needs a" : "takes no"} ${k}`);
154
+ }
140
155
  const r = plugin.mount(ctx);
141
- if (typeof r === "function") disposers.push(r);
156
+ if (typeof r === "function") cleanup(r);
157
+ else watch(r);
142
158
  } catch (e) {
143
159
  report(e);
144
160
  }
@@ -147,7 +163,7 @@ const createRuntime = (options) => {
147
163
  for (const el of els) {
148
164
  if (ignored(el)) continue;
149
165
  for (const { name, value } of [...el.attributes]) {
150
- const raw = strip(name);
166
+ const raw = cut(prefixes, name);
151
167
  if (raw && !mounted.get(el)?.has(name)) mount(el, name, raw, value, only);
152
168
  }
153
169
  }
@@ -155,10 +171,10 @@ const createRuntime = (options) => {
155
171
  const observer = new MutationObserver((records) => {
156
172
  for (const { type, target, attributeName, addedNodes, removedNodes } of records) {
157
173
  if (type === "childList") {
158
- for (const n of removedNodes) unmount(tree(n));
174
+ for (const n of removedNodes) if (!n.isConnected) unmount(tree(n));
159
175
  for (const n of addedNodes) mountEls(tree(n));
160
176
  } else if (attributeName && isEl(target) && !ignored(target)) {
161
- const raw = strip(attributeName);
177
+ const raw = cut(prefixes, attributeName);
162
178
  if (!raw) continue;
163
179
  const value = target.getAttribute(attributeName);
164
180
  if (value === null) unmountAttr(target, attributeName);
@@ -166,26 +182,19 @@ const createRuntime = (options) => {
166
182
  }
167
183
  }
168
184
  });
169
- let ready = false;
170
185
  const apply = (root = document.documentElement, observe = true, only) => {
186
+ if (destroyed) return;
171
187
  mountEls(tree(root), only);
172
188
  if (observe && !roots.has(root)) {
173
189
  observer.observe(root, { subtree: true, childList: true, attributes: true });
174
190
  roots.add(root);
175
191
  }
176
- if (!ready && roots.has(document.documentElement)) {
177
- ready = true;
178
- runtime.emit("ready");
179
- }
180
192
  };
181
193
  const use = (...plugins) => {
182
194
  const added = /* @__PURE__ */ new Set();
183
195
  for (const p of plugins) {
184
- if (p.type === "attribute") {
185
- attributes[p.name] = p;
186
- added.add(p.name);
187
- } else if (p.type === "action") actions[p.name] = p;
188
- else handlers[p.name] = p;
196
+ runtime[`${p.type}s`][p.name] = p;
197
+ if (p.type === "attribute") added.add(p.name);
189
198
  }
190
199
  if (added.size) for (const r of roots) apply(r, false, added);
191
200
  };
@@ -200,6 +209,7 @@ const createRuntime = (options) => {
200
209
  apply: (root, observe) => apply(root, observe),
201
210
  use,
202
211
  destroy: () => {
212
+ destroyed = true;
203
213
  observer.disconnect();
204
214
  stopPatches();
205
215
  unmount([...mounted.keys()]);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/kernel/runtime.ts"],
4
- "sourcesContent": ["import { type CaseStyle, recase } from '../lib/casing.js';\nimport { functionCompiler } from './compile.js';\nimport type {\n ActionCtx,\n AttributePlugin,\n Ctx,\n El,\n Evaluator,\n Mods,\n Plugin,\n Runtime,\n RuntimeOptions,\n Sigmx,\n} from './contracts.js';\nimport { effect } from './reactive.js';\nimport { createStore } from './state.js';\n\nconst isEl = (n: Node): n is El => n.nodeType === 1;\n/** An element (or shadow root) followed by every element under it; nothing for text and comment nodes. */\nconst tree = (n: Node): El[] =>\n isEl(n) ? [n, ...n.querySelectorAll<El>('*')] : n instanceof ShadowRoot ? [...n.querySelectorAll<El>('*')] : [];\n\ntype Parsed = { plugin: string; key: string | undefined; mods: Mods };\nconst parsed = new Map<string, Parsed>();\n\n/** 'on:click__debounce.300ms__prevent' \u2192 { plugin: 'on', key: 'click', mods: {debounce: ['300ms'], prevent: []} } */\nexport const parseAttr = (raw: string): Parsed => {\n let p = parsed.get(raw);\n if (!p) {\n const [head, ...modParts] = raw.split('__');\n const i = head.indexOf(':');\n const mods: Mods = new Map();\n for (const m of modParts) {\n const [name, ...args] = m.split('.');\n mods.set(name, args);\n }\n p = { plugin: i < 0 ? head : head.slice(0, i), key: i < 0 ? undefined : head.slice(i + 1), mods };\n parsed.set(raw, p);\n }\n return p;\n};\n\nconst fail = (message: string, info: Record<string, unknown>): Error => Object.assign(new Error(message), { info });\n\n/** Low-level constructor: you supply the expression pipeline. `createSigmx` wraps it with the runtime compiler. */\nexport const createRuntime = (options: RuntimeOptions): Sigmx => {\n const prefixes = ([] as string[]).concat(options.prefix ?? 'data-');\n const eventPrefixes = ([] as string[]).concat(options.eventPrefix ?? 'sigmx-');\n const store = options.store ?? createStore();\n const compiler = options.compile ?? functionCompiler;\n const { expressions } = options;\n const onError = options.onError ?? ((e, info) => console.error(e, info));\n const attributes: Record<string, AttributePlugin> = Object.create(null);\n const actions: Runtime['actions'] = Object.create(null);\n const handlers: Runtime['handlers'] = Object.create(null);\n\n const runtime: Runtime = {\n prefixes,\n attr: (name) => prefixes[0] + name,\n store,\n compiler,\n emit: (type, detail) => document.dispatchEvent(new CustomEvent(`sigmx-${type}`, { detail })),\n call: (name, ctx, args) => {\n const a = actions[name];\n if (!a) throw ctx.error(`unknown action @${name}`);\n return a.call(ctx, ...args);\n },\n eventPrefixes,\n handle: (event, data) => {\n const p = eventPrefixes.find((p) => event.startsWith(p));\n const h = handlers[p ? event.slice(p.length) : event];\n h?.handle(runtime, data);\n return !!h;\n },\n attributes,\n actions,\n handlers,\n };\n\n // element \u2192 attribute name \u2192 dispose\n const mounted = new Map<El, Map<string, () => void>>();\n const roots = new Set<El | ShadowRoot>();\n const ignoreSelf = prefixes.map((p) => `[${p}ignore__self]`).join();\n const ignoreAny = prefixes.map((p) => `[${p}ignore]`).join();\n const ignored = (el: El) => el.matches(ignoreSelf) || !!el.closest(ignoreAny);\n\n const strip = (attr: string): string | undefined => {\n for (const p of prefixes) if (attr.startsWith(p)) return attr.slice(p.length);\n };\n\n const unmount = (els: Iterable<El>): void => {\n for (const el of els) {\n const m = mounted.get(el);\n if (m && mounted.delete(el)) for (const d of m.values()) d();\n }\n };\n\n const unmountAttr = (el: El, attr: string): void => {\n const m = mounted.get(el);\n m?.get(attr)?.();\n m?.delete(attr);\n };\n\n const actionsFor = (\n el: El,\n evt: Event | undefined,\n error: Ctx['error'],\n cleanup: (fn: () => void) => void,\n report: (e: unknown) => void,\n ) => {\n const ctx: ActionCtx = { el, evt, store, runtime, error, cleanup };\n return new Proxy(\n {},\n {\n get:\n (_, name: string) =>\n (...args: any[]) => {\n const r = runtime.call(name, ctx, args);\n // Async actions (requests) reject long after the expression returned; route that to onError.\n if (r instanceof Promise) r.catch(report);\n return r;\n },\n },\n );\n };\n\n const mount = (el: El, attr: string, raw: string, value: string, only?: Set<string>): void => {\n const { plugin: name, key, mods } = parseAttr(raw);\n const plugin = attributes[name];\n if (!plugin || (only && !only.has(name))) return;\n unmountAttr(el, attr);\n\n const disposers: (() => void)[] = [];\n const info = { plugin: name, el, attr };\n const error: Ctx['error'] = (message, extra) => fail(`${prefixes[0]}${name}: ${message}`, { ...info, ...extra });\n const report = (e: unknown) => onError(e, info);\n let fn: Evaluator | undefined;\n const ctx: Ctx = {\n el,\n plugin: name,\n attr,\n key,\n value,\n mods,\n cased: (style = 'camel') => recase(key ?? '', (mods.get('case')?.[0] as CaseStyle) || style),\n evaluate: (evt, ...args) => {\n fn ??= expressions(value, ['el', 'evt', ...(plugin.args ?? [])], plugin.returns ?? true);\n return fn(store, actionsFor(el, evt, error, ctx.cleanup, report), el, evt, ...args);\n },\n effect: (f) => disposers.push(effect(f, report)),\n listen: (target, type, f, opts) => {\n const h = (e: Event) => {\n try {\n f(e);\n } catch (err) {\n report(err);\n }\n };\n target.addEventListener(type, h, opts);\n disposers.push(() => target.removeEventListener(type, h, opts));\n },\n cleanup: (f) => disposers.push(f),\n error,\n store,\n runtime,\n };\n\n let m = mounted.get(el);\n if (!m) {\n m = new Map();\n mounted.set(el, m);\n }\n m.set(attr, () => {\n for (const d of disposers.splice(0)) d();\n });\n\n try {\n if (plugin.key === 'required' && !key) throw error('needs a key');\n if (plugin.key === 'forbidden' && key) throw error('takes no key');\n if (plugin.value === 'required' && !value) throw error('needs a value');\n if (plugin.value === 'forbidden' && value) throw error('takes no value');\n const r = plugin.mount(ctx);\n if (typeof r === 'function') disposers.push(r);\n } catch (e) {\n report(e);\n }\n };\n\n const mountEls = (els: Iterable<El>, only?: Set<string>): void => {\n for (const el of els) {\n if (ignored(el)) continue;\n for (const { name, value } of [...el.attributes]) {\n const raw = strip(name);\n // Observers can report a subtree more than once (nested insertions); a mounted attribute stays as it is.\n if (raw && !mounted.get(el)?.has(name)) mount(el, name, raw, value, only);\n }\n }\n };\n\n const observer = new MutationObserver((records) => {\n for (const { type, target, attributeName, addedNodes, removedNodes } of records) {\n if (type === 'childList') {\n for (const n of removedNodes) unmount(tree(n));\n for (const n of addedNodes) mountEls(tree(n));\n } else if (attributeName && isEl(target) && !ignored(target)) {\n const raw = strip(attributeName);\n if (!raw) continue;\n const value = target.getAttribute(attributeName);\n if (value === null) unmountAttr(target, attributeName);\n else mount(target, attributeName, raw, value);\n }\n }\n });\n\n let ready = false;\n const apply = (root: El | ShadowRoot = document.documentElement, observe = true, only?: Set<string>) => {\n mountEls(tree(root), only);\n if (observe && !roots.has(root)) {\n observer.observe(root, { subtree: true, childList: true, attributes: true });\n roots.add(root);\n }\n if (!ready && roots.has(document.documentElement)) {\n ready = true;\n runtime.emit('ready');\n }\n };\n\n const use = (...plugins: Plugin[]): void => {\n const added = new Set<string>();\n for (const p of plugins) {\n if (p.type === 'attribute') {\n attributes[p.name] = p;\n added.add(p.name);\n } else if (p.type === 'action') actions[p.name] = p;\n else handlers[p.name] = p;\n }\n if (added.size) for (const r of roots) apply(r, false, added);\n };\n\n const stopPatches = store.onPatch((patch) => runtime.emit('signal-patch', patch));\n use(...(options.plugins ?? []));\n\n const sigmx: Sigmx = {\n runtime,\n store,\n get $() {\n return store.$;\n },\n apply: (root, observe) => apply(root, observe),\n use,\n destroy: () => {\n observer.disconnect();\n stopPatches();\n unmount([...mounted.keys()]);\n roots.clear();\n },\n };\n\n if (options.autoStart ?? true) {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => sigmx.apply(), { once: true });\n } else {\n sigmx.apply();\n }\n }\n return sigmx;\n};\n"],
5
- "mappings": "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",
6
- "names": ["p"]
4
+ "sourcesContent": ["import { type CaseStyle, recase } from '../lib/casing.js';\nimport { functionCompiler } from './compile.js';\nimport type {\n ActionCtx,\n AttributePlugin,\n Ctx,\n El,\n Evaluator,\n Mods,\n Plugin,\n Runtime,\n RuntimeOptions,\n Sigmx,\n} from './contracts.js';\nimport { rootEffect } from './reactive.js';\nimport { createStore } from './state.js';\n\nconst isEl = (n: Node): n is El => n.nodeType === 1;\n/** An element (or shadow root) followed by every element under it; nothing for text and comment nodes. */\nconst tree = (n: Node): El[] =>\n (n as ParentNode).querySelectorAll ? [...(isEl(n) ? [n] : []), ...(n as ParentNode).querySelectorAll<El>('*')] : [];\n\ntype Parsed = { plugin: string; key: string | undefined; mods: Mods };\n\n/** 'on:click__debounce.300ms__prevent' \u2192 { plugin: 'on', key: 'click', mods: {debounce: ['300ms'], prevent: []} } */\nexport const parseAttr = (raw: string): Parsed => {\n const [head, ...modParts] = raw.split('__');\n const [, plugin, key] = /^([^:]*)(?::(.*))?$/.exec(head) as string[];\n return {\n plugin,\n key,\n mods: new Map(\n modParts.map((m) => {\n const [name, ...args] = m.split('.');\n return [name, args];\n }),\n ),\n };\n};\n\n/** The rest of `s` after the first prefix in `list` that it starts with; undefined when none matches. */\nconst cut = (list: readonly string[], s: string): string | undefined => {\n for (const p of list) if (s.startsWith(p)) return s.slice(p.length);\n};\n\n/** Low-level constructor: you supply the expression pipeline. `createSigmx` wraps it with the runtime compiler. */\nexport const createRuntime = (options: RuntimeOptions): Sigmx => {\n const prefixes = ([] as string[]).concat(options.prefix ?? 'data-');\n const eventPrefixes = ([] as string[]).concat(options.eventPrefix ?? 'sigmx-');\n const store = options.store ?? createStore();\n const { expressions } = options;\n const onError = options.onError ?? ((e, info) => console.error(e, info));\n const attributes: Record<string, AttributePlugin> = Object.create(null);\n\n const runtime: Runtime = {\n prefixes,\n attr: (name) => prefixes[0] + name,\n store,\n compiler: options.compile ?? functionCompiler,\n emit: (type, detail) => document.dispatchEvent(new CustomEvent(`sigmx-${type}`, { detail })),\n call: (name, ctx, args) => {\n const a = runtime.actions[name];\n if (!a) throw ctx.error(`unknown action @${name}`);\n return a.call(ctx, ...args);\n },\n eventPrefixes,\n handle: (event, data) => {\n const h = runtime.handlers[cut(eventPrefixes, event) ?? event];\n h?.handle(runtime, data);\n return !!h;\n },\n attributes,\n actions: Object.create(null),\n handlers: Object.create(null),\n };\n\n // element \u2192 attribute name \u2192 dispose\n const mounted = new Map<El, Map<string, () => void>>();\n const roots = new Set<El | ShadowRoot>();\n const ignoreAny = prefixes.map((p) => `[${p}ignore]`).join();\n const ignored = (el: El) => !!el.closest(ignoreAny);\n let destroyed = false;\n\n const unmount = (els: Iterable<El>): void => {\n for (const el of els) {\n const m = mounted.get(el);\n if (m && mounted.delete(el)) for (const d of m.values()) d();\n }\n };\n\n const unmountAttr = (el: El, attr: string): void => {\n const m = mounted.get(el);\n m?.get(attr)?.();\n m?.delete(attr);\n };\n\n const mount = (el: El, attr: string, raw: string, value: string, only?: Set<string>): void => {\n const { plugin: name, key, mods } = parseAttr(raw);\n const plugin = attributes[name];\n if (!plugin || (only && !only.has(name))) return;\n unmountAttr(el, attr);\n\n const disposers: (() => void)[] = [];\n const cleanup = (f: () => void) => {\n disposers.push(f);\n return () => {\n const i = disposers.indexOf(f);\n if (i >= 0) disposers.splice(i, 1);\n };\n };\n const info = { plugin: name, el, attr };\n const error: Ctx['error'] = (message, extra) =>\n Object.assign(new Error(`${prefixes[0]}${name}: ${message}`), { info: { ...info, ...extra } });\n const report = (e: unknown) => onError(e, info);\n let fn: Evaluator | undefined;\n const watched = new WeakSet<Promise<unknown>>(); // promises already routed to onError\n const watch = (r: unknown) => {\n if (r instanceof Promise && !watched.has(r)) {\n watched.add(r);\n r.catch(report);\n }\n };\n const ctx: Ctx = {\n el,\n plugin: name,\n attr,\n key,\n value,\n mods,\n cased: (style = 'camel') => recase(key ?? '', (mods.get('case')?.[0] as CaseStyle) || style),\n evaluate: (evt, ...args) => {\n if (plugin.literal && !mods.has('dynamic')) return value;\n fn ??= expressions(value, ['el', 'evt', ...(plugin.args ?? [])]);\n const actx: ActionCtx = { el, evt, store, runtime, error, cleanup, report };\n const actions = new Proxy(\n {},\n {\n get:\n (_, name: string) =>\n (...args: any[]) => {\n const r = runtime.call(name, actx, args);\n watch(r); // async actions (requests) reject long after the expression returned\n return r;\n },\n },\n );\n const r = fn(store, actions, el, evt, ...args);\n watch(r); // an expression's own rejected promise is reported too, once\n return r;\n },\n // Root-owned: an attribute mounted from inside another effect must outlive that effect's re-runs.\n effect: (f) => {\n cleanup(rootEffect(f, report));\n },\n listen: (target, type, f, opts) => {\n const h = (e: Event) => {\n try {\n f(e);\n } catch (err) {\n report(err);\n }\n };\n target.addEventListener(type, h, opts);\n cleanup(() => target.removeEventListener(type, h, opts));\n },\n cleanup,\n error,\n report,\n store,\n runtime,\n };\n\n let m = mounted.get(el);\n if (!m) {\n m = new Map();\n mounted.set(el, m);\n }\n m.set(attr, () => {\n for (const d of disposers.splice(0)) d();\n });\n\n try {\n // Contract checks: a keyed directive without a key would otherwise write to the path ''.\n for (const [k, v] of [\n ['key', key],\n ['value', value],\n ] as const) {\n const rule = plugin[k];\n if (rule && (rule === 'required') === !v) throw error(`${rule === 'required' ? 'needs a' : 'takes no'} ${k}`);\n }\n const r: unknown = plugin.mount(ctx);\n if (typeof r === 'function') cleanup(r as () => void);\n else watch(r); // an async mount that rejects is reported, not lost\n } catch (e) {\n report(e);\n }\n };\n\n const mountEls = (els: Iterable<El>, only?: Set<string>): void => {\n for (const el of els) {\n if (ignored(el)) continue;\n for (const { name, value } of [...el.attributes]) {\n const raw = cut(prefixes, name);\n // Observers can report a subtree more than once (nested insertions); a mounted attribute stays as it is.\n if (raw && !mounted.get(el)?.has(name)) mount(el, name, raw, value, only);\n }\n }\n };\n\n const observer = new MutationObserver((records) => {\n for (const { type, target, attributeName, addedNodes, removedNodes } of records) {\n if (type === 'childList') {\n // A node that is still connected was moved (teleport, morph), not removed: it keeps its state.\n for (const n of removedNodes) if (!n.isConnected) unmount(tree(n));\n for (const n of addedNodes) mountEls(tree(n));\n } else if (attributeName && isEl(target) && !ignored(target)) {\n const raw = cut(prefixes, attributeName);\n if (!raw) continue;\n const value = target.getAttribute(attributeName);\n if (value === null) unmountAttr(target, attributeName);\n else mount(target, attributeName, raw, value);\n }\n }\n });\n\n const apply = (root: El | ShadowRoot = document.documentElement, observe = true, only?: Set<string>) => {\n if (destroyed) return;\n mountEls(tree(root), only);\n if (observe && !roots.has(root)) {\n observer.observe(root, { subtree: true, childList: true, attributes: true });\n roots.add(root);\n }\n };\n\n const use = (...plugins: Plugin[]): void => {\n const added = new Set<string>();\n for (const p of plugins) {\n (runtime as any)[`${p.type}s`][p.name] = p;\n if (p.type === 'attribute') added.add(p.name);\n }\n if (added.size) for (const r of roots) apply(r, false, added);\n };\n\n const stopPatches = store.onPatch((patch) => runtime.emit('signal-patch', patch));\n use(...(options.plugins ?? []));\n\n const sigmx: Sigmx = {\n runtime,\n store,\n get $() {\n return store.$;\n },\n apply: (root, observe) => apply(root, observe),\n use,\n destroy: () => {\n destroyed = true;\n observer.disconnect();\n stopPatches();\n unmount([...mounted.keys()]);\n roots.clear();\n },\n };\n\n if (options.autoStart ?? true) {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => sigmx.apply(), { once: true });\n } else {\n sigmx.apply();\n }\n }\n return sigmx;\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["name", "args", "r"]
7
7
  }
@@ -4,7 +4,7 @@ export type PluginMeta = {
4
4
  name: string;
5
5
  type: Plugin['type'];
6
6
  from: string;
7
- returns?: boolean;
7
+ literal?: boolean;
8
8
  args?: string[];
9
9
  };
10
10
  export declare const implied: Record<string, string[]>;
@@ -11,7 +11,7 @@ const builtinPlugins = () => Object.entries(builtins).filter(([, v]) => v && typ
11
11
  name: p.name,
12
12
  type: p.type,
13
13
  from: "sigmx/plugins",
14
- returns: p.returns,
14
+ literal: p.literal,
15
15
  args: p.args
16
16
  };
17
17
  });
@@ -25,14 +25,14 @@ const customPluginMeta = (exportName, source, from) => {
25
25
  const body = m[2];
26
26
  const name = /\bname\s*:\s*['"`]([^'"`]+)['"`]/.exec(body)?.[1];
27
27
  if (!name) return;
28
- const returns = /\breturns\s*:\s*(true|false)/.exec(body)?.[1];
28
+ const literal = /\bliteral\s*:\s*true/.test(body);
29
29
  const args = /\bargs\s*:\s*\[([^\]]*)\]/.exec(body)?.[1];
30
30
  return {
31
31
  export: exportName,
32
32
  name,
33
33
  type: m[1],
34
34
  from,
35
- returns: returns === void 0 ? void 0 : returns === "true",
35
+ literal: literal || void 0,
36
36
  args: args?.split(",").map((s) => s.trim().replace(/^['"`]|['"`]$/g, "")).filter(Boolean)
37
37
  };
38
38
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/kernel/scan.ts"],
4
- "sourcesContent": ["// Node only; never bundled for the browser.\nimport * as builtins from '../plugins/index.js';\nimport type { Plugin } from './contracts.js';\n\nexport type PluginMeta = {\n export: string;\n name: string;\n type: Plugin['type'];\n from: string;\n returns?: boolean;\n args?: string[];\n};\n\nconst NETWORK = ['httpGet', 'httpPost', 'httpPut', 'httpPatch', 'httpDelete', 'websocket', 'boost'];\n\nexport const implied: Record<string, string[]> = {\n ...Object.fromEntries(NETWORK.map((n) => [n, ['applyElements', 'applyState']])),\n boost: ['httpGet', 'httpPost', 'applyElements', 'applyState'],\n};\n\nexport const builtinPlugins = (): PluginMeta[] =>\n Object.entries(builtins)\n .filter(([, v]) => v && typeof v === 'object' && 'type' in (v as object))\n .map(([key, v]) => {\n const p = v as Plugin;\n return {\n export: key,\n name: p.name,\n type: p.type,\n from: 'sigmx/plugins',\n returns: (p as any).returns,\n args: (p as any).args,\n };\n });\n\n/**\n * Read a custom plugin's metadata from its source without executing it: finds\n * `attribute({ name: 'x', ... })`, `action({...})` or `handler({...})` near `export const <exportName>`.\n */\nexport const customPluginMeta = (exportName: string, source: string, from: string): PluginMeta | undefined => {\n const re = new RegExp(\n `export\\\\s+const\\\\s+${exportName}\\\\s*(?::[^=]+)?=\\\\s*(attribute|action|handler)\\\\s*\\\\(\\\\s*\\\\{([\\\\s\\\\S]*?)\\\\}\\\\s*\\\\)`,\n 'm',\n );\n const m = re.exec(source);\n if (!m) return;\n const body = m[2];\n const name = /\\bname\\s*:\\s*['\"`]([^'\"`]+)['\"`]/.exec(body)?.[1];\n if (!name) return;\n const returns = /\\breturns\\s*:\\s*(true|false)/.exec(body)?.[1];\n const args = /\\bargs\\s*:\\s*\\[([^\\]]*)\\]/.exec(body)?.[1];\n return {\n export: exportName,\n name,\n type: m[1] as Plugin['type'],\n from,\n returns: returns === undefined ? undefined : returns === 'true',\n args: args\n ?.split(',')\n .map((s) => s.trim().replace(/^['\"`]|['\"`]$/g, ''))\n .filter(Boolean),\n };\n};\n\nconst esc = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/** True if `source` refers to the plugin: `data-<name>` for directives, `@name(` for functions, the name as a string for handlers. */\nexport const mentions = (source: string, p: PluginMeta, prefixes: string[]): boolean => {\n const n = esc(p.name);\n if (p.type === 'attribute')\n return prefixes.some((pre) => new RegExp(`(^|[\\\\s\"'\\`<])${esc(pre)}${n}(?=[\\\\s=:_>\"'\\`/]|$)`, 'm').test(source));\n if (p.type === 'action') return new RegExp(`@${n}\\\\s*\\\\(`).test(source);\n return new RegExp(`['\"\\`](?:[\\\\w-]+-)?${n}['\"\\`]`).test(source);\n};\n\nexport type Selection = {\n plugins: PluginMeta[];\n reasons: Record<string, string>;\n unused: string[];\n};\n\n/**\n * Decide which plugins to ship. `sources` are file contents; `custom` are extra plugins (from\n * `customPluginMeta`); `always` are export names that ship regardless.\n */\nexport const selectPlugins = (\n sources: string[],\n {\n prefixes = ['data-'],\n always = [],\n custom = [],\n }: { prefixes?: string[]; always?: string[]; custom?: PluginMeta[] } = {},\n): Selection => {\n const known = [...builtinPlugins(), ...custom];\n const byExport = new Map(known.map((p) => [p.export, p]));\n const reasons: Record<string, string> = {};\n const add = (exp: string, why: string) => {\n if (!byExport.has(exp) || reasons[exp]) return;\n reasons[exp] = why;\n for (const dep of implied[exp] ?? []) add(dep, exp);\n };\n for (const exp of always) add(exp, 'always');\n const text = sources.join('\\n');\n for (const p of known)\n if (!reasons[p.export] && (p.type !== 'handler' || custom.includes(p)) && mentions(text, p, prefixes))\n add(p.export, 'used');\n const plugins = known.filter((p) => reasons[p.export]);\n return { plugins, reasons, unused: known.filter((p) => !reasons[p.export]).map((p) => p.export) };\n};\n\nexport const generatePluginsModule = (sel: Selection): string => {\n const groups = new Map<string, string[]>();\n for (const p of sel.plugins) groups.set(p.from, [...(groups.get(p.from) ?? []), p.export]);\n const imports = [...groups]\n .map(([from, names]) => `import { ${names.join(', ')} } from ${JSON.stringify(from)}`)\n .join('\\n');\n return `${imports}\\nexport const plugins = [${sel.plugins.map((p) => p.export).join(', ')}]\\nexport const report = ${JSON.stringify({ reasons: sel.reasons, unused: sel.unused }, null, 2)}\\n`;\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// Node only; never bundled for the browser.\nimport * as builtins from '../plugins/index.js';\nimport type { Plugin } from './contracts.js';\n\nexport type PluginMeta = {\n export: string;\n name: string;\n type: Plugin['type'];\n from: string;\n literal?: boolean;\n args?: string[];\n};\n\nconst NETWORK = ['httpGet', 'httpPost', 'httpPut', 'httpPatch', 'httpDelete', 'websocket', 'boost'];\n\nexport const implied: Record<string, string[]> = {\n ...Object.fromEntries(NETWORK.map((n) => [n, ['applyElements', 'applyState']])),\n boost: ['httpGet', 'httpPost', 'applyElements', 'applyState'],\n};\n\nexport const builtinPlugins = (): PluginMeta[] =>\n Object.entries(builtins)\n .filter(([, v]) => v && typeof v === 'object' && 'type' in (v as object))\n .map(([key, v]) => {\n const p = v as Plugin;\n return {\n export: key,\n name: p.name,\n type: p.type,\n from: 'sigmx/plugins',\n literal: (p as any).literal,\n args: (p as any).args,\n };\n });\n\n/**\n * Read a custom plugin's metadata from its source without executing it: finds\n * `attribute({ name: 'x', ... })`, `action({...})` or `handler({...})` near `export const <exportName>`.\n */\nexport const customPluginMeta = (exportName: string, source: string, from: string): PluginMeta | undefined => {\n const re = new RegExp(\n `export\\\\s+const\\\\s+${exportName}\\\\s*(?::[^=]+)?=\\\\s*(attribute|action|handler)\\\\s*\\\\(\\\\s*\\\\{([\\\\s\\\\S]*?)\\\\}\\\\s*\\\\)`,\n 'm',\n );\n const m = re.exec(source);\n if (!m) return;\n const body = m[2];\n const name = /\\bname\\s*:\\s*['\"`]([^'\"`]+)['\"`]/.exec(body)?.[1];\n if (!name) return;\n const literal = /\\bliteral\\s*:\\s*true/.test(body);\n const args = /\\bargs\\s*:\\s*\\[([^\\]]*)\\]/.exec(body)?.[1];\n return {\n export: exportName,\n name,\n type: m[1] as Plugin['type'],\n from,\n literal: literal || undefined,\n args: args\n ?.split(',')\n .map((s) => s.trim().replace(/^['\"`]|['\"`]$/g, ''))\n .filter(Boolean),\n };\n};\n\nconst esc = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/** True if `source` refers to the plugin: `data-<name>` for directives, `@name(` for functions, the name as a string for handlers. */\nexport const mentions = (source: string, p: PluginMeta, prefixes: string[]): boolean => {\n const n = esc(p.name);\n if (p.type === 'attribute')\n return prefixes.some((pre) => new RegExp(`(^|[\\\\s\"'\\`<])${esc(pre)}${n}(?=[\\\\s=:_>\"'\\`/]|$)`, 'm').test(source));\n if (p.type === 'action') return new RegExp(`@${n}\\\\s*\\\\(`).test(source);\n return new RegExp(`['\"\\`](?:[\\\\w-]+-)?${n}['\"\\`]`).test(source);\n};\n\nexport type Selection = {\n plugins: PluginMeta[];\n reasons: Record<string, string>;\n unused: string[];\n};\n\n/**\n * Decide which plugins to ship. `sources` are file contents; `custom` are extra plugins (from\n * `customPluginMeta`); `always` are export names that ship regardless.\n */\nexport const selectPlugins = (\n sources: string[],\n {\n prefixes = ['data-'],\n always = [],\n custom = [],\n }: { prefixes?: string[]; always?: string[]; custom?: PluginMeta[] } = {},\n): Selection => {\n const known = [...builtinPlugins(), ...custom];\n const byExport = new Map(known.map((p) => [p.export, p]));\n const reasons: Record<string, string> = {};\n const add = (exp: string, why: string) => {\n if (!byExport.has(exp) || reasons[exp]) return;\n reasons[exp] = why;\n for (const dep of implied[exp] ?? []) add(dep, exp);\n };\n for (const exp of always) add(exp, 'always');\n const text = sources.join('\\n');\n for (const p of known)\n if (!reasons[p.export] && (p.type !== 'handler' || custom.includes(p)) && mentions(text, p, prefixes))\n add(p.export, 'used');\n const plugins = known.filter((p) => reasons[p.export]);\n return { plugins, reasons, unused: known.filter((p) => !reasons[p.export]).map((p) => p.export) };\n};\n\nexport const generatePluginsModule = (sel: Selection): string => {\n const groups = new Map<string, string[]>();\n for (const p of sel.plugins) groups.set(p.from, [...(groups.get(p.from) ?? []), p.export]);\n const imports = [...groups]\n .map(([from, names]) => `import { ${names.join(', ')} } from ${JSON.stringify(from)}`)\n .join('\\n');\n return `${imports}\\nexport const plugins = [${sel.plugins.map((p) => p.export).join(', ')}]\\nexport const report = ${JSON.stringify({ reasons: sel.reasons, unused: sel.unused }, null, 2)}\\n`;\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -14,7 +14,10 @@ export interface Store {
14
14
  remove(path: string): void;
15
15
  has(path: string): boolean;
16
16
  define(path: string, node: Signal<any>): void;
17
- paths(filter?: Filter): string[];
17
+ /** Leaf paths, filtered; `computed: false` leaves out computed signals. */
18
+ paths(filter?: Filter, options?: {
19
+ computed?: boolean;
20
+ }): string[];
18
21
  snapshot(filter?: Filter, options?: {
19
22
  at?: string;
20
23
  computed?: boolean;
@@ -22,7 +25,5 @@ export interface Store {
22
25
  /** Called after each settled batch with the nested object of changed paths (null = removed). */
23
26
  onPatch(fn: (patch: Patch) => void): () => void;
24
27
  readonly $: any;
25
- /** Identifier scope for compiled expressions: resolves `$count`, `$user`, and `$`. */
26
- readonly scope: object;
27
28
  }
28
29
  export declare const createStore: () => Store;