vsn 1.0.0 → 1.0.2
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 +272 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -4
- package/dist/index.d.ts +27 -4
- package/dist/index.js +272 -12
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +5 -5
- 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,13 @@ 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;
|
|
186
|
+
private resolveAssignmentTarget;
|
|
187
|
+
private resolveIndexPath;
|
|
188
|
+
private resolveTargetPath;
|
|
173
189
|
private assignTarget;
|
|
174
190
|
}
|
|
175
191
|
declare class ReturnNode extends BaseNode {
|
|
@@ -241,7 +257,7 @@ declare class DeclarationNode extends BaseNode {
|
|
|
241
257
|
}
|
|
242
258
|
type ExpressionNode = IdentifierExpression | LiteralExpression | TemplateExpression | UnaryExpression | BinaryExpression | MemberExpression | CallExpression | ArrayExpression | ObjectExpression | IndexExpression | FunctionExpression | AwaitExpression | TernaryExpression | DirectiveExpression | QueryExpression;
|
|
243
259
|
type DeclarationTarget = IdentifierExpression | DirectiveExpression;
|
|
244
|
-
type AssignmentTarget = IdentifierExpression | DirectiveExpression | ArrayPattern | ObjectPattern;
|
|
260
|
+
type AssignmentTarget = IdentifierExpression | MemberExpression | IndexExpression | DirectiveExpression | ArrayPattern | ObjectPattern;
|
|
245
261
|
type FunctionParam = {
|
|
246
262
|
name: string;
|
|
247
263
|
defaultValue?: ExpressionNode;
|
|
@@ -394,6 +410,7 @@ declare class Parser {
|
|
|
394
410
|
private parseBehavior;
|
|
395
411
|
private parseSelector;
|
|
396
412
|
private parseUseStatement;
|
|
413
|
+
private parseUseFlags;
|
|
397
414
|
private wrapErrors;
|
|
398
415
|
private formatError;
|
|
399
416
|
private getLineSnippet;
|
|
@@ -435,6 +452,7 @@ declare class Parser {
|
|
|
435
452
|
private parseCustomFlagArg;
|
|
436
453
|
private isDeclarationStart;
|
|
437
454
|
private isAssignmentStart;
|
|
455
|
+
private isAssignmentOperatorStart;
|
|
438
456
|
private isCallStart;
|
|
439
457
|
private isExpressionStatementStart;
|
|
440
458
|
private isFunctionDeclarationStart;
|
|
@@ -447,6 +465,7 @@ declare class Parser {
|
|
|
447
465
|
private parseForBlock;
|
|
448
466
|
private parseForClause;
|
|
449
467
|
private parseAssignmentExpression;
|
|
468
|
+
private parseAssignmentOperator;
|
|
450
469
|
private parseTryBlock;
|
|
451
470
|
private parseConstructBlock;
|
|
452
471
|
private parseDestructBlock;
|
|
@@ -532,6 +551,7 @@ declare class Engine {
|
|
|
532
551
|
private ignoredAdded;
|
|
533
552
|
private diagnostics;
|
|
534
553
|
private logger;
|
|
554
|
+
private pendingUses;
|
|
535
555
|
constructor(options?: EngineOptions);
|
|
536
556
|
mount(root: HTMLElement): Promise<void>;
|
|
537
557
|
unmount(element: Element): void;
|
|
@@ -545,6 +565,8 @@ declare class Engine {
|
|
|
545
565
|
};
|
|
546
566
|
registerAttributeHandler(handler: AttributeHandler): void;
|
|
547
567
|
private resolveGlobalPath;
|
|
568
|
+
private waitForUses;
|
|
569
|
+
private waitForUseGlobal;
|
|
548
570
|
getScope(element: Element, parentScope?: Scope): Scope;
|
|
549
571
|
evaluate(element: Element): void;
|
|
550
572
|
private attachObserver;
|
|
@@ -580,6 +602,7 @@ declare class Engine {
|
|
|
580
602
|
private describeElement;
|
|
581
603
|
private logDiagnostic;
|
|
582
604
|
private emitError;
|
|
605
|
+
private emitUseError;
|
|
583
606
|
private attachOnHandler;
|
|
584
607
|
private attachBehaviorOnHandler;
|
|
585
608
|
private attachGetHandler;
|
|
@@ -627,4 +650,4 @@ declare const VERSION = "0.1.0";
|
|
|
627
650
|
declare function parseCFS(source: string): ProgramNode;
|
|
628
651
|
declare function autoMount(root?: HTMLElement | Document): Engine | null;
|
|
629
652
|
|
|
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 };
|
|
653
|
+
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,13 @@ 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;
|
|
186
|
+
private resolveAssignmentTarget;
|
|
187
|
+
private resolveIndexPath;
|
|
188
|
+
private resolveTargetPath;
|
|
173
189
|
private assignTarget;
|
|
174
190
|
}
|
|
175
191
|
declare class ReturnNode extends BaseNode {
|
|
@@ -241,7 +257,7 @@ declare class DeclarationNode extends BaseNode {
|
|
|
241
257
|
}
|
|
242
258
|
type ExpressionNode = IdentifierExpression | LiteralExpression | TemplateExpression | UnaryExpression | BinaryExpression | MemberExpression | CallExpression | ArrayExpression | ObjectExpression | IndexExpression | FunctionExpression | AwaitExpression | TernaryExpression | DirectiveExpression | QueryExpression;
|
|
243
259
|
type DeclarationTarget = IdentifierExpression | DirectiveExpression;
|
|
244
|
-
type AssignmentTarget = IdentifierExpression | DirectiveExpression | ArrayPattern | ObjectPattern;
|
|
260
|
+
type AssignmentTarget = IdentifierExpression | MemberExpression | IndexExpression | DirectiveExpression | ArrayPattern | ObjectPattern;
|
|
245
261
|
type FunctionParam = {
|
|
246
262
|
name: string;
|
|
247
263
|
defaultValue?: ExpressionNode;
|
|
@@ -394,6 +410,7 @@ declare class Parser {
|
|
|
394
410
|
private parseBehavior;
|
|
395
411
|
private parseSelector;
|
|
396
412
|
private parseUseStatement;
|
|
413
|
+
private parseUseFlags;
|
|
397
414
|
private wrapErrors;
|
|
398
415
|
private formatError;
|
|
399
416
|
private getLineSnippet;
|
|
@@ -435,6 +452,7 @@ declare class Parser {
|
|
|
435
452
|
private parseCustomFlagArg;
|
|
436
453
|
private isDeclarationStart;
|
|
437
454
|
private isAssignmentStart;
|
|
455
|
+
private isAssignmentOperatorStart;
|
|
438
456
|
private isCallStart;
|
|
439
457
|
private isExpressionStatementStart;
|
|
440
458
|
private isFunctionDeclarationStart;
|
|
@@ -447,6 +465,7 @@ declare class Parser {
|
|
|
447
465
|
private parseForBlock;
|
|
448
466
|
private parseForClause;
|
|
449
467
|
private parseAssignmentExpression;
|
|
468
|
+
private parseAssignmentOperator;
|
|
450
469
|
private parseTryBlock;
|
|
451
470
|
private parseConstructBlock;
|
|
452
471
|
private parseDestructBlock;
|
|
@@ -532,6 +551,7 @@ declare class Engine {
|
|
|
532
551
|
private ignoredAdded;
|
|
533
552
|
private diagnostics;
|
|
534
553
|
private logger;
|
|
554
|
+
private pendingUses;
|
|
535
555
|
constructor(options?: EngineOptions);
|
|
536
556
|
mount(root: HTMLElement): Promise<void>;
|
|
537
557
|
unmount(element: Element): void;
|
|
@@ -545,6 +565,8 @@ declare class Engine {
|
|
|
545
565
|
};
|
|
546
566
|
registerAttributeHandler(handler: AttributeHandler): void;
|
|
547
567
|
private resolveGlobalPath;
|
|
568
|
+
private waitForUses;
|
|
569
|
+
private waitForUseGlobal;
|
|
548
570
|
getScope(element: Element, parentScope?: Scope): Scope;
|
|
549
571
|
evaluate(element: Element): void;
|
|
550
572
|
private attachObserver;
|
|
@@ -580,6 +602,7 @@ declare class Engine {
|
|
|
580
602
|
private describeElement;
|
|
581
603
|
private logDiagnostic;
|
|
582
604
|
private emitError;
|
|
605
|
+
private emitUseError;
|
|
583
606
|
private attachOnHandler;
|
|
584
607
|
private attachBehaviorOnHandler;
|
|
585
608
|
private attachGetHandler;
|
|
@@ -627,4 +650,4 @@ declare const VERSION = "0.1.0";
|
|
|
627
650
|
declare function parseCFS(source: string): ProgramNode;
|
|
628
651
|
declare function autoMount(root?: HTMLElement | Document): Engine | null;
|
|
629
652
|
|
|
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 };
|
|
653
|
+
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,24 +506,117 @@ 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 await 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
|
-
context.rootScope.setPath?.(
|
|
525
|
+
context.rootScope.setPath?.(path, value);
|
|
520
526
|
return value;
|
|
521
527
|
}
|
|
528
|
+
if (this.target instanceof MemberExpression || this.target instanceof IndexExpression) {
|
|
529
|
+
const resolved = await this.resolveAssignmentTarget(context);
|
|
530
|
+
if (resolved?.scope?.setPath) {
|
|
531
|
+
resolved.scope.setPath(resolved.path, value);
|
|
532
|
+
return value;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
522
535
|
this.assignTarget(context, this.target, value);
|
|
523
536
|
return value;
|
|
524
537
|
}
|
|
538
|
+
async applyCompoundAssignment(context, value) {
|
|
539
|
+
if (!context.scope || !context.scope.setPath) {
|
|
540
|
+
return void 0;
|
|
541
|
+
}
|
|
542
|
+
const resolved = await this.resolveAssignmentTarget(context);
|
|
543
|
+
if (!resolved) {
|
|
544
|
+
throw new Error("Compound assignment requires a simple identifier or member path");
|
|
545
|
+
}
|
|
546
|
+
const { scope, path } = resolved;
|
|
547
|
+
const current = scope?.getPath ? scope.getPath(path) : void 0;
|
|
548
|
+
let result;
|
|
549
|
+
if (this.operator === "+=") {
|
|
550
|
+
result = current + value;
|
|
551
|
+
} else if (this.operator === "-=") {
|
|
552
|
+
result = current - value;
|
|
553
|
+
} else if (this.operator === "*=") {
|
|
554
|
+
result = current * value;
|
|
555
|
+
} else {
|
|
556
|
+
result = current / value;
|
|
557
|
+
}
|
|
558
|
+
scope?.setPath?.(path, result);
|
|
559
|
+
return result;
|
|
560
|
+
}
|
|
561
|
+
async resolveAssignmentTarget(context) {
|
|
562
|
+
if (this.target instanceof IdentifierExpression) {
|
|
563
|
+
const isRoot = this.target.name.startsWith("root.");
|
|
564
|
+
const rawPath = isRoot ? this.target.name.slice("root.".length) : this.target.name;
|
|
565
|
+
if (isRoot) {
|
|
566
|
+
return { scope: context.scope, path: `root.${rawPath}` };
|
|
567
|
+
}
|
|
568
|
+
return { scope: context.scope, path: rawPath };
|
|
569
|
+
}
|
|
570
|
+
if (this.target instanceof MemberExpression) {
|
|
571
|
+
const resolvedPath = this.target.getIdentifierPath();
|
|
572
|
+
if (!resolvedPath) {
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
const path = resolvedPath.path;
|
|
576
|
+
const isRoot = path.startsWith("root.");
|
|
577
|
+
const rawPath = isRoot ? path.slice("root.".length) : path;
|
|
578
|
+
if (isRoot) {
|
|
579
|
+
return { scope: context.scope, path: `root.${rawPath}` };
|
|
580
|
+
}
|
|
581
|
+
return { scope: context.scope, path: rawPath };
|
|
582
|
+
}
|
|
583
|
+
if (this.target instanceof IndexExpression) {
|
|
584
|
+
const path = await this.resolveIndexPath(context, this.target);
|
|
585
|
+
if (!path) {
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
const isRoot = path.startsWith("root.");
|
|
589
|
+
const rawPath = isRoot ? path.slice("root.".length) : path;
|
|
590
|
+
if (isRoot) {
|
|
591
|
+
return { scope: context.scope, path: `root.${rawPath}` };
|
|
592
|
+
}
|
|
593
|
+
return { scope: context.scope, path: rawPath };
|
|
594
|
+
}
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
async resolveIndexPath(context, expr) {
|
|
598
|
+
const base = await this.resolveTargetPath(context, expr.target);
|
|
599
|
+
if (!base) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
const indexValue = await expr.index.evaluate(context);
|
|
603
|
+
if (indexValue == null) {
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
return `${base}.${indexValue}`;
|
|
607
|
+
}
|
|
608
|
+
async resolveTargetPath(context, target) {
|
|
609
|
+
if (target instanceof IdentifierExpression) {
|
|
610
|
+
return target.name;
|
|
611
|
+
}
|
|
612
|
+
if (target instanceof MemberExpression) {
|
|
613
|
+
return target.getIdentifierPath()?.path ?? null;
|
|
614
|
+
}
|
|
615
|
+
if (target instanceof IndexExpression) {
|
|
616
|
+
return this.resolveIndexPath(context, target);
|
|
617
|
+
}
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
525
620
|
assignTarget(context, target, value) {
|
|
526
621
|
if (!context.scope || !context.scope.setPath) {
|
|
527
622
|
return;
|
|
@@ -1392,11 +1487,46 @@ var Parser = class _Parser {
|
|
|
1392
1487
|
this.stream.skipWhitespace();
|
|
1393
1488
|
alias = this.stream.expect("Identifier" /* Identifier */).value;
|
|
1394
1489
|
}
|
|
1490
|
+
const { flags, flagArgs } = this.parseUseFlags();
|
|
1395
1491
|
this.stream.skipWhitespace();
|
|
1396
1492
|
this.stream.expect("Semicolon" /* Semicolon */);
|
|
1397
|
-
return new UseNode(name, alias);
|
|
1493
|
+
return new UseNode(name, alias, flags, flagArgs);
|
|
1398
1494
|
});
|
|
1399
1495
|
}
|
|
1496
|
+
parseUseFlags() {
|
|
1497
|
+
const flags = {};
|
|
1498
|
+
const flagArgs = {};
|
|
1499
|
+
while (true) {
|
|
1500
|
+
this.stream.skipWhitespace();
|
|
1501
|
+
if (this.stream.peek()?.type !== "Bang" /* Bang */) {
|
|
1502
|
+
break;
|
|
1503
|
+
}
|
|
1504
|
+
this.stream.next();
|
|
1505
|
+
const name = this.stream.expect("Identifier" /* Identifier */).value;
|
|
1506
|
+
if (name !== "wait") {
|
|
1507
|
+
throw new Error(`Unknown flag ${name}`);
|
|
1508
|
+
}
|
|
1509
|
+
flags.wait = true;
|
|
1510
|
+
if (this.stream.peek()?.type === "LParen" /* LParen */) {
|
|
1511
|
+
this.stream.next();
|
|
1512
|
+
this.stream.skipWhitespace();
|
|
1513
|
+
const timeoutToken = this.stream.expect("Number" /* Number */);
|
|
1514
|
+
const timeoutMs = Number(timeoutToken.value);
|
|
1515
|
+
let intervalMs;
|
|
1516
|
+
this.stream.skipWhitespace();
|
|
1517
|
+
if (this.stream.peek()?.type === "Comma" /* Comma */) {
|
|
1518
|
+
this.stream.next();
|
|
1519
|
+
this.stream.skipWhitespace();
|
|
1520
|
+
const intervalToken = this.stream.expect("Number" /* Number */);
|
|
1521
|
+
intervalMs = Number(intervalToken.value);
|
|
1522
|
+
this.stream.skipWhitespace();
|
|
1523
|
+
}
|
|
1524
|
+
this.stream.expect("RParen" /* RParen */);
|
|
1525
|
+
flagArgs.wait = { timeoutMs, ...intervalMs !== void 0 ? { intervalMs } : {} };
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
return { flags, flagArgs };
|
|
1529
|
+
}
|
|
1400
1530
|
wrapErrors(fn) {
|
|
1401
1531
|
try {
|
|
1402
1532
|
return fn();
|
|
@@ -1627,11 +1757,11 @@ ${caret}`;
|
|
|
1627
1757
|
parseAssignment() {
|
|
1628
1758
|
const target = this.parseAssignmentTarget();
|
|
1629
1759
|
this.stream.skipWhitespace();
|
|
1630
|
-
this.
|
|
1760
|
+
const operator = this.parseAssignmentOperator();
|
|
1631
1761
|
this.stream.skipWhitespace();
|
|
1632
1762
|
const value = this.parseExpression();
|
|
1633
1763
|
this.consumeStatementTerminator();
|
|
1634
|
-
return new AssignmentNode(target, value);
|
|
1764
|
+
return new AssignmentNode(target, value, operator);
|
|
1635
1765
|
}
|
|
1636
1766
|
parseExpression() {
|
|
1637
1767
|
return this.parsePipeExpression();
|
|
@@ -2213,7 +2343,14 @@ ${caret}`;
|
|
|
2213
2343
|
return this.parseObjectPattern();
|
|
2214
2344
|
}
|
|
2215
2345
|
if (token.type === "Identifier" /* Identifier */) {
|
|
2216
|
-
|
|
2346
|
+
const expr = this.parseCallExpression();
|
|
2347
|
+
if (expr instanceof CallExpression) {
|
|
2348
|
+
throw new Error("Invalid assignment target CallExpression");
|
|
2349
|
+
}
|
|
2350
|
+
if (expr instanceof IdentifierExpression || expr instanceof MemberExpression || expr instanceof IndexExpression) {
|
|
2351
|
+
return expr;
|
|
2352
|
+
}
|
|
2353
|
+
throw new Error("Invalid assignment target");
|
|
2217
2354
|
}
|
|
2218
2355
|
throw new Error(`Invalid assignment target ${token.type}`);
|
|
2219
2356
|
}
|
|
@@ -2492,12 +2629,31 @@ ${caret}`;
|
|
|
2492
2629
|
while (this.stream.peekNonWhitespace(index)?.type === "Dot" /* Dot */ && this.stream.peekNonWhitespace(index + 1)?.type === "Identifier" /* Identifier */) {
|
|
2493
2630
|
index += 2;
|
|
2494
2631
|
}
|
|
2495
|
-
|
|
2632
|
+
while (this.stream.peekNonWhitespace(index)?.type === "LBracket" /* LBracket */) {
|
|
2633
|
+
let depth = 0;
|
|
2634
|
+
while (true) {
|
|
2635
|
+
const token = this.stream.peekNonWhitespace(index);
|
|
2636
|
+
if (!token) {
|
|
2637
|
+
return false;
|
|
2638
|
+
}
|
|
2639
|
+
if (token.type === "LBracket" /* LBracket */) {
|
|
2640
|
+
depth += 1;
|
|
2641
|
+
} else if (token.type === "RBracket" /* RBracket */) {
|
|
2642
|
+
depth -= 1;
|
|
2643
|
+
if (depth === 0) {
|
|
2644
|
+
index += 1;
|
|
2645
|
+
break;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
index += 1;
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
return this.isAssignmentOperatorStart(index);
|
|
2496
2652
|
}
|
|
2497
2653
|
if (first.type === "At" /* At */ || first.type === "Dollar" /* Dollar */) {
|
|
2498
2654
|
const second = this.stream.peekNonWhitespace(1);
|
|
2499
2655
|
const third = this.stream.peekNonWhitespace(2);
|
|
2500
|
-
return second?.type === "Identifier" /* Identifier */ &&
|
|
2656
|
+
return second?.type === "Identifier" /* Identifier */ && this.isAssignmentOperatorStart(2);
|
|
2501
2657
|
}
|
|
2502
2658
|
if (first.type === "LBrace" /* LBrace */ || first.type === "LBracket" /* LBracket */) {
|
|
2503
2659
|
const stack = [];
|
|
@@ -2512,7 +2668,7 @@ ${caret}`;
|
|
|
2512
2668
|
} else if (token.type === "RBrace" /* RBrace */ || token.type === "RBracket" /* RBracket */) {
|
|
2513
2669
|
stack.pop();
|
|
2514
2670
|
if (stack.length === 0) {
|
|
2515
|
-
return this.
|
|
2671
|
+
return this.isAssignmentOperatorStart(index + 1);
|
|
2516
2672
|
}
|
|
2517
2673
|
}
|
|
2518
2674
|
index += 1;
|
|
@@ -2520,6 +2676,20 @@ ${caret}`;
|
|
|
2520
2676
|
}
|
|
2521
2677
|
return false;
|
|
2522
2678
|
}
|
|
2679
|
+
isAssignmentOperatorStart(index) {
|
|
2680
|
+
const token = this.stream.peekNonWhitespace(index);
|
|
2681
|
+
if (!token) {
|
|
2682
|
+
return false;
|
|
2683
|
+
}
|
|
2684
|
+
if (token.type === "Equals" /* Equals */) {
|
|
2685
|
+
return true;
|
|
2686
|
+
}
|
|
2687
|
+
if (token.type === "Plus" /* Plus */ || token.type === "Minus" /* Minus */ || token.type === "Star" /* Star */ || token.type === "Slash" /* Slash */) {
|
|
2688
|
+
const next = this.stream.peekNonWhitespace(index + 1);
|
|
2689
|
+
return next?.type === "Equals" /* Equals */;
|
|
2690
|
+
}
|
|
2691
|
+
return false;
|
|
2692
|
+
}
|
|
2523
2693
|
isCallStart() {
|
|
2524
2694
|
const first = this.stream.peekNonWhitespace(0);
|
|
2525
2695
|
if (!first || first.type !== "Identifier" /* Identifier */) {
|
|
@@ -2744,10 +2914,35 @@ ${caret}`;
|
|
|
2744
2914
|
parseAssignmentExpression() {
|
|
2745
2915
|
const target = this.parseAssignmentTarget();
|
|
2746
2916
|
this.stream.skipWhitespace();
|
|
2747
|
-
this.
|
|
2917
|
+
const operator = this.parseAssignmentOperator();
|
|
2748
2918
|
this.stream.skipWhitespace();
|
|
2749
2919
|
const value = this.parseExpression();
|
|
2750
|
-
return new AssignmentNode(target, value);
|
|
2920
|
+
return new AssignmentNode(target, value, operator);
|
|
2921
|
+
}
|
|
2922
|
+
parseAssignmentOperator() {
|
|
2923
|
+
const next = this.stream.peek();
|
|
2924
|
+
if (!next) {
|
|
2925
|
+
throw new Error("Expected assignment operator");
|
|
2926
|
+
}
|
|
2927
|
+
if (next.type === "Equals" /* Equals */) {
|
|
2928
|
+
this.stream.next();
|
|
2929
|
+
return "=";
|
|
2930
|
+
}
|
|
2931
|
+
if (next.type === "Plus" /* Plus */ || next.type === "Minus" /* Minus */ || next.type === "Star" /* Star */ || next.type === "Slash" /* Slash */) {
|
|
2932
|
+
const op = this.stream.next();
|
|
2933
|
+
this.stream.expect("Equals" /* Equals */);
|
|
2934
|
+
if (op.type === "Plus" /* Plus */) {
|
|
2935
|
+
return "+=";
|
|
2936
|
+
}
|
|
2937
|
+
if (op.type === "Minus" /* Minus */) {
|
|
2938
|
+
return "-=";
|
|
2939
|
+
}
|
|
2940
|
+
if (op.type === "Star" /* Star */) {
|
|
2941
|
+
return "*=";
|
|
2942
|
+
}
|
|
2943
|
+
return "/=";
|
|
2944
|
+
}
|
|
2945
|
+
throw new Error("Expected assignment operator");
|
|
2751
2946
|
}
|
|
2752
2947
|
parseTryBlock() {
|
|
2753
2948
|
this.stream.expect("Try" /* Try */);
|
|
@@ -3250,6 +3445,7 @@ var Engine = class _Engine {
|
|
|
3250
3445
|
ignoredAdded = /* @__PURE__ */ new WeakMap();
|
|
3251
3446
|
diagnostics;
|
|
3252
3447
|
logger;
|
|
3448
|
+
pendingUses = [];
|
|
3253
3449
|
constructor(options = {}) {
|
|
3254
3450
|
this.diagnostics = options.diagnostics ?? false;
|
|
3255
3451
|
this.logger = options.logger ?? console;
|
|
@@ -3319,6 +3515,10 @@ var Engine = class _Engine {
|
|
|
3319
3515
|
registerBehaviors(source) {
|
|
3320
3516
|
const program = new Parser(source, { customFlags: new Set(this.flagHandlers.keys()) }).parseProgram();
|
|
3321
3517
|
for (const use of program.uses) {
|
|
3518
|
+
if (use.flags?.wait) {
|
|
3519
|
+
this.pendingUses.push(this.waitForUseGlobal(use));
|
|
3520
|
+
continue;
|
|
3521
|
+
}
|
|
3322
3522
|
const value = this.resolveGlobalPath(use.name);
|
|
3323
3523
|
if (value === void 0) {
|
|
3324
3524
|
console.warn(`vsn: global '${use.name}' not found`);
|
|
@@ -3368,6 +3568,52 @@ var Engine = class _Engine {
|
|
|
3368
3568
|
}
|
|
3369
3569
|
return value;
|
|
3370
3570
|
}
|
|
3571
|
+
async waitForUses() {
|
|
3572
|
+
while (this.pendingUses.length > 0) {
|
|
3573
|
+
const pending = this.pendingUses;
|
|
3574
|
+
this.pendingUses = [];
|
|
3575
|
+
await Promise.all(pending);
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
waitForUseGlobal(use) {
|
|
3579
|
+
const config = use.flagArgs?.wait ?? {};
|
|
3580
|
+
const timeoutMs = config.timeoutMs ?? 1e4;
|
|
3581
|
+
const initialDelayMs = config.intervalMs ?? 100;
|
|
3582
|
+
const maxDelayMs = 1e3;
|
|
3583
|
+
const existing = this.resolveGlobalPath(use.name);
|
|
3584
|
+
if (existing !== void 0) {
|
|
3585
|
+
this.registerGlobal(use.alias, existing);
|
|
3586
|
+
return Promise.resolve();
|
|
3587
|
+
}
|
|
3588
|
+
if (timeoutMs <= 0) {
|
|
3589
|
+
this.emitUseError(use.name, new Error(`vsn: global '${use.name}' not found`));
|
|
3590
|
+
return Promise.resolve();
|
|
3591
|
+
}
|
|
3592
|
+
return new Promise((resolve) => {
|
|
3593
|
+
let elapsedMs = 0;
|
|
3594
|
+
let delayMs = initialDelayMs;
|
|
3595
|
+
const check = () => {
|
|
3596
|
+
const value = this.resolveGlobalPath(use.name);
|
|
3597
|
+
if (value !== void 0) {
|
|
3598
|
+
this.registerGlobal(use.alias, value);
|
|
3599
|
+
resolve();
|
|
3600
|
+
return;
|
|
3601
|
+
}
|
|
3602
|
+
if (elapsedMs >= timeoutMs) {
|
|
3603
|
+
this.emitUseError(use.name, new Error(`vsn: global '${use.name}' not found`));
|
|
3604
|
+
resolve();
|
|
3605
|
+
return;
|
|
3606
|
+
}
|
|
3607
|
+
const scheduledDelay = Math.min(delayMs, timeoutMs - elapsedMs);
|
|
3608
|
+
setTimeout(() => {
|
|
3609
|
+
elapsedMs += scheduledDelay;
|
|
3610
|
+
delayMs = Math.min(delayMs * 2, maxDelayMs);
|
|
3611
|
+
check();
|
|
3612
|
+
}, scheduledDelay);
|
|
3613
|
+
};
|
|
3614
|
+
check();
|
|
3615
|
+
});
|
|
3616
|
+
}
|
|
3371
3617
|
getScope(element, parentScope) {
|
|
3372
3618
|
const existing = this.scopes.get(element);
|
|
3373
3619
|
if (existing) {
|
|
@@ -3491,6 +3737,7 @@ var Engine = class _Engine {
|
|
|
3491
3737
|
}
|
|
3492
3738
|
}
|
|
3493
3739
|
async applyBehaviors(root) {
|
|
3740
|
+
await this.waitForUses();
|
|
3494
3741
|
if (this.behaviorRegistry.length === 0) {
|
|
3495
3742
|
return;
|
|
3496
3743
|
}
|
|
@@ -3898,6 +4145,19 @@ var Engine = class _Engine {
|
|
|
3898
4145
|
})
|
|
3899
4146
|
);
|
|
3900
4147
|
}
|
|
4148
|
+
emitUseError(name, error) {
|
|
4149
|
+
const selector = `use:${name}`;
|
|
4150
|
+
this.logger.warn?.("vsn:error", { error, selector });
|
|
4151
|
+
const target = globalThis.document;
|
|
4152
|
+
if (target && typeof target.dispatchEvent === "function") {
|
|
4153
|
+
target.dispatchEvent(
|
|
4154
|
+
new CustomEvent("vsn:error", {
|
|
4155
|
+
detail: { error, selector },
|
|
4156
|
+
bubbles: true
|
|
4157
|
+
})
|
|
4158
|
+
);
|
|
4159
|
+
}
|
|
4160
|
+
}
|
|
3901
4161
|
attachOnHandler(element, config) {
|
|
3902
4162
|
const options = this.getListenerOptions(config.modifiers);
|
|
3903
4163
|
const listenerTarget = config.modifiers?.includes("outside") ? element.ownerDocument : element;
|