@hyperfixi/engine 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +921 -0
  2. package/LICENSE +20 -0
  3. package/README.md +272 -0
  4. package/dist/additions.d.ts +30 -0
  5. package/dist/ast.d.ts +277 -0
  6. package/dist/commands/animation.d.ts +34 -0
  7. package/dist/commands/control.d.ts +36 -0
  8. package/dist/commands/dom-more.d.ts +68 -0
  9. package/dist/commands/dom.d.ts +50 -0
  10. package/dist/commands/events.d.ts +25 -0
  11. package/dist/commands/js.d.ts +22 -0
  12. package/dist/commands/loops.d.ts +34 -0
  13. package/dist/commands/misc.d.ts +36 -0
  14. package/dist/commands/morph.d.ts +18 -0
  15. package/dist/commands/pick.d.ts +22 -0
  16. package/dist/commands/platform.d.ts +44 -0
  17. package/dist/commands/setters.d.ts +38 -0
  18. package/dist/common.js +3020 -0
  19. package/dist/common.min.js +17 -0
  20. package/dist/conversions.d.ts +6 -0
  21. package/dist/cookies.d.ts +10 -0
  22. package/dist/core.js +2190 -0
  23. package/dist/core.min.js +17 -0
  24. package/dist/engine.d.ts +79 -0
  25. package/dist/everything.d.ts +2 -0
  26. package/dist/expressions-extra.d.ts +2 -0
  27. package/dist/expressions.d.ts +51 -0
  28. package/dist/features.d.ts +47 -0
  29. package/dist/full.js +5673 -0
  30. package/dist/full.min.js +19 -0
  31. package/dist/hyperfixi-hs.dev.js +5676 -0
  32. package/dist/hyperfixi-hs.js +19 -0
  33. package/dist/index.d.ts +39 -0
  34. package/dist/index.js +5737 -0
  35. package/dist/live-templates.d.ts +3 -0
  36. package/dist/minimal.js +2580 -0
  37. package/dist/minimal.min.js +17 -0
  38. package/dist/on.d.ts +39 -0
  39. package/dist/parser.d.ts +97 -0
  40. package/dist/reactivity.d.ts +30 -0
  41. package/dist/runtime.d.ts +160 -0
  42. package/dist/statements.d.ts +24 -0
  43. package/dist/templates.d.ts +61 -0
  44. package/dist/tokenizer.d.ts +25 -0
  45. package/dist/util.d.ts +34 -0
  46. package/package.json +60 -0
