vsn 1.0.4 → 1.0.5

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 CHANGED
@@ -35,6 +35,9 @@ __export(index_exports, {
35
35
  ContinueNode: () => ContinueNode,
36
36
  DeclarationNode: () => DeclarationNode,
37
37
  DirectiveExpression: () => DirectiveExpression,
38
+ ElementDirectiveExpression: () => ElementDirectiveExpression,
39
+ ElementPropertyExpression: () => ElementPropertyExpression,
40
+ ElementRefExpression: () => ElementRefExpression,
38
41
  Engine: () => Engine,
39
42
  ForEachNode: () => ForEachNode,
40
43
  ForNode: () => ForNode,
@@ -623,6 +626,33 @@ var AssignmentNode = class extends BaseNode {
623
626
  this.prefix = prefix;
624
627
  }
625
628
  evaluate(context) {
629
+ const target = this.target;
630
+ if (target instanceof DirectiveExpression) {
631
+ const value2 = this.value.evaluate(context);
632
+ return resolveMaybe(value2, (resolvedValue) => {
633
+ this.assignDirectiveTarget(context, target, resolvedValue, this.operator);
634
+ return resolvedValue;
635
+ });
636
+ }
637
+ if (target instanceof ElementDirectiveExpression) {
638
+ const elementValue = target.element.evaluate(context);
639
+ return resolveMaybe(elementValue, (resolvedElement) => {
640
+ const element = resolveElementFromReference(resolvedElement);
641
+ if (!element) {
642
+ return void 0;
643
+ }
644
+ const value2 = this.value.evaluate(context);
645
+ return resolveMaybe(value2, (resolvedValue) => {
646
+ this.assignDirectiveTarget(
647
+ { ...context, element },
648
+ target.directive,
649
+ resolvedValue,
650
+ this.operator
651
+ );
652
+ return resolvedValue;
653
+ });
654
+ });
655
+ }
626
656
  if (!context.scope || !context.scope.setPath) {
627
657
  return void 0;
628
658
  }
@@ -650,7 +680,7 @@ var AssignmentNode = class extends BaseNode {
650
680
  return resolvedValue;
651
681
  });
652
682
  }
653
- this.assignTarget(context, this.target, resolvedValue);
683
+ this.assignTarget(context, this.target, resolvedValue, this.operator);
654
684
  return resolvedValue;
655
685
  });
656
686
  }
@@ -787,12 +817,49 @@ var AssignmentNode = class extends BaseNode {
787
817
  }
788
818
  return null;
789
819
  }
790
- assignTarget(context, target, value) {
820
+ assignTarget(context, target, value, operator = "=") {
791
821
  if (!context.scope || !context.scope.setPath) {
792
822
  return;
793
823
  }
794
824
  if (target instanceof DirectiveExpression) {
795
- this.assignDirectiveTarget(context, target, value);
825
+ this.assignDirectiveTarget(context, target, value, operator);
826
+ return;
827
+ }
828
+ if (target instanceof ElementDirectiveExpression) {
829
+ const elementValue = target.element.evaluate(context);
830
+ const next = resolveMaybe(elementValue, (resolvedElement) => {
831
+ const element = resolveElementFromReference(resolvedElement);
832
+ if (!element) {
833
+ return;
834
+ }
835
+ this.assignDirectiveTarget(
836
+ { ...context, element },
837
+ target.directive,
838
+ value,
839
+ operator
840
+ );
841
+ });
842
+ if (isPromiseLike(next)) {
843
+ void next;
844
+ }
845
+ return;
846
+ }
847
+ if (target instanceof ElementPropertyExpression) {
848
+ const elementValue = target.element.evaluate(context);
849
+ const next = resolveMaybe(elementValue, (resolvedElement) => {
850
+ if (resolvedElement && typeof resolvedElement === "object" && resolvedElement.__scope) {
851
+ resolvedElement.__scope.setPath?.(target.property, value);
852
+ return;
853
+ }
854
+ const element = resolveElementFromReference(resolvedElement);
855
+ if (!element) {
856
+ return;
857
+ }
858
+ element[target.property] = value;
859
+ });
860
+ if (isPromiseLike(next)) {
861
+ void next;
862
+ }
796
863
  return;
797
864
  }
798
865
  if (target instanceof IdentifierExpression) {
@@ -811,7 +878,7 @@ var AssignmentNode = class extends BaseNode {
811
878
  index += 1;
812
879
  continue;
813
880
  }
814
- this.assignTarget(context, element, source[index]);
881
+ this.assignTarget(context, element, source[index], operator);
815
882
  index += 1;
816
883
  }
817
884
  return;
@@ -831,17 +898,37 @@ var AssignmentNode = class extends BaseNode {
831
898
  continue;
832
899
  }
833
900
  usedKeys.add(entry.key);
834
- this.assignTarget(context, entry.target, source[entry.key]);
901
+ this.assignTarget(context, entry.target, source[entry.key], operator);
835
902
  }
836
903
  return;
837
904
  }
