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