vsn 1.0.0 → 1.0.1
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 +180 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -3
- package/dist/index.d.ts +23 -3
- package/dist/index.js +180 -10
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +4 -4
- package/dist/index.min.js.map +1 -1
- package/package.json +15 -1
package/dist/index.d.cts
CHANGED
|
@@ -129,10 +129,21 @@ declare class ProgramNode extends BaseNode {
|
|
|
129
129
|
uses: UseNode[];
|
|
130
130
|
constructor(behaviors: BehaviorNode[], uses?: UseNode[]);
|
|
131
131
|
}
|
|
132
|
+
interface UseFlags {
|
|
133
|
+
wait?: boolean;
|
|
134
|
+
}
|
|
135
|
+
interface UseFlagArgs {
|
|
136
|
+
wait?: {
|
|
137
|
+
timeoutMs?: number;
|
|
138
|
+
intervalMs?: number;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
132
141
|
declare class UseNode extends BaseNode {
|
|
133
142
|
name: string;
|
|
134
143
|
alias: string;
|
|
135
|
-
|
|
144
|
+
flags: UseFlags;
|
|
145
|
+
flagArgs: UseFlagArgs;
|
|
146
|
+
constructor(name: string, alias: string, flags?: UseFlags, flagArgs?: UseFlagArgs);
|
|
136
147
|
}
|
|
137
148
|
declare class BlockNode extends BaseNode {
|
|
138
149
|
statements: CFSNode[];
|
|
@@ -168,8 +179,10 @@ declare class OnBlockNode extends BaseNode {
|
|
|
168
179
|
declare class AssignmentNode extends BaseNode {
|
|
169
180
|
target: AssignmentTarget;
|
|
170
181
|
value: ExpressionNode;
|
|
171
|
-
|
|
182
|
+
operator: "=" | "+=" | "-=" | "*=" | "/=";
|
|
183
|
+
constructor(target: AssignmentTarget, value: ExpressionNode, operator?: "=" | "+=" | "-=" | "*=" | "/=");
|
|
172
184
|
evaluate(context: ExecutionContext): Promise<any>;
|
|
185
|
+
private applyCompoundAssignment;
|
|
173
186
|
private assignTarget;
|
|
174
187
|
}
|
|
175
188
|
declare class ReturnNode extends BaseNode {
|
|
@@ -394,6 +407,7 @@ declare class Parser {
|
|
|
394
407
|
private parseBehavior;
|
|
395
408
|
private parseSelector;
|
|
396
409
|
private parseUseStatement;
|
|
410
|
+
private parseUseFlags;
|
|
397
411
|
private wrapErrors;
|
|
398
412
|
private formatError;
|
|
399
413
|
private getLineSnippet;
|
|
@@ -435,6 +449,7 @@ declare class Parser {
|
|
|
435
449
|
private parseCustomFlagArg;
|
|
436
450
|
private isDeclarationStart;
|
|
437
451
|
private isAssignmentStart;
|
|
452
|
+
private isAssignmentOperatorStart;
|
|
438
453
|
private isCallStart;
|
|
439
454
|
private isExpressionStatementStart;
|
|
440
455
|
private isFunctionDeclarationStart;
|
|
@@ -447,6 +462,7 @@ declare class Parser {
|
|
|
447
462
|
private parseForBlock;
|
|
448
463
|
private parseForClause;
|
|
449
464
|
private parseAssignmentExpression;
|
|
465
|
+
private parseAssignmentOperator;
|
|
450
466
|
private parseTryBlock;
|
|
451
467
|
private parseConstructBlock;
|
|
452
468
|
private parseDestructBlock;
|
|
@@ -532,6 +548,7 @@ declare class Engine {
|
|
|
532
548
|
private ignoredAdded;
|
|
533
549
|
private diagnostics;
|
|
534
550
|
private logger;
|
|
551
|
+
private pendingUses;
|
|
535
552
|
constructor(options?: EngineOptions);
|
|
536
553
|
mount(root: HTMLElement): Promise<void>;
|
|
537
554
|
unmount(element: Element): void;
|
|
@@ -545,6 +562,8 @@ declare class Engine {
|
|
|
545
562
|
};
|
|
546
563
|
registerAttributeHandler(handler: AttributeHandler): void;
|
|
547
564
|
private resolveGlobalPath;
|
|
565
|
+
private waitForUses;
|
|
566
|
+
private waitForUseGlobal;
|
|
548
567
|
getScope(element: Element, parentScope?: Scope): Scope;
|
|
549
568
|
evaluate(element: Element): void;
|
|
550
569
|
private attachObserver;
|
|
@@ -580,6 +599,7 @@ declare class Engine {
|
|
|
580
599
|
private describeElement;
|
|
581
600
|
private logDiagnostic;
|
|
582
601
|
private emitError;
|
|
602
|
+
private emitUseError;
|
|
583
603
|
private attachOnHandler;
|
|
584
604
|
private attachBehaviorOnHandler;
|
|
585
605
|
private attachGetHandler;
|
|
@@ -627,4 +647,4 @@ declare const VERSION = "0.1.0";
|
|
|
627
647
|
declare function parseCFS(source: string): ProgramNode;
|
|
628
648
|
declare function autoMount(root?: HTMLElement | Document): Engine | null;
|
|
629
649
|
|
|
630
|
-
export { type ArrayElement, ArrayExpression, ArrayPattern, type ArrayPatternElement, AssignmentNode, type AssignmentTarget, AwaitExpression, BaseNode, BehaviorNode, BinaryExpression, BlockNode, type CFSNode, CallExpression, type DeclarationFlagArgs, type DeclarationFlags, DeclarationNode, type DeclarationTarget, DirectiveExpression, Engine, type ExecutionContext, type ExpressionNode, ForNode, FunctionDeclarationNode, FunctionExpression, type FunctionParam, IdentifierExpression, IfNode, IndexExpression, Lexer, LiteralExpression, MemberExpression, type ObjectEntry, ObjectExpression, ObjectPattern, type ObjectPatternEntry, OnBlockNode, Parser, type PatternNode, ProgramNode, QueryExpression, RestElement, ReturnNode, SelectorNode, SpreadElement, StateBlockNode, StateEntryNode, TemplateExpression, TernaryExpression, TokenType, TryNode, UnaryExpression, UseNode, VERSION, WhileNode, autoMount, parseCFS };
|
|
650
|
+
export { type ArrayElement, ArrayExpression, ArrayPattern, type ArrayPatternElement, AssignmentNode, type AssignmentTarget, AwaitExpression, BaseNode, BehaviorNode, BinaryExpression, BlockNode, type CFSNode, CallExpression, type DeclarationFlagArgs, type DeclarationFlags, DeclarationNode, type DeclarationTarget, DirectiveExpression, Engine, type ExecutionContext, type ExpressionNode, ForNode, FunctionDeclarationNode, FunctionExpression, type FunctionParam, IdentifierExpression, IfNode, IndexExpression, Lexer, LiteralExpression, MemberExpression, type ObjectEntry, ObjectExpression, ObjectPattern, type ObjectPatternEntry, OnBlockNode, Parser, type PatternNode, ProgramNode, QueryExpression, RestElement, ReturnNode, SelectorNode, SpreadElement, StateBlockNode, StateEntryNode, TemplateExpression, TernaryExpression, TokenType, TryNode, UnaryExpression, type UseFlagArgs, type UseFlags, UseNode, VERSION, WhileNode, autoMount, parseCFS };
|
package/dist/index.d.ts
CHANGED
|
@@ -129,10 +129,21 @@ declare class ProgramNode extends BaseNode {
|
|
|
129
129
|
uses: UseNode[];
|
|
130
130
|
constructor(behaviors: BehaviorNode[], uses?: UseNode[]);
|
|
131
131
|
}
|
|
132
|
+
interface UseFlags {
|
|
133
|
+
wait?: boolean;
|
|
134
|
+
}
|
|
135
|
+
interface UseFlagArgs {
|
|
136
|
+
wait?: {
|
|
137
|
+
timeoutMs?: number;
|
|
138
|
+
intervalMs?: number;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
132
141
|
declare class UseNode extends BaseNode {
|
|
133
142
|
name: string;
|
|
134
143
|
alias: string;
|
|
135
|
-
|
|
144
|
+
flags: UseFlags;
|
|
145
|
+
flagArgs: UseFlagArgs;
|
|
146
|
+
constructor(name: string, alias: string, flags?: UseFlags, flagArgs?: UseFlagArgs);
|
|
136
147
|
}
|
|
137
148
|
declare class BlockNode extends BaseNode {
|
|
138
149
|
statements: CFSNode[];
|
|
@@ -168,8 +179,10 @@ declare class OnBlockNode extends BaseNode {
|
|
|
168
179
|
declare class AssignmentNode extends BaseNode {
|
|
169
180
|
target: AssignmentTarget;
|
|
170
181
|
value: ExpressionNode;
|
|
171
|
-
|
|
182
|
+
operator: "=" | "+=" | "-=" | "*=" | "/=";
|
|
183
|
+
constructor(target: AssignmentTarget, value: ExpressionNode, operator?: "=" | "+=" | "-=" | "*=" | "/=");
|
|
172
184
|
evaluate(context: ExecutionContext): Promise<any>;
|
|
185
|
+
private applyCompoundAssignment;
|
|
173
186
|
private assignTarget;
|
|
174
187
|
}
|
|
175
188
|
declare class ReturnNode extends BaseNode {
|
|
@@ -394,6 +407,7 @@ declare class Parser {
|
|
|
394
407
|
private parseBehavior;
|
|
395
408
|
private parseSelector;
|
|
396
409
|
private parseUseStatement;
|
|
410
|
+
private parseUseFlags;
|
|
397
411
|
private wrapErrors;
|
|
398
412
|
private formatError;
|
|
399
413
|
private getLineSnippet;
|
|
@@ -435,6 +449,7 @@ declare class Parser {
|
|
|
435
449
|
private parseCustomFlagArg;
|
|
436
450
|
private isDeclarationStart;
|
|
437
451
|
private isAssignmentStart;
|
|
452
|
+
private isAssignmentOperatorStart;
|
|
438
453
|
private isCallStart;
|
|
439
454
|
private isExpressionStatementStart;
|
|
440
455
|
private isFunctionDeclarationStart;
|
|
@@ -447,6 +462,7 @@ declare class Parser {
|
|
|
447
462
|
private parseForBlock;
|
|
448
463
|
private parseForClause;
|
|
449
464
|
private parseAssignmentExpression;
|
|
465
|
+
private parseAssignmentOperator;
|
|
450
466
|
private parseTryBlock;
|
|
451
467
|
private parseConstructBlock;
|
|
452
468
|
private parseDestructBlock;
|
|
@@ -532,6 +548,7 @@ declare class Engine {
|
|
|
532
548
|
private ignoredAdded;
|
|
533
549
|
private diagnostics;
|
|
534
550
|
private logger;
|
|
551
|
+
private pendingUses;
|
|
535
552
|
constructor(options?: EngineOptions);
|
|
536
553
|
mount(root: HTMLElement): Promise<void>;
|
|
537
554
|
unmount(element: Element): void;
|
|
@@ -545,6 +562,8 @@ declare class Engine {
|
|
|
545
562
|
};
|
|
546
563
|
registerAttributeHandler(handler: AttributeHandler): void;
|
|
547
564
|
private resolveGlobalPath;
|
|
565
|
+
private waitForUses;
|
|
566
|
+
private waitForUseGlobal;
|
|
548
567
|
getScope(element: Element, parentScope?: Scope): Scope;
|
|
549
568
|
evaluate(element: Element): void;
|
|
550
569
|
private attachObserver;
|
|
@@ -580,6 +599,7 @@ declare class Engine {
|
|
|
580
599
|
private describeElement;
|
|
581
600
|
private logDiagnostic;
|
|
582
601
|
private emitError;
|
|
602
|
+
private emitUseError;
|
|
583
603
|
private attachOnHandler;
|
|
584
604
|
private attachBehaviorOnHandler;
|
|
585
605
|
private attachGetHandler;
|
|
@@ -627,4 +647,4 @@ declare const VERSION = "0.1.0";
|
|
|
627
647
|
declare function parseCFS(source: string): ProgramNode;
|
|
628
648
|
declare function autoMount(root?: HTMLElement | Document): Engine | null;
|
|
629
649
|
|
|
630
|
-
export { type ArrayElement, ArrayExpression, ArrayPattern, type ArrayPatternElement, AssignmentNode, type AssignmentTarget, AwaitExpression, BaseNode, BehaviorNode, BinaryExpression, BlockNode, type CFSNode, CallExpression, type DeclarationFlagArgs, type DeclarationFlags, DeclarationNode, type DeclarationTarget, DirectiveExpression, Engine, type ExecutionContext, type ExpressionNode, ForNode, FunctionDeclarationNode, FunctionExpression, type FunctionParam, IdentifierExpression, IfNode, IndexExpression, Lexer, LiteralExpression, MemberExpression, type ObjectEntry, ObjectExpression, ObjectPattern, type ObjectPatternEntry, OnBlockNode, Parser, type PatternNode, ProgramNode, QueryExpression, RestElement, ReturnNode, SelectorNode, SpreadElement, StateBlockNode, StateEntryNode, TemplateExpression, TernaryExpression, TokenType, TryNode, UnaryExpression, UseNode, VERSION, WhileNode, autoMount, parseCFS };
|
|
650
|
+
export { type ArrayElement, ArrayExpression, ArrayPattern, type ArrayPatternElement, AssignmentNode, type AssignmentTarget, AwaitExpression, BaseNode, BehaviorNode, BinaryExpression, BlockNode, type CFSNode, CallExpression, type DeclarationFlagArgs, type DeclarationFlags, DeclarationNode, type DeclarationTarget, DirectiveExpression, Engine, type ExecutionContext, type ExpressionNode, ForNode, FunctionDeclarationNode, FunctionExpression, type FunctionParam, IdentifierExpression, IfNode, IndexExpression, Lexer, LiteralExpression, MemberExpression, type ObjectEntry, ObjectExpression, ObjectPattern, type ObjectPatternEntry, OnBlockNode, Parser, type PatternNode, ProgramNode, QueryExpression, RestElement, ReturnNode, SelectorNode, SpreadElement, StateBlockNode, StateEntryNode, TemplateExpression, TernaryExpression, TokenType, TryNode, UnaryExpression, type UseFlagArgs, type UseFlags, UseNode, VERSION, WhileNode, autoMount, parseCFS };
|
package/dist/index.js
CHANGED
|
@@ -445,10 +445,12 @@ var ProgramNode = class extends BaseNode {
|
|
|
445
445
|
}
|
|
446
446
|
};
|
|
447
447
|
var UseNode = class extends BaseNode {
|
|
448
|
-
constructor(name, alias) {
|
|
448
|
+
constructor(name, alias, flags = {}, flagArgs = {}) {
|
|
449
449
|
super("Use");
|
|
450
450
|
this.name = name;
|
|
451
451
|
this.alias = alias;
|
|
452
|
+
this.flags = flags;
|
|
453
|
+
this.flagArgs = flagArgs;
|
|
452
454
|
}
|
|
453
455
|
};
|
|
454
456
|
var BlockNode = class extends BaseNode {
|
|
@@ -504,16 +506,20 @@ var OnBlockNode = class extends BaseNode {
|
|
|
504
506
|
}
|
|
505
507
|
};
|
|
506
508
|
var AssignmentNode = class extends BaseNode {
|
|
507
|
-
constructor(target, value) {
|
|
509
|
+
constructor(target, value, operator = "=") {
|
|
508
510
|
super("Assignment");
|
|
509
511
|
this.target = target;
|
|
510
512
|
this.value = value;
|
|
513
|
+
this.operator = operator;
|
|
511
514
|
}
|
|
512
515
|
async evaluate(context) {
|
|
513
516
|
if (!context.scope || !context.scope.setPath) {
|
|
514
517
|
return void 0;
|
|
515
518
|
}
|
|
516
519
|
const value = await this.value.evaluate(context);
|
|
520
|
+
if (this.operator !== "=") {
|
|
521
|
+
return this.applyCompoundAssignment(context, value);
|
|
522
|
+
}
|
|
517
523
|
if (this.target instanceof IdentifierExpression && this.target.name.startsWith("root.") && context.rootScope) {
|
|
518
524
|
const path = this.target.name.slice("root.".length);
|
|
519
525
|
context.rootScope.setPath?.(`self.${path}`, value);
|
|
@@ -522,6 +528,31 @@ var AssignmentNode = class extends BaseNode {
|
|
|
522
528
|
this.assignTarget(context, this.target, value);
|
|
523
529
|
return value;
|
|
524
530
|
}
|
|
531
|
+
applyCompoundAssignment(context, value) {
|
|
532
|
+
if (!context.scope || !context.scope.setPath) {
|
|
533
|
+
return void 0;
|
|
534
|
+
}
|
|
535
|
+
if (!(this.target instanceof IdentifierExpression)) {
|
|
536
|
+
throw new Error("Compound assignment requires a simple identifier");
|
|
537
|
+
}
|
|
538
|
+
const isRoot = this.target.name.startsWith("root.");
|
|
539
|
+
const scope = isRoot && context.rootScope ? context.rootScope : context.scope;
|
|
540
|
+
const rawPath = isRoot ? this.target.name.slice("root.".length) : this.target.name;
|
|
541
|
+
const path = isRoot ? `self.${rawPath}` : rawPath;
|
|
542
|
+
const current = scope?.getPath ? scope.getPath(path) : void 0;
|
|
543
|
+
let result;
|
|
544
|
+
if (this.operator === "+=") {
|
|
545
|
+
result = current + value;
|
|
546
|
+
} else if (this.operator === "-=") {
|
|
547
|
+
result = current - value;
|
|
548
|
+
} else if (this.operator === "*=") {
|
|
549
|
+
result = current * value;
|
|
550
|
+
} else {
|
|
551
|
+
result = current / value;
|
|
552
|
+
}
|
|
553
|
+
scope?.setPath?.(path, result);
|
|
554
|
+
return result;
|
|
555
|
+
}
|
|
525
556
|
assignTarget(context, target, value) {
|
|
526
557
|
if (!context.scope || !context.scope.setPath) {
|
|
527
558
|
return;
|
|
@@ -1392,11 +1423,46 @@ var Parser = class _Parser {
|
|
|
1392
1423
|
this.stream.skipWhitespace();
|
|
1393
1424
|
alias = this.stream.expect("Identifier" /* Identifier */).value;
|
|
1394
1425
|
}
|
|
1426
|
+
const { flags, flagArgs } = this.parseUseFlags();
|
|
1395
1427
|
this.stream.skipWhitespace();
|
|
1396
1428
|
this.stream.expect("Semicolon" /* Semicolon */);
|
|
1397
|
-
return new UseNode(name, alias);
|
|
1429
|
+
return new UseNode(name, alias, flags, flagArgs);
|
|
1398
1430
|
});
|
|
1399
1431
|
}
|
|
1432
|
+
parseUseFlags() {
|
|
1433
|
+
const flags = {};
|
|
1434
|
+
const flagArgs = {};
|
|
1435
|
+
while (true) {
|
|
1436
|
+
this.stream.skipWhitespace();
|
|
1437
|
+
if (this.stream.peek()?.type !== "Bang" /* Bang */) {
|
|
1438
|
+
break;
|
|
1439
|
+
}
|
|
1440
|
+
this.stream.next();
|
|
1441
|
+
const name = this.stream.expect("Identifier" /* Identifier */).value;
|
|
1442
|
+
if (name !== "wait") {
|
|
1443
|
+
throw new Error(`Unknown flag ${name}`);
|
|
1444
|
+
}
|
|
1445
|
+
flags.wait = true;
|
|
1446
|
+
if (this.stream.peek()?.type === "LParen" /* LParen */) {
|
|
1447
|
+
this.stream.next();
|
|
1448
|
+
this.stream.skipWhitespace();
|
|
1449
|
+
const timeoutToken = this.stream.expect("Number" /* Number */);
|
|
1450
|
+
const timeoutMs = Number(timeoutToken.value);
|
|
1451
|
+
let intervalMs;
|
|
1452
|
+
this.stream.skipWhitespace();
|
|
1453
|
+
if (this.stream.peek()?.type === "Comma" /* Comma */) {
|
|
1454
|
+
this.stream.next();
|
|
1455
|
+
this.stream.skipWhitespace();
|
|
1456
|
+
const intervalToken = this.stream.expect("Number" /* Number */);
|
|
1457
|
+
intervalMs = Number(intervalToken.value);
|
|
1458
|
+
this.stream.skipWhitespace();
|
|
1459
|
+
}
|
|
1460
|
+
this.stream.expect("RParen" /* RParen */);
|
|
1461
|
+
flagArgs.wait = { timeoutMs, ...intervalMs !== void 0 ? { intervalMs } : {} };
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
return { flags, flagArgs };
|
|
1465
|
+
}
|
|
1400
1466
|
wrapErrors(fn) {
|
|
1401
1467
|
try {
|
|
1402
1468
|
return fn();
|
|
@@ -1627,11 +1693,11 @@ ${caret}`;
|
|
|
1627
1693
|
parseAssignment() {
|
|
1628
1694
|
const target = this.parseAssignmentTarget();
|
|
1629
1695
|
this.stream.skipWhitespace();
|
|
1630
|
-
this.
|
|
1696
|
+
const operator = this.parseAssignmentOperator();
|
|
1631
1697
|
this.stream.skipWhitespace();
|
|
1632
1698
|
const value = this.parseExpression();
|
|
1633
1699
|
this.consumeStatementTerminator();
|
|
1634
|
-
return new AssignmentNode(target, value);
|
|
1700
|
+
return new AssignmentNode(target, value, operator);
|
|
1635
1701
|
}
|
|
1636
1702
|
parseExpression() {
|
|
1637
1703
|
return this.parsePipeExpression();
|
|
@@ -2492,12 +2558,12 @@ ${caret}`;
|
|
|
2492
2558
|
while (this.stream.peekNonWhitespace(index)?.type === "Dot" /* Dot */ && this.stream.peekNonWhitespace(index + 1)?.type === "Identifier" /* Identifier */) {
|
|
2493
2559
|
index += 2;
|
|
2494
2560
|
}
|
|
2495
|
-
return this.
|
|
2561
|
+
return this.isAssignmentOperatorStart(index);
|
|
2496
2562
|
}
|
|
2497
2563
|
if (first.type === "At" /* At */ || first.type === "Dollar" /* Dollar */) {
|
|
2498
2564
|
const second = this.stream.peekNonWhitespace(1);
|
|
2499
2565
|
const third = this.stream.peekNonWhitespace(2);
|
|
2500
|
-
return second?.type === "Identifier" /* Identifier */ &&
|
|
2566
|
+
return second?.type === "Identifier" /* Identifier */ && this.isAssignmentOperatorStart(2);
|
|
2501
2567
|
}
|
|
2502
2568
|
if (first.type === "LBrace" /* LBrace */ || first.type === "LBracket" /* LBracket */) {
|
|
2503
2569
|
const stack = [];
|
|
@@ -2512,7 +2578,7 @@ ${caret}`;
|
|
|
2512
2578
|
} else if (token.type === "RBrace" /* RBrace */ || token.type === "RBracket" /* RBracket */) {
|
|
2513
2579
|
stack.pop();
|
|
2514
2580
|
if (stack.length === 0) {
|
|
2515
|
-
return this.
|
|
2581
|
+
return this.isAssignmentOperatorStart(index + 1);
|
|
2516
2582
|
}
|
|
2517
2583
|
}
|
|
2518
2584
|
index += 1;
|
|
@@ -2520,6 +2586,20 @@ ${caret}`;
|
|
|
2520
2586
|
}
|
|
2521
2587
|
return false;
|
|
2522
2588
|
}
|
|
2589
|
+
isAssignmentOperatorStart(index) {
|
|
2590
|
+
const token = this.stream.peekNonWhitespace(index);
|
|
2591
|
+
if (!token) {
|
|
2592
|
+
return false;
|
|
2593
|
+
}
|
|
2594
|
+
if (token.type === "Equals" /* Equals */) {
|
|
2595
|
+
return true;
|
|
2596
|
+
}
|
|
2597
|
+
if (token.type === "Plus" /* Plus */ || token.type === "Minus" /* Minus */ || token.type === "Star" /* Star */ || token.type === "Slash" /* Slash */) {
|
|
2598
|
+
const next = this.stream.peekNonWhitespace(index + 1);
|
|
2599
|
+
return next?.type === "Equals" /* Equals */;
|
|
2600
|
+
}
|
|
2601
|
+
return false;
|
|
2602
|
+
}
|
|
2523
2603
|
isCallStart() {
|
|
2524
2604
|
const first = this.stream.peekNonWhitespace(0);
|
|
2525
2605
|
if (!first || first.type !== "Identifier" /* Identifier */) {
|
|
@@ -2744,10 +2824,35 @@ ${caret}`;
|
|
|
2744
2824
|
parseAssignmentExpression() {
|
|
2745
2825
|
const target = this.parseAssignmentTarget();
|
|
2746
2826
|
this.stream.skipWhitespace();
|
|
2747
|
-
this.
|
|
2827
|
+
const operator = this.parseAssignmentOperator();
|
|
2748
2828
|
this.stream.skipWhitespace();
|
|
2749
2829
|
const value = this.parseExpression();
|
|
2750
|
-
return new AssignmentNode(target, value);
|
|
2830
|
+
return new AssignmentNode(target, value, operator);
|
|
2831
|
+
}
|
|
2832
|
+
parseAssignmentOperator() {
|
|
2833
|
+
const next = this.stream.peek();
|
|
2834
|
+
if (!next) {
|
|
2835
|
+
throw new Error("Expected assignment operator");
|
|
2836
|
+
}
|
|
2837
|
+
if (next.type === "Equals" /* Equals */) {
|
|
2838
|
+
this.stream.next();
|
|
2839
|
+
return "=";
|
|
2840
|
+
}
|
|
2841
|
+
if (next.type === "Plus" /* Plus */ || next.type === "Minus" /* Minus */ || next.type === "Star" /* Star */ || next.type === "Slash" /* Slash */) {
|
|
2842
|
+
const op = this.stream.next();
|
|
2843
|
+
this.stream.expect("Equals" /* Equals */);
|
|
2844
|
+
if (op.type === "Plus" /* Plus */) {
|
|
2845
|
+
return "+=";
|
|
2846
|
+
}
|
|
2847
|
+
if (op.type === "Minus" /* Minus */) {
|
|
2848
|
+
return "-=";
|
|
2849
|
+
}
|
|
2850
|
+
if (op.type === "Star" /* Star */) {
|
|
2851
|
+
return "*=";
|
|
2852
|
+
}
|
|
2853
|
+
return "/=";
|
|
2854
|
+
}
|
|
2855
|
+
throw new Error("Expected assignment operator");
|
|
2751
2856
|
}
|
|
2752
2857
|
parseTryBlock() {
|
|
2753
2858
|
this.stream.expect("Try" /* Try */);
|
|
@@ -3250,6 +3355,7 @@ var Engine = class _Engine {
|
|
|
3250
3355
|
ignoredAdded = /* @__PURE__ */ new WeakMap();
|
|
3251
3356
|
diagnostics;
|
|
3252
3357
|
logger;
|
|
3358
|
+
pendingUses = [];
|
|
3253
3359
|
constructor(options = {}) {
|
|
3254
3360
|
this.diagnostics = options.diagnostics ?? false;
|
|
3255
3361
|
this.logger = options.logger ?? console;
|
|
@@ -3319,6 +3425,10 @@ var Engine = class _Engine {
|
|
|
3319
3425
|
registerBehaviors(source) {
|
|
3320
3426
|
const program = new Parser(source, { customFlags: new Set(this.flagHandlers.keys()) }).parseProgram();
|
|
3321
3427
|
for (const use of program.uses) {
|
|
3428
|
+
if (use.flags?.wait) {
|
|
3429
|
+
this.pendingUses.push(this.waitForUseGlobal(use));
|
|
3430
|
+
continue;
|
|
3431
|
+
}
|
|
3322
3432
|
const value = this.resolveGlobalPath(use.name);
|
|
3323
3433
|
if (value === void 0) {
|
|
3324
3434
|
console.warn(`vsn: global '${use.name}' not found`);
|
|
@@ -3368,6 +3478,52 @@ var Engine = class _Engine {
|
|
|
3368
3478
|
}
|
|
3369
3479
|
return value;
|
|
3370
3480
|
}
|
|
3481
|
+
async waitForUses() {
|
|
3482
|
+
while (this.pendingUses.length > 0) {
|
|
3483
|
+
const pending = this.pendingUses;
|
|
3484
|
+
this.pendingUses = [];
|
|
3485
|
+
await Promise.all(pending);
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
waitForUseGlobal(use) {
|
|
3489
|
+
const config = use.flagArgs?.wait ?? {};
|
|
3490
|
+
const timeoutMs = config.timeoutMs ?? 1e4;
|
|
3491
|
+
const initialDelayMs = config.intervalMs ?? 100;
|
|
3492
|
+
const maxDelayMs = 1e3;
|
|
3493
|
+
const existing = this.resolveGlobalPath(use.name);
|
|
3494
|
+
if (existing !== void 0) {
|
|
3495
|
+
this.registerGlobal(use.alias, existing);
|
|
3496
|
+
return Promise.resolve();
|
|
3497
|
+
}
|
|
3498
|
+
if (timeoutMs <= 0) {
|
|
3499
|
+
this.emitUseError(use.name, new Error(`vsn: global '${use.name}' not found`));
|
|
3500
|
+
return Promise.resolve();
|
|
3501
|
+
}
|
|
3502
|
+
return new Promise((resolve) => {
|
|
3503
|
+
let elapsedMs = 0;
|
|
3504
|
+
let delayMs = initialDelayMs;
|
|
3505
|
+
const check = () => {
|
|
3506
|
+
const value = this.resolveGlobalPath(use.name);
|
|
3507
|
+
if (value !== void 0) {
|
|
3508
|
+
this.registerGlobal(use.alias, value);
|
|
3509
|
+
resolve();
|
|
3510
|
+
return;
|
|
3511
|
+
}
|
|
3512
|
+
if (elapsedMs >= timeoutMs) {
|
|
3513
|
+
this.emitUseError(use.name, new Error(`vsn: global '${use.name}' not found`));
|
|
3514
|
+
resolve();
|
|
3515
|
+
return;
|
|
3516
|
+
}
|
|
3517
|
+
const scheduledDelay = Math.min(delayMs, timeoutMs - elapsedMs);
|
|
3518
|
+
setTimeout(() => {
|
|
3519
|
+
elapsedMs += scheduledDelay;
|
|
3520
|
+
delayMs = Math.min(delayMs * 2, maxDelayMs);
|
|
3521
|
+
check();
|
|
3522
|
+
}, scheduledDelay);
|
|
3523
|
+
};
|
|
3524
|
+
check();
|
|
3525
|
+
});
|
|
3526
|
+
}
|
|
3371
3527
|
getScope(element, parentScope) {
|
|
3372
3528
|
const existing = this.scopes.get(element);
|
|
3373
3529
|
if (existing) {
|
|
@@ -3491,6 +3647,7 @@ var Engine = class _Engine {
|
|
|
3491
3647
|
}
|
|
3492
3648
|
}
|
|
3493
3649
|
async applyBehaviors(root) {
|
|
3650
|
+
await this.waitForUses();
|
|
3494
3651
|
if (this.behaviorRegistry.length === 0) {
|
|
3495
3652
|
return;
|
|
3496
3653
|
}
|
|
@@ -3898,6 +4055,19 @@ var Engine = class _Engine {
|
|
|
3898
4055
|
})
|
|
3899
4056
|
);
|
|
3900
4057
|
}
|
|
4058
|
+
emitUseError(name, error) {
|
|
4059
|
+
const selector = `use:${name}`;
|
|
4060
|
+
this.logger.warn?.("vsn:error", { error, selector });
|
|
4061
|
+
const target = globalThis.document;
|
|
4062
|
+
if (target && typeof target.dispatchEvent === "function") {
|
|
4063
|
+
target.dispatchEvent(
|
|
4064
|
+
new CustomEvent("vsn:error", {
|
|
4065
|
+
detail: { error, selector },
|
|
4066
|
+
bubbles: true
|
|
4067
|
+
})
|
|
4068
|
+
);
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
3901
4071
|
attachOnHandler(element, config) {
|
|
3902
4072
|
const options = this.getListenerOptions(config.modifiers);
|
|
3903
4073
|
const listenerTarget = config.modifiers?.includes("outside") ? element.ownerDocument : element;
|