package/dist/common.js ADDED
@@ -0,0 +1,3020 @@
1
+ "use strict";
2
+ (() => {
3
+ // src/util.ts
4
+ var isP = (v) => typeof v === "object" && v !== null && "then" in v && typeof v.then === "function";
5
+ var then1 = (v, f) => isP(v) ? v.then(f) : f(v);
6
+ var all = (vals, f) => vals.some(isP) ? Promise.all(vals).then(f) : f(vals);
7
+ var obj = (v) => v != null;
8
+ var fn = (v) => typeof v === "function";
9
+ var get = (o, key) => obj(o) ? o[key] : void 0;
10
+ var set = (o, key, value) => {
11
+ if (obj(o)) o[key] = value;
12
+ };
13
+ var isEl = (v) => v instanceof Element;
14
+ var isTarget = (v) => fn(get(v, "addEventListener"));
15
+ var num = (v) => v;
16
+
17
+ // src/runtime.ts
18
+ var config = {
19
+ attributes: "_, script, data-script",
20
+ defaultTransition: "all 500ms ease-in",
21
+ disableSelector: "[disable-scripting], [data-disable-scripting]",
22
+ hideShowStrategies: {},
23
+ fetchThrowsOn: [/^4/, /^5/]
24
+ };
25
+ var conversions = Object.assign(/* @__PURE__ */ Object.create(null), {
26
+ String: (v) => String(v),
27
+ Int: (v) => parseInt(String(v)),
28
+ Float: (v) => parseFloat(String(v)),
29
+ Number: (v) => Number(v),
30
+ Fragment: (v) => toFragment(v)
31
+ });
32
+ var dynamicResolvers = [];
33
+ var host = {
34
+ process(_node) {
35
+ },
36
+ /** A scripted element is being initialised, or was found again. Templates use it. */
37
+ enter(_elt) {
38
+ }
39
+ };
40
+ var store = /* @__PURE__ */ new WeakMap();
41
+ var peekData = (elt) => store.get(elt);
42
+ var dropData = (elt) => store.delete(elt);
43
+ function dataOf(elt) {
44
+ let d = store.get(elt);
45
+ if (!d) store.set(elt, d = {});
46
+ return d;
47
+ }
48
+ var rx = {
49
+ /** True while an effect is evaluating: reads are then recorded as its dependencies. */
50
+ tracking: false,
51
+ readGlobal(_name) {
52
+ },
53
+ readElement(_name, _element) {
54
+ },
55
+ readProperty(_object, _name) {
56
+ },
57
+ readAttribute(_element, _name) {
58
+ },
59
+ /** A selector was queried under `root`: any DOM change inside it re-runs the reader. */
60
+ readQuery(_root) {
61
+ },
62
+ wroteGlobal(_name) {
63
+ },
64
+ wroteElement(_name, _element) {
65
+ },
66
+ /** A property was assigned, or the object was mutated in place. */
67
+ wroteProperty(_object) {
68
+ },
69
+ stop(_element) {
70
+ }
71
+ };
72
+ var tracked = (value) => {
73
+ if (rx.tracking && typeof value === "object" && value !== null)
74
+ rx.readProperty(value, "__mutation__");
75
+ return value;
76
+ };
77
+ var mutatingMethods = {
78
+ Array: ["push", "pop", "shift", "unshift", "splice", "sort", "reverse", "fill", "copyWithin"],
79
+ Set: ["add", "delete", "clear"],
80
+ Map: ["set", "delete", "clear"]
81
+ };
82
+ function maybeNotify(target, method) {
83
+ const type = get(get(target, "constructor"), "name");
84
+ if (typeof type === "string" && mutatingMethods[type]?.includes(method)) rx.wroteProperty(target);
85
+ }
86
+ var getRootNode = (node) => {
87
+ if (node instanceof Node) {
88
+ const root = node.getRootNode();
89
+ if (root instanceof Document || root instanceof ShadowRoot) return root;
90
+ }
91
+ return document;
92
+ };
93
+ var escapeSelector = (s) => s.replace(/[:&()[\]/]/g, (c) => "\\" + c);
94
+ function query(root, css) {
95
+ if (rx.tracking) rx.readQuery(root);
96
+ return root.querySelectorAll(css);
97
+ }
98
+ var ElementCollection = class {
99
+ constructor(raw, relativeTo, escape = false) {
100
+ this.raw = raw;
101
+ this.relativeTo = relativeTo;
102
+ this.escape = escape;
103
+ }
104
+ get css() {
105
+ return this.escape ? escapeSelector(this.raw) : this.raw;
106
+ }
107
+ get className() {
108
+ return this.raw.slice(1);
109
+ }
110
+ get length() {
111
+ return this.select().length;
112
+ }
113
+ contains(node) {
114
+ for (const e of this) if (e.contains(node)) return true;
115
+ return false;
116
+ }
117
+ select() {
118
+ return query(getRootNode(this.relativeTo), this.css);
119
+ }
120
+ [Symbol.iterator]() {
121
+ return this.select()[Symbol.iterator]();
122
+ }
123
+ };
124
+ var shouldAutoIterate = (v) => v instanceof ElementCollection || Array.isArray(v) || v instanceof NodeList || v instanceof HTMLCollection || v instanceof FileList;
125
+ function implicitLoop(value, f) {
126
+ if (shouldAutoIterate(value)) for (const v of value) f(v);
127
+ else f(value);
128
+ }
129
+ var flatGet = (root, getter) => {
130
+ if (root == null) return;
131
+ const value = getter(root);
132
+ if (value !== void 0) return value;
133
+ if (shouldAutoIterate(root)) return Array.from(root, getter);
134
+ };
135
+ var resolveProperty = (root, prop) => {
136
+ if (rx.tracking) rx.readProperty(root, prop);
137
+ return flatGet(root, (o) => get(o, prop));
138
+ };
139
+ var resolveAttribute = (root, name) => {
140
+ if (rx.tracking) rx.readAttribute(root, name);
141
+ return flatGet(root, (o) => isEl(o) ? o.getAttribute(name) : void 0);
142
+ };
143
+ var resolveStyle = (root, prop) => flatGet(root, (o) => get(get(o, "style"), prop));
144
+ var resolveComputedStyle = (root, prop) => flatGet(root, (o) => isEl(o) ? getComputedStyle(o).getPropertyValue(prop) : void 0);
145
+ var setAttribute = (target, name, value) => implicitLoop(target, (elt) => {
146
+ if (!isEl(elt)) return;
147
+ if (value == null) elt.removeAttribute(name);
148
+ else elt.setAttribute(name, String(value));
149
+ });
150
+ var setStyle = (target, prop, value) => implicitLoop(target, (elt) => set(get(elt, "style"), prop, value));
151
+ var setProperty = (target, prop, value) => implicitLoop(target, (elt) => {
152
+ set(elt, prop, value);
153
+ rx.wroteProperty(elt);
154
+ });
155
+ function nullCheck(value, source) {
156
+ if (value == null) throw new Error(`'${source}' is null`);
157
+ }
158
+ var isEmpty = (v) => v == null || get(v, "length") === 0;
159
+ function doesExist(v) {
160
+ if (v == null) return false;
161
+ if (shouldAutoIterate(v)) {
162
+ for (const _ of v) return true;
163
+ return false;
164
+ }
165
+ return true;
166
+ }
167
+ function typeCheck(value, typeName, nullOk) {
168
+ if (value == null && nullOk) return true;
169
+ if (Object.prototype.toString.call(value).slice(8, -1) === typeName) return true;
170
+ const ctor = get(globalThis, typeName);
171
+ return fn(ctor) && value instanceof ctor;
172
+ }
173
+ function convert(value, type) {
174
+ for (const resolver of dynamicResolvers) {
175
+ const converted = resolver(type, value);
176
+ if (converted !== void 0) return converted;
177
+ }
178
+ if (value == null) return null;
179
+ const conversion = conversions[type];
180
+ if (conversion) return conversion(value);
181
+ throw new Error("Unknown conversion : " + type);
182
+ }
183
+ function toFragment(value) {
184
+ const frag = document.createDocumentFragment();
185
+ if (value == null) frag.append("null");
186
+ else
187
+ implicitLoop(value, (v) => {
188
+ if (v instanceof Node) frag.append(v);
189
+ else {
190
+ const template = document.createElement("template");
191
+ template.innerHTML = v === null ? "" : String(v);
192
+ frag.append(template.content);
193
+ }
194
+ });
195
+ return frag;
196
+ }
197
+ function replaceInDom(target, value) {
198
+ implicitLoop(target, (elt) => {
199
+ if (!isEl(elt)) return;
200
+ const parent = elt.parentElement;
201
+ elt.replaceWith(value instanceof Node ? value.cloneNode(true) : toFragment(value));
202
+ if (parent) host.process(parent);
203
+ });
204
+ }
205
+ function triggerEvent(target, name, detail = {}, sender) {
206
+ if (!isTarget(target)) return true;
207
+ detail.sender = sender;
208
+ const event = Object.assign(
209
+ new Event(name, { bubbles: true, cancelable: true, composed: true }),
210
+ {
211
+ detail
212
+ }
213
+ );
214
+ return target.dispatchEvent(event);
215
+ }
216
+ var scopeOf = (elt, name = "elementScope") => (dataOf(elt).scopes ??= {})[name] ??= {};
217
+ var ambient = Object.create(null, {
218
+ selection: { get: () => getSelection()?.toString(), enumerable: true },
219
+ clipboard: {
220
+ get: () => navigator.clipboard.readText(),
221
+ set: (value) => void navigator.clipboard.writeText(String(value))
222
+ }
223
+ });
224
+ function makeContext(owner, feature2, me, event) {
225
+ const detail = get(event, "detail");
226
+ const locals = Object.create(ambient);
227
+ for (let elt = isEl(owner) ? owner : null; elt; elt = elt.parentElement) {
228
+ Object.assign(locals, peekData(elt)?.features);
229
+ }
230
+ return {
231
+ meta: { owner, feature: feature2 },
232
+ locals,
233
+ me,
234
+ you: void 0,
235
+ result: void 0,
236
+ beingTested: null,
237
+ event,
238
+ target: get(event, "target") ?? null,
239
+ detail: detail ?? null,
240
+ sender: get(detail, "sender") ?? null,
241
+ body: typeof document === "undefined" ? null : document.body
242
+ };
243
+ }
244
+ var RESERVED = ["meta", "it", "result", "locals", "event", "target", "detail", "sender", "body"];
245
+ var elementScope = (ctx) => {
246
+ const owner = ctx.meta.owner;
247
+ const behavior = ctx.meta.feature?.behavior;
248
+ return obj(owner) ? scopeOf(owner, behavior ? behavior + "Scope" : void 0) : {};
249
+ };
250
+ function inherited(name, ctx, start) {
251
+ let elt = isEl(start) ? start : isEl(ctx.meta.owner) ? ctx.meta.owner : null;
252
+ while (elt) {
253
+ const scope = peekData(elt)?.scopes?.elementScope;
254
+ if (scope && name in scope) return { value: scope[name], element: elt };
255
+ const domScope = elt.getAttribute("dom-scope");
256
+ if (domScope === "isolated") break;
257
+ const closest = domScope?.match(/^closest\s+(.+)/);
258
+ const parentOf = domScope?.match(/^parent\s+of\s+(.+)/);
259
+ if (closest) elt = elt.parentElement?.closest(closest[1]) ?? null;
260
+ else if (parentOf) elt = elt.closest(parentOf[1])?.parentElement ?? null;
261
+ else elt = elt.parentElement;
262
+ }
263
+ return { value: void 0, element: null };
264
+ }
265
+ function resolveSymbol(name, ctx, scope, target) {
266
+ if (name === "me" || name === "my" || name === "I") return ctx.me;
267
+ if (name === "it" || name === "its") return ctx.beingTested ?? ctx.result;
268
+ if (name === "result") return ctx.result;
269
+ if (name === "you" || name === "your" || name === "yourself") return ctx.you;
270
+ const owner = ctx.meta.owner;
271
+ const global = () => {
272
+ if (rx.tracking) rx.readGlobal(name);
273
+ return tracked(get(globalThis, name));
274
+ };
275
+ if (scope === "global") return global();
276
+ if (scope === "element") {
277
+ if (rx.tracking) rx.readElement(name, owner);
278
+ return tracked(elementScope(ctx)[name]);
279
+ }
280
+ if (scope === "inherited") {
281
+ const found = inherited(name, ctx, target);
282
+ if (rx.tracking) rx.readElement(name, found.element ?? (isEl(target) ? target : owner));
283
+ return tracked(found.value);
284
+ }
285
+ const filterContext = ctx.meta.context;
286
+ if (filterContext != null) {
287
+ const fromEvent = get(filterContext, name);
288
+ if (fromEvent !== void 0) return fromEvent;
289
+ const fromDetail = get(get(filterContext, "detail"), name);
290
+ if (fromDetail !== void 0) return fromDetail;
291
+ }
292
+ const local = RESERVED.includes(name) ? get(ctx, name) : ctx.locals[name];
293
+ if (local !== void 0) return local;
294
+ const fromElement = elementScope(ctx)[name];
295
+ if (fromElement !== void 0) {
296
+ if (rx.tracking) rx.readElement(name, owner);
297
+ return tracked(fromElement);
298
+ }
299
+ return global();
300
+ }
301
+ function setSymbol(name, ctx, scope, value, target) {
302
+ if (scope === "global") {
303
+ set(globalThis, name, value);
304
+ rx.wroteGlobal(name);
305
+ } else if (scope === "element") {
306
+ elementScope(ctx)[name] = value;
307
+ rx.wroteElement(name, ctx.meta.owner);
308
+ } else if (scope === "inherited") {
309
+ const found = inherited(name, ctx, target).element;
310
+ const owner = found ?? (isEl(target) ? target : ctx.meta.owner);
311
+ if (obj(owner)) scopeOf(owner)[name] = value;
312
+ rx.wroteElement(name, owner);
313
+ } else if (!RESERVED.includes(name) && ctx.locals[name] !== void 0) {
314
+ ctx.locals[name] = value;
315
+ } else if (elementScope(ctx)[name] !== void 0) {
316
+ elementScope(ctx)[name] = value;
317
+ rx.wroteElement(name, ctx.meta.owner);
318
+ } else if (!RESERVED.includes(name)) {
319
+ ctx.locals[name] = value;
320
+ } else set(ctx, name, value);
321
+ }
322
+ function runList(cmds, ctx, from = 0) {
323
+ for (let i = from; i < cmds.length; i++) {
324
+ const result = cmds[i].run(ctx);
325
+ if (isP(result)) return result.then((signal) => signal || runList(cmds, ctx, i + 1));
326
+ if (result) return result;
327
+ }
328
+ }
329
+ function guard(f, rescue) {
330
+ try {
331
+ const result = f();
332
+ return isP(result) ? result.then(void 0, rescue) : result;
333
+ } catch (e) {
334
+ return rescue(e);
335
+ }
336
+ }
337
+ function runBlock(ctx, body, handlers) {
338
+ const { errorSymbol, errorHandler, finallyHandler } = handlers;
339
+ const main = () => guard(
340
+ () => then1(runList(body, ctx), (signal) => {
341
+ const kind = get(signal, "k");
342
+ if (kind === "break" || kind === "continue") {
343
+ throw new Error(`Command \`${kind}\` cannot be used outside of a \`repeat\` loop.`);
344
+ }
345
+ return signalOf(signal);
346
+ }),
347
+ (error) => {
348
+ if (!errorHandler || !errorSymbol) throw error;
349
+ ctx.locals[errorSymbol] = error;
350
+ return runList(errorHandler, ctx);
351
+ }
352
+ );
353
+ if (!finallyHandler) return main();
354
+ const cleanUp = () => guard(
355
+ () => then1(runList(finallyHandler, ctx), () => {
356
+ }),
357
+ (error) => console.error(" Exception in finally block: ", error)
358
+ );
359
+ return guard(
360
+ () => then1(main(), (signal) => then1(cleanUp(), () => signalOf(signal))),
361
+ (error) => then1(cleanUp(), () => {
362
+ throw error;
363
+ })
364
+ );
365
+ }
366
+ var signalOf = (v) => {
367
+ const kind = get(v, "k");
368
+ if (kind === "return") return { k: "return", value: get(v, "value") };
369
+ if (kind === "break" || kind === "continue") return { k: kind };
370
+ };
371
+ function implicitLoopWhen(targets, when, ctx, yes, no) {
372
+ const elements = [];
373
+ implicitLoop(targets, (elt) => elements.push(elt));
374
+ const conditions = elements.map((elt) => {
375
+ ctx.beingTested = elt;
376
+ return when.ev(ctx);
377
+ });
378
+ ctx.beingTested = null;
379
+ const apply = (results) => {
380
+ ctx.result = elements.filter((elt, i) => {
381
+ (results[i] ? yes : no)(elt);
382
+ return results[i];
383
+ });
384
+ };
385
+ return conditions.some(isP) ? Promise.all(conditions).then(apply) : apply(conditions);
386
+ }
387
+
388
+ // src/tokenizer.ts
389
+ var OPS = new Set(
390
+ "+ - * / . .. \\ : % | ! ? # & $ ; , ( ) < > <= >= == === != !== { } [ ] = ~ ^".split(" ")
391
+ );
392
+ var ESCAPES = { b: "\b", f: "\f", n: "\n", r: "\r", t: " ", v: "\v" };
393
+ var alpha = (c) => c >= "a" && c <= "z" || c >= "A" && c <= "Z";
394
+ var digit = (c) => c >= "0" && c <= "9";
395
+ var space = (c) => c === " " || c === " " || c === "\r" || c === "\n";
396
+ var cssChar = (c) => alpha(c) || digit(c) || c === "-" || c === "_" || c === ":";
397
+ var identChar = (c) => alpha(c) || digit(c) || c === "_" || c === "$";
398
+ function tokenize(src, template = false) {
399
+ const tokens = [];
400
+ let pos = 0;
401
+ let column = 0;
402
+ let line = 1;
403
+ let last = "<START>";
404
+ let braces = 0;
405
+ const cur = () => src.charAt(pos);
406
+ const at = (offset) => src.charAt(pos + offset);
407
+ const eat = () => {
408
+ last = src.charAt(pos++);
409
+ if (last === "\n") {
410
+ line++;
411
+ column = 0;
412
+ } else column++;
413
+ return last;
414
+ };
415
+ const make = (type) => ({
416
+ type,
417
+ value: "",
418
+ start: pos,
419
+ end: pos + 1,
420
+ line,
421
+ column
422
+ });
423
+ const done = (token, value) => {
424
+ token.value = value;
425
+ token.end = pos;
426
+ return token;
427
+ };
428
+ const eatWhile = (test) => {
429
+ let value = "";
430
+ while (cur() && test(cur())) value += eat();
431
+ return value;
432
+ };
433
+ const inTemplate = () => template && braces === 0;
434
+ const afterValue = () => alpha(last) || digit(last) || ")\"'`}]".includes(last);
435
+ const reference = (type, keepBrace) => {
436
+ const token = make(type);
437
+ let value = eat();
438
+ if (cur() === "{") {
439
+ token.template = true;
440
+ value += eat();
441
+ value += eatWhile((c) => c !== "}");
442
+ if (cur() !== "}")
443
+ throw new Error("Unterminated " + (keepBrace ? "class" : "id") + " reference");
444
+ const brace = eat();
445
+ if (keepBrace) value += brace;
446
+ } else if (keepBrace) {
447
+ while (cssChar(cur()) || cur() === "\\") {
448
+ if (cur() === "\\") eat();
449
+ value += eat();
450
+ }
451
+ } else value += eatWhile(cssChar);
452
+ return done(token, value);
453
+ };
454
+ const string2 = () => {
455
+ const token = make("STRING");
456
+ const quote = eat();
457
+ token.template = quote === "`";
458
+ let value = "";
459
+ while (cur() && cur() !== quote) {
460
+ if (cur() === "\\") {
461
+ eat();
462
+ const next = eat();
463
+ if (next in ESCAPES) value += ESCAPES[next];
464
+ else if (token.template && next === "$") value += "\\$";
465
+ else if (next === "x") {
466
+ const hex = cur() && at(1) ? parseInt(eat() + eat(), 16) : NaN;
467
+ if (Number.isNaN(hex)) {
468
+ throw new Error(
469
+ `Invalid hexadecimal escape at [Line: ${token.line}, Column: ${token.column}]`
470
+ );
471
+ }
472
+ value += String.fromCharCode(hex);
473
+ } else value += next;
474
+ } else value += eat();
475
+ }
476
+ if (cur() !== quote) {
477
+ throw new Error(`Unterminated string at [Line: ${token.line}, Column: ${token.column}]`);
478
+ }
479
+ eat();
480
+ return done(token, value);
481
+ };
482
+ const identifier = () => {
483
+ const token = make("IDENTIFIER");
484
+ let value = eat() + eatWhile(identChar);
485
+ if (cur() === "!" && value === "beep") value += eat();
486
+ return done(token, value);
487
+ };
488
+ const templateIdentifier = () => {
489
+ const token = make("IDENTIFIER");
490
+ let value = eat();
491
+ let escaped = value === "\\";
492
+ if (escaped) value = "";
493
+ while (identChar(cur()) || "\\{}".includes(cur() || " ")) {
494
+ if (cur() === "$" && !escaped) break;
495
+ if (cur() === "\\") {
496
+ escaped = true;
497
+ eat();
498
+ } else {
499
+ escaped = false;
500
+ value += eat();
501
+ }
502
+ }
503
+ return done(token, value);
504
+ };
505
+ const number = () => {
506
+ const token = make("NUMBER");
507
+ let value = eat() + eatWhile(digit);
508
+ if (cur() === "." && digit(at(1))) value += eat();
509
+ value += eatWhile(digit);
510
+ if (cur() === "e" || cur() === "E") {
511
+ if (digit(at(1))) value += eat();
512
+ else if (at(1) === "-") value += eat() + eat();
513
+ }
514
+ return done(token, value + eatWhile(digit));
515
+ };
516
+ const op = () => {
517
+ const token = make("OP");
518
+ token.op = true;
519
+ let value = eat();
520
+ while (cur() && OPS.has(value + cur())) value += eat();
521
+ return done(token, value);
522
+ };
523
+ const attributeRef2 = () => {
524
+ const token = make("ATTRIBUTE_REF");
525
+ let value = eat();
526
+ if (value === "[") {
527
+ value += eatWhile((c) => c !== "]");
528
+ if (cur() === "]") value += eat();
529
+ } else {
530
+ value += eatWhile(cssChar);
531
+ if (cur() === "=") {
532
+ value += eat();
533
+ if (cur() === '"' || cur() === "'") value += string2().value;
534
+ else if (identChar(cur())) value += identifier().value;
535
+ }
536
+ }
537
+ return done(token, value);
538
+ };
539
+ const quoteStartsString = () => {
540
+ const prev = tokens.at(-1);
541
+ if (!prev) return true;
542
+ if (prev.type === "IDENTIFIER" || prev.type === "CLASS_REF" || prev.type === "ID_REF")
543
+ return false;
544
+ return !(prev.op && (prev.value === ">" || prev.value === ")"));
545
+ };
546
+ const isComment = () => {
547
+ const c = cur();
548
+ const end = at(2);
549
+ return (c === "-" || c === "/") && at(1) === c && (space(end) || end === "" || end === c);
550
+ };
551
+ while (pos < src.length) {
552
+ const c = cur();
553
+ const next = at(1);
554
+ if (isComment()) {
555
+ eatWhile((ch) => ch !== "\r" && ch !== "\n");
556
+ eat();
557
+ } else if (space(c)) {
558
+ tokens.push(done(make("WHITESPACE"), eatWhile(space)));
559
+ } else if (!afterValue() && c === "." && (alpha(next) || next === "{" || next === "-")) {
560
+ tokens.push(reference("CLASS_REF", true));
561
+ } else if (!afterValue() && c === "#" && (alpha(next) || next === "{")) {
562
+ tokens.push(reference("ID_REF", false));
563
+ } else if (c === "@" || c === "[" && next === "@") {
564
+ tokens.push(attributeRef2());
565
+ } else if (c === "*" && alpha(next)) {
566
+ const token = make("STYLE_REF");
567
+ tokens.push(done(token, eat() + eatWhile((ch) => alpha(ch) || ch === "-")));
568
+ } else if (inTemplate() && (alpha(c) || c === "\\")) {
569
+ tokens.push(templateIdentifier());
570
+ } else if (!inTemplate() && (alpha(c) || c === "_" || c === "$")) {
571
+ tokens.push(identifier());
572
+ } else if (digit(c)) {
573
+ tokens.push(number());
574
+ } else if (!inTemplate() && (c === '"' || c === "`")) {
575
+ tokens.push(string2());
576
+ } else if (!inTemplate() && c === "'") {
577
+ tokens.push(quoteStartsString() ? string2() : op());
578
+ } else if (OPS.has(c)) {
579
+ if (last === "$" && c === "{") braces++;
580
+ if (c === "}") braces--;
581
+ tokens.push(op());
582
+ } else if (inTemplate() || c === "`") {
583
+ const token = make("RESERVED");
584
+ tokens.push(done(token, eat()));
585
+ } else {
586
+ throw new Error("Unknown token: " + c + " ");
587
+ }
588
+ }
589
+ return tokens;
590
+ }
591
+
592
+ // src/expressions.ts
593
+ function expr(p) {
594
+ p.match("the");
595
+ return logical(p);
596
+ }
597
+ function logical(p) {
598
+ let left = comparison(p);
599
+ let first;
600
+ const next = () => p.match("and") ?? p.match("or");
601
+ for (let t = next(); t; t = next()) {
602
+ first ??= t.value;
603
+ if (first !== t.value)
604
+ p.err("You must parenthesize logical operations with different operators");
605
+ left = logicalNode(t.value, left, comparison(p));
606
+ }
607
+ return left;
608
+ }
609
+ function logicalNode(operator, left, right) {
610
+ const or = operator === "or";
611
+ return {
612
+ type: "logicalOperator",
613
+ operator,
614
+ left,
615
+ right,
616
+ start: left.start,
617
+ end: right.end,
618
+ // Short-circuits, and stays synchronous unless an operand is a promise.
619
+ ev: (ctx) => then1(left.ev(ctx), (l) => !!l === or ? l : right.ev(ctx))
620
+ };
621
+ }
622
+ var MATH = {
623
+ "+": (a, b) => Array.isArray(a) ? a.concat(b) : num(a) + num(b),
624
+ "-": (a, b) => num(a) - num(b),
625
+ "*": (a, b) => num(a) * num(b),
626
+ "/": (a, b) => num(a) / num(b),
627
+ mod: (a, b) => num(a) % num(b)
628
+ };
629
+ function math(p) {
630
+ let left = collection(p);
631
+ let first;
632
+ const next = () => p.matchAnyOp("+", "-", "*", "/") ?? p.match("mod");
633
+ for (let t = next(); t; t = next()) {
634
+ first ??= t.value;
635
+ if (first !== t.value) p.err("You must parenthesize math operations with different operators");
636
+ const l = left;
637
+ const r = collection(p);
638
+ const op = MATH[t.value];
639
+ const node = {
640
+ type: "mathOperator",
641
+ operator: t.value,
642
+ left: l,
643
+ right: r,
644
+ start: l.start,
645
+ end: r.end,
646
+ ev: (ctx) => all([l.ev(ctx), r.ev(ctx)], ([a, b]) => op(a, b))
647
+ };
648
+ left = node;
649
+ }
650
+ return left;
651
+ }
652
+ function collection(p) {
653
+ let root = unary(p);
654
+ for (let changed = true; changed; ) {
655
+ changed = false;
656
+ for (const rule of p.g.collections) {
657
+ const next = rule(p, root);
658
+ if (next) {
659
+ root = next;
660
+ changed = true;
661
+ break;
662
+ }
663
+ }
664
+ }
665
+ return root;
666
+ }
667
+ function unary(p) {
668
+ p.match("the");
669
+ const start = p.pos();
670
+ if (p.match("not")) return unaryNode(p, "logicalNot", start, unary(p), (v) => !v);
671
+ if (p.match("no")) return unaryNode(p, "noExpression", start, collection(p), isEmpty);
672
+ for (const rule of p.g.unaries) {
673
+ const node = rule(p);
674
+ if (node) return indirect(p, node);
675
+ }
676
+ return postfix(p);
677
+ }
678
+ function unaryNode(p, type, start, root, f, chain = type !== "negativeNumber") {
679
+ const node = {
680
+ type,
681
+ root,
682
+ start,
683
+ end: p.endPos(),
684
+ ev: (ctx) => then1(root.ev(ctx), (v) => f(v, ctx))
685
+ };
686
+ return chain ? indirect(p, node) : node;
687
+ }
688
+ var UNITS = "em ex cap ch ic rem lh rlh vw vh vi vb vmin vmax cm mm Q pc pt px".split(" ");
689
+ function postfix(p) {
690
+ const root = negative(p);
691
+ const unit = p.matchAny(...UNITS) ?? p.matchOp("%");
692
+ if (unit) return postfixNode(p, "stringPostfixExpression", root, unit.value);
693
+ const factor = p.matchAny("s", "seconds") ? 1e3 : p.matchAny("ms", "milliseconds") ? 1 : 0;
694
+ if (factor) return postfixNode(p, "timeExpression", root, factor);
695
+ for (const rule of p.g.postfixes) {
696
+ const node = rule(p, root);
697
+ if (node) return node;
698
+ }
699
+ return root;
700
+ }
701
+ function postfixNode(p, type, root, suffix) {
702
+ const apply = (v) => typeof suffix === "number" ? num(v) * suffix : `${v}${suffix}`;
703
+ const node = {
704
+ type,
705
+ root,
706
+ suffix,
707
+ start: root.start,
708
+ end: p.endPos(),
709
+ ev: (ctx) => then1(root.ev(ctx), apply)
710
+ };
711
+ if (root.stat) node.stat = () => apply(evalStatic(root));
712
+ return node;
713
+ }
714
+ function negative(p) {
715
+ const start = p.pos();
716
+ if (p.matchOp("-")) return unaryNode(p, "negativeNumber", start, negative(p), (v) => -num(v));
717
+ return primary(p);
718
+ }
719
+ function primary(p) {
720
+ const node = leaf(p);
721
+ if (node) return indirect(p, node);
722
+ return p.err("Unexpected value: " + p.cur().value);
723
+ }
724
+ function assignable(p) {
725
+ p.match("the");
726
+ return writable(p, primary(p));
727
+ }
728
+ function writable(p, node) {
729
+ const inner = unwrap(node);
730
+ if (!inner.put) {
731
+ p.err(`A target expression must be writable. The expression type '${inner.type}' is not.`);
732
+ }
733
+ return inner;
734
+ }
735
+ function unwrap(node) {
736
+ let inner = node;
737
+ while (inner.type === "parenthesized" && "expr" in inner && isExpr(inner.expr))
738
+ inner = inner.expr;
739
+ return inner;
740
+ }
741
+ var isExpr = (v) => fn(get(v, "ev"));
742
+ function evalStatic(node) {
743
+ if (node.stat) return node.stat();
744
+ throw new Error("This expression cannot be evaluated statically: " + node.type);
745
+ }
746
+ function comparisonOperator(p) {
747
+ const symbol2 = p.matchAnyOp("<", ">", "<=", ">=", "==", "===", "!=", "!==");
748
+ if (symbol2) return { operator: symbol2.value, right: true, isType: false };
749
+ const is = (operator, right = true, isType = false) => ({ operator, right, isType });
750
+ const equalTo = () => p.match("equal") && p.match("to");
751
+ const orEqual = (strict, loose) => {
752
+ p.req("than");
753
+ if (!p.match("or")) return is(strict);
754
+ p.req("equal");
755
+ p.req("to");
756
+ return is(loose);
757
+ };
758
+ if (p.match("is") || p.match("am")) {
759
+ const not2 = !!p.match("not");
760
+ const prefix2 = not2 ? "not " : "";
761
+ if (p.match("in")) return is(prefix2 + "in");
762
+ if (p.match("a") || p.match("an")) return is(prefix2 + "a", false, true);
763
+ if (p.match("empty")) return is(prefix2 + "empty", false);
764
+ if (p.match("between")) return is(prefix2 + "between");
765
+ if (!not2 && p.match("less")) return orEqual("<", "<=");
766
+ if (!not2 && p.match("greater")) return orEqual(">", ">=");
767
+ if (p.match("really")) {
768
+ equalTo();
769
+ return is(not2 ? "!==" : "===");
770
+ }
771
+ if (p.match("equal")) {
772
+ p.match("to");
773
+ return is(not2 ? "!=" : "==");
774
+ }
775
+ return is(not2 ? "is not" : "is");
776
+ }
777
+ if (p.match("equals")) return is("==");
778
+ if (p.match("really")) {
779
+ p.req("equals");
780
+ return is("===");
781
+ }
782
+ if (p.matchAny("exist", "exists")) return is("exist", false);
783
+ const not = !!p.matchAny("do", "does");
784
+ if (not) p.req("not");
785
+ const prefix = not ? "not " : "";
786
+ const verb = (bare, third) => p.match(bare) ?? (not && bare !== "match" && bare !== "contain" ? void 0 : p.match(third));
787
+ if (verb("match", "matches")) return is(prefix + "match");
788
+ if (verb("contain", "contains")) return is(prefix + "contain");
789
+ if (not && p.match("exist")) return is("not exist", false);
790
+ if (verb("include", "includes")) return is(prefix + "include");
791
+ if (p.match(not ? "start" : "starts")) {
792
+ p.req("with");
793
+ return is(prefix + "start with");
794
+ }
795
+ if (p.match(not ? "end" : "ends")) {
796
+ p.req("with");
797
+ return is(prefix + "end with");
798
+ }
799
+ if (verb("precede", "precedes")) return is(prefix + "precede");
800
+ if (verb("follow", "follows")) return is(prefix + "follow");
801
+ if (not) p.expected("matches", "contains", "starts with", "ends with", "precede", "follow");
802
+ }
803
+ function comparison(p) {
804
+ const left = math(p);
805
+ const op = comparisonOperator(p);
806
+ if (!op) return left;
807
+ const { operator } = op;
808
+ let typeName;
809
+ let nullOk = true;
810
+ let right;
811
+ let css;
812
+ if (op.isType) {
813
+ typeName = p.reqType("IDENTIFIER").value;
814
+ nullOk = !p.matchOp("!");
815
+ } else if (op.right) {
816
+ right = math(p);
817
+ if (operator.endsWith("match")) css = right.css;
818
+ }
819
+ let right2;
820
+ if (operator.endsWith("between")) {
821
+ p.req("and");
822
+ right2 = math(p);
823
+ }
824
+ let ignoringCase = false;
825
+ if (p.match("ignoring")) {
826
+ p.req("case");
827
+ ignoringCase = true;
828
+ }
829
+ const lower = (v) => ignoringCase && typeof v === "string" ? v.toLowerCase() : v;
830
+ const flag = right?.type === "symbol" && "scope" in right && right.scope === "local" && right.name !== "undefined" && right.name !== "null" ? right.name : void 0;
831
+ const node = {
832
+ type: "comparisonOperator",
833
+ operator,
834
+ left,
835
+ right,
836
+ right2,
837
+ typeName,
838
+ ignoringCase,
839
+ start: left.start,
840
+ end: p.endPos(),
841
+ ev: (ctx) => all([left.ev(ctx), css ?? right?.ev(ctx), right2?.ev(ctx)], ([l, r, r2]) => {
842
+ if (typeName) {
843
+ const ok = typeCheck(l, typeName, nullOk);
844
+ return operator === "a" ? ok : !ok;
845
+ }
846
+ if (flag && r === void 0 && (operator === "is" || operator === "is not")) {
847
+ const set3 = !!resolveProperty(l, flag);
848
+ return operator === "is" ? set3 : !set3;
849
+ }
850
+ return compare(operator, lower(l), lower(r), r2);
851
+ })
852
+ };
853
+ return node;
854
+ }
855
+ function contains(container, value) {
856
+ const method = get(container, "contains") ?? get(container, "includes");
857
+ if (!fn(method)) throw new Error("The value does not have a contains or includes method on it");
858
+ return !!Reflect.apply(method, container, [value]);
859
+ }
860
+ function matches(target, pattern) {
861
+ const method = get(target, "match") ?? get(target, "matches");
862
+ if (!fn(method)) throw new Error("The value does not have a match or matches method on it");
863
+ return !!Reflect.apply(method, target, [pattern]);
864
+ }
865
+ var position = (a, b, bit) => a instanceof Node && b instanceof Node && (a.compareDocumentPosition(b) & bit) !== 0;
866
+ function compare(operator, l, r, r2) {
867
+ if (operator === "not between") return num(l) < num(r) || num(l) > num(r2);
868
+ if (operator.startsWith("not ")) return !compare(operator.slice(4), l, r, r2);
869
+ switch (operator) {
870
+ case "is":
871
+ case "==":
872
+ return l == r;
873
+ case "is not":
874
+ case "!=":
875
+ return l != r;
876
+ case "===":
877
+ return l === r;
878
+ case "!==":
879
+ return l !== r;
880
+ case "<":
881
+ return num(l) < num(r);
882
+ case ">":
883
+ return num(l) > num(r);
884
+ case "<=":
885
+ return num(l) <= num(r);
886
+ case ">=":
887
+ return num(l) >= num(r);
888
+ case "match":
889
+ return l != null && matches(l, r);
890
+ case "in":
891
+ return r != null && contains(r, l);
892
+ case "contain":
893
+ case "include":
894
+ return l != null && contains(l, r);
895
+ case "start with":
896
+ return l != null && String(l).startsWith(String(r));
897
+ case "end with":
898
+ return l != null && String(l).endsWith(String(r));
899
+ case "between":
900
+ return num(l) >= num(r) && num(l) <= num(r2);
901
+ case "precede":
902
+ return position(l, r, Node.DOCUMENT_POSITION_FOLLOWING);
903
+ case "follow":
904
+ return position(l, r, Node.DOCUMENT_POSITION_PRECEDING);
905
+ case "empty":
906
+ return isEmpty(l);
907
+ case "exist":
908
+ return doesExist(l);
909
+ }
910
+ throw new Error("Unknown comparison : " + operator);
911
+ }
912
+ function leaf(p) {
913
+ const t = p.cur();
914
+ switch (t.type) {
915
+ case "NUMBER":
916
+ p.consume();
917
+ return literal("number", parseFloat(t.value), t);
918
+ case "STRING":
919
+ return string(p);
920
+ case "ID_REF":
921
+ return idRef(p);
922
+ case "CLASS_REF":
923
+ return classRef(p);
924
+ case "ATTRIBUTE_REF":
925
+ return attributeRef(p);
926
+ case "STYLE_REF":
927
+ return styleRef(p);
928
+ }
929
+ if (t.op) {
930
+ if (t.value === "(") return paren(p);
931
+ if (t.value === "[") return arrayLiteral(p);
932
+ if (t.value === "{") return objectLiteral(p);
933
+ if (t.value === "<") return queryRef(p);
934
+ }
935
+ const bool = p.match("true") ?? p.match("false");
936
+ if (bool) return literal("boolean", bool.value === "true", bool);
937
+ const nil = p.match("null");
938
+ if (nil) return literal("null", null, nil);
939
+ for (const rule of p.g.leaves) {
940
+ const node = rule(p);
941
+ if (node) return node;
942
+ }
943
+ return symbol(p);
944
+ }
945
+ function literal(type, value, t) {
946
+ return { type, value, start: t.start, end: t.end, ev: () => value, stat: () => value };
947
+ }
948
+ function paren(p) {
949
+ const start = p.pos();
950
+ p.consume();
951
+ const inner = p.withoutFollows(() => expr(p));
952
+ p.reqOp(")");
953
+ return { type: "parenthesized", expr: inner, start, end: p.endPos(), ev: (ctx) => inner.ev(ctx) };
954
+ }
955
+ var interpolate = (parts, ctx) => all(
956
+ parts.map((part) => typeof part === "string" ? part : part.ev(ctx)),
957
+ (values) => values.map((v) => v === void 0 ? "" : `${v}`).join("")
958
+ );
959
+ function templateParts(p, raw) {
960
+ const inner = p.child(tokenize(raw, true), raw);
961
+ const parts = [];
962
+ let text = "";
963
+ do {
964
+ text += inner.lastWs();
965
+ const t = inner.cur();
966
+ if (t.value === "$") {
967
+ inner.consume();
968
+ const brace = inner.matchOp("{");
969
+ parts.push(text, expr(inner));
970
+ text = "";
971
+ if (brace) inner.reqOp("}");
972
+ } else if (t.value === "\\") {
973
+ inner.consume();
974
+ inner.consume();
975
+ } else if (inner.hasMore()) {
976
+ text += inner.consume().value;
977
+ }
978
+ } while (inner.hasMore());
979
+ parts.push(text + inner.lastWs());
980
+ return parts;
981
+ }
982
+ function string(p) {
983
+ const t = p.consume();
984
+ const value = t.value;
985
+ const node = { type: "string", value, start: t.start, end: t.end, ev: () => value };
986
+ if (t.template) {
987
+ const parts = node.parts = templateParts(p, value);
988
+ node.ev = (ctx) => interpolate(parts, ctx);
989
+ } else node.stat = () => value;
990
+ return node;
991
+ }
992
+ function arrayLiteral(p) {
993
+ const start = p.pos();
994
+ p.consume();
995
+ const values = [];
996
+ if (!p.matchOp("]")) {
997
+ do
998
+ values.push(expr(p));
999
+ while (p.matchOp(","));
1000
+ p.reqOp("]");
1001
+ }
1002
+ return {
1003
+ type: "arrayLiteral",
1004
+ values,
1005
+ start,
1006
+ end: p.endPos(),
1007
+ ev: (ctx) => all(
1008
+ values.map((v) => v.ev(ctx)),
1009
+ (vals) => vals
1010
+ )
1011
+ };
1012
+ }
1013
+ function objectLiteral(p) {
1014
+ const start = p.pos();
1015
+ p.consume();
1016
+ const keys = [];
1017
+ const values = [];
1018
+ const atClose = () => p.cur().op && p.cur().value === "}";
1019
+ if (!p.matchOp("}")) {
1020
+ do {
1021
+ const quoted = p.matchType("STRING");
1022
+ if (quoted) keys.push(quoted.value);
1023
+ else if (p.matchOp("[")) {
1024
+ keys.push(expr(p));
1025
+ p.reqOp("]");
1026
+ } else {
1027
+ let key = "";
1028
+ for (let t = p.matchType("IDENTIFIER") ?? p.matchOp("-"); t; t = p.matchType("IDENTIFIER") ?? p.matchOp("-")) {
1029
+ key += t.value;
1030
+ }
1031
+ keys.push(key);
1032
+ }
1033
+ p.reqOp(":");
1034
+ values.push(expr(p));
1035
+ } while (p.matchOp(",") && !atClose());
1036
+ p.reqOp("}");
1037
+ }
1038
+ return {
1039
+ type: "objectLiteral",
1040
+ keys,
1041
+ values,
1042
+ start,
1043
+ end: p.endPos(),
1044
+ ev: (ctx) => all(
1045
+ [...keys.map((k) => typeof k === "string" ? k : k.ev(ctx)), ...values.map((v) => v.ev(ctx))],
1046
+ (vals) => Object.fromEntries(keys.map((_, i) => [String(vals[i]), vals[keys.length + i]]))
1047
+ )
1048
+ };
1049
+ }
1050
+ function namedArgumentList(p) {
1051
+ if (!p.matchOp("(")) return;
1052
+ const start = p.last.start;
1053
+ const node = nakedNamedArguments(p, start);
1054
+ p.reqOp(")");
1055
+ node.end = p.endPos();
1056
+ return node;
1057
+ }
1058
+ function nakedNamedArguments(p, start = p.pos()) {
1059
+ const names = [];
1060
+ const values = [];
1061
+ if (p.cur().type === "IDENTIFIER") {
1062
+ do {
1063
+ names.push(p.reqType("IDENTIFIER").value);
1064
+ p.reqOp(":");
1065
+ values.push(expr(p));
1066
+ } while (p.matchOp(","));
1067
+ }
1068
+ return {
1069
+ type: "namedArgumentList",
1070
+ names,
1071
+ values,
1072
+ start,
1073
+ end: p.endPos(),
1074
+ ev: (ctx) => all(
1075
+ values.map((v) => v.ev(ctx)),
1076
+ (vals) => Object.fromEntries([
1077
+ ["_namedArgList_", true],
1078
+ ...names.map((n, i) => [n, vals[i]])
1079
+ ])
1080
+ )
1081
+ };
1082
+ }
1083
+ function stringLike(p) {
1084
+ return p.matchType("STRING")?.value ?? p.consumeUntil(void 0, "WHITESPACE").map((t) => t.value).join("");
1085
+ }
1086
+ function symbol(p) {
1087
+ const start = p.pos();
1088
+ let declared;
1089
+ if (p.match("global")) declared = "global";
1090
+ else if (p.match("element")) {
1091
+ declared = "element";
1092
+ if (p.matchOp("'")) p.req("s");
1093
+ } else if (p.match("dom")) declared = "inherited";
1094
+ else if (p.match("local")) declared = "local";
1095
+ const colon = p.matchOp(":");
1096
+ const caret = !colon && p.matchOp("^");
1097
+ const id = p.matchType("IDENTIFIER");
1098
+ if (!id?.value) return;
1099
+ const name = (colon ? ":" : caret ? "^" : "") + id.value;
1100
+ const prefixes = { $: "global", ":": "element", "^": "inherited" };
1101
+ const scope = declared ?? prefixes[name[0]] ?? "local";
1102
+ let on2;
1103
+ if (scope === "inherited" && p.match("on")) {
1104
+ on2 = p.withFollow(["to", "into", "before", "after", "then"], () => expr(p));
1105
+ }
1106
+ return {
1107
+ type: "symbol",
1108
+ name,
1109
+ scope,
1110
+ start,
1111
+ end: p.endPos(),
1112
+ ev: (ctx) => resolveSymbol(name, ctx, scope, on2?.ev(ctx)),
1113
+ lhs: () => void 0,
1114
+ put: (ctx, _lhs, value) => setSymbol(name, ctx, scope, value, on2?.ev(ctx))
1115
+ };
1116
+ }
1117
+ var templated = (p, t) => {
1118
+ const raw = t.value.substring(2);
1119
+ return expr(p.child(tokenize(raw), raw));
1120
+ };
1121
+ function idRef(p) {
1122
+ const t = p.consume();
1123
+ const find = (ctx, id) => getRootNode(ctx.me).getElementById(String(id));
1124
+ const node = {
1125
+ type: "idRef",
1126
+ start: t.start,
1127
+ end: t.end,
1128
+ ev: () => null,
1129
+ lhs: () => void 0,
1130
+ put: (ctx, _lhs, value) => then1(node.ev(ctx), (target) => target && replaceInDom(target, value))
1131
+ };
1132
+ if (t.template) {
1133
+ const inner = node.expr = templated(p, t);
1134
+ node.ev = (ctx) => then1(inner.ev(ctx), (id) => find(ctx, id));
1135
+ } else {
1136
+ const id = node.value = t.value.substring(1);
1137
+ node.css = t.value;
1138
+ node.ev = (ctx) => find(ctx, id);
1139
+ }
1140
+ return node;
1141
+ }
1142
+ function classRef(p) {
1143
+ const t = p.matchType("CLASS_REF");
1144
+ if (!t) return;
1145
+ const node = {
1146
+ type: "classRef",
1147
+ start: t.start,
1148
+ end: t.end,
1149
+ ev: () => null,
1150
+ lhs: () => void 0,
1151
+ put: (ctx, _lhs, value) => then1(
1152
+ node.ev(ctx),
1153
+ (c) => replaceInDom(Array.from(c instanceof ElementCollection ? c : []), value)
1154
+ )
1155
+ };
1156
+ if (t.template) {
1157
+ const inner = node.expr = templated(p, t);
1158
+ node.ev = (ctx) => then1(inner.ev(ctx), (name) => new ElementCollection("." + name, ctx.me, true));
1159
+ } else {
1160
+ const css = node.css = t.value;
1161
+ node.className = css.slice(1);
1162
+ node.ev = (ctx) => new ElementCollection(css, ctx.me, true);
1163
+ }
1164
+ return node;
1165
+ }
1166
+ var TemplatedQuery = class extends ElementCollection {
1167
+ constructor(relativeTo, parts) {
1168
+ super("", relativeTo);
1169
+ this.parts = parts;
1170
+ }
1171
+ get css() {
1172
+ let i = 0;
1173
+ return this.parts.map((part) => isEl(part) ? `[data-hs-query-id='${i++}']` : `${part ?? ""}`).join("");
1174
+ }
1175
+ select() {
1176
+ const elements = this.parts.filter(isEl);
1177
+ elements.forEach((e, i) => e.setAttribute("data-hs-query-id", String(i)));
1178
+ const found = super.select();
1179
+ elements.forEach((e) => e.removeAttribute("data-hs-query-id"));
1180
+ return found;
1181
+ }
1182
+ };
1183
+ function queryRef(p) {
1184
+ const start = p.pos();
1185
+ p.consume();
1186
+ const css = p.consumeUntil("/").map((t) => t.type === "STRING" ? `"${t.value}"` : t.value).join("");
1187
+ p.reqOp("/");
1188
+ p.reqOp(">");
1189
+ const node = {
1190
+ type: "queryRef",
1191
+ css,
1192
+ start,
1193
+ end: p.endPos(),
1194
+ ev: (ctx) => new ElementCollection(css, ctx.me),
1195
+ lhs: () => void 0,
1196
+ put: (ctx, _lhs, value) => then1(
1197
+ node.ev(ctx),
1198
+ (c) => replaceInDom(Array.from(c instanceof ElementCollection ? c : []), value)
1199
+ )
1200
+ };
1201
+ if (/\$[^=]/.test(css)) {
1202
+ const parts = node.parts = templateParts(p, css);
1203
+ node.ev = (ctx) => all(
1204
+ parts.map((part) => typeof part === "string" ? part : part.ev(ctx)),
1205
+ (values) => new TemplatedQuery(ctx.me, values)
1206
+ );
1207
+ }
1208
+ return node;
1209
+ }
1210
+ function attributeRef(p) {
1211
+ const t = p.matchType("ATTRIBUTE_REF");
1212
+ if (!t) return;
1213
+ const inner = t.value.startsWith("[") ? t.value.slice(2, -1) : t.value.slice(1);
1214
+ const [name, quoted] = inner.split("=");
1215
+ const value = quoted && /^["']/.test(quoted) ? quoted.slice(1, -1) : quoted;
1216
+ return {
1217
+ type: "attributeRef",
1218
+ name,
1219
+ value,
1220
+ css: `[${inner}]`,
1221
+ start: t.start,
1222
+ end: t.end,
1223
+ ev: (ctx) => resolveAttribute(ctx.you || ctx.me, name),
1224
+ lhs: () => void 0,
1225
+ put: (ctx, _lhs, v) => setAttribute(ctx.you || ctx.me, name, v)
1226
+ };
1227
+ }
1228
+ function styleRef(p) {
1229
+ const t = p.matchType("STYLE_REF");
1230
+ if (!t) return;
1231
+ const computed = t.value.startsWith("*computed-");
1232
+ const name = t.value.slice(computed ? 10 : 1);
1233
+ return {
1234
+ type: computed ? "computedStyleRef" : "styleRef",
1235
+ name,
1236
+ start: t.start,
1237
+ end: t.end,
1238
+ ev: (ctx) => (computed ? resolveComputedStyle : resolveStyle)(ctx.you || ctx.me, name),
1239
+ lhs: () => void 0,
1240
+ put: (ctx, _lhs, v) => setStyle(ctx.you || ctx.me, name, v)
1241
+ };
1242
+ }
1243
+ function styleLiteral(p) {
1244
+ const start = p.pos();
1245
+ if (!p.matchOp("{")) return;
1246
+ const parts = [""];
1247
+ const exprs = [];
1248
+ while (p.hasMore()) {
1249
+ if (p.matchOp("\\")) p.consume();
1250
+ else if (p.matchOp("}")) break;
1251
+ else if (p.match("$")) {
1252
+ const brace = p.matchOp("{");
1253
+ exprs.push(expr(p));
1254
+ if (brace) p.reqOp("}");
1255
+ parts.push("");
1256
+ } else parts[parts.length - 1] += p.text(p.consume());
1257
+ parts[parts.length - 1] += p.lastWs();
1258
+ }
1259
+ return {
1260
+ type: "styleLiteral",
1261
+ parts,
1262
+ exprs,
1263
+ start,
1264
+ end: p.endPos(),
1265
+ ev: (ctx) => all(
1266
+ exprs.map((e) => e.ev(ctx)),
1267
+ (vals) => parts.map((part, i) => part + (i in vals ? `${vals[i]}` : "")).join("")
1268
+ )
1269
+ };
1270
+ }
1271
+ function implicitMe(p) {
1272
+ const at = p.endPos();
1273
+ return { type: "implicitMeTarget", start: at, end: at, ev: (ctx) => ctx.you || ctx.me };
1274
+ }
1275
+ function dotOrColonPath(p) {
1276
+ const root = p.matchType("IDENTIFIER");
1277
+ if (!root) return;
1278
+ const path = [root.value];
1279
+ const separator = p.matchOp(".") ?? p.matchOp(":");
1280
+ if (separator) {
1281
+ do
1282
+ path.push(p.reqType("IDENTIFIER", "NUMBER").value);
1283
+ while (p.matchOp(separator.value));
1284
+ }
1285
+ return path.join(separator?.value ?? "");
1286
+ }
1287
+ function eventName(p, message = "Expected event name") {
1288
+ return p.matchType("STRING")?.value ?? dotOrColonPath(p) ?? p.err(message);
1289
+ }
1290
+ function indirect(p, root) {
1291
+ return propertyAccess(p, root) ?? ofExpression(p, root) ?? // Before `possessive`, as in upstream's build: `my @a` is an attribute access, and that
1292
+ // takes nothing after it. `my @a as Int`, `my @a.length` and `my @a[0]` are errors there
1293
+ // (`(my @a) as Int` is the spelling); read as a possessive they would parse here alone.
1294
+ attributeAccess(p, root) ?? possessive(p, root) ?? inExpression(p, root) ?? asExpression(p, root) ?? functionCall(p, root) ?? arrayIndex(p, root) ?? extraIndirect(p, root) ?? root;
1295
+ }
1296
+ function extraIndirect(p, root) {
1297
+ for (const rule of p.g.indirects) {
1298
+ const node = rule(p, root);
1299
+ if (node) return node;
1300
+ }
1301
+ }
1302
+ function propertyAccess(p, root) {
1303
+ if (!p.matchOp(".")) return;
1304
+ const prop = p.reqType("IDENTIFIER").value;
1305
+ const rootText = p.text(root);
1306
+ const node = {
1307
+ type: "propertyAccess",
1308
+ root,
1309
+ prop,
1310
+ start: root.start,
1311
+ end: p.endPos(),
1312
+ ev: (ctx) => then1(node.root.ev(ctx), (r) => resolveProperty(r, prop)),
1313
+ lhs: (ctx) => node.root.ev(ctx),
1314
+ put: (_ctx, lhs, value) => {
1315
+ nullCheck(lhs, rootText);
1316
+ setProperty(lhs, prop, value);
1317
+ },
1318
+ del: (_ctx, lhs) => {
1319
+ nullCheck(lhs, rootText);
1320
+ implicitLoop(lhs, (o) => {
1321
+ if (obj(o)) delete o[prop];
1322
+ rx.wroteProperty(o);
1323
+ });
1324
+ }
1325
+ };
1326
+ return indirect(p, node);
1327
+ }
1328
+ function ofExpression(p, root) {
1329
+ if (!p.match("of")) return;
1330
+ const owner = unary(p);
1331
+ let child;
1332
+ let innermost = root;
1333
+ while (innermost.root) {
1334
+ child = innermost;
1335
+ innermost = innermost.root;
1336
+ }
1337
+ const kinds = {
1338
+ symbol: "property",
1339
+ attributeRef: "attribute",
1340
+ styleRef: "style",
1341
+ computedStyleRef: "computed"
1342
+ };
1343
+ const kind = kinds[innermost.type];
1344
+ const name = innermost.name;
1345
+ if (!kind || name === void 0)
1346
+ return p.err("Cannot take a property of a non-symbol: " + innermost.type);
1347
+ const ownerText = p.text(owner);
1348
+ const read = {
1349
+ property: resolveProperty,
1350
+ attribute: resolveAttribute,
1351
+ style: resolveStyle,
1352
+ computed: resolveComputedStyle
1353
+ }[kind];
1354
+ const node = {
1355
+ type: "ofExpression",
1356
+ root: owner,
1357
+ name,
1358
+ kind,
1359
+ start: root.start,
1360
+ end: p.endPos(),
1361
+ ev: (ctx) => then1(node.root.ev(ctx), (r) => read(r, name)),
1362
+ lhs: (ctx) => node.root.ev(ctx),
1363
+ put: (_ctx, lhs, value) => {
1364
+ nullCheck(lhs, ownerText);
1365
+ if (kind === "attribute") setAttribute(lhs, name, value);
1366
+ else if (kind === "property") setProperty(lhs, name, value);
1367
+ else setStyle(lhs, name, value);
1368
+ },
1369
+ del: (_ctx, lhs) => {
1370
+ nullCheck(lhs, ownerText);
1371
+ implicitLoop(lhs, (o) => {
1372
+ if (kind === "attribute") {
1373
+ if (isEl(o)) o.removeAttribute(name);
1374
+ } else if (kind === "property") {
1375
+ if (obj(o)) delete o[name];
1376
+ rx.wroteProperty(o);
1377
+ } else if (o instanceof HTMLElement) o.style.removeProperty(name);
1378
+ });
1379
+ }
1380
+ };
1381
+ if (child) {
1382
+ child.root = node;
1383
+ return indirect(p, root);
1384
+ }
1385
+ return indirect(p, node);
1386
+ }
1387
+ function possessive(p, root) {
1388
+ const apostrophe = p.matchOp("'");
1389
+ const pronoun = root.type === "symbol" && ["my", "its", "your"].includes(root.name ?? "") && ["IDENTIFIER", "ATTRIBUTE_REF", "STYLE_REF"].includes(p.cur().type);
1390
+ if (!apostrophe && !pronoun) return;
1391
+ if (apostrophe) p.req("s");
1392
+ const attribute = attributeRef(p) ?? styleRef(p);
1393
+ const prop = attribute ? void 0 : p.reqType("IDENTIFIER").value;
1394
+ const rootText = p.text(root);
1395
+ const read = (r) => {
1396
+ if (prop !== void 0) return resolveProperty(r, prop);
1397
+ if (attribute?.type === "attributeRef") return resolveAttribute(r, attribute.name);
1398
+ if (attribute?.type === "computedStyleRef") return resolveComputedStyle(r, attribute.name);
1399
+ return attribute && resolveStyle(r, attribute.name);
1400
+ };
1401
+ const node = {
1402
+ type: "possessive",
1403
+ root,
1404
+ prop,
1405
+ attribute,
1406
+ start: root.start,
1407
+ end: p.endPos(),
1408
+ ev: (ctx) => then1(node.root.ev(ctx), read),
1409
+ lhs: (ctx) => node.root.ev(ctx),
1410
+ put: (_ctx, lhs, value) => {
1411
+ nullCheck(lhs, rootText);
1412
+ if (prop !== void 0) setProperty(lhs, prop, value);
1413
+ else if (attribute?.type === "attributeRef") setAttribute(lhs, attribute.name, value);
1414
+ else if (attribute) setStyle(lhs, attribute.name, value);
1415
+ }
1416
+ };
1417
+ return indirect(p, node);
1418
+ }
1419
+ function inExpression(p, root) {
1420
+ if (!p.match("in")) return;
1421
+ const target = unary(p);
1422
+ const find = (r, within) => {
1423
+ if (r == null) return [];
1424
+ const found = [];
1425
+ const css = get(r, "css");
1426
+ if (typeof css === "string") {
1427
+ implicitLoop(within, (t) => isEl(t) && found.push(...query(t, css)));
1428
+ } else if (isEl(r)) {
1429
+ let inside = false;
1430
+ implicitLoop(within, (t) => {
1431
+ if (t instanceof Node && t.contains(r)) inside = true;
1432
+ });
1433
+ if (inside) return r;
1434
+ } else {
1435
+ implicitLoop(r, (a) => implicitLoop(within, (b) => a === b && found.push(a)));
1436
+ }
1437
+ return found;
1438
+ };
1439
+ const node = {
1440
+ type: "inExpression",
1441
+ root,
1442
+ target,
1443
+ start: root.start,
1444
+ end: p.endPos(),
1445
+ ev: (ctx) => all([node.root.ev(ctx), target.ev(ctx)], ([r, t]) => find(r, t)),
1446
+ lhs: (ctx) => node.ev(ctx),
1447
+ put: (_ctx, lhs, value) => replaceInDom(lhs, value)
1448
+ };
1449
+ let filtered;
1450
+ if (p.peek("where")) for (const rule of p.g.collections) filtered ??= rule(p, node);
1451
+ return indirect(p, filtered ?? node);
1452
+ }
1453
+ function asExpression(p, root) {
1454
+ if (!p.match("as")) return;
1455
+ if (!p.match("a")) p.match("an");
1456
+ const make = (inner) => {
1457
+ const conversion = dotOrColonPath(p) ?? p.err("Expected dotOrColonPath");
1458
+ const node2 = {
1459
+ type: "asExpression",
1460
+ root: inner,
1461
+ conversion,
1462
+ start: inner.start,
1463
+ end: p.endPos(),
1464
+ ev: (ctx) => then1(node2.root.ev(ctx), (v) => convert(v, conversion))
1465
+ };
1466
+ return node2;
1467
+ };
1468
+ let node = make(root);
1469
+ while (p.matchOp("|")) node = make(node);
1470
+ return indirect(p, node);
1471
+ }
1472
+ function functionCall(p, root) {
1473
+ if (!p.matchOp("(")) return;
1474
+ const args = [];
1475
+ if (!p.matchOp(")")) {
1476
+ do
1477
+ args.push(expr(p));
1478
+ while (p.matchOp(","));
1479
+ p.reqOp(")");
1480
+ }
1481
+ const rootText = p.text(root);
1482
+ const ownerText = root.root ? p.text(root.root) : "";
1483
+ const node = {
1484
+ type: "functionCall",
1485
+ root,
1486
+ args,
1487
+ start: root.start,
1488
+ end: p.endPos(),
1489
+ ev: (ctx) => {
1490
+ const callee = node.root;
1491
+ const method = callee.prop;
1492
+ const owner = method === void 0 ? void 0 : callee.root;
1493
+ return all(
1494
+ [(owner ?? callee).ev(ctx), ...args.map((a) => a.ev(ctx))],
1495
+ ([target, ...values]) => {
1496
+ if (!owner || method === void 0) return call(target, void 0, values, ctx, rootText);
1497
+ nullCheck(target, ownerText);
1498
+ const result = call(get(target, method), target, values, ctx, rootText);
1499
+ maybeNotify(target, method);
1500
+ return result;
1501
+ }
1502
+ );
1503
+ }
1504
+ };
1505
+ return indirect(p, node);
1506
+ }
1507
+ function call(f, receiver, args, ctx, source) {
1508
+ if (!fn(f)) {
1509
+ nullCheck(f, source);
1510
+ throw new Error(`'${source}' is not a function`);
1511
+ }
1512
+ if (get(f, "hyperfunc")) args.push(ctx);
1513
+ return Reflect.apply(f, receiver, args);
1514
+ }
1515
+ function attributeAccess(p, root) {
1516
+ const attribute = attributeRef(p);
1517
+ return attribute && attributeAccessNode(p, root, attribute);
1518
+ }
1519
+ function attributeAccessNode(p, root, attribute) {
1520
+ const rootText = p.text(root);
1521
+ const node = {
1522
+ type: "attributeRefAccess",
1523
+ root,
1524
+ attribute,
1525
+ start: root.start,
1526
+ end: p.endPos(),
1527
+ ev: (ctx) => then1(node.root.ev(ctx), (r) => resolveAttribute(r, attribute.name)),
1528
+ lhs: (ctx) => node.root.ev(ctx),
1529
+ put: (_ctx, lhs, value) => {
1530
+ nullCheck(lhs, rootText);
1531
+ setAttribute(lhs, attribute.name, value);
1532
+ }
1533
+ };
1534
+ return node;
1535
+ }
1536
+ function arrayIndex(p, root) {
1537
+ if (!p.matchOp("[")) return;
1538
+ const andBefore = !!p.matchOp("..");
1539
+ const first = expr(p);
1540
+ let andAfter = false;
1541
+ let second;
1542
+ if (!andBefore && p.matchOp("..")) {
1543
+ andAfter = true;
1544
+ if (!(p.cur().op && p.cur().value === "]")) second = expr(p);
1545
+ }
1546
+ p.reqOp("]");
1547
+ const rootText = p.text(root);
1548
+ const fromEnd = (list, i) => num(i) < 0 ? num(get(list, "length")) + num(i) : num(i);
1549
+ const slice = (list, from, to) => {
1550
+ const method = get(list, "slice");
1551
+ return fn(method) ? Reflect.apply(method, list, [from, to]) : void 0;
1552
+ };
1553
+ const node = {
1554
+ type: "arrayIndex",
1555
+ root,
1556
+ first,
1557
+ second,
1558
+ andBefore,
1559
+ andAfter,
1560
+ start: root.start,
1561
+ end: p.endPos(),
1562
+ ev: (ctx) => all([node.root.ev(ctx), first.ev(ctx), second?.ev(ctx)], ([list, i, j]) => {
1563
+ if (list == null) return null;
1564
+ if (andBefore) return slice(list, 0, fromEnd(list, i) + 1);
1565
+ if (andAfter)
1566
+ return j == null ? slice(list, num(i)) : slice(list, num(i), fromEnd(list, j) + 1);
1567
+ return get(list, String(i));
1568
+ }),
1569
+ lhs: (ctx) => all([node.root.ev(ctx), first.ev(ctx)], (pair) => pair),
1570
+ put: (_ctx, lhs, value) => {
1571
+ const [list, i] = Array.isArray(lhs) ? lhs : [];
1572
+ nullCheck(list, rootText);
1573
+ if (obj(list)) list[String(i)] = value;
1574
+ },
1575
+ del: (_ctx, lhs) => {
1576
+ if (andBefore || andAfter) throw new Error("Cannot remove a slice - use a single index");
1577
+ const [list, i] = Array.isArray(lhs) ? lhs : [];
1578
+ nullCheck(list, rootText);
1579
+ if (Array.isArray(list)) list.splice(fromEnd(list, i), 1);
1580
+ else if (obj(list)) delete list[String(i)];
1581
+ rx.wroteProperty(list);
1582
+ }
1583
+ };
1584
+ return indirect(p, node);
1585
+ }
1586
+
1587
+ // src/statements.ts
1588
+ function command(p) {
1589
+ const start = p.pos();
1590
+ if (p.matchOp("(")) {
1591
+ const grouped = command(p) ?? p.err("Expected command");
1592
+ p.reqOp(")");
1593
+ return grouped;
1594
+ }
1595
+ const t = p.cur();
1596
+ const rule = p.g.commands[t.value];
1597
+ let cmd;
1598
+ if (rule) cmd = p.match(t.value) && rule(p, t.value, start);
1599
+ else if (t.type === "IDENTIFIER") cmd = p.g.pseudo?.(p, start);
1600
+ if (!cmd || !p.match("unless")) return cmd;
1601
+ const inner = cmd;
1602
+ const condition = expr(p);
1603
+ const unless = {
1604
+ type: "unlessStatementModifier",
1605
+ command: inner,
1606
+ condition,
1607
+ start,
1608
+ end: p.endPos(),
1609
+ run: (ctx) => then1(condition.ev(ctx), (skip) => skip ? void 0 : inner.run(ctx))
1610
+ };
1611
+ return unless;
1612
+ }
1613
+ function commandList(p) {
1614
+ const list = [];
1615
+ while (p.hasMore()) {
1616
+ const cmd = command(p);
1617
+ if (!cmd) break;
1618
+ list.push(cmd);
1619
+ p.match("then");
1620
+ }
1621
+ return list;
1622
+ }
1623
+ function feature(p) {
1624
+ const start = p.pos();
1625
+ if (p.matchOp("(")) {
1626
+ const grouped = feature(p);
1627
+ p.reqOp(")");
1628
+ return grouped;
1629
+ }
1630
+ const t = p.cur();
1631
+ const rule = p.g.features[t.value];
1632
+ if (!rule || !p.match(t.value)) return p.err("Expected feature");
1633
+ return rule(p, start);
1634
+ }
1635
+ function program(p) {
1636
+ const start = p.pos();
1637
+ const features = [];
1638
+ while (p.hasMore()) {
1639
+ const t = p.cur();
1640
+ if (p.featureStart(t) || t.value === "(") {
1641
+ features.push(feature(p));
1642
+ p.match("end");
1643
+ } else if (t.value === "end") break;
1644
+ else p.err();
1645
+ }
1646
+ return { type: "hyperscript", features, start, end: p.endPos() };
1647
+ }
1648
+ function errorAndFinally(p) {
1649
+ const handlers = {};
1650
+ if (p.match("catch")) {
1651
+ handlers.errorSymbol = p.reqType("IDENTIFIER").value;
1652
+ handlers.errorHandler = commandList(p);
1653
+ }
1654
+ if (p.match("finally")) handlers.finallyHandler = commandList(p);
1655
+ return handlers;
1656
+ }
1657
+ function eventArgs(p) {
1658
+ const args = [];
1659
+ const second = p.tok(1).value;
1660
+ const third = p.tok(2).value;
1661
+ if (p.cur().value === "(" && (second === ")" || third === "," || third === ")")) {
1662
+ p.matchOp("(");
1663
+ do
1664
+ args.push(p.reqType("IDENTIFIER").value);
1665
+ while (p.matchOp(","));
1666
+ p.reqOp(")");
1667
+ }
1668
+ return args;
1669
+ }
1670
+
1671
+ // src/commands/control.ts
1672
+ function ifCommand(g) {
1673
+ g.commands.if = (p, _keyword, start) => {
1674
+ const condition = expr(p);
1675
+ p.match("then");
1676
+ const trueBranch = commandList(p);
1677
+ let falseBranch;
1678
+ let chained = false;
1679
+ const otherwise = p.match("else") ?? p.match("otherwise");
1680
+ if (otherwise) {
1681
+ chained = p.peek("if")?.line === otherwise.line;
1682
+ if (chained) {
1683
+ const nested = command(p);
1684
+ falseBranch = nested ? [nested] : [];
1685
+ } else falseBranch = commandList(p);
1686
+ }
1687
+ if (p.hasMore() && !chained) p.req("end");
1688
+ const node = {
1689
+ type: "ifCommand",
1690
+ condition,
1691
+ trueBranch,
1692
+ falseBranch,
1693
+ start,
1694
+ end: p.endPos(),
1695
+ run: (ctx) => then1(
1696
+ condition.ev(ctx),
1697
+ (yes) => yes ? runList(trueBranch, ctx) : falseBranch && runList(falseBranch, ctx)
1698
+ )
1699
+ };
1700
+ return node;
1701
+ };
1702
+ }
1703
+ var EXIT = { k: "return", value: null };
1704
+ function halt(g) {
1705
+ g.commands.halt = (p, _keyword, start) => {
1706
+ let keepExecuting = false;
1707
+ if (p.match("the")) {
1708
+ p.req("event");
1709
+ if (p.matchOp("'")) p.req("s");
1710
+ keepExecuting = true;
1711
+ }
1712
+ const bubbling = !!p.match("bubbling");
1713
+ const haltDefault = !bubbling && !!p.match("default");
1714
+ const node = {
1715
+ type: "haltCommand",
1716
+ keepExecuting,
1717
+ bubbling,
1718
+ haltDefault,
1719
+ start,
1720
+ end: p.endPos(),
1721
+ run: (ctx) => {
1722
+ const event = ctx.event;
1723
+ if (event instanceof Event) {
1724
+ if (!haltDefault) event.stopPropagation();
1725
+ if (!bubbling) event.preventDefault();
1726
+ }
1727
+ if (!keepExecuting) return EXIT;
1728
+ }
1729
+ };
1730
+ return node;
1731
+ };
1732
+ }
1733
+
1734
+ // src/commands/dom.ts
1735
+ function classRefs(p) {
1736
+ const first = classRef(p);
1737
+ if (!first) return;
1738
+ const refs = [first];
1739
+ for (let next = classRef(p); next; next = classRef(p)) refs.push(next);
1740
+ return refs;
1741
+ }
1742
+ var classNames = (refs, ctx) => (refs ?? []).map((ref) => then1(ref.ev(ctx), (c) => String(get(c, "className"))));
1743
+ var cssProperties = (css) => css.split(";").map((declaration) => declaration.split(":")[0].trim()).filter(Boolean);
1744
+ var styleOf = (elt) => elt instanceof HTMLElement || elt instanceof SVGElement ? elt.style : void 0;
1745
+ var eachTarget = (targets, when, ctx, apply, undo) => when ? implicitLoopWhen(
1746
+ targets,
1747
+ when,
1748
+ ctx,
1749
+ (t) => isEl(t) && apply(t),
1750
+ (t) => isEl(t) && undo(t)
1751
+ ) : implicitLoop(targets, (t) => isEl(t) && apply(t));
1752
+ var setAttribute2 = (elt, { name, value }, on2) => on2 ? elt.setAttribute(name, String(value)) : elt.removeAttribute(name);
1753
+ var mark = (on2, targets, when, ctx, names, attribute) => attribute ? eachTarget(
1754
+ targets,
1755
+ when,
1756
+ ctx,
1757
+ (t) => setAttribute2(t, attribute, on2),
1758
+ (t) => setAttribute2(t, attribute, !on2)
1759
+ ) : all(
1760
+ names.map(
1761
+ (name) => eachTarget(
1762
+ targets,
1763
+ when,
1764
+ ctx,
1765
+ (t) => t.classList.toggle(String(name), on2),
1766
+ (t) => t.classList.toggle(String(name), !on2)
1767
+ )
1768
+ ),
1769
+ () => {
1770
+ }
1771
+ );
1772
+ function subject(p) {
1773
+ const refs = classRefs(p);
1774
+ const attribute = refs ? void 0 : attributeRef(p);
1775
+ return { refs, attribute, css: refs || attribute ? void 0 : styleLiteral(p) };
1776
+ }
1777
+ function add(g) {
1778
+ g.commands.add = (p, _keyword, start) => {
1779
+ const { refs, attribute, css } = subject(p);
1780
+ let value;
1781
+ if (!refs && !attribute && !css) {
1782
+ value = p.withFollow(["to"], () => expr(p));
1783
+ if (p.cur().value !== "to")
1784
+ p.err("Expected either a class reference or attribute expression");
1785
+ }
1786
+ const to = p.match("to") ? expr(p) : implicitMe(p);
1787
+ const whenClause = p.match("when") ? expr(p) : void 0;
1788
+ const when = refs || attribute ? whenClause : void 0;
1789
+ const toText = p.text(to);
1790
+ const node = {
1791
+ type: "addCommand",
1792
+ classRefs: refs,
1793
+ attributeRef: attribute,
1794
+ css,
1795
+ value,
1796
+ to,
1797
+ when,
1798
+ start,
1799
+ end: p.endPos(),
1800
+ run: (ctx) => all(
1801
+ [to.ev(ctx), css?.ev(ctx), value?.ev(ctx), ...classNames(refs, ctx)],
1802
+ ([target, cssText, item, ...names]) => {
1803
+ nullCheck(target, toText);
1804
+ if (value) {
1805
+ if (Array.isArray(target)) target.push(item);
1806
+ else if (target instanceof Set) target.add(item);
1807
+ else if (target instanceof Map)
1808
+ throw new Error("Use 'set myMap[key] to value' for Maps");
1809
+ else throw new Error("Cannot add to " + typeof target);
1810
+ rx.wroteProperty(target);
1811
+ } else if (!css) return mark(true, target, when, ctx, names, attribute);
1812
+ else {
1813
+ implicitLoop(target, (t) => {
1814
+ const style = styleOf(t);
1815
+ if (style) style.cssText += cssText;
1816
+ });
1817
+ }
1818
+ }
1819
+ )
1820
+ };
1821
+ return node;
1822
+ };
1823
+ }
1824
+ var isDomTarget = (v) => v instanceof Node || v instanceof NodeList || v instanceof HTMLCollection;
1825
+ function remove(g) {
1826
+ g.commands.remove = (p, _keyword, start) => {
1827
+ const { refs, attribute, css } = subject(p);
1828
+ const element = refs || attribute || css ? void 0 : expr(p);
1829
+ const from = p.match("from") ? expr(p) : element ? void 0 : implicitMe(p);
1830
+ let when;
1831
+ if (p.match("when")) {
1832
+ if (element) p.err("'when' clause is not supported when removing elements");
1833
+ when = expr(p);
1834
+ }
1835
+ const fromText = from ? p.text(from) : "";
1836
+ const elementText = element ? p.text(element) : "";
1837
+ const removeValue = (ctx, value, container) => {
1838
+ if (container == null && element?.del && element.lhs && !isDomTarget(value)) {
1839
+ const target = element;
1840
+ return then1(element.lhs(ctx), (lhs) => target.del?.(ctx, lhs));
1841
+ }
1842
+ nullCheck(value, elementText);
1843
+ if (Array.isArray(container)) {
1844
+ const index = container.indexOf(value);
1845
+ if (index > -1) container.splice(index, 1);
1846
+ rx.wroteProperty(container);
1847
+ } else if (container instanceof Set || container instanceof Map) {
1848
+ container.delete(value);
1849
+ rx.wroteProperty(container);
1850
+ } else {
1851
+ implicitLoop(value, (t) => {
1852
+ if (isEl(t) && t.parentElement && (container == null || container instanceof Node && container.contains(t))) {
1853
+ t.parentElement.removeChild(t);
1854
+ }
1855
+ });
1856
+ }
1857
+ };
1858
+ const node = {
1859
+ type: "removeCommand",
1860
+ classRefs: refs,
1861
+ attributeRef: attribute,
1862
+ css,
1863
+ element,
1864
+ from,
1865
+ when,
1866
+ start,
1867
+ end: p.endPos(),
1868
+ run: (ctx) => all(
1869
+ [from?.ev(ctx), css?.ev(ctx), element?.ev(ctx), ...classNames(refs, ctx)],
1870
+ ([container, cssText, value, ...names]) => {
1871
+ if (element) return removeValue(ctx, value, container);
1872
+ nullCheck(container, fromText);
1873
+ if (css) {
1874
+ const properties = cssProperties(String(cssText));
1875
+ implicitLoop(
1876
+ container,
1877
+ (t) => properties.forEach((property) => styleOf(t)?.removeProperty(property))
1878
+ );
1879
+ } else return mark(false, container, when, ctx, names, attribute);
1880
+ }
1881
+ )
1882
+ };
1883
+ return node;
1884
+ };
1885
+ }
1886
+ var byStyle = (property, hidden, shown) => (op, elt, arg) => {
1887
+ if (arg) elt.style[property] = arg;
1888
+ else if (op === "toggle")
1889
+ elt.style[property] = getComputedStyle(elt)[property] === hidden ? shown : hidden;
1890
+ else elt.style[property] = op === "hide" ? hidden : shown;
1891
+ };
1892
+ var strategies = {
1893
+ display(op, elt, arg) {
1894
+ if (!arg && elt instanceof HTMLDialogElement) {
1895
+ if (op === "hide" || op === "toggle" && elt.open) elt.close();
1896
+ else if (!elt.open) elt.show();
1897
+ return;
1898
+ }
1899
+ const data = dataOf(elt);
1900
+ if (arg) elt.style.display = arg;
1901
+ else if (op === "toggle")
1902
+ strategies.display(getComputedStyle(elt).display === "none" ? "show" : "hide", elt);
1903
+ else if (op === "hide") {
1904
+ data.originalDisplay ??= elt.style.display;
1905
+ elt.style.display = "none";
1906
+ } else if (data.originalDisplay && data.originalDisplay !== "none")
1907
+ elt.style.display = data.originalDisplay;
1908
+ else elt.style.removeProperty("display");
1909
+ },
1910
+ visibility: byStyle("visibility", "hidden", "visible"),
1911
+ opacity: byStyle("opacity", "0", "1"),
1912
+ hidden(op, elt) {
1913
+ const hide = op === "toggle" ? !elt.hasAttribute("hidden") : op === "hide";
1914
+ if (hide) elt.setAttribute("hidden", "");
1915
+ else elt.removeAttribute("hidden");
1916
+ }
1917
+ };
1918
+ function strategy(p, name) {
1919
+ const chosen = name ?? config.defaultHideShowStrategy ?? "display";
1920
+ return config.hideShowStrategies[chosen] ?? strategies[chosen] ?? p.err("Unknown show/hide strategy : " + chosen);
1921
+ }
1922
+ function toggle(g) {
1923
+ g.commands.toggle = (p, _keyword, start) => {
1924
+ p.matchAny("the", "my");
1925
+ const node = { type: "toggleCommand", start, end: start, run: () => {
1926
+ } };
1927
+ let visibility;
1928
+ if (p.cur().type === "STYLE_REF") {
1929
+ const styleProp2 = node.styleProp = p.consume().value.slice(1);
1930
+ visibility = strategy(p, styleProp2);
1931
+ node.on = p.match("of") ? p.withFollow(["with", "between"], () => expr(p)) : implicitMe(p);
1932
+ } else if (p.match("between")) {
1933
+ const first = classRef(p);
1934
+ if (first) {
1935
+ p.req("and");
1936
+ node.between = [first, classRef(p) ?? p.err("Expected classRef")];
1937
+ } else {
1938
+ const attribute2 = attributeRef(p) ?? p.err("Expected either a class reference or attribute expression");
1939
+ p.req("and");
1940
+ node.between = [attribute2, attributeRef(p) ?? p.err("Expected attributeRef")];
1941
+ }
1942
+ } else if (!(node.classRefs = classRefs(p)) && !(node.attributeRef = attributeRef(p))) {
1943
+ const element = p.g.toggleElement;
1944
+ if (!element) node.target = p.withFollow(["between"], () => assignable(p));
1945
+ else {
1946
+ const target2 = p.withFollow(["between", "as"], () => unary(p));
1947
+ if (!p.peek("between")) return element(p, target2, start);
1948
+ node.target = writable(p, target2);
1949
+ }
1950
+ }
1951
+ if (!node.styleProp && !node.target) node.on = p.match("on") ? expr(p) : implicitMe(p);
1952
+ if (p.match("between")) {
1953
+ const values = node.betweenValues = p.withFollow(["and"], () => {
1954
+ const list = [expr(p)];
1955
+ while (p.matchOp(",")) list.push(expr(p));
1956
+ return list;
1957
+ });
1958
+ p.req("and");
1959
+ values.push(expr(p));
1960
+ }
1961
+ if (node.target && !node.betweenValues)
1962
+ p.err("toggle <expression> requires 'between' with values");
1963
+ if (p.peek("for") && !p.peek("in", 2)) {
1964
+ p.match("for");
1965
+ node.time = expr(p);
1966
+ } else if (p.match("until")) {
1967
+ node.until = eventName(p);
1968
+ if (p.match("from")) node.from = expr(p);
1969
+ }
1970
+ node.end = p.endPos();
1971
+ const { on: on2, target, betweenValues, between, attributeRef: attribute, styleProp } = node;
1972
+ const onText = on2 ? p.text(on2) : "";
1973
+ const next = (values, current) => values[(values.findIndex((v) => v == current) + 1) % values.length];
1974
+ const flip = (ctx, targets, values, names) => {
1975
+ if (betweenValues && target?.lhs && target.put) {
1976
+ const write = target;
1977
+ return all(
1978
+ [target.ev(ctx), target.lhs(ctx)],
1979
+ ([current, lhs]) => write.put?.(ctx, lhs, next(values, current))
1980
+ );
1981
+ }
1982
+ if (betweenValues && styleProp) {
1983
+ return implicitLoop(targets, (t) => {
1984
+ const style = styleOf(t);
1985
+ if (!style || !isEl(t)) return;
1986
+ const current = style.getPropertyValue(styleProp) || getComputedStyle(t).getPropertyValue(styleProp);
1987
+ style.setProperty(styleProp, String(next(values, current)));
1988
+ });
1989
+ }
1990
+ nullCheck(targets, onText);
1991
+ implicitLoop(targets, (t) => {
1992
+ if (!isEl(t)) return;
1993
+ if (visibility) {
1994
+ if (t instanceof HTMLElement) visibility("toggle", t);
1995
+ } else if (between) {
1996
+ const [a, b] = between;
1997
+ if (a.type === "classRef" && b.type === "classRef") {
1998
+ const [first, second] = [String(a.className), String(b.className)];
1999
+ const had = t.classList.contains(first);
2000
+ t.classList.toggle(first, !had);
2001
+ t.classList.toggle(second, had);
2002
+ } else if (a.type === "attributeRef" && b.type === "attributeRef") {
2003
+ const hadFirst = t.getAttribute(a.name) === String(a.value);
2004
+ setAttribute2(t, hadFirst ? a : b, false);
2005
+ setAttribute2(t, hadFirst ? b : a, true);
2006
+ }
2007
+ } else if (attribute) setAttribute2(t, attribute, !t.hasAttribute(attribute.name));
2008
+ else names.forEach((name) => t.classList.toggle(String(name)));
2009
+ });
2010
+ };
2011
+ node.run = (ctx) => all(
2012
+ [
2013
+ on2?.ev(ctx),
2014
+ node.time?.ev(ctx),
2015
+ node.from?.ev(ctx),
2016
+ all(
2017
+ (betweenValues ?? []).map((v) => v.ev(ctx)),
2018
+ (v) => v
2019
+ ),
2020
+ ...classNames(node.classRefs, ctx)
2021
+ ],
2022
+ ([targets, time, source, values, ...names]) => {
2023
+ const once = () => flip(ctx, targets, Array.isArray(values) ? values : [], names);
2024
+ if (node.time) {
2025
+ return new Promise((resolve) => {
2026
+ once();
2027
+ setTimeout(() => {
2028
+ once();
2029
+ resolve();
2030
+ }, num(time));
2031
+ });
2032
+ }
2033
+ if (node.until) {
2034
+ const until = node.until;
2035
+ const eventSource = source || ctx.me;
2036
+ return new Promise((resolve) => {
2037
+ if (isTarget(eventSource)) {
2038
+ eventSource.addEventListener(
2039
+ until,
2040
+ () => {
2041
+ once();
2042
+ resolve();
2043
+ },
2044
+ { once: true }
2045
+ );
2046
+ }
2047
+ once();
2048
+ });
2049
+ }
2050
+ return then1(once(), () => {
2051
+ });
2052
+ }
2053
+ );
2054
+ return node;
2055
+ };
2056
+ }
2057
+
2058
+ // src/commands/dom-more.ts
2059
+ function hideShow(g) {
2060
+ for (const op of ["hide", "show"]) {
2061
+ g.commands[op] = (p, _keyword, start) => {
2062
+ const next = p.cur();
2063
+ const target = next.value === "when" || next.value === "with" || p.commandBoundary(next) ? implicitMe(p) : expr(p);
2064
+ let name;
2065
+ if (p.match("with")) name = p.reqType("IDENTIFIER", "STYLE_REF").value.replace(/^\*/, "");
2066
+ let arg;
2067
+ if (op === "show" && p.matchOp(":")) {
2068
+ arg = p.consumeUntil(void 0, "WHITESPACE").map((t) => t.value).join("");
2069
+ }
2070
+ const when = p.match("when") ? expr(p) : void 0;
2071
+ const apply = strategy(p, name);
2072
+ const targetText = p.text(target);
2073
+ const act = (which) => (elt) => {
2074
+ if (elt instanceof HTMLElement) apply(which, elt, which === "show" ? arg : void 0);
2075
+ };
2076
+ const node = {
2077
+ type: `${op}Command`,
2078
+ target,
2079
+ strategy: name,
2080
+ arg,
2081
+ when,
2082
+ start,
2083
+ end: p.endPos(),
2084
+ run: (ctx) => then1(target.ev(ctx), (elements) => {
2085
+ nullCheck(elements, targetText);
2086
+ if (when)
2087
+ return implicitLoopWhen(
2088
+ elements,
2089
+ when,
2090
+ ctx,
2091
+ act(op),
2092
+ act(op === "hide" ? "show" : "hide")
2093
+ );
2094
+ implicitLoop(elements, act(op));
2095
+ })
2096
+ };
2097
+ return node;
2098
+ };
2099
+ }
2100
+ }
2101
+ var MEASUREMENTS = "x y left top right bottom width height bounds scrollLeft scrollTop scrollLeftMax scrollTopMax scrollWidth scrollHeight scroll".split(
2102
+ " "
2103
+ );
2104
+
2105
+ // src/commands/events.ts
2106
+ function send(g) {
2107
+ g.commands.send = g.commands.trigger = (p, keyword, start) => {
2108
+ const event = eventName(p);
2109
+ const details = namedArgumentList(p);
2110
+ const to = p.match(keyword === "trigger" ? "on" : "to") ? expr(p) : implicitMe(p);
2111
+ const toText = p.text(to);
2112
+ const node = {
2113
+ type: "sendCommand",
2114
+ event,
2115
+ details,
2116
+ to,
2117
+ start,
2118
+ end: p.endPos(),
2119
+ run: (ctx) => all([to.ev(ctx), details?.ev(ctx)], ([targets, detail]) => {
2120
+ nullCheck(targets, toText);
2121
+ implicitLoop(
2122
+ targets,
2123
+ (target) => triggerEvent(target, event, obj(detail) ? detail : {}, ctx.me)
2124
+ );
2125
+ })
2126
+ };
2127
+ return node;
2128
+ };
2129
+ }
2130
+ function wait(g) {
2131
+ g.commands.wait = (p, _keyword, start) => {
2132
+ const node = { type: "waitCommand", start, end: start, run: () => {
2133
+ } };
2134
+ if (p.match("for")) {
2135
+ p.match("a");
2136
+ const events = node.events = [];
2137
+ do {
2138
+ const t = p.cur();
2139
+ if (t.type === "NUMBER" || t.op && t.value === "(") events.push(expr(p));
2140
+ else events.push({ event: eventName(p), args: eventArgs(p) });
2141
+ } while (p.match("or"));
2142
+ const from = node.from = p.match("from") ? expr(p) : void 0;
2143
+ const fromText = from ? p.text(from) : "me";
2144
+ node.run = (ctx) => then1(from ? from.ev(ctx) : ctx.me, (source) => {
2145
+ if (!isTarget(source)) throw new Error("Not a valid event target: " + fromText);
2146
+ return new Promise((resolve) => {
2147
+ for (const spec of events) {
2148
+ if ("event" in spec) {
2149
+ source.addEventListener(
2150
+ spec.event,
2151
+ (event) => {
2152
+ ctx.result = event;
2153
+ for (const arg of spec.args) {
2154
+ ctx.locals[arg] = get(event, arg) || get(get(event, "detail"), arg) || null;
2155
+ }
2156
+ resolve();
2157
+ },
2158
+ { once: true }
2159
+ );
2160
+ } else {
2161
+ then1(
2162
+ spec.ev(ctx),
2163
+ (ms) => setTimeout(() => {
2164
+ ctx.result = ms;
2165
+ resolve();
2166
+ }, num(ms))
2167
+ );
2168
+ }
2169
+ }
2170
+ });
2171
+ });
2172
+ } else {
2173
+ let time;
2174
+ if (p.match("a")) p.req("tick");
2175
+ else time = node.time = expr(p);
2176
+ node.run = (ctx) => then1(
2177
+ time?.ev(ctx),
2178
+ (ms) => new Promise((resolve) => setTimeout(resolve, time ? num(ms) : 0))
2179
+ );
2180
+ }
2181
+ node.end = p.endPos();
2182
+ return node;
2183
+ };
2184
+ }
2185
+
2186
+ // src/commands/misc.ts
2187
+ function log(g) {
2188
+ g.commands.log = (p, _keyword, start) => {
2189
+ const values = [expr(p)];
2190
+ while (p.matchOp(",")) values.push(expr(p));
2191
+ const logger = p.match("with") ? expr(p) : void 0;
2192
+ const node = {
2193
+ type: "logCommand",
2194
+ values,
2195
+ logger,
2196
+ start,
2197
+ end: p.endPos(),
2198
+ run: (ctx) => all([logger?.ev(ctx), ...values.map((v) => v.ev(ctx))], ([out, ...vals]) => {
2199
+ if (fn(out)) out(...vals);
2200
+ else console.log(...vals);
2201
+ })
2202
+ };
2203
+ return node;
2204
+ };
2205
+ }
2206
+ function get_(g) {
2207
+ g.commands.get = g.commands.call = (p, keyword, start) => {
2208
+ const value = expr(p);
2209
+ if (keyword === "call" && value.type !== "functionCall") p.err("Must be a function invocation");
2210
+ const node = {
2211
+ type: "getCommand",
2212
+ value,
2213
+ start,
2214
+ end: p.endPos(),
2215
+ run: (ctx) => then1(value.ev(ctx), (v) => {
2216
+ ctx.result = v;
2217
+ })
2218
+ };
2219
+ return node;
2220
+ };
2221
+ }
2222
+ function pseudoCommand(g) {
2223
+ g.pseudo = (p, start) => {
2224
+ const next = p.tok(1);
2225
+ if (!(next.op && (next.value === "." || next.value === "("))) return;
2226
+ const value = primary(p);
2227
+ if (value.type !== "functionCall") p.err("Pseudo-commands must be function calls");
2228
+ const callee = value.root;
2229
+ const args = "args" in value && Array.isArray(value.args) ? value.args : [];
2230
+ let target;
2231
+ if (callee && !callee.root) {
2232
+ if (p.matchAny("the", "to", "on", "with", "into", "from", "at")) target = expr(p);
2233
+ else if (p.match("me")) target = implicitMe(p);
2234
+ }
2235
+ const method = callee?.name ?? "";
2236
+ const targetText = target ? p.text(target) : "";
2237
+ const valueText = p.text(value);
2238
+ const receiver = target;
2239
+ const node = {
2240
+ type: "pseudoCommand",
2241
+ value,
2242
+ target,
2243
+ start,
2244
+ end: p.endPos(),
2245
+ run: (ctx) => {
2246
+ if (!receiver) {
2247
+ return then1(value.ev(ctx), (v) => {
2248
+ ctx.result = v;
2249
+ });
2250
+ }
2251
+ return all([receiver.ev(ctx), ...args.map((a) => a.ev(ctx))], ([owner, ...vals]) => {
2252
+ nullCheck(owner, targetText);
2253
+ ctx.result = call(get(owner, method), owner, vals, ctx, valueText);
2254
+ maybeNotify(owner, method);
2255
+ });
2256
+ }
2257
+ };
2258
+ return node;
2259
+ };
2260
+ }
2261
+
2262
+ // src/commands/setters.ts
2263
+ function set2(g) {
2264
+ g.commands.set = (p, _keyword, start) => parseSet(p, start);
2265
+ }
2266
+ function parseSet(p, start) {
2267
+ {
2268
+ if (p.cur().op && p.cur().value === "{") {
2269
+ const object = objectLiteral(p);
2270
+ p.req("on");
2271
+ const target2 = expr(p);
2272
+ const node2 = {
2273
+ type: "setCommand",
2274
+ target: target2,
2275
+ object,
2276
+ start,
2277
+ end: p.endPos(),
2278
+ run: (ctx) => all(
2279
+ [object.ev(ctx), target2.ev(ctx)],
2280
+ ([props, onto]) => void Object.assign(Object(onto), props)
2281
+ )
2282
+ };
2283
+ return node2;
2284
+ }
2285
+ const target = p.withFollow(["to"], () => assignable(p));
2286
+ p.req("to");
2287
+ const value = expr(p);
2288
+ const node = {
2289
+ type: "setCommand",
2290
+ target,
2291
+ value,
2292
+ start,
2293
+ end: p.endPos(),
2294
+ // `set` writes its target and nothing else: `it` is left alone.
2295
+ run: (ctx) => all([target.lhs?.(ctx), value.ev(ctx)], ([lhs, v]) => target.put?.(ctx, lhs, v))
2296
+ };
2297
+ return node;
2298
+ }
2299
+ }
2300
+ function increment(g) {
2301
+ for (const keyword of ["increment", "decrement"]) {
2302
+ const sign = keyword === "increment" ? 1 : -1;
2303
+ g.commands[keyword] = (p, _keyword, start) => {
2304
+ const target = p.withFollow(sign < 0 ? ["by"] : [], () => assignable(p));
2305
+ const amount = p.match("by") ? expr(p) : void 0;
2306
+ const node = {
2307
+ type: `${keyword}Command`,
2308
+ target,
2309
+ amount,
2310
+ start,
2311
+ end: p.endPos(),
2312
+ run: (ctx) => all([target.ev(ctx), amount?.ev(ctx), target.lhs?.(ctx)], ([current, by, lhs]) => {
2313
+ const value = (current ? parseFloat(String(current)) : 0) + sign * (amount ? parseFloat(String(by)) : 1);
2314
+ ctx.result = value;
2315
+ target.put?.(ctx, lhs, value);
2316
+ })
2317
+ };
2318
+ return node;
2319
+ };
2320
+ }
2321
+ }
2322
+ function setContent(elt, value) {
2323
+ elt.replaceChildren(toFragment(value));
2324
+ host.process(elt);
2325
+ }
2326
+ var WRITES = [
2327
+ "arrayIndex",
2328
+ "propertyAccess",
2329
+ "possessive",
2330
+ "ofExpression",
2331
+ "attributeRef",
2332
+ "styleRef",
2333
+ "attributeRefAccess"
2334
+ ];
2335
+ var OPERATIONS = {
2336
+ into: "into",
2337
+ before: "before",
2338
+ after: "after",
2339
+ start: "start",
2340
+ end: "end"
2341
+ };
2342
+ var INSERT = { before: "before", after: "after", start: "prepend", end: "append" };
2343
+ function put(g) {
2344
+ g.commands.put = (p, _keyword, start) => {
2345
+ const value = expr(p);
2346
+ let word = p.matchAny("into", "before", "after");
2347
+ if (!word && p.match("at")) {
2348
+ p.match("the");
2349
+ word = p.matchAny("start", "end");
2350
+ p.req("of");
2351
+ }
2352
+ const operation = OPERATIONS[(word ?? p.expected("into", "before", "at start of", "at end of", "after")).value];
2353
+ const target = unwrap(expr(p));
2354
+ const targetText = p.text(target);
2355
+ const into = (ctx, v) => {
2356
+ if (target.type === "symbol") {
2357
+ return then1(target.ev(ctx), (current) => {
2358
+ if (isEl(current) || current instanceof Document) setContent(current, v);
2359
+ else target.put?.(ctx, void 0, v);
2360
+ });
2361
+ }
2362
+ if (WRITES.includes(target.type)) {
2363
+ return then1(target.lhs?.(ctx), (lhs) => target.put?.(ctx, lhs, v));
2364
+ }
2365
+ return then1(target.ev(ctx), (root) => {
2366
+ nullCheck(root, targetText);
2367
+ implicitLoop(root, (elt) => {
2368
+ if (isEl(elt) || elt instanceof Document) setContent(elt, v);
2369
+ });
2370
+ });
2371
+ };
2372
+ const insert = (ctx, v, method) => then1(target.ev(ctx), (root) => {
2373
+ nullCheck(root, targetText);
2374
+ if (Array.isArray(root)) {
2375
+ if (method === "prepend") root.unshift(v);
2376
+ else root.push(v);
2377
+ rx.wroteProperty(root);
2378
+ return;
2379
+ }
2380
+ implicitLoop(root, (elt) => {
2381
+ if (!isEl(elt)) return;
2382
+ elt[method](v instanceof Node ? v : toFragment(v));
2383
+ host.process(elt.parentElement ?? elt);
2384
+ });
2385
+ });
2386
+ const node = {
2387
+ type: "putCommand",
2388
+ value,
2389
+ operation,
2390
+ target,
2391
+ start,
2392
+ end: p.endPos(),
2393
+ run: (ctx) => then1(
2394
+ value.ev(ctx),
2395
+ (v) => operation === "into" ? into(ctx, v) : insert(ctx, v, INSERT[operation])
2396
+ )
2397
+ };
2398
+ return node;
2399
+ };
2400
+ }
2401
+
2402
+ // src/parser.ts
2403
+ var ParseError = class extends Error {
2404
+ constructor(message, token, source, expected) {
2405
+ super(message);
2406
+ this.token = token;
2407
+ this.source = source;
2408
+ this.expected = expected;
2409
+ }
2410
+ /** What the author wrote, when a plugin rewrote the script before it was parsed. */
2411
+ written;
2412
+ };
2413
+ var createGrammar = () => ({
2414
+ commands: /* @__PURE__ */ Object.create(null),
2415
+ features: /* @__PURE__ */ Object.create(null),
2416
+ leaves: [],
2417
+ indirects: [],
2418
+ unaries: [],
2419
+ postfixes: [],
2420
+ collections: []
2421
+ });
2422
+ var Parser = class _Parser {
2423
+ constructor(g, tokens, src) {
2424
+ this.g = g;
2425
+ this.tokens = tokens;
2426
+ this.src = src;
2427
+ const end = src.length;
2428
+ this.eof = { type: "EOF", value: "<<<EOF>>>", start: end, end, line: 0, column: 0 };
2429
+ this.last = this.eof;
2430
+ this.skipWs();
2431
+ }
2432
+ i = 0;
2433
+ follows = [];
2434
+ eof;
2435
+ /** The last token consumed by a match. */
2436
+ last;
2437
+ child(tokens, src) {
2438
+ return new _Parser(this.g, tokens, src);
2439
+ }
2440
+ // ----- access ------------------------------------------------------------
2441
+ /** The nth token from here; whitespace is skipped unless `ws`. */
2442
+ tok(n = 0, ws = false) {
2443
+ let j = this.i;
2444
+ for (; ; ) {
2445
+ if (!ws) while (this.tokens[j]?.type === "WHITESPACE") j++;
2446
+ if (n-- === 0) return this.tokens[j] ?? this.eof;
2447
+ j++;
2448
+ }
2449
+ }
2450
+ cur() {
2451
+ return this.tokens[this.i] ?? this.eof;
2452
+ }
2453
+ hasMore() {
2454
+ return this.i < this.tokens.length;
2455
+ }
2456
+ /** Start offset of the current token — what a rule records as its node's `start`. */
2457
+ pos() {
2458
+ return this.cur().start;
2459
+ }
2460
+ /** End offset of the last consumed token — a node's `end`. */
2461
+ endPos() {
2462
+ return this.last.end;
2463
+ }
2464
+ text(node) {
2465
+ return this.src.substring(node.start, node.end);
2466
+ }
2467
+ // ----- matching ----------------------------------------------------------
2468
+ match(value, type = "IDENTIFIER") {
2469
+ if (this.follows.includes(value)) return;
2470
+ const t = this.cur();
2471
+ if (t.value === value && t.type === type) return this.consume();
2472
+ }
2473
+ matchOp(value) {
2474
+ const t = this.cur();
2475
+ if (t.op && t.value === value) return this.consume();
2476
+ }
2477
+ matchType(...types) {
2478
+ if (types.includes(this.cur().type)) return this.consume();
2479
+ }
2480
+ matchAny(...values) {
2481
+ for (const value of values) {
2482
+ const t = this.match(value);
2483
+ if (t) return t;
2484
+ }
2485
+ }
2486
+ matchAnyOp(...values) {
2487
+ for (const value of values) {
2488
+ const t = this.matchOp(value);
2489
+ if (t) return t;
2490
+ }
2491
+ }
2492
+ req(value) {
2493
+ return this.match(value) ?? this.expected(value);
2494
+ }
2495
+ reqOp(value) {
2496
+ return this.matchOp(value) ?? this.expected(value);
2497
+ }
2498
+ reqType(...types) {
2499
+ return this.matchType(...types) ?? this.expected(...types);
2500
+ }
2501
+ /** Is the nth token from here this identifier (or this `type`)? Consumes nothing. */
2502
+ peek(value, n = 0, type = "IDENTIFIER") {
2503
+ const t = this.tok(n);
2504
+ if (t.value === value && t.type === type) return t;
2505
+ }
2506
+ // ----- consuming ---------------------------------------------------------
2507
+ consume() {
2508
+ if (!this.hasMore()) return this.eof;
2509
+ this.last = this.tokens[this.i++];
2510
+ this.skipWs();
2511
+ return this.last;
2512
+ }
2513
+ skipWs() {
2514
+ while (this.tokens[this.i]?.type === "WHITESPACE") this.i++;
2515
+ }
2516
+ /** Raw tokens (whitespace included) up to a token with this value or type. */
2517
+ consumeUntil(value, type) {
2518
+ const out = [];
2519
+ let t = this.cur();
2520
+ while ((type == null || t.type !== type) && (value == null || t.value !== value) && t.type !== "EOF") {
2521
+ out.push(t);
2522
+ this.i++;
2523
+ t = this.cur();
2524
+ }
2525
+ this.skipWs();
2526
+ return out;
2527
+ }
2528
+ /** The whitespace just before the current token, if any. */
2529
+ lastWs() {
2530
+ const t = this.tokens[this.i - 1];
2531
+ return t?.type === "WHITESPACE" ? t.value : "";
2532
+ }
2533
+ // ----- follow set: words a nested rule must leave for its caller ----------
2534
+ pushFollow(...words) {
2535
+ this.follows.push(...words);
2536
+ return words.length;
2537
+ }
2538
+ popFollow(count = 1) {
2539
+ this.follows.length -= count;
2540
+ }
2541
+ /** Parse with `words` reserved for the caller, e.g. the `to` of `set x to y`. */
2542
+ withFollow(words, f) {
2543
+ const count = this.pushFollow(...words);
2544
+ try {
2545
+ return f();
2546
+ } finally {
2547
+ this.popFollow(count);
2548
+ }
2549
+ }
2550
+ /** Parse with no reserved words — inside parentheses the outer rule's words are free again. */
2551
+ withoutFollows(f) {
2552
+ const saved = this.follows;
2553
+ this.follows = [];
2554
+ try {
2555
+ return f();
2556
+ } finally {
2557
+ this.follows = saved;
2558
+ }
2559
+ }
2560
+ // ----- errors ------------------------------------------------------------
2561
+ err(message, expected) {
2562
+ const token = this.cur();
2563
+ throw new ParseError(message ?? "Unexpected Token : " + token.value, token, this.src, expected);
2564
+ }
2565
+ expected(...expected) {
2566
+ this.err(
2567
+ expected.length === 1 ? `Expected '${expected[0]}' but found '${this.cur().value}'` : "Expected one of: " + expected.map((e) => `'${e}'`).join(", "),
2568
+ expected
2569
+ );
2570
+ }
2571
+ // ----- statement boundaries ------------------------------------------------
2572
+ commandStart(token) {
2573
+ return token.value in this.g.commands;
2574
+ }
2575
+ featureStart(token) {
2576
+ return token.value in this.g.features;
2577
+ }
2578
+ commandBoundary(token) {
2579
+ return ["end", "then", "else", "otherwise", ")"].includes(token.value) || this.commandStart(token) || this.featureStart(token) || token.type === "EOF";
2580
+ }
2581
+ };
2582
+ function formatError(e) {
2583
+ const lines = e.source.split("\n");
2584
+ const index = e.token.line ? e.token.line - 1 : lines.length - 1;
2585
+ const line = lines[index] ?? "";
2586
+ const column = e.token.line ? e.token.column : Math.max(0, line.length - 1);
2587
+ const gutter = String(index + 1).length;
2588
+ const pad = " ".repeat(gutter + 5 + column);
2589
+ return ` ${index + 1} | ${line}
2590
+ ` + pad + "^".repeat(Math.max(1, e.token.value.length)) + "\n" + pad + e.message + "\n";
2591
+ }
2592
+
2593
+ // src/engine.ts
2594
+ var grammar = createGrammar();
2595
+ function register(...modules) {
2596
+ for (const module of modules) module(grammar);
2597
+ }
2598
+ var parser = (src) => new Parser(grammar, tokenize(src), src);
2599
+ function parseProgram(src) {
2600
+ const p = parser(src);
2601
+ const parsed = program(p);
2602
+ if (p.hasMore()) p.err();
2603
+ return parsed;
2604
+ }
2605
+ function parse(src) {
2606
+ const p = parser(src);
2607
+ const first = p.cur();
2608
+ const parsed = p.commandStart(first) ? { kind: "commands", commands: commandList(p) } : p.featureStart(first) ? { kind: "features", program: program(p) } : { kind: "expression", expression: expr(p) };
2609
+ if (p.hasMore()) p.err();
2610
+ return parsed;
2611
+ }
2612
+ function evaluate(src, overrides) {
2613
+ let parsed;
2614
+ try {
2615
+ parsed = parse(src);
2616
+ } catch (e) {
2617
+ if (e instanceof ParseError) throw new Error(e.message + "\n\n" + formatError(e));
2618
+ throw e;
2619
+ }
2620
+ const body = document.body;
2621
+ if (parsed.kind === "features") {
2622
+ for (const feature2 of parsed.program.features) feature2.install(body, body);
2623
+ return;
2624
+ }
2625
+ const ctx = Object.assign(makeContext(body, void 0, body, null), overrides);
2626
+ if (parsed.kind === "expression") return parsed.expression.ev(ctx);
2627
+ return then1(runList(parsed.commands, ctx), (signal) => {
2628
+ const returned = get(signal, "k") === "return" ? get(signal, "value") : void 0;
2629
+ return returned !== void 0 ? returned : ctx.result;
2630
+ });
2631
+ }
2632
+ var attributes = () => config.attributes.replaceAll(" ", "").split(",");
2633
+ var isScript = (elt) => elt instanceof HTMLScriptElement && elt.type === "text/hyperscript";
2634
+ function scriptOf(elt) {
2635
+ for (const name of attributes()) {
2636
+ if (elt.hasAttribute(name)) return elt.getAttribute(name);
2637
+ }
2638
+ return isScript(elt) ? elt.innerText : null;
2639
+ }
2640
+ var hash = (s) => {
2641
+ let h = 5381;
2642
+ for (let i = 0; i < s.length; i++) h = (h << 5) + h + s.charCodeAt(i);
2643
+ return h;
2644
+ };
2645
+ var transforms = [];
2646
+ function initElement(elt) {
2647
+ if (elt.closest(config.disableSelector)) return;
2648
+ const written = scriptOf(elt);
2649
+ if (!written) return;
2650
+ const scriptHash = hash(written);
2651
+ if (peekData(elt)?.initialized) {
2652
+ if (peekData(elt)?.scriptHash === scriptHash) return host.enter(elt);
2653
+ cleanup(elt);
2654
+ }
2655
+ if (!triggerEvent(elt, "hyperscript:before:init")) return;
2656
+ Object.assign(dataOf(elt), { initialized: true, scriptHash });
2657
+ const target = isScript(elt) ? document.body : elt;
2658
+ let src = written;
2659
+ try {
2660
+ for (const transform of transforms) src = transform(src, elt) ?? src;
2661
+ const { features } = parseProgram(src);
2662
+ host.enter(elt);
2663
+ for (const feature2 of features) feature2.install(target, elt);
2664
+ elt.setAttribute("data-hyperscript-powered", "true");
2665
+ triggerEvent(elt, "hyperscript:after:init");
2666
+ setTimeout(() => triggerEvent(target, "load", { hyperscript: true }), 1);
2667
+ } catch (e) {
2668
+ if (e instanceof ParseError) {
2669
+ if (src !== written) e.written = written;
2670
+ triggerEvent(elt, "hyperscript:parse-error", { errors: [e] });
2671
+ const from = e.written ? `
2672
+ rewritten from: ${e.written}
2673
+ ` : "";
2674
+ console.error("hyperscript: 1 parse error(s) on:", elt, "\n\n" + formatError(e) + from);
2675
+ } else {
2676
+ triggerEvent(elt, "exception", { error: e });
2677
+ console.error("hyperscript errors were found on the following element:", elt, "\n\n", e);
2678
+ }
2679
+ }
2680
+ }
2681
+ var beforeProcess = [];
2682
+ var afterProcess = [];
2683
+ function processNode(node) {
2684
+ if (!(node instanceof Element || node instanceof Document || node instanceof DocumentFragment))
2685
+ return;
2686
+ for (const hook of beforeProcess) hook(node);
2687
+ const selector = attributes().map((a) => `[${a}]`).join(", ") + ", [type='text/hyperscript']";
2688
+ if (node instanceof Element && node.matches(selector)) initElement(node);
2689
+ node.querySelectorAll(selector).forEach(initElement);
2690
+ for (const hook of afterProcess) hook(node);
2691
+ }
2692
+ function cleanup(elt) {
2693
+ const data = peekData(elt);
2694
+ if (!data) return;
2695
+ triggerEvent(elt, "hyperscript:before:cleanup");
2696
+ for (const { target, event, handler } of data.listeners ?? [])
2697
+ target.removeEventListener(event, handler);
2698
+ for (const observer of data.observers ?? []) observer.disconnect();
2699
+ for (const timer of data.timers ?? []) clearTimeout(timer);
2700
+ rx.stop(elt);
2701
+ elt.querySelectorAll("[data-hyperscript-powered]").forEach(cleanup);
2702
+ triggerEvent(elt, "hyperscript:after:cleanup");
2703
+ elt.removeAttribute("data-hyperscript-powered");
2704
+ dropData(elt);
2705
+ }
2706
+ host.process = processNode;
2707
+ function hostParse(src) {
2708
+ try {
2709
+ const parsed = parse(src);
2710
+ if (parsed.kind === "features") return { ...parsed.program, errors: [] };
2711
+ return { ...parsed.kind === "commands" ? parsed.commands[0] : parsed.expression, errors: [] };
2712
+ } catch (e) {
2713
+ if (e instanceof ParseError) return { errors: [e] };
2714
+ throw e;
2715
+ }
2716
+ }
2717
+ var api = Object.assign(evaluate, {
2718
+ // Upstream's shape: `config.conversions.Foo = …` and `config.conversions.dynamicResolvers.push(…)`.
2719
+ config: Object.assign(config, { conversions: Object.assign(conversions, { dynamicResolvers }) }),
2720
+ /** `use(plugin)`: the plugin receives this object. */
2721
+ use(plugin) {
2722
+ plugin(api);
2723
+ },
2724
+ addBeforeProcessHook: (hook) => void beforeProcess.push(hook),
2725
+ addAfterProcessHook: (hook) => void afterProcess.push(hook),
2726
+ /** Not in upstream: rewrite a script as it is read, leaving the attribute as written. */
2727
+ addSourceTransform: (transform) => void transforms.push(transform),
2728
+ evaluate,
2729
+ parse: hostParse,
2730
+ process: processNode,
2731
+ /** Upstream's older name for `process`. */
2732
+ processNode,
2733
+ cleanup,
2734
+ /** The part of upstream's `internals` that pages and tests reach for. */
2735
+ internals: { runtime: { cleanup, processNode } },
2736
+ version: false ? "dev" : "3.3.0"
2737
+ });
2738
+ function boot() {
2739
+ Object.assign(globalThis, { _hyperscript: api });
2740
+ if (typeof document === "undefined") return;
2741
+ const start = () => {
2742
+ processNode(document.documentElement);
2743
+ document.dispatchEvent(new Event("hyperscript:ready"));
2744
+ };
2745
+ if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", start);
2746
+ else setTimeout(start);
2747
+ }
2748
+
2749
+ // src/on.ts
2750
+ function queueFor(elt, feature2) {
2751
+ if (typeof elt !== "object" || elt === null) return { queue: [], executing: false };
2752
+ const queues = dataOf(elt).eventQueues ??= /* @__PURE__ */ new Map();
2753
+ let queue = queues.get(feature2);
2754
+ if (!queue) queues.set(feature2, queue = { queue: [], executing: false });
2755
+ return queue;
2756
+ }
2757
+ function execute(ctx, feature2) {
2758
+ const info = queueFor(ctx.me, feature2);
2759
+ if (info.executing && !feature2.every) {
2760
+ if (feature2.queue === "none" || feature2.queue === "first" && info.queue.length > 0) return;
2761
+ if (feature2.queue !== "all") info.queue.length = 0;
2762
+ info.queue.push(ctx);
2763
+ return;
2764
+ }
2765
+ info.executing = true;
2766
+ const finish = (failure) => {
2767
+ info.executing = false;
2768
+ const queued = info.queue.shift();
2769
+ if (queued) setTimeout(() => execute(queued, feature2), 1);
2770
+ if (failure) {
2771
+ const { error } = failure;
2772
+ console.error(get(error, "message") ?? error);
2773
+ console.error(get(error, "stack"));
2774
+ triggerEvent(ctx.me, "exception", { error });
2775
+ }
2776
+ };
2777
+ guard(
2778
+ () => then1(runBlock(ctx, feature2.body, feature2), () => finish()),
2779
+ (error) => finish({ error })
2780
+ );
2781
+ }
2782
+ function install(feature2, elt) {
2783
+ if (!isTarget(elt)) return;
2784
+ const data = dataOf(elt);
2785
+ const listeners = data.listeners ??= [];
2786
+ const observers = data.observers ??= [];
2787
+ const timers = data.timers ??= /* @__PURE__ */ new Set();
2788
+ for (const spec of feature2.events) {
2789
+ const state = { execCount: 0 };
2790
+ const targets = spec.elsewhere ? [document] : spec.from ? spec.from.ev(makeContext(elt, feature2, elt, null)) : [elt];
2791
+ implicitLoop(targets, (target) => {
2792
+ if (!isTarget(target)) {
2793
+ console.warn(
2794
+ "'%s' feature ignored because target does not exists:",
2795
+ feature2.displayName,
2796
+ elt
2797
+ );
2798
+ return;
2799
+ }
2800
+ let name = spec.on;
2801
+ if (spec.mutationSpec && target instanceof Node) {
2802
+ name = "hyperscript:mutation";
2803
+ const observer = new MutationObserver(
2804
+ (mutationList) => triggerEvent(target, name, { mutationList, observer })
2805
+ );
2806
+ observer.observe(target, spec.mutationSpec);
2807
+ observers.push(observer);
2808
+ }
2809
+ if (spec.intersectionSpec && target instanceof Element) {
2810
+ name = "hyperscript:intersection";
2811
+ const observer = new IntersectionObserver((entries) => {
2812
+ for (const entry of entries) {
2813
+ triggerEvent(target, name, {
2814
+ observer,
2815
+ entry,
2816
+ intersecting: entry.isIntersecting,
2817
+ isIntersecting: entry.isIntersecting,
2818
+ intersectionRatio: entry.intersectionRatio
2819
+ });
2820
+ }
2821
+ }, spec.intersectionSpec);
2822
+ observer.observe(target);
2823
+ observers.push(observer);
2824
+ }
2825
+ if (spec.resizeSpec && target instanceof Element) {
2826
+ name = "hyperscript:resize";
2827
+ const observer = new ResizeObserver((entries) => {
2828
+ for (const entry of entries) {
2829
+ const { width, height } = entry.contentRect;
2830
+ triggerEvent(target, name, { width, height, contentRect: entry.contentRect, entry });
2831
+ }
2832
+ });
2833
+ observer.observe(target);
2834
+ observers.push(observer);
2835
+ }
2836
+ const handler = (event) => {
2837
+ if (elt instanceof Node && target !== elt && !elt.isConnected) {
2838
+ target.removeEventListener(name, handler);
2839
+ return;
2840
+ }
2841
+ const ctx = makeContext(elt, feature2, elt, event);
2842
+ if (spec.elsewhere && elt instanceof Node && event.target instanceof Node && elt.contains(event.target))
2843
+ return;
2844
+ if (spec.from) ctx.result = target;
2845
+ for (const arg of spec.args) {
2846
+ const fromEvent = get(event, arg);
2847
+ if (fromEvent !== void 0) ctx.locals[arg] = fromEvent;
2848
+ else if (ctx.detail != null) ctx.locals[arg] = get(ctx.detail, arg);
2849
+ }
2850
+ if (spec.filter) {
2851
+ ctx.meta.context = event;
2852
+ try {
2853
+ if (!spec.filter.ev(ctx)) return;
2854
+ } finally {
2855
+ ctx.meta.context = void 0;
2856
+ }
2857
+ }
2858
+ if (spec.inExpr?.css) {
2859
+ let match = event.target instanceof Element ? event.target : null;
2860
+ while (match && !match.matches(spec.inExpr.css)) match = match.parentElement;
2861
+ if (!match) return;
2862
+ ctx.result = match;
2863
+ }
2864
+ state.execCount++;
2865
+ if (spec.startCount) {
2866
+ const count = state.execCount;
2867
+ if (spec.endCount ? count < spec.startCount || count > spec.endCount : spec.unbounded ? count < spec.startCount : count !== spec.startCount)
2868
+ return;
2869
+ }
2870
+ if (spec.debounceTime) {
2871
+ if (state.debounced) {
2872
+ clearTimeout(state.debounced);
2873
+ timers.delete(state.debounced);
2874
+ }
2875
+ timers.add(
2876
+ state.debounced = setTimeout(() => execute(ctx, feature2), spec.debounceTime)
2877
+ );
2878
+ return;
2879
+ }
2880
+ if (spec.throttleTime) {
2881
+ if (state.lastExec && Date.now() < state.lastExec + spec.throttleTime) return;
2882
+ state.lastExec = Date.now();
2883
+ }
2884
+ execute(ctx, feature2);
2885
+ };
2886
+ target.addEventListener(name, handler);
2887
+ listeners.push({ target, event: name, handler });
2888
+ });
2889
+ }
2890
+ }
2891
+ function mutationSpec(p) {
2892
+ if (!p.match("of")) {
2893
+ return {
2894
+ attributes: true,
2895
+ characterData: true,
2896
+ childList: true,
2897
+ attributeOldValue: true,
2898
+ characterDataOldValue: true
2899
+ };
2900
+ }
2901
+ const spec = {};
2902
+ do {
2903
+ if (p.match("anything"))
2904
+ Object.assign(spec, {
2905
+ attributes: true,
2906
+ subtree: true,
2907
+ characterData: true,
2908
+ childList: true
2909
+ });
2910
+ else if (p.match("childList")) spec.childList = true;
2911
+ else if (p.match("attributes")) spec.attributes = true;
2912
+ else if (p.match("subtree")) spec.subtree = true;
2913
+ else if (p.match("characterData")) spec.characterData = true;
2914
+ else if (p.cur().type === "ATTRIBUTE_REF") {
2915
+ const attribute = p.consume().value;
2916
+ if (!attribute.startsWith("@")) p.err("Only shorthand attribute references are allowed here");
2917
+ (spec.attributeFilter ??= []).push(attribute.substring(1));
2918
+ } else p.err("Unknown mutation config specification");
2919
+ } while (p.match("or"));
2920
+ if (spec.attributes || spec.attributeFilter) spec.attributeOldValue = true;
2921
+ if (spec.characterData) spec.characterDataOldValue = true;
2922
+ return spec;
2923
+ }
2924
+ function intersectionSpec(p) {
2925
+ const spec = {};
2926
+ if (p.match("with")) {
2927
+ const root = evalStatic(expr(p));
2928
+ if (root instanceof Element) spec.root = root;
2929
+ }
2930
+ if (p.match("having")) {
2931
+ do {
2932
+ if (p.match("margin")) spec.rootMargin = stringLike(p);
2933
+ else if (p.match("threshold")) spec.threshold = Number(evalStatic(expr(p)));
2934
+ else p.err("Unknown intersection config specification");
2935
+ } while (p.match("and"));
2936
+ }
2937
+ return spec;
2938
+ }
2939
+ function eventSpec(p, first) {
2940
+ const on2 = eventName(p);
2941
+ const args = eventArgs(p);
2942
+ let filter;
2943
+ if (p.matchOp("[")) {
2944
+ filter = expr(p);
2945
+ p.reqOp("]");
2946
+ }
2947
+ let startCount;
2948
+ let endCount;
2949
+ let unbounded = false;
2950
+ if (first) startCount = 1;
2951
+ else if (p.cur().type === "NUMBER") {
2952
+ startCount = parseInt(p.consume().value);
2953
+ if (p.match("to")) endCount = parseInt(p.consume().value);
2954
+ else if (p.match("and")) {
2955
+ unbounded = true;
2956
+ p.req("on");
2957
+ }
2958
+ }
2959
+ const spec = {
2960
+ on: on2,
2961
+ args,
2962
+ filter,
2963
+ startCount,
2964
+ endCount,
2965
+ unbounded,
2966
+ elsewhere: false,
2967
+ resizeSpec: on2 === "resize"
2968
+ };
2969
+ if (on2 === "intersection") spec.intersectionSpec = intersectionSpec(p);
2970
+ else if (on2 === "mutation") spec.mutationSpec = mutationSpec(p);
2971
+ if (p.match("from")) {
2972
+ if (p.match("elsewhere")) spec.elsewhere = true;
2973
+ else spec.from = p.withFollow(["or"], () => expr(p));
2974
+ }
2975
+ if (!spec.from && !spec.elsewhere && p.match("elsewhere")) spec.elsewhere = true;
2976
+ if (p.match("in")) spec.inExpr = unary(p);
2977
+ const time = () => {
2978
+ p.req("at");
2979
+ return Number(evalStatic(unary(p)));
2980
+ };
2981
+ if (p.match("debounced")) spec.debounceTime = time();
2982
+ else if (p.match("throttled")) spec.throttleTime = time();
2983
+ return spec;
2984
+ }
2985
+ function on(g) {
2986
+ g.features.on = (p, start) => {
2987
+ const every = !!p.match("every");
2988
+ const first = !every && !!p.match("first");
2989
+ const events = [];
2990
+ do
2991
+ events.push(eventSpec(p, first));
2992
+ while (p.match("or"));
2993
+ let queue = "last";
2994
+ if (!every && p.match("queue")) {
2995
+ if (p.match("all")) queue = "all";
2996
+ else if (p.match("first")) queue = "first";
2997
+ else if (p.match("none")) queue = "none";
2998
+ else p.req("last");
2999
+ }
3000
+ const body = commandList(p);
3001
+ const feature2 = {
3002
+ type: "onFeature",
3003
+ displayName: "on " + events.map((e) => e.on).join(" or "),
3004
+ events,
3005
+ body,
3006
+ every,
3007
+ queue,
3008
+ ...errorAndFinally(p),
3009
+ start,
3010
+ end: p.endPos(),
3011
+ install: (target) => install(feature2, target)
3012
+ };
3013
+ return feature2;
3014
+ };
3015
+ }
3016
+
3017
+ // src/bundles/common.ts
3018
+ register(on, add, remove, toggle, hideShow, set2, put, increment, ifCommand, halt, send, wait, log, get_, pseudoCommand);
3019
+ boot();
3020
+ })();