vsn 1.0.2 → 1.0.4
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 +1833 -794
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +191 -54
- package/dist/index.d.ts +191 -54
- package/dist/index.js +1828 -792
- 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 +480 -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/dist/plugins/sanitize-html.d.ts +484 -0
- package/dist/plugins/sanitize-html.js +236 -0
- package/dist/plugins/sanitize-html.js.map +1 -0
- package/dist/plugins/sanitize-html.min.js +2 -0
- package/dist/plugins/sanitize-html.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;
|
|
781
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();
|
|
782
1010
|
}
|
|
783
|
-
|
|
784
|
-
|
|
1011
|
+
let index = 0;
|
|
1012
|
+
const loop = () => {
|
|
1013
|
+
if (index >= entries.length || context.returning) {
|
|
1014
|
+
context.scope = previousScope;
|
|
1015
|
+
return void 0;
|
|
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);
|
|
1045
|
+
}
|
|
1046
|
+
return [];
|
|
1047
|
+
}
|
|
1048
|
+
if (typeof value === "string") {
|
|
1049
|
+
return Array.from(value);
|
|
785
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
|
+
});
|
|
894
1221
|
}
|
|
895
|
-
|
|
1222
|
+
if (activeScope && activeScope === scope) {
|
|
1223
|
+
this.restoreParams(activeScope, previousValues);
|
|
1224
|
+
}
|
|
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
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1232
|
+
const setPath = scope.setPath?.bind(scope);
|
|
1233
|
+
if (!setPath) {
|
|
1234
|
+
return;
|
|
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;
|
|
917
1259
|
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
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,13 +1347,22 @@ 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 {
|
|
@@ -1016,15 +1371,17 @@ var UnaryExpression = class extends BaseNode {
|
|
|
1016
1371
|
this.operator = operator;
|
|
1017
1372
|
this.argument = argument;
|
|
1018
1373
|
}
|
|
1019
|
-
|
|
1020
|
-
const value =
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
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", "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,30 +3077,13 @@ ${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
|
-
this.stream.next();
|
|
2628
|
-
this.stream.skipWhitespace();
|
|
2629
|
-
const numberToken = this.stream.expect("Number" /* Number */);
|
|
2630
|
-
flagArgs.debounce = Number(numberToken.value);
|
|
2631
|
-
this.stream.skipWhitespace();
|
|
2632
|
-
this.stream.expect("RParen" /* RParen */);
|
|
2633
|
-
} else {
|
|
2634
|
-
flagArgs.debounce = 200;
|
|
2635
|
-
}
|
|
2636
|
-
} else if (this.customFlags.has(name)) {
|
|
2637
|
-
flags[name] = true;
|
|
2638
|
-
const customArg = this.parseCustomFlagArg();
|
|
2639
|
-
if (customArg !== void 0) {
|
|
2640
|
-
flagArgs[name] = customArg;
|
|
2641
|
-
}
|
|
2642
|
-
} else {
|
|
2643
|
-
throw new Error(`Unknown flag ${name}`);
|
|
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;
|
|
2644
3087
|
}
|
|
2645
3088
|
}
|
|
2646
3089
|
return { flags, flagArgs };
|
|
@@ -2655,21 +3098,86 @@ ${caret}`;
|
|
|
2655
3098
|
if (!token) {
|
|
2656
3099
|
throw new Error("Unterminated flag arguments");
|
|
2657
3100
|
}
|
|
2658
|
-
|
|
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
|
+
}
|
|
2659
3111
|
if (token.type === "Number" /* Number */) {
|
|
2660
|
-
|
|
2661
|
-
}
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
}
|
|
2668
|
-
|
|
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;
|
|
3168
|
+
} else {
|
|
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();
|
|
3178
|
+
}
|
|
2669
3179
|
}
|
|
2670
|
-
|
|
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
|
}
|
|
@@ -3420,17 +3932,14 @@ function applyShow(element, expression, scope) {
|
|
|
3420
3932
|
}
|
|
3421
3933
|
|
|
3422
3934
|
// src/runtime/html.ts
|
|
3423
|
-
function
|
|
3424
|
-
return value.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "");
|
|
3425
|
-
}
|
|
3426
|
-
function applyHtml(element, expression, scope, trusted) {
|
|
3935
|
+
function applyHtml(element, expression, scope) {
|
|
3427
3936
|
const key = expression.trim();
|
|
3428
3937
|
if (!key) {
|
|
3429
3938
|
return;
|
|
3430
3939
|
}
|
|
3431
3940
|
const value = scope.get(key);
|
|
3432
3941
|
const html = value == null ? "" : String(value);
|
|
3433
|
-
element.innerHTML =
|
|
3942
|
+
element.innerHTML = html;
|
|
3434
3943
|
}
|
|
3435
3944
|
|
|
3436
3945
|
// src/runtime/http.ts
|
|
@@ -3450,7 +3959,7 @@ async function applyGet(element, config, scope, onHtmlApplied) {
|
|
|
3450
3959
|
}
|
|
3451
3960
|
if (config.swap === "outer") {
|
|
3452
3961
|
const wrapper = document.createElement("div");
|
|
3453
|
-
applyHtml(wrapper, "__html", { get: () => html }
|
|
3962
|
+
applyHtml(wrapper, "__html", { get: () => html });
|
|
3454
3963
|
const replacement = wrapper.firstElementChild;
|
|
3455
3964
|
if (replacement && target.parentNode) {
|
|
3456
3965
|
target.parentNode.replaceChild(replacement, target);
|
|
@@ -3458,7 +3967,7 @@ async function applyGet(element, config, scope, onHtmlApplied) {
|
|
|
3458
3967
|
}
|
|
3459
3968
|
return;
|
|
3460
3969
|
}
|
|
3461
|
-
applyHtml(target, "__html", { get: () => html }
|
|
3970
|
+
applyHtml(target, "__html", { get: () => html });
|
|
3462
3971
|
onHtmlApplied?.(target);
|
|
3463
3972
|
}
|
|
3464
3973
|
function resolveTarget(element, selector) {
|
|
@@ -3494,18 +4003,19 @@ var Engine = class _Engine {
|
|
|
3494
4003
|
eachBindings = /* @__PURE__ */ new WeakMap();
|
|
3495
4004
|
lifecycleBindings = /* @__PURE__ */ new WeakMap();
|
|
3496
4005
|
behaviorRegistry = [];
|
|
4006
|
+
behaviorRegistryHashes = /* @__PURE__ */ new Set();
|
|
3497
4007
|
behaviorBindings = /* @__PURE__ */ new WeakMap();
|
|
3498
4008
|
behaviorListeners = /* @__PURE__ */ new WeakMap();
|
|
3499
4009
|
behaviorId = 0;
|
|
3500
4010
|
codeCache = /* @__PURE__ */ new Map();
|
|
3501
4011
|
behaviorCache = /* @__PURE__ */ new Map();
|
|
3502
4012
|
observer;
|
|
3503
|
-
observerRoot;
|
|
3504
4013
|
attributeHandlers = [];
|
|
3505
4014
|
globals = {};
|
|
3506
4015
|
importantFlags = /* @__PURE__ */ new WeakMap();
|
|
3507
4016
|
inlineDeclarations = /* @__PURE__ */ new WeakMap();
|
|
3508
4017
|
flagHandlers = /* @__PURE__ */ new Map();
|
|
4018
|
+
behaviorModifiers = /* @__PURE__ */ new Map();
|
|
3509
4019
|
pendingAdded = /* @__PURE__ */ new Set();
|
|
3510
4020
|
pendingRemoved = /* @__PURE__ */ new Set();
|
|
3511
4021
|
pendingUpdated = /* @__PURE__ */ new Set();
|
|
@@ -3514,10 +4024,118 @@ var Engine = class _Engine {
|
|
|
3514
4024
|
diagnostics;
|
|
3515
4025
|
logger;
|
|
3516
4026
|
pendingUses = [];
|
|
4027
|
+
pendingAutoBindToScope = [];
|
|
4028
|
+
scopeWatchers = /* @__PURE__ */ new WeakMap();
|
|
4029
|
+
executionStack = [];
|
|
4030
|
+
groupProxyCache = /* @__PURE__ */ new WeakMap();
|
|
3517
4031
|
constructor(options = {}) {
|
|
3518
4032
|
this.diagnostics = options.diagnostics ?? false;
|
|
3519
4033
|
this.logger = options.logger ?? console;
|
|
3520
4034
|
this.registerGlobal("console", console);
|
|
4035
|
+
this.registerFlag("important");
|
|
4036
|
+
this.registerFlag("debounce", {
|
|
4037
|
+
onEventBind: ({ args }) => ({
|
|
4038
|
+
debounceMs: typeof args === "number" ? args : 200
|
|
4039
|
+
})
|
|
4040
|
+
});
|
|
4041
|
+
this.registerFlag("prevent", {
|
|
4042
|
+
onEventBefore: ({ event }) => {
|
|
4043
|
+
event?.preventDefault();
|
|
4044
|
+
}
|
|
4045
|
+
});
|
|
4046
|
+
this.registerFlag("stop", {
|
|
4047
|
+
onEventBefore: ({ event }) => {
|
|
4048
|
+
event?.stopPropagation();
|
|
4049
|
+
}
|
|
4050
|
+
});
|
|
4051
|
+
this.registerFlag("self", {
|
|
4052
|
+
onEventBefore: ({ event, element }) => {
|
|
4053
|
+
const target = event?.target;
|
|
4054
|
+
if (!(target instanceof Node)) {
|
|
4055
|
+
return false;
|
|
4056
|
+
}
|
|
4057
|
+
return target === element;
|
|
4058
|
+
}
|
|
4059
|
+
});
|
|
4060
|
+
this.registerFlag("outside", {
|
|
4061
|
+
onEventBind: ({ element }) => ({ listenerTarget: element.ownerDocument }),
|
|
4062
|
+
onEventBefore: ({ event, element }) => {
|
|
4063
|
+
const target = event?.target;
|
|
4064
|
+
if (!(target instanceof Node)) {
|
|
4065
|
+
return false;
|
|
4066
|
+
}
|
|
4067
|
+
return !element.contains(target);
|
|
4068
|
+
}
|
|
4069
|
+
});
|
|
4070
|
+
this.registerFlag("once", {
|
|
4071
|
+
onEventBind: () => ({ options: { once: true } })
|
|
4072
|
+
});
|
|
4073
|
+
this.registerFlag("passive", {
|
|
4074
|
+
onEventBind: () => ({ options: { passive: true } })
|
|
4075
|
+
});
|
|
4076
|
+
this.registerFlag("capture", {
|
|
4077
|
+
onEventBind: () => ({ options: { capture: true } })
|
|
4078
|
+
});
|
|
4079
|
+
this.registerFlag("shift", {
|
|
4080
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "shift")
|
|
4081
|
+
});
|
|
4082
|
+
this.registerFlag("ctrl", {
|
|
4083
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "ctrl")
|
|
4084
|
+
});
|
|
4085
|
+
this.registerFlag("control", {
|
|
4086
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "ctrl")
|
|
4087
|
+
});
|
|
4088
|
+
this.registerFlag("alt", {
|
|
4089
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "alt")
|
|
4090
|
+
});
|
|
4091
|
+
this.registerFlag("meta", {
|
|
4092
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "meta")
|
|
4093
|
+
});
|
|
4094
|
+
this.registerFlag("enter", {
|
|
4095
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "enter")
|
|
4096
|
+
});
|
|
4097
|
+
this.registerFlag("escape", {
|
|
4098
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "escape")
|
|
4099
|
+
});
|
|
4100
|
+
this.registerFlag("esc", {
|
|
4101
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "escape")
|
|
4102
|
+
});
|
|
4103
|
+
this.registerFlag("tab", {
|
|
4104
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "tab")
|
|
4105
|
+
});
|
|
4106
|
+
this.registerFlag("space", {
|
|
4107
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "space")
|
|
4108
|
+
});
|
|
4109
|
+
this.registerFlag("up", {
|
|
4110
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowup")
|
|
4111
|
+
});
|
|
4112
|
+
this.registerFlag("down", {
|
|
4113
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowdown")
|
|
4114
|
+
});
|
|
4115
|
+
this.registerFlag("left", {
|
|
4116
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowleft")
|
|
4117
|
+
});
|
|
4118
|
+
this.registerFlag("right", {
|
|
4119
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowright")
|
|
4120
|
+
});
|
|
4121
|
+
this.registerFlag("arrowup", {
|
|
4122
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowup")
|
|
4123
|
+
});
|
|
4124
|
+
this.registerFlag("arrowdown", {
|
|
4125
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowdown")
|
|
4126
|
+
});
|
|
4127
|
+
this.registerFlag("arrowleft", {
|
|
4128
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowleft")
|
|
4129
|
+
});
|
|
4130
|
+
this.registerFlag("arrowright", {
|
|
4131
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "arrowright")
|
|
4132
|
+
});
|
|
4133
|
+
this.registerFlag("delete", {
|
|
4134
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "delete")
|
|
4135
|
+
});
|
|
4136
|
+
this.registerFlag("backspace", {
|
|
4137
|
+
onEventBefore: ({ event }) => this.matchesKeyFlag(event, "backspace")
|
|
4138
|
+
});
|
|
3521
4139
|
this.registerGlobal("list", {
|
|
3522
4140
|
async map(items, fn) {
|
|
3523
4141
|
if (!Array.isArray(items) || typeof fn !== "function") {
|
|
@@ -3555,6 +4173,96 @@ var Engine = class _Engine {
|
|
|
3555
4173
|
}
|
|
3556
4174
|
});
|
|
3557
4175
|
this.registerDefaultAttributeHandlers();
|
|
4176
|
+
this.registerFlag("int", {
|
|
4177
|
+
transformValue: (_context, value) => this.coerceInt(value)
|
|
4178
|
+
});
|
|
4179
|
+
this.registerFlag("float", {
|
|
4180
|
+
transformValue: (_context, value) => this.coerceFloat(value)
|
|
4181
|
+
});
|
|
4182
|
+
this.registerBehaviorModifier("group", {
|
|
4183
|
+
onConstruct: ({ args, scope, rootScope, behavior, element }) => {
|
|
4184
|
+
const key = typeof args === "string" ? args : void 0;
|
|
4185
|
+
if (!key) {
|
|
4186
|
+
return;
|
|
4187
|
+
}
|
|
4188
|
+
const targetScope = this.getGroupTargetScope(element, behavior, scope, rootScope);
|
|
4189
|
+
const existing = targetScope.getPath?.(key);
|
|
4190
|
+
const list = Array.isArray(existing) ? existing : [];
|
|
4191
|
+
const proxy = this.getGroupProxy(scope);
|
|
4192
|
+
if (!list.includes(proxy)) {
|
|
4193
|
+
list.push(proxy);
|
|
4194
|
+
targetScope.setPath?.(key, list);
|
|
4195
|
+
} else if (!Array.isArray(existing)) {
|
|
4196
|
+
targetScope.setPath?.(key, list);
|
|
4197
|
+
}
|
|
4198
|
+
},
|
|
4199
|
+
onUnbind: ({ args, scope, rootScope, behavior, element }) => {
|
|
4200
|
+
const key = typeof args === "string" ? args : void 0;
|
|
4201
|
+
if (!key) {
|
|
4202
|
+
return;
|
|
4203
|
+
}
|
|
4204
|
+
const targetScope = this.getGroupTargetScope(element, behavior, scope, rootScope);
|
|
4205
|
+
const existing = targetScope.getPath?.(key);
|
|
4206
|
+
if (!Array.isArray(existing)) {
|
|
4207
|
+
return;
|
|
4208
|
+
}
|
|
4209
|
+
const proxy = this.getGroupProxy(scope);
|
|
4210
|
+
const next = existing.filter((entry) => entry !== proxy);
|
|
4211
|
+
if (next.length !== existing.length) {
|
|
4212
|
+
targetScope.setPath?.(key, next);
|
|
4213
|
+
}
|
|
4214
|
+
}
|
|
4215
|
+
});
|
|
4216
|
+
}
|
|
4217
|
+
getGroupTargetScope(element, behavior, scope, rootScope) {
|
|
4218
|
+
let targetScope = rootScope ?? scope;
|
|
4219
|
+
if (behavior.parentSelector) {
|
|
4220
|
+
const parentElement = element.closest(behavior.parentSelector);
|
|
4221
|
+
if (parentElement) {
|
|
4222
|
+
targetScope = this.getScope(parentElement);
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
return targetScope;
|
|
4226
|
+
}
|
|
4227
|
+
getGroupProxy(scope) {
|
|
4228
|
+
const cached = this.groupProxyCache.get(scope);
|
|
4229
|
+
if (cached) {
|
|
4230
|
+
return cached;
|
|
4231
|
+
}
|
|
4232
|
+
const proxy = new Proxy(
|
|
4233
|
+
{},
|
|
4234
|
+
{
|
|
4235
|
+
get: (_target, prop) => {
|
|
4236
|
+
if (typeof prop === "symbol") {
|
|
4237
|
+
return void 0;
|
|
4238
|
+
}
|
|
4239
|
+
if (prop === "__scope") {
|
|
4240
|
+
return scope;
|
|
4241
|
+
}
|
|
4242
|
+
return scope.getPath(String(prop));
|
|
4243
|
+
},
|
|
4244
|
+
set: (_target, prop, value) => {
|
|
4245
|
+
if (typeof prop === "symbol") {
|
|
4246
|
+
return false;
|
|
4247
|
+
}
|
|
4248
|
+
scope.setPath(String(prop), value);
|
|
4249
|
+
return true;
|
|
4250
|
+
},
|
|
4251
|
+
has: (_target, prop) => {
|
|
4252
|
+
if (typeof prop === "symbol") {
|
|
4253
|
+
return false;
|
|
4254
|
+
}
|
|
4255
|
+
return scope.getPath(String(prop)) !== void 0;
|
|
4256
|
+
},
|
|
4257
|
+
getOwnPropertyDescriptor: () => ({
|
|
4258
|
+
enumerable: true,
|
|
4259
|
+
configurable: true
|
|
4260
|
+
}),
|
|
4261
|
+
ownKeys: () => []
|
|
4262
|
+
}
|
|
4263
|
+
);
|
|
4264
|
+
this.groupProxyCache.set(scope, proxy);
|
|
4265
|
+
return proxy;
|
|
3558
4266
|
}
|
|
3559
4267
|
async mount(root) {
|
|
3560
4268
|
const documentRoot = root.ownerDocument;
|
|
@@ -3581,7 +4289,10 @@ var Engine = class _Engine {
|
|
|
3581
4289
|
this.disconnectObserver();
|
|
3582
4290
|
}
|
|
3583
4291
|
registerBehaviors(source) {
|
|
3584
|
-
const program = new Parser(source, {
|
|
4292
|
+
const program = new Parser(source, {
|
|
4293
|
+
customFlags: new Set(this.flagHandlers.keys()),
|
|
4294
|
+
behaviorFlags: new Set(this.behaviorModifiers.keys())
|
|
4295
|
+
}).parseProgram();
|
|
3585
4296
|
for (const use of program.uses) {
|
|
3586
4297
|
if (use.flags?.wait) {
|
|
3587
4298
|
this.pendingUses.push(this.waitForUseGlobal(use));
|
|
@@ -3605,11 +4316,14 @@ var Engine = class _Engine {
|
|
|
3605
4316
|
Object.assign(this.globals, values);
|
|
3606
4317
|
}
|
|
3607
4318
|
registerFlag(name, handler = {}) {
|
|
3608
|
-
|
|
4319
|
+
this.flagHandlers.set(name, handler);
|
|
4320
|
+
}
|
|
4321
|
+
registerBehaviorModifier(name, handler = {}) {
|
|
4322
|
+
const reserved = /* @__PURE__ */ new Set(["important", "debounce"]);
|
|
3609
4323
|
if (reserved.has(name)) {
|
|
3610
|
-
throw new Error(`
|
|
4324
|
+
throw new Error(`Behavior modifier '${name}' is reserved`);
|
|
3611
4325
|
}
|
|
3612
|
-
this.
|
|
4326
|
+
this.behaviorModifiers.set(name, handler);
|
|
3613
4327
|
}
|
|
3614
4328
|
getRegistryStats() {
|
|
3615
4329
|
return {
|
|
@@ -3707,17 +4421,14 @@ var Engine = class _Engine {
|
|
|
3707
4421
|
}
|
|
3708
4422
|
const htmlBinding = this.htmlBindings.get(element);
|
|
3709
4423
|
if (htmlBinding && element instanceof HTMLElement) {
|
|
3710
|
-
applyHtml(element, htmlBinding.expr, scope
|
|
3711
|
-
|
|
3712
|
-
this.handleTrustedHtml(element);
|
|
3713
|
-
}
|
|
4424
|
+
applyHtml(element, htmlBinding.expr, scope);
|
|
4425
|
+
this.handleHtmlBehaviors(element);
|
|
3714
4426
|
}
|
|
3715
4427
|
}
|
|
3716
4428
|
attachObserver(root) {
|
|
3717
4429
|
if (this.observer) {
|
|
3718
4430
|
return;
|
|
3719
4431
|
}
|
|
3720
|
-
this.observerRoot = root;
|
|
3721
4432
|
this.observerFlush = debounce(() => this.flushObserverQueue(), 10);
|
|
3722
4433
|
this.observer = new MutationObserver((mutations) => {
|
|
3723
4434
|
for (const mutation of mutations) {
|
|
@@ -3747,7 +4458,6 @@ var Engine = class _Engine {
|
|
|
3747
4458
|
disconnectObserver() {
|
|
3748
4459
|
this.observer?.disconnect();
|
|
3749
4460
|
this.observer = void 0;
|
|
3750
|
-
this.observerRoot = void 0;
|
|
3751
4461
|
this.pendingAdded.clear();
|
|
3752
4462
|
this.pendingRemoved.clear();
|
|
3753
4463
|
this.pendingUpdated.clear();
|
|
@@ -3776,6 +4486,8 @@ var Engine = class _Engine {
|
|
|
3776
4486
|
if (this.behaviorBindings.has(node)) {
|
|
3777
4487
|
this.runBehaviorDestruct(node);
|
|
3778
4488
|
}
|
|
4489
|
+
this.cleanupScopeWatchers(node);
|
|
4490
|
+
this.cleanupBehaviorListeners(node);
|
|
3779
4491
|
for (const child of Array.from(node.querySelectorAll("*"))) {
|
|
3780
4492
|
if (this.lifecycleBindings.has(child)) {
|
|
3781
4493
|
this.runDestruct(child);
|
|
@@ -3783,6 +4495,8 @@ var Engine = class _Engine {
|
|
|
3783
4495
|
if (this.behaviorBindings.has(child)) {
|
|
3784
4496
|
this.runBehaviorDestruct(child);
|
|
3785
4497
|
}
|
|
4498
|
+
this.cleanupScopeWatchers(child);
|
|
4499
|
+
this.cleanupBehaviorListeners(child);
|
|
3786
4500
|
}
|
|
3787
4501
|
}
|
|
3788
4502
|
handleAddedNode(node) {
|
|
@@ -3806,13 +4520,13 @@ var Engine = class _Engine {
|
|
|
3806
4520
|
}
|
|
3807
4521
|
async applyBehaviors(root) {
|
|
3808
4522
|
await this.waitForUses();
|
|
3809
|
-
if (this.behaviorRegistry.length
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
await this.reapplyBehaviorsForElement(element);
|
|
4523
|
+
if (this.behaviorRegistry.length > 0) {
|
|
4524
|
+
const elements = [root, ...Array.from(root.querySelectorAll("*"))];
|
|
4525
|
+
for (const element of elements) {
|
|
4526
|
+
await this.reapplyBehaviorsForElement(element);
|
|
4527
|
+
}
|
|
3815
4528
|
}
|
|
4529
|
+
this.flushAutoBindQueue();
|
|
3816
4530
|
}
|
|
3817
4531
|
async reapplyBehaviorsForElement(element) {
|
|
3818
4532
|
if (this.behaviorRegistry.length === 0) {
|
|
@@ -3844,15 +4558,18 @@ var Engine = class _Engine {
|
|
|
3844
4558
|
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3845
4559
|
this.applyBehaviorFunctions(element, scope, behavior.functions, rootScope);
|
|
3846
4560
|
await this.applyBehaviorDeclarations(element, scope, behavior.declarations, rootScope);
|
|
4561
|
+
await this.applyBehaviorModifierHook("onBind", behavior, element, scope, rootScope);
|
|
3847
4562
|
if (behavior.construct) {
|
|
3848
4563
|
await this.safeExecuteBlock(behavior.construct, scope, element, rootScope);
|
|
3849
4564
|
}
|
|
4565
|
+
await this.applyBehaviorModifierHook("onConstruct", behavior, element, scope, rootScope);
|
|
3850
4566
|
for (const onBlock of behavior.onBlocks) {
|
|
3851
4567
|
this.attachBehaviorOnHandler(
|
|
3852
4568
|
element,
|
|
3853
4569
|
onBlock.event,
|
|
3854
4570
|
onBlock.body,
|
|
3855
|
-
onBlock.
|
|
4571
|
+
onBlock.flags,
|
|
4572
|
+
onBlock.flagArgs,
|
|
3856
4573
|
onBlock.args,
|
|
3857
4574
|
behavior.id,
|
|
3858
4575
|
rootScope
|
|
@@ -3862,10 +4579,11 @@ var Engine = class _Engine {
|
|
|
3862
4579
|
}
|
|
3863
4580
|
unbindBehaviorForElement(behavior, element, scope, bound) {
|
|
3864
4581
|
bound.delete(behavior.id);
|
|
4582
|
+
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3865
4583
|
if (behavior.destruct) {
|
|
3866
|
-
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3867
4584
|
void this.safeExecuteBlock(behavior.destruct, scope, element, rootScope);
|
|
3868
4585
|
}
|
|
4586
|
+
void this.applyBehaviorModifierHook("onDestruct", behavior, element, scope, rootScope);
|
|
3869
4587
|
const listenerMap = this.behaviorListeners.get(element);
|
|
3870
4588
|
const listeners = listenerMap?.get(behavior.id);
|
|
3871
4589
|
if (listeners) {
|
|
@@ -3874,6 +4592,7 @@ var Engine = class _Engine {
|
|
|
3874
4592
|
}
|
|
3875
4593
|
listenerMap?.delete(behavior.id);
|
|
3876
4594
|
}
|
|
4595
|
+
void this.applyBehaviorModifierHook("onUnbind", behavior, element, scope, rootScope);
|
|
3877
4596
|
this.logDiagnostic("unbind", element, behavior);
|
|
3878
4597
|
}
|
|
3879
4598
|
runBehaviorDestruct(element) {
|
|
@@ -3883,11 +4602,15 @@ var Engine = class _Engine {
|
|
|
3883
4602
|
}
|
|
3884
4603
|
const scope = this.getScope(element);
|
|
3885
4604
|
for (const behavior of this.behaviorRegistry) {
|
|
3886
|
-
if (!bound.has(behavior.id) || !behavior.destruct) {
|
|
4605
|
+
if (!bound.has(behavior.id) || !behavior.destruct && !this.behaviorHasModifierHooks(behavior)) {
|
|
3887
4606
|
continue;
|
|
3888
4607
|
}
|
|
3889
4608
|
const rootScope = this.getBehaviorRootScope(element, behavior);
|
|
3890
|
-
|
|
4609
|
+
if (behavior.destruct) {
|
|
4610
|
+
void this.safeExecuteBlock(behavior.destruct, scope, element, rootScope);
|
|
4611
|
+
}
|
|
4612
|
+
void this.applyBehaviorModifierHook("onDestruct", behavior, element, scope, rootScope);
|
|
4613
|
+
void this.applyBehaviorModifierHook("onUnbind", behavior, element, scope, rootScope);
|
|
3891
4614
|
}
|
|
3892
4615
|
}
|
|
3893
4616
|
attachAttributes(element) {
|
|
@@ -3971,6 +4694,7 @@ var Engine = class _Engine {
|
|
|
3971
4694
|
const fragment = element.content.cloneNode(true);
|
|
3972
4695
|
const roots = Array.from(fragment.children);
|
|
3973
4696
|
const itemScope = new Scope(scope);
|
|
4697
|
+
itemScope.isEachItem = true;
|
|
3974
4698
|
itemScope.setPath(`self.${binding.itemName}`, item);
|
|
3975
4699
|
if (binding.indexName) {
|
|
3976
4700
|
itemScope.setPath(`self.${binding.indexName}`, index);
|
|
@@ -4009,7 +4733,93 @@ var Engine = class _Engine {
|
|
|
4009
4733
|
if (name.includes(":to")) {
|
|
4010
4734
|
return "to";
|
|
4011
4735
|
}
|
|
4012
|
-
return "
|
|
4736
|
+
return "auto";
|
|
4737
|
+
}
|
|
4738
|
+
resolveBindConfig(element, expr, scope, direction) {
|
|
4739
|
+
if (direction !== "auto") {
|
|
4740
|
+
return {
|
|
4741
|
+
direction,
|
|
4742
|
+
seedFromScope: false,
|
|
4743
|
+
syncToScope: direction === "to" || direction === "both",
|
|
4744
|
+
deferToScope: false
|
|
4745
|
+
};
|
|
4746
|
+
}
|
|
4747
|
+
if (this.isInEachScope(scope)) {
|
|
4748
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: false };
|
|
4749
|
+
}
|
|
4750
|
+
if (this.isFormControl(element)) {
|
|
4751
|
+
if (this.hasScopeValue(scope, expr)) {
|
|
4752
|
+
return { direction: "both", seedFromScope: true, syncToScope: false, deferToScope: false };
|
|
4753
|
+
}
|
|
4754
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: true };
|
|
4755
|
+
}
|
|
4756
|
+
if (this.hasScopeValue(scope, expr)) {
|
|
4757
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: false };
|
|
4758
|
+
}
|
|
4759
|
+
if (this.hasElementValue(element)) {
|
|
4760
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: true };
|
|
4761
|
+
}
|
|
4762
|
+
return { direction: "both", seedFromScope: false, syncToScope: false, deferToScope: false };
|
|
4763
|
+
}
|
|
4764
|
+
isFormControl(element) {
|
|
4765
|
+
return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement;
|
|
4766
|
+
}
|
|
4767
|
+
hasScopeValue(scope, expr) {
|
|
4768
|
+
const key = expr.trim();
|
|
4769
|
+
if (!key) {
|
|
4770
|
+
return false;
|
|
4771
|
+
}
|
|
4772
|
+
const value = scope.get(key);
|
|
4773
|
+
return value !== void 0 && value !== null;
|
|
4774
|
+
}
|
|
4775
|
+
hasElementValue(element) {
|
|
4776
|
+
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
|
|
4777
|
+
return element.value.length > 0;
|
|
4778
|
+
}
|
|
4779
|
+
return (element.textContent ?? "").trim().length > 0;
|
|
4780
|
+
}
|
|
4781
|
+
coerceInt(value) {
|
|
4782
|
+
if (value == null || value === "") {
|
|
4783
|
+
return value;
|
|
4784
|
+
}
|
|
4785
|
+
const num = typeof value === "number" ? value : Number.parseInt(String(value), 10);
|
|
4786
|
+
return Number.isNaN(num) ? value : num;
|
|
4787
|
+
}
|
|
4788
|
+
coerceFloat(value) {
|
|
4789
|
+
if (value == null || value === "") {
|
|
4790
|
+
return value;
|
|
4791
|
+
}
|
|
4792
|
+
const num = typeof value === "number" ? value : Number.parseFloat(String(value));
|
|
4793
|
+
return Number.isNaN(num) ? value : num;
|
|
4794
|
+
}
|
|
4795
|
+
isInEachScope(scope) {
|
|
4796
|
+
let cursor = scope;
|
|
4797
|
+
while (cursor) {
|
|
4798
|
+
if (cursor.isEachItem) {
|
|
4799
|
+
return true;
|
|
4800
|
+
}
|
|
4801
|
+
cursor = cursor.parent;
|
|
4802
|
+
}
|
|
4803
|
+
return false;
|
|
4804
|
+
}
|
|
4805
|
+
flushAutoBindQueue() {
|
|
4806
|
+
if (this.pendingAutoBindToScope.length === 0) {
|
|
4807
|
+
return;
|
|
4808
|
+
}
|
|
4809
|
+
const pending = this.pendingAutoBindToScope;
|
|
4810
|
+
this.pendingAutoBindToScope = [];
|
|
4811
|
+
for (const entry of pending) {
|
|
4812
|
+
if (!entry.element.isConnected) {
|
|
4813
|
+
continue;
|
|
4814
|
+
}
|
|
4815
|
+
if (this.hasScopeValue(entry.scope, entry.expr)) {
|
|
4816
|
+
continue;
|
|
4817
|
+
}
|
|
4818
|
+
if (!this.hasElementValue(entry.element)) {
|
|
4819
|
+
continue;
|
|
4820
|
+
}
|
|
4821
|
+
applyBindToScope(entry.element, entry.expr, entry.scope);
|
|
4822
|
+
}
|
|
4013
4823
|
}
|
|
4014
4824
|
hasVsnAttributes(element) {
|
|
4015
4825
|
return element.getAttributeNames().some((name) => name.startsWith("vsn-"));
|
|
@@ -4034,7 +4844,7 @@ var Engine = class _Engine {
|
|
|
4034
4844
|
}
|
|
4035
4845
|
return void 0;
|
|
4036
4846
|
}
|
|
4037
|
-
watch(scope, expr, handler) {
|
|
4847
|
+
watch(scope, expr, handler, element) {
|
|
4038
4848
|
const key = expr.trim();
|
|
4039
4849
|
if (!key) {
|
|
4040
4850
|
return;
|
|
@@ -4049,29 +4859,70 @@ var Engine = class _Engine {
|
|
|
4049
4859
|
}
|
|
4050
4860
|
if (target) {
|
|
4051
4861
|
target.on(key, handler);
|
|
4862
|
+
if (element) {
|
|
4863
|
+
this.trackScopeWatcher(element, target, "path", handler, key);
|
|
4864
|
+
}
|
|
4052
4865
|
return;
|
|
4053
4866
|
}
|
|
4054
4867
|
let cursor = scope;
|
|
4055
4868
|
while (cursor) {
|
|
4056
4869
|
cursor.on(key, handler);
|
|
4870
|
+
if (element) {
|
|
4871
|
+
this.trackScopeWatcher(element, cursor, "path", handler, key);
|
|
4872
|
+
}
|
|
4057
4873
|
cursor = cursor.parent;
|
|
4058
4874
|
}
|
|
4059
4875
|
}
|
|
4060
|
-
watchWithDebounce(scope, expr, handler, debounceMs) {
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
} else {
|
|
4064
|
-
this.watch(scope, expr, handler);
|
|
4065
|
-
}
|
|
4876
|
+
watchWithDebounce(scope, expr, handler, debounceMs, element) {
|
|
4877
|
+
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4878
|
+
this.watch(scope, expr, effectiveHandler, element);
|
|
4066
4879
|
}
|
|
4067
|
-
watchAllScopes(scope, handler, debounceMs) {
|
|
4880
|
+
watchAllScopes(scope, handler, debounceMs, element) {
|
|
4068
4881
|
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4069
4882
|
let cursor = scope;
|
|
4070
4883
|
while (cursor) {
|
|
4071
4884
|
cursor.onAny(effectiveHandler);
|
|
4885
|
+
if (element) {
|
|
4886
|
+
this.trackScopeWatcher(element, cursor, "any", effectiveHandler);
|
|
4887
|
+
}
|
|
4072
4888
|
cursor = cursor.parent;
|
|
4073
4889
|
}
|
|
4074
4890
|
}
|
|
4891
|
+
trackScopeWatcher(element, scope, kind, handler, key) {
|
|
4892
|
+
const watchers = this.scopeWatchers.get(element) ?? [];
|
|
4893
|
+
watchers.push({ scope, kind, handler, ...key ? { key } : {} });
|
|
4894
|
+
this.scopeWatchers.set(element, watchers);
|
|
4895
|
+
}
|
|
4896
|
+
cleanupScopeWatchers(element) {
|
|
4897
|
+
const watchers = this.scopeWatchers.get(element);
|
|
4898
|
+
if (!watchers) {
|
|
4899
|
+
return;
|
|
4900
|
+
}
|
|
4901
|
+
for (const watcher of watchers) {
|
|
4902
|
+
if (watcher.kind === "any") {
|
|
4903
|
+
watcher.scope.offAny(watcher.handler);
|
|
4904
|
+
continue;
|
|
4905
|
+
}
|
|
4906
|
+
if (watcher.key) {
|
|
4907
|
+
watcher.scope.off(watcher.key, watcher.handler);
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
this.scopeWatchers.delete(element);
|
|
4911
|
+
}
|
|
4912
|
+
cleanupBehaviorListeners(element) {
|
|
4913
|
+
const listenerMap = this.behaviorListeners.get(element);
|
|
4914
|
+
if (!listenerMap) {
|
|
4915
|
+
return;
|
|
4916
|
+
}
|
|
4917
|
+
for (const listeners of listenerMap.values()) {
|
|
4918
|
+
for (const listener of listeners) {
|
|
4919
|
+
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
4920
|
+
}
|
|
4921
|
+
}
|
|
4922
|
+
listenerMap.clear();
|
|
4923
|
+
this.behaviorListeners.delete(element);
|
|
4924
|
+
this.behaviorBindings.delete(element);
|
|
4925
|
+
}
|
|
4075
4926
|
parseOnAttribute(name, value) {
|
|
4076
4927
|
if (!name.startsWith("vsn-on:")) {
|
|
4077
4928
|
return null;
|
|
@@ -4081,111 +4932,56 @@ var Engine = class _Engine {
|
|
|
4081
4932
|
if (!event) {
|
|
4082
4933
|
return null;
|
|
4083
4934
|
}
|
|
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);
|
|
4935
|
+
if (event.includes(".")) {
|
|
4936
|
+
throw new Error("vsn:on does not support dot modifiers; use !flags instead");
|
|
4097
4937
|
}
|
|
4098
|
-
const
|
|
4938
|
+
const { flagMap, flagArgs } = this.parseInlineFlags(flags);
|
|
4099
4939
|
const config = {
|
|
4100
|
-
event
|
|
4940
|
+
event,
|
|
4101
4941
|
code: value,
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
...descriptor.keyModifiers.length > 0 ? { keyModifiers: descriptor.keyModifiers } : {}
|
|
4942
|
+
flags: flagMap,
|
|
4943
|
+
flagArgs
|
|
4105
4944
|
};
|
|
4106
4945
|
return config;
|
|
4107
4946
|
}
|
|
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);
|
|
4947
|
+
parseInlineFlags(parts) {
|
|
4948
|
+
const flagMap = {};
|
|
4949
|
+
const flagArgs = {};
|
|
4950
|
+
for (const raw of parts) {
|
|
4951
|
+
const trimmed = raw.trim();
|
|
4952
|
+
if (!trimmed) {
|
|
4953
|
+
continue;
|
|
4119
4954
|
}
|
|
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
|
-
}
|
|
4955
|
+
const match = trimmed.match(/^([a-zA-Z][\w-]*)(?:\((.+)\))?$/);
|
|
4956
|
+
if (!match) {
|
|
4165
4957
|
continue;
|
|
4166
4958
|
}
|
|
4167
|
-
const
|
|
4168
|
-
if (
|
|
4169
|
-
|
|
4959
|
+
const name = match[1] ?? "";
|
|
4960
|
+
if (!name) {
|
|
4961
|
+
continue;
|
|
4962
|
+
}
|
|
4963
|
+
if (!this.flagHandlers.has(name)) {
|
|
4964
|
+
throw new Error(`Unknown flag ${name}`);
|
|
4965
|
+
}
|
|
4966
|
+
flagMap[name] = true;
|
|
4967
|
+
if (match[2] !== void 0) {
|
|
4968
|
+
flagArgs[name] = this.parseInlineFlagArg(match[2]);
|
|
4170
4969
|
}
|
|
4171
4970
|
}
|
|
4172
|
-
return
|
|
4971
|
+
return { flagMap, flagArgs };
|
|
4173
4972
|
}
|
|
4174
|
-
|
|
4175
|
-
|
|
4973
|
+
parseInlineFlagArg(raw) {
|
|
4974
|
+
const trimmed = raw.trim();
|
|
4975
|
+
if (trimmed === "true") {
|
|
4176
4976
|
return true;
|
|
4177
4977
|
}
|
|
4178
|
-
|
|
4179
|
-
if (!target || !(target instanceof Node)) {
|
|
4180
|
-
return !modifiers.includes("self") && !modifiers.includes("outside");
|
|
4181
|
-
}
|
|
4182
|
-
if (modifiers.includes("self") && target !== element) {
|
|
4978
|
+
if (trimmed === "false") {
|
|
4183
4979
|
return false;
|
|
4184
4980
|
}
|
|
4185
|
-
if (
|
|
4186
|
-
return
|
|
4981
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
4982
|
+
return Number(trimmed);
|
|
4187
4983
|
}
|
|
4188
|
-
return
|
|
4984
|
+
return trimmed;
|
|
4189
4985
|
}
|
|
4190
4986
|
describeElement(element) {
|
|
4191
4987
|
const tag = element.tagName.toLowerCase();
|
|
@@ -4227,51 +5023,50 @@ var Engine = class _Engine {
|
|
|
4227
5023
|
}
|
|
4228
5024
|
}
|
|
4229
5025
|
attachOnHandler(element, config) {
|
|
4230
|
-
const options = this.
|
|
4231
|
-
|
|
5026
|
+
const { listenerTarget, options, debounceMs } = this.getEventBindingConfig(
|
|
5027
|
+
element,
|
|
5028
|
+
config.flags,
|
|
5029
|
+
config.flagArgs
|
|
5030
|
+
);
|
|
4232
5031
|
let effectiveHandler;
|
|
4233
5032
|
const handler = async (event) => {
|
|
4234
5033
|
if (!element.isConnected) {
|
|
4235
5034
|
listenerTarget.removeEventListener(config.event, effectiveHandler, options);
|
|
4236
5035
|
return;
|
|
4237
5036
|
}
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
}
|
|
4241
|
-
if (!this.matchesTargetModifiers(element, event, config.modifiers)) {
|
|
5037
|
+
const scope = this.getScope(element);
|
|
5038
|
+
if (!this.applyEventFlagBefore(element, scope, config.flags, config.flagArgs, event)) {
|
|
4242
5039
|
return;
|
|
4243
5040
|
}
|
|
4244
|
-
this.applyEventModifiers(event, config.modifiers);
|
|
4245
|
-
const scope = this.getScope(element);
|
|
4246
5041
|
try {
|
|
4247
5042
|
await this.execute(config.code, scope, element);
|
|
4248
5043
|
this.evaluate(element);
|
|
4249
5044
|
} catch (error) {
|
|
4250
5045
|
this.emitError(element, error);
|
|
5046
|
+
} finally {
|
|
5047
|
+
this.applyEventFlagAfter(element, scope, config.flags, config.flagArgs, event);
|
|
4251
5048
|
}
|
|
4252
5049
|
};
|
|
4253
|
-
effectiveHandler =
|
|
5050
|
+
effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4254
5051
|
listenerTarget.addEventListener(config.event, effectiveHandler, options);
|
|
4255
5052
|
}
|
|
4256
|
-
attachBehaviorOnHandler(element, event, body,
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
5053
|
+
attachBehaviorOnHandler(element, event, body, flags, flagArgs, args, behaviorId, rootScope) {
|
|
5054
|
+
if (event.includes(".")) {
|
|
5055
|
+
throw new Error("vsn:on does not support dot modifiers; use !flags instead");
|
|
5056
|
+
}
|
|
5057
|
+
const { listenerTarget, options, debounceMs } = this.getEventBindingConfig(element, flags, flagArgs);
|
|
4260
5058
|
const handler = async (evt) => {
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
}
|
|
4264
|
-
if (!this.matchesTargetModifiers(element, evt, combinedModifiers)) {
|
|
5059
|
+
const scope = this.getScope(element);
|
|
5060
|
+
if (!this.applyEventFlagBefore(element, scope, flags, flagArgs, evt)) {
|
|
4265
5061
|
return;
|
|
4266
5062
|
}
|
|
4267
|
-
this.applyEventModifiers(evt, combinedModifiers);
|
|
4268
|
-
const scope = this.getScope(element);
|
|
4269
5063
|
const previousValues = /* @__PURE__ */ new Map();
|
|
4270
5064
|
if (args && args.length > 0) {
|
|
4271
5065
|
const argName = args[0];
|
|
4272
5066
|
if (argName) {
|
|
4273
5067
|
previousValues.set(argName, scope.getPath(argName));
|
|
4274
|
-
|
|
5068
|
+
const [nextArg] = this.applyEventFlagArgTransforms(element, scope, flags, flagArgs, evt);
|
|
5069
|
+
scope.setPath(argName, nextArg);
|
|
4275
5070
|
}
|
|
4276
5071
|
}
|
|
4277
5072
|
let failed = false;
|
|
@@ -4284,16 +5079,17 @@ var Engine = class _Engine {
|
|
|
4284
5079
|
for (const [name, value] of previousValues.entries()) {
|
|
4285
5080
|
scope.setPath(name, value);
|
|
4286
5081
|
}
|
|
5082
|
+
this.applyEventFlagAfter(element, scope, flags, flagArgs, evt);
|
|
4287
5083
|
}
|
|
4288
5084
|
if (!failed) {
|
|
4289
5085
|
this.evaluate(element);
|
|
4290
5086
|
}
|
|
4291
5087
|
};
|
|
4292
|
-
const
|
|
4293
|
-
listenerTarget.addEventListener(
|
|
5088
|
+
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
5089
|
+
listenerTarget.addEventListener(event, effectiveHandler, options);
|
|
4294
5090
|
const listenerMap = this.behaviorListeners.get(element) ?? /* @__PURE__ */ new Map();
|
|
4295
5091
|
const listeners = listenerMap.get(behaviorId) ?? [];
|
|
4296
|
-
listeners.push({ target: listenerTarget, event
|
|
5092
|
+
listeners.push({ target: listenerTarget, event, handler: effectiveHandler, options });
|
|
4297
5093
|
listenerMap.set(behaviorId, listeners);
|
|
4298
5094
|
this.behaviorListeners.set(element, listenerMap);
|
|
4299
5095
|
}
|
|
@@ -4305,9 +5101,7 @@ var Engine = class _Engine {
|
|
|
4305
5101
|
}
|
|
4306
5102
|
try {
|
|
4307
5103
|
await applyGet(element, config, this.getScope(element), (target) => {
|
|
4308
|
-
|
|
4309
|
-
this.handleTrustedHtml(target);
|
|
4310
|
-
}
|
|
5104
|
+
this.handleHtmlBehaviors(target);
|
|
4311
5105
|
});
|
|
4312
5106
|
} catch (error) {
|
|
4313
5107
|
console.warn("vsn:getError", error);
|
|
@@ -4324,33 +5118,158 @@ var Engine = class _Engine {
|
|
|
4324
5118
|
Promise.resolve().then(handler);
|
|
4325
5119
|
}
|
|
4326
5120
|
}
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
5121
|
+
getEventBindingConfig(element, flags, flagArgs) {
|
|
5122
|
+
let listenerTarget = element;
|
|
5123
|
+
let options = {};
|
|
5124
|
+
let debounceMs;
|
|
5125
|
+
for (const name of Object.keys(flags)) {
|
|
5126
|
+
const handler = this.flagHandlers.get(name);
|
|
5127
|
+
if (!handler?.onEventBind) {
|
|
5128
|
+
continue;
|
|
5129
|
+
}
|
|
5130
|
+
const patch = handler.onEventBind({
|
|
5131
|
+
name,
|
|
5132
|
+
args: flagArgs[name],
|
|
5133
|
+
element,
|
|
5134
|
+
scope: this.getScope(element),
|
|
5135
|
+
rootScope: void 0,
|
|
5136
|
+
event: void 0,
|
|
5137
|
+
engine: this
|
|
5138
|
+
});
|
|
5139
|
+
if (!patch) {
|
|
5140
|
+
continue;
|
|
5141
|
+
}
|
|
5142
|
+
if (patch.listenerTarget) {
|
|
5143
|
+
listenerTarget = patch.listenerTarget;
|
|
5144
|
+
}
|
|
5145
|
+
if (patch.options) {
|
|
5146
|
+
options = { ...options, ...patch.options };
|
|
5147
|
+
}
|
|
5148
|
+
if (patch.debounceMs !== void 0) {
|
|
5149
|
+
debounceMs = patch.debounceMs;
|
|
5150
|
+
}
|
|
5151
|
+
}
|
|
5152
|
+
return {
|
|
5153
|
+
listenerTarget,
|
|
5154
|
+
...Object.keys(options).length > 0 ? { options } : {},
|
|
5155
|
+
...debounceMs !== void 0 ? { debounceMs } : {}
|
|
5156
|
+
};
|
|
5157
|
+
}
|
|
5158
|
+
applyEventFlagBefore(element, scope, flags, flagArgs, event) {
|
|
5159
|
+
for (const name of Object.keys(flags)) {
|
|
5160
|
+
const handler = this.flagHandlers.get(name);
|
|
5161
|
+
if (!handler?.onEventBefore) {
|
|
5162
|
+
continue;
|
|
5163
|
+
}
|
|
5164
|
+
const result = handler.onEventBefore({
|
|
5165
|
+
name,
|
|
5166
|
+
args: flagArgs[name],
|
|
5167
|
+
element,
|
|
5168
|
+
scope,
|
|
5169
|
+
rootScope: void 0,
|
|
5170
|
+
event,
|
|
5171
|
+
engine: this
|
|
5172
|
+
});
|
|
5173
|
+
if (result === false) {
|
|
5174
|
+
return false;
|
|
5175
|
+
}
|
|
4330
5176
|
}
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
5177
|
+
return true;
|
|
5178
|
+
}
|
|
5179
|
+
applyEventFlagAfter(element, scope, flags, flagArgs, event) {
|
|
5180
|
+
for (const name of Object.keys(flags)) {
|
|
5181
|
+
const handler = this.flagHandlers.get(name);
|
|
5182
|
+
if (!handler?.onEventAfter) {
|
|
5183
|
+
continue;
|
|
4336
5184
|
}
|
|
5185
|
+
handler.onEventAfter({
|
|
5186
|
+
name,
|
|
5187
|
+
args: flagArgs[name],
|
|
5188
|
+
element,
|
|
5189
|
+
scope,
|
|
5190
|
+
rootScope: void 0,
|
|
5191
|
+
event,
|
|
5192
|
+
engine: this
|
|
5193
|
+
});
|
|
4337
5194
|
}
|
|
4338
5195
|
}
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
5196
|
+
applyEventFlagArgTransforms(element, scope, flags, flagArgs, event) {
|
|
5197
|
+
let args = [event];
|
|
5198
|
+
for (const name of Object.keys(flags)) {
|
|
5199
|
+
const handler = this.flagHandlers.get(name);
|
|
5200
|
+
if (!handler?.transformEventArgs) {
|
|
5201
|
+
continue;
|
|
5202
|
+
}
|
|
5203
|
+
const nextArgs = handler.transformEventArgs(
|
|
5204
|
+
{
|
|
5205
|
+
name,
|
|
5206
|
+
args: flagArgs[name],
|
|
5207
|
+
element,
|
|
5208
|
+
scope,
|
|
5209
|
+
rootScope: void 0,
|
|
5210
|
+
event,
|
|
5211
|
+
engine: this
|
|
5212
|
+
},
|
|
5213
|
+
args
|
|
5214
|
+
);
|
|
5215
|
+
if (Array.isArray(nextArgs)) {
|
|
5216
|
+
args = nextArgs;
|
|
5217
|
+
}
|
|
4342
5218
|
}
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
5219
|
+
return args;
|
|
5220
|
+
}
|
|
5221
|
+
matchesKeyFlag(event, flag) {
|
|
5222
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
5223
|
+
return false;
|
|
5224
|
+
}
|
|
5225
|
+
const modifierChecks = {
|
|
5226
|
+
shift: event.shiftKey,
|
|
5227
|
+
ctrl: event.ctrlKey,
|
|
5228
|
+
alt: event.altKey,
|
|
5229
|
+
meta: event.metaKey
|
|
5230
|
+
};
|
|
5231
|
+
if (flag in modifierChecks) {
|
|
5232
|
+
return modifierChecks[flag] ?? false;
|
|
5233
|
+
}
|
|
5234
|
+
const keyAliases = {
|
|
5235
|
+
escape: "escape",
|
|
5236
|
+
esc: "escape",
|
|
5237
|
+
enter: "enter",
|
|
5238
|
+
tab: "tab",
|
|
5239
|
+
space: "space",
|
|
5240
|
+
spacebar: "space",
|
|
5241
|
+
up: "arrowup",
|
|
5242
|
+
down: "arrowdown",
|
|
5243
|
+
left: "arrowleft",
|
|
5244
|
+
right: "arrowright",
|
|
5245
|
+
arrowup: "arrowup",
|
|
5246
|
+
arrowdown: "arrowdown",
|
|
5247
|
+
arrowleft: "arrowleft",
|
|
5248
|
+
arrowright: "arrowright",
|
|
5249
|
+
delete: "delete",
|
|
5250
|
+
backspace: "backspace"
|
|
5251
|
+
};
|
|
5252
|
+
let key = event.key?.toLowerCase() ?? "";
|
|
5253
|
+
if (key === " ") {
|
|
5254
|
+
key = "space";
|
|
4346
5255
|
}
|
|
4347
|
-
|
|
4348
|
-
|
|
5256
|
+
const expectedKey = keyAliases[flag] ?? flag;
|
|
5257
|
+
return key === expectedKey;
|
|
5258
|
+
}
|
|
5259
|
+
async withExecutionElement(element, fn) {
|
|
5260
|
+
if (!element) {
|
|
5261
|
+
await fn();
|
|
5262
|
+
return;
|
|
4349
5263
|
}
|
|
4350
|
-
|
|
4351
|
-
|
|
5264
|
+
this.executionStack.push(element);
|
|
5265
|
+
try {
|
|
5266
|
+
await fn();
|
|
5267
|
+
} finally {
|
|
5268
|
+
this.executionStack.pop();
|
|
4352
5269
|
}
|
|
4353
|
-
|
|
5270
|
+
}
|
|
5271
|
+
getCurrentElement() {
|
|
5272
|
+
return this.executionStack[this.executionStack.length - 1];
|
|
4354
5273
|
}
|
|
4355
5274
|
async execute(code, scope, element, rootScope) {
|
|
4356
5275
|
let block = this.codeCache.get(code);
|
|
@@ -4358,22 +5277,26 @@ var Engine = class _Engine {
|
|
|
4358
5277
|
block = Parser.parseInline(code);
|
|
4359
5278
|
this.codeCache.set(code, block);
|
|
4360
5279
|
}
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
5280
|
+
await this.withExecutionElement(element, async () => {
|
|
5281
|
+
const context = {
|
|
5282
|
+
scope,
|
|
5283
|
+
rootScope,
|
|
5284
|
+
globals: this.globals,
|
|
5285
|
+
...element ? { element } : {}
|
|
5286
|
+
};
|
|
5287
|
+
await block.evaluate(context);
|
|
5288
|
+
});
|
|
4368
5289
|
}
|
|
4369
5290
|
async executeBlock(block, scope, element, rootScope) {
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
5291
|
+
await this.withExecutionElement(element, async () => {
|
|
5292
|
+
const context = {
|
|
5293
|
+
scope,
|
|
5294
|
+
rootScope,
|
|
5295
|
+
globals: this.globals,
|
|
5296
|
+
...element ? { element } : {}
|
|
5297
|
+
};
|
|
5298
|
+
await block.evaluate(context);
|
|
5299
|
+
});
|
|
4377
5300
|
}
|
|
4378
5301
|
async safeExecute(code, scope, element, rootScope) {
|
|
4379
5302
|
try {
|
|
@@ -4396,15 +5319,26 @@ var Engine = class _Engine {
|
|
|
4396
5319
|
collectBehavior(behavior, parentSelector, rootSelectorOverride) {
|
|
4397
5320
|
const selector = parentSelector ? `${parentSelector} ${behavior.selector.selectorText}` : behavior.selector.selectorText;
|
|
4398
5321
|
const rootSelector = rootSelectorOverride ?? (parentSelector ?? behavior.selector.selectorText);
|
|
5322
|
+
const behaviorHash = this.hashBehavior(behavior);
|
|
5323
|
+
const hash = `${selector}::${rootSelector}::${behaviorHash}`;
|
|
5324
|
+
if (this.behaviorRegistryHashes.has(hash)) {
|
|
5325
|
+
return;
|
|
5326
|
+
}
|
|
4399
5327
|
const cached = this.getCachedBehavior(behavior);
|
|
4400
|
-
|
|
5328
|
+
const entry = {
|
|
4401
5329
|
id: this.behaviorId += 1,
|
|
5330
|
+
hash,
|
|
4402
5331
|
selector,
|
|
4403
5332
|
rootSelector,
|
|
4404
5333
|
specificity: this.computeSpecificity(selector),
|
|
4405
5334
|
order: this.behaviorRegistry.length,
|
|
4406
|
-
|
|
4407
|
-
|
|
5335
|
+
flags: behavior.flags ?? {},
|
|
5336
|
+
flagArgs: behavior.flagArgs ?? {},
|
|
5337
|
+
...cached,
|
|
5338
|
+
...parentSelector ? { parentSelector } : {}
|
|
5339
|
+
};
|
|
5340
|
+
this.behaviorRegistry.push(entry);
|
|
5341
|
+
this.behaviorRegistryHashes.add(hash);
|
|
4408
5342
|
this.collectNestedBehaviors(behavior.body, selector, rootSelector);
|
|
4409
5343
|
}
|
|
4410
5344
|
collectNestedBehaviors(block, parentSelector, rootSelector) {
|
|
@@ -4477,7 +5411,8 @@ var Engine = class _Engine {
|
|
|
4477
5411
|
blocks.push({
|
|
4478
5412
|
event: statement.eventName,
|
|
4479
5413
|
body: statement.body,
|
|
4480
|
-
|
|
5414
|
+
flags: statement.flags,
|
|
5415
|
+
flagArgs: statement.flagArgs,
|
|
4481
5416
|
args: statement.args
|
|
4482
5417
|
});
|
|
4483
5418
|
}
|
|
@@ -4542,6 +5477,8 @@ var Engine = class _Engine {
|
|
|
4542
5477
|
return {
|
|
4543
5478
|
type,
|
|
4544
5479
|
selector: node.selector?.selectorText ?? "",
|
|
5480
|
+
flags: node.flags ?? {},
|
|
5481
|
+
flagArgs: node.flagArgs ?? {},
|
|
4545
5482
|
body: this.normalizeNode(node.body)
|
|
4546
5483
|
};
|
|
4547
5484
|
}
|
|
@@ -4559,6 +5496,8 @@ var Engine = class _Engine {
|
|
|
4559
5496
|
type,
|
|
4560
5497
|
eventName: node.eventName ?? "",
|
|
4561
5498
|
args: Array.isArray(node.args) ? node.args : [],
|
|
5499
|
+
flags: node.flags ?? {},
|
|
5500
|
+
flagArgs: node.flagArgs ?? {},
|
|
4562
5501
|
body: this.normalizeNode(node.body)
|
|
4563
5502
|
};
|
|
4564
5503
|
}
|
|
@@ -4576,21 +5515,9 @@ var Engine = class _Engine {
|
|
|
4576
5515
|
return {
|
|
4577
5516
|
type,
|
|
4578
5517
|
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
5518
|
value: this.normalizeNode(node.value),
|
|
4593
|
-
|
|
5519
|
+
operator: node.operator ?? "",
|
|
5520
|
+
prefix: Boolean(node.prefix)
|
|
4594
5521
|
};
|
|
4595
5522
|
}
|
|
4596
5523
|
if (type === "FunctionDeclaration") {
|
|
@@ -4624,6 +5551,15 @@ var Engine = class _Engine {
|
|
|
4624
5551
|
value: this.normalizeNode(node.value ?? null)
|
|
4625
5552
|
};
|
|
4626
5553
|
}
|
|
5554
|
+
if (type === "Assert") {
|
|
5555
|
+
return {
|
|
5556
|
+
type,
|
|
5557
|
+
test: this.normalizeNode(node.test)
|
|
5558
|
+
};
|
|
5559
|
+
}
|
|
5560
|
+
if (type === "Break" || type === "Continue") {
|
|
5561
|
+
return { type };
|
|
5562
|
+
}
|
|
4627
5563
|
if (type === "If") {
|
|
4628
5564
|
return {
|
|
4629
5565
|
type,
|
|
@@ -4648,6 +5584,15 @@ var Engine = class _Engine {
|
|
|
4648
5584
|
body: this.normalizeNode(node.body)
|
|
4649
5585
|
};
|
|
4650
5586
|
}
|
|
5587
|
+
if (type === "ForEach") {
|
|
5588
|
+
return {
|
|
5589
|
+
type,
|
|
5590
|
+
kind: node.kind ?? "of",
|
|
5591
|
+
target: this.normalizeNode(node.target),
|
|
5592
|
+
iterable: this.normalizeNode(node.iterable),
|
|
5593
|
+
body: this.normalizeNode(node.body)
|
|
5594
|
+
};
|
|
5595
|
+
}
|
|
4651
5596
|
if (type === "Try") {
|
|
4652
5597
|
return {
|
|
4653
5598
|
type,
|
|
@@ -4770,7 +5715,9 @@ var Engine = class _Engine {
|
|
|
4770
5715
|
globals: this.globals,
|
|
4771
5716
|
element,
|
|
4772
5717
|
returnValue: void 0,
|
|
4773
|
-
returning: false
|
|
5718
|
+
returning: false,
|
|
5719
|
+
breaking: false,
|
|
5720
|
+
continuing: false
|
|
4774
5721
|
};
|
|
4775
5722
|
const previousValues = /* @__PURE__ */ new Map();
|
|
4776
5723
|
await this.applyFunctionParams(callScope, declaration.params, previousValues, context, args);
|
|
@@ -4821,6 +5768,7 @@ var Engine = class _Engine {
|
|
|
4821
5768
|
const context = { scope, rootScope, element };
|
|
4822
5769
|
const operator = declaration.operator;
|
|
4823
5770
|
const debounceMs = declaration.flags.debounce ? declaration.flagArgs.debounce ?? 200 : void 0;
|
|
5771
|
+
const transform = (value) => this.applyCustomFlagTransforms(value, element, scope, declaration);
|
|
4824
5772
|
const importantKey = this.getImportantKey(declaration);
|
|
4825
5773
|
if (!declaration.flags.important && importantKey && this.isImportant(element, importantKey)) {
|
|
4826
5774
|
return;
|
|
@@ -4831,7 +5779,8 @@ var Engine = class _Engine {
|
|
|
4831
5779
|
this.applyCustomFlags(element, scope, declaration);
|
|
4832
5780
|
if (declaration.target instanceof IdentifierExpression) {
|
|
4833
5781
|
const value = await declaration.value.evaluate(context);
|
|
4834
|
-
|
|
5782
|
+
const transformed = this.applyCustomFlagTransforms(value, element, scope, declaration);
|
|
5783
|
+
scope.setPath(declaration.target.name, transformed);
|
|
4835
5784
|
if (declaration.flags.important && importantKey) {
|
|
4836
5785
|
this.markImportant(element, importantKey);
|
|
4837
5786
|
}
|
|
@@ -4844,7 +5793,7 @@ var Engine = class _Engine {
|
|
|
4844
5793
|
const exprIdentifier = declaration.value instanceof IdentifierExpression ? declaration.value.name : void 0;
|
|
4845
5794
|
if (operator === ":>") {
|
|
4846
5795
|
if (exprIdentifier) {
|
|
4847
|
-
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope);
|
|
5796
|
+
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope, transform);
|
|
4848
5797
|
}
|
|
4849
5798
|
if (declaration.flags.important && importantKey) {
|
|
4850
5799
|
this.markImportant(element, importantKey);
|
|
@@ -4852,11 +5801,12 @@ var Engine = class _Engine {
|
|
|
4852
5801
|
return;
|
|
4853
5802
|
}
|
|
4854
5803
|
if (operator === ":=" && exprIdentifier) {
|
|
4855
|
-
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope);
|
|
5804
|
+
this.applyDirectiveToScope(element, target, exprIdentifier, scope, debounceMs, rootScope, transform);
|
|
4856
5805
|
}
|
|
4857
5806
|
if (!exprIdentifier) {
|
|
4858
5807
|
const value = await declaration.value.evaluate(context);
|
|
4859
|
-
this.
|
|
5808
|
+
const transformed = this.applyCustomFlagTransforms(value, element, scope, declaration);
|
|
5809
|
+
this.setDirectiveValue(element, target, transformed);
|
|
4860
5810
|
const shouldWatch2 = operator === ":<" || operator === ":=";
|
|
4861
5811
|
if (shouldWatch2) {
|
|
4862
5812
|
this.applyDirectiveFromExpression(
|
|
@@ -4864,7 +5814,6 @@ var Engine = class _Engine {
|
|
|
4864
5814
|
target,
|
|
4865
5815
|
declaration.value,
|
|
4866
5816
|
scope,
|
|
4867
|
-
declaration.flags.trusted,
|
|
4868
5817
|
debounceMs,
|
|
4869
5818
|
rootScope
|
|
4870
5819
|
);
|
|
@@ -4880,7 +5829,6 @@ var Engine = class _Engine {
|
|
|
4880
5829
|
target,
|
|
4881
5830
|
exprIdentifier,
|
|
4882
5831
|
scope,
|
|
4883
|
-
declaration.flags.trusted,
|
|
4884
5832
|
debounceMs,
|
|
4885
5833
|
shouldWatch,
|
|
4886
5834
|
rootScope
|
|
@@ -4906,23 +5854,78 @@ var Engine = class _Engine {
|
|
|
4906
5854
|
});
|
|
4907
5855
|
}
|
|
4908
5856
|
}
|
|
4909
|
-
|
|
5857
|
+
applyCustomFlagTransforms(value, element, scope, declaration) {
|
|
5858
|
+
if (this.flagHandlers.size === 0) {
|
|
5859
|
+
return value;
|
|
5860
|
+
}
|
|
5861
|
+
let nextValue = value;
|
|
5862
|
+
for (const [name, handler] of this.flagHandlers) {
|
|
5863
|
+
if (!declaration.flags[name] || !handler.transformValue) {
|
|
5864
|
+
continue;
|
|
5865
|
+
}
|
|
5866
|
+
nextValue = handler.transformValue(
|
|
5867
|
+
{
|
|
5868
|
+
name,
|
|
5869
|
+
args: declaration.flagArgs[name],
|
|
5870
|
+
element,
|
|
5871
|
+
scope,
|
|
5872
|
+
declaration
|
|
5873
|
+
},
|
|
5874
|
+
nextValue
|
|
5875
|
+
);
|
|
5876
|
+
}
|
|
5877
|
+
return nextValue;
|
|
5878
|
+
}
|
|
5879
|
+
async applyBehaviorModifierHook(hook, behavior, element, scope, rootScope) {
|
|
5880
|
+
if (this.behaviorModifiers.size === 0) {
|
|
5881
|
+
return;
|
|
5882
|
+
}
|
|
5883
|
+
for (const [name, handler] of this.behaviorModifiers) {
|
|
5884
|
+
if (!behavior.flags?.[name]) {
|
|
5885
|
+
continue;
|
|
5886
|
+
}
|
|
5887
|
+
const callback = handler[hook];
|
|
5888
|
+
if (!callback) {
|
|
5889
|
+
continue;
|
|
5890
|
+
}
|
|
5891
|
+
await callback({
|
|
5892
|
+
name,
|
|
5893
|
+
args: behavior.flagArgs?.[name],
|
|
5894
|
+
element,
|
|
5895
|
+
scope,
|
|
5896
|
+
rootScope,
|
|
5897
|
+
behavior,
|
|
5898
|
+
engine: this
|
|
5899
|
+
});
|
|
5900
|
+
}
|
|
5901
|
+
}
|
|
5902
|
+
behaviorHasModifierHooks(behavior) {
|
|
5903
|
+
if (this.behaviorModifiers.size === 0) {
|
|
5904
|
+
return false;
|
|
5905
|
+
}
|
|
5906
|
+
const flags = behavior.flags ?? {};
|
|
5907
|
+
for (const name of Object.keys(flags)) {
|
|
5908
|
+
if (flags[name] && this.behaviorModifiers.has(name)) {
|
|
5909
|
+
return true;
|
|
5910
|
+
}
|
|
5911
|
+
}
|
|
5912
|
+
return false;
|
|
5913
|
+
}
|
|
5914
|
+
applyDirectiveFromScope(element, target, expr, scope, debounceMs, watch = true, rootScope) {
|
|
4910
5915
|
if (target.kind === "attr" && target.name === "html" && element instanceof HTMLElement) {
|
|
4911
5916
|
const handler2 = () => {
|
|
4912
5917
|
const useRoot = expr.startsWith("root.") && rootScope;
|
|
4913
5918
|
const sourceScope = useRoot ? rootScope : scope;
|
|
4914
5919
|
const localExpr = useRoot ? `self.${expr.slice("root.".length)}` : expr;
|
|
4915
|
-
applyHtml(element, localExpr, sourceScope
|
|
5920
|
+
applyHtml(element, localExpr, sourceScope);
|
|
4916
5921
|
};
|
|
4917
5922
|
handler2();
|
|
4918
|
-
|
|
4919
|
-
this.handleTrustedHtml(element);
|
|
4920
|
-
}
|
|
5923
|
+
this.handleHtmlBehaviors(element);
|
|
4921
5924
|
if (watch) {
|
|
4922
5925
|
const useRoot = expr.startsWith("root.") && rootScope;
|
|
4923
5926
|
const sourceScope = useRoot ? rootScope : scope;
|
|
4924
5927
|
const watchExpr = useRoot ? expr.slice("root.".length) : expr;
|
|
4925
|
-
this.watchWithDebounce(sourceScope, watchExpr, handler2, debounceMs);
|
|
5928
|
+
this.watchWithDebounce(sourceScope, watchExpr, handler2, debounceMs, element);
|
|
4926
5929
|
}
|
|
4927
5930
|
return;
|
|
4928
5931
|
}
|
|
@@ -4934,80 +5937,90 @@ var Engine = class _Engine {
|
|
|
4934
5937
|
if (value == null) {
|
|
4935
5938
|
return;
|
|
4936
5939
|
}
|
|
4937
|
-
this.setDirectiveValue(element, target, value
|
|
5940
|
+
this.setDirectiveValue(element, target, value);
|
|
4938
5941
|
};
|
|
4939
5942
|
handler();
|
|
4940
5943
|
if (watch) {
|
|
4941
5944
|
const useRoot = expr.startsWith("root.") && rootScope;
|
|
4942
5945
|
const sourceScope = useRoot ? rootScope : scope;
|
|
4943
5946
|
const watchExpr = useRoot ? expr.slice("root.".length) : expr;
|
|
4944
|
-
this.watchWithDebounce(sourceScope, watchExpr, handler, debounceMs);
|
|
5947
|
+
this.watchWithDebounce(sourceScope, watchExpr, handler, debounceMs, element);
|
|
4945
5948
|
}
|
|
4946
5949
|
}
|
|
4947
|
-
applyDirectiveFromExpression(element, target, expr, scope,
|
|
5950
|
+
applyDirectiveFromExpression(element, target, expr, scope, debounceMs, rootScope) {
|
|
4948
5951
|
const handler = async () => {
|
|
4949
5952
|
const context = { scope, rootScope, element };
|
|
4950
5953
|
const value = await expr.evaluate(context);
|
|
4951
|
-
this.setDirectiveValue(element, target, value
|
|
5954
|
+
this.setDirectiveValue(element, target, value);
|
|
4952
5955
|
};
|
|
4953
5956
|
void handler();
|
|
4954
5957
|
this.watchAllScopes(scope, () => {
|
|
4955
5958
|
void handler();
|
|
4956
|
-
}, debounceMs);
|
|
5959
|
+
}, debounceMs, element);
|
|
4957
5960
|
}
|
|
4958
|
-
applyDirectiveToScope(element, target, expr, scope, debounceMs, rootScope) {
|
|
5961
|
+
applyDirectiveToScope(element, target, expr, scope, debounceMs, rootScope, transform) {
|
|
4959
5962
|
const useRoot = expr.startsWith("root.") && rootScope;
|
|
4960
5963
|
const targetScope = useRoot ? rootScope : scope;
|
|
4961
5964
|
const targetExpr = useRoot ? `self.${expr.slice("root.".length)}` : expr;
|
|
4962
5965
|
if (target.kind === "attr" && target.name === "value") {
|
|
4963
|
-
this.applyValueBindingToScope(element, targetExpr, debounceMs, targetScope);
|
|
5966
|
+
this.applyValueBindingToScope(element, targetExpr, debounceMs, targetScope, transform);
|
|
4964
5967
|
return;
|
|
4965
5968
|
}
|
|
4966
5969
|
if (target.kind === "attr" && target.name === "checked") {
|
|
4967
|
-
this.applyCheckedBindingToScope(element, targetExpr, debounceMs, targetScope);
|
|
5970
|
+
this.applyCheckedBindingToScope(element, targetExpr, debounceMs, targetScope, transform);
|
|
4968
5971
|
return;
|
|
4969
5972
|
}
|
|
4970
5973
|
const value = this.getDirectiveValue(element, target);
|
|
4971
5974
|
if (value != null) {
|
|
4972
|
-
|
|
5975
|
+
const nextValue = transform ? transform(value) : value;
|
|
5976
|
+
targetScope.set(targetExpr, nextValue);
|
|
4973
5977
|
}
|
|
4974
5978
|
}
|
|
4975
|
-
applyCheckedBindingToScope(element, expr, debounceMs, scope) {
|
|
5979
|
+
applyCheckedBindingToScope(element, expr, debounceMs, scope, transform) {
|
|
4976
5980
|
if (!(element instanceof HTMLInputElement)) {
|
|
4977
5981
|
return;
|
|
4978
5982
|
}
|
|
4979
5983
|
const handler = () => {
|
|
4980
5984
|
const targetScope = scope ?? this.getScope(element);
|
|
4981
|
-
|
|
5985
|
+
const value = transform ? transform(element.checked) : element.checked;
|
|
5986
|
+
targetScope.set(expr, value);
|
|
4982
5987
|
};
|
|
4983
5988
|
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4984
5989
|
effectiveHandler();
|
|
4985
5990
|
element.addEventListener("change", effectiveHandler);
|
|
4986
5991
|
element.addEventListener("input", effectiveHandler);
|
|
4987
5992
|
}
|
|
4988
|
-
applyValueBindingToScope(element, expr, debounceMs, scope) {
|
|
5993
|
+
applyValueBindingToScope(element, expr, debounceMs, scope, transform) {
|
|
4989
5994
|
if (!(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) {
|
|
4990
5995
|
return;
|
|
4991
5996
|
}
|
|
4992
5997
|
const handler = () => {
|
|
4993
5998
|
const targetScope = scope ?? this.getScope(element);
|
|
4994
|
-
|
|
5999
|
+
const value = element.value;
|
|
6000
|
+
const nextValue = transform ? transform(value) : value;
|
|
6001
|
+
targetScope.set(expr, nextValue);
|
|
4995
6002
|
};
|
|
4996
6003
|
const effectiveHandler = debounceMs ? debounce(handler, debounceMs) : handler;
|
|
4997
6004
|
effectiveHandler();
|
|
4998
6005
|
element.addEventListener("input", effectiveHandler);
|
|
4999
6006
|
element.addEventListener("change", effectiveHandler);
|
|
5000
6007
|
}
|
|
5001
|
-
setDirectiveValue(element, target, value
|
|
6008
|
+
setDirectiveValue(element, target, value) {
|
|
5002
6009
|
if (target.kind === "attr" && target.name === "html" && element instanceof HTMLElement) {
|
|
5003
6010
|
const html = value == null ? "" : String(value);
|
|
5004
|
-
element.innerHTML =
|
|
5005
|
-
|
|
5006
|
-
this.handleTrustedHtml(element);
|
|
5007
|
-
}
|
|
6011
|
+
element.innerHTML = html;
|
|
6012
|
+
this.handleHtmlBehaviors(element);
|
|
5008
6013
|
return;
|
|
5009
6014
|
}
|
|
5010
6015
|
if (target.kind === "attr") {
|
|
6016
|
+
if (target.name === "text" && element instanceof HTMLElement) {
|
|
6017
|
+
element.innerText = value == null ? "" : String(value);
|
|
6018
|
+
return;
|
|
6019
|
+
}
|
|
6020
|
+
if (target.name === "content" && element instanceof HTMLElement) {
|
|
6021
|
+
element.textContent = value == null ? "" : String(value);
|
|
6022
|
+
return;
|
|
6023
|
+
}
|
|
5011
6024
|
if (target.name === "value") {
|
|
5012
6025
|
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
|
5013
6026
|
element.value = value == null ? "" : String(value);
|
|
@@ -5038,6 +6051,12 @@ var Engine = class _Engine {
|
|
|
5038
6051
|
}
|
|
5039
6052
|
getDirectiveValue(element, target) {
|
|
5040
6053
|
if (target.kind === "attr") {
|
|
6054
|
+
if (target.name === "text" && element instanceof HTMLElement) {
|
|
6055
|
+
return element.innerText;
|
|
6056
|
+
}
|
|
6057
|
+
if (target.name === "content" && element instanceof HTMLElement) {
|
|
6058
|
+
return element.textContent ?? "";
|
|
6059
|
+
}
|
|
5041
6060
|
if (target.name === "value") {
|
|
5042
6061
|
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
|
5043
6062
|
return element.value;
|
|
@@ -5056,7 +6075,7 @@ var Engine = class _Engine {
|
|
|
5056
6075
|
}
|
|
5057
6076
|
return void 0;
|
|
5058
6077
|
}
|
|
5059
|
-
|
|
6078
|
+
handleHtmlBehaviors(root) {
|
|
5060
6079
|
const scripts = Array.from(root.querySelectorAll('script[type="text/vsn"]'));
|
|
5061
6080
|
if (scripts.length === 0) {
|
|
5062
6081
|
return;
|
|
@@ -5073,17 +6092,27 @@ var Engine = class _Engine {
|
|
|
5073
6092
|
id: "vsn-bind",
|
|
5074
6093
|
match: (name) => name.startsWith("vsn-bind"),
|
|
5075
6094
|
handle: (element, name, value, scope) => {
|
|
5076
|
-
const
|
|
5077
|
-
this.
|
|
5078
|
-
|
|
6095
|
+
const parsedDirection = this.parseBindDirection(name);
|
|
6096
|
+
const config = this.resolveBindConfig(element, value, scope, parsedDirection);
|
|
6097
|
+
const direction = config.direction;
|
|
6098
|
+
const auto = parsedDirection === "auto";
|
|
6099
|
+
this.bindBindings.set(element, { expr: value, direction, auto });
|
|
6100
|
+
if (!auto && (direction === "to" || direction === "both")) {
|
|
5079
6101
|
this.markInlineDeclaration(element, `state:${value}`);
|
|
5080
6102
|
}
|
|
5081
|
-
if (
|
|
6103
|
+
if (config.seedFromScope) {
|
|
6104
|
+
applyBindToElement(element, value, scope);
|
|
6105
|
+
}
|
|
6106
|
+
if (config.deferToScope) {
|
|
6107
|
+
this.pendingAutoBindToScope.push({ element, expr: value, scope });
|
|
6108
|
+
} else if (config.syncToScope) {
|
|
5082
6109
|
applyBindToScope(element, value, scope);
|
|
6110
|
+
}
|
|
6111
|
+
if (direction === "to" || direction === "both") {
|
|
5083
6112
|
this.attachBindInputHandler(element, value);
|
|
5084
6113
|
}
|
|
5085
6114
|
if (direction === "from" || direction === "both") {
|
|
5086
|
-
this.watch(scope, value, () => applyBindToElement(element, value, scope));
|
|
6115
|
+
this.watch(scope, value, () => applyBindToElement(element, value, scope), element);
|
|
5087
6116
|
}
|
|
5088
6117
|
}
|
|
5089
6118
|
});
|
|
@@ -5095,7 +6124,7 @@ var Engine = class _Engine {
|
|
|
5095
6124
|
if (element instanceof HTMLElement) {
|
|
5096
6125
|
applyIf(element, value, scope);
|
|
5097
6126
|
}
|
|
5098
|
-
this.watch(scope, value, () => this.evaluate(element));
|
|
6127
|
+
this.watch(scope, value, () => this.evaluate(element), element);
|
|
5099
6128
|
}
|
|
5100
6129
|
});
|
|
5101
6130
|
this.registerAttributeHandler({
|
|
@@ -5106,23 +6135,20 @@ var Engine = class _Engine {
|
|
|
5106
6135
|
if (element instanceof HTMLElement) {
|
|
5107
6136
|
applyShow(element, value, scope);
|
|
5108
6137
|
}
|
|
5109
|
-
this.watch(scope, value, () => this.evaluate(element));
|
|
6138
|
+
this.watch(scope, value, () => this.evaluate(element), element);
|
|
5110
6139
|
}
|
|
5111
6140
|
});
|
|
5112
6141
|
this.registerAttributeHandler({
|
|
5113
6142
|
id: "vsn-html",
|
|
5114
6143
|
match: (name) => name.startsWith("vsn-html"),
|
|
5115
|
-
handle: (element,
|
|
5116
|
-
|
|
5117
|
-
this.htmlBindings.set(element, { expr: value, trusted });
|
|
6144
|
+
handle: (element, _name, value, scope) => {
|
|
6145
|
+
this.htmlBindings.set(element, { expr: value });
|
|
5118
6146
|
this.markInlineDeclaration(element, "attr:html");
|
|
5119
6147
|
if (element instanceof HTMLElement) {
|
|
5120
|
-
applyHtml(element, value, scope
|
|
5121
|
-
|
|
5122
|
-
this.handleTrustedHtml(element);
|
|
5123
|
-
}
|
|
6148
|
+
applyHtml(element, value, scope);
|
|
6149
|
+
this.handleHtmlBehaviors(element);
|
|
5124
6150
|
}
|
|
5125
|
-
this.watch(scope, value, () => this.evaluate(element));
|
|
6151
|
+
this.watch(scope, value, () => this.evaluate(element), element);
|
|
5126
6152
|
}
|
|
5127
6153
|
});
|
|
5128
6154
|
this.registerAttributeHandler({
|
|
@@ -5135,14 +6161,13 @@ var Engine = class _Engine {
|
|
|
5135
6161
|
}
|
|
5136
6162
|
this.eachBindings.set(element, { ...config, rendered: [] });
|
|
5137
6163
|
this.renderEach(element);
|
|
5138
|
-
this.watch(scope, config.listExpr, () => this.renderEach(element));
|
|
6164
|
+
this.watch(scope, config.listExpr, () => this.renderEach(element), element);
|
|
5139
6165
|
}
|
|
5140
6166
|
});
|
|
5141
6167
|
this.registerAttributeHandler({
|
|
5142
6168
|
id: "vsn-get",
|
|
5143
6169
|
match: (name) => name.startsWith("vsn-get"),
|
|
5144
6170
|
handle: (element, name) => {
|
|
5145
|
-
const trusted = name.includes("!trusted");
|
|
5146
6171
|
const autoLoad = name.includes("!load");
|
|
5147
6172
|
const url = element.getAttribute(name) ?? "";
|
|
5148
6173
|
const target = element.getAttribute("vsn-target") ?? void 0;
|
|
@@ -5150,7 +6175,6 @@ var Engine = class _Engine {
|
|
|
5150
6175
|
const config = {
|
|
5151
6176
|
url,
|
|
5152
6177
|
swap,
|
|
5153
|
-
trusted,
|
|
5154
6178
|
...target ? { targetSelector: target } : {}
|
|
5155
6179
|
};
|
|
5156
6180
|
this.getBindings.set(element, config);
|
|
@@ -5190,15 +6214,27 @@ function parseCFS(source) {
|
|
|
5190
6214
|
const parser = new Parser(source);
|
|
5191
6215
|
return parser.parseProgram();
|
|
5192
6216
|
}
|
|
6217
|
+
if (typeof window !== "undefined") {
|
|
6218
|
+
window["parseCFS"] = parseCFS;
|
|
6219
|
+
}
|
|
5193
6220
|
function autoMount(root = document) {
|
|
5194
6221
|
if (typeof document === "undefined") {
|
|
5195
6222
|
return null;
|
|
5196
6223
|
}
|
|
5197
6224
|
const engine = new Engine();
|
|
6225
|
+
globalThis.VSNEngine = engine;
|
|
5198
6226
|
const startTime = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
5199
6227
|
const mount = () => {
|
|
5200
6228
|
const target = root instanceof Document ? root.body : root;
|
|
5201
6229
|
if (target) {
|
|
6230
|
+
const plugins = globalThis.VSNPlugins;
|
|
6231
|
+
if (plugins && typeof plugins === "object") {
|
|
6232
|
+
for (const plugin of Object.values(plugins)) {
|
|
6233
|
+
if (typeof plugin === "function") {
|
|
6234
|
+
plugin(engine);
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6237
|
+
}
|
|
5202
6238
|
const sources = Array.from(document.querySelectorAll('script[type="text/vsn"]')).map((script) => script.textContent ?? "").join("\n");
|
|
5203
6239
|
if (sources.trim()) {
|
|
5204
6240
|
engine.registerBehaviors(sources);
|
|
@@ -5210,9 +6246,9 @@ function autoMount(root = document) {
|
|
|
5210
6246
|
}
|
|
5211
6247
|
};
|
|
5212
6248
|
if (document.readyState === "loading") {
|
|
5213
|
-
document.addEventListener("DOMContentLoaded", mount, { once: true });
|
|
6249
|
+
document.addEventListener("DOMContentLoaded", () => setTimeout(mount, 0), { once: true });
|
|
5214
6250
|
} else {
|
|
5215
|
-
mount
|
|
6251
|
+
setTimeout(mount, 0);
|
|
5216
6252
|
}
|
|
5217
6253
|
return engine;
|
|
5218
6254
|
}
|
|
@@ -5226,16 +6262,21 @@ if (typeof document !== "undefined") {
|
|
|
5226
6262
|
0 && (module.exports = {
|
|
5227
6263
|
ArrayExpression,
|
|
5228
6264
|
ArrayPattern,
|
|
6265
|
+
AssertError,
|
|
6266
|
+
AssertNode,
|
|
5229
6267
|
AssignmentNode,
|
|
5230
6268
|
AwaitExpression,
|
|
5231
6269
|
BaseNode,
|
|
5232
6270
|
BehaviorNode,
|
|
5233
6271
|
BinaryExpression,
|
|
5234
6272
|
BlockNode,
|
|
6273
|
+
BreakNode,
|
|
5235
6274
|
CallExpression,
|
|
6275
|
+
ContinueNode,
|
|
5236
6276
|
DeclarationNode,
|
|
5237
6277
|
DirectiveExpression,
|
|
5238
6278
|
Engine,
|
|
6279
|
+
ForEachNode,
|
|
5239
6280
|
ForNode,
|
|
5240
6281
|
FunctionDeclarationNode,
|
|
5241
6282
|
FunctionExpression,
|
|
@@ -5255,8 +6296,6 @@ if (typeof document !== "undefined") {
|
|
|
5255
6296
|
ReturnNode,
|
|
5256
6297
|
SelectorNode,
|
|
5257
6298
|
SpreadElement,
|
|
5258
|
-
StateBlockNode,
|
|
5259
|
-
StateEntryNode,
|
|
5260
6299
|
TemplateExpression,
|
|
5261
6300
|
TernaryExpression,
|
|
5262
6301
|
TokenType,
|