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.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
- constructor(name: string, alias: string);
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
- constructor(target: AssignmentTarget, value: ExpressionNode);
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
- constructor(name: string, alias: string);
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
- constructor(target: AssignmentTarget, value: ExpressionNode);
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.stream.expect("Equals" /* Equals */);
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.stream.peekNonWhitespace(index)?.type === "Equals" /* Equals */;
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 */ && third?.type === "Equals" /* Equals */;
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.stream.peekNonWhitespace(index + 1)?.type === "Equals" /* Equals */;
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.stream.expect("Equals" /* Equals */);
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;