vsn 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1864 -716
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +194 -53
- package/dist/index.d.ts +194 -53
- package/dist/index.js +1859 -714
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +8 -8
- package/dist/index.min.js.map +1 -1
- package/dist/plugins/microdata.d.ts +481 -0
- package/dist/plugins/microdata.js +178 -0
- package/dist/plugins/microdata.js.map +1 -0
- package/dist/plugins/microdata.min.js +2 -0
- package/dist/plugins/microdata.min.js.map +1 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -20,6 +20,9 @@ var TokenType = /* @__PURE__ */ ((TokenType2) => {
|
|
|
20
20
|
TokenType2["While"] = "While";
|
|
21
21
|
TokenType2["Try"] = "Try";
|
|
22
22
|
TokenType2["Catch"] = "Catch";
|
|
23
|
+
TokenType2["Assert"] = "Assert";
|
|
24
|
+
TokenType2["Break"] = "Break";
|
|
25
|
+
TokenType2["Continue"] = "Continue";
|
|
23
26
|
TokenType2["LBrace"] = "LBrace";
|
|
24
27
|
TokenType2["RBrace"] = "RBrace";
|
|
25
28
|
TokenType2["LParen"] = "LParen";
|
|
@@ -35,7 +38,9 @@ var TokenType = /* @__PURE__ */ ((TokenType2) => {
|
|
|
35
38
|
TokenType2["Greater"] = "Greater";
|
|
36
39
|
TokenType2["Less"] = "Less";
|
|
37
40
|
TokenType2["Plus"] = "Plus";
|
|
41
|
+
TokenType2["PlusPlus"] = "PlusPlus";
|
|
38
42
|
TokenType2["Minus"] = "Minus";
|
|
43
|
+
TokenType2["MinusMinus"] = "MinusMinus";
|
|
39
44
|
TokenType2["Tilde"] = "Tilde";
|
|
40
45
|
TokenType2["Star"] = "Star";
|
|
41
46
|
TokenType2["Slash"] = "Slash";
|
|
@@ -75,6 +80,9 @@ var KEYWORDS = {
|
|
|
75
80
|
while: "While" /* While */,
|
|
76
81
|
try: "Try" /* Try */,
|
|
77
82
|
catch: "Catch" /* Catch */,
|
|
83
|
+
assert: "Assert" /* Assert */,
|
|
84
|
+
break: "Break" /* Break */,
|
|
85
|
+
continue: "Continue" /* Continue */,
|
|
78
86
|
true: "Boolean" /* Boolean */,
|
|
79
87
|
false: "Boolean" /* Boolean */,
|
|
80
88
|
null: "Null" /* Null */
|
|
@@ -176,8 +184,20 @@ var Lexer = class {
|
|
|
176
184
|
readIdentifier() {
|
|
177
185
|
const start = this.position();
|
|
178
186
|
let value = "";
|
|
179
|
-
while (!this.eof()
|
|
180
|
-
|
|
187
|
+
while (!this.eof()) {
|
|
188
|
+
const ch = this.peek();
|
|
189
|
+
if (this.isAlphaNumeric(ch) || ch === "_") {
|
|
190
|
+
value += this.next();
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (ch === "-") {
|
|
194
|
+
if (this.peek(1) === "-") {
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
value += this.next();
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
181
201
|
}
|
|
182
202
|
const keywordType = KEYWORDS[value];
|
|
183
203
|
if (keywordType) {
|
|
@@ -318,6 +338,16 @@ var Lexer = class {
|
|
|
318
338
|
this.next();
|
|
319
339
|
return this.token("Pipe" /* Pipe */, "|>", start);
|
|
320
340
|
}
|
|
341
|
+
if (ch === "+" && next === "+") {
|
|
342
|
+
this.next();
|
|
343
|
+
this.next();
|
|
344
|
+
return this.token("PlusPlus" /* PlusPlus */, "++", start);
|
|
345
|
+
}
|
|
346
|
+
if (ch === "-" && next === "-") {
|
|
347
|
+
this.next();
|
|
348
|
+
this.next();
|
|
349
|
+
return this.token("MinusMinus" /* MinusMinus */, "--", start);
|
|
350
|
+
}
|
|
321
351
|
if (ch === "." && next === "." && this.peek(2) === ".") {
|
|
322
352
|
this.next();
|
|
323
353
|
this.next();
|
|
@@ -420,11 +450,20 @@ var BaseNode = class {
|
|
|
420
450
|
async prepare(_context) {
|
|
421
451
|
return;
|
|
422
452
|
}
|
|
423
|
-
|
|
453
|
+
evaluate(_context) {
|
|
424
454
|
return void 0;
|
|
425
455
|
}
|
|
426
456
|
};
|
|
427
|
-
|
|
457
|
+
function isPromiseLike(value) {
|
|
458
|
+
return Boolean(value) && typeof value.then === "function";
|
|
459
|
+
}
|
|
460
|
+
function resolveMaybe(value, next) {
|
|
461
|
+
if (isPromiseLike(value)) {
|
|
462
|
+
return value.then(next);
|
|
463
|
+
}
|
|
464
|
+
return next(value);
|
|
465
|
+
}
|
|
466
|
+
function evaluateWithChildScope(context, block) {
|
|
428
467
|
const scope = context.scope;
|
|
429
468
|
if (!scope || !scope.createChild) {
|
|
430
469
|
return block.evaluate(context);
|
|
@@ -432,7 +471,7 @@ async function evaluateWithChildScope(context, block) {
|
|
|
432
471
|
const previousScope = context.scope;
|
|
433
472
|
context.scope = scope.createChild();
|
|
434
473
|
try {
|
|
435
|
-
return
|
|
474
|
+
return block.evaluate(context);
|
|
436
475
|
} finally {
|
|
437
476
|
context.scope = previousScope;
|
|
438
477
|
}
|
|
@@ -458,15 +497,25 @@ var BlockNode = class extends BaseNode {
|
|
|
458
497
|
super("Block");
|
|
459
498
|
this.statements = statements;
|
|
460
499
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
500
|
+
evaluate(context) {
|
|
501
|
+
let index = 0;
|
|
502
|
+
const run = () => {
|
|
503
|
+
while (index < this.statements.length) {
|
|
504
|
+
if (context.returning || context.breaking || context.continuing) {
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
const statement = this.statements[index];
|
|
508
|
+
index += 1;
|
|
509
|
+
if (statement && typeof statement.evaluate === "function") {
|
|
510
|
+
const result = statement.evaluate(context);
|
|
511
|
+
if (isPromiseLike(result)) {
|
|
512
|
+
return result.then(() => run());
|
|
513
|
+
}
|
|
514
|
+
}
|
|
468
515
|
}
|
|
469
|
-
|
|
516
|
+
return void 0;
|
|
517
|
+
};
|
|
518
|
+
return run();
|
|
470
519
|
}
|
|
471
520
|
};
|
|
472
521
|
var SelectorNode = class extends BaseNode {
|
|
@@ -476,87 +525,205 @@ var SelectorNode = class extends BaseNode {
|
|
|
476
525
|
}
|
|
477
526
|
};
|
|
478
527
|
var BehaviorNode = class extends BaseNode {
|
|
479
|
-
constructor(selector, body) {
|
|
528
|
+
constructor(selector, body, flags = {}, flagArgs = {}) {
|
|
480
529
|
super("Behavior");
|
|
481
530
|
this.selector = selector;
|
|
482
531
|
this.body = body;
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
var StateEntryNode = class extends BaseNode {
|
|
486
|
-
constructor(name, value, important) {
|
|
487
|
-
super("StateEntry");
|
|
488
|
-
this.name = name;
|
|
489
|
-
this.value = value;
|
|
490
|
-
this.important = important;
|
|
491
|
-
}
|
|
492
|
-
};
|
|
493
|
-
var StateBlockNode = class extends BaseNode {
|
|
494
|
-
constructor(entries) {
|
|
495
|
-
super("StateBlock");
|
|
496
|
-
this.entries = entries;
|
|
532
|
+
this.flags = flags;
|
|
533
|
+
this.flagArgs = flagArgs;
|
|
497
534
|
}
|
|
498
535
|
};
|
|
499
536
|
var OnBlockNode = class extends BaseNode {
|
|
500
|
-
constructor(eventName, args, body,
|
|
537
|
+
constructor(eventName, args, body, flags = {}, flagArgs = {}) {
|
|
501
538
|
super("OnBlock");
|
|
502
539
|
this.eventName = eventName;
|
|
503
540
|
this.args = args;
|
|
504
541
|
this.body = body;
|
|
505
|
-
this.
|
|
542
|
+
this.flags = flags;
|
|
543
|
+
this.flagArgs = flagArgs;
|
|
506
544
|
}
|
|
507
545
|
};
|
|
508
546
|
var AssignmentNode = class extends BaseNode {
|
|
509
|
-
constructor(target, value, operator = "=") {
|
|
547
|
+
constructor(target, value, operator = "=", prefix = false) {
|
|
510
548
|
super("Assignment");
|
|
511
549
|
this.target = target;
|
|
512
550
|
this.value = value;
|
|
513
551
|
this.operator = operator;
|
|
552
|
+
this.prefix = prefix;
|
|
514
553
|
}
|
|
515
|
-
|
|
554
|
+
evaluate(context) {
|
|
516
555
|
if (!context.scope || !context.scope.setPath) {
|
|
517
556
|
return void 0;
|
|
518
557
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
558
|
+
if (this.operator === "++" || this.operator === "--") {
|
|
559
|
+
return this.applyIncrement(context);
|
|
560
|
+
}
|
|
561
|
+
const value = this.value.evaluate(context);
|
|
562
|
+
return resolveMaybe(value, (resolvedValue) => {
|
|
563
|
+
if (this.operator !== "=") {
|
|
564
|
+
return this.applyCompoundAssignment(context, resolvedValue);
|
|
565
|
+
}
|
|
566
|
+
if (this.target instanceof IdentifierExpression && this.target.name.startsWith("root.") && context.rootScope) {
|
|
567
|
+
const path = this.target.name.slice("root.".length);
|
|
568
|
+
context.rootScope.setPath?.(`self.${path}`, resolvedValue);
|
|
569
|
+
return resolvedValue;
|
|
570
|
+
}
|
|
571
|
+
if (this.target instanceof MemberExpression || this.target instanceof IndexExpression) {
|
|
572
|
+
const resolved = this.resolveAssignmentTarget(context);
|
|
573
|
+
return resolveMaybe(resolved, (resolvedTarget) => {
|
|
574
|
+
if (resolvedTarget?.scope?.setPath) {
|
|
575
|
+
resolvedTarget.scope.setPath(resolvedTarget.path, resolvedValue);
|
|
576
|
+
return resolvedValue;
|
|
577
|
+
}
|
|
578
|
+
this.assignTarget(context, this.target, resolvedValue);
|
|
579
|
+
return resolvedValue;
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
this.assignTarget(context, this.target, resolvedValue);
|
|
583
|
+
return resolvedValue;
|
|
584
|
+
});
|
|
530
585
|
}
|
|
531
586
|
applyCompoundAssignment(context, value) {
|
|
532
587
|
if (!context.scope || !context.scope.setPath) {
|
|
533
588
|
return void 0;
|
|
534
589
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
590
|
+
const resolved = this.resolveAssignmentTarget(context);
|
|
591
|
+
return resolveMaybe(resolved, (resolvedTarget) => {
|
|
592
|
+
if (!resolvedTarget) {
|
|
593
|
+
throw new Error("Compound assignment requires a simple identifier or member path");
|
|
594
|
+
}
|
|
595
|
+
const { scope, path } = resolvedTarget;
|
|
596
|
+
const current = scope?.getPath ? scope.getPath(path) : void 0;
|
|
597
|
+
let result;
|
|
598
|
+
if (this.operator === "+=") {
|
|
599
|
+
result = current + value;
|
|
600
|
+
} else if (this.operator === "-=") {
|
|
601
|
+
result = current - value;
|
|
602
|
+
} else if (this.operator === "*=") {
|
|
603
|
+
result = current * value;
|
|
604
|
+
} else {
|
|
605
|
+
result = current / value;
|
|
606
|
+
}
|
|
607
|
+
scope?.setPath?.(path, result);
|
|
608
|
+
return result;
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
applyIncrement(context) {
|
|
612
|
+
if (!context.scope || !context.scope.setPath) {
|
|
613
|
+
return void 0;
|
|
552
614
|
}
|
|
553
|
-
|
|
554
|
-
return
|
|
615
|
+
const resolved = this.resolveAssignmentTarget(context);
|
|
616
|
+
return resolveMaybe(resolved, (resolvedTarget) => {
|
|
617
|
+
if (!resolvedTarget) {
|
|
618
|
+
throw new Error("Increment/decrement requires a simple identifier or member path");
|
|
619
|
+
}
|
|
620
|
+
const { scope, path } = resolvedTarget;
|
|
621
|
+
const current = scope?.getPath ? scope.getPath(path) : void 0;
|
|
622
|
+
const numeric = typeof current === "number" ? current : Number(current);
|
|
623
|
+
const delta = this.operator === "++" ? 1 : -1;
|
|
624
|
+
const next = (Number.isNaN(numeric) ? 0 : numeric) + delta;
|
|
625
|
+
scope?.setPath?.(path, next);
|
|
626
|
+
return this.prefix ? next : numeric;
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
resolveAssignmentTarget(context) {
|
|
630
|
+
if (this.target instanceof IdentifierExpression) {
|
|
631
|
+
const isRoot = this.target.name.startsWith("root.");
|
|
632
|
+
const rawPath = isRoot ? this.target.name.slice("root.".length) : this.target.name;
|
|
633
|
+
if (isRoot) {
|
|
634
|
+
if (context.rootScope) {
|
|
635
|
+
return { scope: context.rootScope, path: `self.${rawPath}` };
|
|
636
|
+
}
|
|
637
|
+
return { scope: context.scope, path: `root.${rawPath}` };
|
|
638
|
+
}
|
|
639
|
+
return { scope: context.scope, path: rawPath };
|
|
640
|
+
}
|
|
641
|
+
if (this.target instanceof MemberExpression) {
|
|
642
|
+
const resolvedPath = this.target.getIdentifierPath();
|
|
643
|
+
if (resolvedPath) {
|
|
644
|
+
const path = resolvedPath.path;
|
|
645
|
+
const isRoot = path.startsWith("root.");
|
|
646
|
+
const rawPath = isRoot ? path.slice("root.".length) : path;
|
|
647
|
+
if (isRoot) {
|
|
648
|
+
if (context.rootScope) {
|
|
649
|
+
return { scope: context.rootScope, path: `self.${rawPath}` };
|
|
650
|
+
}
|
|
651
|
+
return { scope: context.scope, path: `root.${rawPath}` };
|
|
652
|
+
}
|
|
653
|
+
return { scope: context.scope, path: rawPath };
|
|
654
|
+
}
|
|
655
|
+
const targetExpr = this.target;
|
|
656
|
+
const basePath = this.resolveTargetPath(context, targetExpr.target);
|
|
657
|
+
return resolveMaybe(basePath, (resolvedBase) => {
|
|
658
|
+
if (!resolvedBase) {
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
const path = `${resolvedBase}.${targetExpr.property}`;
|
|
662
|
+
const isRoot = path.startsWith("root.");
|
|
663
|
+
const rawPath = isRoot ? path.slice("root.".length) : path;
|
|
664
|
+
if (isRoot) {
|
|
665
|
+
if (context.rootScope) {
|
|
666
|
+
return { scope: context.rootScope, path: `self.${rawPath}` };
|
|
667
|
+
}
|
|
668
|
+
return { scope: context.scope, path: `root.${rawPath}` };
|
|
669
|
+
}
|
|
670
|
+
return { scope: context.scope, path: rawPath };
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
if (this.target instanceof IndexExpression) {
|
|
674
|
+
const path = this.resolveIndexPath(context, this.target);
|
|
675
|
+
return resolveMaybe(path, (resolvedPath) => {
|
|
676
|
+
if (!resolvedPath) {
|
|
677
|
+
return null;
|
|
678
|
+
}
|
|
679
|
+
const isRoot = resolvedPath.startsWith("root.");
|
|
680
|
+
const rawPath = isRoot ? resolvedPath.slice("root.".length) : resolvedPath;
|
|
681
|
+
if (isRoot) {
|
|
682
|
+
if (context.rootScope) {
|
|
683
|
+
return { scope: context.rootScope, path: `self.${rawPath}` };
|
|
684
|
+
}
|
|
685
|
+
return { scope: context.scope, path: `root.${rawPath}` };
|
|
686
|
+
}
|
|
687
|
+
return { scope: context.scope, path: rawPath };
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
return null;
|
|
691
|
+
}
|
|
692
|
+
resolveIndexPath(context, expr) {
|
|
693
|
+
const base = this.resolveTargetPath(context, expr.target);
|
|
694
|
+
return resolveMaybe(base, (resolvedBase) => {
|
|
695
|
+
if (!resolvedBase) {
|
|
696
|
+
return null;
|
|
697
|
+
}
|
|
698
|
+
const indexValue = expr.index.evaluate(context);
|
|
699
|
+
return resolveMaybe(indexValue, (resolvedIndex) => {
|
|
700
|
+
if (resolvedIndex == null) {
|
|
701
|
+
return null;
|
|
702
|
+
}
|
|
703
|
+
return `${resolvedBase}.${resolvedIndex}`;
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
resolveTargetPath(context, target) {
|
|
708
|
+
if (target instanceof IdentifierExpression) {
|
|
709
|
+
return target.name;
|
|
710
|
+
}
|
|
711
|
+
if (target instanceof MemberExpression) {
|
|
712
|
+
return target.getIdentifierPath()?.path ?? null;
|
|
713
|
+
}
|
|
714
|
+
if (target instanceof IndexExpression) {
|
|
715
|
+
return this.resolveIndexPath(context, target);
|
|
716
|
+
}
|
|
717
|
+
return null;
|
|
555
718
|
}
|
|
556
719
|
assignTarget(context, target, value) {
|
|
557
720
|
if (!context.scope || !context.scope.setPath) {
|
|
558
721
|
return;
|
|
559
722
|
}
|
|
723
|
+
if (target instanceof DirectiveExpression) {
|
|
724
|
+
this.assignDirectiveTarget(context, target, value);
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
560
727
|
if (target instanceof IdentifierExpression) {
|
|
561
728
|
context.scope.setPath(target.name, value);
|
|
562
729
|
return;
|
|
@@ -598,19 +765,99 @@ var AssignmentNode = class extends BaseNode {
|
|
|
598
765
|
return;
|
|
599
766
|
}
|
|
600
767
|
}
|
|
768
|
+
assignDirectiveTarget(context, target, value) {
|
|
769
|
+
const element = context.element;
|
|
770
|
+
if (!element) {
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
if (target.kind === "attr") {
|
|
774
|
+
if (target.name === "value") {
|
|
775
|
+
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
|
776
|
+
element.value = value == null ? "" : String(value);
|
|
777
|
+
element.setAttribute("value", element.value);
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
if (element instanceof HTMLSelectElement) {
|
|
781
|
+
element.value = value == null ? "" : String(value);
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
if (target.name === "checked" && element instanceof HTMLInputElement) {
|
|
786
|
+
const checked = value === true || value === "true" || value === 1 || value === "1";
|
|
787
|
+
element.checked = checked;
|
|
788
|
+
if (checked) {
|
|
789
|
+
element.setAttribute("checked", "");
|
|
790
|
+
} else {
|
|
791
|
+
element.removeAttribute("checked");
|
|
792
|
+
}
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (target.name === "html" && element instanceof HTMLElement) {
|
|
796
|
+
element.innerHTML = value == null ? "" : String(value);
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
element.setAttribute(target.name, value == null ? "" : String(value));
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
if (target.kind === "style" && element instanceof HTMLElement) {
|
|
803
|
+
element.style.setProperty(target.name, value == null ? "" : String(value));
|
|
804
|
+
}
|
|
805
|
+
}
|
|
601
806
|
};
|
|
602
807
|
var ReturnNode = class extends BaseNode {
|
|
603
808
|
constructor(value) {
|
|
604
809
|
super("Return");
|
|
605
810
|
this.value = value;
|
|
606
811
|
}
|
|
607
|
-
|
|
812
|
+
evaluate(context) {
|
|
608
813
|
if (context.returning) {
|
|
609
814
|
return context.returnValue;
|
|
610
815
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
816
|
+
const nextValue = this.value ? this.value.evaluate(context) : void 0;
|
|
817
|
+
return resolveMaybe(nextValue, (resolved) => {
|
|
818
|
+
context.returnValue = resolved;
|
|
819
|
+
context.returning = true;
|
|
820
|
+
return context.returnValue;
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
var BreakNode = class extends BaseNode {
|
|
825
|
+
constructor() {
|
|
826
|
+
super("Break");
|
|
827
|
+
}
|
|
828
|
+
evaluate(context) {
|
|
829
|
+
context.breaking = true;
|
|
830
|
+
return void 0;
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
var ContinueNode = class extends BaseNode {
|
|
834
|
+
constructor() {
|
|
835
|
+
super("Continue");
|
|
836
|
+
}
|
|
837
|
+
evaluate(context) {
|
|
838
|
+
context.continuing = true;
|
|
839
|
+
return void 0;
|
|
840
|
+
}
|
|
841
|
+
};
|
|
842
|
+
var AssertError = class extends Error {
|
|
843
|
+
constructor(message = "Assertion failed") {
|
|
844
|
+
super(message);
|
|
845
|
+
this.name = "AssertError";
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
var AssertNode = class extends BaseNode {
|
|
849
|
+
constructor(test) {
|
|
850
|
+
super("Assert");
|
|
851
|
+
this.test = test;
|
|
852
|
+
}
|
|
853
|
+
evaluate(context) {
|
|
854
|
+
const value = this.test.evaluate(context);
|
|
855
|
+
return resolveMaybe(value, (resolved) => {
|
|
856
|
+
if (!resolved) {
|
|
857
|
+
throw new AssertError();
|
|
858
|
+
}
|
|
859
|
+
return resolved;
|
|
860
|
+
});
|
|
614
861
|
}
|
|
615
862
|
};
|
|
616
863
|
var IfNode = class extends BaseNode {
|
|
@@ -620,14 +867,17 @@ var IfNode = class extends BaseNode {
|
|
|
620
867
|
this.consequent = consequent;
|
|
621
868
|
this.alternate = alternate;
|
|
622
869
|
}
|
|
623
|
-
|
|
624
|
-
const condition =
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
870
|
+
evaluate(context) {
|
|
871
|
+
const condition = this.test.evaluate(context);
|
|
872
|
+
return resolveMaybe(condition, (resolved) => {
|
|
873
|
+
if (resolved) {
|
|
874
|
+
return evaluateWithChildScope(context, this.consequent);
|
|
875
|
+
}
|
|
876
|
+
if (this.alternate) {
|
|
877
|
+
return evaluateWithChildScope(context, this.alternate);
|
|
878
|
+
}
|
|
879
|
+
return void 0;
|
|
880
|
+
});
|
|
631
881
|
}
|
|
632
882
|
};
|
|
633
883
|
var WhileNode = class extends BaseNode {
|
|
@@ -636,21 +886,104 @@ var WhileNode = class extends BaseNode {
|
|
|
636
886
|
this.test = test;
|
|
637
887
|
this.body = body;
|
|
638
888
|
}
|
|
639
|
-
|
|
889
|
+
evaluate(context) {
|
|
640
890
|
const previousScope = context.scope;
|
|
641
891
|
if (context.scope?.createChild) {
|
|
642
892
|
context.scope = context.scope.createChild();
|
|
643
893
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if (context.returning) {
|
|
648
|
-
|
|
894
|
+
const run = () => {
|
|
895
|
+
const condition = this.test.evaluate(context);
|
|
896
|
+
return resolveMaybe(condition, (resolved) => {
|
|
897
|
+
if (!resolved || context.returning) {
|
|
898
|
+
return void 0;
|
|
649
899
|
}
|
|
900
|
+
const bodyResult = this.body.evaluate(context);
|
|
901
|
+
return resolveMaybe(bodyResult, () => {
|
|
902
|
+
if (context.breaking) {
|
|
903
|
+
context.breaking = false;
|
|
904
|
+
return void 0;
|
|
905
|
+
}
|
|
906
|
+
if (context.continuing) {
|
|
907
|
+
context.continuing = false;
|
|
908
|
+
}
|
|
909
|
+
return run();
|
|
910
|
+
});
|
|
911
|
+
});
|
|
912
|
+
};
|
|
913
|
+
const result = run();
|
|
914
|
+
if (isPromiseLike(result)) {
|
|
915
|
+
return result.finally(() => {
|
|
916
|
+
context.scope = previousScope;
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
context.scope = previousScope;
|
|
920
|
+
return result;
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
var ForEachNode = class extends BaseNode {
|
|
924
|
+
constructor(target, iterable, kind, body) {
|
|
925
|
+
super("ForEach");
|
|
926
|
+
this.target = target;
|
|
927
|
+
this.iterable = iterable;
|
|
928
|
+
this.kind = kind;
|
|
929
|
+
this.body = body;
|
|
930
|
+
}
|
|
931
|
+
evaluate(context) {
|
|
932
|
+
const iterableValue = this.iterable.evaluate(context);
|
|
933
|
+
return resolveMaybe(iterableValue, (resolved) => {
|
|
934
|
+
const entries = this.getEntries(resolved);
|
|
935
|
+
const previousScope = context.scope;
|
|
936
|
+
let bodyScope = context.scope;
|
|
937
|
+
if (context.scope?.createChild) {
|
|
938
|
+
bodyScope = context.scope.createChild();
|
|
650
939
|
}
|
|
651
|
-
|
|
652
|
-
|
|
940
|
+
let index = 0;
|
|
941
|
+
const loop = () => {
|
|
942
|
+
if (index >= entries.length || context.returning) {
|
|
943
|
+
context.scope = previousScope;
|
|
944
|
+
return void 0;
|
|
945
|
+
}
|
|
946
|
+
const value = entries[index];
|
|
947
|
+
index += 1;
|
|
948
|
+
context.scope = bodyScope;
|
|
949
|
+
context.scope?.setPath?.(this.target.name, value);
|
|
950
|
+
const bodyResult = this.body.evaluate(context);
|
|
951
|
+
return resolveMaybe(bodyResult, () => {
|
|
952
|
+
if (context.breaking) {
|
|
953
|
+
context.breaking = false;
|
|
954
|
+
context.scope = previousScope;
|
|
955
|
+
return void 0;
|
|
956
|
+
}
|
|
957
|
+
if (context.continuing) {
|
|
958
|
+
context.continuing = false;
|
|
959
|
+
}
|
|
960
|
+
context.scope = previousScope;
|
|
961
|
+
return loop();
|
|
962
|
+
});
|
|
963
|
+
};
|
|
964
|
+
return loop();
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
getEntries(value) {
|
|
968
|
+
if (value == null) {
|
|
969
|
+
return [];
|
|
970
|
+
}
|
|
971
|
+
if (this.kind === "in") {
|
|
972
|
+
if (typeof value === "object") {
|
|
973
|
+
return Object.keys(value);
|
|
974
|
+
}
|
|
975
|
+
return [];
|
|
976
|
+
}
|
|
977
|
+
if (typeof value === "string") {
|
|
978
|
+
return Array.from(value);
|
|
979
|
+
}
|
|
980
|
+
if (typeof value[Symbol.iterator] === "function") {
|
|
981
|
+
return Array.from(value);
|
|
982
|
+
}
|
|
983
|
+
if (typeof value === "object") {
|
|
984
|
+
return Object.values(value);
|
|
653
985
|
}
|
|
986
|
+
return [];
|
|
654
987
|
}
|
|
655
988
|
};
|
|
656
989
|
var ForNode = class extends BaseNode {
|
|
@@ -661,27 +994,45 @@ var ForNode = class extends BaseNode {
|
|
|
661
994
|
this.update = update;
|
|
662
995
|
this.body = body;
|
|
663
996
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
997
|
+
evaluate(context) {
|
|
998
|
+
const initResult = this.init ? this.init.evaluate(context) : void 0;
|
|
999
|
+
const run = () => {
|
|
1000
|
+
const previousScope = context.scope;
|
|
1001
|
+
let bodyScope = context.scope;
|
|
1002
|
+
if (context.scope?.createChild) {
|
|
1003
|
+
bodyScope = context.scope.createChild();
|
|
1004
|
+
}
|
|
1005
|
+
const loop = () => {
|
|
1006
|
+
const testResult = this.test ? this.test.evaluate(context) : true;
|
|
1007
|
+
return resolveMaybe(testResult, (passed) => {
|
|
1008
|
+
if (!passed || context.returning) {
|
|
1009
|
+
context.scope = previousScope;
|
|
1010
|
+
return void 0;
|
|
1011
|
+
}
|
|
1012
|
+
context.scope = bodyScope;
|
|
1013
|
+
const bodyResult = this.body.evaluate(context);
|
|
1014
|
+
return resolveMaybe(bodyResult, () => {
|
|
1015
|
+
if (context.returning) {
|
|
1016
|
+
context.scope = previousScope;
|
|
1017
|
+
return void 0;
|
|
1018
|
+
}
|
|
1019
|
+
if (context.breaking) {
|
|
1020
|
+
context.breaking = false;
|
|
1021
|
+
context.scope = previousScope;
|
|
1022
|
+
return void 0;
|
|
1023
|
+
}
|
|
1024
|
+
context.scope = previousScope;
|
|
1025
|
+
if (context.continuing) {
|
|
1026
|
+
context.continuing = false;
|
|
1027
|
+
}
|
|
1028
|
+
const updateResult = this.update ? this.update.evaluate(context) : void 0;
|
|
1029
|
+
return resolveMaybe(updateResult, () => loop());
|
|
1030
|
+
});
|
|
1031
|
+
});
|
|
1032
|
+
};
|
|
1033
|
+
return loop();
|
|
1034
|
+
};
|
|
1035
|
+
return resolveMaybe(initResult, () => run());
|
|
685
1036
|
}
|
|
686
1037
|
};
|
|
687
1038
|
var TryNode = class extends BaseNode {
|
|
@@ -691,10 +1042,8 @@ var TryNode = class extends BaseNode {
|
|
|
691
1042
|
this.errorName = errorName;
|
|
692
1043
|
this.handler = handler;
|
|
693
1044
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
return await evaluateWithChildScope(context, this.body);
|
|
697
|
-
} catch (error) {
|
|
1045
|
+
evaluate(context) {
|
|
1046
|
+
const handleError = (error) => {
|
|
698
1047
|
if (context.returning) {
|
|
699
1048
|
return context.returnValue;
|
|
700
1049
|
}
|
|
@@ -712,11 +1061,23 @@ var TryNode = class extends BaseNode {
|
|
|
712
1061
|
scope.setPath(`self.${this.errorName}`, error);
|
|
713
1062
|
}
|
|
714
1063
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
scope.setPath
|
|
1064
|
+
const handlerResult = this.handler.evaluate(context);
|
|
1065
|
+
return resolveMaybe(handlerResult, () => {
|
|
1066
|
+
if (scope && scope.setPath && handlerScope === previousScope) {
|
|
1067
|
+
scope.setPath(this.errorName, previous);
|
|
1068
|
+
}
|
|
1069
|
+
context.scope = previousScope;
|
|
1070
|
+
return void 0;
|
|
1071
|
+
});
|
|
1072
|
+
};
|
|
1073
|
+
try {
|
|
1074
|
+
const bodyResult = evaluateWithChildScope(context, this.body);
|
|
1075
|
+
if (isPromiseLike(bodyResult)) {
|
|
1076
|
+
return bodyResult.catch((error) => handleError(error));
|
|
718
1077
|
}
|
|
719
|
-
|
|
1078
|
+
return bodyResult;
|
|
1079
|
+
} catch (error) {
|
|
1080
|
+
return handleError(error);
|
|
720
1081
|
}
|
|
721
1082
|
}
|
|
722
1083
|
};
|
|
@@ -736,11 +1097,35 @@ var FunctionExpression = class extends BaseNode {
|
|
|
736
1097
|
this.body = body;
|
|
737
1098
|
this.isAsync = isAsync;
|
|
738
1099
|
}
|
|
739
|
-
|
|
1100
|
+
evaluate(context) {
|
|
740
1101
|
const scope = context.scope;
|
|
741
1102
|
const globals = context.globals;
|
|
742
1103
|
const element = context.element;
|
|
743
|
-
|
|
1104
|
+
if (this.isAsync) {
|
|
1105
|
+
return (...args) => {
|
|
1106
|
+
const activeScope = scope?.createChild ? scope.createChild() : scope;
|
|
1107
|
+
const inner = {
|
|
1108
|
+
scope: activeScope,
|
|
1109
|
+
rootScope: context.rootScope,
|
|
1110
|
+
...globals ? { globals } : {},
|
|
1111
|
+
...element ? { element } : {},
|
|
1112
|
+
returnValue: void 0,
|
|
1113
|
+
returning: false,
|
|
1114
|
+
breaking: false,
|
|
1115
|
+
continuing: false
|
|
1116
|
+
};
|
|
1117
|
+
const previousValues = /* @__PURE__ */ new Map();
|
|
1118
|
+
const applyResult = activeScope ? this.applyParams(activeScope, previousValues, inner, args) : void 0;
|
|
1119
|
+
const bodyResult = resolveMaybe(applyResult, () => this.body.evaluate(inner));
|
|
1120
|
+
const finalResult = resolveMaybe(bodyResult, () => inner.returnValue);
|
|
1121
|
+
return Promise.resolve(finalResult).finally(() => {
|
|
1122
|
+
if (activeScope && activeScope === scope) {
|
|
1123
|
+
this.restoreParams(activeScope, previousValues);
|
|
1124
|
+
}
|
|
1125
|
+
});
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
return (...args) => {
|
|
744
1129
|
const activeScope = scope?.createChild ? scope.createChild() : scope;
|
|
745
1130
|
const inner = {
|
|
746
1131
|
scope: activeScope,
|
|
@@ -748,47 +1133,69 @@ var FunctionExpression = class extends BaseNode {
|
|
|
748
1133
|
...globals ? { globals } : {},
|
|
749
1134
|
...element ? { element } : {},
|
|
750
1135
|
returnValue: void 0,
|
|
751
|
-
returning: false
|
|
1136
|
+
returning: false,
|
|
1137
|
+
breaking: false,
|
|
1138
|
+
continuing: false
|
|
752
1139
|
};
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
1140
|
+
const previousValues = /* @__PURE__ */ new Map();
|
|
1141
|
+
const applyResult = activeScope ? this.applyParams(activeScope, previousValues, inner, args) : void 0;
|
|
1142
|
+
const bodyResult = resolveMaybe(applyResult, () => this.body.evaluate(inner));
|
|
1143
|
+
const finalResult = resolveMaybe(bodyResult, () => inner.returnValue);
|
|
1144
|
+
if (isPromiseLike(finalResult)) {
|
|
1145
|
+
return finalResult.finally(() => {
|
|
1146
|
+
if (activeScope && activeScope === scope) {
|
|
1147
|
+
this.restoreParams(activeScope, previousValues);
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
if (activeScope && activeScope === scope) {
|
|
1152
|
+
this.restoreParams(activeScope, previousValues);
|
|
762
1153
|
}
|
|
763
|
-
return
|
|
1154
|
+
return finalResult;
|
|
764
1155
|
};
|
|
765
1156
|
}
|
|
766
|
-
|
|
767
|
-
if (!scope
|
|
1157
|
+
applyParams(scope, previousValues, context, args) {
|
|
1158
|
+
if (!scope) {
|
|
768
1159
|
return;
|
|
769
1160
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
if (!name) {
|
|
774
|
-
continue;
|
|
775
|
-
}
|
|
776
|
-
previousValues.set(name, scope.getPath(name));
|
|
777
|
-
if (param.rest) {
|
|
778
|
-
scope.setPath(`self.${name}`, args.slice(argIndex));
|
|
779
|
-
argIndex = args.length;
|
|
780
|
-
continue;
|
|
781
|
-
}
|
|
782
|
-
let value = args[argIndex];
|
|
783
|
-
if (value === void 0 && param.defaultValue) {
|
|
784
|
-
value = await param.defaultValue.evaluate(context);
|
|
785
|
-
}
|
|
786
|
-
scope.setPath(`self.${name}`, value);
|
|
787
|
-
argIndex += 1;
|
|
1161
|
+
const setPath = scope.setPath?.bind(scope);
|
|
1162
|
+
if (!setPath) {
|
|
1163
|
+
return;
|
|
788
1164
|
}
|
|
1165
|
+
const params = this.params;
|
|
1166
|
+
const applyAt = (paramIndex, argIndex) => {
|
|
1167
|
+
for (let i = paramIndex; i < params.length; i += 1) {
|
|
1168
|
+
const param = params[i];
|
|
1169
|
+
const name = param.name;
|
|
1170
|
+
if (!name) {
|
|
1171
|
+
continue;
|
|
1172
|
+
}
|
|
1173
|
+
previousValues.set(name, scope.getPath(name));
|
|
1174
|
+
if (param.rest) {
|
|
1175
|
+
setPath(`self.${name}`, args.slice(argIndex));
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
let value = args[argIndex];
|
|
1179
|
+
if (value === void 0 && param.defaultValue) {
|
|
1180
|
+
const defaultValue = param.defaultValue.evaluate(context);
|
|
1181
|
+
return resolveMaybe(defaultValue, (resolvedDefault) => {
|
|
1182
|
+
setPath(`self.${name}`, resolvedDefault);
|
|
1183
|
+
return applyAt(i + 1, argIndex + 1);
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
setPath(`self.${name}`, value);
|
|
1187
|
+
argIndex += 1;
|
|
1188
|
+
}
|
|
1189
|
+
return;
|
|
1190
|
+
};
|
|
1191
|
+
return applyAt(0, 0);
|
|
789
1192
|
}
|
|
790
1193
|
restoreParams(scope, previousValues) {
|
|
791
|
-
if (!scope
|
|
1194
|
+
if (!scope) {
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
const setPath = scope.setPath?.bind(scope);
|
|
1198
|
+
if (!setPath) {
|
|
792
1199
|
return;
|
|
793
1200
|
}
|
|
794
1201
|
for (const param of this.params) {
|
|
@@ -796,7 +1203,7 @@ var FunctionExpression = class extends BaseNode {
|
|
|
796
1203
|
if (!name) {
|
|
797
1204
|
continue;
|
|
798
1205
|
}
|
|
799
|
-
|
|
1206
|
+
setPath(name, previousValues.get(name));
|
|
800
1207
|
}
|
|
801
1208
|
}
|
|
802
1209
|
};
|
|
@@ -815,7 +1222,7 @@ var IdentifierExpression = class extends BaseNode {
|
|
|
815
1222
|
super("Identifier");
|
|
816
1223
|
this.name = name;
|
|
817
1224
|
}
|
|
818
|
-
|
|
1225
|
+
evaluate(context) {
|
|
819
1226
|
if (this.name.startsWith("root.") && context.rootScope) {
|
|
820
1227
|
const path = this.name.slice("root.".length);
|
|
821
1228
|
return context.rootScope.getPath(`self.${path}`);
|
|
@@ -860,7 +1267,7 @@ var LiteralExpression = class extends BaseNode {
|
|
|
860
1267
|
super("Literal");
|
|
861
1268
|
this.value = value;
|
|
862
1269
|
}
|
|
863
|
-
|
|
1270
|
+
evaluate() {
|
|
864
1271
|
return this.value;
|
|
865
1272
|
}
|
|
866
1273
|
};
|
|
@@ -869,13 +1276,22 @@ var TemplateExpression = class extends BaseNode {
|
|
|
869
1276
|
super("TemplateExpression");
|
|
870
1277
|
this.parts = parts;
|
|
871
1278
|
}
|
|
872
|
-
|
|
1279
|
+
evaluate(context) {
|
|
873
1280
|
let result = "";
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1281
|
+
let index = 0;
|
|
1282
|
+
const run = () => {
|
|
1283
|
+
while (index < this.parts.length) {
|
|
1284
|
+
const part = this.parts[index];
|
|
1285
|
+
index += 1;
|
|
1286
|
+
const value = part.evaluate(context);
|
|
1287
|
+
return resolveMaybe(value, (resolved) => {
|
|
1288
|
+
result += resolved == null ? "" : String(resolved);
|
|
1289
|
+
return run();
|
|
1290
|
+
});
|
|
1291
|
+
}
|
|
1292
|
+
return result;
|
|
1293
|
+
};
|
|
1294
|
+
return run();
|
|
879
1295
|
}
|
|
880
1296
|
};
|
|
881
1297
|
var UnaryExpression = class extends BaseNode {
|
|
@@ -884,15 +1300,17 @@ var UnaryExpression = class extends BaseNode {
|
|
|
884
1300
|
this.operator = operator;
|
|
885
1301
|
this.argument = argument;
|
|
886
1302
|
}
|
|
887
|
-
|
|
888
|
-
const value =
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
1303
|
+
evaluate(context) {
|
|
1304
|
+
const value = this.argument.evaluate(context);
|
|
1305
|
+
return resolveMaybe(value, (resolved) => {
|
|
1306
|
+
if (this.operator === "!") {
|
|
1307
|
+
return !resolved;
|
|
1308
|
+
}
|
|
1309
|
+
if (this.operator === "-") {
|
|
1310
|
+
return -resolved;
|
|
1311
|
+
}
|
|
1312
|
+
return resolved;
|
|
1313
|
+
});
|
|
896
1314
|
}
|
|
897
1315
|
};
|
|
898
1316
|
var BinaryExpression = class extends BaseNode {
|
|
@@ -902,61 +1320,71 @@ var BinaryExpression = class extends BaseNode {
|
|
|
902
1320
|
this.left = left;
|
|
903
1321
|
this.right = right;
|
|
904
1322
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
return
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1323
|
+
evaluate(context) {
|
|
1324
|
+
const leftValue = this.left.evaluate(context);
|
|
1325
|
+
return resolveMaybe(leftValue, (resolvedLeft) => {
|
|
1326
|
+
if (this.operator === "&&") {
|
|
1327
|
+
if (!resolvedLeft) {
|
|
1328
|
+
return resolvedLeft;
|
|
1329
|
+
}
|
|
1330
|
+
return this.right.evaluate(context);
|
|
1331
|
+
}
|
|
1332
|
+
if (this.operator === "||") {
|
|
1333
|
+
if (resolvedLeft) {
|
|
1334
|
+
return resolvedLeft;
|
|
1335
|
+
}
|
|
1336
|
+
return this.right.evaluate(context);
|
|
1337
|
+
}
|
|
1338
|
+
if (this.operator === "??") {
|
|
1339
|
+
if (resolvedLeft !== null && resolvedLeft !== void 0) {
|
|
1340
|
+
return resolvedLeft;
|
|
1341
|
+
}
|
|
1342
|
+
return this.right.evaluate(context);
|
|
1343
|
+
}
|
|
1344
|
+
const rightValue = this.right.evaluate(context);
|
|
1345
|
+
return resolveMaybe(rightValue, (resolvedRight) => {
|
|
1346
|
+
if (this.operator === "+") {
|
|
1347
|
+
return resolvedLeft + resolvedRight;
|
|
1348
|
+
}
|
|
1349
|
+
if (this.operator === "-") {
|
|
1350
|
+
return resolvedLeft - resolvedRight;
|
|
1351
|
+
}
|
|
1352
|
+
if (this.operator === "*") {
|
|
1353
|
+
return resolvedLeft * resolvedRight;
|
|
1354
|
+
}
|
|
1355
|
+
if (this.operator === "/") {
|
|
1356
|
+
return resolvedLeft / resolvedRight;
|
|
1357
|
+
}
|
|
1358
|
+
if (this.operator === "%") {
|
|
1359
|
+
return resolvedLeft % resolvedRight;
|
|
1360
|
+
}
|
|
1361
|
+
if (this.operator === "==") {
|
|
1362
|
+
return resolvedLeft == resolvedRight;
|
|
1363
|
+
}
|
|
1364
|
+
if (this.operator === "!=") {
|
|
1365
|
+
return resolvedLeft != resolvedRight;
|
|
1366
|
+
}
|
|
1367
|
+
if (this.operator === "===") {
|
|
1368
|
+
return resolvedLeft === resolvedRight;
|
|
1369
|
+
}
|
|
1370
|
+
if (this.operator === "!==") {
|
|
1371
|
+
return resolvedLeft !== resolvedRight;
|
|
1372
|
+
}
|
|
1373
|
+
if (this.operator === "<") {
|
|
1374
|
+
return resolvedLeft < resolvedRight;
|
|
1375
|
+
}
|
|
1376
|
+
if (this.operator === ">") {
|
|
1377
|
+
return resolvedLeft > resolvedRight;
|
|
1378
|
+
}
|
|
1379
|
+
if (this.operator === "<=") {
|
|
1380
|
+
return resolvedLeft <= resolvedRight;
|
|
1381
|
+
}
|
|
1382
|
+
if (this.operator === ">=") {
|
|
1383
|
+
return resolvedLeft >= resolvedRight;
|
|
1384
|
+
}
|
|
1385
|
+
return void 0;
|
|
1386
|
+
});
|
|
1387
|
+
});
|
|
960
1388
|
}
|
|
961
1389
|
};
|
|
962
1390
|
var TernaryExpression = class extends BaseNode {
|
|
@@ -966,12 +1394,14 @@ var TernaryExpression = class extends BaseNode {
|
|
|
966
1394
|
this.consequent = consequent;
|
|
967
1395
|
this.alternate = alternate;
|
|
968
1396
|
}
|
|
969
|
-
|
|
970
|
-
const condition =
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1397
|
+
evaluate(context) {
|
|
1398
|
+
const condition = this.test.evaluate(context);
|
|
1399
|
+
return resolveMaybe(condition, (resolved) => {
|
|
1400
|
+
if (resolved) {
|
|
1401
|
+
return this.consequent.evaluate(context);
|
|
1402
|
+
}
|
|
1403
|
+
return this.alternate.evaluate(context);
|
|
1404
|
+
});
|
|
975
1405
|
}
|
|
976
1406
|
};
|
|
977
1407
|
var MemberExpression = class _MemberExpression extends BaseNode {
|
|
@@ -981,11 +1411,11 @@ var MemberExpression = class _MemberExpression extends BaseNode {
|
|
|
981
1411
|
this.property = property;
|
|
982
1412
|
this.optional = optional;
|
|
983
1413
|
}
|
|
984
|
-
|
|
985
|
-
const resolved =
|
|
986
|
-
return resolved?.value;
|
|
1414
|
+
evaluate(context) {
|
|
1415
|
+
const resolved = this.resolve(context);
|
|
1416
|
+
return resolveMaybe(resolved, (resolvedValue) => resolvedValue?.value);
|
|
987
1417
|
}
|
|
988
|
-
|
|
1418
|
+
resolve(context) {
|
|
989
1419
|
const path = this.getIdentifierPath();
|
|
990
1420
|
if (path) {
|
|
991
1421
|
const resolved = this.resolveFromScope(context, path);
|
|
@@ -997,11 +1427,13 @@ var MemberExpression = class _MemberExpression extends BaseNode {
|
|
|
997
1427
|
return resolvedGlobal;
|
|
998
1428
|
}
|
|
999
1429
|
}
|
|
1000
|
-
const target =
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1430
|
+
const target = this.target.evaluate(context);
|
|
1431
|
+
return resolveMaybe(target, (resolvedTarget) => {
|
|
1432
|
+
if (resolvedTarget == null) {
|
|
1433
|
+
return { value: void 0, target: resolvedTarget, optional: this.optional };
|
|
1434
|
+
}
|
|
1435
|
+
return { value: resolvedTarget[this.property], target: resolvedTarget, optional: this.optional };
|
|
1436
|
+
});
|
|
1005
1437
|
}
|
|
1006
1438
|
getIdentifierPath() {
|
|
1007
1439
|
const targetPath = this.getTargetIdentifierPath();
|
|
@@ -1077,25 +1509,39 @@ var CallExpression = class extends BaseNode {
|
|
|
1077
1509
|
this.callee = callee;
|
|
1078
1510
|
this.args = args;
|
|
1079
1511
|
}
|
|
1080
|
-
|
|
1081
|
-
const resolved =
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
return
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1512
|
+
evaluate(context) {
|
|
1513
|
+
const resolved = this.resolveCallee(context);
|
|
1514
|
+
return resolveMaybe(resolved, (resolvedCallee) => {
|
|
1515
|
+
const fnValue = resolvedCallee?.fn ?? this.callee.evaluate(context);
|
|
1516
|
+
return resolveMaybe(fnValue, (resolvedFn) => {
|
|
1517
|
+
if (typeof resolvedFn !== "function") {
|
|
1518
|
+
return void 0;
|
|
1519
|
+
}
|
|
1520
|
+
const values = [];
|
|
1521
|
+
const evalArgs = (index) => {
|
|
1522
|
+
for (let i = index; i < this.args.length; i += 1) {
|
|
1523
|
+
const arg = this.args[i];
|
|
1524
|
+
const argValue = arg.evaluate(context);
|
|
1525
|
+
return resolveMaybe(argValue, (resolvedArg) => {
|
|
1526
|
+
values.push(resolvedArg);
|
|
1527
|
+
return evalArgs(i + 1);
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
return resolvedFn.apply(resolvedCallee?.thisArg, values);
|
|
1531
|
+
};
|
|
1532
|
+
return evalArgs(0);
|
|
1533
|
+
});
|
|
1534
|
+
});
|
|
1091
1535
|
}
|
|
1092
|
-
|
|
1536
|
+
resolveCallee(context) {
|
|
1093
1537
|
if (this.callee instanceof MemberExpression) {
|
|
1094
|
-
const resolved =
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1538
|
+
const resolved = this.callee.resolve(context);
|
|
1539
|
+
return resolveMaybe(resolved, (resolvedValue) => {
|
|
1540
|
+
if (!resolvedValue) {
|
|
1541
|
+
return void 0;
|
|
1542
|
+
}
|
|
1543
|
+
return { fn: resolvedValue.value, thisArg: resolvedValue.target };
|
|
1544
|
+
});
|
|
1099
1545
|
}
|
|
1100
1546
|
if (!(this.callee instanceof IdentifierExpression)) {
|
|
1101
1547
|
return void 0;
|
|
@@ -1137,27 +1583,40 @@ var ArrayExpression = class extends BaseNode {
|
|
|
1137
1583
|
super("ArrayExpression");
|
|
1138
1584
|
this.elements = elements;
|
|
1139
1585
|
}
|
|
1140
|
-
|
|
1586
|
+
evaluate(context) {
|
|
1141
1587
|
const values = [];
|
|
1142
|
-
|
|
1143
|
-
if (
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1588
|
+
const pushElements = (value) => {
|
|
1589
|
+
if (value == null) {
|
|
1590
|
+
return;
|
|
1591
|
+
}
|
|
1592
|
+
const iterator = value[Symbol.iterator];
|
|
1593
|
+
if (typeof iterator === "function") {
|
|
1594
|
+
for (const entry of value) {
|
|
1595
|
+
values.push(entry);
|
|
1147
1596
|
}
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1597
|
+
} else {
|
|
1598
|
+
values.push(value);
|
|
1599
|
+
}
|
|
1600
|
+
};
|
|
1601
|
+
const evalAt = (index) => {
|
|
1602
|
+
for (let i = index; i < this.elements.length; i += 1) {
|
|
1603
|
+
const element = this.elements[i];
|
|
1604
|
+
if (element instanceof SpreadElement) {
|
|
1605
|
+
const spreadValue = element.value.evaluate(context);
|
|
1606
|
+
return resolveMaybe(spreadValue, (resolvedSpread) => {
|
|
1607
|
+
pushElements(resolvedSpread);
|
|
1608
|
+
return evalAt(i + 1);
|
|
1609
|
+
});
|
|
1155
1610
|
}
|
|
1156
|
-
|
|
1611
|
+
const value = element.evaluate(context);
|
|
1612
|
+
return resolveMaybe(value, (resolvedValue) => {
|
|
1613
|
+
values.push(resolvedValue);
|
|
1614
|
+
return evalAt(i + 1);
|
|
1615
|
+
});
|
|
1157
1616
|
}
|
|
1158
|
-
values
|
|
1159
|
-
}
|
|
1160
|
-
return
|
|
1617
|
+
return values;
|
|
1618
|
+
};
|
|
1619
|
+
return evalAt(0);
|
|
1161
1620
|
}
|
|
1162
1621
|
};
|
|
1163
1622
|
var ObjectExpression = class extends BaseNode {
|
|
@@ -1165,24 +1624,39 @@ var ObjectExpression = class extends BaseNode {
|
|
|
1165
1624
|
super("ObjectExpression");
|
|
1166
1625
|
this.entries = entries;
|
|
1167
1626
|
}
|
|
1168
|
-
|
|
1627
|
+
evaluate(context) {
|
|
1169
1628
|
const result = {};
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
const
|
|
1173
|
-
if (
|
|
1174
|
-
|
|
1629
|
+
const evalAt = (index) => {
|
|
1630
|
+
for (let i = index; i < this.entries.length; i += 1) {
|
|
1631
|
+
const entry = this.entries[i];
|
|
1632
|
+
if ("spread" in entry) {
|
|
1633
|
+
const spreadValue = entry.spread.evaluate(context);
|
|
1634
|
+
return resolveMaybe(spreadValue, (resolvedSpread) => {
|
|
1635
|
+
if (resolvedSpread != null) {
|
|
1636
|
+
Object.assign(result, resolvedSpread);
|
|
1637
|
+
}
|
|
1638
|
+
return evalAt(i + 1);
|
|
1639
|
+
});
|
|
1175
1640
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1641
|
+
if ("computed" in entry && entry.computed) {
|
|
1642
|
+
const keyValue = entry.keyExpr.evaluate(context);
|
|
1643
|
+
return resolveMaybe(keyValue, (resolvedKey) => {
|
|
1644
|
+
const entryValue = entry.value.evaluate(context);
|
|
1645
|
+
return resolveMaybe(entryValue, (resolvedValue) => {
|
|
1646
|
+
result[String(resolvedKey)] = resolvedValue;
|
|
1647
|
+
return evalAt(i + 1);
|
|
1648
|
+
});
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
const value = entry.value.evaluate(context);
|
|
1652
|
+
return resolveMaybe(value, (resolvedValue) => {
|
|
1653
|
+
result[entry.key] = resolvedValue;
|
|
1654
|
+
return evalAt(i + 1);
|
|
1655
|
+
});
|
|
1183
1656
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1657
|
+
return result;
|
|
1658
|
+
};
|
|
1659
|
+
return evalAt(0);
|
|
1186
1660
|
}
|
|
1187
1661
|
};
|
|
1188
1662
|
var IndexExpression = class extends BaseNode {
|
|
@@ -1191,16 +1665,30 @@ var IndexExpression = class extends BaseNode {
|
|
|
1191
1665
|
this.target = target;
|
|
1192
1666
|
this.index = index;
|
|
1193
1667
|
}
|
|
1194
|
-
|
|
1195
|
-
const target =
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
return
|
|
1668
|
+
evaluate(context) {
|
|
1669
|
+
const target = this.target.evaluate(context);
|
|
1670
|
+
return resolveMaybe(target, (resolvedTarget) => {
|
|
1671
|
+
if (resolvedTarget == null) {
|
|
1672
|
+
return void 0;
|
|
1673
|
+
}
|
|
1674
|
+
const index = this.index.evaluate(context);
|
|
1675
|
+
return resolveMaybe(index, (resolvedIndex) => {
|
|
1676
|
+
if (resolvedIndex == null) {
|
|
1677
|
+
return void 0;
|
|
1678
|
+
}
|
|
1679
|
+
const key = this.normalizeIndexKey(resolvedTarget, resolvedIndex);
|
|
1680
|
+
return resolvedTarget[key];
|
|
1681
|
+
});
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
normalizeIndexKey(target, index) {
|
|
1685
|
+
if (Array.isArray(target) && typeof index === "string" && index.trim() !== "") {
|
|
1686
|
+
const numeric = Number(index);
|
|
1687
|
+
if (!Number.isNaN(numeric)) {
|
|
1688
|
+
return numeric;
|
|
1689
|
+
}
|
|
1202
1690
|
}
|
|
1203
|
-
return
|
|
1691
|
+
return index;
|
|
1204
1692
|
}
|
|
1205
1693
|
};
|
|
1206
1694
|
var DirectiveExpression = class extends BaseNode {
|
|
@@ -1209,7 +1697,7 @@ var DirectiveExpression = class extends BaseNode {
|
|
|
1209
1697
|
this.kind = kind;
|
|
1210
1698
|
this.name = name;
|
|
1211
1699
|
}
|
|
1212
|
-
|
|
1700
|
+
evaluate(context) {
|
|
1213
1701
|
const element = context.element;
|
|
1214
1702
|
if (!element) {
|
|
1215
1703
|
return `${this.kind}:${this.name}`;
|
|
@@ -1223,6 +1711,12 @@ var DirectiveExpression = class extends BaseNode {
|
|
|
1223
1711
|
return element.value;
|
|
1224
1712
|
}
|
|
1225
1713
|
}
|
|
1714
|
+
if (this.name === "text" && element instanceof HTMLElement) {
|
|
1715
|
+
return element.innerText;
|
|
1716
|
+
}
|
|
1717
|
+
if (this.name === "content" && element instanceof HTMLElement) {
|
|
1718
|
+
return element.textContent ?? "";
|
|
1719
|
+
}
|
|
1226
1720
|
if (this.name === "checked" && element instanceof HTMLInputElement) {
|
|
1227
1721
|
return element.checked;
|
|
1228
1722
|
}
|
|
@@ -1242,9 +1736,9 @@ var AwaitExpression = class extends BaseNode {
|
|
|
1242
1736
|
super("AwaitExpression");
|
|
1243
1737
|
this.argument = argument;
|
|
1244
1738
|
}
|
|
1245
|
-
|
|
1246
|
-
const value =
|
|
1247
|
-
return
|
|
1739
|
+
evaluate(context) {
|
|
1740
|
+
const value = this.argument.evaluate(context);
|
|
1741
|
+
return Promise.resolve(value);
|
|
1248
1742
|
}
|
|
1249
1743
|
};
|
|
1250
1744
|
var QueryExpression = class extends BaseNode {
|
|
@@ -1253,7 +1747,7 @@ var QueryExpression = class extends BaseNode {
|
|
|
1253
1747
|
this.direction = direction;
|
|
1254
1748
|
this.selector = selector;
|
|
1255
1749
|
}
|
|
1256
|
-
|
|
1750
|
+
evaluate(context) {
|
|
1257
1751
|
const selector = this.selector.trim();
|
|
1258
1752
|
if (!selector) {
|
|
1259
1753
|
return [];
|
|
@@ -1319,6 +1813,9 @@ var TokenStream = class {
|
|
|
1319
1813
|
let count = 0;
|
|
1320
1814
|
for (let i = this.index; i < this.tokens.length; i++) {
|
|
1321
1815
|
const token = this.tokens[i];
|
|
1816
|
+
if (!token) {
|
|
1817
|
+
continue;
|
|
1818
|
+
}
|
|
1322
1819
|
if (token.type === "Whitespace" /* Whitespace */) {
|
|
1323
1820
|
continue;
|
|
1324
1821
|
}
|
|
@@ -1329,6 +1826,29 @@ var TokenStream = class {
|
|
|
1329
1826
|
}
|
|
1330
1827
|
return null;
|
|
1331
1828
|
}
|
|
1829
|
+
indexAfterDelimited(openType, closeType, offset = 0) {
|
|
1830
|
+
const first = this.peekNonWhitespace(offset);
|
|
1831
|
+
if (!first || first.type !== openType) {
|
|
1832
|
+
return null;
|
|
1833
|
+
}
|
|
1834
|
+
let index = offset + 1;
|
|
1835
|
+
let depth = 1;
|
|
1836
|
+
while (true) {
|
|
1837
|
+
const token = this.peekNonWhitespace(index);
|
|
1838
|
+
if (!token) {
|
|
1839
|
+
return null;
|
|
1840
|
+
}
|
|
1841
|
+
if (token.type === openType) {
|
|
1842
|
+
depth += 1;
|
|
1843
|
+
} else if (token.type === closeType) {
|
|
1844
|
+
depth -= 1;
|
|
1845
|
+
if (depth === 0) {
|
|
1846
|
+
return index + 1;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
index += 1;
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1332
1852
|
};
|
|
1333
1853
|
|
|
1334
1854
|
// src/parser/parser.ts
|
|
@@ -1336,11 +1856,14 @@ var Parser = class _Parser {
|
|
|
1336
1856
|
stream;
|
|
1337
1857
|
source;
|
|
1338
1858
|
customFlags;
|
|
1859
|
+
behaviorFlags;
|
|
1339
1860
|
allowImplicitSemicolon = false;
|
|
1340
1861
|
awaitStack = [];
|
|
1862
|
+
functionDepth = 0;
|
|
1341
1863
|
constructor(input, options) {
|
|
1342
1864
|
this.source = input;
|
|
1343
|
-
this.customFlags = options?.customFlags ?? /* @__PURE__ */ new Set();
|
|
1865
|
+
this.customFlags = options?.customFlags ?? /* @__PURE__ */ new Set(["important", "trusted", "debounce"]);
|
|
1866
|
+
this.behaviorFlags = options?.behaviorFlags ?? /* @__PURE__ */ new Set();
|
|
1344
1867
|
const lexer = new Lexer(input);
|
|
1345
1868
|
this.stream = new TokenStream(lexer.tokenize());
|
|
1346
1869
|
}
|
|
@@ -1380,8 +1903,9 @@ var Parser = class _Parser {
|
|
|
1380
1903
|
this.stream.skipWhitespace();
|
|
1381
1904
|
this.stream.expect("Behavior" /* Behavior */);
|
|
1382
1905
|
const selector = this.parseSelector();
|
|
1906
|
+
const { flags, flagArgs } = this.parseBehaviorFlags();
|
|
1383
1907
|
const body = this.parseBlock({ allowDeclarations: true });
|
|
1384
|
-
return new BehaviorNode(selector, body);
|
|
1908
|
+
return new BehaviorNode(selector, body, flags, flagArgs);
|
|
1385
1909
|
});
|
|
1386
1910
|
}
|
|
1387
1911
|
parseSelector() {
|
|
@@ -1395,6 +1919,9 @@ var Parser = class _Parser {
|
|
|
1395
1919
|
if (token.type === "LBrace" /* LBrace */) {
|
|
1396
1920
|
break;
|
|
1397
1921
|
}
|
|
1922
|
+
if (token.type === "Bang" /* Bang */) {
|
|
1923
|
+
break;
|
|
1924
|
+
}
|
|
1398
1925
|
if (token.type === "Whitespace" /* Whitespace */) {
|
|
1399
1926
|
this.stream.next();
|
|
1400
1927
|
if (sawNonWhitespace && selectorText[selectorText.length - 1] !== " ") {
|
|
@@ -1410,6 +1937,10 @@ var Parser = class _Parser {
|
|
|
1410
1937
|
}
|
|
1411
1938
|
return new SelectorNode(selectorText.trim());
|
|
1412
1939
|
}
|
|
1940
|
+
parseBehaviorFlags() {
|
|
1941
|
+
const result = this.parseFlags(this.behaviorFlags, "behavior modifier");
|
|
1942
|
+
return { flags: result.flags, flagArgs: result.flagArgs };
|
|
1943
|
+
}
|
|
1413
1944
|
parseUseStatement() {
|
|
1414
1945
|
return this.wrapErrors(() => {
|
|
1415
1946
|
this.stream.expect("Use" /* Use */);
|
|
@@ -1493,6 +2024,7 @@ ${caret}`;
|
|
|
1493
2024
|
}
|
|
1494
2025
|
parseBlock(options) {
|
|
1495
2026
|
const allowDeclarations = options?.allowDeclarations ?? false;
|
|
2027
|
+
const allowReturn = options?.allowReturn ?? this.functionDepth > 0;
|
|
1496
2028
|
this.stream.skipWhitespace();
|
|
1497
2029
|
this.stream.expect("LBrace" /* LBrace */);
|
|
1498
2030
|
const statements = [];
|
|
@@ -1554,7 +2086,7 @@ ${caret}`;
|
|
|
1554
2086
|
}
|
|
1555
2087
|
sawConstruct = true;
|
|
1556
2088
|
}
|
|
1557
|
-
statements.push(this.parseStatement());
|
|
2089
|
+
statements.push(this.parseStatement({ allowReturn }));
|
|
1558
2090
|
}
|
|
1559
2091
|
}
|
|
1560
2092
|
return new BlockNode(statements);
|
|
@@ -1573,6 +2105,15 @@ ${caret}`;
|
|
|
1573
2105
|
}
|
|
1574
2106
|
return this.parseReturnStatement();
|
|
1575
2107
|
}
|
|
2108
|
+
if (next.type === "Assert" /* Assert */) {
|
|
2109
|
+
return this.parseAssertStatement();
|
|
2110
|
+
}
|
|
2111
|
+
if (next.type === "Break" /* Break */) {
|
|
2112
|
+
return this.parseBreakStatement();
|
|
2113
|
+
}
|
|
2114
|
+
if (next.type === "Continue" /* Continue */) {
|
|
2115
|
+
return this.parseContinueStatement();
|
|
2116
|
+
}
|
|
1576
2117
|
if (allowBlocks && next.type === "On" /* On */) {
|
|
1577
2118
|
return this.parseOnBlock();
|
|
1578
2119
|
}
|
|
@@ -1608,44 +2149,6 @@ ${caret}`;
|
|
|
1608
2149
|
}
|
|
1609
2150
|
throw new Error(`Unexpected token ${next.type}`);
|
|
1610
2151
|
}
|
|
1611
|
-
parseStateBlock() {
|
|
1612
|
-
this.stream.expect("State" /* State */);
|
|
1613
|
-
this.stream.skipWhitespace();
|
|
1614
|
-
this.stream.expect("LBrace" /* LBrace */);
|
|
1615
|
-
const entries = [];
|
|
1616
|
-
while (true) {
|
|
1617
|
-
this.stream.skipWhitespace();
|
|
1618
|
-
const next = this.stream.peek();
|
|
1619
|
-
if (!next) {
|
|
1620
|
-
throw new Error("Unterminated state block");
|
|
1621
|
-
}
|
|
1622
|
-
if (next.type === "RBrace" /* RBrace */) {
|
|
1623
|
-
this.stream.next();
|
|
1624
|
-
break;
|
|
1625
|
-
}
|
|
1626
|
-
const nameToken = this.stream.expect("Identifier" /* Identifier */);
|
|
1627
|
-
this.stream.skipWhitespace();
|
|
1628
|
-
this.stream.expect("Colon" /* Colon */);
|
|
1629
|
-
this.stream.skipWhitespace();
|
|
1630
|
-
const value = this.parseExpression();
|
|
1631
|
-
this.stream.skipWhitespace();
|
|
1632
|
-
let important = false;
|
|
1633
|
-
if (this.stream.peek()?.type === "Bang" /* Bang */) {
|
|
1634
|
-
this.stream.next();
|
|
1635
|
-
this.stream.skipWhitespace();
|
|
1636
|
-
const importantToken = this.stream.next();
|
|
1637
|
-
if (importantToken.type === "Identifier" /* Identifier */ && importantToken.value === "important") {
|
|
1638
|
-
important = true;
|
|
1639
|
-
} else {
|
|
1640
|
-
throw new Error("Expected 'important' after '!'");
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1643
|
-
this.stream.skipWhitespace();
|
|
1644
|
-
this.stream.expect("Semicolon" /* Semicolon */);
|
|
1645
|
-
entries.push(new StateEntryNode(nameToken.value, value, important));
|
|
1646
|
-
}
|
|
1647
|
-
return new StateBlockNode(entries);
|
|
1648
|
-
}
|
|
1649
2152
|
parseOnBlock() {
|
|
1650
2153
|
this.stream.expect("On" /* On */);
|
|
1651
2154
|
this.stream.skipWhitespace();
|
|
@@ -1673,22 +2176,9 @@ ${caret}`;
|
|
|
1673
2176
|
}
|
|
1674
2177
|
throw new Error(`Unexpected token in on() args: ${next.type}`);
|
|
1675
2178
|
}
|
|
1676
|
-
const
|
|
2179
|
+
const { flags, flagArgs } = this.parseFlags(this.customFlags, "flag");
|
|
1677
2180
|
const body = this.parseBlock({ allowDeclarations: false });
|
|
1678
|
-
return new OnBlockNode(event, args, body,
|
|
1679
|
-
}
|
|
1680
|
-
parseOnModifiers() {
|
|
1681
|
-
const modifiers = [];
|
|
1682
|
-
while (true) {
|
|
1683
|
-
this.stream.skipWhitespace();
|
|
1684
|
-
if (this.stream.peek()?.type !== "Bang" /* Bang */) {
|
|
1685
|
-
break;
|
|
1686
|
-
}
|
|
1687
|
-
this.stream.next();
|
|
1688
|
-
const name = this.stream.expect("Identifier" /* Identifier */).value;
|
|
1689
|
-
modifiers.push(name);
|
|
1690
|
-
}
|
|
1691
|
-
return modifiers;
|
|
2181
|
+
return new OnBlockNode(event, args, body, flags, flagArgs);
|
|
1692
2182
|
}
|
|
1693
2183
|
parseAssignment() {
|
|
1694
2184
|
const target = this.parseAssignmentTarget();
|
|
@@ -1898,6 +2388,11 @@ ${caret}`;
|
|
|
1898
2388
|
if (!token) {
|
|
1899
2389
|
throw new Error("Expected expression");
|
|
1900
2390
|
}
|
|
2391
|
+
if (token.type === "PlusPlus" /* PlusPlus */ || token.type === "MinusMinus" /* MinusMinus */) {
|
|
2392
|
+
this.stream.next();
|
|
2393
|
+
const argument = this.parseUnaryExpression();
|
|
2394
|
+
return this.createIncrementNode(token, argument, true);
|
|
2395
|
+
}
|
|
1901
2396
|
if (token.type === "Bang" /* Bang */) {
|
|
1902
2397
|
this.stream.next();
|
|
1903
2398
|
const argument = this.parseUnaryExpression();
|
|
@@ -1913,7 +2408,31 @@ ${caret}`;
|
|
|
1913
2408
|
const argument = this.parseUnaryExpression();
|
|
1914
2409
|
return new AwaitExpression(argument);
|
|
1915
2410
|
}
|
|
1916
|
-
return this.
|
|
2411
|
+
return this.parsePostfixExpression();
|
|
2412
|
+
}
|
|
2413
|
+
parsePostfixExpression() {
|
|
2414
|
+
let expr = this.parseCallExpression();
|
|
2415
|
+
while (true) {
|
|
2416
|
+
this.stream.skipWhitespace();
|
|
2417
|
+
const token = this.stream.peek();
|
|
2418
|
+
if (!token) {
|
|
2419
|
+
break;
|
|
2420
|
+
}
|
|
2421
|
+
if (token.type === "PlusPlus" /* PlusPlus */ || token.type === "MinusMinus" /* MinusMinus */) {
|
|
2422
|
+
this.stream.next();
|
|
2423
|
+
expr = this.createIncrementNode(token, expr, false);
|
|
2424
|
+
continue;
|
|
2425
|
+
}
|
|
2426
|
+
break;
|
|
2427
|
+
}
|
|
2428
|
+
return expr;
|
|
2429
|
+
}
|
|
2430
|
+
createIncrementNode(token, argument, prefix) {
|
|
2431
|
+
if (!(argument instanceof IdentifierExpression) && !(argument instanceof MemberExpression) && !(argument instanceof IndexExpression) && !(argument instanceof DirectiveExpression)) {
|
|
2432
|
+
throw new Error("Increment/decrement requires a mutable target");
|
|
2433
|
+
}
|
|
2434
|
+
const operator = token.type === "PlusPlus" /* PlusPlus */ ? "++" : "--";
|
|
2435
|
+
return new AssignmentNode(argument, new LiteralExpression(1), operator, prefix);
|
|
1917
2436
|
}
|
|
1918
2437
|
parseCallExpression() {
|
|
1919
2438
|
let expr = this.parsePrimaryExpression();
|
|
@@ -2225,6 +2744,7 @@ ${caret}`;
|
|
|
2225
2744
|
this.stream.expect("LBrace" /* LBrace */);
|
|
2226
2745
|
const statements = [];
|
|
2227
2746
|
this.awaitStack.push(allowAwait);
|
|
2747
|
+
this.functionDepth += 1;
|
|
2228
2748
|
try {
|
|
2229
2749
|
while (true) {
|
|
2230
2750
|
this.stream.skipWhitespace();
|
|
@@ -2236,9 +2756,10 @@ ${caret}`;
|
|
|
2236
2756
|
this.stream.next();
|
|
2237
2757
|
break;
|
|
2238
2758
|
}
|
|
2239
|
-
statements.push(this.parseStatement({ allowBlocks:
|
|
2759
|
+
statements.push(this.parseStatement({ allowBlocks: true, allowReturn: true }));
|
|
2240
2760
|
}
|
|
2241
2761
|
} finally {
|
|
2762
|
+
this.functionDepth -= 1;
|
|
2242
2763
|
this.awaitStack.pop();
|
|
2243
2764
|
}
|
|
2244
2765
|
return new BlockNode(statements);
|
|
@@ -2279,7 +2800,14 @@ ${caret}`;
|
|
|
2279
2800
|
return this.parseObjectPattern();
|
|
2280
2801
|
}
|
|
2281
2802
|
if (token.type === "Identifier" /* Identifier */) {
|
|
2282
|
-
|
|
2803
|
+
const expr = this.parseCallExpression();
|
|
2804
|
+
if (expr instanceof CallExpression) {
|
|
2805
|
+
throw new Error("Invalid assignment target CallExpression");
|
|
2806
|
+
}
|
|
2807
|
+
if (expr instanceof IdentifierExpression || expr instanceof MemberExpression || expr instanceof IndexExpression) {
|
|
2808
|
+
return expr;
|
|
2809
|
+
}
|
|
2810
|
+
throw new Error("Invalid assignment target");
|
|
2283
2811
|
}
|
|
2284
2812
|
throw new Error(`Invalid assignment target ${token.type}`);
|
|
2285
2813
|
}
|
|
@@ -2427,7 +2955,7 @@ ${caret}`;
|
|
|
2427
2955
|
const operator = this.parseDeclarationOperator();
|
|
2428
2956
|
this.stream.skipWhitespace();
|
|
2429
2957
|
const value = this.parseExpression();
|
|
2430
|
-
const { flags, flagArgs } = this.parseFlags();
|
|
2958
|
+
const { flags, flagArgs } = this.parseFlags(this.customFlags, "flag");
|
|
2431
2959
|
this.stream.skipWhitespace();
|
|
2432
2960
|
this.stream.expect("Semicolon" /* Semicolon */);
|
|
2433
2961
|
return new DeclarationNode(target, operator, value, flags, flagArgs);
|
|
@@ -2468,7 +2996,7 @@ ${caret}`;
|
|
|
2468
2996
|
}
|
|
2469
2997
|
return ":";
|
|
2470
2998
|
}
|
|
2471
|
-
parseFlags() {
|
|
2999
|
+
parseFlags(allowed, errorLabel) {
|
|
2472
3000
|
const flags = {};
|
|
2473
3001
|
const flagArgs = {};
|
|
2474
3002
|
while (true) {
|
|
@@ -2478,59 +3006,107 @@ ${caret}`;
|
|
|
2478
3006
|
}
|
|
2479
3007
|
this.stream.next();
|
|
2480
3008
|
const name = this.stream.expect("Identifier" /* Identifier */).value;
|
|
2481
|
-
if (
|
|
2482
|
-
|
|
2483
|
-
}
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
3009
|
+
if (allowed && !allowed.has(name)) {
|
|
3010
|
+
throw new Error(`Unknown ${errorLabel} ${name}`);
|
|
3011
|
+
}
|
|
3012
|
+
flags[name] = true;
|
|
3013
|
+
const customArg = this.parseCustomFlagArg();
|
|
3014
|
+
if (customArg !== void 0) {
|
|
3015
|
+
flagArgs[name] = customArg;
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
return { flags, flagArgs };
|
|
3019
|
+
}
|
|
3020
|
+
parseCustomFlagArg() {
|
|
3021
|
+
if (this.stream.peek()?.type !== "LParen" /* LParen */) {
|
|
3022
|
+
return void 0;
|
|
3023
|
+
}
|
|
3024
|
+
this.stream.next();
|
|
3025
|
+
this.stream.skipWhitespace();
|
|
3026
|
+
const token = this.stream.peek();
|
|
3027
|
+
if (!token) {
|
|
3028
|
+
throw new Error("Unterminated flag arguments");
|
|
3029
|
+
}
|
|
3030
|
+
const value = this.parseCustomFlagLiteral();
|
|
3031
|
+
this.stream.skipWhitespace();
|
|
3032
|
+
this.stream.expect("RParen" /* RParen */);
|
|
3033
|
+
return value;
|
|
3034
|
+
}
|
|
3035
|
+
parseCustomFlagLiteral() {
|
|
3036
|
+
const token = this.stream.peek();
|
|
3037
|
+
if (!token) {
|
|
3038
|
+
throw new Error("Unterminated flag arguments");
|
|
3039
|
+
}
|
|
3040
|
+
if (token.type === "Number" /* Number */) {
|
|
3041
|
+
return Number(this.stream.next().value);
|
|
3042
|
+
}
|
|
3043
|
+
if (token.type === "String" /* String */) {
|
|
3044
|
+
return this.stream.next().value;
|
|
3045
|
+
}
|
|
3046
|
+
if (token.type === "Boolean" /* Boolean */) {
|
|
3047
|
+
return this.stream.next().value === "true";
|
|
3048
|
+
}
|
|
3049
|
+
if (token.type === "Identifier" /* Identifier */) {
|
|
3050
|
+
return this.stream.next().value;
|
|
3051
|
+
}
|
|
3052
|
+
if (token.type === "LBracket" /* LBracket */) {
|
|
3053
|
+
return this.parseCustomFlagArray();
|
|
3054
|
+
}
|
|
3055
|
+
if (token.type === "LBrace" /* LBrace */) {
|
|
3056
|
+
return this.parseCustomFlagObject();
|
|
3057
|
+
}
|
|
3058
|
+
throw new Error(`Unsupported flag argument ${token.type}`);
|
|
3059
|
+
}
|
|
3060
|
+
parseCustomFlagArray() {
|
|
3061
|
+
this.stream.expect("LBracket" /* LBracket */);
|
|
3062
|
+
const items = [];
|
|
3063
|
+
while (true) {
|
|
3064
|
+
this.stream.skipWhitespace();
|
|
3065
|
+
const next = this.stream.peek();
|
|
3066
|
+
if (!next) {
|
|
3067
|
+
throw new Error("Unterminated flag array");
|
|
3068
|
+
}
|
|
3069
|
+
if (next.type === "RBracket" /* RBracket */) {
|
|
3070
|
+
this.stream.next();
|
|
3071
|
+
break;
|
|
3072
|
+
}
|
|
3073
|
+
items.push(this.parseCustomFlagLiteral());
|
|
3074
|
+
this.stream.skipWhitespace();
|
|
3075
|
+
if (this.stream.peek()?.type === "Comma" /* Comma */) {
|
|
3076
|
+
this.stream.next();
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
return items;
|
|
3080
|
+
}
|
|
3081
|
+
parseCustomFlagObject() {
|
|
3082
|
+
this.stream.expect("LBrace" /* LBrace */);
|
|
3083
|
+
const obj = {};
|
|
3084
|
+
while (true) {
|
|
3085
|
+
this.stream.skipWhitespace();
|
|
3086
|
+
const next = this.stream.peek();
|
|
3087
|
+
if (!next) {
|
|
3088
|
+
throw new Error("Unterminated flag object");
|
|
3089
|
+
}
|
|
3090
|
+
if (next.type === "RBrace" /* RBrace */) {
|
|
3091
|
+
this.stream.next();
|
|
3092
|
+
break;
|
|
3093
|
+
}
|
|
3094
|
+
let key;
|
|
3095
|
+
if (next.type === "Identifier" /* Identifier */ || next.type === "String" /* String */) {
|
|
3096
|
+
key = this.stream.next().value;
|
|
2503
3097
|
} else {
|
|
2504
|
-
throw new Error(`
|
|
3098
|
+
throw new Error(`Unsupported flag object key ${next.type}`);
|
|
3099
|
+
}
|
|
3100
|
+
this.stream.skipWhitespace();
|
|
3101
|
+
this.stream.expect("Colon" /* Colon */);
|
|
3102
|
+
this.stream.skipWhitespace();
|
|
3103
|
+
obj[key] = this.parseCustomFlagLiteral();
|
|
3104
|
+
this.stream.skipWhitespace();
|
|
3105
|
+
if (this.stream.peek()?.type === "Comma" /* Comma */) {
|
|
3106
|
+
this.stream.next();
|
|
2505
3107
|
}
|
|
2506
3108
|
}
|
|
2507
|
-
return
|
|
2508
|
-
}
|
|
2509
|
-
parseCustomFlagArg() {
|
|
2510
|
-
if (this.stream.peek()?.type !== "LParen" /* LParen */) {
|
|
2511
|
-
return void 0;
|
|
2512
|
-
}
|
|
2513
|
-
this.stream.next();
|
|
2514
|
-
this.stream.skipWhitespace();
|
|
2515
|
-
const token = this.stream.peek();
|
|
2516
|
-
if (!token) {
|
|
2517
|
-
throw new Error("Unterminated flag arguments");
|
|
2518
|
-
}
|
|
2519
|
-
let value;
|
|
2520
|
-
if (token.type === "Number" /* Number */) {
|
|
2521
|
-
value = Number(this.stream.next().value);
|
|
2522
|
-
} else if (token.type === "String" /* String */) {
|
|
2523
|
-
value = this.stream.next().value;
|
|
2524
|
-
} else if (token.type === "Boolean" /* Boolean */) {
|
|
2525
|
-
value = this.stream.next().value === "true";
|
|
2526
|
-
} else if (token.type === "Identifier" /* Identifier */) {
|
|
2527
|
-
value = this.stream.next().value;
|
|
2528
|
-
} else {
|
|
2529
|
-
throw new Error(`Unsupported flag argument ${token.type}`);
|
|
2530
|
-
}
|
|
2531
|
-
this.stream.skipWhitespace();
|
|
2532
|
-
this.stream.expect("RParen" /* RParen */);
|
|
2533
|
-
return value;
|
|
3109
|
+
return obj;
|
|
2534
3110
|
}
|
|
2535
3111
|
isDeclarationStart() {
|
|
2536
3112
|
const first = this.stream.peekNonWhitespace(0);
|
|
@@ -2555,14 +3131,29 @@ ${caret}`;
|
|
|
2555
3131
|
}
|
|
2556
3132
|
if (first.type === "Identifier" /* Identifier */) {
|
|
2557
3133
|
let index = 1;
|
|
2558
|
-
while (
|
|
2559
|
-
|
|
3134
|
+
while (true) {
|
|
3135
|
+
const token = this.stream.peekNonWhitespace(index);
|
|
3136
|
+
if (!token) {
|
|
3137
|
+
return false;
|
|
3138
|
+
}
|
|
3139
|
+
if (token.type === "Dot" /* Dot */ && this.stream.peekNonWhitespace(index + 1)?.type === "Identifier" /* Identifier */) {
|
|
3140
|
+
index += 2;
|
|
3141
|
+
continue;
|
|
3142
|
+
}
|
|
3143
|
+
if (token.type === "LBracket" /* LBracket */) {
|
|
3144
|
+
const indexAfter = this.stream.indexAfterDelimited("LBracket" /* LBracket */, "RBracket" /* RBracket */, index);
|
|
3145
|
+
if (indexAfter === null) {
|
|
3146
|
+
return false;
|
|
3147
|
+
}
|
|
3148
|
+
index = indexAfter;
|
|
3149
|
+
continue;
|
|
3150
|
+
}
|
|
3151
|
+
break;
|
|
2560
3152
|
}
|
|
2561
3153
|
return this.isAssignmentOperatorStart(index);
|
|
2562
3154
|
}
|
|
2563
3155
|
if (first.type === "At" /* At */ || first.type === "Dollar" /* Dollar */) {
|
|
2564
3156
|
const second = this.stream.peekNonWhitespace(1);
|
|
2565
|
-
const third = this.stream.peekNonWhitespace(2);
|
|
2566
3157
|
return second?.type === "Identifier" /* Identifier */ && this.isAssignmentOperatorStart(2);
|
|
2567
3158
|
}
|
|
2568
3159
|
if (first.type === "LBrace" /* LBrace */ || first.type === "LBracket" /* LBracket */) {
|
|
@@ -2600,17 +3191,6 @@ ${caret}`;
|
|
|
2600
3191
|
}
|
|
2601
3192
|
return false;
|
|
2602
3193
|
}
|
|
2603
|
-
isCallStart() {
|
|
2604
|
-
const first = this.stream.peekNonWhitespace(0);
|
|
2605
|
-
if (!first || first.type !== "Identifier" /* Identifier */) {
|
|
2606
|
-
return false;
|
|
2607
|
-
}
|
|
2608
|
-
let index = 1;
|
|
2609
|
-
while (this.stream.peekNonWhitespace(index)?.type === "Dot" /* Dot */ && this.stream.peekNonWhitespace(index + 1)?.type === "Identifier" /* Identifier */) {
|
|
2610
|
-
index += 2;
|
|
2611
|
-
}
|
|
2612
|
-
return this.stream.peekNonWhitespace(index)?.type === "LParen" /* LParen */;
|
|
2613
|
-
}
|
|
2614
3194
|
isExpressionStatementStart() {
|
|
2615
3195
|
const first = this.stream.peekNonWhitespace(0);
|
|
2616
3196
|
if (!first) {
|
|
@@ -2640,50 +3220,22 @@ ${caret}`;
|
|
|
2640
3220
|
if (this.stream.peekNonWhitespace(index)?.type !== "LParen" /* LParen */) {
|
|
2641
3221
|
return false;
|
|
2642
3222
|
}
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
const token = this.stream.peekNonWhitespace(index);
|
|
2647
|
-
if (!token) {
|
|
2648
|
-
return false;
|
|
2649
|
-
}
|
|
2650
|
-
if (token.type === "LParen" /* LParen */) {
|
|
2651
|
-
depth += 1;
|
|
2652
|
-
} else if (token.type === "RParen" /* RParen */) {
|
|
2653
|
-
depth -= 1;
|
|
2654
|
-
if (depth === 0) {
|
|
2655
|
-
index += 1;
|
|
2656
|
-
break;
|
|
2657
|
-
}
|
|
2658
|
-
}
|
|
2659
|
-
index += 1;
|
|
3223
|
+
const indexAfterParams = this.stream.indexAfterDelimited("LParen" /* LParen */, "RParen" /* RParen */, index);
|
|
3224
|
+
if (indexAfterParams === null) {
|
|
3225
|
+
return false;
|
|
2660
3226
|
}
|
|
2661
|
-
return this.stream.peekNonWhitespace(
|
|
3227
|
+
return this.stream.peekNonWhitespace(indexAfterParams)?.type === "LBrace" /* LBrace */;
|
|
2662
3228
|
}
|
|
2663
3229
|
isArrowFunctionStart() {
|
|
2664
3230
|
const first = this.stream.peekNonWhitespace(0);
|
|
2665
3231
|
if (!first || first.type !== "LParen" /* LParen */) {
|
|
2666
3232
|
return false;
|
|
2667
3233
|
}
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
const token = this.stream.peekNonWhitespace(index);
|
|
2672
|
-
if (!token) {
|
|
2673
|
-
return false;
|
|
2674
|
-
}
|
|
2675
|
-
if (token.type === "LParen" /* LParen */) {
|
|
2676
|
-
depth += 1;
|
|
2677
|
-
} else if (token.type === "RParen" /* RParen */) {
|
|
2678
|
-
depth -= 1;
|
|
2679
|
-
if (depth === 0) {
|
|
2680
|
-
index += 1;
|
|
2681
|
-
break;
|
|
2682
|
-
}
|
|
2683
|
-
}
|
|
2684
|
-
index += 1;
|
|
3234
|
+
const indexAfterParams = this.stream.indexAfterDelimited("LParen" /* LParen */, "RParen" /* RParen */, 0);
|
|
3235
|
+
if (indexAfterParams === null) {
|
|
3236
|
+
return false;
|
|
2685
3237
|
}
|
|
2686
|
-
return this.stream.peekNonWhitespace(
|
|
3238
|
+
return this.stream.peekNonWhitespace(indexAfterParams)?.type === "Arrow" /* Arrow */;
|
|
2687
3239
|
}
|
|
2688
3240
|
isAsyncArrowFunctionStart() {
|
|
2689
3241
|
const first = this.stream.peekNonWhitespace(0);
|
|
@@ -2693,25 +3245,11 @@ ${caret}`;
|
|
|
2693
3245
|
if (this.stream.peekNonWhitespace(1)?.type !== "LParen" /* LParen */) {
|
|
2694
3246
|
return false;
|
|
2695
3247
|
}
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
const token = this.stream.peekNonWhitespace(index);
|
|
2700
|
-
if (!token) {
|
|
2701
|
-
return false;
|
|
2702
|
-
}
|
|
2703
|
-
if (token.type === "LParen" /* LParen */) {
|
|
2704
|
-
depth += 1;
|
|
2705
|
-
} else if (token.type === "RParen" /* RParen */) {
|
|
2706
|
-
depth -= 1;
|
|
2707
|
-
if (depth === 0) {
|
|
2708
|
-
index += 1;
|
|
2709
|
-
break;
|
|
2710
|
-
}
|
|
2711
|
-
}
|
|
2712
|
-
index += 1;
|
|
3248
|
+
const indexAfterParams = this.stream.indexAfterDelimited("LParen" /* LParen */, "RParen" /* RParen */, 1);
|
|
3249
|
+
if (indexAfterParams === null) {
|
|
3250
|
+
return false;
|
|
2713
3251
|
}
|
|
2714
|
-
return this.stream.peekNonWhitespace(
|
|
3252
|
+
return this.stream.peekNonWhitespace(indexAfterParams)?.type === "Arrow" /* Arrow */;
|
|
2715
3253
|
}
|
|
2716
3254
|
isFunctionExpressionAssignmentStart() {
|
|
2717
3255
|
const first = this.stream.peekNonWhitespace(0);
|
|
@@ -2728,25 +3266,11 @@ ${caret}`;
|
|
|
2728
3266
|
if (this.stream.peekNonWhitespace(index)?.type !== "LParen" /* LParen */) {
|
|
2729
3267
|
return false;
|
|
2730
3268
|
}
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
const token = this.stream.peekNonWhitespace(index);
|
|
2735
|
-
if (!token) {
|
|
2736
|
-
return false;
|
|
2737
|
-
}
|
|
2738
|
-
if (token.type === "LParen" /* LParen */) {
|
|
2739
|
-
depth += 1;
|
|
2740
|
-
} else if (token.type === "RParen" /* RParen */) {
|
|
2741
|
-
depth -= 1;
|
|
2742
|
-
if (depth === 0) {
|
|
2743
|
-
index += 1;
|
|
2744
|
-
break;
|
|
2745
|
-
}
|
|
2746
|
-
}
|
|
2747
|
-
index += 1;
|
|
3269
|
+
const indexAfterParams = this.stream.indexAfterDelimited("LParen" /* LParen */, "RParen" /* RParen */, index);
|
|
3270
|
+
if (indexAfterParams === null) {
|
|
3271
|
+
return false;
|
|
2748
3272
|
}
|
|
2749
|
-
return this.stream.peekNonWhitespace(
|
|
3273
|
+
return this.stream.peekNonWhitespace(indexAfterParams)?.type === "Arrow" /* Arrow */;
|
|
2750
3274
|
}
|
|
2751
3275
|
parseExpressionStatement() {
|
|
2752
3276
|
const expr = this.parseExpression();
|
|
@@ -2761,7 +3285,7 @@ ${caret}`;
|
|
|
2761
3285
|
const test = this.parseExpression();
|
|
2762
3286
|
this.stream.skipWhitespace();
|
|
2763
3287
|
this.stream.expect("RParen" /* RParen */);
|
|
2764
|
-
const consequent = this.
|
|
3288
|
+
const consequent = this.parseConditionalBody();
|
|
2765
3289
|
this.stream.skipWhitespace();
|
|
2766
3290
|
let alternate;
|
|
2767
3291
|
if (this.stream.peek()?.type === "Else" /* Else */) {
|
|
@@ -2771,11 +3295,19 @@ ${caret}`;
|
|
|
2771
3295
|
const nested = this.parseIfBlock();
|
|
2772
3296
|
alternate = new BlockNode([nested]);
|
|
2773
3297
|
} else {
|
|
2774
|
-
alternate = this.
|
|
3298
|
+
alternate = this.parseConditionalBody();
|
|
2775
3299
|
}
|
|
2776
3300
|
}
|
|
2777
3301
|
return new IfNode(test, consequent, alternate);
|
|
2778
3302
|
}
|
|
3303
|
+
parseConditionalBody() {
|
|
3304
|
+
this.stream.skipWhitespace();
|
|
3305
|
+
if (this.stream.peek()?.type === "LBrace" /* LBrace */) {
|
|
3306
|
+
return this.parseBlock({ allowDeclarations: false });
|
|
3307
|
+
}
|
|
3308
|
+
const statement = this.parseStatement({ allowBlocks: false, allowReturn: this.functionDepth > 0 });
|
|
3309
|
+
return new BlockNode([statement]);
|
|
3310
|
+
}
|
|
2779
3311
|
parseWhileBlock() {
|
|
2780
3312
|
this.stream.expect("While" /* While */);
|
|
2781
3313
|
this.stream.skipWhitespace();
|
|
@@ -2792,6 +3324,21 @@ ${caret}`;
|
|
|
2792
3324
|
this.stream.skipWhitespace();
|
|
2793
3325
|
this.stream.expect("LParen" /* LParen */);
|
|
2794
3326
|
this.stream.skipWhitespace();
|
|
3327
|
+
const eachKind = this.detectForEachKind();
|
|
3328
|
+
if (eachKind) {
|
|
3329
|
+
const target = this.parseForEachTarget();
|
|
3330
|
+
this.stream.skipWhitespace();
|
|
3331
|
+
const keyword = this.stream.expect("Identifier" /* Identifier */);
|
|
3332
|
+
if (keyword.value !== eachKind) {
|
|
3333
|
+
throw new Error(`Expected '${eachKind}' but got '${keyword.value}'`);
|
|
3334
|
+
}
|
|
3335
|
+
this.stream.skipWhitespace();
|
|
3336
|
+
const iterable = this.parseExpression();
|
|
3337
|
+
this.stream.skipWhitespace();
|
|
3338
|
+
this.stream.expect("RParen" /* RParen */);
|
|
3339
|
+
const body2 = this.parseBlock({ allowDeclarations: false });
|
|
3340
|
+
return new ForEachNode(target, iterable, eachKind, body2);
|
|
3341
|
+
}
|
|
2795
3342
|
let init;
|
|
2796
3343
|
if (this.stream.peek()?.type !== "Semicolon" /* Semicolon */) {
|
|
2797
3344
|
init = this.parseForClause();
|
|
@@ -2815,6 +3362,43 @@ ${caret}`;
|
|
|
2815
3362
|
const body = this.parseBlock({ allowDeclarations: false });
|
|
2816
3363
|
return new ForNode(init, test, update, body);
|
|
2817
3364
|
}
|
|
3365
|
+
detectForEachKind() {
|
|
3366
|
+
let offset = 0;
|
|
3367
|
+
let depth = 0;
|
|
3368
|
+
while (true) {
|
|
3369
|
+
const token = this.stream.peekNonWhitespace(offset);
|
|
3370
|
+
if (!token) {
|
|
3371
|
+
return null;
|
|
3372
|
+
}
|
|
3373
|
+
if (token.type === "LParen" /* LParen */ || token.type === "LBracket" /* LBracket */ || token.type === "LBrace" /* LBrace */) {
|
|
3374
|
+
depth += 1;
|
|
3375
|
+
} else if (token.type === "RParen" /* RParen */ || token.type === "RBracket" /* RBracket */ || token.type === "RBrace" /* RBrace */) {
|
|
3376
|
+
if (depth === 0) {
|
|
3377
|
+
return null;
|
|
3378
|
+
}
|
|
3379
|
+
depth -= 1;
|
|
3380
|
+
}
|
|
3381
|
+
if (depth === 0) {
|
|
3382
|
+
if (token.type === "Semicolon" /* Semicolon */) {
|
|
3383
|
+
return null;
|
|
3384
|
+
}
|
|
3385
|
+
if (token.type === "Identifier" /* Identifier */ && (token.value === "in" || token.value === "of")) {
|
|
3386
|
+
return token.value;
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
offset += 1;
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
parseForEachTarget() {
|
|
3393
|
+
const token = this.stream.peek();
|
|
3394
|
+
if (!token) {
|
|
3395
|
+
throw new Error("Expected for-each target");
|
|
3396
|
+
}
|
|
3397
|
+
if (token.type !== "Identifier" /* Identifier */) {
|
|
3398
|
+
throw new Error("for-in/of target must be an identifier");
|
|
3399
|
+
}
|
|
3400
|
+
return new IdentifierExpression(this.stream.next().value);
|
|
3401
|
+
}
|
|
2818
3402
|
parseForClause() {
|
|
2819
3403
|
if (this.isAssignmentStart()) {
|
|
2820
3404
|
return this.parseAssignmentExpression();
|
|
@@ -2910,9 +3494,6 @@ ${caret}`;
|
|
|
2910
3494
|
const body = this.parseFunctionBlockWithAwait(isAsync);
|
|
2911
3495
|
return new FunctionDeclarationNode(name, params, body, isAsync);
|
|
2912
3496
|
}
|
|
2913
|
-
parseFunctionBlock() {
|
|
2914
|
-
return this.parseFunctionBlockWithAwait(false);
|
|
2915
|
-
}
|
|
2916
3497
|
parseReturnStatement() {
|
|
2917
3498
|
this.stream.expect("Return" /* Return */);
|
|
2918
3499
|
this.stream.skipWhitespace();
|
|
@@ -2925,6 +3506,23 @@ ${caret}`;
|
|
|
2925
3506
|
this.stream.expect("Semicolon" /* Semicolon */);
|
|
2926
3507
|
return new ReturnNode(value);
|
|
2927
3508
|
}
|
|
3509
|
+
parseAssertStatement() {
|
|
3510
|
+
this.stream.expect("Assert" /* Assert */);
|
|
3511
|
+
this.stream.skipWhitespace();
|
|
3512
|
+
const test = this.parseExpression();
|
|
3513
|
+
this.consumeStatementTerminator();
|
|
3514
|
+
return new AssertNode(test);
|
|
3515
|
+
}
|
|
3516
|
+
parseBreakStatement() {
|
|
3517
|
+
this.stream.expect("Break" /* Break */);
|
|
3518
|
+
this.consumeStatementTerminator();
|
|
3519
|
+
return new BreakNode();
|
|
3520
|
+
}
|
|
3521
|
+
parseContinueStatement() {
|
|
3522
|
+
this.stream.expect("Continue" /* Continue */);
|
|
3523
|
+
this.consumeStatementTerminator();
|
|
3524
|
+
return new ContinueNode();
|
|
3525
|
+
}
|
|
2928
3526
|
parseArrowFunctionExpression(isAsync = false) {
|
|
2929
3527
|
const params = this.parseFunctionParams();
|
|
2930
3528
|
this.stream.skipWhitespace();
|
|
@@ -3034,6 +3632,7 @@ var Scope = class _Scope {
|
|
|
3034
3632
|
root;
|
|
3035
3633
|
listeners = /* @__PURE__ */ new Map();
|
|
3036
3634
|
anyListeners = /* @__PURE__ */ new Set();
|
|
3635
|
+
isEachItem = false;
|
|
3037
3636
|
createChild() {
|
|
3038
3637
|
return new _Scope(this);
|
|
3039
3638
|
}
|
|
@@ -3336,18 +3935,19 @@ var Engine = class _Engine {
|
|
|
3336
3935
|
eachBindings = /* @__PURE__ */ new WeakMap();
|
|
3337
3936
|
lifecycleBindings = /* @__PURE__ */ new WeakMap();
|
|
3338
3937
|
behaviorRegistry = [];
|
|
3938
|
+
behaviorRegistryHashes = /* @__PURE__ */ new Set();
|
|
3339
3939
|
behaviorBindings = /* @__PURE__ */ new WeakMap();
|
|
3340
3940
|
behaviorListeners = /* @__PURE__ */ new WeakMap();
|
|
3341
3941
|
behaviorId = 0;
|
|
3342
3942
|
codeCache = /* @__PURE__ */ new Map();
|
|
3343
3943
|
behaviorCache = /* @__PURE__ */ new Map();
|
|
3344
3944
|
observer;
|
|
3345
|
-
observerRoot;
|
|
3346
3945
|
attributeHandlers = [];
|
|
3347
3946
|
globals = {};
|
|
3348
3947
|
importantFlags = /* @__PURE__ */ new WeakMap();
|
|
3349
3948
|
inlineDeclarations = /* @__PURE__ */ new WeakMap();
|
|
3350
3949
|
flagHandlers = /* @__PURE__ */ new Map();
|
|
3950
|
+
behaviorModifiers = /* @__PURE__ */ new Map();
|
|
3351
3951
|
pendingAdded = /* @__PURE__ */ new Set();
|
|
3352
3952
|
pendingRemoved = /* @__PURE__ */ new Set();
|
|
3353
3953
|
pendingUpdated = /* @__PURE__ */ new Set();
|
|
@@ -3356,10 +3956,119 @@ var Engine = class _Engine {
|
|
|
3356
3956
|
diagnostics;
|
|
3357
3957
|
logger;
|
|
3358
3958
|
pendingUses = [];
|
|
3959
|
+
pendingAutoBindToScope = [];
|
|
3960
|
+
scopeWatchers = /* @__PURE__ */ new WeakMap();
|
|
3961
|
+
executionStack = [];
|
|
3962
|
+
groupProxyCache = /* @__PURE__ */ new WeakMap();
|
|
3359
3963
|
constructor(options = {}) {
|
|
3360
3964
|
this.diagnostics = options.diagnostics ?? false;
|
|
3361
3965
|
this.logger = options.logger ?? console;
|
|
3362
3966
|
this.registerGlobal("console", console);
|
|
3967
|
+
this.registerFlag("important");
|
|
3968
|
+
this.registerFlag("trusted");
|
|
3969
|
+
this.registerFlag("debounce", {
|
|
3970
|
+
onEventBind: ({ args }) => ({
|
|
3971
|
+
debounceMs: typeof args === "number" ? args : 200
|
|
3972
|
+
})
|
|
3973
|
+
});
|
|
3974
|
+
this.registerFlag("prevent", {
|
|
3975
|
+
onEventBefore: ({ event }) => {
|
|
3976
|
+
event?.preventDefault();
|
|
3977
|
+
}
|
|
3978
|
+
});
|
|
3979
|
+
this.registerFlag("stop", {
|
|
3980
|
+
onEventBefore: ({ event }) => {
|
|
3981
|
+
event?.stopPropagation();
|
|
3982
|
+
}
|
|
3983
|
+
});
|
|
3984
|
+
this.registerFlag("self", {
|
|
3985
|
+
onEventBefore: ({ event, element }) => {
|
|
3986
|
+
const target = event?.target;
|
|
3987
|
+
if (!(target instanceof Node)) {
|
|
3988
|
+
return false;
|
|
3989
|
+
}
|
|
3990
|
+
return target === element;
|
|
3991
|
+
}
|
|
3992
|
+
});
|
|
3993
|
+
this.registerFlag("outside", {
|
|
3994
|
+
onEventBind: ({ element }) => ({ listenerTarget: element.ownerDocument }),
|
|
3995
|
+
onEventBefore: ({ event, element }) => {
|
|
3996
|
+
const target = event?.target;
|
|
3997
|
+
if (!(target instanceof Node)) {
|
|
3998
|
+
return false;
|
|
3999
|
+
}
|
|
4000
|
+
return !element.contains(target);
|
|
4001
|
+
}
|
|
4002
|
+
});
|
|
4003
|
+
this.registerFlag("once", {
|
|
4004
|
+
onEventBind: () => ({ options: { once: true } })
|
|
4005
|
+
});
|
|
4006
|
+
this.registerFlag("passive", {
|
|
4007
|
+
onEventBind: () => ({ options: { passive: true } })
|
|
4008
|
+
});
|
|
4009
|
+
this.registerFlag("capture", {
|
|
4010
|
+
onEventBind: () => ({ options: { capture: true } })
|
|
4011
|
+
});
|
|
4012
|
+
this.registerFlag("shift", {
|
|
4013
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "shift")
|
|
4014
|
+
});
|
|
4015
|
+
this.registerFlag("ctrl", {
|
|
4016
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "ctrl")
|
|
4017
|
+
});
|
|
4018
|
+
this.registerFlag("control", {
|
|
4019
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "ctrl")
|
|
4020
|
+
});
|
|
4021
|
+
this.registerFlag("alt", {
|
|
4022
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "alt")
|
|
4023
|
+
});
|
|
4024
|
+
this.registerFlag("meta", {
|
|
4025
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "meta")
|
|
4026
|
+
});
|
|
4027
|
+
this.registerFlag("enter", {
|
|
4028
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "enter")
|
|
4029
|
+
});
|
|
4030
|
+
this.registerFlag("escape", {
|
|
4031
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "escape")
|
|
4032
|
+
});
|
|
4033
|
+
this.registerFlag("esc", {
|
|
4034
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "escape")
|
|
4035
|
+
});
|
|
4036
|
+
this.registerFlag("tab", {
|
|
4037
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "tab")
|
|
4038
|
+
});
|
|
4039
|
+
this.registerFlag("space", {
|
|
4040
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "space")
|
|
4041
|
+
});
|
|
4042
|
+
this.registerFlag("up", {
|
|
4043
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowup")
|
|
4044
|
+
});
|
|
4045
|
+
this.registerFlag("down", {
|
|
4046
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowdown")
|
|
4047
|
+
});
|
|
4048
|
+
this.registerFlag("left", {
|
|
4049
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowleft")
|
|
4050
|
+
});
|
|
4051
|
+
this.registerFlag("right", {
|
|
4052
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowright")
|
|
4053
|
+
});
|
|
4054
|
+
this.registerFlag("arrowup", {
|
|
4055
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowup")
|
|
4056
|
+
});
|
|
4057
|
+
this.registerFlag("arrowdown", {
|
|
4058
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowdown")
|
|
4059
|
+
});
|
|
4060
|
+
this.registerFlag("arrowleft", {
|
|
4061
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowleft")
|
|
4062
|
+
});
|
|
4063
|
+
this.registerFlag("arrowright", {
|
|
4064
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowright")
|
|
4065
|
+
});
|
|
4066
|
+
this.registerFlag("delete", {
|
|
4067
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "delete")
|
|
4068
|
+
});
|
|
4069
|
+
this.registerFlag("backspace", {
|
|
4070
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "backspace")
|
|
4071
|
+
});
|
|
3363
4072
|
this.registerGlobal("list", {
|
|
3364
4073
|
async map(items, fn) {
|
|
3365
4074
|
if (!Array.isArray(items) || typeof fn !== "function") {
|
|
@@ -3397,6 +4106,96 @@ var Engine = class _Engine {
|
|
|
3397
4106
|
}
|
|
3398
4107
|
});
|
|
3399
4108
|
this.registerDefaultAttributeHandlers();
|
|
4109
|
+
this.registerFlag("int", {
|
|
4110
|
+
transformValue: (_context, value) => this.coerceInt(value)
|
|
4111
|
+
});
|
|
4112
|
+
this.registerFlag("float", {
|
|
4113
|
+
transformValue: (_context, value) => this.coerceFloat(value)
|
|
4114
|
+
});
|
|
4115
|
+
this.registerBehaviorModifier("group", {
|
|
4116
|
+
onConstruct: ({ args, scope, rootScope, behavior, element }) => {
|
|
4117
|
+
const key = typeof args === "string" ? args : void 0;
|
|
4118
|
+
if (!key) {
|
|
4119
|
+
return;
|
|
4120
|
+
}
|
|
4121
|
+
const targetScope = this.getGroupTargetScope(element, behavior, scope, rootScope);
|
|
4122
|
+
const existing = targetScope.getPath?.(key);
|
|
4123
|
+
const list = Array.isArray(existing) ? existing : [];
|
|
4124
|
+
const proxy = this.getGroupProxy(scope);
|
|
4125
|
+
if (!list.includes(proxy)) {
|
|
4126
|
+
list.push(proxy);
|
|
4127
|
+
targetScope.setPath?.(key, list);
|
|
4128
|
+
} else if (!Array.isArray(existing)) {
|
|
4129
|
+
targetScope.setPath?.(key, list);
|
|
4130
|
+
}
|
|
4131
|
+
},
|
|
4132
|
+
onUnbind: ({ args, scope, rootScope, behavior, element }) => {
|
|
4133
|
+
const key = typeof args === "string" ? args : void 0;
|
|
4134
|
+
if (!key) {
|
|
4135
|
+
return;
|
|
4136
|
+
}
|
|
4137
|
+
const targetScope = this.getGroupTargetScope(element, behavior, scope, rootScope);
|
|
4138
|
+
const existing = targetScope.getPath?.(key);
|
|
4139
|
+
if (!Array.isArray(existing)) {
|
|
4140
|
+
return;
|
|
4141
|
+
}
|
|
4142
|
+
const proxy = this.getGroupProxy(scope);
|
|
4143
|
+
const next = existing.filter((entry) => entry !== proxy);
|
|
4144
|
+
if (next.length !== existing.length) {
|
|
4145
|
+
targetScope.setPath?.(key, next);
|
|
4146
|
+
}
|
|
4147
|
+
}
|
|
4148
|
+
});
|
|
4149
|
+
}
|
|
4150
|
+
getGroupTargetScope(element, behavior, scope, rootScope) {
|
|
4151
|
+
let targetScope = rootScope ?? scope;
|
|
4152
|
+
if (behavior.parentSelector) {
|
|
4153
|
+
const parentElement = element.closest(behavior.parentSelector);
|
|
4154
|
+
if (parentElement) {
|
|
4155
|
+
targetScope = this.getScope(parentElement);
|
|
4156
|
+
}
|
|
4157
|
+
}
|
|
4158
|
+
return targetScope;
|
|
4159
|
+
}
|
|
4160
|
+
getGroupProxy(scope) {
|
|
4161
|
+
const cached = this.groupProxyCache.get(scope);
|
|
4162
|
+
if (cached) {
|
|
4163
|
+
return cached;
|
|
4164
|
+
}
|
|
4165
|
+
const proxy = new Proxy(
|
|
4166
|
+
{},
|
|
4167
|
+
{
|
|
4168
|
+
get: (_target, prop) => {
|
|
4169
|
+
if (typeof prop === "symbol") {
|
|
4170
|
+
return void 0;
|
|
4171
|
+
}
|
|
4172
|
+
if (prop === "__scope") {
|
|
4173
|
+
return scope;
|
|
4174
|
+
}
|
|
4175
|
+
return scope.getPath(String(prop));
|
|
4176
|
+
},
|
|
4177
|
+
set: (_target, prop, value) => {
|
|
4178
|
+
if (typeof prop === "symbol") {
|
|
4179
|
+
return false;
|
|
4180
|
+
}
|
|
4181
|
+
scope.setPath(String(prop), value);
|
|
4182
|
+
return true;
|
|
4183
|
+
},
|
|
4184
|
+
has: (_target, prop) => {
|
|
4185
|
+
if (typeof prop === "symbol") {
|
|
4186
|
+
return false;
|
|
4187
|
+
}
|
|
4188
|
+
return scope.getPath(String(prop)) !== void 0;
|
|
4189
|
+
},
|
|
4190
|
+
getOwnPropertyDescriptor: () => ({
|
|
4191
|
+
enumerable: true,
|
|
4192
|
+
configurable: true
|
|
4193
|
+
}),
|
|
4194
|
+
ownKeys: () => []
|
|
4195
|
+
}
|
|
4196
|
+
);
|
|
4197
|
+
this.groupProxyCache.set(scope, proxy);
|
|
4198
|
+
return proxy;
|
|
3400
4199
|
}
|
|
3401
4200
|
async mount(root) {
|
|
3402
4201
|
const documentRoot = root.ownerDocument;
|
|
@@ -3423,7 +4222,10 @@ var Engine = class _Engine {
|
|
|
3423
4222
|
this.disconnectObserver();
|
|
3424
4223
|
}
|
|
3425
4224
|
registerBehaviors(source) {
|
|
3426
|
-
const program = new Parser(source, {
|
|
4225
|
+
const program = new Parser(source, {
|
|
4226
|
+
customFlags: new Set(this.flagHandlers.keys()),
|
|
4227
|
+
behaviorFlags: new Set(this.behaviorModifiers.keys())
|
|
4228
|
+
}).parseProgram();
|
|
3427
4229
|
for (const use of program.uses) {
|
|
3428
4230
|
if (use.flags?.wait) {
|
|
3429
4231
|
this.pendingUses.push(this.waitForUseGlobal(use));
|
|
@@ -3447,11 +4249,14 @@ var Engine = class _Engine {
|
|
|
3447
4249
|
Object.assign(this.globals, values);
|
|
3448
4250
|
}
|
|
3449
4251
|
registerFlag(name, handler = {}) {
|
|
4252
|
+
this.flagHandlers.set(name, handler);
|
|
4253
|
+
}
|
|
4254
|
+
registerBehaviorModifier(name, handler = {}) {
|
|
3450
4255
|
const reserved = /* @__PURE__ */ new Set(["important", "trusted", "debounce"]);
|
|
3451
4256
|
if (reserved.has(name)) {
|
|
3452
|
-
throw new Error(`
|
|
4257
|
+
throw new Error(`Behavior modifier '${name}' is reserved`);
|
|
3453
4258
|
}
|
|
3454
|
-
this.
|
|
4259
|
+
this.behaviorModifiers.set(name, handler);
|
|
3455
4260
|
}
|
|
3456
4261
|
getRegistryStats() {
|
|
3457
4262
|
return {
|
|
@@ -3559,7 +4364,6 @@ var Engine = class _Engine {
|
|
|
3559
4364
|
if (this.observer) {
|
|
3560
4365
|
return;
|
|
3561
4366
|
}
|
|
3562
|
-
this.observerRoot = root;
|
|
3563
4367
|
this.observerFlush = debounce(() => this.flushObserverQueue(), 10);
|
|
3564
4368
|
this.observer = new MutationObserver((mutations) => {
|
|
3565
4369
|
for (const mutation of mutations) {
|
|
@@ -3589,7 +4393,6 @@ var Engine = class _Engine {
|
|
|
3589
4393
|
disconnectObserver() {
|
|
3590
4394
|
this.observer?.disconnect();
|
|
3591
4395
|
this.observer = void 0;
|
|
3592
|
-
this.observerRoot = void 0;
|
|
3593
4396
|
this.pendingAdded.clear();
|
|
3594
4397
|
this.pendingRemoved.clear();
|
|
3595
4398
|
this.pendingUpdated.clear();
|
|
@@ -3618,6 +4421,8 @@ var Engine = class _Engine {
|
|
|
3618
4421
|
if (this.behaviorBindings.has(node)) {
|
|
3619
4422
|
this.runBehaviorDestruct(node);
|
|
3620
4423
|
}
|
|
4424
|
+
this.cleanupScopeWatchers(node);
|
|
4425
|
+
this.cleanupBehaviorListeners(node);
|
|
3621
4426
|
for (const child of Array.from(node.querySelectorAll("*"))) {
|
|
3622
4427
|
if (this.lifecycleBindings.has(child)) {
|
|
3623
4428
|
this.runDestruct(child);
|
|
@@ -3625,6 +4430,8 @@ var Engine = class _Engine {
|
|
|
3625
4430
|
if (this.behaviorBindings.has(child)) {
|
|
3626
4431
|
this.runBehaviorDestruct(child);
|
|
3627
4432
|
}
|
|
4433
|
+
this.cleanupScopeWatchers(child);
|
|
4434
|
+
this.cleanupBehaviorListeners(child);
|
|
3628
4435
|
}
|
|
3629
4436
|
}
|
|
3630
4437
|
handleAddedNode(node) {
|
|
@@ -3648,13 +4455,13 @@ var Engine = class _Engine {
|
|
|
3648
4455
|
}
|
|
3649
4456
|
async applyBehaviors(root) {
|
|
3650
4457
|
await this.waitForUses();
|
|
3651
|
-
if (this.behaviorRegistry.length
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
await this.reapplyBehaviorsForElement(element);
|
|
4458
|
+
if (this.behaviorRegistry.length > 0) {
|
|
4459
|
+
const elements = [root, ...Array.from(root.querySelectorAll("*"))];
|
|
4460
|
+
for (const element of elements) {
|
|
4461
|
+
await this.reapplyBehaviorsForElement(element);
|
|
4462
|
+
}
|
|
3657
4463
|
}
|
|
4464
|
+
this.flushAutoBindQueue();
|
|
3658
4465
|
}
|
|
3659
4466
|
async reapplyBehaviorsForElement(element) {
|
|
3660
4467
|
if (this.behaviorRegistry.length === 0) {
|
|
@@ -3686,15 +4493,18 @@ var Engine = class _Engine {
|
|
|
3686
4493
|
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3687
4494
|
this.applyBehaviorFunctions(element, scope, behavior.functions, rootScope);
|
|
3688
4495
|
await this.applyBehaviorDeclarations(element, scope, behavior.declarations, rootScope);
|
|
4496
|
+
await this.applyBehaviorModifierHook("onBind", behavior, element, scope, rootScope);
|
|
3689
4497
|
if (behavior.construct) {
|
|
3690
4498
|
await this.safeExecuteBlock(behavior.construct, scope, element, rootScope);
|
|
3691
4499
|
}
|
|
4500
|
+
await this.applyBehaviorModifierHook("onConstruct", behavior, element, scope, rootScope);
|
|
3692
4501
|
for (const onBlock of behavior.onBlocks) {
|
|
3693
4502
|
this.attachBehaviorOnHandler(
|
|
3694
4503
|
element,
|
|
3695
4504
|
onBlock.event,
|
|
3696
4505
|
onBlock.body,
|
|
3697
|
-
onBlock.
|
|
4506
|
+
onBlock.flags,
|
|
4507
|
+
onBlock.flagArgs,
|
|
3698
4508
|
onBlock.args,
|
|
3699
4509
|
behavior.id,
|
|
3700
4510
|
rootScope
|
|
@@ -3704,10 +4514,11 @@ var Engine = class _Engine {
|
|
|
3704
4514
|
}
|
|
3705
4515
|
unbindBehaviorForElement(behavior, element, scope, bound) {
|
|
3706
4516
|
bound.delete(behavior.id);
|
|
4517
|
+
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3707
4518
|
if (behavior.destruct) {
|
|
3708
|
-
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3709
4519
|
void this.safeExecuteBlock(behavior.destruct, scope, element, rootScope);
|
|
3710
4520
|
}
|
|
4521
|
+
void this.applyBehaviorModifierHook("onDestruct", behavior, element, scope, rootScope);
|
|
3711
4522
|
const listenerMap = this.behaviorListeners.get(element);
|
|
3712
4523
|
const listeners = listenerMap?.get(behavior.id);
|
|
3713
4524
|
if (listeners) {
|
|
@@ -3716,6 +4527,7 @@ var Engine = class _Engine {
|
|
|
3716
4527
|
}
|
|
3717
4528
|
listenerMap?.delete(behavior.id);
|
|
3718
4529
|
}
|
|
4530
|
+
void this.applyBehaviorModifierHook("onUnbind", behavior, element, scope, rootScope);
|
|
3719
4531
|
this.logDiagnostic("unbind", element, behavior);
|
|
3720
4532
|
}
|
|
3721
4533
|
runBehaviorDestruct(element) {
|
|
@@ -3725,11 +4537,15 @@ var Engine = class _Engine {
|
|
|
3725
4537
|
}
|
|
3726
4538
|
const scope = this.getScope(element);
|
|
3727
4539
|
for (const behavior of this.behaviorRegistry) {
|
|
3728
|
-
if (!bound.has(behavior.id) || !behavior.destruct) {
|
|
4540
|
+
if (!bound.has(behavior.id) || !behavior.destruct && !this.behaviorHasModifierHooks(behavior)) {
|
|
3729
4541
|
continue;
|
|
3730
4542
|
}
|
|
3731
4543
|
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3732
|
-
|
|
4544
|
+
if (behavior.destruct) {
|
|
4545
|
+
void this.safeExecuteBlock(behavior.destruct, scope, element, rootScope);
|
|
4546
|
+
}
|
|
4547
|
+
void this.applyBehaviorModifierHook("onDestruct", behavior, element, scope, rootScope);
|
|
4548
|
+
void this.applyBehaviorModifierHook("onUnbind", behavior, element, scope, rootScope);
|
|
3733
4549
|
}
|
|
3734
4550
|
}
|
|
3735
4551
|
attachAttributes(element) {
|
|
@@ -3813,6 +4629,7 @@ var Engine = class _Engine {
|
|
|
3813
4629
|
const fragment = element.content.cloneNode(true);
|
|
3814
4630
|
const roots = Array.from(fragment.children);
|
|
3815
4631
|
const itemScope = new Scope(scope);
|
|
4632
|
+
itemScope.isEachItem = true;
|
|
3816
4633
|
itemScope.setPath(`self.${binding.itemName}`, item);
|
|
3817
4634
|
if (binding.indexName) {
|
|
3818
4635
|
itemScope.setPath(`self.${binding.indexName}`, index);
|
|
@@ -3851,7 +4668,93 @@ var Engine = class _Engine {
|
|
|
3851
4668
|
if (name.includes(":to")) {
|
|
3852
4669
|
return "to";
|
|
3853
4670
|
}
|
|
3854
|
-
return "
|
|
4671
|
+
return "auto";
|
|
4672
|
+
}
|
|
4673
|
+
resolveBindConfig(element, expr, scope, direction) {
|
|
4674
|
+
if (direction !== "auto") {
|
|
4675
|
+
return {
|
|
4676
|
+
direction,
|
|
4677
|
+
seedFromScope: false,
|
|
4678
|
+
syncToScope: direction === "to" || direction === "both",
|
|
4679
|
+
deferToScope: false
|
|
4680
|
+
};
|
|
4681
|
+
}
|
|
4682
|
+
if (this.isInEachScope(scope)) {
|
|
4683
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: false };
|
|
4684
|
+
}
|
|
4685
|
+
if (this.isFormControl(element)) {
|
|
4686
|
+
if (this.hasScopeValue(scope, expr)) {
|
|
4687
|
+
return { direction: "both", seedFromScope: true, syncToScope: false, deferToScope: false };
|
|
4688
|
+
}
|
|
4689
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: true };
|
|
4690
|
+
}
|
|
4691
|
+
if (this.hasScopeValue(scope, expr)) {
|
|
4692
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: false };
|
|
4693
|
+
}
|
|
4694
|
+
if (this.hasElementValue(element)) {
|
|
4695
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: true };
|
|
4696
|
+
}
|
|
4697
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: false };
|
|
4698
|
+
}
|
|
4699
|
+
isFormControl(element) {
|
|
4700
|
+
return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement;
|
|
4701
|
+
}
|
|
4702
|
+
hasScopeValue(scope, expr) {
|
|
4703
|
+
const key = expr.trim();
|
|
4704
|
+
if (!key) {
|
|
4705
|
+
return false;
|
|
4706
|
+
}
|
|
4707
|
+
const value = scope.get(key);
|
|
4708
|
+
return value !== void 0 && value !== null;
|
|
4709
|
+
}
|
|
4710
|
+
hasElementValue(element) {
|
|
4711
|
+
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
|
|
4712
|
+
return element.value.length > 0;
|
|
4713
|
+
}
|
|
4714
|
+
return (element.textContent ?? "").trim().length > 0;
|
|
4715
|
+
}
|
|
4716
|
+
coerceInt(value) {
|
|
4717
|
+
if (value == null || value === "") {
|
|
4718
|
+
return value;
|
|
4719
|
+
}
|
|
4720
|
+
const num = typeof value === "number" ? value : Number.parseInt(String(value), 10);
|
|
4721
|
+
return Number.isNaN(num) ? value : num;
|
|
4722
|
+
}
|
|
4723
|
+
coerceFloat(value) {
|
|
4724
|
+
if (value == null || value === "") {
|
|
4725
|
+
return value;
|
|
4726
|
+
}
|
|
4727
|
+
const num = typeof value === "number" ? value : Number.parseFloat(String(value));
|
|
4728
|
+
return Number.isNaN(num) ? value : num;
|
|
4729
|
+
}
|
|
4730
|
+
isInEachScope(scope) {
|
|
4731
|
+
let cursor = scope;
|
|
4732
|
+
while (cursor) {
|
|
4733
|
+
if (cursor.isEachItem) {
|
|
4734
|
+
return true;
|
|
4735
|
+
}
|
|
4736
|
+
cursor = cursor.parent;
|
|
4737
|
+
}
|
|
4738
|
+
return false;
|
|
4739
|
+
}
|
|
4740
|
+
flushAutoBindQueue() {
|
|
4741
|
+
if (this.pendingAutoBindToScope.length === 0) {
|
|
4742
|
+
return;
|
|
4743
|
+
}
|
|
4744
|
+
const pending = this.pendingAutoBindToScope;
|
|
4745
|
+
this.pendingAutoBindToScope = [];
|
|
4746
|
+
for (const entry of pending) {
|
|
4747
|
+
if (!entry.element.isConnected) {
|
|
4748
|
+
continue;
|
|
4749
|
+
}
|
|
4750
|
+
if (this.hasScopeValue(entry.scope, entry.expr)) {
|
|
4751
|
+
continue;
|
|
4752
|
+
}
|
|
4753
|
+
if (!this.hasElementValue(entry.element)) {
|
|
4754
|
+
continue;
|
|
4755
|
+
}
|
|
4756
|
+
applyBindToScope(entry.element, entry.expr, entry.scope);
|
|
4757
|
+
}
|
|
3855
4758
|
}
|
|
3856
4759
|
hasVsnAttributes(element) {
|
|
3857
4760
|
return element.getAttributeNames().some((name) => name.startsWith("vsn-"));
|
|
@@ -3876,7 +4779,7 @@ var Engine = class _Engine {
|
|
|
3876
4779
|
}
|
|
3877
4780
|
return void 0;
|
|
3878
4781
|
}
|
|
3879
|
-
watch(scope, expr, handler) {
|
|
4782
|
+
watch(scope, expr, handler, element) {
|
|
3880
4783
|
const key = expr.trim();
|
|
3881
4784
|
if (!key) {
|
|
3882
4785
|
return;
|
|
@@ -3891,29 +4794,70 @@ var Engine = class _Engine {
|
|
|
3891
4794
|
}
|
|
3892
4795
|
if (target) {
|
|
3893
4796
|
target.on(key, handler);
|
|
4797
|
+
if (element) {
|
|
4798
|
+
this.trackScopeWatcher(element, target, "path", handler, key);
|
|
4799
|
+
}
|
|
3894
4800
|
return;
|
|
3895
4801
|
}
|
|
3896
4802
|
let cursor = scope;
|
|
3897
4803
|
while (cursor) {
|
|
3898
4804
|
cursor.on(key, handler);
|
|
4805
|
+
if (element) {
|
|
4806
|
+
this.trackScopeWatcher(element, cursor, "path", handler, key);
|
|
4807
|
+
}
|
|
3899
4808
|
cursor = cursor.parent;
|
|
3900
4809
|
}
|
|
3901
4810
|
}
|
|
3902
|
-
watchWithDebounce(scope, expr, handler, debounceMs) {
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
} else {
|
|
3906
|
-
this.watch(scope, expr, handler);
|
|
3907
|
-
}
|
|
4811
|
+
watchWithDebounce(scope, expr, handler, debounceMs, element) {
|
|
4812
|
+
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4813
|
+
this.watch(scope, expr, effectiveHandler, element);
|
|
3908
4814
|
}
|
|
3909
|
-
watchAllScopes(scope, handler, debounceMs) {
|
|
4815
|
+
watchAllScopes(scope, handler, debounceMs, element) {
|
|
3910
4816
|
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
3911
4817
|
let cursor = scope;
|
|
3912
4818
|
while (cursor) {
|
|
3913
4819
|
cursor.onAny(effectiveHandler);
|
|
4820
|
+
if (element) {
|
|
4821
|
+
this.trackScopeWatcher(element, cursor, "any", effectiveHandler);
|
|
4822
|
+
}
|
|
3914
4823
|
cursor = cursor.parent;
|
|
3915
4824
|
}
|
|
3916
4825
|
}
|
|
4826
|
+
trackScopeWatcher(element, scope, kind, handler, key) {
|
|
4827
|
+
const watchers = this.scopeWatchers.get(element) ?? [];
|
|
4828
|
+
watchers.push({ scope, kind, handler, ...key ? { key } : {} });
|
|
4829
|
+
this.scopeWatchers.set(element, watchers);
|
|
4830
|
+
}
|
|
4831
|
+
cleanupScopeWatchers(element) {
|
|
4832
|
+
const watchers = this.scopeWatchers.get(element);
|
|
4833
|
+
if (!watchers) {
|
|
4834
|
+
return;
|
|
4835
|
+
}
|
|
4836
|
+
for (const watcher of watchers) {
|
|
4837
|
+
if (watcher.kind === "any") {
|
|
4838
|
+
watcher.scope.offAny(watcher.handler);
|
|
4839
|
+
continue;
|
|
4840
|
+
}
|
|
4841
|
+
if (watcher.key) {
|
|
4842
|
+
watcher.scope.off(watcher.key, watcher.handler);
|
|
4843
|
+
}
|
|
4844
|
+
}
|
|
4845
|
+
this.scopeWatchers.delete(element);
|
|
4846
|
+
}
|
|
4847
|
+
cleanupBehaviorListeners(element) {
|
|
4848
|
+
const listenerMap = this.behaviorListeners.get(element);
|
|
4849
|
+
if (!listenerMap) {
|
|
4850
|
+
return;
|
|
4851
|
+
}
|
|
4852
|
+
for (const listeners of listenerMap.values()) {
|
|
4853
|
+
for (const listener of listeners) {
|
|
4854
|
+
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
4855
|
+
}
|
|
4856
|
+
}
|
|
4857
|
+
listenerMap.clear();
|
|
4858
|
+
this.behaviorListeners.delete(element);
|
|
4859
|
+
this.behaviorBindings.delete(element);
|
|
4860
|
+
}
|
|
3917
4861
|
parseOnAttribute(name, value) {
|
|
3918
4862
|
if (!name.startsWith("vsn-on:")) {
|
|
3919
4863
|
return null;
|
|
@@ -3923,111 +4867,56 @@ var Engine = class _Engine {
|
|
|
3923
4867
|
if (!event) {
|
|
3924
4868
|
return null;
|
|
3925
4869
|
}
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
return null;
|
|
3929
|
-
}
|
|
3930
|
-
let debounceMs;
|
|
3931
|
-
const modifiers = [];
|
|
3932
|
-
for (const flag of flags) {
|
|
3933
|
-
if (flag.startsWith("debounce")) {
|
|
3934
|
-
const match = flag.match(/debounce\((\d+)\)/);
|
|
3935
|
-
debounceMs = match ? Number(match[1]) : 200;
|
|
3936
|
-
continue;
|
|
3937
|
-
}
|
|
3938
|
-
modifiers.push(flag);
|
|
4870
|
+
if (event.includes(".")) {
|
|
4871
|
+
throw new Error("vsn:on does not support dot modifiers; use !flags instead");
|
|
3939
4872
|
}
|
|
3940
|
-
const
|
|
4873
|
+
const { flagMap, flagArgs } = this.parseInlineFlags(flags);
|
|
3941
4874
|
const config = {
|
|
3942
|
-
event
|
|
4875
|
+
event,
|
|
3943
4876
|
code: value,
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
...descriptor.keyModifiers.length > 0 ? { keyModifiers: descriptor.keyModifiers } : {}
|
|
4877
|
+
flags: flagMap,
|
|
4878
|
+
flagArgs
|
|
3947
4879
|
};
|
|
3948
4880
|
return config;
|
|
3949
4881
|
}
|
|
3950
|
-
|
|
3951
|
-
const
|
|
3952
|
-
const
|
|
3953
|
-
const
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
if (modifierSet.has(part)) {
|
|
3958
|
-
modifiers.push(part);
|
|
3959
|
-
} else {
|
|
3960
|
-
keyModifiers.push(part);
|
|
4882
|
+
parseInlineFlags(parts) {
|
|
4883
|
+
const flagMap = {};
|
|
4884
|
+
const flagArgs = {};
|
|
4885
|
+
for (const raw of parts) {
|
|
4886
|
+
const trimmed = raw.trim();
|
|
4887
|
+
if (!trimmed) {
|
|
4888
|
+
continue;
|
|
3961
4889
|
}
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
}
|
|
3965
|
-
matchesKeyModifiers(event, keyModifiers) {
|
|
3966
|
-
if (!keyModifiers || keyModifiers.length === 0) {
|
|
3967
|
-
return true;
|
|
3968
|
-
}
|
|
3969
|
-
if (!(event instanceof KeyboardEvent)) {
|
|
3970
|
-
return false;
|
|
3971
|
-
}
|
|
3972
|
-
const modifierChecks = {
|
|
3973
|
-
shift: event.shiftKey,
|
|
3974
|
-
ctrl: event.ctrlKey,
|
|
3975
|
-
control: event.ctrlKey,
|
|
3976
|
-
alt: event.altKey,
|
|
3977
|
-
meta: event.metaKey
|
|
3978
|
-
};
|
|
3979
|
-
const keyAliases = {
|
|
3980
|
-
esc: "escape",
|
|
3981
|
-
escape: "escape",
|
|
3982
|
-
enter: "enter",
|
|
3983
|
-
tab: "tab",
|
|
3984
|
-
space: "space",
|
|
3985
|
-
spacebar: "space",
|
|
3986
|
-
up: "arrowup",
|
|
3987
|
-
down: "arrowdown",
|
|
3988
|
-
left: "arrowleft",
|
|
3989
|
-
right: "arrowright",
|
|
3990
|
-
arrowup: "arrowup",
|
|
3991
|
-
arrowdown: "arrowdown",
|
|
3992
|
-
arrowleft: "arrowleft",
|
|
3993
|
-
arrowright: "arrowright",
|
|
3994
|
-
delete: "delete",
|
|
3995
|
-
backspace: "backspace"
|
|
3996
|
-
};
|
|
3997
|
-
let key = event.key?.toLowerCase() ?? "";
|
|
3998
|
-
if (key === " ") {
|
|
3999
|
-
key = "space";
|
|
4000
|
-
}
|
|
4001
|
-
for (const rawModifier of keyModifiers) {
|
|
4002
|
-
const modifier = rawModifier.toLowerCase();
|
|
4003
|
-
if (modifier in modifierChecks) {
|
|
4004
|
-
if (!modifierChecks[modifier]) {
|
|
4005
|
-
return false;
|
|
4006
|
-
}
|
|
4890
|
+
const match = trimmed.match(/^([a-zA-Z][\w-]*)(?:\((.+)\))?$/);
|
|
4891
|
+
if (!match) {
|
|
4007
4892
|
continue;
|
|
4008
4893
|
}
|
|
4009
|
-
const
|
|
4010
|
-
if (
|
|
4011
|
-
|
|
4894
|
+
const name = match[1] ?? "";
|
|
4895
|
+
if (!name) {
|
|
4896
|
+
continue;
|
|
4897
|
+
}
|
|
4898
|
+
if (!this.flagHandlers.has(name)) {
|
|
4899
|
+
throw new Error(`Unknown flag ${name}`);
|
|
4900
|
+
}
|
|
4901
|
+
flagMap[name] = true;
|
|
4902
|
+
if (match[2] !== void 0) {
|
|
4903
|
+
flagArgs[name] = this.parseInlineFlagArg(match[2]);
|
|
4012
4904
|
}
|
|
4013
4905
|
}
|
|
4014
|
-
return
|
|
4906
|
+
return { flagMap, flagArgs };
|
|
4015
4907
|
}
|
|
4016
|
-
|
|
4017
|
-
|
|
4908
|
+
parseInlineFlagArg(raw) {
|
|
4909
|
+
const trimmed = raw.trim();
|
|
4910
|
+
if (trimmed === "true") {
|
|
4018
4911
|
return true;
|
|
4019
4912
|
}
|
|
4020
|
-
|
|
4021
|
-
if (!target || !(target instanceof Node)) {
|
|
4022
|
-
return !modifiers.includes("self") && !modifiers.includes("outside");
|
|
4023
|
-
}
|
|
4024
|
-
if (modifiers.includes("self") && target !== element) {
|
|
4913
|
+
if (trimmed === "false") {
|
|
4025
4914
|
return false;
|
|
4026
4915
|
}
|
|
4027
|
-
if (
|
|
4028
|
-
return
|
|
4916
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
4917
|
+
return Number(trimmed);
|
|
4029
4918
|
}
|
|
4030
|
-
return
|
|
4919
|
+
return trimmed;
|
|
4031
4920
|
}
|
|
4032
4921
|
describeElement(element) {
|
|
4033
4922
|
const tag = element.tagName.toLowerCase();
|
|
@@ -4069,51 +4958,50 @@ var Engine = class _Engine {
|
|
|
4069
4958
|
}
|
|
4070
4959
|
}
|
|
4071
4960
|
attachOnHandler(element, config) {
|
|
4072
|
-
const options = this.
|
|
4073
|
-
|
|
4961
|
+
const { listenerTarget, options, debounceMs } = this.getEventBindingConfig(
|
|
4962
|
+
element,
|
|
4963
|
+
config.flags,
|
|
4964
|
+
config.flagArgs
|
|
4965
|
+
);
|
|
4074
4966
|
let effectiveHandler;
|
|
4075
4967
|
const handler = async (event) => {
|
|
4076
4968
|
if (!element.isConnected) {
|
|
4077
4969
|
listenerTarget.removeEventListener(config.event, effectiveHandler, options);
|
|
4078
4970
|
return;
|
|
4079
4971
|
}
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
}
|
|
4083
|
-
if (!this.matchesTargetModifiers(element, event, config.modifiers)) {
|
|
4972
|
+
const scope = this.getScope(element);
|
|
4973
|
+
if (!this.applyEventFlagBefore(element, scope, config.flags, config.flagArgs, event)) {
|
|
4084
4974
|
return;
|
|
4085
4975
|
}
|
|
4086
|
-
this.applyEventModifiers(event, config.modifiers);
|
|
4087
|
-
const scope = this.getScope(element);
|
|
4088
4976
|
try {
|
|
4089
4977
|
await this.execute(config.code, scope, element);
|
|
4090
4978
|
this.evaluate(element);
|
|
4091
4979
|
} catch (error) {
|
|
4092
4980
|
this.emitError(element, error);
|
|
4981
|
+
} finally {
|
|
4982
|
+
this.applyEventFlagAfter(element, scope, config.flags, config.flagArgs, event);
|
|
4093
4983
|
}
|
|
4094
4984
|
};
|
|
4095
|
-
effectiveHandler =
|
|
4985
|
+
effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4096
4986
|
listenerTarget.addEventListener(config.event, effectiveHandler, options);
|
|
4097
4987
|
}
|
|
4098
|
-
attachBehaviorOnHandler(element, event, body,
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4988
|
+
attachBehaviorOnHandler(element, event, body, flags, flagArgs, args, behaviorId, rootScope) {
|
|
4989
|
+
if (event.includes(".")) {
|
|
4990
|
+
throw new Error("vsn:on does not support dot modifiers; use !flags instead");
|
|
4991
|
+
}
|
|
4992
|
+
const { listenerTarget, options, debounceMs } = this.getEventBindingConfig(element, flags, flagArgs);
|
|
4102
4993
|
const handler = async (evt) => {
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
}
|
|
4106
|
-
if (!this.matchesTargetModifiers(element, evt, combinedModifiers)) {
|
|
4994
|
+
const scope = this.getScope(element);
|
|
4995
|
+
if (!this.applyEventFlagBefore(element, scope, flags, flagArgs, evt)) {
|
|
4107
4996
|
return;
|
|
4108
4997
|
}
|
|
4109
|
-
this.applyEventModifiers(evt, combinedModifiers);
|
|
4110
|
-
const scope = this.getScope(element);
|
|
4111
4998
|
const previousValues = /* @__PURE__ */ new Map();
|
|
4112
4999
|
if (args && args.length > 0) {
|
|
4113
5000
|
const argName = args[0];
|
|
4114
5001
|
if (argName) {
|
|
4115
5002
|
previousValues.set(argName, scope.getPath(argName));
|
|
4116
|
-
|
|
5003
|
+
const [nextArg] = this.applyEventFlagArgTransforms(element, scope, flags, flagArgs, evt);
|
|
5004
|
+
scope.setPath(argName, nextArg);
|
|
4117
5005
|
}
|
|
4118
5006
|
}
|
|
4119
5007
|
let failed = false;
|
|
@@ -4126,16 +5014,17 @@ var Engine = class _Engine {
|
|
|
4126
5014
|
for (const [name, value] of previousValues.entries()) {
|
|
4127
5015
|
scope.setPath(name, value);
|
|
4128
5016
|
}
|
|
5017
|
+
this.applyEventFlagAfter(element, scope, flags, flagArgs, evt);
|
|
4129
5018
|
}
|
|
4130
5019
|
if (!failed) {
|
|
4131
5020
|
this.evaluate(element);
|
|
4132
5021
|
}
|
|
4133
5022
|
};
|
|
4134
|
-
const
|
|
4135
|
-
listenerTarget.addEventListener(
|
|
5023
|
+
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
5024
|
+
listenerTarget.addEventListener(event, effectiveHandler, options);
|
|
4136
5025
|
const listenerMap = this.behaviorListeners.get(element) ?? /* @__PURE__ */ new Map();
|
|
4137
5026
|
const listeners = listenerMap.get(behaviorId) ?? [];
|
|
4138
|
-
listeners.push({ target: listenerTarget, event
|
|
5027
|
+
listeners.push({ target: listenerTarget, event, handler: effectiveHandler, options });
|
|
4139
5028
|
listenerMap.set(behaviorId, listeners);
|
|
4140
5029
|
this.behaviorListeners.set(element, listenerMap);
|
|
4141
5030
|
}
|
|
@@ -4166,33 +5055,158 @@ var Engine = class _Engine {
|
|
|
4166
5055
|
Promise.resolve().then(handler);
|
|
4167
5056
|
}
|
|
4168
5057
|
}
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
5058
|
+
getEventBindingConfig(element, flags, flagArgs) {
|
|
5059
|
+
let listenerTarget = element;
|
|
5060
|
+
let options = {};
|
|
5061
|
+
let debounceMs;
|
|
5062
|
+
for (const name of Object.keys(flags)) {
|
|
5063
|
+
const handler = this.flagHandlers.get(name);
|
|
5064
|
+
if (!handler?.onEventBind) {
|
|
5065
|
+
continue;
|
|
5066
|
+
}
|
|
5067
|
+
const patch = handler.onEventBind({
|
|
5068
|
+
name,
|
|
5069
|
+
args: flagArgs[name],
|
|
5070
|
+
element,
|
|
5071
|
+
scope: this.getScope(element),
|
|
5072
|
+
rootScope: void 0,
|
|
5073
|
+
event: void 0,
|
|
5074
|
+
engine: this
|
|
5075
|
+
});
|
|
5076
|
+
if (!patch) {
|
|
5077
|
+
continue;
|
|
5078
|
+
}
|
|
5079
|
+
if (patch.listenerTarget) {
|
|
5080
|
+
listenerTarget = patch.listenerTarget;
|
|
5081
|
+
}
|
|
5082
|
+
if (patch.options) {
|
|
5083
|
+
options = { ...options, ...patch.options };
|
|
5084
|
+
}
|
|
5085
|
+
if (patch.debounceMs !== void 0) {
|
|
5086
|
+
debounceMs = patch.debounceMs;
|
|
5087
|
+
}
|
|
5088
|
+
}
|
|
5089
|
+
return {
|
|
5090
|
+
listenerTarget,
|
|
5091
|
+
...Object.keys(options).length > 0 ? { options } : {},
|
|
5092
|
+
...debounceMs !== void 0 ? { debounceMs } : {}
|
|
5093
|
+
};
|
|
5094
|
+
}
|
|
5095
|
+
applyEventFlagBefore(element, scope, flags, flagArgs, event) {
|
|
5096
|
+
for (const name of Object.keys(flags)) {
|
|
5097
|
+
const handler = this.flagHandlers.get(name);
|
|
5098
|
+
if (!handler?.onEventBefore) {
|
|
5099
|
+
continue;
|
|
5100
|
+
}
|
|
5101
|
+
const result = handler.onEventBefore({
|
|
5102
|
+
name,
|
|
5103
|
+
args: flagArgs[name],
|
|
5104
|
+
element,
|
|
5105
|
+
scope,
|
|
5106
|
+
rootScope: void 0,
|
|
5107
|
+
event,
|
|
5108
|
+
engine: this
|
|
5109
|
+
});
|
|
5110
|
+
if (result === false) {
|
|
5111
|
+
return false;
|
|
5112
|
+
}
|
|
4172
5113
|
}
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
5114
|
+
return true;
|
|
5115
|
+
}
|
|
5116
|
+
applyEventFlagAfter(element, scope, flags, flagArgs, event) {
|
|
5117
|
+
for (const name of Object.keys(flags)) {
|
|
5118
|
+
const handler = this.flagHandlers.get(name);
|
|
5119
|
+
if (!handler?.onEventAfter) {
|
|
5120
|
+
continue;
|
|
4178
5121
|
}
|
|
5122
|
+
handler.onEventAfter({
|
|
5123
|
+
name,
|
|
5124
|
+
args: flagArgs[name],
|
|
5125
|
+
element,
|
|
5126
|
+
scope,
|
|
5127
|
+
rootScope: void 0,
|
|
5128
|
+
event,
|
|
5129
|
+
engine: this
|
|
5130
|
+
});
|
|
4179
5131
|
}
|
|
4180
5132
|
}
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
5133
|
+
applyEventFlagArgTransforms(element, scope, flags, flagArgs, event) {
|
|
5134
|
+
let args = [event];
|
|
5135
|
+
for (const name of Object.keys(flags)) {
|
|
5136
|
+
const handler = this.flagHandlers.get(name);
|
|
5137
|
+
if (!handler?.transformEventArgs) {
|
|
5138
|
+
continue;
|
|
5139
|
+
}
|
|
5140
|
+
const nextArgs = handler.transformEventArgs(
|
|
5141
|
+
{
|
|
5142
|
+
name,
|
|
5143
|
+
args: flagArgs[name],
|
|
5144
|
+
element,
|
|
5145
|
+
scope,
|
|
5146
|
+
rootScope: void 0,
|
|
5147
|
+
event,
|
|
5148
|
+
engine: this
|
|
5149
|
+
},
|
|
5150
|
+
args
|
|
5151
|
+
);
|
|
5152
|
+
if (Array.isArray(nextArgs)) {
|
|
5153
|
+
args = nextArgs;
|
|
5154
|
+
}
|
|
5155
|
+
}
|
|
5156
|
+
return args;
|
|
5157
|
+
}
|
|
5158
|
+
matchesKeyFlag(event, flag) {
|
|
5159
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
5160
|
+
return false;
|
|
5161
|
+
}
|
|
5162
|
+
const modifierChecks = {
|
|
5163
|
+
shift: event.shiftKey,
|
|
5164
|
+
ctrl: event.ctrlKey,
|
|
5165
|
+
alt: event.altKey,
|
|
5166
|
+
meta: event.metaKey
|
|
5167
|
+
};
|
|
5168
|
+
if (flag in modifierChecks) {
|
|
5169
|
+
return modifierChecks[flag] ?? false;
|
|
4184
5170
|
}
|
|
4185
|
-
const
|
|
4186
|
-
|
|
4187
|
-
|
|
5171
|
+
const keyAliases = {
|
|
5172
|
+
escape: "escape",
|
|
5173
|
+
esc: "escape",
|
|
5174
|
+
enter: "enter",
|
|
5175
|
+
tab: "tab",
|
|
5176
|
+
space: "space",
|
|
5177
|
+
spacebar: "space",
|
|
5178
|
+
up: "arrowup",
|
|
5179
|
+
down: "arrowdown",
|
|
5180
|
+
left: "arrowleft",
|
|
5181
|
+
right: "arrowright",
|
|
5182
|
+
arrowup: "arrowup",
|
|
5183
|
+
arrowdown: "arrowdown",
|
|
5184
|
+
arrowleft: "arrowleft",
|
|
5185
|
+
arrowright: "arrowright",
|
|
5186
|
+
delete: "delete",
|
|
5187
|
+
backspace: "backspace"
|
|
5188
|
+
};
|
|
5189
|
+
let key = event.key?.toLowerCase() ?? "";
|
|
5190
|
+
if (key === " ") {
|
|
5191
|
+
key = "space";
|
|
4188
5192
|
}
|
|
4189
|
-
|
|
4190
|
-
|
|
5193
|
+
const expectedKey = keyAliases[flag] ?? flag;
|
|
5194
|
+
return key === expectedKey;
|
|
5195
|
+
}
|
|
5196
|
+
async withExecutionElement(element, fn) {
|
|
5197
|
+
if (!element) {
|
|
5198
|
+
await fn();
|
|
5199
|
+
return;
|
|
4191
5200
|
}
|
|
4192
|
-
|
|
4193
|
-
|
|
5201
|
+
this.executionStack.push(element);
|
|
5202
|
+
try {
|
|
5203
|
+
await fn();
|
|
5204
|
+
} finally {
|
|
5205
|
+
this.executionStack.pop();
|
|
4194
5206
|
}
|
|
4195
|
-
|
|
5207
|
+
}
|
|
5208
|
+
getCurrentElement() {
|
|
5209
|
+
return this.executionStack[this.executionStack.length - 1];
|
|
4196
5210
|
}
|
|
4197
5211
|
async execute(code, scope, element, rootScope) {
|
|
4198
5212
|
let block = this.codeCache.get(code);
|
|
@@ -4200,22 +5214,26 @@ var Engine = class _Engine {
|
|
|
4200
5214
|
block = Parser.parseInline(code);
|
|
4201
5215
|
this.codeCache.set(code, block);
|
|
4202
5216
|
}
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
5217
|
+
await this.withExecutionElement(element, async () => {
|
|
5218
|
+
const context = {
|
|
5219
|
+
scope,
|
|
5220
|
+
rootScope,
|
|
5221
|
+
globals: this.globals,
|
|
5222
|
+
...element ? { element } : {}
|
|
5223
|
+
};
|
|
5224
|
+
await block.evaluate(context);
|
|
5225
|
+
});
|
|
4210
5226
|
}
|
|
4211
5227
|
async executeBlock(block, scope, element, rootScope) {
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
5228
|
+
await this.withExecutionElement(element, async () => {
|
|
5229
|
+
const context = {
|
|
5230
|
+
scope,
|
|
5231
|
+
rootScope,
|
|
5232
|
+
globals: this.globals,
|
|
5233
|
+
...element ? { element } : {}
|
|
5234
|
+
};
|
|
5235
|
+
await block.evaluate(context);
|
|
5236
|
+
});
|
|
4219
5237
|
}
|
|
4220
5238
|
async safeExecute(code, scope, element, rootScope) {
|
|
4221
5239
|
try {
|
|
@@ -4238,15 +5256,26 @@ var Engine = class _Engine {
|
|
|
4238
5256
|
collectBehavior(behavior, parentSelector, rootSelectorOverride) {
|
|
4239
5257
|
const selector = parentSelector ? `${parentSelector} ${behavior.selector.selectorText}` : behavior.selector.selectorText;
|
|
4240
5258
|
const rootSelector = rootSelectorOverride ?? (parentSelector ?? behavior.selector.selectorText);
|
|
5259
|
+
const behaviorHash = this.hashBehavior(behavior);
|
|
5260
|
+
const hash = `${selector}::${rootSelector}::${behaviorHash}`;
|
|
5261
|
+
if (this.behaviorRegistryHashes.has(hash)) {
|
|
5262
|
+
return;
|
|
5263
|
+
}
|
|
4241
5264
|
const cached = this.getCachedBehavior(behavior);
|
|
4242
|
-
|
|
5265
|
+
const entry = {
|
|
4243
5266
|
id: this.behaviorId += 1,
|
|
5267
|
+
hash,
|
|
4244
5268
|
selector,
|
|
4245
5269
|
rootSelector,
|
|
4246
5270
|
specificity: this.computeSpecificity(selector),
|
|
4247
5271
|
order: this.behaviorRegistry.length,
|
|
4248
|
-
|
|
4249
|
-
|
|
5272
|
+
flags: behavior.flags ?? {},
|
|
5273
|
+
flagArgs: behavior.flagArgs ?? {},
|
|
5274
|
+
...cached,
|
|
5275
|
+
...parentSelector ? { parentSelector } : {}
|
|
5276
|
+
};
|
|
5277
|
+
this.behaviorRegistry.push(entry);
|
|
5278
|
+
this.behaviorRegistryHashes.add(hash);
|
|
4250
5279
|
this.collectNestedBehaviors(behavior.body, selector, rootSelector);
|
|
4251
5280
|
}
|
|
4252
5281
|
collectNestedBehaviors(block, parentSelector, rootSelector) {
|
|
@@ -4319,7 +5348,8 @@ var Engine = class _Engine {
|
|
|
4319
5348
|
blocks.push({
|
|
4320
5349
|
event: statement.eventName,
|
|
4321
5350
|
body: statement.body,
|
|
4322
|
-
|
|
5351
|
+
flags: statement.flags,
|
|
5352
|
+
flagArgs: statement.flagArgs,
|
|
4323
5353
|
args: statement.args
|
|
4324
5354
|
});
|
|
4325
5355
|
}
|
|
@@ -4384,6 +5414,8 @@ var Engine = class _Engine {
|
|
|
4384
5414
|
return {
|
|
4385
5415
|
type,
|
|
4386
5416
|
selector: node.selector?.selectorText ?? "",
|
|
5417
|
+
flags: node.flags ?? {},
|
|
5418
|
+
flagArgs: node.flagArgs ?? {},
|
|
4387
5419
|
body: this.normalizeNode(node.body)
|
|
4388
5420
|
};
|
|
4389
5421
|
}
|
|
@@ -4401,6 +5433,8 @@ var Engine = class _Engine {
|
|
|
4401
5433
|
type,
|
|
4402
5434
|
eventName: node.eventName ?? "",
|
|
4403
5435
|
args: Array.isArray(node.args) ? node.args : [],
|
|
5436
|
+
flags: node.flags ?? {},
|
|
5437
|
+
flagArgs: node.flagArgs ?? {},
|
|
4404
5438
|
body: this.normalizeNode(node.body)
|
|
4405
5439
|
};
|
|
4406
5440
|
}
|
|
@@ -4418,21 +5452,9 @@ var Engine = class _Engine {
|
|
|
4418
5452
|
return {
|
|
4419
5453
|
type,
|
|
4420
5454
|
target: this.normalizeNode(node.target),
|
|
4421
|
-
value: this.normalizeNode(node.value)
|
|
4422
|
-
};
|
|
4423
|
-
}
|
|
4424
|
-
if (type === "StateBlock") {
|
|
4425
|
-
return {
|
|
4426
|
-
type,
|
|
4427
|
-
entries: Array.isArray(node.entries) ? node.entries.map((entry) => this.normalizeNode(entry)) : []
|
|
4428
|
-
};
|
|
4429
|
-
}
|
|
4430
|
-
if (type === "StateEntry") {
|
|
4431
|
-
return {
|
|
4432
|
-
type,
|
|
4433
|
-
name: node.name ?? "",
|
|
4434
5455
|
value: this.normalizeNode(node.value),
|
|
4435
|
-
|
|
5456
|
+
operator: node.operator ?? "",
|
|
5457
|
+
prefix: Boolean(node.prefix)
|
|
4436
5458
|
};
|
|
4437
5459
|
}
|
|
4438
5460
|
if (type === "FunctionDeclaration") {
|
|
@@ -4466,6 +5488,15 @@ var Engine = class _Engine {
|
|
|
4466
5488
|
value: this.normalizeNode(node.value ?? null)
|
|
4467
5489
|
};
|
|
4468
5490
|
}
|
|
5491
|
+
if (type === "Assert") {
|
|
5492
|
+
return {
|
|
5493
|
+
type,
|
|
5494
|
+
test: this.normalizeNode(node.test)
|
|
5495
|
+
};
|
|
5496
|
+
}
|
|
5497
|
+
if (type === "Break" || type === "Continue") {
|
|
5498
|
+
return { type };
|
|
5499
|
+
}
|
|
4469
5500
|
if (type === "If") {
|
|
4470
5501
|
return {
|
|
4471
5502
|
type,
|
|
@@ -4490,6 +5521,15 @@ var Engine = class _Engine {
|
|
|
4490
5521
|
body: this.normalizeNode(node.body)
|
|
4491
5522
|
};
|
|
4492
5523
|
}
|
|
5524
|
+
if (type === "ForEach") {
|
|
5525
|
+
return {
|
|
5526
|
+
type,
|
|
5527
|
+
kind: node.kind ?? "of",
|
|
5528
|
+
target: this.normalizeNode(node.target),
|
|
5529
|
+
iterable: this.normalizeNode(node.iterable),
|
|
5530
|
+
body: this.normalizeNode(node.body)
|
|
5531
|
+
};
|
|
5532
|
+
}
|
|
4493
5533
|
if (type === "Try") {
|
|
4494
5534
|
return {
|
|
4495
5535
|
type,
|
|
@@ -4612,7 +5652,9 @@ var Engine = class _Engine {
|
|
|
4612
5652
|
globals: this.globals,
|
|
4613
5653
|
element,
|
|
4614
5654
|
returnValue: void 0,
|
|
4615
|
-
returning: false
|
|
5655
|
+
returning: false,
|
|
5656
|
+
breaking: false,
|
|
5657
|
+
continuing: false
|
|
4616
5658
|
};
|
|
4617
5659
|
const previousValues = /* @__PURE__ */ new Map();
|
|
4618
5660
|
await this.applyFunctionParams(callScope, declaration.params, previousValues, context, args);
|
|
@@ -4663,6 +5705,7 @@ var Engine = class _Engine {
|
|
|
4663
5705
|
const context = { scope, rootScope, element };
|
|
4664
5706
|
const operator = declaration.operator;
|
|
4665
5707
|
const debounceMs = declaration.flags.debounce ? declaration.flagArgs.debounce ?? 200 : void 0;
|
|
5708
|
+
const transform = (value) => this.applyCustomFlagTransforms(value, element, scope, declaration);
|
|
4666
5709
|
const importantKey = this.getImportantKey(declaration);
|
|
4667
5710
|
if (!declaration.flags.important && importantKey && this.isImportant(element, importantKey)) {
|
|
4668
5711
|
return;
|
|
@@ -4673,7 +5716,8 @@ var Engine = class _Engine {
|
|
|
4673
5716
|
this.applyCustomFlags(element, scope, declaration);
|
|
4674
5717
|
if (declaration.target instanceof IdentifierExpression) {
|
|
4675
5718
|
const value = await declaration.value.evaluate(context);
|
|
4676
|
-
|
|
5719
|
+
const transformed = this.applyCustomFlagTransforms(value, element, scope, declaration);
|
|
5720
|
+
scope.setPath(declaration.target.name, transformed);
|
|
4677
5721
|
if (declaration.flags.important && importantKey) {
|
|
4678
5722
|
this.markImportant(element, importantKey);
|
|
4679
5723
|
}
|
|
@@ -4686,7 +5730,7 @@ var Engine = class _Engine {
|
|
|
4686
5730
|
const exprIdentifier = declaration.value instanceof IdentifierExpression ? declaration.value.name : void 0;
|
|
4687
5731
|
if (operator === ":>") {
|
|
4688
5732
|
if (exprIdentifier) {
|
|
4689
|
-
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope);
|
|
5733
|
+
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope, transform);
|
|
4690
5734
|
}
|
|
4691
5735
|
if (declaration.flags.important && importantKey) {
|
|
4692
5736
|
this.markImportant(element, importantKey);
|
|
@@ -4694,11 +5738,12 @@ var Engine = class _Engine {
|
|
|
4694
5738
|
return;
|
|
4695
5739
|
}
|
|
4696
5740
|
if (operator === ":=" && exprIdentifier) {
|
|
4697
|
-
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope);
|
|
5741
|
+
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope, transform);
|
|
4698
5742
|
}
|
|
4699
5743
|
if (!exprIdentifier) {
|
|
4700
5744
|
const value = await declaration.value.evaluate(context);
|
|
4701
|
-
this.
|
|
5745
|
+
const transformed = this.applyCustomFlagTransforms(value, element, scope, declaration);
|
|
5746
|
+
this.setDirectiveValue(element, target, transformed, declaration.flags.trusted);
|
|
4702
5747
|
const shouldWatch2 = operator === ":<" || operator === ":=";
|
|
4703
5748
|
if (shouldWatch2) {
|
|
4704
5749
|
this.applyDirectiveFromExpression(
|
|
@@ -4748,6 +5793,63 @@ var Engine = class _Engine {
|
|
|
4748
5793
|
});
|
|
4749
5794
|
}
|
|
4750
5795
|
}
|
|
5796
|
+
applyCustomFlagTransforms(value, element, scope, declaration) {
|
|
5797
|
+
if (this.flagHandlers.size === 0) {
|
|
5798
|
+
return value;
|
|
5799
|
+
}
|
|
5800
|
+
let nextValue = value;
|
|
5801
|
+
for (const [name, handler] of this.flagHandlers) {
|
|
5802
|
+
if (!declaration.flags[name] || !handler.transformValue) {
|
|
5803
|
+
continue;
|
|
5804
|
+
}
|
|
5805
|
+
nextValue = handler.transformValue(
|
|
5806
|
+
{
|
|
5807
|
+
name,
|
|
5808
|
+
args: declaration.flagArgs[name],
|
|
5809
|
+
element,
|
|
5810
|
+
scope,
|
|
5811
|
+
declaration
|
|
5812
|
+
},
|
|
5813
|
+
nextValue
|
|
5814
|
+
);
|
|
5815
|
+
}
|
|
5816
|
+
return nextValue;
|
|
5817
|
+
}
|
|
5818
|
+
async applyBehaviorModifierHook(hook, behavior, element, scope, rootScope) {
|
|
5819
|
+
if (this.behaviorModifiers.size === 0) {
|
|
5820
|
+
return;
|
|
5821
|
+
}
|
|
5822
|
+
for (const [name, handler] of this.behaviorModifiers) {
|
|
5823
|
+
if (!behavior.flags?.[name]) {
|
|
5824
|
+
continue;
|
|
5825
|
+
}
|
|
5826
|
+
const callback = handler[hook];
|
|
5827
|
+
if (!callback) {
|
|
5828
|
+
continue;
|
|
5829
|
+
}
|
|
5830
|
+
await callback({
|
|
5831
|
+
name,
|
|
5832
|
+
args: behavior.flagArgs?.[name],
|
|
5833
|
+
element,
|
|
5834
|
+
scope,
|
|
5835
|
+
rootScope,
|
|
5836
|
+
behavior,
|
|
5837
|
+
engine: this
|
|
5838
|
+
});
|
|
5839
|
+
}
|
|
5840
|
+
}
|
|
5841
|
+
behaviorHasModifierHooks(behavior) {
|
|
5842
|
+
if (this.behaviorModifiers.size === 0) {
|
|
5843
|
+
return false;
|
|
5844
|
+
}
|
|
5845
|
+
const flags = behavior.flags ?? {};
|
|
5846
|
+
for (const name of Object.keys(flags)) {
|
|
5847
|
+
if (flags[name] && this.behaviorModifiers.has(name)) {
|
|
5848
|
+
return true;
|
|
5849
|
+
}
|
|
5850
|
+
}
|
|
5851
|
+
return false;
|
|
5852
|
+
}
|
|
4751
5853
|
applyDirectiveFromScope(element, target, expr, scope, trusted, debounceMs, watch = true, rootScope) {
|
|
4752
5854
|
if (target.kind === "attr" && target.name === "html" && element instanceof HTMLElement) {
|
|
4753
5855
|
const handler2 = () => {
|
|
@@ -4764,7 +5866,7 @@ var Engine = class _Engine {
|
|
|
4764
5866
|
const useRoot = expr.startsWith("root.") && rootScope;
|
|
4765
5867
|
const sourceScope = useRoot ? rootScope : scope;
|
|
4766
5868
|
const watchExpr = useRoot ? expr.slice("root.".length) : expr;
|
|
4767
|
-
this.watchWithDebounce(sourceScope, watchExpr, handler2, debounceMs);
|
|
5869
|
+
this.watchWithDebounce(sourceScope, watchExpr, handler2, debounceMs, element);
|
|
4768
5870
|
}
|
|
4769
5871
|
return;
|
|
4770
5872
|
}
|
|
@@ -4783,7 +5885,7 @@ var Engine = class _Engine {
|
|
|
4783
5885
|
const useRoot = expr.startsWith("root.") && rootScope;
|
|
4784
5886
|
const sourceScope = useRoot ? rootScope : scope;
|
|
4785
5887
|
const watchExpr = useRoot ? expr.slice("root.".length) : expr;
|
|
4786
|
-
this.watchWithDebounce(sourceScope, watchExpr, handler, debounceMs);
|
|
5888
|
+
this.watchWithDebounce(sourceScope, watchExpr, handler, debounceMs, element);
|
|
4787
5889
|
}
|
|
4788
5890
|
}
|
|
4789
5891
|
applyDirectiveFromExpression(element, target, expr, scope, trusted, debounceMs, rootScope) {
|
|
@@ -4795,45 +5897,49 @@ var Engine = class _Engine {
|
|
|
4795
5897
|
void handler();
|
|
4796
5898
|
this.watchAllScopes(scope, () => {
|
|
4797
5899
|
void handler();
|
|
4798
|
-
}, debounceMs);
|
|
5900
|
+
}, debounceMs, element);
|
|
4799
5901
|
}
|
|
4800
|
-
applyDirectiveToScope(element, target, expr, scope, debounceMs, rootScope) {
|
|
5902
|
+
applyDirectiveToScope(element, target, expr, scope, debounceMs, rootScope, transform) {
|
|
4801
5903
|
const useRoot = expr.startsWith("root.") && rootScope;
|
|
4802
5904
|
const targetScope = useRoot ? rootScope : scope;
|
|
4803
5905
|
const targetExpr = useRoot ? `self.${expr.slice("root.".length)}` : expr;
|
|
4804
5906
|
if (target.kind === "attr" && target.name === "value") {
|
|
4805
|
-
this.applyValueBindingToScope(element, targetExpr, debounceMs, targetScope);
|
|
5907
|
+
this.applyValueBindingToScope(element, targetExpr, debounceMs, targetScope, transform);
|
|
4806
5908
|
return;
|
|
4807
5909
|
}
|
|
4808
5910
|
if (target.kind === "attr" && target.name === "checked") {
|
|
4809
|
-
this.applyCheckedBindingToScope(element, targetExpr, debounceMs, targetScope);
|
|
5911
|
+
this.applyCheckedBindingToScope(element, targetExpr, debounceMs, targetScope, transform);
|
|
4810
5912
|
return;
|
|
4811
5913
|
}
|
|
4812
5914
|
const value = this.getDirectiveValue(element, target);
|
|
4813
5915
|
if (value != null) {
|
|
4814
|
-
|
|
5916
|
+
const nextValue = transform ? transform(value) : value;
|
|
5917
|
+
targetScope.set(targetExpr, nextValue);
|
|
4815
5918
|
}
|
|
4816
5919
|
}
|
|
4817
|
-
applyCheckedBindingToScope(element, expr, debounceMs, scope) {
|
|
5920
|
+
applyCheckedBindingToScope(element, expr, debounceMs, scope, transform) {
|
|
4818
5921
|
if (!(element instanceof HTMLInputElement)) {
|
|
4819
5922
|
return;
|
|
4820
5923
|
}
|
|
4821
5924
|
const handler = () => {
|
|
4822
5925
|
const targetScope = scope ?? this.getScope(element);
|
|
4823
|
-
|
|
5926
|
+
const value = transform ? transform(element.checked) : element.checked;
|
|
5927
|
+
targetScope.set(expr, value);
|
|
4824
5928
|
};
|
|
4825
5929
|
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4826
5930
|
effectiveHandler();
|
|
4827
5931
|
element.addEventListener("change", effectiveHandler);
|
|
4828
5932
|
element.addEventListener("input", effectiveHandler);
|
|
4829
5933
|
}
|
|
4830
|
-
applyValueBindingToScope(element, expr, debounceMs, scope) {
|
|
5934
|
+
applyValueBindingToScope(element, expr, debounceMs, scope, transform) {
|
|
4831
5935
|
if (!(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) {
|
|
4832
5936
|
return;
|
|
4833
5937
|
}
|
|
4834
5938
|
const handler = () => {
|
|
4835
5939
|
const targetScope = scope ?? this.getScope(element);
|
|
4836
|
-
|
|
5940
|
+
const value = element.value;
|
|
5941
|
+
const nextValue = transform ? transform(value) : value;
|
|
5942
|
+
targetScope.set(expr, nextValue);
|
|
4837
5943
|
};
|
|
4838
5944
|
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4839
5945
|
effectiveHandler();
|
|
@@ -4850,6 +5956,14 @@ var Engine = class _Engine {
|
|
|
4850
5956
|
return;
|
|
4851
5957
|
}
|
|
4852
5958
|
if (target.kind === "attr") {
|
|
5959
|
+
if (target.name === "text" && element instanceof HTMLElement) {
|
|
5960
|
+
element.innerText = value == null ? "" : String(value);
|
|
5961
|
+
return;
|
|
5962
|
+
}
|
|
5963
|
+
if (target.name === "content" && element instanceof HTMLElement) {
|
|
5964
|
+
element.textContent = value == null ? "" : String(value);
|
|
5965
|
+
return;
|
|
5966
|
+
}
|
|
4853
5967
|
if (target.name === "value") {
|
|
4854
5968
|
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
|
4855
5969
|
element.value = value == null ? "" : String(value);
|
|
@@ -4880,6 +5994,12 @@ var Engine = class _Engine {
|
|
|
4880
5994
|
}
|
|
4881
5995
|
getDirectiveValue(element, target) {
|
|
4882
5996
|
if (target.kind === "attr") {
|
|
5997
|
+
if (target.name === "text" && element instanceof HTMLElement) {
|
|
5998
|
+
return element.innerText;
|
|
5999
|
+
}
|
|
6000
|
+
if (target.name === "content" && element instanceof HTMLElement) {
|
|
6001
|
+
return element.textContent ?? "";
|
|
6002
|
+
}
|
|
4883
6003
|
if (target.name === "value") {
|
|
4884
6004
|
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
|
4885
6005
|
return element.value;
|
|
@@ -4915,17 +6035,27 @@ var Engine = class _Engine {
|
|
|
4915
6035
|
id: "vsn-bind",
|
|
4916
6036
|
match: (name) => name.startsWith("vsn-bind"),
|
|
4917
6037
|
handle: (element, name, value, scope) => {
|
|
4918
|
-
const
|
|
4919
|
-
this.
|
|
4920
|
-
|
|
6038
|
+
const parsedDirection = this.parseBindDirection(name);
|
|
6039
|
+
const config = this.resolveBindConfig(element, value, scope, parsedDirection);
|
|
6040
|
+
const direction = config.direction;
|
|
6041
|
+
const auto = parsedDirection === "auto";
|
|
6042
|
+
this.bindBindings.set(element, { expr: value, direction, auto });
|
|
6043
|
+
if (!auto && (direction === "to" || direction === "both")) {
|
|
4921
6044
|
this.markInlineDeclaration(element, `state:${value}`);
|
|
4922
6045
|
}
|
|
4923
|
-
if (
|
|
6046
|
+
if (config.seedFromScope) {
|
|
6047
|
+
applyBindToElement(element, value, scope);
|
|
6048
|
+
}
|
|
6049
|
+
if (config.deferToScope) {
|
|
6050
|
+
this.pendingAutoBindToScope.push({ element, expr: value, scope });
|
|
6051
|
+
} else if (config.syncToScope) {
|
|
4924
6052
|
applyBindToScope(element, value, scope);
|
|
6053
|
+
}
|
|
6054
|
+
if (direction === "to" || direction === "both") {
|
|
4925
6055
|
this.attachBindInputHandler(element, value);
|
|
4926
6056
|
}
|
|
4927
6057
|
if (direction === "from" || direction === "both") {
|
|
4928
|
-
this.watch(scope, value, () => applyBindToElement(element, value, scope));
|
|
6058
|
+
this.watch(scope, value, () => applyBindToElement(element, value, scope), element);
|
|
4929
6059
|
}
|
|
4930
6060
|
}
|
|
4931
6061
|
});
|
|
@@ -4937,7 +6067,7 @@ var Engine = class _Engine {
|
|
|
4937
6067
|
if (element instanceof HTMLElement) {
|
|
4938
6068
|
applyIf(element, value, scope);
|
|
4939
6069
|
}
|
|
4940
|
-
this.watch(scope, value, () => this.evaluate(element));
|
|
6070
|
+
this.watch(scope, value, () => this.evaluate(element), element);
|
|
4941
6071
|
}
|
|
4942
6072
|
});
|
|
4943
6073
|
this.registerAttributeHandler({
|
|
@@ -4948,7 +6078,7 @@ var Engine = class _Engine {
|
|
|
4948
6078
|
if (element instanceof HTMLElement) {
|
|
4949
6079
|
applyShow(element, value, scope);
|
|
4950
6080
|
}
|
|
4951
|
-
this.watch(scope, value, () => this.evaluate(element));
|
|
6081
|
+
this.watch(scope, value, () => this.evaluate(element), element);
|
|
4952
6082
|
}
|
|
4953
6083
|
});
|
|
4954
6084
|
this.registerAttributeHandler({
|
|
@@ -4964,7 +6094,7 @@ var Engine = class _Engine {
|
|
|
4964
6094
|
this.handleTrustedHtml(element);
|
|
4965
6095
|
}
|
|
4966
6096
|
}
|
|
4967
|
-
this.watch(scope, value, () => this.evaluate(element));
|
|
6097
|
+
this.watch(scope, value, () => this.evaluate(element), element);
|
|
4968
6098
|
}
|
|
4969
6099
|
});
|
|
4970
6100
|
this.registerAttributeHandler({
|
|
@@ -4977,7 +6107,7 @@ var Engine = class _Engine {
|
|
|
4977
6107
|
}
|
|
4978
6108
|
this.eachBindings.set(element, { ...config, rendered: [] });
|
|
4979
6109
|
this.renderEach(element);
|
|
4980
|
-
this.watch(scope, config.listExpr, () => this.renderEach(element));
|
|
6110
|
+
this.watch(scope, config.listExpr, () => this.renderEach(element), element);
|
|
4981
6111
|
}
|
|
4982
6112
|
});
|
|
4983
6113
|
this.registerAttributeHandler({
|
|
@@ -5032,15 +6162,27 @@ function parseCFS(source) {
|
|
|
5032
6162
|
const parser = new Parser(source);
|
|
5033
6163
|
return parser.parseProgram();
|
|
5034
6164
|
}
|
|
6165
|
+
if (typeof window !== "undefined") {
|
|
6166
|
+
window["parseCFS"] = parseCFS;
|
|
6167
|
+
}
|
|
5035
6168
|
function autoMount(root = document) {
|
|
5036
6169
|
if (typeof document === "undefined") {
|
|
5037
6170
|
return null;
|
|
5038
6171
|
}
|
|
5039
6172
|
const engine = new Engine();
|
|
6173
|
+
globalThis.VSNEngine = engine;
|
|
5040
6174
|
const startTime = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
5041
6175
|
const mount = () => {
|
|
5042
6176
|
const target = root instanceof Document ? root.body : root;
|
|
5043
6177
|
if (target) {
|
|
6178
|
+
const plugins = globalThis.VSNPlugins;
|
|
6179
|
+
if (plugins && typeof plugins === "object") {
|
|
6180
|
+
for (const plugin of Object.values(plugins)) {
|
|
6181
|
+
if (typeof plugin === "function") {
|
|
6182
|
+
plugin(engine);
|
|
6183
|
+
}
|
|
6184
|
+
}
|
|
6185
|
+
}
|
|
5044
6186
|
const sources = Array.from(document.querySelectorAll('script[type="text/vsn"]')).map((script) => script.textContent ?? "").join("\n");
|
|
5045
6187
|
if (sources.trim()) {
|
|
5046
6188
|
engine.registerBehaviors(sources);
|
|
@@ -5052,9 +6194,9 @@ function autoMount(root = document) {
|
|
|
5052
6194
|
}
|
|
5053
6195
|
};
|
|
5054
6196
|
if (document.readyState === "loading") {
|
|
5055
|
-
document.addEventListener("DOMContentLoaded", mount, { once: true });
|
|
6197
|
+
document.addEventListener("DOMContentLoaded", () => setTimeout(mount, 0), { once: true });
|
|
5056
6198
|
} else {
|
|
5057
|
-
mount
|
|
6199
|
+
setTimeout(mount, 0);
|
|
5058
6200
|
}
|
|
5059
6201
|
return engine;
|
|
5060
6202
|
}
|
|
@@ -5067,16 +6209,21 @@ if (typeof document !== "undefined") {
|
|
|
5067
6209
|
export {
|
|
5068
6210
|
ArrayExpression,
|
|
5069
6211
|
ArrayPattern,
|
|
6212
|
+
AssertError,
|
|
6213
|
+
AssertNode,
|
|
5070
6214
|
AssignmentNode,
|
|
5071
6215
|
AwaitExpression,
|
|
5072
6216
|
BaseNode,
|
|
5073
6217
|
BehaviorNode,
|
|
5074
6218
|
BinaryExpression,
|
|
5075
6219
|
BlockNode,
|
|
6220
|
+
BreakNode,
|
|
5076
6221
|
CallExpression,
|
|
6222
|
+
ContinueNode,
|
|
5077
6223
|
DeclarationNode,
|
|
5078
6224
|
DirectiveExpression,
|
|
5079
6225
|
Engine,
|
|
6226
|
+
ForEachNode,
|
|
5080
6227
|
ForNode,
|
|
5081
6228
|
FunctionDeclarationNode,
|
|
5082
6229
|
FunctionExpression,
|
|
@@ -5096,8 +6243,6 @@ export {
|
|
|
5096
6243
|
ReturnNode,
|
|
5097
6244
|
SelectorNode,
|
|
5098
6245
|
SpreadElement,
|
|
5099
|
-
StateBlockNode,
|
|
5100
|
-
StateEntryNode,
|
|
5101
6246
|
TemplateExpression,
|
|
5102
6247
|
TernaryExpression,
|
|
5103
6248
|
TokenType,
|