vsn 1.0.2 → 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 +1827 -769
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +190 -52
- package/dist/index.d.ts +190 -52
- package/dist/index.js +1822 -767
- 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.cjs
CHANGED
|
@@ -22,16 +22,21 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
ArrayExpression: () => ArrayExpression,
|
|
24
24
|
ArrayPattern: () => ArrayPattern,
|
|
25
|
+
AssertError: () => AssertError,
|
|
26
|
+
AssertNode: () => AssertNode,
|
|
25
27
|
AssignmentNode: () => AssignmentNode,
|
|
26
28
|
AwaitExpression: () => AwaitExpression,
|
|
27
29
|
BaseNode: () => BaseNode,
|
|
28
30
|
BehaviorNode: () => BehaviorNode,
|
|
29
31
|
BinaryExpression: () => BinaryExpression,
|
|
30
32
|
BlockNode: () => BlockNode,
|
|
33
|
+
BreakNode: () => BreakNode,
|
|
31
34
|
CallExpression: () => CallExpression,
|
|
35
|
+
ContinueNode: () => ContinueNode,
|
|
32
36
|
DeclarationNode: () => DeclarationNode,
|
|
33
37
|
DirectiveExpression: () => DirectiveExpression,
|
|
34
38
|
Engine: () => Engine,
|
|
39
|
+
ForEachNode: () => ForEachNode,
|
|
35
40
|
ForNode: () => ForNode,
|
|
36
41
|
FunctionDeclarationNode: () => FunctionDeclarationNode,
|
|
37
42
|
FunctionExpression: () => FunctionExpression,
|
|
@@ -51,8 +56,6 @@ __export(index_exports, {
|
|
|
51
56
|
ReturnNode: () => ReturnNode,
|
|
52
57
|
SelectorNode: () => SelectorNode,
|
|
53
58
|
SpreadElement: () => SpreadElement,
|
|
54
|
-
StateBlockNode: () => StateBlockNode,
|
|
55
|
-
StateEntryNode: () => StateEntryNode,
|
|
56
59
|
TemplateExpression: () => TemplateExpression,
|
|
57
60
|
TernaryExpression: () => TernaryExpression,
|
|
58
61
|
TokenType: () => TokenType,
|
|
@@ -88,6 +91,9 @@ var TokenType = /* @__PURE__ */ ((TokenType2) => {
|
|
|
88
91
|
TokenType2["While"] = "While";
|
|
89
92
|
TokenType2["Try"] = "Try";
|
|
90
93
|
TokenType2["Catch"] = "Catch";
|
|
94
|
+
TokenType2["Assert"] = "Assert";
|
|
95
|
+
TokenType2["Break"] = "Break";
|
|
96
|
+
TokenType2["Continue"] = "Continue";
|
|
91
97
|
TokenType2["LBrace"] = "LBrace";
|
|
92
98
|
TokenType2["RBrace"] = "RBrace";
|
|
93
99
|
TokenType2["LParen"] = "LParen";
|
|
@@ -103,7 +109,9 @@ var TokenType = /* @__PURE__ */ ((TokenType2) => {
|
|
|
103
109
|
TokenType2["Greater"] = "Greater";
|
|
104
110
|
TokenType2["Less"] = "Less";
|
|
105
111
|
TokenType2["Plus"] = "Plus";
|
|
112
|
+
TokenType2["PlusPlus"] = "PlusPlus";
|
|
106
113
|
TokenType2["Minus"] = "Minus";
|
|
114
|
+
TokenType2["MinusMinus"] = "MinusMinus";
|
|
107
115
|
TokenType2["Tilde"] = "Tilde";
|
|
108
116
|
TokenType2["Star"] = "Star";
|
|
109
117
|
TokenType2["Slash"] = "Slash";
|
|
@@ -143,6 +151,9 @@ var KEYWORDS = {
|
|
|
143
151
|
while: "While" /* While */,
|
|
144
152
|
try: "Try" /* Try */,
|
|
145
153
|
catch: "Catch" /* Catch */,
|
|
154
|
+
assert: "Assert" /* Assert */,
|
|
155
|
+
break: "Break" /* Break */,
|
|
156
|
+
continue: "Continue" /* Continue */,
|
|
146
157
|
true: "Boolean" /* Boolean */,
|
|
147
158
|
false: "Boolean" /* Boolean */,
|
|
148
159
|
null: "Null" /* Null */
|
|
@@ -244,8 +255,20 @@ var Lexer = class {
|
|
|
244
255
|
readIdentifier() {
|
|
245
256
|
const start = this.position();
|
|
246
257
|
let value = "";
|
|
247
|
-
while (!this.eof()
|
|
248
|
-
|
|
258
|
+
while (!this.eof()) {
|
|
259
|
+
const ch = this.peek();
|
|
260
|
+
if (this.isAlphaNumeric(ch) || ch === "_") {
|
|
261
|
+
value += this.next();
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (ch === "-") {
|
|
265
|
+
if (this.peek(1) === "-") {
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
value += this.next();
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
break;
|
|
249
272
|
}
|
|
250
273
|
const keywordType = KEYWORDS[value];
|
|
251
274
|
if (keywordType) {
|
|
@@ -386,6 +409,16 @@ var Lexer = class {
|
|
|
386
409
|
this.next();
|
|
387
410
|
return this.token("Pipe" /* Pipe */, "|>", start);
|
|
388
411
|
}
|
|
412
|
+
if (ch === "+" && next === "+") {
|
|
413
|
+
this.next();
|
|
414
|
+
this.next();
|
|
415
|
+
return this.token("PlusPlus" /* PlusPlus */, "++", start);
|
|
416
|
+
}
|
|
417
|
+
if (ch === "-" && next === "-") {
|
|
418
|
+
this.next();
|
|
419
|
+
this.next();
|
|
420
|
+
return this.token("MinusMinus" /* MinusMinus */, "--", start);
|
|
421
|
+
}
|
|
389
422
|
if (ch === "." && next === "." && this.peek(2) === ".") {
|
|
390
423
|
this.next();
|
|
391
424
|
this.next();
|
|
@@ -488,11 +521,20 @@ var BaseNode = class {
|
|
|
488
521
|
async prepare(_context) {
|
|
489
522
|
return;
|
|
490
523
|
}
|
|
491
|
-
|
|
524
|
+
evaluate(_context) {
|
|
492
525
|
return void 0;
|
|
493
526
|
}
|
|
494
527
|
};
|
|
495
|
-
|
|
528
|
+
function isPromiseLike(value) {
|
|
529
|
+
return Boolean(value) && typeof value.then === "function";
|
|
530
|
+
}
|
|
531
|
+
function resolveMaybe(value, next) {
|
|
532
|
+
if (isPromiseLike(value)) {
|
|
533
|
+
return value.then(next);
|
|
534
|
+
}
|
|
535
|
+
return next(value);
|
|
536
|
+
}
|
|
537
|
+
function evaluateWithChildScope(context, block) {
|
|
496
538
|
const scope = context.scope;
|
|
497
539
|
if (!scope || !scope.createChild) {
|
|
498
540
|
return block.evaluate(context);
|
|
@@ -500,7 +542,7 @@ async function evaluateWithChildScope(context, block) {
|
|
|
500
542
|
const previousScope = context.scope;
|
|
501
543
|
context.scope = scope.createChild();
|
|
502
544
|
try {
|
|
503
|
-
return
|
|
545
|
+
return block.evaluate(context);
|
|
504
546
|
} finally {
|
|
505
547
|
context.scope = previousScope;
|
|
506
548
|
}
|
|
@@ -526,15 +568,25 @@ var BlockNode = class extends BaseNode {
|
|
|
526
568
|
super("Block");
|
|
527
569
|
this.statements = statements;
|
|
528
570
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
571
|
+
evaluate(context) {
|
|
572
|
+
let index = 0;
|
|
573
|
+
const run = () => {
|
|
574
|
+
while (index < this.statements.length) {
|
|
575
|
+
if (context.returning || context.breaking || context.continuing) {
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
const statement = this.statements[index];
|
|
579
|
+
index += 1;
|
|
580
|
+
if (statement && typeof statement.evaluate === "function") {
|
|
581
|
+
const result = statement.evaluate(context);
|
|
582
|
+
if (isPromiseLike(result)) {
|
|
583
|
+
return result.then(() => run());
|
|
584
|
+
}
|
|
585
|
+
}
|
|
536
586
|
}
|
|
537
|
-
|
|
587
|
+
return void 0;
|
|
588
|
+
};
|
|
589
|
+
return run();
|
|
538
590
|
}
|
|
539
591
|
};
|
|
540
592
|
var SelectorNode = class extends BaseNode {
|
|
@@ -544,136 +596,186 @@ var SelectorNode = class extends BaseNode {
|
|
|
544
596
|
}
|
|
545
597
|
};
|
|
546
598
|
var BehaviorNode = class extends BaseNode {
|
|
547
|
-
constructor(selector, body) {
|
|
599
|
+
constructor(selector, body, flags = {}, flagArgs = {}) {
|
|
548
600
|
super("Behavior");
|
|
549
601
|
this.selector = selector;
|
|
550
602
|
this.body = body;
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
var StateEntryNode = class extends BaseNode {
|
|
554
|
-
constructor(name, value, important) {
|
|
555
|
-
super("StateEntry");
|
|
556
|
-
this.name = name;
|
|
557
|
-
this.value = value;
|
|
558
|
-
this.important = important;
|
|
559
|
-
}
|
|
560
|
-
};
|
|
561
|
-
var StateBlockNode = class extends BaseNode {
|
|
562
|
-
constructor(entries) {
|
|
563
|
-
super("StateBlock");
|
|
564
|
-
this.entries = entries;
|
|
603
|
+
this.flags = flags;
|
|
604
|
+
this.flagArgs = flagArgs;
|
|
565
605
|
}
|
|
566
606
|
};
|
|
567
607
|
var OnBlockNode = class extends BaseNode {
|
|
568
|
-
constructor(eventName, args, body,
|
|
608
|
+
constructor(eventName, args, body, flags = {}, flagArgs = {}) {
|
|
569
609
|
super("OnBlock");
|
|
570
610
|
this.eventName = eventName;
|
|
571
611
|
this.args = args;
|
|
572
612
|
this.body = body;
|
|
573
|
-
this.
|
|
613
|
+
this.flags = flags;
|
|
614
|
+
this.flagArgs = flagArgs;
|
|
574
615
|
}
|
|
575
616
|
};
|
|
576
617
|
var AssignmentNode = class extends BaseNode {
|
|
577
|
-
constructor(target, value, operator = "=") {
|
|
618
|
+
constructor(target, value, operator = "=", prefix = false) {
|
|
578
619
|
super("Assignment");
|
|
579
620
|
this.target = target;
|
|
580
621
|
this.value = value;
|
|
581
622
|
this.operator = operator;
|
|
623
|
+
this.prefix = prefix;
|
|
582
624
|
}
|
|
583
|
-
|
|
625
|
+
evaluate(context) {
|
|
584
626
|
if (!context.scope || !context.scope.setPath) {
|
|
585
627
|
return void 0;
|
|
586
628
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
629
|
+
if (this.operator === "++" || this.operator === "--") {
|
|
630
|
+
return this.applyIncrement(context);
|
|
631
|
+
}
|
|
632
|
+
const value = this.value.evaluate(context);
|
|
633
|
+
return resolveMaybe(value, (resolvedValue) => {
|
|
634
|
+
if (this.operator !== "=") {
|
|
635
|
+
return this.applyCompoundAssignment(context, resolvedValue);
|
|
636
|
+
}
|
|
637
|
+
if (this.target instanceof IdentifierExpression && this.target.name.startsWith("root.") && context.rootScope) {
|
|
638
|
+
const path = this.target.name.slice("root.".length);
|
|
639
|
+
context.rootScope.setPath?.(`self.${path}`, resolvedValue);
|
|
640
|
+
return resolvedValue;
|
|
641
|
+
}
|
|
642
|
+
if (this.target instanceof MemberExpression || this.target instanceof IndexExpression) {
|
|
643
|
+
const resolved = this.resolveAssignmentTarget(context);
|
|
644
|
+
return resolveMaybe(resolved, (resolvedTarget) => {
|
|
645
|
+
if (resolvedTarget?.scope?.setPath) {
|
|
646
|
+
resolvedTarget.scope.setPath(resolvedTarget.path, resolvedValue);
|
|
647
|
+
return resolvedValue;
|
|
648
|
+
}
|
|
649
|
+
this.assignTarget(context, this.target, resolvedValue);
|
|
650
|
+
return resolvedValue;
|
|
651
|
+
});
|
|
601
652
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
653
|
+
this.assignTarget(context, this.target, resolvedValue);
|
|
654
|
+
return resolvedValue;
|
|
655
|
+
});
|
|
605
656
|
}
|
|
606
|
-
|
|
657
|
+
applyCompoundAssignment(context, value) {
|
|
607
658
|
if (!context.scope || !context.scope.setPath) {
|
|
608
659
|
return void 0;
|
|
609
660
|
}
|
|
610
|
-
const resolved =
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
661
|
+
const resolved = this.resolveAssignmentTarget(context);
|
|
662
|
+
return resolveMaybe(resolved, (resolvedTarget) => {
|
|
663
|
+
if (!resolvedTarget) {
|
|
664
|
+
throw new Error("Compound assignment requires a simple identifier or member path");
|
|
665
|
+
}
|
|
666
|
+
const { scope, path } = resolvedTarget;
|
|
667
|
+
const current = scope?.getPath ? scope.getPath(path) : void 0;
|
|
668
|
+
let result;
|
|
669
|
+
if (this.operator === "+=") {
|
|
670
|
+
result = current + value;
|
|
671
|
+
} else if (this.operator === "-=") {
|
|
672
|
+
result = current - value;
|
|
673
|
+
} else if (this.operator === "*=") {
|
|
674
|
+
result = current * value;
|
|
675
|
+
} else {
|
|
676
|
+
result = current / value;
|
|
677
|
+
}
|
|
678
|
+
scope?.setPath?.(path, result);
|
|
679
|
+
return result;
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
applyIncrement(context) {
|
|
683
|
+
if (!context.scope || !context.scope.setPath) {
|
|
684
|
+
return void 0;
|
|
625
685
|
}
|
|
626
|
-
|
|
627
|
-
return
|
|
686
|
+
const resolved = this.resolveAssignmentTarget(context);
|
|
687
|
+
return resolveMaybe(resolved, (resolvedTarget) => {
|
|
688
|
+
if (!resolvedTarget) {
|
|
689
|
+
throw new Error("Increment/decrement requires a simple identifier or member path");
|
|
690
|
+
}
|
|
691
|
+
const { scope, path } = resolvedTarget;
|
|
692
|
+
const current = scope?.getPath ? scope.getPath(path) : void 0;
|
|
693
|
+
const numeric = typeof current === "number" ? current : Number(current);
|
|
694
|
+
const delta = this.operator === "++" ? 1 : -1;
|
|
695
|
+
const next = (Number.isNaN(numeric) ? 0 : numeric) + delta;
|
|
696
|
+
scope?.setPath?.(path, next);
|
|
697
|
+
return this.prefix ? next : numeric;
|
|
698
|
+
});
|
|
628
699
|
}
|
|
629
|
-
|
|
700
|
+
resolveAssignmentTarget(context) {
|
|
630
701
|
if (this.target instanceof IdentifierExpression) {
|
|
631
702
|
const isRoot = this.target.name.startsWith("root.");
|
|
632
703
|
const rawPath = isRoot ? this.target.name.slice("root.".length) : this.target.name;
|
|
633
704
|
if (isRoot) {
|
|
705
|
+
if (context.rootScope) {
|
|
706
|
+
return { scope: context.rootScope, path: `self.${rawPath}` };
|
|
707
|
+
}
|
|
634
708
|
return { scope: context.scope, path: `root.${rawPath}` };
|
|
635
709
|
}
|
|
636
710
|
return { scope: context.scope, path: rawPath };
|
|
637
711
|
}
|
|
638
712
|
if (this.target instanceof MemberExpression) {
|
|
639
713
|
const resolvedPath = this.target.getIdentifierPath();
|
|
640
|
-
if (
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
714
|
+
if (resolvedPath) {
|
|
715
|
+
const path = resolvedPath.path;
|
|
716
|
+
const isRoot = path.startsWith("root.");
|
|
717
|
+
const rawPath = isRoot ? path.slice("root.".length) : path;
|
|
718
|
+
if (isRoot) {
|
|
719
|
+
if (context.rootScope) {
|
|
720
|
+
return { scope: context.rootScope, path: `self.${rawPath}` };
|
|
721
|
+
}
|
|
722
|
+
return { scope: context.scope, path: `root.${rawPath}` };
|
|
723
|
+
}
|
|
724
|
+
return { scope: context.scope, path: rawPath };
|
|
648
725
|
}
|
|
649
|
-
|
|
726
|
+
const targetExpr = this.target;
|
|
727
|
+
const basePath = this.resolveTargetPath(context, targetExpr.target);
|
|
728
|
+
return resolveMaybe(basePath, (resolvedBase) => {
|
|
729
|
+
if (!resolvedBase) {
|
|
730
|
+
return null;
|
|
731
|
+
}
|
|
732
|
+
const path = `${resolvedBase}.${targetExpr.property}`;
|
|
733
|
+
const isRoot = path.startsWith("root.");
|
|
734
|
+
const rawPath = isRoot ? path.slice("root.".length) : path;
|
|
735
|
+
if (isRoot) {
|
|
736
|
+
if (context.rootScope) {
|
|
737
|
+
return { scope: context.rootScope, path: `self.${rawPath}` };
|
|
738
|
+
}
|
|
739
|
+
return { scope: context.scope, path: `root.${rawPath}` };
|
|
740
|
+
}
|
|
741
|
+
return { scope: context.scope, path: rawPath };
|
|
742
|
+
});
|
|
650
743
|
}
|
|
651
744
|
if (this.target instanceof IndexExpression) {
|
|
652
|
-
const path =
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
745
|
+
const path = this.resolveIndexPath(context, this.target);
|
|
746
|
+
return resolveMaybe(path, (resolvedPath) => {
|
|
747
|
+
if (!resolvedPath) {
|
|
748
|
+
return null;
|
|
749
|
+
}
|
|
750
|
+
const isRoot = resolvedPath.startsWith("root.");
|
|
751
|
+
const rawPath = isRoot ? resolvedPath.slice("root.".length) : resolvedPath;
|
|
752
|
+
if (isRoot) {
|
|
753
|
+
if (context.rootScope) {
|
|
754
|
+
return { scope: context.rootScope, path: `self.${rawPath}` };
|
|
755
|
+
}
|
|
756
|
+
return { scope: context.scope, path: `root.${rawPath}` };
|
|
757
|
+
}
|
|
758
|
+
return { scope: context.scope, path: rawPath };
|
|
759
|
+
});
|
|
662
760
|
}
|
|
663
761
|
return null;
|
|
664
762
|
}
|
|
665
|
-
|
|
666
|
-
const base =
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
return
|
|
673
|
-
|
|
674
|
-
|
|
763
|
+
resolveIndexPath(context, expr) {
|
|
764
|
+
const base = this.resolveTargetPath(context, expr.target);
|
|
765
|
+
return resolveMaybe(base, (resolvedBase) => {
|
|
766
|
+
if (!resolvedBase) {
|
|
767
|
+
return null;
|
|
768
|
+
}
|
|
769
|
+
const indexValue = expr.index.evaluate(context);
|
|
770
|
+
return resolveMaybe(indexValue, (resolvedIndex) => {
|
|
771
|
+
if (resolvedIndex == null) {
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
return `${resolvedBase}.${resolvedIndex}`;
|
|
775
|
+
});
|
|
776
|
+
});
|
|
675
777
|
}
|
|
676
|
-
|
|
778
|
+
resolveTargetPath(context, target) {
|
|
677
779
|
if (target instanceof IdentifierExpression) {
|
|
678
780
|
return target.name;
|
|
679
781
|
}
|
|
@@ -689,6 +791,10 @@ var AssignmentNode = class extends BaseNode {
|
|
|
689
791
|
if (!context.scope || !context.scope.setPath) {
|
|
690
792
|
return;
|
|
691
793
|
}
|
|
794
|
+
if (target instanceof DirectiveExpression) {
|
|
795
|
+
this.assignDirectiveTarget(context, target, value);
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
692
798
|
if (target instanceof IdentifierExpression) {
|
|
693
799
|
context.scope.setPath(target.name, value);
|
|
694
800
|
return;
|
|
@@ -730,19 +836,99 @@ var AssignmentNode = class extends BaseNode {
|
|
|
730
836
|
return;
|
|
731
837
|
}
|
|
732
838
|
}
|
|
839
|
+
assignDirectiveTarget(context, target, value) {
|
|
840
|
+
const element = context.element;
|
|
841
|
+
if (!element) {
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
if (target.kind === "attr") {
|
|
845
|
+
if (target.name === "value") {
|
|
846
|
+
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
|
847
|
+
element.value = value == null ? "" : String(value);
|
|
848
|
+
element.setAttribute("value", element.value);
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
if (element instanceof HTMLSelectElement) {
|
|
852
|
+
element.value = value == null ? "" : String(value);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (target.name === "checked" && element instanceof HTMLInputElement) {
|
|
857
|
+
const checked = value === true || value === "true" || value === 1 || value === "1";
|
|
858
|
+
element.checked = checked;
|
|
859
|
+
if (checked) {
|
|
860
|
+
element.setAttribute("checked", "");
|
|
861
|
+
} else {
|
|
862
|
+
element.removeAttribute("checked");
|
|
863
|
+
}
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
if (target.name === "html" && element instanceof HTMLElement) {
|
|
867
|
+
element.innerHTML = value == null ? "" : String(value);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
element.setAttribute(target.name, value == null ? "" : String(value));
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
if (target.kind === "style" && element instanceof HTMLElement) {
|
|
874
|
+
element.style.setProperty(target.name, value == null ? "" : String(value));
|
|
875
|
+
}
|
|
876
|
+
}
|
|
733
877
|
};
|
|
734
878
|
var ReturnNode = class extends BaseNode {
|
|
735
879
|
constructor(value) {
|
|
736
880
|
super("Return");
|
|
737
881
|
this.value = value;
|
|
738
882
|
}
|
|
739
|
-
|
|
883
|
+
evaluate(context) {
|
|
740
884
|
if (context.returning) {
|
|
741
885
|
return context.returnValue;
|
|
742
886
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
887
|
+
const nextValue = this.value ? this.value.evaluate(context) : void 0;
|
|
888
|
+
return resolveMaybe(nextValue, (resolved) => {
|
|
889
|
+
context.returnValue = resolved;
|
|
890
|
+
context.returning = true;
|
|
891
|
+
return context.returnValue;
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
var BreakNode = class extends BaseNode {
|
|
896
|
+
constructor() {
|
|
897
|
+
super("Break");
|
|
898
|
+
}
|
|
899
|
+
evaluate(context) {
|
|
900
|
+
context.breaking = true;
|
|
901
|
+
return void 0;
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
var ContinueNode = class extends BaseNode {
|
|
905
|
+
constructor() {
|
|
906
|
+
super("Continue");
|
|
907
|
+
}
|
|
908
|
+
evaluate(context) {
|
|
909
|
+
context.continuing = true;
|
|
910
|
+
return void 0;
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
var AssertError = class extends Error {
|
|
914
|
+
constructor(message = "Assertion failed") {
|
|
915
|
+
super(message);
|
|
916
|
+
this.name = "AssertError";
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
var AssertNode = class extends BaseNode {
|
|
920
|
+
constructor(test) {
|
|
921
|
+
super("Assert");
|
|
922
|
+
this.test = test;
|
|
923
|
+
}
|
|
924
|
+
evaluate(context) {
|
|
925
|
+
const value = this.test.evaluate(context);
|
|
926
|
+
return resolveMaybe(value, (resolved) => {
|
|
927
|
+
if (!resolved) {
|
|
928
|
+
throw new AssertError();
|
|
929
|
+
}
|
|
930
|
+
return resolved;
|
|
931
|
+
});
|
|
746
932
|
}
|
|
747
933
|
};
|
|
748
934
|
var IfNode = class extends BaseNode {
|
|
@@ -752,14 +938,17 @@ var IfNode = class extends BaseNode {
|
|
|
752
938
|
this.consequent = consequent;
|
|
753
939
|
this.alternate = alternate;
|
|
754
940
|
}
|
|
755
|
-
|
|
756
|
-
const condition =
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
941
|
+
evaluate(context) {
|
|
942
|
+
const condition = this.test.evaluate(context);
|
|
943
|
+
return resolveMaybe(condition, (resolved) => {
|
|
944
|
+
if (resolved) {
|
|
945
|
+
return evaluateWithChildScope(context, this.consequent);
|
|
946
|
+
}
|
|
947
|
+
if (this.alternate) {
|
|
948
|
+
return evaluateWithChildScope(context, this.alternate);
|
|
949
|
+
}
|
|
950
|
+
return void 0;
|
|
951
|
+
});
|
|
763
952
|
}
|
|
764
953
|
};
|
|
765
954
|
var WhileNode = class extends BaseNode {
|
|
@@ -768,21 +957,104 @@ var WhileNode = class extends BaseNode {
|
|
|
768
957
|
this.test = test;
|
|
769
958
|
this.body = body;
|
|
770
959
|
}
|
|
771
|
-
|
|
960
|
+
evaluate(context) {
|
|
772
961
|
const previousScope = context.scope;
|
|
773
962
|
if (context.scope?.createChild) {
|
|
774
963
|
context.scope = context.scope.createChild();
|
|
775
964
|
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
if (context.returning) {
|
|
780
|
-
|
|
965
|
+
const run = () => {
|
|
966
|
+
const condition = this.test.evaluate(context);
|
|
967
|
+
return resolveMaybe(condition, (resolved) => {
|
|
968
|
+
if (!resolved || context.returning) {
|
|
969
|
+
return void 0;
|
|
970
|
+
}
|
|
971
|
+
const bodyResult = this.body.evaluate(context);
|
|
972
|
+
return resolveMaybe(bodyResult, () => {
|
|
973
|
+
if (context.breaking) {
|
|
974
|
+
context.breaking = false;
|
|
975
|
+
return void 0;
|
|
976
|
+
}
|
|
977
|
+
if (context.continuing) {
|
|
978
|
+
context.continuing = false;
|
|
979
|
+
}
|
|
980
|
+
return run();
|
|
981
|
+
});
|
|
982
|
+
});
|
|
983
|
+
};
|
|
984
|
+
const result = run();
|
|
985
|
+
if (isPromiseLike(result)) {
|
|
986
|
+
return result.finally(() => {
|
|
987
|
+
context.scope = previousScope;
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
context.scope = previousScope;
|
|
991
|
+
return result;
|
|
992
|
+
}
|
|
993
|
+
};
|
|
994
|
+
var ForEachNode = class extends BaseNode {
|
|
995
|
+
constructor(target, iterable, kind, body) {
|
|
996
|
+
super("ForEach");
|
|
997
|
+
this.target = target;
|
|
998
|
+
this.iterable = iterable;
|
|
999
|
+
this.kind = kind;
|
|
1000
|
+
this.body = body;
|
|
1001
|
+
}
|
|
1002
|
+
evaluate(context) {
|
|
1003
|
+
const iterableValue = this.iterable.evaluate(context);
|
|
1004
|
+
return resolveMaybe(iterableValue, (resolved) => {
|
|
1005
|
+
const entries = this.getEntries(resolved);
|
|
1006
|
+
const previousScope = context.scope;
|
|
1007
|
+
let bodyScope = context.scope;
|
|
1008
|
+
if (context.scope?.createChild) {
|
|
1009
|
+
bodyScope = context.scope.createChild();
|
|
1010
|
+
}
|
|
1011
|
+
let index = 0;
|
|
1012
|
+
const loop = () => {
|
|
1013
|
+
if (index >= entries.length || context.returning) {
|
|
1014
|
+
context.scope = previousScope;
|
|
1015
|
+
return void 0;
|
|
781
1016
|
}
|
|
1017
|
+
const value = entries[index];
|
|
1018
|
+
index += 1;
|
|
1019
|
+
context.scope = bodyScope;
|
|
1020
|
+
context.scope?.setPath?.(this.target.name, value);
|
|
1021
|
+
const bodyResult = this.body.evaluate(context);
|
|
1022
|
+
return resolveMaybe(bodyResult, () => {
|
|
1023
|
+
if (context.breaking) {
|
|
1024
|
+
context.breaking = false;
|
|
1025
|
+
context.scope = previousScope;
|
|
1026
|
+
return void 0;
|
|
1027
|
+
}
|
|
1028
|
+
if (context.continuing) {
|
|
1029
|
+
context.continuing = false;
|
|
1030
|
+
}
|
|
1031
|
+
context.scope = previousScope;
|
|
1032
|
+
return loop();
|
|
1033
|
+
});
|
|
1034
|
+
};
|
|
1035
|
+
return loop();
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
getEntries(value) {
|
|
1039
|
+
if (value == null) {
|
|
1040
|
+
return [];
|
|
1041
|
+
}
|
|
1042
|
+
if (this.kind === "in") {
|
|
1043
|
+
if (typeof value === "object") {
|
|
1044
|
+
return Object.keys(value);
|
|
782
1045
|
}
|
|
783
|
-
|
|
784
|
-
context.scope = previousScope;
|
|
1046
|
+
return [];
|
|
785
1047
|
}
|
|
1048
|
+
if (typeof value === "string") {
|
|
1049
|
+
return Array.from(value);
|
|
1050
|
+
}
|
|
1051
|
+
if (typeof value[Symbol.iterator] === "function") {
|
|
1052
|
+
return Array.from(value);
|
|
1053
|
+
}
|
|
1054
|
+
if (typeof value === "object") {
|
|
1055
|
+
return Object.values(value);
|
|
1056
|
+
}
|
|
1057
|
+
return [];
|
|
786
1058
|
}
|
|
787
1059
|
};
|
|
788
1060
|
var ForNode = class extends BaseNode {
|
|
@@ -793,27 +1065,45 @@ var ForNode = class extends BaseNode {
|
|
|
793
1065
|
this.update = update;
|
|
794
1066
|
this.body = body;
|
|
795
1067
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
1068
|
+
evaluate(context) {
|
|
1069
|
+
const initResult = this.init ? this.init.evaluate(context) : void 0;
|
|
1070
|
+
const run = () => {
|
|
1071
|
+
const previousScope = context.scope;
|
|
1072
|
+
let bodyScope = context.scope;
|
|
1073
|
+
if (context.scope?.createChild) {
|
|
1074
|
+
bodyScope = context.scope.createChild();
|
|
1075
|
+
}
|
|
1076
|
+
const loop = () => {
|
|
1077
|
+
const testResult = this.test ? this.test.evaluate(context) : true;
|
|
1078
|
+
return resolveMaybe(testResult, (passed) => {
|
|
1079
|
+
if (!passed || context.returning) {
|
|
1080
|
+
context.scope = previousScope;
|
|
1081
|
+
return void 0;
|
|
1082
|
+
}
|
|
1083
|
+
context.scope = bodyScope;
|
|
1084
|
+
const bodyResult = this.body.evaluate(context);
|
|
1085
|
+
return resolveMaybe(bodyResult, () => {
|
|
1086
|
+
if (context.returning) {
|
|
1087
|
+
context.scope = previousScope;
|
|
1088
|
+
return void 0;
|
|
1089
|
+
}
|
|
1090
|
+
if (context.breaking) {
|
|
1091
|
+
context.breaking = false;
|
|
1092
|
+
context.scope = previousScope;
|
|
1093
|
+
return void 0;
|
|
1094
|
+
}
|
|
1095
|
+
context.scope = previousScope;
|
|
1096
|
+
if (context.continuing) {
|
|
1097
|
+
context.continuing = false;
|
|
1098
|
+
}
|
|
1099
|
+
const updateResult = this.update ? this.update.evaluate(context) : void 0;
|
|
1100
|
+
return resolveMaybe(updateResult, () => loop());
|
|
1101
|
+
});
|
|
1102
|
+
});
|
|
1103
|
+
};
|
|
1104
|
+
return loop();
|
|
1105
|
+
};
|
|
1106
|
+
return resolveMaybe(initResult, () => run());
|
|
817
1107
|
}
|
|
818
1108
|
};
|
|
819
1109
|
var TryNode = class extends BaseNode {
|
|
@@ -823,10 +1113,8 @@ var TryNode = class extends BaseNode {
|
|
|
823
1113
|
this.errorName = errorName;
|
|
824
1114
|
this.handler = handler;
|
|
825
1115
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
return await evaluateWithChildScope(context, this.body);
|
|
829
|
-
} catch (error) {
|
|
1116
|
+
evaluate(context) {
|
|
1117
|
+
const handleError = (error) => {
|
|
830
1118
|
if (context.returning) {
|
|
831
1119
|
return context.returnValue;
|
|
832
1120
|
}
|
|
@@ -844,11 +1132,23 @@ var TryNode = class extends BaseNode {
|
|
|
844
1132
|
scope.setPath(`self.${this.errorName}`, error);
|
|
845
1133
|
}
|
|
846
1134
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
scope.setPath
|
|
1135
|
+
const handlerResult = this.handler.evaluate(context);
|
|
1136
|
+
return resolveMaybe(handlerResult, () => {
|
|
1137
|
+
if (scope && scope.setPath && handlerScope === previousScope) {
|
|
1138
|
+
scope.setPath(this.errorName, previous);
|
|
1139
|
+
}
|
|
1140
|
+
context.scope = previousScope;
|
|
1141
|
+
return void 0;
|
|
1142
|
+
});
|
|
1143
|
+
};
|
|
1144
|
+
try {
|
|
1145
|
+
const bodyResult = evaluateWithChildScope(context, this.body);
|
|
1146
|
+
if (isPromiseLike(bodyResult)) {
|
|
1147
|
+
return bodyResult.catch((error) => handleError(error));
|
|
850
1148
|
}
|
|
851
|
-
|
|
1149
|
+
return bodyResult;
|
|
1150
|
+
} catch (error) {
|
|
1151
|
+
return handleError(error);
|
|
852
1152
|
}
|
|
853
1153
|
}
|
|
854
1154
|
};
|
|
@@ -868,11 +1168,35 @@ var FunctionExpression = class extends BaseNode {
|
|
|
868
1168
|
this.body = body;
|
|
869
1169
|
this.isAsync = isAsync;
|
|
870
1170
|
}
|
|
871
|
-
|
|
1171
|
+
evaluate(context) {
|
|
872
1172
|
const scope = context.scope;
|
|
873
1173
|
const globals = context.globals;
|
|
874
1174
|
const element = context.element;
|
|
875
|
-
|
|
1175
|
+
if (this.isAsync) {
|
|
1176
|
+
return (...args) => {
|
|
1177
|
+
const activeScope = scope?.createChild ? scope.createChild() : scope;
|
|
1178
|
+
const inner = {
|
|
1179
|
+
scope: activeScope,
|
|
1180
|
+
rootScope: context.rootScope,
|
|
1181
|
+
...globals ? { globals } : {},
|
|
1182
|
+
...element ? { element } : {},
|
|
1183
|
+
returnValue: void 0,
|
|
1184
|
+
returning: false,
|
|
1185
|
+
breaking: false,
|
|
1186
|
+
continuing: false
|
|
1187
|
+
};
|
|
1188
|
+
const previousValues = /* @__PURE__ */ new Map();
|
|
1189
|
+
const applyResult = activeScope ? this.applyParams(activeScope, previousValues, inner, args) : void 0;
|
|
1190
|
+
const bodyResult = resolveMaybe(applyResult, () => this.body.evaluate(inner));
|
|
1191
|
+
const finalResult = resolveMaybe(bodyResult, () => inner.returnValue);
|
|
1192
|
+
return Promise.resolve(finalResult).finally(() => {
|
|
1193
|
+
if (activeScope && activeScope === scope) {
|
|
1194
|
+
this.restoreParams(activeScope, previousValues);
|
|
1195
|
+
}
|
|
1196
|
+
});
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
return (...args) => {
|
|
876
1200
|
const activeScope = scope?.createChild ? scope.createChild() : scope;
|
|
877
1201
|
const inner = {
|
|
878
1202
|
scope: activeScope,
|
|
@@ -880,47 +1204,69 @@ var FunctionExpression = class extends BaseNode {
|
|
|
880
1204
|
...globals ? { globals } : {},
|
|
881
1205
|
...element ? { element } : {},
|
|
882
1206
|
returnValue: void 0,
|
|
883
|
-
returning: false
|
|
1207
|
+
returning: false,
|
|
1208
|
+
breaking: false,
|
|
1209
|
+
continuing: false
|
|
884
1210
|
};
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
1211
|
+
const previousValues = /* @__PURE__ */ new Map();
|
|
1212
|
+
const applyResult = activeScope ? this.applyParams(activeScope, previousValues, inner, args) : void 0;
|
|
1213
|
+
const bodyResult = resolveMaybe(applyResult, () => this.body.evaluate(inner));
|
|
1214
|
+
const finalResult = resolveMaybe(bodyResult, () => inner.returnValue);
|
|
1215
|
+
if (isPromiseLike(finalResult)) {
|
|
1216
|
+
return finalResult.finally(() => {
|
|
1217
|
+
if (activeScope && activeScope === scope) {
|
|
1218
|
+
this.restoreParams(activeScope, previousValues);
|
|
1219
|
+
}
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
if (activeScope && activeScope === scope) {
|
|
1223
|
+
this.restoreParams(activeScope, previousValues);
|
|
894
1224
|
}
|
|
895
|
-
return
|
|
1225
|
+
return finalResult;
|
|
896
1226
|
};
|
|
897
1227
|
}
|
|
898
|
-
|
|
899
|
-
if (!scope
|
|
1228
|
+
applyParams(scope, previousValues, context, args) {
|
|
1229
|
+
if (!scope) {
|
|
900
1230
|
return;
|
|
901
1231
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
if (!name) {
|
|
906
|
-
continue;
|
|
907
|
-
}
|
|
908
|
-
previousValues.set(name, scope.getPath(name));
|
|
909
|
-
if (param.rest) {
|
|
910
|
-
scope.setPath(`self.${name}`, args.slice(argIndex));
|
|
911
|
-
argIndex = args.length;
|
|
912
|
-
continue;
|
|
913
|
-
}
|
|
914
|
-
let value = args[argIndex];
|
|
915
|
-
if (value === void 0 && param.defaultValue) {
|
|
916
|
-
value = await param.defaultValue.evaluate(context);
|
|
917
|
-
}
|
|
918
|
-
scope.setPath(`self.${name}`, value);
|
|
919
|
-
argIndex += 1;
|
|
1232
|
+
const setPath = scope.setPath?.bind(scope);
|
|
1233
|
+
if (!setPath) {
|
|
1234
|
+
return;
|
|
920
1235
|
}
|
|
1236
|
+
const params = this.params;
|
|
1237
|
+
const applyAt = (paramIndex, argIndex) => {
|
|
1238
|
+
for (let i = paramIndex; i < params.length; i += 1) {
|
|
1239
|
+
const param = params[i];
|
|
1240
|
+
const name = param.name;
|
|
1241
|
+
if (!name) {
|
|
1242
|
+
continue;
|
|
1243
|
+
}
|
|
1244
|
+
previousValues.set(name, scope.getPath(name));
|
|
1245
|
+
if (param.rest) {
|
|
1246
|
+
setPath(`self.${name}`, args.slice(argIndex));
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1249
|
+
let value = args[argIndex];
|
|
1250
|
+
if (value === void 0 && param.defaultValue) {
|
|
1251
|
+
const defaultValue = param.defaultValue.evaluate(context);
|
|
1252
|
+
return resolveMaybe(defaultValue, (resolvedDefault) => {
|
|
1253
|
+
setPath(`self.${name}`, resolvedDefault);
|
|
1254
|
+
return applyAt(i + 1, argIndex + 1);
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
setPath(`self.${name}`, value);
|
|
1258
|
+
argIndex += 1;
|
|
1259
|
+
}
|
|
1260
|
+
return;
|
|
1261
|
+
};
|
|
1262
|
+
return applyAt(0, 0);
|
|
921
1263
|
}
|
|
922
1264
|
restoreParams(scope, previousValues) {
|
|
923
|
-
if (!scope
|
|
1265
|
+
if (!scope) {
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
const setPath = scope.setPath?.bind(scope);
|
|
1269
|
+
if (!setPath) {
|
|
924
1270
|
return;
|
|
925
1271
|
}
|
|
926
1272
|
for (const param of this.params) {
|
|
@@ -928,7 +1274,7 @@ var FunctionExpression = class extends BaseNode {
|
|
|
928
1274
|
if (!name) {
|
|
929
1275
|
continue;
|
|
930
1276
|
}
|
|
931
|
-
|
|
1277
|
+
setPath(name, previousValues.get(name));
|
|
932
1278
|
}
|
|
933
1279
|
}
|
|
934
1280
|
};
|
|
@@ -947,7 +1293,7 @@ var IdentifierExpression = class extends BaseNode {
|
|
|
947
1293
|
super("Identifier");
|
|
948
1294
|
this.name = name;
|
|
949
1295
|
}
|
|
950
|
-
|
|
1296
|
+
evaluate(context) {
|
|
951
1297
|
if (this.name.startsWith("root.") && context.rootScope) {
|
|
952
1298
|
const path = this.name.slice("root.".length);
|
|
953
1299
|
return context.rootScope.getPath(`self.${path}`);
|
|
@@ -992,7 +1338,7 @@ var LiteralExpression = class extends BaseNode {
|
|
|
992
1338
|
super("Literal");
|
|
993
1339
|
this.value = value;
|
|
994
1340
|
}
|
|
995
|
-
|
|
1341
|
+
evaluate() {
|
|
996
1342
|
return this.value;
|
|
997
1343
|
}
|
|
998
1344
|
};
|
|
@@ -1001,30 +1347,41 @@ var TemplateExpression = class extends BaseNode {
|
|
|
1001
1347
|
super("TemplateExpression");
|
|
1002
1348
|
this.parts = parts;
|
|
1003
1349
|
}
|
|
1004
|
-
|
|
1350
|
+
evaluate(context) {
|
|
1005
1351
|
let result = "";
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1352
|
+
let index = 0;
|
|
1353
|
+
const run = () => {
|
|
1354
|
+
while (index < this.parts.length) {
|
|
1355
|
+
const part = this.parts[index];
|
|
1356
|
+
index += 1;
|
|
1357
|
+
const value = part.evaluate(context);
|
|
1358
|
+
return resolveMaybe(value, (resolved) => {
|
|
1359
|
+
result += resolved == null ? "" : String(resolved);
|
|
1360
|
+
return run();
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
return result;
|
|
1364
|
+
};
|
|
1365
|
+
return run();
|
|
1011
1366
|
}
|
|
1012
1367
|
};
|
|
1013
1368
|
var UnaryExpression = class extends BaseNode {
|
|
1014
1369
|
constructor(operator, argument) {
|
|
1015
1370
|
super("UnaryExpression");
|
|
1016
1371
|
this.operator = operator;
|
|
1017
|
-
this.argument = argument;
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
const value =
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1372
|
+
this.argument = argument;
|
|
1373
|
+
}
|
|
1374
|
+
evaluate(context) {
|
|
1375
|
+
const value = this.argument.evaluate(context);
|
|
1376
|
+
return resolveMaybe(value, (resolved) => {
|
|
1377
|
+
if (this.operator === "!") {
|
|
1378
|
+
return !resolved;
|
|
1379
|
+
}
|
|
1380
|
+
if (this.operator === "-") {
|
|
1381
|
+
return -resolved;
|
|
1382
|
+
}
|
|
1383
|
+
return resolved;
|
|
1384
|
+
});
|
|
1028
1385
|
}
|
|
1029
1386
|
};
|
|
1030
1387
|
var BinaryExpression = class extends BaseNode {
|
|
@@ -1034,61 +1391,71 @@ var BinaryExpression = class extends BaseNode {
|
|
|
1034
1391
|
this.left = left;
|
|
1035
1392
|
this.right = right;
|
|
1036
1393
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
return
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1394
|
+
evaluate(context) {
|
|
1395
|
+
const leftValue = this.left.evaluate(context);
|
|
1396
|
+
return resolveMaybe(leftValue, (resolvedLeft) => {
|
|
1397
|
+
if (this.operator === "&&") {
|
|
1398
|
+
if (!resolvedLeft) {
|
|
1399
|
+
return resolvedLeft;
|
|
1400
|
+
}
|
|
1401
|
+
return this.right.evaluate(context);
|
|
1402
|
+
}
|
|
1403
|
+
if (this.operator === "||") {
|
|
1404
|
+
if (resolvedLeft) {
|
|
1405
|
+
return resolvedLeft;
|
|
1406
|
+
}
|
|
1407
|
+
return this.right.evaluate(context);
|
|
1408
|
+
}
|
|
1409
|
+
if (this.operator === "??") {
|
|
1410
|
+
if (resolvedLeft !== null && resolvedLeft !== void 0) {
|
|
1411
|
+
return resolvedLeft;
|
|
1412
|
+
}
|
|
1413
|
+
return this.right.evaluate(context);
|
|
1414
|
+
}
|
|
1415
|
+
const rightValue = this.right.evaluate(context);
|
|
1416
|
+
return resolveMaybe(rightValue, (resolvedRight) => {
|
|
1417
|
+
if (this.operator === "+") {
|
|
1418
|
+
return resolvedLeft + resolvedRight;
|
|
1419
|
+
}
|
|
1420
|
+
if (this.operator === "-") {
|
|
1421
|
+
return resolvedLeft - resolvedRight;
|
|
1422
|
+
}
|
|
1423
|
+
if (this.operator === "*") {
|
|
1424
|
+
return resolvedLeft * resolvedRight;
|
|
1425
|
+
}
|
|
1426
|
+
if (this.operator === "/") {
|
|
1427
|
+
return resolvedLeft / resolvedRight;
|
|
1428
|
+
}
|
|
1429
|
+
if (this.operator === "%") {
|
|
1430
|
+
return resolvedLeft % resolvedRight;
|
|
1431
|
+
}
|
|
1432
|
+
if (this.operator === "==") {
|
|
1433
|
+
return resolvedLeft == resolvedRight;
|
|
1434
|
+
}
|
|
1435
|
+
if (this.operator === "!=") {
|
|
1436
|
+
return resolvedLeft != resolvedRight;
|
|
1437
|
+
}
|
|
1438
|
+
if (this.operator === "===") {
|
|
1439
|
+
return resolvedLeft === resolvedRight;
|
|
1440
|
+
}
|
|
1441
|
+
if (this.operator === "!==") {
|
|
1442
|
+
return resolvedLeft !== resolvedRight;
|
|
1443
|
+
}
|
|
1444
|
+
if (this.operator === "<") {
|
|
1445
|
+
return resolvedLeft < resolvedRight;
|
|
1446
|
+
}
|
|
1447
|
+
if (this.operator === ">") {
|
|
1448
|
+
return resolvedLeft > resolvedRight;
|
|
1449
|
+
}
|
|
1450
|
+
if (this.operator === "<=") {
|
|
1451
|
+
return resolvedLeft <= resolvedRight;
|
|
1452
|
+
}
|
|
1453
|
+
if (this.operator === ">=") {
|
|
1454
|
+
return resolvedLeft >= resolvedRight;
|
|
1455
|
+
}
|
|
1456
|
+
return void 0;
|
|
1457
|
+
});
|
|
1458
|
+
});
|
|
1092
1459
|
}
|
|
1093
1460
|
};
|
|
1094
1461
|
var TernaryExpression = class extends BaseNode {
|
|
@@ -1098,12 +1465,14 @@ var TernaryExpression = class extends BaseNode {
|
|
|
1098
1465
|
this.consequent = consequent;
|
|
1099
1466
|
this.alternate = alternate;
|
|
1100
1467
|
}
|
|
1101
|
-
|
|
1102
|
-
const condition =
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1468
|
+
evaluate(context) {
|
|
1469
|
+
const condition = this.test.evaluate(context);
|
|
1470
|
+
return resolveMaybe(condition, (resolved) => {
|
|
1471
|
+
if (resolved) {
|
|
1472
|
+
return this.consequent.evaluate(context);
|
|
1473
|
+
}
|
|
1474
|
+
return this.alternate.evaluate(context);
|
|
1475
|
+
});
|
|
1107
1476
|
}
|
|
1108
1477
|
};
|
|
1109
1478
|
var MemberExpression = class _MemberExpression extends BaseNode {
|
|
@@ -1113,11 +1482,11 @@ var MemberExpression = class _MemberExpression extends BaseNode {
|
|
|
1113
1482
|
this.property = property;
|
|
1114
1483
|
this.optional = optional;
|
|
1115
1484
|
}
|
|
1116
|
-
|
|
1117
|
-
const resolved =
|
|
1118
|
-
return resolved?.value;
|
|
1485
|
+
evaluate(context) {
|
|
1486
|
+
const resolved = this.resolve(context);
|
|
1487
|
+
return resolveMaybe(resolved, (resolvedValue) => resolvedValue?.value);
|
|
1119
1488
|
}
|
|
1120
|
-
|
|
1489
|
+
resolve(context) {
|
|
1121
1490
|
const path = this.getIdentifierPath();
|
|
1122
1491
|
if (path) {
|
|
1123
1492
|
const resolved = this.resolveFromScope(context, path);
|
|
@@ -1129,11 +1498,13 @@ var MemberExpression = class _MemberExpression extends BaseNode {
|
|
|
1129
1498
|
return resolvedGlobal;
|
|
1130
1499
|
}
|
|
1131
1500
|
}
|
|
1132
|
-
const target =
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1501
|
+
const target = this.target.evaluate(context);
|
|
1502
|
+
return resolveMaybe(target, (resolvedTarget) => {
|
|
1503
|
+
if (resolvedTarget == null) {
|
|
1504
|
+
return { value: void 0, target: resolvedTarget, optional: this.optional };
|
|
1505
|
+
}
|
|
1506
|
+
return { value: resolvedTarget[this.property], target: resolvedTarget, optional: this.optional };
|
|
1507
|
+
});
|
|
1137
1508
|
}
|
|
1138
1509
|
getIdentifierPath() {
|
|
1139
1510
|
const targetPath = this.getTargetIdentifierPath();
|
|
@@ -1209,25 +1580,39 @@ var CallExpression = class extends BaseNode {
|
|
|
1209
1580
|
this.callee = callee;
|
|
1210
1581
|
this.args = args;
|
|
1211
1582
|
}
|
|
1212
|
-
|
|
1213
|
-
const resolved =
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
return
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1583
|
+
evaluate(context) {
|
|
1584
|
+
const resolved = this.resolveCallee(context);
|
|
1585
|
+
return resolveMaybe(resolved, (resolvedCallee) => {
|
|
1586
|
+
const fnValue = resolvedCallee?.fn ?? this.callee.evaluate(context);
|
|
1587
|
+
return resolveMaybe(fnValue, (resolvedFn) => {
|
|
1588
|
+
if (typeof resolvedFn !== "function") {
|
|
1589
|
+
return void 0;
|
|
1590
|
+
}
|
|
1591
|
+
const values = [];
|
|
1592
|
+
const evalArgs = (index) => {
|
|
1593
|
+
for (let i = index; i < this.args.length; i += 1) {
|
|
1594
|
+
const arg = this.args[i];
|
|
1595
|
+
const argValue = arg.evaluate(context);
|
|
1596
|
+
return resolveMaybe(argValue, (resolvedArg) => {
|
|
1597
|
+
values.push(resolvedArg);
|
|
1598
|
+
return evalArgs(i + 1);
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
return resolvedFn.apply(resolvedCallee?.thisArg, values);
|
|
1602
|
+
};
|
|
1603
|
+
return evalArgs(0);
|
|
1604
|
+
});
|
|
1605
|
+
});
|
|
1223
1606
|
}
|
|
1224
|
-
|
|
1607
|
+
resolveCallee(context) {
|
|
1225
1608
|
if (this.callee instanceof MemberExpression) {
|
|
1226
|
-
const resolved =
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1609
|
+
const resolved = this.callee.resolve(context);
|
|
1610
|
+
return resolveMaybe(resolved, (resolvedValue) => {
|
|
1611
|
+
if (!resolvedValue) {
|
|
1612
|
+
return void 0;
|
|
1613
|
+
}
|
|
1614
|
+
return { fn: resolvedValue.value, thisArg: resolvedValue.target };
|
|
1615
|
+
});
|
|
1231
1616
|
}
|
|
1232
1617
|
if (!(this.callee instanceof IdentifierExpression)) {
|
|
1233
1618
|
return void 0;
|
|
@@ -1269,27 +1654,40 @@ var ArrayExpression = class extends BaseNode {
|
|
|
1269
1654
|
super("ArrayExpression");
|
|
1270
1655
|
this.elements = elements;
|
|
1271
1656
|
}
|
|
1272
|
-
|
|
1657
|
+
evaluate(context) {
|
|
1273
1658
|
const values = [];
|
|
1274
|
-
|
|
1275
|
-
if (
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1659
|
+
const pushElements = (value) => {
|
|
1660
|
+
if (value == null) {
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
const iterator = value[Symbol.iterator];
|
|
1664
|
+
if (typeof iterator === "function") {
|
|
1665
|
+
for (const entry of value) {
|
|
1666
|
+
values.push(entry);
|
|
1279
1667
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1668
|
+
} else {
|
|
1669
|
+
values.push(value);
|
|
1670
|
+
}
|
|
1671
|
+
};
|
|
1672
|
+
const evalAt = (index) => {
|
|
1673
|
+
for (let i = index; i < this.elements.length; i += 1) {
|
|
1674
|
+
const element = this.elements[i];
|
|
1675
|
+
if (element instanceof SpreadElement) {
|
|
1676
|
+
const spreadValue = element.value.evaluate(context);
|
|
1677
|
+
return resolveMaybe(spreadValue, (resolvedSpread) => {
|
|
1678
|
+
pushElements(resolvedSpread);
|
|
1679
|
+
return evalAt(i + 1);
|
|
1680
|
+
});
|
|
1287
1681
|
}
|
|
1288
|
-
|
|
1682
|
+
const value = element.evaluate(context);
|
|
1683
|
+
return resolveMaybe(value, (resolvedValue) => {
|
|
1684
|
+
values.push(resolvedValue);
|
|
1685
|
+
return evalAt(i + 1);
|
|
1686
|
+
});
|
|
1289
1687
|
}
|
|
1290
|
-
values
|
|
1291
|
-
}
|
|
1292
|
-
return
|
|
1688
|
+
return values;
|
|
1689
|
+
};
|
|
1690
|
+
return evalAt(0);
|
|
1293
1691
|
}
|
|
1294
1692
|
};
|
|
1295
1693
|
var ObjectExpression = class extends BaseNode {
|
|
@@ -1297,24 +1695,39 @@ var ObjectExpression = class extends BaseNode {
|
|
|
1297
1695
|
super("ObjectExpression");
|
|
1298
1696
|
this.entries = entries;
|
|
1299
1697
|
}
|
|
1300
|
-
|
|
1698
|
+
evaluate(context) {
|
|
1301
1699
|
const result = {};
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
const
|
|
1305
|
-
if (
|
|
1306
|
-
|
|
1700
|
+
const evalAt = (index) => {
|
|
1701
|
+
for (let i = index; i < this.entries.length; i += 1) {
|
|
1702
|
+
const entry = this.entries[i];
|
|
1703
|
+
if ("spread" in entry) {
|
|
1704
|
+
const spreadValue = entry.spread.evaluate(context);
|
|
1705
|
+
return resolveMaybe(spreadValue, (resolvedSpread) => {
|
|
1706
|
+
if (resolvedSpread != null) {
|
|
1707
|
+
Object.assign(result, resolvedSpread);
|
|
1708
|
+
}
|
|
1709
|
+
return evalAt(i + 1);
|
|
1710
|
+
});
|
|
1307
1711
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1712
|
+
if ("computed" in entry && entry.computed) {
|
|
1713
|
+
const keyValue = entry.keyExpr.evaluate(context);
|
|
1714
|
+
return resolveMaybe(keyValue, (resolvedKey) => {
|
|
1715
|
+
const entryValue = entry.value.evaluate(context);
|
|
1716
|
+
return resolveMaybe(entryValue, (resolvedValue) => {
|
|
1717
|
+
result[String(resolvedKey)] = resolvedValue;
|
|
1718
|
+
return evalAt(i + 1);
|
|
1719
|
+
});
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1722
|
+
const value = entry.value.evaluate(context);
|
|
1723
|
+
return resolveMaybe(value, (resolvedValue) => {
|
|
1724
|
+
result[entry.key] = resolvedValue;
|
|
1725
|
+
return evalAt(i + 1);
|
|
1726
|
+
});
|
|
1315
1727
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1728
|
+
return result;
|
|
1729
|
+
};
|
|
1730
|
+
return evalAt(0);
|
|
1318
1731
|
}
|
|
1319
1732
|
};
|
|
1320
1733
|
var IndexExpression = class extends BaseNode {
|
|
@@ -1323,16 +1736,30 @@ var IndexExpression = class extends BaseNode {
|
|
|
1323
1736
|
this.target = target;
|
|
1324
1737
|
this.index = index;
|
|
1325
1738
|
}
|
|
1326
|
-
|
|
1327
|
-
const target =
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
return
|
|
1739
|
+
evaluate(context) {
|
|
1740
|
+
const target = this.target.evaluate(context);
|
|
1741
|
+
return resolveMaybe(target, (resolvedTarget) => {
|
|
1742
|
+
if (resolvedTarget == null) {
|
|
1743
|
+
return void 0;
|
|
1744
|
+
}
|
|
1745
|
+
const index = this.index.evaluate(context);
|
|
1746
|
+
return resolveMaybe(index, (resolvedIndex) => {
|
|
1747
|
+
if (resolvedIndex == null) {
|
|
1748
|
+
return void 0;
|
|
1749
|
+
}
|
|
1750
|
+
const key = this.normalizeIndexKey(resolvedTarget, resolvedIndex);
|
|
1751
|
+
return resolvedTarget[key];
|
|
1752
|
+
});
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1755
|
+
normalizeIndexKey(target, index) {
|
|
1756
|
+
if (Array.isArray(target) && typeof index === "string" && index.trim() !== "") {
|
|
1757
|
+
const numeric = Number(index);
|
|
1758
|
+
if (!Number.isNaN(numeric)) {
|
|
1759
|
+
return numeric;
|
|
1760
|
+
}
|
|
1334
1761
|
}
|
|
1335
|
-
return
|
|
1762
|
+
return index;
|
|
1336
1763
|
}
|
|
1337
1764
|
};
|
|
1338
1765
|
var DirectiveExpression = class extends BaseNode {
|
|
@@ -1341,7 +1768,7 @@ var DirectiveExpression = class extends BaseNode {
|
|
|
1341
1768
|
this.kind = kind;
|
|
1342
1769
|
this.name = name;
|
|
1343
1770
|
}
|
|
1344
|
-
|
|
1771
|
+
evaluate(context) {
|
|
1345
1772
|
const element = context.element;
|
|
1346
1773
|
if (!element) {
|
|
1347
1774
|
return `${this.kind}:${this.name}`;
|
|
@@ -1355,6 +1782,12 @@ var DirectiveExpression = class extends BaseNode {
|
|
|
1355
1782
|
return element.value;
|
|
1356
1783
|
}
|
|
1357
1784
|
}
|
|
1785
|
+
if (this.name === "text" && element instanceof HTMLElement) {
|
|
1786
|
+
return element.innerText;
|
|
1787
|
+
}
|
|
1788
|
+
if (this.name === "content" && element instanceof HTMLElement) {
|
|
1789
|
+
return element.textContent ?? "";
|
|
1790
|
+
}
|
|
1358
1791
|
if (this.name === "checked" && element instanceof HTMLInputElement) {
|
|
1359
1792
|
return element.checked;
|
|
1360
1793
|
}
|
|
@@ -1374,9 +1807,9 @@ var AwaitExpression = class extends BaseNode {
|
|
|
1374
1807
|
super("AwaitExpression");
|
|
1375
1808
|
this.argument = argument;
|
|
1376
1809
|
}
|
|
1377
|
-
|
|
1378
|
-
const value =
|
|
1379
|
-
return
|
|
1810
|
+
evaluate(context) {
|
|
1811
|
+
const value = this.argument.evaluate(context);
|
|
1812
|
+
return Promise.resolve(value);
|
|
1380
1813
|
}
|
|
1381
1814
|
};
|
|
1382
1815
|
var QueryExpression = class extends BaseNode {
|
|
@@ -1385,7 +1818,7 @@ var QueryExpression = class extends BaseNode {
|
|
|
1385
1818
|
this.direction = direction;
|
|
1386
1819
|
this.selector = selector;
|
|
1387
1820
|
}
|
|
1388
|
-
|
|
1821
|
+
evaluate(context) {
|
|
1389
1822
|
const selector = this.selector.trim();
|
|
1390
1823
|
if (!selector) {
|
|
1391
1824
|
return [];
|
|
@@ -1451,6 +1884,9 @@ var TokenStream = class {
|
|
|
1451
1884
|
let count = 0;
|
|
1452
1885
|
for (let i = this.index; i < this.tokens.length; i++) {
|
|
1453
1886
|
const token = this.tokens[i];
|
|
1887
|
+
if (!token) {
|
|
1888
|
+
continue;
|
|
1889
|
+
}
|
|
1454
1890
|
if (token.type === "Whitespace" /* Whitespace */) {
|
|
1455
1891
|
continue;
|
|
1456
1892
|
}
|
|
@@ -1461,6 +1897,29 @@ var TokenStream = class {
|
|
|
1461
1897
|
}
|
|
1462
1898
|
return null;
|
|
1463
1899
|
}
|
|
1900
|
+
indexAfterDelimited(openType, closeType, offset = 0) {
|
|
1901
|
+
const first = this.peekNonWhitespace(offset);
|
|
1902
|
+
if (!first || first.type !== openType) {
|
|
1903
|
+
return null;
|
|
1904
|
+
}
|
|
1905
|
+
let index = offset + 1;
|
|
1906
|
+
let depth = 1;
|
|
1907
|
+
while (true) {
|
|
1908
|
+
const token = this.peekNonWhitespace(index);
|
|
1909
|
+
if (!token) {
|
|
1910
|
+
return null;
|
|
1911
|
+
}
|
|
1912
|
+
if (token.type === openType) {
|
|
1913
|
+
depth += 1;
|
|
1914
|
+
} else if (token.type === closeType) {
|
|
1915
|
+
depth -= 1;
|
|
1916
|
+
if (depth === 0) {
|
|
1917
|
+
return index + 1;
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
index += 1;
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1464
1923
|
};
|
|
1465
1924
|
|
|
1466
1925
|
// src/parser/parser.ts
|
|
@@ -1468,11 +1927,14 @@ var Parser = class _Parser {
|
|
|
1468
1927
|
stream;
|
|
1469
1928
|
source;
|
|
1470
1929
|
customFlags;
|
|
1930
|
+
behaviorFlags;
|
|
1471
1931
|
allowImplicitSemicolon = false;
|
|
1472
1932
|
awaitStack = [];
|
|
1933
|
+
functionDepth = 0;
|
|
1473
1934
|
constructor(input, options) {
|
|
1474
1935
|
this.source = input;
|
|
1475
|
-
this.customFlags = options?.customFlags ?? /* @__PURE__ */ new Set();
|
|
1936
|
+
this.customFlags = options?.customFlags ?? /* @__PURE__ */ new Set(["important", "trusted", "debounce"]);
|
|
1937
|
+
this.behaviorFlags = options?.behaviorFlags ?? /* @__PURE__ */ new Set();
|
|
1476
1938
|
const lexer = new Lexer(input);
|
|
1477
1939
|
this.stream = new TokenStream(lexer.tokenize());
|
|
1478
1940
|
}
|
|
@@ -1512,8 +1974,9 @@ var Parser = class _Parser {
|
|
|
1512
1974
|
this.stream.skipWhitespace();
|
|
1513
1975
|
this.stream.expect("Behavior" /* Behavior */);
|
|
1514
1976
|
const selector = this.parseSelector();
|
|
1977
|
+
const { flags, flagArgs } = this.parseBehaviorFlags();
|
|
1515
1978
|
const body = this.parseBlock({ allowDeclarations: true });
|
|
1516
|
-
return new BehaviorNode(selector, body);
|
|
1979
|
+
return new BehaviorNode(selector, body, flags, flagArgs);
|
|
1517
1980
|
});
|
|
1518
1981
|
}
|
|
1519
1982
|
parseSelector() {
|
|
@@ -1527,6 +1990,9 @@ var Parser = class _Parser {
|
|
|
1527
1990
|
if (token.type === "LBrace" /* LBrace */) {
|
|
1528
1991
|
break;
|
|
1529
1992
|
}
|
|
1993
|
+
if (token.type === "Bang" /* Bang */) {
|
|
1994
|
+
break;
|
|
1995
|
+
}
|
|
1530
1996
|
if (token.type === "Whitespace" /* Whitespace */) {
|
|
1531
1997
|
this.stream.next();
|
|
1532
1998
|
if (sawNonWhitespace && selectorText[selectorText.length - 1] !== " ") {
|
|
@@ -1542,6 +2008,10 @@ var Parser = class _Parser {
|
|
|
1542
2008
|
}
|
|
1543
2009
|
return new SelectorNode(selectorText.trim());
|
|
1544
2010
|
}
|
|
2011
|
+
parseBehaviorFlags() {
|
|
2012
|
+
const result = this.parseFlags(this.behaviorFlags, "behavior modifier");
|
|
2013
|
+
return { flags: result.flags, flagArgs: result.flagArgs };
|
|
2014
|
+
}
|
|
1545
2015
|
parseUseStatement() {
|
|
1546
2016
|
return this.wrapErrors(() => {
|
|
1547
2017
|
this.stream.expect("Use" /* Use */);
|
|
@@ -1625,6 +2095,7 @@ ${caret}`;
|
|
|
1625
2095
|
}
|
|
1626
2096
|
parseBlock(options) {
|
|
1627
2097
|
const allowDeclarations = options?.allowDeclarations ?? false;
|
|
2098
|
+
const allowReturn = options?.allowReturn ?? this.functionDepth > 0;
|
|
1628
2099
|
this.stream.skipWhitespace();
|
|
1629
2100
|
this.stream.expect("LBrace" /* LBrace */);
|
|
1630
2101
|
const statements = [];
|
|
@@ -1686,7 +2157,7 @@ ${caret}`;
|
|
|
1686
2157
|
}
|
|
1687
2158
|
sawConstruct = true;
|
|
1688
2159
|
}
|
|
1689
|
-
statements.push(this.parseStatement());
|
|
2160
|
+
statements.push(this.parseStatement({ allowReturn }));
|
|
1690
2161
|
}
|
|
1691
2162
|
}
|
|
1692
2163
|
return new BlockNode(statements);
|
|
@@ -1705,6 +2176,15 @@ ${caret}`;
|
|
|
1705
2176
|
}
|
|
1706
2177
|
return this.parseReturnStatement();
|
|
1707
2178
|
}
|
|
2179
|
+
if (next.type === "Assert" /* Assert */) {
|
|
2180
|
+
return this.parseAssertStatement();
|
|
2181
|
+
}
|
|
2182
|
+
if (next.type === "Break" /* Break */) {
|
|
2183
|
+
return this.parseBreakStatement();
|
|
2184
|
+
}
|
|
2185
|
+
if (next.type === "Continue" /* Continue */) {
|
|
2186
|
+
return this.parseContinueStatement();
|
|
2187
|
+
}
|
|
1708
2188
|
if (allowBlocks && next.type === "On" /* On */) {
|
|
1709
2189
|
return this.parseOnBlock();
|
|
1710
2190
|
}
|
|
@@ -1740,44 +2220,6 @@ ${caret}`;
|
|
|
1740
2220
|
}
|
|
1741
2221
|
throw new Error(`Unexpected token ${next.type}`);
|
|
1742
2222
|
}
|
|
1743
|
-
parseStateBlock() {
|
|
1744
|
-
this.stream.expect("State" /* State */);
|
|
1745
|
-
this.stream.skipWhitespace();
|
|
1746
|
-
this.stream.expect("LBrace" /* LBrace */);
|
|
1747
|
-
const entries = [];
|
|
1748
|
-
while (true) {
|
|
1749
|
-
this.stream.skipWhitespace();
|
|
1750
|
-
const next = this.stream.peek();
|
|
1751
|
-
if (!next) {
|
|
1752
|
-
throw new Error("Unterminated state block");
|
|
1753
|
-
}
|
|
1754
|
-
if (next.type === "RBrace" /* RBrace */) {
|
|
1755
|
-
this.stream.next();
|
|
1756
|
-
break;
|
|
1757
|
-
}
|
|
1758
|
-
const nameToken = this.stream.expect("Identifier" /* Identifier */);
|
|
1759
|
-
this.stream.skipWhitespace();
|
|
1760
|
-
this.stream.expect("Colon" /* Colon */);
|
|
1761
|
-
this.stream.skipWhitespace();
|
|
1762
|
-
const value = this.parseExpression();
|
|
1763
|
-
this.stream.skipWhitespace();
|
|
1764
|
-
let important = false;
|
|
1765
|
-
if (this.stream.peek()?.type === "Bang" /* Bang */) {
|
|
1766
|
-
this.stream.next();
|
|
1767
|
-
this.stream.skipWhitespace();
|
|
1768
|
-
const importantToken = this.stream.next();
|
|
1769
|
-
if (importantToken.type === "Identifier" /* Identifier */ && importantToken.value === "important") {
|
|
1770
|
-
important = true;
|
|
1771
|
-
} else {
|
|
1772
|
-
throw new Error("Expected 'important' after '!'");
|
|
1773
|
-
}
|
|
1774
|
-
}
|
|
1775
|
-
this.stream.skipWhitespace();
|
|
1776
|
-
this.stream.expect("Semicolon" /* Semicolon */);
|
|
1777
|
-
entries.push(new StateEntryNode(nameToken.value, value, important));
|
|
1778
|
-
}
|
|
1779
|
-
return new StateBlockNode(entries);
|
|
1780
|
-
}
|
|
1781
2223
|
parseOnBlock() {
|
|
1782
2224
|
this.stream.expect("On" /* On */);
|
|
1783
2225
|
this.stream.skipWhitespace();
|
|
@@ -1805,22 +2247,9 @@ ${caret}`;
|
|
|
1805
2247
|
}
|
|
1806
2248
|
throw new Error(`Unexpected token in on() args: ${next.type}`);
|
|
1807
2249
|
}
|
|
1808
|
-
const
|
|
2250
|
+
const { flags, flagArgs } = this.parseFlags(this.customFlags, "flag");
|
|
1809
2251
|
const body = this.parseBlock({ allowDeclarations: false });
|
|
1810
|
-
return new OnBlockNode(event, args, body,
|
|
1811
|
-
}
|
|
1812
|
-
parseOnModifiers() {
|
|
1813
|
-
const modifiers = [];
|
|
1814
|
-
while (true) {
|
|
1815
|
-
this.stream.skipWhitespace();
|
|
1816
|
-
if (this.stream.peek()?.type !== "Bang" /* Bang */) {
|
|
1817
|
-
break;
|
|
1818
|
-
}
|
|
1819
|
-
this.stream.next();
|
|
1820
|
-
const name = this.stream.expect("Identifier" /* Identifier */).value;
|
|
1821
|
-
modifiers.push(name);
|
|
1822
|
-
}
|
|
1823
|
-
return modifiers;
|
|
2252
|
+
return new OnBlockNode(event, args, body, flags, flagArgs);
|
|
1824
2253
|
}
|
|
1825
2254
|
parseAssignment() {
|
|
1826
2255
|
const target = this.parseAssignmentTarget();
|
|
@@ -2030,6 +2459,11 @@ ${caret}`;
|
|
|
2030
2459
|
if (!token) {
|
|
2031
2460
|
throw new Error("Expected expression");
|
|
2032
2461
|
}
|
|
2462
|
+
if (token.type === "PlusPlus" /* PlusPlus */ || token.type === "MinusMinus" /* MinusMinus */) {
|
|
2463
|
+
this.stream.next();
|
|
2464
|
+
const argument = this.parseUnaryExpression();
|
|
2465
|
+
return this.createIncrementNode(token, argument, true);
|
|
2466
|
+
}
|
|
2033
2467
|
if (token.type === "Bang" /* Bang */) {
|
|
2034
2468
|
this.stream.next();
|
|
2035
2469
|
const argument = this.parseUnaryExpression();
|
|
@@ -2045,7 +2479,31 @@ ${caret}`;
|
|
|
2045
2479
|
const argument = this.parseUnaryExpression();
|
|
2046
2480
|
return new AwaitExpression(argument);
|
|
2047
2481
|
}
|
|
2048
|
-
return this.
|
|
2482
|
+
return this.parsePostfixExpression();
|
|
2483
|
+
}
|
|
2484
|
+
parsePostfixExpression() {
|
|
2485
|
+
let expr = this.parseCallExpression();
|
|
2486
|
+
while (true) {
|
|
2487
|
+
this.stream.skipWhitespace();
|
|
2488
|
+
const token = this.stream.peek();
|
|
2489
|
+
if (!token) {
|
|
2490
|
+
break;
|
|
2491
|
+
}
|
|
2492
|
+
if (token.type === "PlusPlus" /* PlusPlus */ || token.type === "MinusMinus" /* MinusMinus */) {
|
|
2493
|
+
this.stream.next();
|
|
2494
|
+
expr = this.createIncrementNode(token, expr, false);
|
|
2495
|
+
continue;
|
|
2496
|
+
}
|
|
2497
|
+
break;
|
|
2498
|
+
}
|
|
2499
|
+
return expr;
|
|
2500
|
+
}
|
|
2501
|
+
createIncrementNode(token, argument, prefix) {
|
|
2502
|
+
if (!(argument instanceof IdentifierExpression) && !(argument instanceof MemberExpression) && !(argument instanceof IndexExpression) && !(argument instanceof DirectiveExpression)) {
|
|
2503
|
+
throw new Error("Increment/decrement requires a mutable target");
|
|
2504
|
+
}
|
|
2505
|
+
const operator = token.type === "PlusPlus" /* PlusPlus */ ? "++" : "--";
|
|
2506
|
+
return new AssignmentNode(argument, new LiteralExpression(1), operator, prefix);
|
|
2049
2507
|
}
|
|
2050
2508
|
parseCallExpression() {
|
|
2051
2509
|
let expr = this.parsePrimaryExpression();
|
|
@@ -2357,6 +2815,7 @@ ${caret}`;
|
|
|
2357
2815
|
this.stream.expect("LBrace" /* LBrace */);
|
|
2358
2816
|
const statements = [];
|
|
2359
2817
|
this.awaitStack.push(allowAwait);
|
|
2818
|
+
this.functionDepth += 1;
|
|
2360
2819
|
try {
|
|
2361
2820
|
while (true) {
|
|
2362
2821
|
this.stream.skipWhitespace();
|
|
@@ -2368,9 +2827,10 @@ ${caret}`;
|
|
|
2368
2827
|
this.stream.next();
|
|
2369
2828
|
break;
|
|
2370
2829
|
}
|
|
2371
|
-
statements.push(this.parseStatement({ allowBlocks:
|
|
2830
|
+
statements.push(this.parseStatement({ allowBlocks: true, allowReturn: true }));
|
|
2372
2831
|
}
|
|
2373
2832
|
} finally {
|
|
2833
|
+
this.functionDepth -= 1;
|
|
2374
2834
|
this.awaitStack.pop();
|
|
2375
2835
|
}
|
|
2376
2836
|
return new BlockNode(statements);
|
|
@@ -2566,7 +3026,7 @@ ${caret}`;
|
|
|
2566
3026
|
const operator = this.parseDeclarationOperator();
|
|
2567
3027
|
this.stream.skipWhitespace();
|
|
2568
3028
|
const value = this.parseExpression();
|
|
2569
|
-
const { flags, flagArgs } = this.parseFlags();
|
|
3029
|
+
const { flags, flagArgs } = this.parseFlags(this.customFlags, "flag");
|
|
2570
3030
|
this.stream.skipWhitespace();
|
|
2571
3031
|
this.stream.expect("Semicolon" /* Semicolon */);
|
|
2572
3032
|
return new DeclarationNode(target, operator, value, flags, flagArgs);
|
|
@@ -2607,7 +3067,7 @@ ${caret}`;
|
|
|
2607
3067
|
}
|
|
2608
3068
|
return ":";
|
|
2609
3069
|
}
|
|
2610
|
-
parseFlags() {
|
|
3070
|
+
parseFlags(allowed, errorLabel) {
|
|
2611
3071
|
const flags = {};
|
|
2612
3072
|
const flagArgs = {};
|
|
2613
3073
|
while (true) {
|
|
@@ -2617,59 +3077,107 @@ ${caret}`;
|
|
|
2617
3077
|
}
|
|
2618
3078
|
this.stream.next();
|
|
2619
3079
|
const name = this.stream.expect("Identifier" /* Identifier */).value;
|
|
2620
|
-
if (
|
|
2621
|
-
|
|
2622
|
-
}
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
3080
|
+
if (allowed && !allowed.has(name)) {
|
|
3081
|
+
throw new Error(`Unknown ${errorLabel} ${name}`);
|
|
3082
|
+
}
|
|
3083
|
+
flags[name] = true;
|
|
3084
|
+
const customArg = this.parseCustomFlagArg();
|
|
3085
|
+
if (customArg !== void 0) {
|
|
3086
|
+
flagArgs[name] = customArg;
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
return { flags, flagArgs };
|
|
3090
|
+
}
|
|
3091
|
+
parseCustomFlagArg() {
|
|
3092
|
+
if (this.stream.peek()?.type !== "LParen" /* LParen */) {
|
|
3093
|
+
return void 0;
|
|
3094
|
+
}
|
|
3095
|
+
this.stream.next();
|
|
3096
|
+
this.stream.skipWhitespace();
|
|
3097
|
+
const token = this.stream.peek();
|
|
3098
|
+
if (!token) {
|
|
3099
|
+
throw new Error("Unterminated flag arguments");
|
|
3100
|
+
}
|
|
3101
|
+
const value = this.parseCustomFlagLiteral();
|
|
3102
|
+
this.stream.skipWhitespace();
|
|
3103
|
+
this.stream.expect("RParen" /* RParen */);
|
|
3104
|
+
return value;
|
|
3105
|
+
}
|
|
3106
|
+
parseCustomFlagLiteral() {
|
|
3107
|
+
const token = this.stream.peek();
|
|
3108
|
+
if (!token) {
|
|
3109
|
+
throw new Error("Unterminated flag arguments");
|
|
3110
|
+
}
|
|
3111
|
+
if (token.type === "Number" /* Number */) {
|
|
3112
|
+
return Number(this.stream.next().value);
|
|
3113
|
+
}
|
|
3114
|
+
if (token.type === "String" /* String */) {
|
|
3115
|
+
return this.stream.next().value;
|
|
3116
|
+
}
|
|
3117
|
+
if (token.type === "Boolean" /* Boolean */) {
|
|
3118
|
+
return this.stream.next().value === "true";
|
|
3119
|
+
}
|
|
3120
|
+
if (token.type === "Identifier" /* Identifier */) {
|
|
3121
|
+
return this.stream.next().value;
|
|
3122
|
+
}
|
|
3123
|
+
if (token.type === "LBracket" /* LBracket */) {
|
|
3124
|
+
return this.parseCustomFlagArray();
|
|
3125
|
+
}
|
|
3126
|
+
if (token.type === "LBrace" /* LBrace */) {
|
|
3127
|
+
return this.parseCustomFlagObject();
|
|
3128
|
+
}
|
|
3129
|
+
throw new Error(`Unsupported flag argument ${token.type}`);
|
|
3130
|
+
}
|
|
3131
|
+
parseCustomFlagArray() {
|
|
3132
|
+
this.stream.expect("LBracket" /* LBracket */);
|
|
3133
|
+
const items = [];
|
|
3134
|
+
while (true) {
|
|
3135
|
+
this.stream.skipWhitespace();
|
|
3136
|
+
const next = this.stream.peek();
|
|
3137
|
+
if (!next) {
|
|
3138
|
+
throw new Error("Unterminated flag array");
|
|
3139
|
+
}
|
|
3140
|
+
if (next.type === "RBracket" /* RBracket */) {
|
|
3141
|
+
this.stream.next();
|
|
3142
|
+
break;
|
|
3143
|
+
}
|
|
3144
|
+
items.push(this.parseCustomFlagLiteral());
|
|
3145
|
+
this.stream.skipWhitespace();
|
|
3146
|
+
if (this.stream.peek()?.type === "Comma" /* Comma */) {
|
|
3147
|
+
this.stream.next();
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
return items;
|
|
3151
|
+
}
|
|
3152
|
+
parseCustomFlagObject() {
|
|
3153
|
+
this.stream.expect("LBrace" /* LBrace */);
|
|
3154
|
+
const obj = {};
|
|
3155
|
+
while (true) {
|
|
3156
|
+
this.stream.skipWhitespace();
|
|
3157
|
+
const next = this.stream.peek();
|
|
3158
|
+
if (!next) {
|
|
3159
|
+
throw new Error("Unterminated flag object");
|
|
3160
|
+
}
|
|
3161
|
+
if (next.type === "RBrace" /* RBrace */) {
|
|
3162
|
+
this.stream.next();
|
|
3163
|
+
break;
|
|
3164
|
+
}
|
|
3165
|
+
let key;
|
|
3166
|
+
if (next.type === "Identifier" /* Identifier */ || next.type === "String" /* String */) {
|
|
3167
|
+
key = this.stream.next().value;
|
|
2642
3168
|
} else {
|
|
2643
|
-
throw new Error(`
|
|
3169
|
+
throw new Error(`Unsupported flag object key ${next.type}`);
|
|
3170
|
+
}
|
|
3171
|
+
this.stream.skipWhitespace();
|
|
3172
|
+
this.stream.expect("Colon" /* Colon */);
|
|
3173
|
+
this.stream.skipWhitespace();
|
|
3174
|
+
obj[key] = this.parseCustomFlagLiteral();
|
|
3175
|
+
this.stream.skipWhitespace();
|
|
3176
|
+
if (this.stream.peek()?.type === "Comma" /* Comma */) {
|
|
3177
|
+
this.stream.next();
|
|
2644
3178
|
}
|
|
2645
3179
|
}
|
|
2646
|
-
return
|
|
2647
|
-
}
|
|
2648
|
-
parseCustomFlagArg() {
|
|
2649
|
-
if (this.stream.peek()?.type !== "LParen" /* LParen */) {
|
|
2650
|
-
return void 0;
|
|
2651
|
-
}
|
|
2652
|
-
this.stream.next();
|
|
2653
|
-
this.stream.skipWhitespace();
|
|
2654
|
-
const token = this.stream.peek();
|
|
2655
|
-
if (!token) {
|
|
2656
|
-
throw new Error("Unterminated flag arguments");
|
|
2657
|
-
}
|
|
2658
|
-
let value;
|
|
2659
|
-
if (token.type === "Number" /* Number */) {
|
|
2660
|
-
value = Number(this.stream.next().value);
|
|
2661
|
-
} else if (token.type === "String" /* String */) {
|
|
2662
|
-
value = this.stream.next().value;
|
|
2663
|
-
} else if (token.type === "Boolean" /* Boolean */) {
|
|
2664
|
-
value = this.stream.next().value === "true";
|
|
2665
|
-
} else if (token.type === "Identifier" /* Identifier */) {
|
|
2666
|
-
value = this.stream.next().value;
|
|
2667
|
-
} else {
|
|
2668
|
-
throw new Error(`Unsupported flag argument ${token.type}`);
|
|
2669
|
-
}
|
|
2670
|
-
this.stream.skipWhitespace();
|
|
2671
|
-
this.stream.expect("RParen" /* RParen */);
|
|
2672
|
-
return value;
|
|
3180
|
+
return obj;
|
|
2673
3181
|
}
|
|
2674
3182
|
isDeclarationStart() {
|
|
2675
3183
|
const first = this.stream.peekNonWhitespace(0);
|
|
@@ -2694,33 +3202,29 @@ ${caret}`;
|
|
|
2694
3202
|
}
|
|
2695
3203
|
if (first.type === "Identifier" /* Identifier */) {
|
|
2696
3204
|
let index = 1;
|
|
2697
|
-
while (
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
3205
|
+
while (true) {
|
|
3206
|
+
const token = this.stream.peekNonWhitespace(index);
|
|
3207
|
+
if (!token) {
|
|
3208
|
+
return false;
|
|
3209
|
+
}
|
|
3210
|
+
if (token.type === "Dot" /* Dot */ && this.stream.peekNonWhitespace(index + 1)?.type === "Identifier" /* Identifier */) {
|
|
3211
|
+
index += 2;
|
|
3212
|
+
continue;
|
|
3213
|
+
}
|
|
3214
|
+
if (token.type === "LBracket" /* LBracket */) {
|
|
3215
|
+
const indexAfter = this.stream.indexAfterDelimited("LBracket" /* LBracket */, "RBracket" /* RBracket */, index);
|
|
3216
|
+
if (indexAfter === null) {
|
|
2705
3217
|
return false;
|
|
2706
3218
|
}
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
} else if (token.type === "RBracket" /* RBracket */) {
|
|
2710
|
-
depth -= 1;
|
|
2711
|
-
if (depth === 0) {
|
|
2712
|
-
index += 1;
|
|
2713
|
-
break;
|
|
2714
|
-
}
|
|
2715
|
-
}
|
|
2716
|
-
index += 1;
|
|
3219
|
+
index = indexAfter;
|
|
3220
|
+
continue;
|
|
2717
3221
|
}
|
|
3222
|
+
break;
|
|
2718
3223
|
}
|
|
2719
3224
|
return this.isAssignmentOperatorStart(index);
|
|
2720
3225
|
}
|
|
2721
3226
|
if (first.type === "At" /* At */ || first.type === "Dollar" /* Dollar */) {
|
|
2722
3227
|
const second = this.stream.peekNonWhitespace(1);
|
|
2723
|
-
const third = this.stream.peekNonWhitespace(2);
|
|
2724
3228
|
return second?.type === "Identifier" /* Identifier */ && this.isAssignmentOperatorStart(2);
|
|
2725
3229
|
}
|
|
2726
3230
|
if (first.type === "LBrace" /* LBrace */ || first.type === "LBracket" /* LBracket */) {
|
|
@@ -2758,17 +3262,6 @@ ${caret}`;
|
|
|
2758
3262
|
}
|
|
2759
3263
|
return false;
|
|
2760
3264
|
}
|
|
2761
|
-
isCallStart() {
|
|
2762
|
-
const first = this.stream.peekNonWhitespace(0);
|
|
2763
|
-
if (!first || first.type !== "Identifier" /* Identifier */) {
|
|
2764
|
-
return false;
|
|
2765
|
-
}
|
|
2766
|
-
let index = 1;
|
|
2767
|
-
while (this.stream.peekNonWhitespace(index)?.type === "Dot" /* Dot */ && this.stream.peekNonWhitespace(index + 1)?.type === "Identifier" /* Identifier */) {
|
|
2768
|
-
index += 2;
|
|
2769
|
-
}
|
|
2770
|
-
return this.stream.peekNonWhitespace(index)?.type === "LParen" /* LParen */;
|
|
2771
|
-
}
|
|
2772
3265
|
isExpressionStatementStart() {
|
|
2773
3266
|
const first = this.stream.peekNonWhitespace(0);
|
|
2774
3267
|
if (!first) {
|
|
@@ -2798,50 +3291,22 @@ ${caret}`;
|
|
|
2798
3291
|
if (this.stream.peekNonWhitespace(index)?.type !== "LParen" /* LParen */) {
|
|
2799
3292
|
return false;
|
|
2800
3293
|
}
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
const token = this.stream.peekNonWhitespace(index);
|
|
2805
|
-
if (!token) {
|
|
2806
|
-
return false;
|
|
2807
|
-
}
|
|
2808
|
-
if (token.type === "LParen" /* LParen */) {
|
|
2809
|
-
depth += 1;
|
|
2810
|
-
} else if (token.type === "RParen" /* RParen */) {
|
|
2811
|
-
depth -= 1;
|
|
2812
|
-
if (depth === 0) {
|
|
2813
|
-
index += 1;
|
|
2814
|
-
break;
|
|
2815
|
-
}
|
|
2816
|
-
}
|
|
2817
|
-
index += 1;
|
|
3294
|
+
const indexAfterParams = this.stream.indexAfterDelimited("LParen" /* LParen */, "RParen" /* RParen */, index);
|
|
3295
|
+
if (indexAfterParams === null) {
|
|
3296
|
+
return false;
|
|
2818
3297
|
}
|
|
2819
|
-
return this.stream.peekNonWhitespace(
|
|
3298
|
+
return this.stream.peekNonWhitespace(indexAfterParams)?.type === "LBrace" /* LBrace */;
|
|
2820
3299
|
}
|
|
2821
3300
|
isArrowFunctionStart() {
|
|
2822
3301
|
const first = this.stream.peekNonWhitespace(0);
|
|
2823
3302
|
if (!first || first.type !== "LParen" /* LParen */) {
|
|
2824
3303
|
return false;
|
|
2825
3304
|
}
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
const token = this.stream.peekNonWhitespace(index);
|
|
2830
|
-
if (!token) {
|
|
2831
|
-
return false;
|
|
2832
|
-
}
|
|
2833
|
-
if (token.type === "LParen" /* LParen */) {
|
|
2834
|
-
depth += 1;
|
|
2835
|
-
} else if (token.type === "RParen" /* RParen */) {
|
|
2836
|
-
depth -= 1;
|
|
2837
|
-
if (depth === 0) {
|
|
2838
|
-
index += 1;
|
|
2839
|
-
break;
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
2842
|
-
index += 1;
|
|
3305
|
+
const indexAfterParams = this.stream.indexAfterDelimited("LParen" /* LParen */, "RParen" /* RParen */, 0);
|
|
3306
|
+
if (indexAfterParams === null) {
|
|
3307
|
+
return false;
|
|
2843
3308
|
}
|
|
2844
|
-
return this.stream.peekNonWhitespace(
|
|
3309
|
+
return this.stream.peekNonWhitespace(indexAfterParams)?.type === "Arrow" /* Arrow */;
|
|
2845
3310
|
}
|
|
2846
3311
|
isAsyncArrowFunctionStart() {
|
|
2847
3312
|
const first = this.stream.peekNonWhitespace(0);
|
|
@@ -2851,25 +3316,11 @@ ${caret}`;
|
|
|
2851
3316
|
if (this.stream.peekNonWhitespace(1)?.type !== "LParen" /* LParen */) {
|
|
2852
3317
|
return false;
|
|
2853
3318
|
}
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
const token = this.stream.peekNonWhitespace(index);
|
|
2858
|
-
if (!token) {
|
|
2859
|
-
return false;
|
|
2860
|
-
}
|
|
2861
|
-
if (token.type === "LParen" /* LParen */) {
|
|
2862
|
-
depth += 1;
|
|
2863
|
-
} else if (token.type === "RParen" /* RParen */) {
|
|
2864
|
-
depth -= 1;
|
|
2865
|
-
if (depth === 0) {
|
|
2866
|
-
index += 1;
|
|
2867
|
-
break;
|
|
2868
|
-
}
|
|
2869
|
-
}
|
|
2870
|
-
index += 1;
|
|
3319
|
+
const indexAfterParams = this.stream.indexAfterDelimited("LParen" /* LParen */, "RParen" /* RParen */, 1);
|
|
3320
|
+
if (indexAfterParams === null) {
|
|
3321
|
+
return false;
|
|
2871
3322
|
}
|
|
2872
|
-
return this.stream.peekNonWhitespace(
|
|
3323
|
+
return this.stream.peekNonWhitespace(indexAfterParams)?.type === "Arrow" /* Arrow */;
|
|
2873
3324
|
}
|
|
2874
3325
|
isFunctionExpressionAssignmentStart() {
|
|
2875
3326
|
const first = this.stream.peekNonWhitespace(0);
|
|
@@ -2886,25 +3337,11 @@ ${caret}`;
|
|
|
2886
3337
|
if (this.stream.peekNonWhitespace(index)?.type !== "LParen" /* LParen */) {
|
|
2887
3338
|
return false;
|
|
2888
3339
|
}
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
const token = this.stream.peekNonWhitespace(index);
|
|
2893
|
-
if (!token) {
|
|
2894
|
-
return false;
|
|
2895
|
-
}
|
|
2896
|
-
if (token.type === "LParen" /* LParen */) {
|
|
2897
|
-
depth += 1;
|
|
2898
|
-
} else if (token.type === "RParen" /* RParen */) {
|
|
2899
|
-
depth -= 1;
|
|
2900
|
-
if (depth === 0) {
|
|
2901
|
-
index += 1;
|
|
2902
|
-
break;
|
|
2903
|
-
}
|
|
2904
|
-
}
|
|
2905
|
-
index += 1;
|
|
3340
|
+
const indexAfterParams = this.stream.indexAfterDelimited("LParen" /* LParen */, "RParen" /* RParen */, index);
|
|
3341
|
+
if (indexAfterParams === null) {
|
|
3342
|
+
return false;
|
|
2906
3343
|
}
|
|
2907
|
-
return this.stream.peekNonWhitespace(
|
|
3344
|
+
return this.stream.peekNonWhitespace(indexAfterParams)?.type === "Arrow" /* Arrow */;
|
|
2908
3345
|
}
|
|
2909
3346
|
parseExpressionStatement() {
|
|
2910
3347
|
const expr = this.parseExpression();
|
|
@@ -2919,7 +3356,7 @@ ${caret}`;
|
|
|
2919
3356
|
const test = this.parseExpression();
|
|
2920
3357
|
this.stream.skipWhitespace();
|
|
2921
3358
|
this.stream.expect("RParen" /* RParen */);
|
|
2922
|
-
const consequent = this.
|
|
3359
|
+
const consequent = this.parseConditionalBody();
|
|
2923
3360
|
this.stream.skipWhitespace();
|
|
2924
3361
|
let alternate;
|
|
2925
3362
|
if (this.stream.peek()?.type === "Else" /* Else */) {
|
|
@@ -2929,11 +3366,19 @@ ${caret}`;
|
|
|
2929
3366
|
const nested = this.parseIfBlock();
|
|
2930
3367
|
alternate = new BlockNode([nested]);
|
|
2931
3368
|
} else {
|
|
2932
|
-
alternate = this.
|
|
3369
|
+
alternate = this.parseConditionalBody();
|
|
2933
3370
|
}
|
|
2934
3371
|
}
|
|
2935
3372
|
return new IfNode(test, consequent, alternate);
|
|
2936
3373
|
}
|
|
3374
|
+
parseConditionalBody() {
|
|
3375
|
+
this.stream.skipWhitespace();
|
|
3376
|
+
if (this.stream.peek()?.type === "LBrace" /* LBrace */) {
|
|
3377
|
+
return this.parseBlock({ allowDeclarations: false });
|
|
3378
|
+
}
|
|
3379
|
+
const statement = this.parseStatement({ allowBlocks: false, allowReturn: this.functionDepth > 0 });
|
|
3380
|
+
return new BlockNode([statement]);
|
|
3381
|
+
}
|
|
2937
3382
|
parseWhileBlock() {
|
|
2938
3383
|
this.stream.expect("While" /* While */);
|
|
2939
3384
|
this.stream.skipWhitespace();
|
|
@@ -2950,6 +3395,21 @@ ${caret}`;
|
|
|
2950
3395
|
this.stream.skipWhitespace();
|
|
2951
3396
|
this.stream.expect("LParen" /* LParen */);
|
|
2952
3397
|
this.stream.skipWhitespace();
|
|
3398
|
+
const eachKind = this.detectForEachKind();
|
|
3399
|
+
if (eachKind) {
|
|
3400
|
+
const target = this.parseForEachTarget();
|
|
3401
|
+
this.stream.skipWhitespace();
|
|
3402
|
+
const keyword = this.stream.expect("Identifier" /* Identifier */);
|
|
3403
|
+
if (keyword.value !== eachKind) {
|
|
3404
|
+
throw new Error(`Expected '${eachKind}' but got '${keyword.value}'`);
|
|
3405
|
+
}
|
|
3406
|
+
this.stream.skipWhitespace();
|
|
3407
|
+
const iterable = this.parseExpression();
|
|
3408
|
+
this.stream.skipWhitespace();
|
|
3409
|
+
this.stream.expect("RParen" /* RParen */);
|
|
3410
|
+
const body2 = this.parseBlock({ allowDeclarations: false });
|
|
3411
|
+
return new ForEachNode(target, iterable, eachKind, body2);
|
|
3412
|
+
}
|
|
2953
3413
|
let init;
|
|
2954
3414
|
if (this.stream.peek()?.type !== "Semicolon" /* Semicolon */) {
|
|
2955
3415
|
init = this.parseForClause();
|
|
@@ -2973,6 +3433,43 @@ ${caret}`;
|
|
|
2973
3433
|
const body = this.parseBlock({ allowDeclarations: false });
|
|
2974
3434
|
return new ForNode(init, test, update, body);
|
|
2975
3435
|
}
|
|
3436
|
+
detectForEachKind() {
|
|
3437
|
+
let offset = 0;
|
|
3438
|
+
let depth = 0;
|
|
3439
|
+
while (true) {
|
|
3440
|
+
const token = this.stream.peekNonWhitespace(offset);
|
|
3441
|
+
if (!token) {
|
|
3442
|
+
return null;
|
|
3443
|
+
}
|
|
3444
|
+
if (token.type === "LParen" /* LParen */ || token.type === "LBracket" /* LBracket */ || token.type === "LBrace" /* LBrace */) {
|
|
3445
|
+
depth += 1;
|
|
3446
|
+
} else if (token.type === "RParen" /* RParen */ || token.type === "RBracket" /* RBracket */ || token.type === "RBrace" /* RBrace */) {
|
|
3447
|
+
if (depth === 0) {
|
|
3448
|
+
return null;
|
|
3449
|
+
}
|
|
3450
|
+
depth -= 1;
|
|
3451
|
+
}
|
|
3452
|
+
if (depth === 0) {
|
|
3453
|
+
if (token.type === "Semicolon" /* Semicolon */) {
|
|
3454
|
+
return null;
|
|
3455
|
+
}
|
|
3456
|
+
if (token.type === "Identifier" /* Identifier */ && (token.value === "in" || token.value === "of")) {
|
|
3457
|
+
return token.value;
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
offset += 1;
|
|
3461
|
+
}
|
|
3462
|
+
}
|
|
3463
|
+
parseForEachTarget() {
|
|
3464
|
+
const token = this.stream.peek();
|
|
3465
|
+
if (!token) {
|
|
3466
|
+
throw new Error("Expected for-each target");
|
|
3467
|
+
}
|
|
3468
|
+
if (token.type !== "Identifier" /* Identifier */) {
|
|
3469
|
+
throw new Error("for-in/of target must be an identifier");
|
|
3470
|
+
}
|
|
3471
|
+
return new IdentifierExpression(this.stream.next().value);
|
|
3472
|
+
}
|
|
2976
3473
|
parseForClause() {
|
|
2977
3474
|
if (this.isAssignmentStart()) {
|
|
2978
3475
|
return this.parseAssignmentExpression();
|
|
@@ -3068,9 +3565,6 @@ ${caret}`;
|
|
|
3068
3565
|
const body = this.parseFunctionBlockWithAwait(isAsync);
|
|
3069
3566
|
return new FunctionDeclarationNode(name, params, body, isAsync);
|
|
3070
3567
|
}
|
|
3071
|
-
parseFunctionBlock() {
|
|
3072
|
-
return this.parseFunctionBlockWithAwait(false);
|
|
3073
|
-
}
|
|
3074
3568
|
parseReturnStatement() {
|
|
3075
3569
|
this.stream.expect("Return" /* Return */);
|
|
3076
3570
|
this.stream.skipWhitespace();
|
|
@@ -3083,6 +3577,23 @@ ${caret}`;
|
|
|
3083
3577
|
this.stream.expect("Semicolon" /* Semicolon */);
|
|
3084
3578
|
return new ReturnNode(value);
|
|
3085
3579
|
}
|
|
3580
|
+
parseAssertStatement() {
|
|
3581
|
+
this.stream.expect("Assert" /* Assert */);
|
|
3582
|
+
this.stream.skipWhitespace();
|
|
3583
|
+
const test = this.parseExpression();
|
|
3584
|
+
this.consumeStatementTerminator();
|
|
3585
|
+
return new AssertNode(test);
|
|
3586
|
+
}
|
|
3587
|
+
parseBreakStatement() {
|
|
3588
|
+
this.stream.expect("Break" /* Break */);
|
|
3589
|
+
this.consumeStatementTerminator();
|
|
3590
|
+
return new BreakNode();
|
|
3591
|
+
}
|
|
3592
|
+
parseContinueStatement() {
|
|
3593
|
+
this.stream.expect("Continue" /* Continue */);
|
|
3594
|
+
this.consumeStatementTerminator();
|
|
3595
|
+
return new ContinueNode();
|
|
3596
|
+
}
|
|
3086
3597
|
parseArrowFunctionExpression(isAsync = false) {
|
|
3087
3598
|
const params = this.parseFunctionParams();
|
|
3088
3599
|
this.stream.skipWhitespace();
|
|
@@ -3192,6 +3703,7 @@ var Scope = class _Scope {
|
|
|
3192
3703
|
root;
|
|
3193
3704
|
listeners = /* @__PURE__ */ new Map();
|
|
3194
3705
|
anyListeners = /* @__PURE__ */ new Set();
|
|
3706
|
+
isEachItem = false;
|
|
3195
3707
|
createChild() {
|
|
3196
3708
|
return new _Scope(this);
|
|
3197
3709
|
}
|
|
@@ -3494,18 +4006,19 @@ var Engine = class _Engine {
|
|
|
3494
4006
|
eachBindings = /* @__PURE__ */ new WeakMap();
|
|
3495
4007
|
lifecycleBindings = /* @__PURE__ */ new WeakMap();
|
|
3496
4008
|
behaviorRegistry = [];
|
|
4009
|
+
behaviorRegistryHashes = /* @__PURE__ */ new Set();
|
|
3497
4010
|
behaviorBindings = /* @__PURE__ */ new WeakMap();
|
|
3498
4011
|
behaviorListeners = /* @__PURE__ */ new WeakMap();
|
|
3499
4012
|
behaviorId = 0;
|
|
3500
4013
|
codeCache = /* @__PURE__ */ new Map();
|
|
3501
4014
|
behaviorCache = /* @__PURE__ */ new Map();
|
|
3502
4015
|
observer;
|
|
3503
|
-
observerRoot;
|
|
3504
4016
|
attributeHandlers = [];
|
|
3505
4017
|
globals = {};
|
|
3506
4018
|
importantFlags = /* @__PURE__ */ new WeakMap();
|
|
3507
4019
|
inlineDeclarations = /* @__PURE__ */ new WeakMap();
|
|
3508
4020
|
flagHandlers = /* @__PURE__ */ new Map();
|
|
4021
|
+
behaviorModifiers = /* @__PURE__ */ new Map();
|
|
3509
4022
|
pendingAdded = /* @__PURE__ */ new Set();
|
|
3510
4023
|
pendingRemoved = /* @__PURE__ */ new Set();
|
|
3511
4024
|
pendingUpdated = /* @__PURE__ */ new Set();
|
|
@@ -3514,10 +4027,119 @@ var Engine = class _Engine {
|
|
|
3514
4027
|
diagnostics;
|
|
3515
4028
|
logger;
|
|
3516
4029
|
pendingUses = [];
|
|
4030
|
+
pendingAutoBindToScope = [];
|
|
4031
|
+
scopeWatchers = /* @__PURE__ */ new WeakMap();
|
|
4032
|
+
executionStack = [];
|
|
4033
|
+
groupProxyCache = /* @__PURE__ */ new WeakMap();
|
|
3517
4034
|
constructor(options = {}) {
|
|
3518
4035
|
this.diagnostics = options.diagnostics ?? false;
|
|
3519
4036
|
this.logger = options.logger ?? console;
|
|
3520
4037
|
this.registerGlobal("console", console);
|
|
4038
|
+
this.registerFlag("important");
|
|
4039
|
+
this.registerFlag("trusted");
|
|
4040
|
+
this.registerFlag("debounce", {
|
|
4041
|
+
onEventBind: ({ args }) => ({
|
|
4042
|
+
debounceMs: typeof args === "number" ? args : 200
|
|
4043
|
+
})
|
|
4044
|
+
});
|
|
4045
|
+
this.registerFlag("prevent", {
|
|
4046
|
+
onEventBefore: ({ event }) => {
|
|
4047
|
+
event?.preventDefault();
|
|
4048
|
+
}
|
|
4049
|
+
});
|
|
4050
|
+
this.registerFlag("stop", {
|
|
4051
|
+
onEventBefore: ({ event }) => {
|
|
4052
|
+
event?.stopPropagation();
|
|
4053
|
+
}
|
|
4054
|
+
});
|
|
4055
|
+
this.registerFlag("self", {
|
|
4056
|
+
onEventBefore: ({ event, element }) => {
|
|
4057
|
+
const target = event?.target;
|
|
4058
|
+
if (!(target instanceof Node)) {
|
|
4059
|
+
return false;
|
|
4060
|
+
}
|
|
4061
|
+
return target === element;
|
|
4062
|
+
}
|
|
4063
|
+
});
|
|
4064
|
+
this.registerFlag("outside", {
|
|
4065
|
+
onEventBind: ({ element }) => ({ listenerTarget: element.ownerDocument }),
|
|
4066
|
+
onEventBefore: ({ event, element }) => {
|
|
4067
|
+
const target = event?.target;
|
|
4068
|
+
if (!(target instanceof Node)) {
|
|
4069
|
+
return false;
|
|
4070
|
+
}
|
|
4071
|
+
return !element.contains(target);
|
|
4072
|
+
}
|
|
4073
|
+
});
|
|
4074
|
+
this.registerFlag("once", {
|
|
4075
|
+
onEventBind: () => ({ options: { once: true } })
|
|
4076
|
+
});
|
|
4077
|
+
this.registerFlag("passive", {
|
|
4078
|
+
onEventBind: () => ({ options: { passive: true } })
|
|
4079
|
+
});
|
|
4080
|
+
this.registerFlag("capture", {
|
|
4081
|
+
onEventBind: () => ({ options: { capture: true } })
|
|
4082
|
+
});
|
|
4083
|
+
this.registerFlag("shift", {
|
|
4084
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "shift")
|
|
4085
|
+
});
|
|
4086
|
+
this.registerFlag("ctrl", {
|
|
4087
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "ctrl")
|
|
4088
|
+
});
|
|
4089
|
+
this.registerFlag("control", {
|
|
4090
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "ctrl")
|
|
4091
|
+
});
|
|
4092
|
+
this.registerFlag("alt", {
|
|
4093
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "alt")
|
|
4094
|
+
});
|
|
4095
|
+
this.registerFlag("meta", {
|
|
4096
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "meta")
|
|
4097
|
+
});
|
|
4098
|
+
this.registerFlag("enter", {
|
|
4099
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "enter")
|
|
4100
|
+
});
|
|
4101
|
+
this.registerFlag("escape", {
|
|
4102
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "escape")
|
|
4103
|
+
});
|
|
4104
|
+
this.registerFlag("esc", {
|
|
4105
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "escape")
|
|
4106
|
+
});
|
|
4107
|
+
this.registerFlag("tab", {
|
|
4108
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "tab")
|
|
4109
|
+
});
|
|
4110
|
+
this.registerFlag("space", {
|
|
4111
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "space")
|
|
4112
|
+
});
|
|
4113
|
+
this.registerFlag("up", {
|
|
4114
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowup")
|
|
4115
|
+
});
|
|
4116
|
+
this.registerFlag("down", {
|
|
4117
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowdown")
|
|
4118
|
+
});
|
|
4119
|
+
this.registerFlag("left", {
|
|
4120
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowleft")
|
|
4121
|
+
});
|
|
4122
|
+
this.registerFlag("right", {
|
|
4123
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowright")
|
|
4124
|
+
});
|
|
4125
|
+
this.registerFlag("arrowup", {
|
|
4126
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowup")
|
|
4127
|
+
});
|
|
4128
|
+
this.registerFlag("arrowdown", {
|
|
4129
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowdown")
|
|
4130
|
+
});
|
|
4131
|
+
this.registerFlag("arrowleft", {
|
|
4132
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowleft")
|
|
4133
|
+
});
|
|
4134
|
+
this.registerFlag("arrowright", {
|
|
4135
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowright")
|
|
4136
|
+
});
|
|
4137
|
+
this.registerFlag("delete", {
|
|
4138
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "delete")
|
|
4139
|
+
});
|
|
4140
|
+
this.registerFlag("backspace", {
|
|
4141
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "backspace")
|
|
4142
|
+
});
|
|
3521
4143
|
this.registerGlobal("list", {
|
|
3522
4144
|
async map(items, fn) {
|
|
3523
4145
|
if (!Array.isArray(items) || typeof fn !== "function") {
|
|
@@ -3555,6 +4177,96 @@ var Engine = class _Engine {
|
|
|
3555
4177
|
}
|
|
3556
4178
|
});
|
|
3557
4179
|
this.registerDefaultAttributeHandlers();
|
|
4180
|
+
this.registerFlag("int", {
|
|
4181
|
+
transformValue: (_context, value) => this.coerceInt(value)
|
|
4182
|
+
});
|
|
4183
|
+
this.registerFlag("float", {
|
|
4184
|
+
transformValue: (_context, value) => this.coerceFloat(value)
|
|
4185
|
+
});
|
|
4186
|
+
this.registerBehaviorModifier("group", {
|
|
4187
|
+
onConstruct: ({ args, scope, rootScope, behavior, element }) => {
|
|
4188
|
+
const key = typeof args === "string" ? args : void 0;
|
|
4189
|
+
if (!key) {
|
|
4190
|
+
return;
|
|
4191
|
+
}
|
|
4192
|
+
const targetScope = this.getGroupTargetScope(element, behavior, scope, rootScope);
|
|
4193
|
+
const existing = targetScope.getPath?.(key);
|
|
4194
|
+
const list = Array.isArray(existing) ? existing : [];
|
|
4195
|
+
const proxy = this.getGroupProxy(scope);
|
|
4196
|
+
if (!list.includes(proxy)) {
|
|
4197
|
+
list.push(proxy);
|
|
4198
|
+
targetScope.setPath?.(key, list);
|
|
4199
|
+
} else if (!Array.isArray(existing)) {
|
|
4200
|
+
targetScope.setPath?.(key, list);
|
|
4201
|
+
}
|
|
4202
|
+
},
|
|
4203
|
+
onUnbind: ({ args, scope, rootScope, behavior, element }) => {
|
|
4204
|
+
const key = typeof args === "string" ? args : void 0;
|
|
4205
|
+
if (!key) {
|
|
4206
|
+
return;
|
|
4207
|
+
}
|
|
4208
|
+
const targetScope = this.getGroupTargetScope(element, behavior, scope, rootScope);
|
|
4209
|
+
const existing = targetScope.getPath?.(key);
|
|
4210
|
+
if (!Array.isArray(existing)) {
|
|
4211
|
+
return;
|
|
4212
|
+
}
|
|
4213
|
+
const proxy = this.getGroupProxy(scope);
|
|
4214
|
+
const next = existing.filter((entry) => entry !== proxy);
|
|
4215
|
+
if (next.length !== existing.length) {
|
|
4216
|
+
targetScope.setPath?.(key, next);
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
});
|
|
4220
|
+
}
|
|
4221
|
+
getGroupTargetScope(element, behavior, scope, rootScope) {
|
|
4222
|
+
let targetScope = rootScope ?? scope;
|
|
4223
|
+
if (behavior.parentSelector) {
|
|
4224
|
+
const parentElement = element.closest(behavior.parentSelector);
|
|
4225
|
+
if (parentElement) {
|
|
4226
|
+
targetScope = this.getScope(parentElement);
|
|
4227
|
+
}
|
|
4228
|
+
}
|
|
4229
|
+
return targetScope;
|
|
4230
|
+
}
|
|
4231
|
+
getGroupProxy(scope) {
|
|
4232
|
+
const cached = this.groupProxyCache.get(scope);
|
|
4233
|
+
if (cached) {
|
|
4234
|
+
return cached;
|
|
4235
|
+
}
|
|
4236
|
+
const proxy = new Proxy(
|
|
4237
|
+
{},
|
|
4238
|
+
{
|
|
4239
|
+
get: (_target, prop) => {
|
|
4240
|
+
if (typeof prop === "symbol") {
|
|
4241
|
+
return void 0;
|
|
4242
|
+
}
|
|
4243
|
+
if (prop === "__scope") {
|
|
4244
|
+
return scope;
|
|
4245
|
+
}
|
|
4246
|
+
return scope.getPath(String(prop));
|
|
4247
|
+
},
|
|
4248
|
+
set: (_target, prop, value) => {
|
|
4249
|
+
if (typeof prop === "symbol") {
|
|
4250
|
+
return false;
|
|
4251
|
+
}
|
|
4252
|
+
scope.setPath(String(prop), value);
|
|
4253
|
+
return true;
|
|
4254
|
+
},
|
|
4255
|
+
has: (_target, prop) => {
|
|
4256
|
+
if (typeof prop === "symbol") {
|
|
4257
|
+
return false;
|
|
4258
|
+
}
|
|
4259
|
+
return scope.getPath(String(prop)) !== void 0;
|
|
4260
|
+
},
|
|
4261
|
+
getOwnPropertyDescriptor: () => ({
|
|
4262
|
+
enumerable: true,
|
|
4263
|
+
configurable: true
|
|
4264
|
+
}),
|
|
4265
|
+
ownKeys: () => []
|
|
4266
|
+
}
|
|
4267
|
+
);
|
|
4268
|
+
this.groupProxyCache.set(scope, proxy);
|
|
4269
|
+
return proxy;
|
|
3558
4270
|
}
|
|
3559
4271
|
async mount(root) {
|
|
3560
4272
|
const documentRoot = root.ownerDocument;
|
|
@@ -3581,7 +4293,10 @@ var Engine = class _Engine {
|
|
|
3581
4293
|
this.disconnectObserver();
|
|
3582
4294
|
}
|
|
3583
4295
|
registerBehaviors(source) {
|
|
3584
|
-
const program = new Parser(source, {
|
|
4296
|
+
const program = new Parser(source, {
|
|
4297
|
+
customFlags: new Set(this.flagHandlers.keys()),
|
|
4298
|
+
behaviorFlags: new Set(this.behaviorModifiers.keys())
|
|
4299
|
+
}).parseProgram();
|
|
3585
4300
|
for (const use of program.uses) {
|
|
3586
4301
|
if (use.flags?.wait) {
|
|
3587
4302
|
this.pendingUses.push(this.waitForUseGlobal(use));
|
|
@@ -3605,11 +4320,14 @@ var Engine = class _Engine {
|
|
|
3605
4320
|
Object.assign(this.globals, values);
|
|
3606
4321
|
}
|
|
3607
4322
|
registerFlag(name, handler = {}) {
|
|
4323
|
+
this.flagHandlers.set(name, handler);
|
|
4324
|
+
}
|
|
4325
|
+
registerBehaviorModifier(name, handler = {}) {
|
|
3608
4326
|
const reserved = /* @__PURE__ */ new Set(["important", "trusted", "debounce"]);
|
|
3609
4327
|
if (reserved.has(name)) {
|
|
3610
|
-
throw new Error(`
|
|
4328
|
+
throw new Error(`Behavior modifier '${name}' is reserved`);
|
|
3611
4329
|
}
|
|
3612
|
-
this.
|
|
4330
|
+
this.behaviorModifiers.set(name, handler);
|
|
3613
4331
|
}
|
|
3614
4332
|
getRegistryStats() {
|
|
3615
4333
|
return {
|
|
@@ -3717,7 +4435,6 @@ var Engine = class _Engine {
|
|
|
3717
4435
|
if (this.observer) {
|
|
3718
4436
|
return;
|
|
3719
4437
|
}
|
|
3720
|
-
this.observerRoot = root;
|
|
3721
4438
|
this.observerFlush = debounce(() => this.flushObserverQueue(), 10);
|
|
3722
4439
|
this.observer = new MutationObserver((mutations) => {
|
|
3723
4440
|
for (const mutation of mutations) {
|
|
@@ -3747,7 +4464,6 @@ var Engine = class _Engine {
|
|
|
3747
4464
|
disconnectObserver() {
|
|
3748
4465
|
this.observer?.disconnect();
|
|
3749
4466
|
this.observer = void 0;
|
|
3750
|
-
this.observerRoot = void 0;
|
|
3751
4467
|
this.pendingAdded.clear();
|
|
3752
4468
|
this.pendingRemoved.clear();
|
|
3753
4469
|
this.pendingUpdated.clear();
|
|
@@ -3776,6 +4492,8 @@ var Engine = class _Engine {
|
|
|
3776
4492
|
if (this.behaviorBindings.has(node)) {
|
|
3777
4493
|
this.runBehaviorDestruct(node);
|
|
3778
4494
|
}
|
|
4495
|
+
this.cleanupScopeWatchers(node);
|
|
4496
|
+
this.cleanupBehaviorListeners(node);
|
|
3779
4497
|
for (const child of Array.from(node.querySelectorAll("*"))) {
|
|
3780
4498
|
if (this.lifecycleBindings.has(child)) {
|
|
3781
4499
|
this.runDestruct(child);
|
|
@@ -3783,6 +4501,8 @@ var Engine = class _Engine {
|
|
|
3783
4501
|
if (this.behaviorBindings.has(child)) {
|
|
3784
4502
|
this.runBehaviorDestruct(child);
|
|
3785
4503
|
}
|
|
4504
|
+
this.cleanupScopeWatchers(child);
|
|
4505
|
+
this.cleanupBehaviorListeners(child);
|
|
3786
4506
|
}
|
|
3787
4507
|
}
|
|
3788
4508
|
handleAddedNode(node) {
|
|
@@ -3806,13 +4526,13 @@ var Engine = class _Engine {
|
|
|
3806
4526
|
}
|
|
3807
4527
|
async applyBehaviors(root) {
|
|
3808
4528
|
await this.waitForUses();
|
|
3809
|
-
if (this.behaviorRegistry.length
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
await this.reapplyBehaviorsForElement(element);
|
|
4529
|
+
if (this.behaviorRegistry.length > 0) {
|
|
4530
|
+
const elements = [root, ...Array.from(root.querySelectorAll("*"))];
|
|
4531
|
+
for (const element of elements) {
|
|
4532
|
+
await this.reapplyBehaviorsForElement(element);
|
|
4533
|
+
}
|
|
3815
4534
|
}
|
|
4535
|
+
this.flushAutoBindQueue();
|
|
3816
4536
|
}
|
|
3817
4537
|
async reapplyBehaviorsForElement(element) {
|
|
3818
4538
|
if (this.behaviorRegistry.length === 0) {
|
|
@@ -3844,15 +4564,18 @@ var Engine = class _Engine {
|
|
|
3844
4564
|
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3845
4565
|
this.applyBehaviorFunctions(element, scope, behavior.functions, rootScope);
|
|
3846
4566
|
await this.applyBehaviorDeclarations(element, scope, behavior.declarations, rootScope);
|
|
4567
|
+
await this.applyBehaviorModifierHook("onBind", behavior, element, scope, rootScope);
|
|
3847
4568
|
if (behavior.construct) {
|
|
3848
4569
|
await this.safeExecuteBlock(behavior.construct, scope, element, rootScope);
|
|
3849
4570
|
}
|
|
4571
|
+
await this.applyBehaviorModifierHook("onConstruct", behavior, element, scope, rootScope);
|
|
3850
4572
|
for (const onBlock of behavior.onBlocks) {
|
|
3851
4573
|
this.attachBehaviorOnHandler(
|
|
3852
4574
|
element,
|
|
3853
4575
|
onBlock.event,
|
|
3854
4576
|
onBlock.body,
|
|
3855
|
-
onBlock.
|
|
4577
|
+
onBlock.flags,
|
|
4578
|
+
onBlock.flagArgs,
|
|
3856
4579
|
onBlock.args,
|
|
3857
4580
|
behavior.id,
|
|
3858
4581
|
rootScope
|
|
@@ -3862,10 +4585,11 @@ var Engine = class _Engine {
|
|
|
3862
4585
|
}
|
|
3863
4586
|
unbindBehaviorForElement(behavior, element, scope, bound) {
|
|
3864
4587
|
bound.delete(behavior.id);
|
|
4588
|
+
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3865
4589
|
if (behavior.destruct) {
|
|
3866
|
-
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3867
4590
|
void this.safeExecuteBlock(behavior.destruct, scope, element, rootScope);
|
|
3868
4591
|
}
|
|
4592
|
+
void this.applyBehaviorModifierHook("onDestruct", behavior, element, scope, rootScope);
|
|
3869
4593
|
const listenerMap = this.behaviorListeners.get(element);
|
|
3870
4594
|
const listeners = listenerMap?.get(behavior.id);
|
|
3871
4595
|
if (listeners) {
|
|
@@ -3874,6 +4598,7 @@ var Engine = class _Engine {
|
|
|
3874
4598
|
}
|
|
3875
4599
|
listenerMap?.delete(behavior.id);
|
|
3876
4600
|
}
|
|
4601
|
+
void this.applyBehaviorModifierHook("onUnbind", behavior, element, scope, rootScope);
|
|
3877
4602
|
this.logDiagnostic("unbind", element, behavior);
|
|
3878
4603
|
}
|
|
3879
4604
|
runBehaviorDestruct(element) {
|
|
@@ -3883,11 +4608,15 @@ var Engine = class _Engine {
|
|
|
3883
4608
|
}
|
|
3884
4609
|
const scope = this.getScope(element);
|
|
3885
4610
|
for (const behavior of this.behaviorRegistry) {
|
|
3886
|
-
if (!bound.has(behavior.id) || !behavior.destruct) {
|
|
4611
|
+
if (!bound.has(behavior.id) || !behavior.destruct && !this.behaviorHasModifierHooks(behavior)) {
|
|
3887
4612
|
continue;
|
|
3888
4613
|
}
|
|
3889
4614
|
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3890
|
-
|
|
4615
|
+
if (behavior.destruct) {
|
|
4616
|
+
void this.safeExecuteBlock(behavior.destruct, scope, element, rootScope);
|
|
4617
|
+
}
|
|
4618
|
+
void this.applyBehaviorModifierHook("onDestruct", behavior, element, scope, rootScope);
|
|
4619
|
+
void this.applyBehaviorModifierHook("onUnbind", behavior, element, scope, rootScope);
|
|
3891
4620
|
}
|
|
3892
4621
|
}
|
|
3893
4622
|
attachAttributes(element) {
|
|
@@ -3971,6 +4700,7 @@ var Engine = class _Engine {
|
|
|
3971
4700
|
const fragment = element.content.cloneNode(true);
|
|
3972
4701
|
const roots = Array.from(fragment.children);
|
|
3973
4702
|
const itemScope = new Scope(scope);
|
|
4703
|
+
itemScope.isEachItem = true;
|
|
3974
4704
|
itemScope.setPath(`self.${binding.itemName}`, item);
|
|
3975
4705
|
if (binding.indexName) {
|
|
3976
4706
|
itemScope.setPath(`self.${binding.indexName}`, index);
|
|
@@ -4009,7 +4739,93 @@ var Engine = class _Engine {
|
|
|
4009
4739
|
if (name.includes(":to")) {
|
|
4010
4740
|
return "to";
|
|
4011
4741
|
}
|
|
4012
|
-
return "
|
|
4742
|
+
return "auto";
|
|
4743
|
+
}
|
|
4744
|
+
resolveBindConfig(element, expr, scope, direction) {
|
|
4745
|
+
if (direction !== "auto") {
|
|
4746
|
+
return {
|
|
4747
|
+
direction,
|
|
4748
|
+
seedFromScope: false,
|
|
4749
|
+
syncToScope: direction === "to" || direction === "both",
|
|
4750
|
+
deferToScope: false
|
|
4751
|
+
};
|
|
4752
|
+
}
|
|
4753
|
+
if (this.isInEachScope(scope)) {
|
|
4754
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: false };
|
|
4755
|
+
}
|
|
4756
|
+
if (this.isFormControl(element)) {
|
|
4757
|
+
if (this.hasScopeValue(scope, expr)) {
|
|
4758
|
+
return { direction: "both", seedFromScope: true, syncToScope: false, deferToScope: false };
|
|
4759
|
+
}
|
|
4760
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: true };
|
|
4761
|
+
}
|
|
4762
|
+
if (this.hasScopeValue(scope, expr)) {
|
|
4763
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: false };
|
|
4764
|
+
}
|
|
4765
|
+
if (this.hasElementValue(element)) {
|
|
4766
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: true };
|
|
4767
|
+
}
|
|
4768
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: false };
|
|
4769
|
+
}
|
|
4770
|
+
isFormControl(element) {
|
|
4771
|
+
return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement;
|
|
4772
|
+
}
|
|
4773
|
+
hasScopeValue(scope, expr) {
|
|
4774
|
+
const key = expr.trim();
|
|
4775
|
+
if (!key) {
|
|
4776
|
+
return false;
|
|
4777
|
+
}
|
|
4778
|
+
const value = scope.get(key);
|
|
4779
|
+
return value !== void 0 && value !== null;
|
|
4780
|
+
}
|
|
4781
|
+
hasElementValue(element) {
|
|
4782
|
+
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
|
|
4783
|
+
return element.value.length > 0;
|
|
4784
|
+
}
|
|
4785
|
+
return (element.textContent ?? "").trim().length > 0;
|
|
4786
|
+
}
|
|
4787
|
+
coerceInt(value) {
|
|
4788
|
+
if (value == null || value === "") {
|
|
4789
|
+
return value;
|
|
4790
|
+
}
|
|
4791
|
+
const num = typeof value === "number" ? value : Number.parseInt(String(value), 10);
|
|
4792
|
+
return Number.isNaN(num) ? value : num;
|
|
4793
|
+
}
|
|
4794
|
+
coerceFloat(value) {
|
|
4795
|
+
if (value == null || value === "") {
|
|
4796
|
+
return value;
|
|
4797
|
+
}
|
|
4798
|
+
const num = typeof value === "number" ? value : Number.parseFloat(String(value));
|
|
4799
|
+
return Number.isNaN(num) ? value : num;
|
|
4800
|
+
}
|
|
4801
|
+
isInEachScope(scope) {
|
|
4802
|
+
let cursor = scope;
|
|
4803
|
+
while (cursor) {
|
|
4804
|
+
if (cursor.isEachItem) {
|
|
4805
|
+
return true;
|
|
4806
|
+
}
|
|
4807
|
+
cursor = cursor.parent;
|
|
4808
|
+
}
|
|
4809
|
+
return false;
|
|
4810
|
+
}
|
|
4811
|
+
flushAutoBindQueue() {
|
|
4812
|
+
if (this.pendingAutoBindToScope.length === 0) {
|
|
4813
|
+
return;
|
|
4814
|
+
}
|
|
4815
|
+
const pending = this.pendingAutoBindToScope;
|
|
4816
|
+
this.pendingAutoBindToScope = [];
|
|
4817
|
+
for (const entry of pending) {
|
|
4818
|
+
if (!entry.element.isConnected) {
|
|
4819
|
+
continue;
|
|
4820
|
+
}
|
|
4821
|
+
if (this.hasScopeValue(entry.scope, entry.expr)) {
|
|
4822
|
+
continue;
|
|
4823
|
+
}
|
|
4824
|
+
if (!this.hasElementValue(entry.element)) {
|
|
4825
|
+
continue;
|
|
4826
|
+
}
|
|
4827
|
+
applyBindToScope(entry.element, entry.expr, entry.scope);
|
|
4828
|
+
}
|
|
4013
4829
|
}
|
|
4014
4830
|
hasVsnAttributes(element) {
|
|
4015
4831
|
return element.getAttributeNames().some((name) => name.startsWith("vsn-"));
|
|
@@ -4034,7 +4850,7 @@ var Engine = class _Engine {
|
|
|
4034
4850
|
}
|
|
4035
4851
|
return void 0;
|
|
4036
4852
|
}
|
|
4037
|
-
watch(scope, expr, handler) {
|
|
4853
|
+
watch(scope, expr, handler, element) {
|
|
4038
4854
|
const key = expr.trim();
|
|
4039
4855
|
if (!key) {
|
|
4040
4856
|
return;
|
|
@@ -4049,29 +4865,70 @@ var Engine = class _Engine {
|
|
|
4049
4865
|
}
|
|
4050
4866
|
if (target) {
|
|
4051
4867
|
target.on(key, handler);
|
|
4868
|
+
if (element) {
|
|
4869
|
+
this.trackScopeWatcher(element, target, "path", handler, key);
|
|
4870
|
+
}
|
|
4052
4871
|
return;
|
|
4053
4872
|
}
|
|
4054
4873
|
let cursor = scope;
|
|
4055
4874
|
while (cursor) {
|
|
4056
4875
|
cursor.on(key, handler);
|
|
4876
|
+
if (element) {
|
|
4877
|
+
this.trackScopeWatcher(element, cursor, "path", handler, key);
|
|
4878
|
+
}
|
|
4057
4879
|
cursor = cursor.parent;
|
|
4058
4880
|
}
|
|
4059
4881
|
}
|
|
4060
|
-
watchWithDebounce(scope, expr, handler, debounceMs) {
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
} else {
|
|
4064
|
-
this.watch(scope, expr, handler);
|
|
4065
|
-
}
|
|
4882
|
+
watchWithDebounce(scope, expr, handler, debounceMs, element) {
|
|
4883
|
+
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4884
|
+
this.watch(scope, expr, effectiveHandler, element);
|
|
4066
4885
|
}
|
|
4067
|
-
watchAllScopes(scope, handler, debounceMs) {
|
|
4886
|
+
watchAllScopes(scope, handler, debounceMs, element) {
|
|
4068
4887
|
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4069
4888
|
let cursor = scope;
|
|
4070
4889
|
while (cursor) {
|
|
4071
4890
|
cursor.onAny(effectiveHandler);
|
|
4891
|
+
if (element) {
|
|
4892
|
+
this.trackScopeWatcher(element, cursor, "any", effectiveHandler);
|
|
4893
|
+
}
|
|
4072
4894
|
cursor = cursor.parent;
|
|
4073
4895
|
}
|
|
4074
4896
|
}
|
|
4897
|
+
trackScopeWatcher(element, scope, kind, handler, key) {
|
|
4898
|
+
const watchers = this.scopeWatchers.get(element) ?? [];
|
|
4899
|
+
watchers.push({ scope, kind, handler, ...key ? { key } : {} });
|
|
4900
|
+
this.scopeWatchers.set(element, watchers);
|
|
4901
|
+
}
|
|
4902
|
+
cleanupScopeWatchers(element) {
|
|
4903
|
+
const watchers = this.scopeWatchers.get(element);
|
|
4904
|
+
if (!watchers) {
|
|
4905
|
+
return;
|
|
4906
|
+
}
|
|
4907
|
+
for (const watcher of watchers) {
|
|
4908
|
+
if (watcher.kind === "any") {
|
|
4909
|
+
watcher.scope.offAny(watcher.handler);
|
|
4910
|
+
continue;
|
|
4911
|
+
}
|
|
4912
|
+
if (watcher.key) {
|
|
4913
|
+
watcher.scope.off(watcher.key, watcher.handler);
|
|
4914
|
+
}
|
|
4915
|
+
}
|
|
4916
|
+
this.scopeWatchers.delete(element);
|
|
4917
|
+
}
|
|
4918
|
+
cleanupBehaviorListeners(element) {
|
|
4919
|
+
const listenerMap = this.behaviorListeners.get(element);
|
|
4920
|
+
if (!listenerMap) {
|
|
4921
|
+
return;
|
|
4922
|
+
}
|
|
4923
|
+
for (const listeners of listenerMap.values()) {
|
|
4924
|
+
for (const listener of listeners) {
|
|
4925
|
+
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
listenerMap.clear();
|
|
4929
|
+
this.behaviorListeners.delete(element);
|
|
4930
|
+
this.behaviorBindings.delete(element);
|
|
4931
|
+
}
|
|
4075
4932
|
parseOnAttribute(name, value) {
|
|
4076
4933
|
if (!name.startsWith("vsn-on:")) {
|
|
4077
4934
|
return null;
|
|
@@ -4081,111 +4938,56 @@ var Engine = class _Engine {
|
|
|
4081
4938
|
if (!event) {
|
|
4082
4939
|
return null;
|
|
4083
4940
|
}
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
return null;
|
|
4087
|
-
}
|
|
4088
|
-
let debounceMs;
|
|
4089
|
-
const modifiers = [];
|
|
4090
|
-
for (const flag of flags) {
|
|
4091
|
-
if (flag.startsWith("debounce")) {
|
|
4092
|
-
const match = flag.match(/debounce\((\d+)\)/);
|
|
4093
|
-
debounceMs = match ? Number(match[1]) : 200;
|
|
4094
|
-
continue;
|
|
4095
|
-
}
|
|
4096
|
-
modifiers.push(flag);
|
|
4941
|
+
if (event.includes(".")) {
|
|
4942
|
+
throw new Error("vsn:on does not support dot modifiers; use !flags instead");
|
|
4097
4943
|
}
|
|
4098
|
-
const
|
|
4944
|
+
const { flagMap, flagArgs } = this.parseInlineFlags(flags);
|
|
4099
4945
|
const config = {
|
|
4100
|
-
event
|
|
4946
|
+
event,
|
|
4101
4947
|
code: value,
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
...descriptor.keyModifiers.length > 0 ? { keyModifiers: descriptor.keyModifiers } : {}
|
|
4948
|
+
flags: flagMap,
|
|
4949
|
+
flagArgs
|
|
4105
4950
|
};
|
|
4106
4951
|
return config;
|
|
4107
4952
|
}
|
|
4108
|
-
|
|
4109
|
-
const
|
|
4110
|
-
const
|
|
4111
|
-
const
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
if (modifierSet.has(part)) {
|
|
4116
|
-
modifiers.push(part);
|
|
4117
|
-
} else {
|
|
4118
|
-
keyModifiers.push(part);
|
|
4953
|
+
parseInlineFlags(parts) {
|
|
4954
|
+
const flagMap = {};
|
|
4955
|
+
const flagArgs = {};
|
|
4956
|
+
for (const raw of parts) {
|
|
4957
|
+
const trimmed = raw.trim();
|
|
4958
|
+
if (!trimmed) {
|
|
4959
|
+
continue;
|
|
4119
4960
|
}
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
}
|
|
4123
|
-
matchesKeyModifiers(event, keyModifiers) {
|
|
4124
|
-
if (!keyModifiers || keyModifiers.length === 0) {
|
|
4125
|
-
return true;
|
|
4126
|
-
}
|
|
4127
|
-
if (!(event instanceof KeyboardEvent)) {
|
|
4128
|
-
return false;
|
|
4129
|
-
}
|
|
4130
|
-
const modifierChecks = {
|
|
4131
|
-
shift: event.shiftKey,
|
|
4132
|
-
ctrl: event.ctrlKey,
|
|
4133
|
-
control: event.ctrlKey,
|
|
4134
|
-
alt: event.altKey,
|
|
4135
|
-
meta: event.metaKey
|
|
4136
|
-
};
|
|
4137
|
-
const keyAliases = {
|
|
4138
|
-
esc: "escape",
|
|
4139
|
-
escape: "escape",
|
|
4140
|
-
enter: "enter",
|
|
4141
|
-
tab: "tab",
|
|
4142
|
-
space: "space",
|
|
4143
|
-
spacebar: "space",
|
|
4144
|
-
up: "arrowup",
|
|
4145
|
-
down: "arrowdown",
|
|
4146
|
-
left: "arrowleft",
|
|
4147
|
-
right: "arrowright",
|
|
4148
|
-
arrowup: "arrowup",
|
|
4149
|
-
arrowdown: "arrowdown",
|
|
4150
|
-
arrowleft: "arrowleft",
|
|
4151
|
-
arrowright: "arrowright",
|
|
4152
|
-
delete: "delete",
|
|
4153
|
-
backspace: "backspace"
|
|
4154
|
-
};
|
|
4155
|
-
let key = event.key?.toLowerCase() ?? "";
|
|
4156
|
-
if (key === " ") {
|
|
4157
|
-
key = "space";
|
|
4158
|
-
}
|
|
4159
|
-
for (const rawModifier of keyModifiers) {
|
|
4160
|
-
const modifier = rawModifier.toLowerCase();
|
|
4161
|
-
if (modifier in modifierChecks) {
|
|
4162
|
-
if (!modifierChecks[modifier]) {
|
|
4163
|
-
return false;
|
|
4164
|
-
}
|
|
4961
|
+
const match = trimmed.match(/^([a-zA-Z][\w-]*)(?:\((.+)\))?$/);
|
|
4962
|
+
if (!match) {
|
|
4165
4963
|
continue;
|
|
4166
4964
|
}
|
|
4167
|
-
const
|
|
4168
|
-
if (
|
|
4169
|
-
|
|
4965
|
+
const name = match[1] ?? "";
|
|
4966
|
+
if (!name) {
|
|
4967
|
+
continue;
|
|
4968
|
+
}
|
|
4969
|
+
if (!this.flagHandlers.has(name)) {
|
|
4970
|
+
throw new Error(`Unknown flag ${name}`);
|
|
4971
|
+
}
|
|
4972
|
+
flagMap[name] = true;
|
|
4973
|
+
if (match[2] !== void 0) {
|
|
4974
|
+
flagArgs[name] = this.parseInlineFlagArg(match[2]);
|
|
4170
4975
|
}
|
|
4171
4976
|
}
|
|
4172
|
-
return
|
|
4977
|
+
return { flagMap, flagArgs };
|
|
4173
4978
|
}
|
|
4174
|
-
|
|
4175
|
-
|
|
4979
|
+
parseInlineFlagArg(raw) {
|
|
4980
|
+
const trimmed = raw.trim();
|
|
4981
|
+
if (trimmed === "true") {
|
|
4176
4982
|
return true;
|
|
4177
4983
|
}
|
|
4178
|
-
|
|
4179
|
-
if (!target || !(target instanceof Node)) {
|
|
4180
|
-
return !modifiers.includes("self") && !modifiers.includes("outside");
|
|
4181
|
-
}
|
|
4182
|
-
if (modifiers.includes("self") && target !== element) {
|
|
4984
|
+
if (trimmed === "false") {
|
|
4183
4985
|
return false;
|
|
4184
4986
|
}
|
|
4185
|
-
if (
|
|
4186
|
-
return
|
|
4987
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
4988
|
+
return Number(trimmed);
|
|
4187
4989
|
}
|
|
4188
|
-
return
|
|
4990
|
+
return trimmed;
|
|
4189
4991
|
}
|
|
4190
4992
|
describeElement(element) {
|
|
4191
4993
|
const tag = element.tagName.toLowerCase();
|
|
@@ -4227,51 +5029,50 @@ var Engine = class _Engine {
|
|
|
4227
5029
|
}
|
|
4228
5030
|
}
|
|
4229
5031
|
attachOnHandler(element, config) {
|
|
4230
|
-
const options = this.
|
|
4231
|
-
|
|
5032
|
+
const { listenerTarget, options, debounceMs } = this.getEventBindingConfig(
|
|
5033
|
+
element,
|
|
5034
|
+
config.flags,
|
|
5035
|
+
config.flagArgs
|
|
5036
|
+
);
|
|
4232
5037
|
let effectiveHandler;
|
|
4233
5038
|
const handler = async (event) => {
|
|
4234
5039
|
if (!element.isConnected) {
|
|
4235
5040
|
listenerTarget.removeEventListener(config.event, effectiveHandler, options);
|
|
4236
5041
|
return;
|
|
4237
5042
|
}
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
}
|
|
4241
|
-
if (!this.matchesTargetModifiers(element, event, config.modifiers)) {
|
|
5043
|
+
const scope = this.getScope(element);
|
|
5044
|
+
if (!this.applyEventFlagBefore(element, scope, config.flags, config.flagArgs, event)) {
|
|
4242
5045
|
return;
|
|
4243
5046
|
}
|
|
4244
|
-
this.applyEventModifiers(event, config.modifiers);
|
|
4245
|
-
const scope = this.getScope(element);
|
|
4246
5047
|
try {
|
|
4247
5048
|
await this.execute(config.code, scope, element);
|
|
4248
5049
|
this.evaluate(element);
|
|
4249
5050
|
} catch (error) {
|
|
4250
5051
|
this.emitError(element, error);
|
|
5052
|
+
} finally {
|
|
5053
|
+
this.applyEventFlagAfter(element, scope, config.flags, config.flagArgs, event);
|
|
4251
5054
|
}
|
|
4252
5055
|
};
|
|
4253
|
-
effectiveHandler =
|
|
5056
|
+
effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4254
5057
|
listenerTarget.addEventListener(config.event, effectiveHandler, options);
|
|
4255
5058
|
}
|
|
4256
|
-
attachBehaviorOnHandler(element, event, body,
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
5059
|
+
attachBehaviorOnHandler(element, event, body, flags, flagArgs, args, behaviorId, rootScope) {
|
|
5060
|
+
if (event.includes(".")) {
|
|
5061
|
+
throw new Error("vsn:on does not support dot modifiers; use !flags instead");
|
|
5062
|
+
}
|
|
5063
|
+
const { listenerTarget, options, debounceMs } = this.getEventBindingConfig(element, flags, flagArgs);
|
|
4260
5064
|
const handler = async (evt) => {
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
}
|
|
4264
|
-
if (!this.matchesTargetModifiers(element, evt, combinedModifiers)) {
|
|
5065
|
+
const scope = this.getScope(element);
|
|
5066
|
+
if (!this.applyEventFlagBefore(element, scope, flags, flagArgs, evt)) {
|
|
4265
5067
|
return;
|
|
4266
5068
|
}
|
|
4267
|
-
this.applyEventModifiers(evt, combinedModifiers);
|
|
4268
|
-
const scope = this.getScope(element);
|
|
4269
5069
|
const previousValues = /* @__PURE__ */ new Map();
|
|
4270
5070
|
if (args && args.length > 0) {
|
|
4271
5071
|
const argName = args[0];
|
|
4272
5072
|
if (argName) {
|
|
4273
5073
|
previousValues.set(argName, scope.getPath(argName));
|
|
4274
|
-
|
|
5074
|
+
const [nextArg] = this.applyEventFlagArgTransforms(element, scope, flags, flagArgs, evt);
|
|
5075
|
+
scope.setPath(argName, nextArg);
|
|
4275
5076
|
}
|
|
4276
5077
|
}
|
|
4277
5078
|
let failed = false;
|
|
@@ -4284,16 +5085,17 @@ var Engine = class _Engine {
|
|
|
4284
5085
|
for (const [name, value] of previousValues.entries()) {
|
|
4285
5086
|
scope.setPath(name, value);
|
|
4286
5087
|
}
|
|
5088
|
+
this.applyEventFlagAfter(element, scope, flags, flagArgs, evt);
|
|
4287
5089
|
}
|
|
4288
5090
|
if (!failed) {
|
|
4289
5091
|
this.evaluate(element);
|
|
4290
5092
|
}
|
|
4291
5093
|
};
|
|
4292
|
-
const
|
|
4293
|
-
listenerTarget.addEventListener(
|
|
5094
|
+
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
5095
|
+
listenerTarget.addEventListener(event, effectiveHandler, options);
|
|
4294
5096
|
const listenerMap = this.behaviorListeners.get(element) ?? /* @__PURE__ */ new Map();
|
|
4295
5097
|
const listeners = listenerMap.get(behaviorId) ?? [];
|
|
4296
|
-
listeners.push({ target: listenerTarget, event
|
|
5098
|
+
listeners.push({ target: listenerTarget, event, handler: effectiveHandler, options });
|
|
4297
5099
|
listenerMap.set(behaviorId, listeners);
|
|
4298
5100
|
this.behaviorListeners.set(element, listenerMap);
|
|
4299
5101
|
}
|
|
@@ -4324,33 +5126,158 @@ var Engine = class _Engine {
|
|
|
4324
5126
|
Promise.resolve().then(handler);
|
|
4325
5127
|
}
|
|
4326
5128
|
}
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
5129
|
+
getEventBindingConfig(element, flags, flagArgs) {
|
|
5130
|
+
let listenerTarget = element;
|
|
5131
|
+
let options = {};
|
|
5132
|
+
let debounceMs;
|
|
5133
|
+
for (const name of Object.keys(flags)) {
|
|
5134
|
+
const handler = this.flagHandlers.get(name);
|
|
5135
|
+
if (!handler?.onEventBind) {
|
|
5136
|
+
continue;
|
|
5137
|
+
}
|
|
5138
|
+
const patch = handler.onEventBind({
|
|
5139
|
+
name,
|
|
5140
|
+
args: flagArgs[name],
|
|
5141
|
+
element,
|
|
5142
|
+
scope: this.getScope(element),
|
|
5143
|
+
rootScope: void 0,
|
|
5144
|
+
event: void 0,
|
|
5145
|
+
engine: this
|
|
5146
|
+
});
|
|
5147
|
+
if (!patch) {
|
|
5148
|
+
continue;
|
|
5149
|
+
}
|
|
5150
|
+
if (patch.listenerTarget) {
|
|
5151
|
+
listenerTarget = patch.listenerTarget;
|
|
5152
|
+
}
|
|
5153
|
+
if (patch.options) {
|
|
5154
|
+
options = { ...options, ...patch.options };
|
|
5155
|
+
}
|
|
5156
|
+
if (patch.debounceMs !== void 0) {
|
|
5157
|
+
debounceMs = patch.debounceMs;
|
|
5158
|
+
}
|
|
5159
|
+
}
|
|
5160
|
+
return {
|
|
5161
|
+
listenerTarget,
|
|
5162
|
+
...Object.keys(options).length > 0 ? { options } : {},
|
|
5163
|
+
...debounceMs !== void 0 ? { debounceMs } : {}
|
|
5164
|
+
};
|
|
5165
|
+
}
|
|
5166
|
+
applyEventFlagBefore(element, scope, flags, flagArgs, event) {
|
|
5167
|
+
for (const name of Object.keys(flags)) {
|
|
5168
|
+
const handler = this.flagHandlers.get(name);
|
|
5169
|
+
if (!handler?.onEventBefore) {
|
|
5170
|
+
continue;
|
|
5171
|
+
}
|
|
5172
|
+
const result = handler.onEventBefore({
|
|
5173
|
+
name,
|
|
5174
|
+
args: flagArgs[name],
|
|
5175
|
+
element,
|
|
5176
|
+
scope,
|
|
5177
|
+
rootScope: void 0,
|
|
5178
|
+
event,
|
|
5179
|
+
engine: this
|
|
5180
|
+
});
|
|
5181
|
+
if (result === false) {
|
|
5182
|
+
return false;
|
|
5183
|
+
}
|
|
4330
5184
|
}
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
5185
|
+
return true;
|
|
5186
|
+
}
|
|
5187
|
+
applyEventFlagAfter(element, scope, flags, flagArgs, event) {
|
|
5188
|
+
for (const name of Object.keys(flags)) {
|
|
5189
|
+
const handler = this.flagHandlers.get(name);
|
|
5190
|
+
if (!handler?.onEventAfter) {
|
|
5191
|
+
continue;
|
|
4336
5192
|
}
|
|
5193
|
+
handler.onEventAfter({
|
|
5194
|
+
name,
|
|
5195
|
+
args: flagArgs[name],
|
|
5196
|
+
element,
|
|
5197
|
+
scope,
|
|
5198
|
+
rootScope: void 0,
|
|
5199
|
+
event,
|
|
5200
|
+
engine: this
|
|
5201
|
+
});
|
|
4337
5202
|
}
|
|
4338
5203
|
}
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
5204
|
+
applyEventFlagArgTransforms(element, scope, flags, flagArgs, event) {
|
|
5205
|
+
let args = [event];
|
|
5206
|
+
for (const name of Object.keys(flags)) {
|
|
5207
|
+
const handler = this.flagHandlers.get(name);
|
|
5208
|
+
if (!handler?.transformEventArgs) {
|
|
5209
|
+
continue;
|
|
5210
|
+
}
|
|
5211
|
+
const nextArgs = handler.transformEventArgs(
|
|
5212
|
+
{
|
|
5213
|
+
name,
|
|
5214
|
+
args: flagArgs[name],
|
|
5215
|
+
element,
|
|
5216
|
+
scope,
|
|
5217
|
+
rootScope: void 0,
|
|
5218
|
+
event,
|
|
5219
|
+
engine: this
|
|
5220
|
+
},
|
|
5221
|
+
args
|
|
5222
|
+
);
|
|
5223
|
+
if (Array.isArray(nextArgs)) {
|
|
5224
|
+
args = nextArgs;
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5227
|
+
return args;
|
|
5228
|
+
}
|
|
5229
|
+
matchesKeyFlag(event, flag) {
|
|
5230
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
5231
|
+
return false;
|
|
5232
|
+
}
|
|
5233
|
+
const modifierChecks = {
|
|
5234
|
+
shift: event.shiftKey,
|
|
5235
|
+
ctrl: event.ctrlKey,
|
|
5236
|
+
alt: event.altKey,
|
|
5237
|
+
meta: event.metaKey
|
|
5238
|
+
};
|
|
5239
|
+
if (flag in modifierChecks) {
|
|
5240
|
+
return modifierChecks[flag] ?? false;
|
|
4342
5241
|
}
|
|
4343
|
-
const
|
|
4344
|
-
|
|
4345
|
-
|
|
5242
|
+
const keyAliases = {
|
|
5243
|
+
escape: "escape",
|
|
5244
|
+
esc: "escape",
|
|
5245
|
+
enter: "enter",
|
|
5246
|
+
tab: "tab",
|
|
5247
|
+
space: "space",
|
|
5248
|
+
spacebar: "space",
|
|
5249
|
+
up: "arrowup",
|
|
5250
|
+
down: "arrowdown",
|
|
5251
|
+
left: "arrowleft",
|
|
5252
|
+
right: "arrowright",
|
|
5253
|
+
arrowup: "arrowup",
|
|
5254
|
+
arrowdown: "arrowdown",
|
|
5255
|
+
arrowleft: "arrowleft",
|
|
5256
|
+
arrowright: "arrowright",
|
|
5257
|
+
delete: "delete",
|
|
5258
|
+
backspace: "backspace"
|
|
5259
|
+
};
|
|
5260
|
+
let key = event.key?.toLowerCase() ?? "";
|
|
5261
|
+
if (key === " ") {
|
|
5262
|
+
key = "space";
|
|
4346
5263
|
}
|
|
4347
|
-
|
|
4348
|
-
|
|
5264
|
+
const expectedKey = keyAliases[flag] ?? flag;
|
|
5265
|
+
return key === expectedKey;
|
|
5266
|
+
}
|
|
5267
|
+
async withExecutionElement(element, fn) {
|
|
5268
|
+
if (!element) {
|
|
5269
|
+
await fn();
|
|
5270
|
+
return;
|
|
4349
5271
|
}
|
|
4350
|
-
|
|
4351
|
-
|
|
5272
|
+
this.executionStack.push(element);
|
|
5273
|
+
try {
|
|
5274
|
+
await fn();
|
|
5275
|
+
} finally {
|
|
5276
|
+
this.executionStack.pop();
|
|
4352
5277
|
}
|
|
4353
|
-
|
|
5278
|
+
}
|
|
5279
|
+
getCurrentElement() {
|
|
5280
|
+
return this.executionStack[this.executionStack.length - 1];
|
|
4354
5281
|
}
|
|
4355
5282
|
async execute(code, scope, element, rootScope) {
|
|
4356
5283
|
let block = this.codeCache.get(code);
|
|
@@ -4358,22 +5285,26 @@ var Engine = class _Engine {
|
|
|
4358
5285
|
block = Parser.parseInline(code);
|
|
4359
5286
|
this.codeCache.set(code, block);
|
|
4360
5287
|
}
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
5288
|
+
await this.withExecutionElement(element, async () => {
|
|
5289
|
+
const context = {
|
|
5290
|
+
scope,
|
|
5291
|
+
rootScope,
|
|
5292
|
+
globals: this.globals,
|
|
5293
|
+
...element ? { element } : {}
|
|
5294
|
+
};
|
|
5295
|
+
await block.evaluate(context);
|
|
5296
|
+
});
|
|
4368
5297
|
}
|
|
4369
5298
|
async executeBlock(block, scope, element, rootScope) {
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
5299
|
+
await this.withExecutionElement(element, async () => {
|
|
5300
|
+
const context = {
|
|
5301
|
+
scope,
|
|
5302
|
+
rootScope,
|
|
5303
|
+
globals: this.globals,
|
|
5304
|
+
...element ? { element } : {}
|
|
5305
|
+
};
|
|
5306
|
+
await block.evaluate(context);
|
|
5307
|
+
});
|
|
4377
5308
|
}
|
|
4378
5309
|
async safeExecute(code, scope, element, rootScope) {
|
|
4379
5310
|
try {
|
|
@@ -4396,15 +5327,26 @@ var Engine = class _Engine {
|
|
|
4396
5327
|
collectBehavior(behavior, parentSelector, rootSelectorOverride) {
|
|
4397
5328
|
const selector = parentSelector ? `${parentSelector} ${behavior.selector.selectorText}` : behavior.selector.selectorText;
|
|
4398
5329
|
const rootSelector = rootSelectorOverride ?? (parentSelector ?? behavior.selector.selectorText);
|
|
5330
|
+
const behaviorHash = this.hashBehavior(behavior);
|
|
5331
|
+
const hash = `${selector}::${rootSelector}::${behaviorHash}`;
|
|
5332
|
+
if (this.behaviorRegistryHashes.has(hash)) {
|
|
5333
|
+
return;
|
|
5334
|
+
}
|
|
4399
5335
|
const cached = this.getCachedBehavior(behavior);
|
|
4400
|
-
|
|
5336
|
+
const entry = {
|
|
4401
5337
|
id: this.behaviorId += 1,
|
|
5338
|
+
hash,
|
|
4402
5339
|
selector,
|
|
4403
5340
|
rootSelector,
|
|
4404
5341
|
specificity: this.computeSpecificity(selector),
|
|
4405
5342
|
order: this.behaviorRegistry.length,
|
|
4406
|
-
|
|
4407
|
-
|
|
5343
|
+
flags: behavior.flags ?? {},
|
|
5344
|
+
flagArgs: behavior.flagArgs ?? {},
|
|
5345
|
+
...cached,
|
|
5346
|
+
...parentSelector ? { parentSelector } : {}
|
|
5347
|
+
};
|
|
5348
|
+
this.behaviorRegistry.push(entry);
|
|
5349
|
+
this.behaviorRegistryHashes.add(hash);
|
|
4408
5350
|
this.collectNestedBehaviors(behavior.body, selector, rootSelector);
|
|
4409
5351
|
}
|
|
4410
5352
|
collectNestedBehaviors(block, parentSelector, rootSelector) {
|
|
@@ -4477,7 +5419,8 @@ var Engine = class _Engine {
|
|
|
4477
5419
|
blocks.push({
|
|
4478
5420
|
event: statement.eventName,
|
|
4479
5421
|
body: statement.body,
|
|
4480
|
-
|
|
5422
|
+
flags: statement.flags,
|
|
5423
|
+
flagArgs: statement.flagArgs,
|
|
4481
5424
|
args: statement.args
|
|
4482
5425
|
});
|
|
4483
5426
|
}
|
|
@@ -4542,6 +5485,8 @@ var Engine = class _Engine {
|
|
|
4542
5485
|
return {
|
|
4543
5486
|
type,
|
|
4544
5487
|
selector: node.selector?.selectorText ?? "",
|
|
5488
|
+
flags: node.flags ?? {},
|
|
5489
|
+
flagArgs: node.flagArgs ?? {},
|
|
4545
5490
|
body: this.normalizeNode(node.body)
|
|
4546
5491
|
};
|
|
4547
5492
|
}
|
|
@@ -4559,6 +5504,8 @@ var Engine = class _Engine {
|
|
|
4559
5504
|
type,
|
|
4560
5505
|
eventName: node.eventName ?? "",
|
|
4561
5506
|
args: Array.isArray(node.args) ? node.args : [],
|
|
5507
|
+
flags: node.flags ?? {},
|
|
5508
|
+
flagArgs: node.flagArgs ?? {},
|
|
4562
5509
|
body: this.normalizeNode(node.body)
|
|
4563
5510
|
};
|
|
4564
5511
|
}
|
|
@@ -4576,21 +5523,9 @@ var Engine = class _Engine {
|
|
|
4576
5523
|
return {
|
|
4577
5524
|
type,
|
|
4578
5525
|
target: this.normalizeNode(node.target),
|
|
4579
|
-
value: this.normalizeNode(node.value)
|
|
4580
|
-
};
|
|
4581
|
-
}
|
|
4582
|
-
if (type === "StateBlock") {
|
|
4583
|
-
return {
|
|
4584
|
-
type,
|
|
4585
|
-
entries: Array.isArray(node.entries) ? node.entries.map((entry) => this.normalizeNode(entry)) : []
|
|
4586
|
-
};
|
|
4587
|
-
}
|
|
4588
|
-
if (type === "StateEntry") {
|
|
4589
|
-
return {
|
|
4590
|
-
type,
|
|
4591
|
-
name: node.name ?? "",
|
|
4592
5526
|
value: this.normalizeNode(node.value),
|
|
4593
|
-
|
|
5527
|
+
operator: node.operator ?? "",
|
|
5528
|
+
prefix: Boolean(node.prefix)
|
|
4594
5529
|
};
|
|
4595
5530
|
}
|
|
4596
5531
|
if (type === "FunctionDeclaration") {
|
|
@@ -4624,6 +5559,15 @@ var Engine = class _Engine {
|
|
|
4624
5559
|
value: this.normalizeNode(node.value ?? null)
|
|
4625
5560
|
};
|
|
4626
5561
|
}
|
|
5562
|
+
if (type === "Assert") {
|
|
5563
|
+
return {
|
|
5564
|
+
type,
|
|
5565
|
+
test: this.normalizeNode(node.test)
|
|
5566
|
+
};
|
|
5567
|
+
}
|
|
5568
|
+
if (type === "Break" || type === "Continue") {
|
|
5569
|
+
return { type };
|
|
5570
|
+
}
|
|
4627
5571
|
if (type === "If") {
|
|
4628
5572
|
return {
|
|
4629
5573
|
type,
|
|
@@ -4648,6 +5592,15 @@ var Engine = class _Engine {
|
|
|
4648
5592
|
body: this.normalizeNode(node.body)
|
|
4649
5593
|
};
|
|
4650
5594
|
}
|
|
5595
|
+
if (type === "ForEach") {
|
|
5596
|
+
return {
|
|
5597
|
+
type,
|
|
5598
|
+
kind: node.kind ?? "of",
|
|
5599
|
+
target: this.normalizeNode(node.target),
|
|
5600
|
+
iterable: this.normalizeNode(node.iterable),
|
|
5601
|
+
body: this.normalizeNode(node.body)
|
|
5602
|
+
};
|
|
5603
|
+
}
|
|
4651
5604
|
if (type === "Try") {
|
|
4652
5605
|
return {
|
|
4653
5606
|
type,
|
|
@@ -4770,7 +5723,9 @@ var Engine = class _Engine {
|
|
|
4770
5723
|
globals: this.globals,
|
|
4771
5724
|
element,
|
|
4772
5725
|
returnValue: void 0,
|
|
4773
|
-
returning: false
|
|
5726
|
+
returning: false,
|
|
5727
|
+
breaking: false,
|
|
5728
|
+
continuing: false
|
|
4774
5729
|
};
|
|
4775
5730
|
const previousValues = /* @__PURE__ */ new Map();
|
|
4776
5731
|
await this.applyFunctionParams(callScope, declaration.params, previousValues, context, args);
|
|
@@ -4821,6 +5776,7 @@ var Engine = class _Engine {
|
|
|
4821
5776
|
const context = { scope, rootScope, element };
|
|
4822
5777
|
const operator = declaration.operator;
|
|
4823
5778
|
const debounceMs = declaration.flags.debounce ? declaration.flagArgs.debounce ?? 200 : void 0;
|
|
5779
|
+
const transform = (value) => this.applyCustomFlagTransforms(value, element, scope, declaration);
|
|
4824
5780
|
const importantKey = this.getImportantKey(declaration);
|
|
4825
5781
|
if (!declaration.flags.important && importantKey && this.isImportant(element, importantKey)) {
|
|
4826
5782
|
return;
|
|
@@ -4831,7 +5787,8 @@ var Engine = class _Engine {
|
|
|
4831
5787
|
this.applyCustomFlags(element, scope, declaration);
|
|
4832
5788
|
if (declaration.target instanceof IdentifierExpression) {
|
|
4833
5789
|
const value = await declaration.value.evaluate(context);
|
|
4834
|
-
|
|
5790
|
+
const transformed = this.applyCustomFlagTransforms(value, element, scope, declaration);
|
|
5791
|
+
scope.setPath(declaration.target.name, transformed);
|
|
4835
5792
|
if (declaration.flags.important && importantKey) {
|
|
4836
5793
|
this.markImportant(element, importantKey);
|
|
4837
5794
|
}
|
|
@@ -4844,7 +5801,7 @@ var Engine = class _Engine {
|
|
|
4844
5801
|
const exprIdentifier = declaration.value instanceof IdentifierExpression ? declaration.value.name : void 0;
|
|
4845
5802
|
if (operator === ":>") {
|
|
4846
5803
|
if (exprIdentifier) {
|
|
4847
|
-
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope);
|
|
5804
|
+
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope, transform);
|
|
4848
5805
|
}
|
|
4849
5806
|
if (declaration.flags.important && importantKey) {
|
|
4850
5807
|
this.markImportant(element, importantKey);
|
|
@@ -4852,11 +5809,12 @@ var Engine = class _Engine {
|
|
|
4852
5809
|
return;
|
|
4853
5810
|
}
|
|
4854
5811
|
if (operator === ":=" && exprIdentifier) {
|
|
4855
|
-
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope);
|
|
5812
|
+
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope, transform);
|
|
4856
5813
|
}
|
|
4857
5814
|
if (!exprIdentifier) {
|
|
4858
5815
|
const value = await declaration.value.evaluate(context);
|
|
4859
|
-
this.
|
|
5816
|
+
const transformed = this.applyCustomFlagTransforms(value, element, scope, declaration);
|
|
5817
|
+
this.setDirectiveValue(element, target, transformed, declaration.flags.trusted);
|
|
4860
5818
|
const shouldWatch2 = operator === ":<" || operator === ":=";
|
|
4861
5819
|
if (shouldWatch2) {
|
|
4862
5820
|
this.applyDirectiveFromExpression(
|
|
@@ -4906,6 +5864,63 @@ var Engine = class _Engine {
|
|
|
4906
5864
|
});
|
|
4907
5865
|
}
|
|
4908
5866
|
}
|
|
5867
|
+
applyCustomFlagTransforms(value, element, scope, declaration) {
|
|
5868
|
+
if (this.flagHandlers.size === 0) {
|
|
5869
|
+
return value;
|
|
5870
|
+
}
|
|
5871
|
+
let nextValue = value;
|
|
5872
|
+
for (const [name, handler] of this.flagHandlers) {
|
|
5873
|
+
if (!declaration.flags[name] || !handler.transformValue) {
|
|
5874
|
+
continue;
|
|
5875
|
+
}
|
|
5876
|
+
nextValue = handler.transformValue(
|
|
5877
|
+
{
|
|
5878
|
+
name,
|
|
5879
|
+
args: declaration.flagArgs[name],
|
|
5880
|
+
element,
|
|
5881
|
+
scope,
|
|
5882
|
+
declaration
|
|
5883
|
+
},
|
|
5884
|
+
nextValue
|
|
5885
|
+
);
|
|
5886
|
+
}
|
|
5887
|
+
return nextValue;
|
|
5888
|
+
}
|
|
5889
|
+
async applyBehaviorModifierHook(hook, behavior, element, scope, rootScope) {
|
|
5890
|
+
if (this.behaviorModifiers.size === 0) {
|
|
5891
|
+
return;
|
|
5892
|
+
}
|
|
5893
|
+
for (const [name, handler] of this.behaviorModifiers) {
|
|
5894
|
+
if (!behavior.flags?.[name]) {
|
|
5895
|
+
continue;
|
|
5896
|
+
}
|
|
5897
|
+
const callback = handler[hook];
|
|
5898
|
+
if (!callback) {
|
|
5899
|
+
continue;
|
|
5900
|
+
}
|
|
5901
|
+
await callback({
|
|
5902
|
+
name,
|
|
5903
|
+
args: behavior.flagArgs?.[name],
|
|
5904
|
+
element,
|
|
5905
|
+
scope,
|
|
5906
|
+
rootScope,
|
|
5907
|
+
behavior,
|
|
5908
|
+
engine: this
|
|
5909
|
+
});
|
|
5910
|
+
}
|
|
5911
|
+
}
|
|
5912
|
+
behaviorHasModifierHooks(behavior) {
|
|
5913
|
+
if (this.behaviorModifiers.size === 0) {
|
|
5914
|
+
return false;
|
|
5915
|
+
}
|
|
5916
|
+
const flags = behavior.flags ?? {};
|
|
5917
|
+
for (const name of Object.keys(flags)) {
|
|
5918
|
+
if (flags[name] && this.behaviorModifiers.has(name)) {
|
|
5919
|
+
return true;
|
|
5920
|
+
}
|
|
5921
|
+
}
|
|
5922
|
+
return false;
|
|
5923
|
+
}
|
|
4909
5924
|
applyDirectiveFromScope(element, target, expr, scope, trusted, debounceMs, watch = true, rootScope) {
|
|
4910
5925
|
if (target.kind === "attr" && target.name === "html" && element instanceof HTMLElement) {
|
|
4911
5926
|
const handler2 = () => {
|
|
@@ -4922,7 +5937,7 @@ var Engine = class _Engine {
|
|
|
4922
5937
|
const useRoot = expr.startsWith("root.") && rootScope;
|
|
4923
5938
|
const sourceScope = useRoot ? rootScope : scope;
|
|
4924
5939
|
const watchExpr = useRoot ? expr.slice("root.".length) : expr;
|
|
4925
|
-
this.watchWithDebounce(sourceScope, watchExpr, handler2, debounceMs);
|
|
5940
|
+
this.watchWithDebounce(sourceScope, watchExpr, handler2, debounceMs, element);
|
|
4926
5941
|
}
|
|
4927
5942
|
return;
|
|
4928
5943
|
}
|
|
@@ -4941,7 +5956,7 @@ var Engine = class _Engine {
|
|
|
4941
5956
|
const useRoot = expr.startsWith("root.") && rootScope;
|
|
4942
5957
|
const sourceScope = useRoot ? rootScope : scope;
|
|
4943
5958
|
const watchExpr = useRoot ? expr.slice("root.".length) : expr;
|
|
4944
|
-
this.watchWithDebounce(sourceScope, watchExpr, handler, debounceMs);
|
|
5959
|
+
this.watchWithDebounce(sourceScope, watchExpr, handler, debounceMs, element);
|
|
4945
5960
|
}
|
|
4946
5961
|
}
|
|
4947
5962
|
applyDirectiveFromExpression(element, target, expr, scope, trusted, debounceMs, rootScope) {
|
|
@@ -4953,45 +5968,49 @@ var Engine = class _Engine {
|
|
|
4953
5968
|
void handler();
|
|
4954
5969
|
this.watchAllScopes(scope, () => {
|
|
4955
5970
|
void handler();
|
|
4956
|
-
}, debounceMs);
|
|
5971
|
+
}, debounceMs, element);
|
|
4957
5972
|
}
|
|
4958
|
-
applyDirectiveToScope(element, target, expr, scope, debounceMs, rootScope) {
|
|
5973
|
+
applyDirectiveToScope(element, target, expr, scope, debounceMs, rootScope, transform) {
|
|
4959
5974
|
const useRoot = expr.startsWith("root.") && rootScope;
|
|
4960
5975
|
const targetScope = useRoot ? rootScope : scope;
|
|
4961
5976
|
const targetExpr = useRoot ? `self.${expr.slice("root.".length)}` : expr;
|
|
4962
5977
|
if (target.kind === "attr" && target.name === "value") {
|
|
4963
|
-
this.applyValueBindingToScope(element, targetExpr, debounceMs, targetScope);
|
|
5978
|
+
this.applyValueBindingToScope(element, targetExpr, debounceMs, targetScope, transform);
|
|
4964
5979
|
return;
|
|
4965
5980
|
}
|
|
4966
5981
|
if (target.kind === "attr" && target.name === "checked") {
|
|
4967
|
-
this.applyCheckedBindingToScope(element, targetExpr, debounceMs, targetScope);
|
|
5982
|
+
this.applyCheckedBindingToScope(element, targetExpr, debounceMs, targetScope, transform);
|
|
4968
5983
|
return;
|
|
4969
5984
|
}
|
|
4970
5985
|
const value = this.getDirectiveValue(element, target);
|
|
4971
5986
|
if (value != null) {
|
|
4972
|
-
|
|
5987
|
+
const nextValue = transform ? transform(value) : value;
|
|
5988
|
+
targetScope.set(targetExpr, nextValue);
|
|
4973
5989
|
}
|
|
4974
5990
|
}
|
|
4975
|
-
applyCheckedBindingToScope(element, expr, debounceMs, scope) {
|
|
5991
|
+
applyCheckedBindingToScope(element, expr, debounceMs, scope, transform) {
|
|
4976
5992
|
if (!(element instanceof HTMLInputElement)) {
|
|
4977
5993
|
return;
|
|
4978
5994
|
}
|
|
4979
5995
|
const handler = () => {
|
|
4980
5996
|
const targetScope = scope ?? this.getScope(element);
|
|
4981
|
-
|
|
5997
|
+
const value = transform ? transform(element.checked) : element.checked;
|
|
5998
|
+
targetScope.set(expr, value);
|
|
4982
5999
|
};
|
|
4983
6000
|
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4984
6001
|
effectiveHandler();
|
|
4985
6002
|
element.addEventListener("change", effectiveHandler);
|
|
4986
6003
|
element.addEventListener("input", effectiveHandler);
|
|
4987
6004
|
}
|
|
4988
|
-
applyValueBindingToScope(element, expr, debounceMs, scope) {
|
|
6005
|
+
applyValueBindingToScope(element, expr, debounceMs, scope, transform) {
|
|
4989
6006
|
if (!(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) {
|
|
4990
6007
|
return;
|
|
4991
6008
|
}
|
|
4992
6009
|
const handler = () => {
|
|
4993
6010
|
const targetScope = scope ?? this.getScope(element);
|
|
4994
|
-
|
|
6011
|
+
const value = element.value;
|
|
6012
|
+
const nextValue = transform ? transform(value) : value;
|
|
6013
|
+
targetScope.set(expr, nextValue);
|
|
4995
6014
|
};
|
|
4996
6015
|
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4997
6016
|
effectiveHandler();
|
|
@@ -5008,6 +6027,14 @@ var Engine = class _Engine {
|
|
|
5008
6027
|
return;
|
|
5009
6028
|
}
|
|
5010
6029
|
if (target.kind === "attr") {
|
|
6030
|
+
if (target.name === "text" && element instanceof HTMLElement) {
|
|
6031
|
+
element.innerText = value == null ? "" : String(value);
|
|
6032
|
+
return;
|
|
6033
|
+
}
|
|
6034
|
+
if (target.name === "content" && element instanceof HTMLElement) {
|
|
6035
|
+
element.textContent = value == null ? "" : String(value);
|
|
6036
|
+
return;
|
|
6037
|
+
}
|
|
5011
6038
|
if (target.name === "value") {
|
|
5012
6039
|
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
|
5013
6040
|
element.value = value == null ? "" : String(value);
|
|
@@ -5038,6 +6065,12 @@ var Engine = class _Engine {
|
|
|
5038
6065
|
}
|
|
5039
6066
|
getDirectiveValue(element, target) {
|
|
5040
6067
|
if (target.kind === "attr") {
|
|
6068
|
+
if (target.name === "text" && element instanceof HTMLElement) {
|
|
6069
|
+
return element.innerText;
|
|
6070
|
+
}
|
|
6071
|
+
if (target.name === "content" && element instanceof HTMLElement) {
|
|
6072
|
+
return element.textContent ?? "";
|
|
6073
|
+
}
|
|
5041
6074
|
if (target.name === "value") {
|
|
5042
6075
|
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
|
5043
6076
|
return element.value;
|
|
@@ -5073,17 +6106,27 @@ var Engine = class _Engine {
|
|
|
5073
6106
|
id: "vsn-bind",
|
|
5074
6107
|
match: (name) => name.startsWith("vsn-bind"),
|
|
5075
6108
|
handle: (element, name, value, scope) => {
|
|
5076
|
-
const
|
|
5077
|
-
this.
|
|
5078
|
-
|
|
6109
|
+
const parsedDirection = this.parseBindDirection(name);
|
|
6110
|
+
const config = this.resolveBindConfig(element, value, scope, parsedDirection);
|
|
6111
|
+
const direction = config.direction;
|
|
6112
|
+
const auto = parsedDirection === "auto";
|
|
6113
|
+
this.bindBindings.set(element, { expr: value, direction, auto });
|
|
6114
|
+
if (!auto && (direction === "to" || direction === "both")) {
|
|
5079
6115
|
this.markInlineDeclaration(element, `state:${value}`);
|
|
5080
6116
|
}
|
|
5081
|
-
if (
|
|
6117
|
+
if (config.seedFromScope) {
|
|
6118
|
+
applyBindToElement(element, value, scope);
|
|
6119
|
+
}
|
|
6120
|
+
if (config.deferToScope) {
|
|
6121
|
+
this.pendingAutoBindToScope.push({ element, expr: value, scope });
|
|
6122
|
+
} else if (config.syncToScope) {
|
|
5082
6123
|
applyBindToScope(element, value, scope);
|
|
6124
|
+
}
|
|
6125
|
+
if (direction === "to" || direction === "both") {
|
|
5083
6126
|
this.attachBindInputHandler(element, value);
|
|
5084
6127
|
}
|
|
5085
6128
|
if (direction === "from" || direction === "both") {
|
|
5086
|
-
this.watch(scope, value, () => applyBindToElement(element, value, scope));
|
|
6129
|
+
this.watch(scope, value, () => applyBindToElement(element, value, scope), element);
|
|
5087
6130
|
}
|
|
5088
6131
|
}
|
|
5089
6132
|
});
|
|
@@ -5095,7 +6138,7 @@ var Engine = class _Engine {
|
|
|
5095
6138
|
if (element instanceof HTMLElement) {
|
|
5096
6139
|
applyIf(element, value, scope);
|
|
5097
6140
|
}
|
|
5098
|
-
this.watch(scope, value, () => this.evaluate(element));
|
|
6141
|
+
this.watch(scope, value, () => this.evaluate(element), element);
|
|
5099
6142
|
}
|
|
5100
6143
|
});
|
|
5101
6144
|
this.registerAttributeHandler({
|
|
@@ -5106,7 +6149,7 @@ var Engine = class _Engine {
|
|
|
5106
6149
|
if (element instanceof HTMLElement) {
|
|
5107
6150
|
applyShow(element, value, scope);
|
|
5108
6151
|
}
|
|
5109
|
-
this.watch(scope, value, () => this.evaluate(element));
|
|
6152
|
+
this.watch(scope, value, () => this.evaluate(element), element);
|
|
5110
6153
|
}
|
|
5111
6154
|
});
|
|
5112
6155
|
this.registerAttributeHandler({
|
|
@@ -5122,7 +6165,7 @@ var Engine = class _Engine {
|
|
|
5122
6165
|
this.handleTrustedHtml(element);
|
|
5123
6166
|
}
|
|
5124
6167
|
}
|
|
5125
|
-
this.watch(scope, value, () => this.evaluate(element));
|
|
6168
|
+
this.watch(scope, value, () => this.evaluate(element), element);
|
|
5126
6169
|
}
|
|
5127
6170
|
});
|
|
5128
6171
|
this.registerAttributeHandler({
|
|
@@ -5135,7 +6178,7 @@ var Engine = class _Engine {
|
|
|
5135
6178
|
}
|
|
5136
6179
|
this.eachBindings.set(element, { ...config, rendered: [] });
|
|
5137
6180
|
this.renderEach(element);
|
|
5138
|
-
this.watch(scope, config.listExpr, () => this.renderEach(element));
|
|
6181
|
+
this.watch(scope, config.listExpr, () => this.renderEach(element), element);
|
|
5139
6182
|
}
|
|
5140
6183
|
});
|
|
5141
6184
|
this.registerAttributeHandler({
|
|
@@ -5190,15 +6233,27 @@ function parseCFS(source) {
|
|
|
5190
6233
|
const parser = new Parser(source);
|
|
5191
6234
|
return parser.parseProgram();
|
|
5192
6235
|
}
|
|
6236
|
+
if (typeof window !== "undefined") {
|
|
6237
|
+
window["parseCFS"] = parseCFS;
|
|
6238
|
+
}
|
|
5193
6239
|
function autoMount(root = document) {
|
|
5194
6240
|
if (typeof document === "undefined") {
|
|
5195
6241
|
return null;
|
|
5196
6242
|
}
|
|
5197
6243
|
const engine = new Engine();
|
|
6244
|
+
globalThis.VSNEngine = engine;
|
|
5198
6245
|
const startTime = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
5199
6246
|
const mount = () => {
|
|
5200
6247
|
const target = root instanceof Document ? root.body : root;
|
|
5201
6248
|
if (target) {
|
|
6249
|
+
const plugins = globalThis.VSNPlugins;
|
|
6250
|
+
if (plugins && typeof plugins === "object") {
|
|
6251
|
+
for (const plugin of Object.values(plugins)) {
|
|
6252
|
+
if (typeof plugin === "function") {
|
|
6253
|
+
plugin(engine);
|
|
6254
|
+
}
|
|
6255
|
+
}
|
|
6256
|
+
}
|
|
5202
6257
|
const sources = Array.from(document.querySelectorAll('script[type="text/vsn"]')).map((script) => script.textContent ?? "").join("\n");
|
|
5203
6258
|
if (sources.trim()) {
|
|
5204
6259
|
engine.registerBehaviors(sources);
|
|
@@ -5210,9 +6265,9 @@ function autoMount(root = document) {
|
|
|
5210
6265
|
}
|
|
5211
6266
|
};
|
|
5212
6267
|
if (document.readyState === "loading") {
|
|
5213
|
-
document.addEventListener("DOMContentLoaded", mount, { once: true });
|
|
6268
|
+
document.addEventListener("DOMContentLoaded", () => setTimeout(mount, 0), { once: true });
|
|
5214
6269
|
} else {
|
|
5215
|
-
mount
|
|
6270
|
+
setTimeout(mount, 0);
|
|
5216
6271
|
}
|
|
5217
6272
|
return engine;
|
|
5218
6273
|
}
|
|
@@ -5226,16 +6281,21 @@ if (typeof document !== "undefined") {
|
|
|
5226
6281
|
0 && (module.exports = {
|
|
5227
6282
|
ArrayExpression,
|
|
5228
6283
|
ArrayPattern,
|
|
6284
|
+
AssertError,
|
|
6285
|
+
AssertNode,
|
|
5229
6286
|
AssignmentNode,
|
|
5230
6287
|
AwaitExpression,
|
|
5231
6288
|
BaseNode,
|
|
5232
6289
|
BehaviorNode,
|
|
5233
6290
|
BinaryExpression,
|
|
5234
6291
|
BlockNode,
|
|
6292
|
+
BreakNode,
|
|
5235
6293
|
CallExpression,
|
|
6294
|
+
ContinueNode,
|
|
5236
6295
|
DeclarationNode,
|
|
5237
6296
|
DirectiveExpression,
|
|
5238
6297
|
Engine,
|
|
6298
|
+
ForEachNode,
|
|
5239
6299
|
ForNode,
|
|
5240
6300
|
FunctionDeclarationNode,
|
|
5241
6301
|
FunctionExpression,
|
|
@@ -5255,8 +6315,6 @@ if (typeof document !== "undefined") {
|
|
|
5255
6315
|
ReturnNode,
|
|
5256
6316
|
SelectorNode,
|
|
5257
6317
|
SpreadElement,
|
|
5258
|
-
StateBlockNode,
|
|
5259
|
-
StateEntryNode,
|
|
5260
6318
|
TemplateExpression,
|
|
5261
6319
|
TernaryExpression,
|
|
5262
6320
|
TokenType,
|