838
905
  }
839
- assignDirectiveTarget(context, target, value) {
906
+ assignDirectiveTarget(context, target, value, operator = "=") {
840
907
  const element = context.element;
841
908
  if (!element) {
842
909
  return;
843
910
  }
844
911
  if (target.kind === "attr") {
912
+ if (target.name === "class" && "classList" in element && operator !== "=") {
913
+ const classes = normalizeClassList(value);
914
+ if (classes.length === 0) {
915
+ return;
916
+ }
917
+ if (operator === "+=") {
918
+ element.classList.add(...classes);
919
+ return;
920
+ }
921
+ if (operator === "-=") {
922
+ element.classList.remove(...classes);
923
+ return;
924
+ }
925
+ if (operator === "~=") {
926
+ for (const name of classes) {
927
+ element.classList.toggle(name);
928
+ }
929
+ return;
930
+ }
931
+ }
845
932
  if (target.name === "value") {
846
933
  if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
847
934
  element.value = value == null ? "" : String(value);
@@ -875,6 +962,15 @@ var AssignmentNode = class extends BaseNode {
875
962
  }
876
963
  }
877
964
  };
965
+ function normalizeClassList(value) {
966
+ if (value == null) {
967
+ return [];
968
+ }
969
+ if (Array.isArray(value)) {
970
+ return value.flatMap((entry) => String(entry).split(/\s+/)).map((entry) => entry.trim()).filter(Boolean);
971
+ }
972
+ return String(value).split(/\s+/).map((entry) => entry.trim()).filter(Boolean);
973
+ }
878
974
  var ReturnNode = class extends BaseNode {
879
975
  constructor(value) {
880
976
  super("Return");
@@ -1309,6 +1405,25 @@ var IdentifierExpression = class extends BaseNode {
1309
1405
  return context.globals ? context.globals[this.name] : void 0;
1310
1406
  }
1311
1407
  };
1408
+ var ElementRefExpression = class extends BaseNode {
1409
+ constructor(id) {
1410
+ super("ElementRef");
1411
+ this.id = id;
1412
+ }
1413
+ evaluate(context) {
1414
+ const doc = context.element?.ownerDocument ?? (typeof document !== "undefined" ? document : void 0);
1415
+ if (!doc) {
1416
+ return void 0;
1417
+ }
1418
+ const element = doc.getElementById(this.id);
1419
+ if (!element) {
1420
+ return void 0;
1421
+ }
1422
+ const engine = globalThis.VSNEngine;
1423
+ const scope = engine?.getScope ? engine.getScope(element) : void 0;
1424
+ return { __element: element, __scope: scope };
1425
+ }
1426
+ };
1312
1427
  var SpreadElement = class extends BaseNode {
1313
1428
  constructor(value) {
1314
1429
  super("SpreadElement");
@@ -1802,6 +1917,56 @@ var DirectiveExpression = class extends BaseNode {
1802
1917
  return void 0;
1803
1918
  }
1804
1919
  };
1920
+ var ElementDirectiveExpression = class extends BaseNode {
1921
+ constructor(element, directive) {
1922
+ super("ElementDirective");
1923
+ this.element = element;
1924
+ this.directive = directive;
1925
+ }
1926
+ evaluate(context) {
1927
+ const elementValue = this.element.evaluate(context);
1928
+ return resolveMaybe(elementValue, (resolvedElement) => {
1929
+ const element = resolveElementFromReference(resolvedElement);
1930
+ if (!element) {
1931
+ return void 0;
1932
+ }
1933
+ const nextContext = { ...context, element };
1934
+ return this.directive.evaluate(nextContext);
1935
+ });
1936
+ }
1937
+ };
1938
+ var ElementPropertyExpression = class extends BaseNode {
1939
+ constructor(element, property) {
1940
+ super("ElementProperty");
1941
+ this.element = element;
1942
+ this.property = property;
1943
+ }
1944
+ evaluate(context) {
1945
+ const elementValue = this.element.evaluate(context);
1946
+ return resolveMaybe(elementValue, (resolvedElement) => {
1947
+ if (resolvedElement && typeof resolvedElement === "object" && resolvedElement.__scope) {
1948
+ return resolvedElement.__scope.getPath?.(this.property);
1949
+ }
1950
+ const element = resolveElementFromReference(resolvedElement);
1951
+ if (!element) {
1952
+ return void 0;
1953
+ }
1954
+ return element[this.property];
1955
+ });
1956
+ }
1957
+ };
1958
+ function resolveElementFromReference(value) {
1959
+ if (value && typeof value === "object") {
1960
+ if (value.nodeType === 1) {
1961
+ return value;
1962
+ }
1963
+ const candidate = value.__element;
1964
+ if (candidate && typeof candidate === "object" && candidate.nodeType === 1) {
1965
+ return candidate;
1966
+ }
1967
+ }
1968
+ return void 0;
1969
+ }
1805
1970
  var AwaitExpression = class extends BaseNode {
1806
1971
  constructor(argument) {
1807
1972
  super("AwaitExpression");
@@ -2499,7 +2664,7 @@ ${caret}`;
2499
2664
  return expr;
2500
2665
  }
2501
2666
  createIncrementNode(token, argument, prefix) {
2502
- if (!(argument instanceof IdentifierExpression) && !(argument instanceof MemberExpression) && !(argument instanceof IndexExpression) && !(argument instanceof DirectiveExpression)) {
2667
+ if (!(argument instanceof IdentifierExpression) && !(argument instanceof MemberExpression) && !(argument instanceof IndexExpression) && !(argument instanceof DirectiveExpression) && !(argument instanceof ElementDirectiveExpression)) {
2503
2668
  throw new Error("Increment/decrement requires a mutable target");
2504
2669
  }
2505
2670
  const operator = token.type === "PlusPlus" /* PlusPlus */ ? "++" : "--";
@@ -2585,8 +2750,18 @@ ${caret}`;
2585
2750
  }
2586
2751
  if (next.type === "Dot" /* Dot */) {
2587
2752
  this.stream.next();
2588
- const name = this.stream.expect("Identifier" /* Identifier */);
2589
- expr = new MemberExpression(expr, name.value);
2753
+ const chained = this.stream.peek();
2754
+ if (chained?.type === "At" /* At */ || chained?.type === "Dollar" /* Dollar */) {
2755
+ const directive = this.parseDirectiveExpression();
2756
+ expr = new ElementDirectiveExpression(expr, directive);
2757
+ } else {
2758
+ const name = this.stream.expect("Identifier" /* Identifier */);
2759
+ if (expr instanceof ElementRefExpression) {
2760
+ expr = new ElementPropertyExpression(expr, name.value);
2761
+ } else {
2762
+ expr = new MemberExpression(expr, name.value);
2763
+ }
2764
+ }
2590
2765
  continue;
2591
2766
  }
2592
2767
  if (next.type === "LBracket" /* LBracket */) {
@@ -2609,10 +2784,10 @@ ${caret}`;
2609
2784
  throw new Error("Expected expression");
2610
2785
  }
2611
2786
  if (token.type === "At" /* At */ || token.type === "Dollar" /* Dollar */) {
2612
- const kind = token.type === "At" /* At */ ? "attr" : "style";
2613
- this.stream.next();
2614
- const name = this.stream.expect("Identifier" /* Identifier */);
2615
- return new DirectiveExpression(kind, name.value);
2787
+ return this.parseDirectiveExpression();
2788
+ }
2789
+ if (token.type === "Hash" /* Hash */) {
2790
+ return this.parseElementRefExpression();
2616
2791
  }
2617
2792
  if (token.type === "Question" /* Question */) {
2618
2793
  return this.parseQueryExpression();
@@ -2659,6 +2834,21 @@ ${caret}`;
2659
2834
  }
2660
2835
  throw new Error(`Unsupported expression token ${token.type}`);
2661
2836
  }
2837
+ parseDirectiveExpression() {
2838
+ const token = this.stream.peek();
2839
+ if (!token || token.type !== "At" /* At */ && token.type !== "Dollar" /* Dollar */) {
2840
+ throw new Error("Expected directive");
2841
+ }
2842
+ const kind = token.type === "At" /* At */ ? "attr" : "style";
2843
+ this.stream.next();
2844
+ const name = this.stream.expect("Identifier" /* Identifier */);
2845
+ return new DirectiveExpression(kind, name.value);
2846
+ }
2847
+ parseElementRefExpression() {
2848
+ this.stream.expect("Hash" /* Hash */);
2849
+ const id = this.stream.expect("Identifier" /* Identifier */).value;
2850
+ return new ElementRefExpression(id);
2851
+ }
2662
2852
  parseArrayExpression() {
2663
2853
  this.stream.expect("LBracket" /* LBracket */);
2664
2854
  const elements = [];
@@ -2875,7 +3065,14 @@ ${caret}`;
2875
3065
  if (expr instanceof CallExpression) {
2876
3066
  throw new Error("Invalid assignment target CallExpression");
2877
3067
  }
2878
- if (expr instanceof IdentifierExpression || expr instanceof MemberExpression || expr instanceof IndexExpression) {
3068
+ if (expr instanceof IdentifierExpression || expr instanceof MemberExpression || expr instanceof IndexExpression || expr instanceof ElementDirectiveExpression) {
3069
+ return expr;
3070
+ }
3071
+ throw new Error("Invalid assignment target");
3072
+ }
3073
+ if (token.type === "Hash" /* Hash */) {
3074
+ const expr = this.parseCallExpression();
3075
+ if (expr instanceof ElementDirectiveExpression) {
2879
3076
  return expr;
2880
3077
  }
2881
3078
  throw new Error("Invalid assignment target");
@@ -3227,6 +3424,45 @@ ${caret}`;
3227
3424
  const second = this.stream.peekNonWhitespace(1);
3228
3425
  return second?.type === "Identifier" /* Identifier */ && this.isAssignmentOperatorStart(2);
3229
3426
  }
3427
+ if (first.type === "Hash" /* Hash */) {
3428
+ let index = 1;
3429
+ if (this.stream.peekNonWhitespace(index)?.type !== "Identifier" /* Identifier */) {
3430
+ return false;
3431
+ }
3432
+ index += 1;
3433
+ while (true) {
3434
+ const token = this.stream.peekNonWhitespace(index);
3435
+ if (!token) {
3436
+ return false;
3437
+ }
3438
+ if (token.type === "Dot" /* Dot */) {
3439
+ const next = this.stream.peekNonWhitespace(index + 1);
3440
+ if (next?.type === "Identifier" /* Identifier */) {
3441
+ index += 2;
3442
+ continue;
3443
+ }
3444
+ if (next?.type === "At" /* At */ || next?.type === "Dollar" /* Dollar */) {
3445
+ const afterDirective = this.stream.peekNonWhitespace(index + 2);
3446
+ if (afterDirective?.type !== "Identifier" /* Identifier */) {
3447
+ return false;
3448
+ }
3449
+ index += 3;
3450
+ continue;
3451
+ }
3452
+ return false;
3453
+ }
3454
+ if (token.type === "LBracket" /* LBracket */) {
3455
+ const indexAfter = this.stream.indexAfterDelimited("LBracket" /* LBracket */, "RBracket" /* RBracket */, index);
3456
+ if (indexAfter === null) {
3457
+ return false;
3458
+ }
3459
+ index = indexAfter;
3460
+ continue;
3461
+ }
3462
+ break;
3463
+ }
3464
+ return this.isAssignmentOperatorStart(index);
3465
+ }
3230
3466
  if (first.type === "LBrace" /* LBrace */ || first.type === "LBracket" /* LBracket */) {
3231
3467
  const stack = [];
3232
3468
  let index = 0;
@@ -3256,6 +3492,10 @@ ${caret}`;
3256
3492
  if (token.type === "Equals" /* Equals */) {
3257
3493
  return true;
3258
3494
  }
3495
+ if (token.type === "Tilde" /* Tilde */) {
3496
+ const next = this.stream.peekNonWhitespace(index + 1);
3497
+ return next?.type === "Equals" /* Equals */;
3498
+ }
3259
3499
  if (token.type === "Plus" /* Plus */ || token.type === "Minus" /* Minus */ || token.type === "Star" /* Star */ || token.type === "Slash" /* Slash */) {
3260
3500
  const next = this.stream.peekNonWhitespace(index + 1);
3261
3501
  return next?.type === "Equals" /* Equals */;
@@ -3270,7 +3510,7 @@ ${caret}`;
3270
3510
  if (first.type === "Identifier" /* Identifier */) {
3271
3511
  return true;
3272
3512
  }
3273
- return first.type === "Number" /* Number */ || first.type === "String" /* String */ || first.type === "Boolean" /* Boolean */ || first.type === "Null" /* Null */ || first.type === "LParen" /* LParen */ || first.type === "LBracket" /* LBracket */ || first.type === "LBrace" /* LBrace */ || first.type === "At" /* At */ || first.type === "Dollar" /* Dollar */ || first.type === "Question" /* Question */ || first.type === "Bang" /* Bang */ || first.type === "Minus" /* Minus */;
3513
+ return first.type === "Number" /* Number */ || first.type === "String" /* String */ || first.type === "Boolean" /* Boolean */ || first.type === "Null" /* Null */ || first.type === "LParen" /* LParen */ || first.type === "LBracket" /* LBracket */ || first.type === "LBrace" /* LBrace */ || first.type === "At" /* At */ || first.type === "Dollar" /* Dollar */ || first.type === "Hash" /* Hash */ || first.type === "Question" /* Question */ || first.type === "Bang" /* Bang */ || first.type === "Minus" /* Minus */;
3274
3514
  }
3275
3515
  isFunctionDeclarationStart() {
3276
3516
  const first = this.stream.peekNonWhitespace(0);
@@ -3493,6 +3733,11 @@ ${caret}`;
3493
3733
  this.stream.next();
3494
3734
  return "=";
3495
3735
  }
3736
+ if (next.type === "Tilde" /* Tilde */) {
3737
+ this.stream.next();
3738
+ this.stream.expect("Equals" /* Equals */);
3739
+ return "~=";
3740
+ }
3496
3741
  if (next.type === "Plus" /* Plus */ || next.type === "Minus" /* Minus */ || next.type === "Star" /* Star */ || next.type === "Slash" /* Slash */) {
3497
3742
  const op = this.stream.next();
3498
3743
  this.stream.expect("Equals" /* Equals */);
@@ -5604,6 +5849,9 @@ var Engine = class _Engine {
5604
5849
  if (type === "Identifier") {
5605
5850
  return { type, name: node.name ?? "" };
5606
5851
  }
5852
+ if (type === "ElementRef") {
5853
+ return { type, id: node.id ?? "" };
5854
+ }
5607
5855
  if (type === "Literal") {
5608
5856
  return { type, value: node.value };
5609
5857
  }
@@ -5660,6 +5908,20 @@ var Engine = class _Engine {
5660
5908
  if (type === "Directive") {
5661
5909
  return { type, kind: node.kind ?? "", name: node.name ?? "" };
5662
5910
  }
5911
+ if (type === "ElementDirective") {
5912
+ return {
5913
+ type,
5914
+ element: this.normalizeNode(node.element),
5915
+ directive: this.normalizeNode(node.directive)
5916
+ };
5917
+ }
5918
+ if (type === "ElementProperty") {
5919
+ return {
5920
+ type,
5921
+ element: this.normalizeNode(node.element),
5922
+ property: node.property ?? ""
5923
+ };
5924
+ }
5663
5925
  if (type === "Query") {
5664
5926
  return { type, direction: node.direction ?? "", selector: node.selector ?? "" };
5665
5927
  }
@@ -6275,6 +6537,9 @@ if (typeof document !== "undefined") {
6275
6537
  ContinueNode,
6276
6538
  DeclarationNode,
6277
6539
  DirectiveExpression,
6540
+ ElementDirectiveExpression,
6541
+ ElementPropertyExpression,
6542
+ ElementRefExpression,
6278
6543
  Engine,
6279
6544
  ForEachNode,
6280
6545
  ForNode,