@hyperfixi/core 2.1.0 → 2.2.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.
Files changed (42) hide show
  1. package/dist/api/hyperscript-api.d.ts +6 -1
  2. package/dist/chunks/{bridge-CZfeDyEz.js → bridge-BELRwj7r.js} +2 -2
  3. package/dist/chunks/browser-modular-B7Bb-ABs.js +2 -0
  4. package/dist/chunks/index-lsDi6izr.js +2 -0
  5. package/dist/commands/dom/toggle.d.ts +2 -0
  6. package/dist/commands/index.js +35 -0
  7. package/dist/commands/index.mjs +35 -0
  8. package/dist/expressions/index.js +0 -27
  9. package/dist/expressions/index.mjs +0 -27
  10. package/dist/hyperfixi-classic-i18n.js +1 -1
  11. package/dist/hyperfixi-minimal.js +1 -1
  12. package/dist/hyperfixi-multilingual.js +1 -1
  13. package/dist/hyperfixi-standard.js +1 -1
  14. package/dist/hyperfixi.js +1 -1
  15. package/dist/hyperfixi.mjs +1 -1
  16. package/dist/i18n/error-catalog.d.ts +12 -0
  17. package/dist/index.js +31354 -23496
  18. package/dist/index.min.js +1 -1
  19. package/dist/index.mjs +31354 -23496
  20. package/dist/lokascript-browser-classic-i18n.js +1 -1
  21. package/dist/lokascript-browser-minimal.js +1 -1
  22. package/dist/lokascript-browser-standard.js +1 -1
  23. package/dist/lokascript-browser.js +1 -1
  24. package/dist/lokascript-multilingual.js +1 -1
  25. package/dist/lse/index.d.ts +15 -0
  26. package/dist/lse/index.js +84 -0
  27. package/dist/lse/index.mjs +71 -0
  28. package/dist/parser/full-parser.js +598 -241
  29. package/dist/parser/full-parser.mjs +598 -241
  30. package/dist/parser/helpers/ast-helpers.d.ts +1 -0
  31. package/dist/parser/parser-types.d.ts +22 -7
  32. package/dist/parser/parser.d.ts +7 -0
  33. package/dist/parser/pratt-parser.d.ts +42 -0
  34. package/dist/parser/token-consumer.d.ts +1 -2
  35. package/dist/parser/tokenizer.d.ts +0 -33
  36. package/dist/registry/index.js +0 -27
  37. package/dist/registry/index.mjs +0 -27
  38. package/dist/runtime/runtime-base.d.ts +3 -0
  39. package/dist/types/base-types.d.ts +11 -0
  40. package/dist/types/core.d.ts +1 -0
  41. package/package.json +13 -4
  42. package/dist/chunks/browser-modular-CwTpxqdt.js +0 -2
@@ -1,4 +1,4 @@
1
- const KEYWORDS$1 = {
1
+ const KEYWORDS = {
2
2
  THEN: 'then',
3
3
  ELSE: 'else',
4
4
  END: 'end',
@@ -27,11 +27,11 @@ const KEYWORDS$1 = {
27
27
  THE: 'the',
28
28
  START: 'start'};
29
29
  const COMMAND_TERMINATORS = [
30
- KEYWORDS$1.THEN,
31
- KEYWORDS$1.AND,
32
- KEYWORDS$1.ELSE,
33
- KEYWORDS$1.END,
34
- KEYWORDS$1.ON,
30
+ KEYWORDS.THEN,
31
+ KEYWORDS.AND,
32
+ KEYWORDS.ELSE,
33
+ KEYWORDS.END,
34
+ KEYWORDS.ON,
35
35
  ];
36
36
  const COMMANDS = new Set([
37
37
  'add',
@@ -346,74 +346,6 @@ var TokenKind;
346
346
  TokenKind["SYMBOL"] = "symbol";
347
347
  TokenKind["UNKNOWN"] = "unknown";
348
348
  })(TokenKind || (TokenKind = {}));
349
- function getTokenKind(tokenType) {
350
- switch (tokenType) {
351
- case TokenType.KEYWORD:
352
- case TokenType.COMMAND:
353
- case TokenType.EXPRESSION:
354
- case TokenType.CONTEXT_VAR:
355
- case TokenType.GLOBAL_VAR:
356
- case TokenType.EVENT:
357
- case TokenType.IDENTIFIER:
358
- return TokenKind.IDENTIFIER;
359
- case TokenType.STRING:
360
- return TokenKind.STRING;
361
- case TokenType.NUMBER:
362
- return TokenKind.NUMBER;
363
- case TokenType.BOOLEAN:
364
- return TokenKind.IDENTIFIER;
365
- case TokenType.TEMPLATE_LITERAL:
366
- return TokenKind.TEMPLATE;
367
- case TokenType.CSS_SELECTOR:
368
- case TokenType.ID_SELECTOR:
369
- case TokenType.CLASS_SELECTOR:
370
- case TokenType.QUERY_REFERENCE:
371
- return TokenKind.SELECTOR;
372
- case TokenType.OPERATOR:
373
- case TokenType.LOGICAL_OPERATOR:
374
- case TokenType.COMPARISON_OPERATOR:
375
- return TokenKind.OPERATOR;
376
- case TokenType.TIME_EXPRESSION:
377
- return TokenKind.TIME;
378
- case TokenType.COMMENT:
379
- return TokenKind.COMMENT;
380
- case TokenType.SYMBOL:
381
- return TokenKind.SYMBOL;
382
- case TokenType.OBJECT_LITERAL:
383
- case TokenType.ARRAY_LITERAL:
384
- case TokenType.UNKNOWN:
385
- default:
386
- return TokenKind.UNKNOWN;
387
- }
388
- }
389
- var TokenType;
390
- (function (TokenType) {
391
- TokenType["KEYWORD"] = "keyword";
392
- TokenType["COMMAND"] = "command";
393
- TokenType["EXPRESSION"] = "expression";
394
- TokenType["STRING"] = "string";
395
- TokenType["NUMBER"] = "number";
396
- TokenType["BOOLEAN"] = "boolean";
397
- TokenType["TEMPLATE_LITERAL"] = "template_literal";
398
- TokenType["CSS_SELECTOR"] = "css_selector";
399
- TokenType["ID_SELECTOR"] = "id_selector";
400
- TokenType["CLASS_SELECTOR"] = "class_selector";
401
- TokenType["QUERY_REFERENCE"] = "query_reference";
402
- TokenType["CONTEXT_VAR"] = "context_var";
403
- TokenType["GLOBAL_VAR"] = "global_var";
404
- TokenType["EVENT"] = "event";
405
- TokenType["OPERATOR"] = "operator";
406
- TokenType["LOGICAL_OPERATOR"] = "logical_operator";
407
- TokenType["COMPARISON_OPERATOR"] = "comparison_operator";
408
- TokenType["TIME_EXPRESSION"] = "time_expression";
409
- TokenType["OBJECT_LITERAL"] = "object_literal";
410
- TokenType["ARRAY_LITERAL"] = "array_literal";
411
- TokenType["SYMBOL"] = "symbol";
412
- TokenType["COMMENT"] = "comment";
413
- TokenType["IDENTIFIER"] = "identifier";
414
- TokenType["UNKNOWN"] = "unknown";
415
- })(TokenType || (TokenType = {}));
416
- const KEYWORDS = TOKENIZER_KEYWORDS;
417
349
  const MATHEMATICAL_OPERATORS = new Set(['+', '-', '*', '/', 'mod']);
418
350
  const TIME_UNITS = new Set(['ms', 's', 'seconds', 'minutes', 'hours', 'days']);
419
351
  function createTokenizer() {
@@ -456,7 +388,7 @@ function tokenize(input) {
456
388
  const start = tokenizer.position;
457
389
  advance(tokenizer);
458
390
  advance(tokenizer);
459
- addToken(tokenizer, TokenType.OPERATOR, "'s", start);
391
+ addToken(tokenizer, TokenKind.OPERATOR, "'s", start);
460
392
  }
461
393
  else {
462
394
  tokenizeString(tokenizer);
@@ -486,7 +418,7 @@ function tokenize(input) {
486
418
  const start = tokenizer.position;
487
419
  advance(tokenizer);
488
420
  advance(tokenizer);
489
- addToken(tokenizer, TokenType.OPERATOR, '..', start);
421
+ addToken(tokenizer, TokenKind.OPERATOR, '..', start);
490
422
  continue;
491
423
  }
492
424
  const prevToken = tokenizer.tokens[tokenizer.tokens.length - 1];
@@ -521,7 +453,8 @@ function tokenize(input) {
521
453
  prevToken.value === '{' ||
522
454
  prevToken.value === ',' ||
523
455
  prevToken.value === ';';
524
- if (isCSSSelectorContext && isAlpha(peek(tokenizer))) {
456
+ const isAdjacentToPrev = prevToken && prevToken.end === tokenizer.position;
457
+ if (isCSSSelectorContext && !isAdjacentToPrev && isAlpha(peek(tokenizer))) {
525
458
  tokenizeCSSSelector(tokenizer);
526
459
  continue;
527
460
  }
@@ -531,46 +464,45 @@ function tokenize(input) {
531
464
  continue;
532
465
  }
533
466
  if (char === '{') {
534
- addToken(tokenizer, TokenType.OPERATOR, '{');
467
+ addToken(tokenizer, TokenKind.OPERATOR, '{');
535
468
  advance(tokenizer);
536
469
  continue;
537
470
  }
538
471
  if (char === '}') {
539
- addToken(tokenizer, TokenType.OPERATOR, '}');
472
+ addToken(tokenizer, TokenKind.OPERATOR, '}');
540
473
  advance(tokenizer);
541
474
  continue;
542
475
  }
543
476
  if (char === '[') {
544
477
  const prevToken = tokenizer.tokens[tokenizer.tokens.length - 1];
545
478
  const isEventCondition = prevToken &&
546
- (prevToken.kind === TokenType.EVENT ||
547
- (prevToken.kind === TokenType.IDENTIFIER && DOM_EVENTS.has(prevToken.value))) &&
479
+ prevToken.kind === TokenKind.IDENTIFIER &&
480
+ DOM_EVENTS.has(prevToken.value) &&
548
481
  tokenizer.tokens.length >= 2 &&
549
482
  tokenizer.tokens[tokenizer.tokens.length - 2]?.value === 'on';
550
483
  const isMemberAccess = prevToken &&
551
- (prevToken.kind === TokenType.IDENTIFIER ||
552
- prevToken.kind === TokenType.CONTEXT_VAR ||
484
+ (prevToken.kind === TokenKind.IDENTIFIER ||
553
485
  prevToken.value === ')' ||
554
486
  prevToken.value === ']') &&
555
487
  !isEventCondition;
556
488
  if (isMemberAccess) {
557
- addToken(tokenizer, TokenType.OPERATOR, '[');
489
+ addToken(tokenizer, TokenKind.OPERATOR, '[');
558
490
  advance(tokenizer);
559
491
  }
560
492
  else {
561
493
  if (isEventCondition) {
562
- addToken(tokenizer, TokenType.SYMBOL, '[');
494
+ addToken(tokenizer, TokenKind.SYMBOL, '[');
563
495
  advance(tokenizer);
564
496
  }
565
497
  else {
566
- addToken(tokenizer, TokenType.OPERATOR, '[');
498
+ addToken(tokenizer, TokenKind.OPERATOR, '[');
567
499
  advance(tokenizer);
568
500
  }
569
501
  }
570
502
  continue;
571
503
  }
572
504
  if (char === ']') {
573
- addToken(tokenizer, TokenType.OPERATOR, ']');
505
+ addToken(tokenizer, TokenKind.OPERATOR, ']');
574
506
  advance(tokenizer);
575
507
  continue;
576
508
  }
@@ -595,7 +527,7 @@ function tokenize(input) {
595
527
  tokenizeIdentifier(tokenizer);
596
528
  continue;
597
529
  }
598
- addToken(tokenizer, TokenType.UNKNOWN, char);
530
+ addToken(tokenizer, TokenKind.UNKNOWN, char);
599
531
  advance(tokenizer);
600
532
  }
601
533
  return tokenizer.tokens;
@@ -637,7 +569,7 @@ function skipWhitespace(tokenizer) {
637
569
  }
638
570
  }
639
571
  }
640
- function addToken(tokenizer, type, value, start, end) {
572
+ function addToken(tokenizer, kind, value, start, end) {
641
573
  const tokenStart = start ?? tokenizer.position - value.length;
642
574
  const tokenEnd = tokenizer.position;
643
575
  let tokenColumn = tokenizer.column - value.length;
@@ -652,7 +584,7 @@ function addToken(tokenizer, type, value, start, end) {
652
584
  tokenColumn = start - lastNewlinePos;
653
585
  }
654
586
  const token = {
655
- kind: getTokenKind(type),
587
+ kind,
656
588
  value,
657
589
  start: tokenStart,
658
590
  end: tokenEnd,
@@ -688,7 +620,7 @@ function tokenizeComment(tokenizer) {
688
620
  break;
689
621
  value += advance(tokenizer);
690
622
  }
691
- addToken(tokenizer, TokenType.COMMENT, '--' + value, start);
623
+ addToken(tokenizer, TokenKind.COMMENT, '--' + value, start);
692
624
  }
693
625
  function tokenizeString(tokenizer) {
694
626
  const start = tokenizer.position;
@@ -705,7 +637,7 @@ function tokenizeString(tokenizer) {
705
637
  }
706
638
  }
707
639
  }
708
- addToken(tokenizer, TokenType.STRING, value, start);
640
+ addToken(tokenizer, TokenKind.STRING, value, start);
709
641
  }
710
642
  function tokenizeTemplateLiteral(tokenizer) {
711
643
  const start = tokenizer.position;
@@ -749,7 +681,7 @@ function tokenizeTemplateLiteral(tokenizer) {
749
681
  if (tokenizer.position >= tokenizer.input.length && !tokenizer.input.endsWith('`')) {
750
682
  throw new Error(`Unterminated template literal at line ${tokenizer.line}, column ${tokenizer.column - value.length}`);
751
683
  }
752
- addToken(tokenizer, TokenType.TEMPLATE_LITERAL, value, start);
684
+ addToken(tokenizer, TokenKind.TEMPLATE, value, start);
753
685
  }
754
686
  function tokenizeCSSSelector(tokenizer) {
755
687
  const start = tokenizer.position;
@@ -764,8 +696,7 @@ function tokenizeCSSSelector(tokenizer) {
764
696
  break;
765
697
  }
766
698
  }
767
- const type = prefix === '#' ? TokenType.ID_SELECTOR : TokenType.CLASS_SELECTOR;
768
- addToken(tokenizer, type, value, start);
699
+ addToken(tokenizer, TokenKind.SELECTOR, value, start);
769
700
  }
770
701
  function tokenizeQueryReference(tokenizer) {
771
702
  const start = tokenizer.position;
@@ -780,7 +711,7 @@ function tokenizeQueryReference(tokenizer) {
780
711
  break;
781
712
  }
782
713
  }
783
- addToken(tokenizer, TokenType.QUERY_REFERENCE, value, start);
714
+ addToken(tokenizer, TokenKind.SELECTOR, value, start);
784
715
  }
785
716
  function tokenizeSymbol(tokenizer) {
786
717
  const start = tokenizer.position;
@@ -794,7 +725,7 @@ function tokenizeSymbol(tokenizer) {
794
725
  break;
795
726
  }
796
727
  }
797
- addToken(tokenizer, TokenType.SYMBOL, value, start);
728
+ addToken(tokenizer, TokenKind.SYMBOL, value, start);
798
729
  }
799
730
  function tokenizeOperator(tokenizer) {
800
731
  const start = tokenizer.position;
@@ -804,7 +735,7 @@ function tokenizeOperator(tokenizer) {
804
735
  value = "'s";
805
736
  advance(tokenizer);
806
737
  advance(tokenizer);
807
- addToken(tokenizer, TokenType.OPERATOR, value, start);
738
+ addToken(tokenizer, TokenKind.OPERATOR, value, start);
808
739
  return;
809
740
  }
810
741
  const twoChar = tokenizer.input.substring(tokenizer.position, tokenizer.position + 2);
@@ -823,17 +754,7 @@ function tokenizeOperator(tokenizer) {
823
754
  else {
824
755
  value = advance(tokenizer);
825
756
  }
826
- let type = TokenType.OPERATOR;
827
- if (COMPARISON_OPERATORS.has(value)) {
828
- type = TokenType.COMPARISON_OPERATOR;
829
- }
830
- else if (['&&', '||'].includes(value)) {
831
- type = TokenType.LOGICAL_OPERATOR;
832
- }
833
- else if (MATHEMATICAL_OPERATORS.has(value)) {
834
- type = TokenType.OPERATOR;
835
- }
836
- addToken(tokenizer, type, value, start);
757
+ addToken(tokenizer, TokenKind.OPERATOR, value, start);
837
758
  }
838
759
  function tokenizeNumberOrTime(tokenizer) {
839
760
  const start = tokenizer.position;
@@ -899,11 +820,11 @@ function tokenizeNumberOrTime(tokenizer) {
899
820
  }
900
821
  }
901
822
  if (TIME_UNITS.has(unit)) {
902
- addToken(tokenizer, TokenType.TIME_EXPRESSION, value + unit, start);
823
+ addToken(tokenizer, TokenKind.TIME, value + unit, start);
903
824
  }
904
825
  else {
905
826
  tokenizer.position = unitStart;
906
- addToken(tokenizer, TokenType.NUMBER, value, start);
827
+ addToken(tokenizer, TokenKind.NUMBER, value, start);
907
828
  }
908
829
  }
909
830
  function tokenizeIdentifier(tokenizer) {
@@ -949,7 +870,7 @@ function tokenizeGlobalVariable(tokenizer) {
949
870
  break;
950
871
  }
951
872
  }
952
- addToken(tokenizer, TokenType.GLOBAL_VAR, value, start);
873
+ addToken(tokenizer, TokenKind.IDENTIFIER, value, start);
953
874
  }
954
875
  function tryTokenizeCompoundOperator(tokenizer, firstWord, start) {
955
876
  const lowerFirst = firstWord.toLowerCase();
@@ -959,10 +880,7 @@ function tryTokenizeCompoundOperator(tokenizer, firstWord, start) {
959
880
  }
960
881
  const prevToken = tokenizer.tokens[tokenizer.tokens.length - 1];
961
882
  if (prevToken &&
962
- (prevToken.kind === 'identifier' ||
963
- prevToken.kind === 'id_selector' ||
964
- prevToken.kind === 'class_selector' ||
965
- prevToken.kind === 'context_var')) {
883
+ (prevToken.kind === TokenKind.IDENTIFIER || prevToken.kind === TokenKind.SELECTOR)) {
966
884
  const nextChar = tokenizer.position < tokenizer.input.length ? tokenizer.input[tokenizer.position] : '';
967
885
  if (nextChar === "'" || nextChar === "'") {
968
886
  return false;
@@ -992,17 +910,17 @@ function tryTokenizeCompoundOperator(tokenizer, firstWord, start) {
992
910
  }
993
911
  const longestCompound = tryBuildLongestCompound(tokenizer, lowerFirst, lowerNext);
994
912
  if (longestCompound) {
995
- addToken(tokenizer, TokenType.COMPARISON_OPERATOR, longestCompound, start);
913
+ addToken(tokenizer, TokenKind.OPERATOR, longestCompound, start);
996
914
  return true;
997
915
  }
998
916
  if (COMPARISON_OPERATORS.has(compound)) {
999
- addToken(tokenizer, TokenType.COMPARISON_OPERATOR, compound, start);
917
+ addToken(tokenizer, TokenKind.OPERATOR, compound, start);
1000
918
  return true;
1001
919
  }
1002
920
  }
1003
921
  if (COMPARISON_OPERATORS.has(lowerFirst)) {
1004
922
  tokenizer.position = originalPosition;
1005
- addToken(tokenizer, TokenType.COMPARISON_OPERATOR, firstWord, start);
923
+ addToken(tokenizer, TokenKind.OPERATOR, firstWord, start);
1006
924
  return true;
1007
925
  }
1008
926
  tokenizer.position = originalPosition;
@@ -1049,7 +967,7 @@ function tryBuildCompoundPreposition(tokenizer, firstWord, secondWord, start) {
1049
967
  const lowerFourth = fourthWord.toLowerCase();
1050
968
  if (lowerFourth === 'of') {
1051
969
  const compound = `at the ${lowerThird} of`;
1052
- addToken(tokenizer, TokenType.KEYWORD, compound, start);
970
+ addToken(tokenizer, TokenKind.IDENTIFIER, compound, start);
1053
971
  return true;
1054
972
  }
1055
973
  }
@@ -1075,7 +993,7 @@ function tryBuildCompoundPreposition(tokenizer, firstWord, secondWord, start) {
1075
993
  const lowerThird = thirdWord.toLowerCase();
1076
994
  if (lowerThird === 'of') {
1077
995
  const compound = `at ${lowerSecond} of`;
1078
- addToken(tokenizer, TokenType.KEYWORD, compound, start);
996
+ addToken(tokenizer, TokenKind.IDENTIFIER, compound, start);
1079
997
  return true;
1080
998
  }
1081
999
  tokenizer.position = afterSecondWord;
@@ -1087,36 +1005,18 @@ function tryBuildCompoundPreposition(tokenizer, firstWord, secondWord, start) {
1087
1005
  function classifyIdentifier(value) {
1088
1006
  const lowerValue = value.toLowerCase();
1089
1007
  if (lowerValue === 'include' || lowerValue === 'includes') {
1090
- return TokenType.COMPARISON_OPERATOR;
1008
+ return TokenKind.OPERATOR;
1091
1009
  }
1092
1010
  if (LOGICAL_OPERATORS.has(lowerValue)) {
1093
- return TokenType.LOGICAL_OPERATOR;
1011
+ return TokenKind.OPERATOR;
1094
1012
  }
1095
1013
  if (MATHEMATICAL_OPERATORS.has(value) || MATHEMATICAL_OPERATORS.has(lowerValue)) {
1096
- return TokenType.OPERATOR;
1014
+ return TokenKind.OPERATOR;
1097
1015
  }
1098
1016
  if (COMPARISON_OPERATORS.has(lowerValue)) {
1099
- return TokenType.COMPARISON_OPERATOR;
1017
+ return TokenKind.OPERATOR;
1100
1018
  }
1101
- if (value === 'I') {
1102
- return TokenType.CONTEXT_VAR;
1103
- }
1104
- if (CONTEXT_VARS.has(lowerValue)) {
1105
- return TokenType.CONTEXT_VAR;
1106
- }
1107
- if (COMMANDS.has(lowerValue)) {
1108
- return TokenType.COMMAND;
1109
- }
1110
- if (DOM_EVENTS.has(lowerValue)) {
1111
- return TokenType.EVENT;
1112
- }
1113
- if (['true', 'false', 'null', 'undefined'].includes(lowerValue)) {
1114
- return TokenType.BOOLEAN;
1115
- }
1116
- if (KEYWORDS.has(lowerValue)) {
1117
- return TokenType.KEYWORD;
1118
- }
1119
- return TokenType.IDENTIFIER;
1019
+ return TokenKind.IDENTIFIER;
1120
1020
  }
1121
1021
  function isAlpha(char) {
1122
1022
  return /[a-zA-Z]/.test(char);
@@ -1382,6 +1282,9 @@ class SemanticIntegrationAdapter {
1382
1282
  if (/\btell\b/.test(lowerInput)) {
1383
1283
  return true;
1384
1284
  }
1285
+ if (/\*[a-zA-Z]/.test(input)) {
1286
+ return true;
1287
+ }
1385
1288
  return false;
1386
1289
  }
1387
1290
  trySemanticParse(input) {
@@ -2132,6 +2035,26 @@ function createErrorNode(pos) {
2132
2035
  column: pos.column,
2133
2036
  };
2134
2037
  }
2038
+ function createErrorCommandNode(pos, message, source) {
2039
+ const diagnostic = {
2040
+ message,
2041
+ severity: 'error',
2042
+ code: 'parse-error',
2043
+ line: pos.line,
2044
+ column: pos.column,
2045
+ ...(source && { source }),
2046
+ };
2047
+ return {
2048
+ type: 'command',
2049
+ name: '__ERROR__',
2050
+ args: [],
2051
+ diagnostics: [diagnostic],
2052
+ start: pos.start,
2053
+ end: pos.end,
2054
+ line: pos.line,
2055
+ column: pos.column,
2056
+ };
2057
+ }
2135
2058
  function createProgramNode(statements) {
2136
2059
  debug.parse(`✅ createProgramNode: Called with ${statements.length} statements`);
2137
2060
  if (statements.length === 0) {
@@ -2176,10 +2099,10 @@ function isKeyword(token, keywords) {
2176
2099
  return keywords.some(kw => token.value === kw || token.value.toLowerCase() === kw);
2177
2100
  }
2178
2101
  const DEFAULT_BOUNDARY_KEYWORDS = [
2179
- KEYWORDS$1.THEN,
2180
- KEYWORDS$1.AND,
2181
- KEYWORDS$1.ELSE,
2182
- KEYWORDS$1.END,
2102
+ KEYWORDS.THEN,
2103
+ KEYWORDS.AND,
2104
+ KEYWORDS.ELSE,
2105
+ KEYWORDS.END,
2183
2106
  ];
2184
2107
  function isCommandBoundary(ctx, additionalBoundaries = []) {
2185
2108
  if (ctx.isAtEnd()) {
@@ -2489,21 +2412,21 @@ function parseTriggerCommand(ctx, identifierNode) {
2489
2412
 
2490
2413
  function parseHaltCommand(ctx, identifierNode) {
2491
2414
  const args = [];
2492
- if (ctx.check(KEYWORDS$1.THE)) {
2415
+ if (ctx.check(KEYWORDS.THE)) {
2493
2416
  const theToken = ctx.advance();
2494
2417
  args.push({
2495
2418
  type: 'identifier',
2496
- name: KEYWORDS$1.THE,
2419
+ name: KEYWORDS.THE,
2497
2420
  start: theToken.start,
2498
2421
  end: theToken.end,
2499
2422
  line: theToken.line,
2500
2423
  column: theToken.column,
2501
2424
  });
2502
- if (ctx.check(KEYWORDS$1.EVENT)) {
2425
+ if (ctx.check(KEYWORDS.EVENT)) {
2503
2426
  const eventToken = ctx.advance();
2504
2427
  args.push({
2505
2428
  type: 'identifier',
2506
- name: KEYWORDS$1.EVENT,
2429
+ name: KEYWORDS.EVENT,
2507
2430
  start: eventToken.start,
2508
2431
  end: eventToken.end,
2509
2432
  line: eventToken.line,
@@ -2525,34 +2448,34 @@ function parseRepeatCommand(ctx, commandToken) {
2525
2448
  let collection = null;
2526
2449
  let variable = null;
2527
2450
  let times = null;
2528
- if (ctx.check(KEYWORDS$1.FOR)) {
2451
+ if (ctx.check(KEYWORDS.FOR)) {
2529
2452
  ctx.advance();
2530
- loopType = KEYWORDS$1.FOR;
2453
+ loopType = KEYWORDS.FOR;
2531
2454
  const identToken = ctx.peek();
2532
2455
  if (isIdentifierLike(identToken)) {
2533
2456
  variable = identToken.value;
2534
2457
  ctx.advance();
2535
2458
  }
2536
- if (ctx.check(KEYWORDS$1.IN)) {
2459
+ if (ctx.check(KEYWORDS.IN)) {
2537
2460
  ctx.advance();
2538
2461
  collection = ctx.parseExpression();
2539
2462
  }
2540
2463
  }
2541
- else if (ctx.check(KEYWORDS$1.IN)) {
2464
+ else if (ctx.check(KEYWORDS.IN)) {
2542
2465
  ctx.advance();
2543
- loopType = KEYWORDS$1.FOR;
2466
+ loopType = KEYWORDS.FOR;
2544
2467
  variable = 'it';
2545
2468
  collection = ctx.parseExpression();
2546
2469
  }
2547
- else if (ctx.check(KEYWORDS$1.WHILE)) {
2470
+ else if (ctx.check(KEYWORDS.WHILE)) {
2548
2471
  ctx.advance();
2549
- loopType = KEYWORDS$1.WHILE;
2472
+ loopType = KEYWORDS.WHILE;
2550
2473
  condition = ctx.parseExpression();
2551
2474
  }
2552
- else if (ctx.check(KEYWORDS$1.UNTIL)) {
2475
+ else if (ctx.check(KEYWORDS.UNTIL)) {
2553
2476
  ctx.advance();
2554
- loopType = KEYWORDS$1.UNTIL;
2555
- if (ctx.check(KEYWORDS$1.EVENT)) {
2477
+ loopType = KEYWORDS.UNTIL;
2478
+ if (ctx.check(KEYWORDS.EVENT)) {
2556
2479
  ctx.advance();
2557
2480
  loopType = 'until-event';
2558
2481
  const eventToken = ctx.peek();
@@ -2569,11 +2492,11 @@ function parseRepeatCommand(ctx, commandToken) {
2569
2492
  throw new Error('Expected event name after "event"');
2570
2493
  }
2571
2494
  debug.parse('🔍 Checking for "from", current token:', ctx.peek().value);
2572
- if (ctx.check(KEYWORDS$1.FROM)) {
2495
+ if (ctx.check(KEYWORDS.FROM)) {
2573
2496
  debug.parse('✅ Found "from", advancing...');
2574
2497
  ctx.advance();
2575
2498
  debug.parse('📍 After consuming "from", current token:', ctx.peek().value);
2576
- if (consumeOptionalKeyword(ctx, KEYWORDS$1.THE)) {
2499
+ if (consumeOptionalKeyword(ctx, KEYWORDS.THE)) {
2577
2500
  debug.parse('✅ Found "the", advancing...');
2578
2501
  }
2579
2502
  const beforePrimary = ctx.peek();
@@ -2593,27 +2516,27 @@ function parseRepeatCommand(ctx, commandToken) {
2593
2516
  condition = ctx.parseExpression();
2594
2517
  }
2595
2518
  }
2596
- else if (ctx.check(KEYWORDS$1.FOREVER)) {
2519
+ else if (ctx.check(KEYWORDS.FOREVER)) {
2597
2520
  ctx.advance();
2598
- loopType = KEYWORDS$1.FOREVER;
2521
+ loopType = KEYWORDS.FOREVER;
2599
2522
  }
2600
2523
  else {
2601
2524
  times = ctx.parseExpression();
2602
- if (ctx.check(KEYWORDS$1.TIMES)) {
2525
+ if (ctx.check(KEYWORDS.TIMES)) {
2603
2526
  ctx.advance();
2604
- loopType = KEYWORDS$1.TIMES;
2527
+ loopType = KEYWORDS.TIMES;
2605
2528
  }
2606
2529
  }
2607
2530
  let indexVariable = null;
2608
- if (ctx.check(KEYWORDS$1.WITH)) {
2531
+ if (ctx.check(KEYWORDS.WITH)) {
2609
2532
  const nextToken = ctx.peekAt(1);
2610
- if (nextToken && nextToken.value.toLowerCase() === KEYWORDS$1.INDEX) {
2533
+ if (nextToken && nextToken.value.toLowerCase() === KEYWORDS.INDEX) {
2611
2534
  ctx.advance();
2612
2535
  ctx.advance();
2613
- indexVariable = KEYWORDS$1.INDEX;
2536
+ indexVariable = KEYWORDS.INDEX;
2614
2537
  }
2615
2538
  }
2616
- else if (ctx.check(KEYWORDS$1.INDEX)) {
2539
+ else if (ctx.check(KEYWORDS.INDEX)) {
2617
2540
  ctx.advance();
2618
2541
  const indexToken = ctx.peek();
2619
2542
  if (isIdentifierLike(indexToken)) {
@@ -2621,7 +2544,7 @@ function parseRepeatCommand(ctx, commandToken) {
2621
2544
  ctx.advance();
2622
2545
  }
2623
2546
  else {
2624
- indexVariable = KEYWORDS$1.INDEX;
2547
+ indexVariable = KEYWORDS.INDEX;
2625
2548
  }
2626
2549
  }
2627
2550
  const commands = ctx.parseCommandListUntilEnd();
@@ -2669,14 +2592,14 @@ function parseIfCommand(ctx, commandToken) {
2669
2592
  const maxThenLookahead = 500;
2670
2593
  for (let i = 0; i < maxThenLookahead && !ctx.isAtEnd(); i++) {
2671
2594
  const token = ctx.peek();
2672
- if (token.value === KEYWORDS$1.THEN) {
2595
+ if (token.value === KEYWORDS.THEN) {
2673
2596
  hasThen = true;
2674
2597
  break;
2675
2598
  }
2676
- if (token.value === KEYWORDS$1.END ||
2677
- token.value === KEYWORDS$1.BEHAVIOR ||
2678
- token.value === KEYWORDS$1.DEF ||
2679
- token.value === KEYWORDS$1.ON) {
2599
+ if (token.value === KEYWORDS.END ||
2600
+ token.value === KEYWORDS.BEHAVIOR ||
2601
+ token.value === KEYWORDS.DEF ||
2602
+ token.value === KEYWORDS.ON) {
2680
2603
  break;
2681
2604
  }
2682
2605
  ctx.advance();
@@ -2690,12 +2613,12 @@ function parseIfCommand(ctx, commandToken) {
2690
2613
  while (!ctx.isAtEnd() && ctx.current - savedPosition < maxLookahead) {
2691
2614
  const token = ctx.peek();
2692
2615
  const tokenValue = token.value?.toLowerCase();
2693
- if (tokenValue === KEYWORDS$1.BEHAVIOR ||
2694
- tokenValue === KEYWORDS$1.DEF ||
2695
- tokenValue === KEYWORDS$1.ON) {
2616
+ if (tokenValue === KEYWORDS.BEHAVIOR ||
2617
+ tokenValue === KEYWORDS.DEF ||
2618
+ tokenValue === KEYWORDS.ON) {
2696
2619
  break;
2697
2620
  }
2698
- if (tokenValue === KEYWORDS$1.ELSE || tokenValue === KEYWORDS$1.END) {
2621
+ if (tokenValue === KEYWORDS.ELSE || tokenValue === KEYWORDS.END) {
2699
2622
  if (token.line === ifStatementLine) {
2700
2623
  hasImplicitMultiLineEnd = true;
2701
2624
  }
@@ -2723,7 +2646,7 @@ function parseIfCommand(ctx, commandToken) {
2723
2646
  while (!ctx.isAtEnd() &&
2724
2647
  !ctx.checkIsCommand() &&
2725
2648
  !ctx.isCommand(ctx.peek().value) &&
2726
- !ctx.check(KEYWORDS$1.THEN) &&
2649
+ !ctx.check(KEYWORDS.THEN) &&
2727
2650
  iterations < maxIterations) {
2728
2651
  const beforePos = ctx.savePosition();
2729
2652
  conditionTokens.push(ctx.parseLogicalAnd());
@@ -2755,7 +2678,7 @@ function parseIfCommand(ctx, commandToken) {
2755
2678
  ctx.advance();
2756
2679
  }
2757
2680
  const thenCommands = [];
2758
- while (!ctx.isAtEnd() && !ctx.check(KEYWORDS$1.ELSE) && !ctx.check(KEYWORDS$1.END)) {
2681
+ while (!ctx.isAtEnd() && !ctx.check(KEYWORDS.ELSE) && !ctx.check(KEYWORDS.END)) {
2759
2682
  if (ctx.checkIsCommand() || ctx.isCommand(ctx.peek().value)) {
2760
2683
  ctx.advance();
2761
2684
  const cmd = ctx.parseCommand();
@@ -2777,9 +2700,9 @@ function parseIfCommand(ctx, commandToken) {
2777
2700
  column: commandToken.column,
2778
2701
  }));
2779
2702
  let consumedElseIf = false;
2780
- if (ctx.check(KEYWORDS$1.ELSE)) {
2703
+ if (ctx.check(KEYWORDS.ELSE)) {
2781
2704
  ctx.advance();
2782
- if (ctx.check(KEYWORDS$1.IF)) {
2705
+ if (ctx.check(KEYWORDS.IF)) {
2783
2706
  const ifToken = ctx.peek();
2784
2707
  ctx.advance();
2785
2708
  const elseIfCommand = parseIfCommand(ctx, ifToken);
@@ -2793,7 +2716,7 @@ function parseIfCommand(ctx, commandToken) {
2793
2716
  }
2794
2717
  else {
2795
2718
  const elseCommands = [];
2796
- while (!ctx.isAtEnd() && !ctx.check(KEYWORDS$1.END)) {
2719
+ while (!ctx.isAtEnd() && !ctx.check(KEYWORDS.END)) {
2797
2720
  if (ctx.checkIsCommand() || ctx.isCommand(ctx.peek().value)) {
2798
2721
  ctx.advance();
2799
2722
  const cmd = ctx.parseCommand();
@@ -2814,7 +2737,7 @@ function parseIfCommand(ctx, commandToken) {
2814
2737
  }
2815
2738
  }
2816
2739
  if (!consumedElseIf) {
2817
- ctx.consume(KEYWORDS$1.END, "Expected 'end' after if block");
2740
+ ctx.consume(KEYWORDS.END, "Expected 'end' after if block");
2818
2741
  }
2819
2742
  }
2820
2743
  else {
@@ -2841,7 +2764,7 @@ function parseForCommand(ctx, commandToken) {
2841
2764
  const args = [];
2842
2765
  let variable = null;
2843
2766
  let collection = null;
2844
- if (ctx.check(KEYWORDS$1.EACH)) {
2767
+ if (ctx.check(KEYWORDS.EACH)) {
2845
2768
  ctx.advance();
2846
2769
  }
2847
2770
  const identToken = ctx.peek();
@@ -2852,7 +2775,7 @@ function parseForCommand(ctx, commandToken) {
2852
2775
  else {
2853
2776
  throw new Error('Expected variable name after "for"');
2854
2777
  }
2855
- if (!ctx.check(KEYWORDS$1.IN)) {
2778
+ if (!ctx.check(KEYWORDS.IN)) {
2856
2779
  throw new Error('Expected "in" after variable name in for loop');
2857
2780
  }
2858
2781
  ctx.advance();
@@ -2861,15 +2784,15 @@ function parseForCommand(ctx, commandToken) {
2861
2784
  throw new Error('Expected collection expression after "in"');
2862
2785
  }
2863
2786
  let indexVariable = null;
2864
- if (ctx.check(KEYWORDS$1.WITH)) {
2787
+ if (ctx.check(KEYWORDS.WITH)) {
2865
2788
  const nextToken = ctx.peekAt(1);
2866
- if (nextToken && nextToken.value.toLowerCase() === KEYWORDS$1.INDEX) {
2789
+ if (nextToken && nextToken.value.toLowerCase() === KEYWORDS.INDEX) {
2867
2790
  ctx.advance();
2868
2791
  ctx.advance();
2869
- indexVariable = KEYWORDS$1.INDEX;
2792
+ indexVariable = KEYWORDS.INDEX;
2870
2793
  }
2871
2794
  }
2872
- else if (ctx.check(KEYWORDS$1.INDEX)) {
2795
+ else if (ctx.check(KEYWORDS.INDEX)) {
2873
2796
  ctx.advance();
2874
2797
  const indexToken = ctx.peek();
2875
2798
  if (isIdentifierLike(indexToken)) {
@@ -2877,7 +2800,7 @@ function parseForCommand(ctx, commandToken) {
2877
2800
  ctx.advance();
2878
2801
  }
2879
2802
  else {
2880
- indexVariable = KEYWORDS$1.INDEX;
2803
+ indexVariable = KEYWORDS.INDEX;
2881
2804
  }
2882
2805
  }
2883
2806
  const commands = ctx.parseCommandListUntilEnd();
@@ -2989,7 +2912,7 @@ function parseTransitionCommand(ctx, commandToken) {
2989
2912
  throw new Error('Transition command requires a CSS property');
2990
2913
  }
2991
2914
  args.push(property);
2992
- if (!ctx.check(KEYWORDS$1.TO)) {
2915
+ if (!ctx.check(KEYWORDS.TO)) {
2993
2916
  throw new Error('Expected "to" keyword after property in transition command');
2994
2917
  }
2995
2918
  ctx.advance();
@@ -3000,7 +2923,7 @@ function parseTransitionCommand(ctx, commandToken) {
3000
2923
  const duration = ctx.parsePrimary();
3001
2924
  modifiers['over'] = duration;
3002
2925
  }
3003
- if (ctx.check(KEYWORDS$1.WITH)) {
2926
+ if (ctx.check(KEYWORDS.WITH)) {
3004
2927
  ctx.advance();
3005
2928
  const timingFunction = ctx.parsePrimary();
3006
2929
  modifiers['with'] = timingFunction;
@@ -3014,11 +2937,11 @@ function parseTransitionCommand(ctx, commandToken) {
3014
2937
 
3015
2938
  function parseRemoveCommand(ctx, identifierNode) {
3016
2939
  const args = [];
3017
- const classArg = parseOneArgument(ctx, [KEYWORDS$1.FROM]);
2940
+ const classArg = parseOneArgument(ctx, [KEYWORDS.FROM]);
3018
2941
  if (classArg) {
3019
2942
  args.push(classArg);
3020
2943
  }
3021
- consumeKeywordToArgs(ctx, KEYWORDS$1.FROM, args);
2944
+ consumeKeywordToArgs(ctx, KEYWORDS.FROM, args);
3022
2945
  const targetArg = parseOneArgument(ctx);
3023
2946
  if (targetArg) {
3024
2947
  args.push(targetArg);
@@ -3030,19 +2953,19 @@ function parseRemoveCommand(ctx, identifierNode) {
3030
2953
  }
3031
2954
  function parseToggleCommand(ctx, identifierNode) {
3032
2955
  const args = [];
3033
- if (ctx.check(KEYWORDS$1.BETWEEN)) {
2956
+ if (ctx.check(KEYWORDS.BETWEEN)) {
3034
2957
  ctx.advance();
3035
2958
  args.push(ctx.createIdentifier('between'));
3036
- const firstArg = parseOneArgument(ctx, [KEYWORDS$1.AND]);
2959
+ const firstArg = parseOneArgument(ctx, [KEYWORDS.AND]);
3037
2960
  if (firstArg) {
3038
2961
  args.push(firstArg);
3039
2962
  }
3040
- consumeKeywordToArgs(ctx, KEYWORDS$1.AND, args);
3041
- const secondArg = parseOneArgument(ctx, [KEYWORDS$1.FROM, KEYWORDS$1.ON, KEYWORDS$1.FOR]);
2963
+ consumeKeywordToArgs(ctx, KEYWORDS.AND, args);
2964
+ const secondArg = parseOneArgument(ctx, [KEYWORDS.FROM, KEYWORDS.ON, KEYWORDS.FOR]);
3042
2965
  if (secondArg) {
3043
2966
  args.push(secondArg);
3044
2967
  }
3045
- const preposition = consumeOneOfKeywordsToArgs(ctx, [KEYWORDS$1.FROM, KEYWORDS$1.ON], args);
2968
+ const preposition = consumeOneOfKeywordsToArgs(ctx, [KEYWORDS.FROM, KEYWORDS.ON], args);
3046
2969
  if (preposition) {
3047
2970
  const targetArg = parseOneArgument(ctx);
3048
2971
  if (targetArg) {
@@ -3054,11 +2977,11 @@ function parseToggleCommand(ctx, identifierNode) {
3054
2977
  .endingAt(ctx.getPosition())
3055
2978
  .build();
3056
2979
  }
3057
- const classArg = parseOneArgument(ctx, [KEYWORDS$1.FROM, KEYWORDS$1.ON]);
2980
+ const classArg = parseOneArgument(ctx, [KEYWORDS.FROM, KEYWORDS.ON]);
3058
2981
  if (classArg) {
3059
2982
  args.push(classArg);
3060
2983
  }
3061
- const preposition = consumeOneOfKeywordsToArgs(ctx, [KEYWORDS$1.FROM, KEYWORDS$1.ON], args);
2984
+ const preposition = consumeOneOfKeywordsToArgs(ctx, [KEYWORDS.FROM, KEYWORDS.ON], args);
3062
2985
  if (preposition) {
3063
2986
  const targetArg = parseOneArgument(ctx);
3064
2987
  if (targetArg) {
@@ -3076,12 +2999,12 @@ function parseAddCommand(ctx, commandToken) {
3076
2999
  args.push(ctx.parseCSSObjectLiteral());
3077
3000
  }
3078
3001
  else {
3079
- const classArg = parseOneArgument(ctx, [KEYWORDS$1.TO]);
3002
+ const classArg = parseOneArgument(ctx, [KEYWORDS.TO]);
3080
3003
  if (classArg) {
3081
3004
  args.push(classArg);
3082
3005
  }
3083
3006
  }
3084
- if (ctx.check(KEYWORDS$1.TO)) {
3007
+ if (ctx.check(KEYWORDS.TO)) {
3085
3008
  ctx.advance();
3086
3009
  const targetArg = parseOneArgument(ctx);
3087
3010
  if (targetArg) {
@@ -3114,19 +3037,19 @@ function parsePutCommand(ctx, identifierNode) {
3114
3037
  operation = PUT_OPERATIONS.AT_END_OF;
3115
3038
  }
3116
3039
  else if (operation === PUT_OPERATIONS.AT) {
3117
- if (ctx.check(KEYWORDS$1.START) || ctx.check(KEYWORDS$1.THE)) {
3118
- consumeOptionalKeyword(ctx, KEYWORDS$1.THE);
3119
- if (ctx.check(KEYWORDS$1.START)) {
3040
+ if (ctx.check(KEYWORDS.START) || ctx.check(KEYWORDS.THE)) {
3041
+ consumeOptionalKeyword(ctx, KEYWORDS.THE);
3042
+ if (ctx.check(KEYWORDS.START)) {
3120
3043
  ctx.advance();
3121
- if (ctx.check(KEYWORDS$1.OF)) {
3044
+ if (ctx.check(KEYWORDS.OF)) {
3122
3045
  ctx.advance();
3123
3046
  operation = PUT_OPERATIONS.AT_START_OF;
3124
3047
  }
3125
3048
  }
3126
3049
  }
3127
- else if (ctx.check(KEYWORDS$1.END)) {
3050
+ else if (ctx.check(KEYWORDS.END)) {
3128
3051
  ctx.advance();
3129
- if (ctx.check(KEYWORDS$1.OF)) {
3052
+ if (ctx.check(KEYWORDS.OF)) {
3130
3053
  ctx.advance();
3131
3054
  operation = PUT_OPERATIONS.AT_END_OF;
3132
3055
  }
@@ -3176,7 +3099,7 @@ function parseSwapCommand(ctx, identifierNode) {
3176
3099
  .endingAt(ctx.getPosition())
3177
3100
  .build();
3178
3101
  }
3179
- if (!ctx.isAtEnd() && ctx.check(KEYWORDS$1.OF)) {
3102
+ if (!ctx.isAtEnd() && ctx.check(KEYWORDS.OF)) {
3180
3103
  ctx.advance();
3181
3104
  args.push(ctx.createIdentifier('of'));
3182
3105
  }
@@ -3184,7 +3107,7 @@ function parseSwapCommand(ctx, identifierNode) {
3184
3107
  if (targetExpr) {
3185
3108
  args.push(targetExpr);
3186
3109
  }
3187
- if (!ctx.isAtEnd() && ctx.check(KEYWORDS$1.WITH)) {
3110
+ if (!ctx.isAtEnd() && ctx.check(KEYWORDS.WITH)) {
3188
3111
  ctx.advance();
3189
3112
  args.push(ctx.createIdentifier('with'));
3190
3113
  const contentExpr = ctx.parseExpression();
@@ -3250,9 +3173,9 @@ function parseWaitCommand(ctx, commandToken) {
3250
3173
  }
3251
3174
  } while (!ctx.isAtEnd());
3252
3175
  let eventTarget = null;
3253
- if (ctx.check(KEYWORDS$1.FROM)) {
3176
+ if (ctx.check(KEYWORDS.FROM)) {
3254
3177
  ctx.advance();
3255
- consumeOptionalKeyword(ctx, KEYWORDS$1.THE);
3178
+ consumeOptionalKeyword(ctx, KEYWORDS.THE);
3256
3179
  eventTarget = ctx.parsePrimary();
3257
3180
  }
3258
3181
  const eventPos = {
@@ -3370,7 +3293,7 @@ function parseColonVariable(ctx) {
3370
3293
  };
3371
3294
  }
3372
3295
  function parseScopedVariable(ctx) {
3373
- if (!ctx.check(KEYWORDS$1.GLOBAL) && !ctx.check(KEYWORDS$1.LOCAL))
3296
+ if (!ctx.check(KEYWORDS.GLOBAL) && !ctx.check(KEYWORDS.LOCAL))
3374
3297
  return null;
3375
3298
  const scopeToken = ctx.advance();
3376
3299
  const variableToken = ctx.advance();
@@ -3383,15 +3306,15 @@ function parseScopedVariable(ctx) {
3383
3306
  };
3384
3307
  }
3385
3308
  function parsePropertyOfTarget(ctx, startPosition) {
3386
- if (!ctx.check(KEYWORDS$1.THE))
3309
+ if (!ctx.check(KEYWORDS.THE))
3387
3310
  return null;
3388
3311
  const thePosition = ctx.savePosition();
3389
3312
  ctx.advance();
3390
3313
  const nextToken = ctx.peek();
3391
3314
  const tokenAfterNext = ctx.peekAt(1);
3392
- if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS$1.OF) {
3315
+ if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS.OF) {
3393
3316
  const propertyToken = ctx.advance();
3394
- if (ctx.check(KEYWORDS$1.OF)) {
3317
+ if (ctx.check(KEYWORDS.OF)) {
3395
3318
  ctx.advance();
3396
3319
  const targetToken = ctx.advance();
3397
3320
  const isIdSelector = targetToken.value.startsWith('#');
@@ -3416,7 +3339,7 @@ function parsePropertyOfTarget(ctx, startPosition) {
3416
3339
  ctx.restorePosition(startPosition);
3417
3340
  return null;
3418
3341
  }
3419
- if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS$1.TO) {
3342
+ if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS.TO) {
3420
3343
  const variableToken = ctx.advance();
3421
3344
  return {
3422
3345
  type: 'identifier',
@@ -3444,11 +3367,11 @@ function parseTargetFallback(ctx) {
3444
3367
  }
3445
3368
  const targetTokens = [];
3446
3369
  while (!ctx.isAtEnd() &&
3447
- !ctx.check(KEYWORDS$1.TO) &&
3448
- !ctx.check(KEYWORDS$1.THEN) &&
3449
- !ctx.check(KEYWORDS$1.AND) &&
3450
- !ctx.check(KEYWORDS$1.ELSE) &&
3451
- !ctx.check(KEYWORDS$1.END)) {
3370
+ !ctx.check(KEYWORDS.TO) &&
3371
+ !ctx.check(KEYWORDS.THEN) &&
3372
+ !ctx.check(KEYWORDS.AND) &&
3373
+ !ctx.check(KEYWORDS.ELSE) &&
3374
+ !ctx.check(KEYWORDS.END)) {
3452
3375
  targetTokens.push(ctx.parsePrimary());
3453
3376
  }
3454
3377
  if (targetTokens.length === 0) {
@@ -3456,8 +3379,8 @@ function parseTargetFallback(ctx) {
3456
3379
  }
3457
3380
  if (targetTokens.length >= 4) {
3458
3381
  const nodeStr = (node, key) => node[key];
3459
- if (nodeStr(targetTokens[0], 'value') === KEYWORDS$1.THE &&
3460
- nodeStr(targetTokens[2], 'value') === KEYWORDS$1.OF) {
3382
+ if (nodeStr(targetTokens[0], 'value') === KEYWORDS.THE &&
3383
+ nodeStr(targetTokens[2], 'value') === KEYWORDS.OF) {
3461
3384
  const propToken = targetTokens[1];
3462
3385
  const targetToken = targetTokens[3];
3463
3386
  return {
@@ -3510,7 +3433,7 @@ function parseSetCommand(ctx, identifierNode) {
3510
3433
  targetExpression = fallback.expression;
3511
3434
  fallbackTokens = fallback.tokens;
3512
3435
  }
3513
- if (!ctx.check(KEYWORDS$1.TO)) {
3436
+ if (!ctx.check(KEYWORDS.TO)) {
3514
3437
  const found = ctx.isAtEnd() ? 'end of input' : ctx.peek().value;
3515
3438
  throw new Error(`Expected 'to' in set command, found: ${found}`);
3516
3439
  }
@@ -3523,7 +3446,7 @@ function parseSetCommand(ctx, identifierNode) {
3523
3446
  else if (fallbackTokens.length > 0) {
3524
3447
  finalArgs.push(...fallbackTokens);
3525
3448
  }
3526
- finalArgs.push(ctx.createIdentifier(KEYWORDS$1.TO));
3449
+ finalArgs.push(ctx.createIdentifier(KEYWORDS.TO));
3527
3450
  if (value) {
3528
3451
  finalArgs.push(value);
3529
3452
  }
@@ -3537,7 +3460,7 @@ function parseIncrementDecrementCommand(ctx, commandToken) {
3537
3460
  const isIncrement = commandName === 'increment';
3538
3461
  const operator = isIncrement ? '+' : '-';
3539
3462
  let hasGlobal = false;
3540
- if (ctx.check(KEYWORDS$1.GLOBAL)) {
3463
+ if (ctx.check(KEYWORDS.GLOBAL)) {
3541
3464
  hasGlobal = true;
3542
3465
  ctx.advance();
3543
3466
  }
@@ -3546,7 +3469,7 @@ function parseIncrementDecrementCommand(ctx, commandToken) {
3546
3469
  throw new Error(`Expected variable or expression after ${commandName}`);
3547
3470
  }
3548
3471
  let amount;
3549
- if (ctx.check(KEYWORDS$1.BY)) {
3472
+ if (ctx.check(KEYWORDS.BY)) {
3550
3473
  ctx.advance();
3551
3474
  const parsedAmount = ctx.parseExpression();
3552
3475
  if (!parsedAmount) {
@@ -3577,7 +3500,7 @@ function parseIncrementDecrementCommand(ctx, commandToken) {
3577
3500
  column: commandToken.column,
3578
3501
  };
3579
3502
  const binaryExpr = createBinaryExpression(operator, target, amount, pos);
3580
- const toIdentifier = createIdentifier(KEYWORDS$1.TO, pos);
3503
+ const toIdentifier = createIdentifier(KEYWORDS.TO, pos);
3581
3504
  const args = [targetWithScope, toIdentifier, binaryExpr];
3582
3505
  return CommandNodeBuilder.from(commandToken)
3583
3506
  .withName('set')
@@ -3794,12 +3717,12 @@ function parseJsCommand(ctx, identifierNode) {
3794
3717
  ctx.consume(')', 'Expected ) after js parameters');
3795
3718
  }
3796
3719
  const jsCodeStart = ctx.peek().start;
3797
- while (!ctx.check(KEYWORDS$1.END) && !ctx.isAtEnd()) {
3720
+ while (!ctx.check(KEYWORDS.END) && !ctx.isAtEnd()) {
3798
3721
  ctx.advance();
3799
3722
  }
3800
3723
  const endToken = ctx.peek();
3801
3724
  const jsCodeEnd = endToken.start;
3802
- ctx.consume(KEYWORDS$1.END, 'Expected end after js code body');
3725
+ ctx.consume(KEYWORDS.END, 'Expected end after js code body');
3803
3726
  const rawSlice = ctx.getInputSlice(jsCodeStart, jsCodeEnd);
3804
3727
  const code = rawSlice.trim();
3805
3728
  const codeNode = {
@@ -3845,10 +3768,10 @@ function parseTellCommand(ctx, identifierNode) {
3845
3768
  catch {
3846
3769
  break;
3847
3770
  }
3848
- if (ctx.match(KEYWORDS$1.AND)) {
3771
+ if (ctx.match(KEYWORDS.AND)) {
3849
3772
  continue;
3850
3773
  }
3851
- if (ctx.check(KEYWORDS$1.THEN) || ctx.check(KEYWORDS$1.ELSE) || ctx.check(KEYWORDS$1.END)) {
3774
+ if (ctx.check(KEYWORDS.THEN) || ctx.check(KEYWORDS.ELSE) || ctx.check(KEYWORDS.END)) {
3852
3775
  break;
3853
3776
  }
3854
3777
  if (ctx.checkIsCommand()) {
@@ -3869,6 +3792,292 @@ function parseTellCommand(ctx, identifierNode) {
3869
3792
  .build();
3870
3793
  }
3871
3794
 
3795
+ const STOP_TOKENS = new Set([
3796
+ 'then',
3797
+ 'end',
3798
+ 'to',
3799
+ 'into',
3800
+ 'on',
3801
+ 'with',
3802
+ 'from',
3803
+ 'in',
3804
+ 'by',
3805
+ 'for',
3806
+ 'while',
3807
+ 'until',
3808
+ 'unless',
3809
+ 'else',
3810
+ 'catch',
3811
+ 'finally',
3812
+ ]);
3813
+ const STOP_DELIMITERS = new Set([')', ']', '}', ',']);
3814
+ function mergeFragments(...fragments) {
3815
+ const merged = new Map();
3816
+ for (const fragment of fragments) {
3817
+ for (const [key, entry] of fragment) {
3818
+ const existing = merged.get(key);
3819
+ if (existing) {
3820
+ merged.set(key, {
3821
+ prefix: entry.prefix ?? existing.prefix,
3822
+ infix: entry.infix ?? existing.infix,
3823
+ });
3824
+ }
3825
+ else {
3826
+ merged.set(key, { ...entry });
3827
+ }
3828
+ }
3829
+ }
3830
+ return merged;
3831
+ }
3832
+ function leftAssoc(bp, handler) {
3833
+ return {
3834
+ infix: {
3835
+ bp: [bp, bp + 1],
3836
+ handler: handler ??
3837
+ ((left, token, ctx) => ({
3838
+ type: 'binaryExpression',
3839
+ operator: token.value,
3840
+ left,
3841
+ right: ctx.parseExpr(bp + 1),
3842
+ start: left.start,
3843
+ })),
3844
+ },
3845
+ };
3846
+ }
3847
+ function rightAssoc(bp, handler) {
3848
+ return {
3849
+ infix: {
3850
+ bp: [bp + 1, bp],
3851
+ handler: ((left, token, ctx) => ({
3852
+ type: 'binaryExpression',
3853
+ operator: token.value,
3854
+ left,
3855
+ right: ctx.parseExpr(bp),
3856
+ start: left.start,
3857
+ })),
3858
+ },
3859
+ };
3860
+ }
3861
+ function prefix(bp, handler) {
3862
+ return {
3863
+ prefix: {
3864
+ bp,
3865
+ handler: handler ??
3866
+ ((token, ctx) => ({
3867
+ type: 'unaryExpression',
3868
+ operator: token.value,
3869
+ operand: ctx.parseExpr(bp),
3870
+ start: token.start,
3871
+ })),
3872
+ },
3873
+ };
3874
+ }
3875
+ const CORE_FRAGMENT = new Map([
3876
+ ['or', leftAssoc(10)],
3877
+ ['||', leftAssoc(10)],
3878
+ ['and', leftAssoc(20)],
3879
+ ['&&', leftAssoc(20)],
3880
+ ['==', leftAssoc(30)],
3881
+ ['!=', leftAssoc(30)],
3882
+ ['<', leftAssoc(30)],
3883
+ ['>', leftAssoc(30)],
3884
+ ['<=', leftAssoc(30)],
3885
+ ['>=', leftAssoc(30)],
3886
+ ['is', leftAssoc(30)],
3887
+ ['matches', leftAssoc(30)],
3888
+ ['contains', leftAssoc(30)],
3889
+ ['+', { ...leftAssoc(40), ...prefix(80) }],
3890
+ ['-', { ...leftAssoc(40), ...prefix(80) }],
3891
+ ['*', leftAssoc(50)],
3892
+ ['/', leftAssoc(50)],
3893
+ ['%', leftAssoc(50)],
3894
+ ['mod', leftAssoc(50)],
3895
+ ['^', rightAssoc(60)],
3896
+ ['**', rightAssoc(60)],
3897
+ [
3898
+ 'as',
3899
+ leftAssoc(70, (left, _token, ctx) => ({
3900
+ type: 'asExpression',
3901
+ expression: left,
3902
+ targetType: ctx.parseExpr(71),
3903
+ start: left.start,
3904
+ })),
3905
+ ],
3906
+ ['not', prefix(80)],
3907
+ ['!', prefix(80)],
3908
+ ['no', prefix(80)],
3909
+ ]);
3910
+ const POSITIONAL_FRAGMENT = new Map([
3911
+ [
3912
+ 'first',
3913
+ prefix(85, (token, ctx) => ({
3914
+ type: 'positionalExpression',
3915
+ position: 'first',
3916
+ operand: ctx.parseExpr(85),
3917
+ start: token.start,
3918
+ })),
3919
+ ],
3920
+ [
3921
+ 'last',
3922
+ prefix(85, (token, ctx) => ({
3923
+ type: 'positionalExpression',
3924
+ position: 'last',
3925
+ operand: ctx.parseExpr(85),
3926
+ start: token.start,
3927
+ })),
3928
+ ],
3929
+ ]);
3930
+ const PROPERTY_FRAGMENT = new Map([
3931
+ [
3932
+ '.',
3933
+ {
3934
+ infix: {
3935
+ bp: [90, 91],
3936
+ handler: (left, _token, ctx) => {
3937
+ const propToken = ctx.advance();
3938
+ return {
3939
+ type: 'propertyAccess',
3940
+ object: left,
3941
+ property: propToken.value,
3942
+ start: left.start,
3943
+ };
3944
+ },
3945
+ },
3946
+ },
3947
+ ],
3948
+ [
3949
+ '?.',
3950
+ {
3951
+ infix: {
3952
+ bp: [90, 91],
3953
+ handler: (left, _token, ctx) => {
3954
+ const propToken = ctx.advance();
3955
+ return {
3956
+ type: 'optionalChain',
3957
+ object: left,
3958
+ property: propToken.value,
3959
+ start: left.start,
3960
+ };
3961
+ },
3962
+ },
3963
+ },
3964
+ ],
3965
+ [
3966
+ "'s",
3967
+ {
3968
+ infix: {
3969
+ bp: [95, 96],
3970
+ handler: (left, _token, ctx) => {
3971
+ const propToken = ctx.advance();
3972
+ return {
3973
+ type: 'possessiveExpression',
3974
+ object: left,
3975
+ property: propToken.value,
3976
+ start: left.start,
3977
+ };
3978
+ },
3979
+ },
3980
+ },
3981
+ ],
3982
+ ]);
3983
+ const PARSER_COMPARISON_FRAGMENT = new Map([
3984
+ ['===', leftAssoc(30)],
3985
+ ['!==', leftAssoc(30)],
3986
+ ['is not', leftAssoc(30)],
3987
+ ['is a', leftAssoc(30)],
3988
+ ['is an', leftAssoc(30)],
3989
+ ['is not a', leftAssoc(30)],
3990
+ ['is not an', leftAssoc(30)],
3991
+ ['is in', leftAssoc(30)],
3992
+ ['is not in', leftAssoc(30)],
3993
+ ['has', leftAssoc(30)],
3994
+ ['have', leftAssoc(30)],
3995
+ ['match', leftAssoc(30)],
3996
+ ['include', leftAssoc(30)],
3997
+ ['includes', leftAssoc(30)],
3998
+ ['equals', leftAssoc(30)],
3999
+ ['does not contain', leftAssoc(30)],
4000
+ ['does not include', leftAssoc(30)],
4001
+ ['in', leftAssoc(30)],
4002
+ ['of', leftAssoc(30)],
4003
+ ['really', leftAssoc(30)],
4004
+ [
4005
+ 'exists',
4006
+ {
4007
+ prefix: {
4008
+ bp: 80,
4009
+ handler: (token, ctx) => ({
4010
+ type: 'unaryExpression',
4011
+ operator: token.value,
4012
+ operand: ctx.parseExpr(80),
4013
+ start: token.start,
4014
+ }),
4015
+ },
4016
+ infix: {
4017
+ bp: [30, 31],
4018
+ handler: (left, token) => ({
4019
+ type: 'unaryExpression',
4020
+ operator: token.value,
4021
+ operand: left,
4022
+ prefix: false,
4023
+ start: left.start,
4024
+ }),
4025
+ },
4026
+ },
4027
+ ],
4028
+ [
4029
+ 'does not exist',
4030
+ {
4031
+ infix: {
4032
+ bp: [30, 31],
4033
+ handler: (left, token) => ({
4034
+ type: 'unaryExpression',
4035
+ operator: token.value,
4036
+ operand: left,
4037
+ prefix: false,
4038
+ start: left.start,
4039
+ }),
4040
+ },
4041
+ },
4042
+ ],
4043
+ [
4044
+ 'is empty',
4045
+ {
4046
+ infix: {
4047
+ bp: [30, 31],
4048
+ handler: (left, token) => ({
4049
+ type: 'unaryExpression',
4050
+ operator: token.value,
4051
+ operand: left,
4052
+ prefix: false,
4053
+ start: left.start,
4054
+ }),
4055
+ },
4056
+ },
4057
+ ],
4058
+ [
4059
+ 'is not empty',
4060
+ {
4061
+ infix: {
4062
+ bp: [30, 31],
4063
+ handler: (left, token) => ({
4064
+ type: 'unaryExpression',
4065
+ operator: token.value,
4066
+ operand: left,
4067
+ prefix: false,
4068
+ start: left.start,
4069
+ }),
4070
+ },
4071
+ },
4072
+ ],
4073
+ ['some', prefix(80)],
4074
+ ]);
4075
+ const ASSIGNMENT_FRAGMENT = new Map([
4076
+ ['=', rightAssoc(5)],
4077
+ ]);
4078
+ mergeFragments(CORE_FRAGMENT, POSITIONAL_FRAGMENT, PROPERTY_FRAGMENT);
4079
+ const PARSER_TABLE = mergeFragments(CORE_FRAGMENT, PARSER_COMPARISON_FRAGMENT, ASSIGNMENT_FRAGMENT);
4080
+
3872
4081
  function parseTimeToMs(timeStr) {
3873
4082
  if (timeStr.endsWith('ms'))
3874
4083
  return parseInt(timeStr, 10);
@@ -3887,7 +4096,9 @@ function parseTimeToMs(timeStr) {
3887
4096
  class Parser {
3888
4097
  constructor(tokens, options, originalInput) {
3889
4098
  this.current = 0;
4099
+ this.errors = [];
3890
4100
  this.warnings = [];
4101
+ this.prattCache = new Map();
3891
4102
  this.tokens = tokens;
3892
4103
  this.keywordResolver = options?.keywords;
3893
4104
  this.registryIntegration = options?.registryIntegration;
@@ -3910,6 +4121,14 @@ class Parser {
3910
4121
  this.warnings.push(warning);
3911
4122
  }
3912
4123
  parse() {
4124
+ this.prattCache.clear();
4125
+ const result = this.parseInternal();
4126
+ if (this.errors.length > 0) {
4127
+ result.errors = [...this.errors];
4128
+ }
4129
+ return result;
4130
+ }
4131
+ parseInternal() {
3913
4132
  try {
3914
4133
  if (this.tokens.length === 0) {
3915
4134
  this.addError('Cannot parse empty input');
@@ -4125,7 +4344,114 @@ class Parser {
4125
4344
  }
4126
4345
  }
4127
4346
  parseExpression() {
4128
- return this.parseAssignment();
4347
+ return this.parseExpressionPratt(0);
4348
+ }
4349
+ parseExpressionPratt(minBp) {
4350
+ const cacheKey = `${this.current}:${minBp}`;
4351
+ const cached = this.prattCache.get(cacheKey);
4352
+ if (cached) {
4353
+ this.current = cached.endPos;
4354
+ return cached.node;
4355
+ }
4356
+ this.current;
4357
+ if (this.isAtEnd()) {
4358
+ this.addError('Unexpected end of expression');
4359
+ return this.createErrorNode();
4360
+ }
4361
+ const firstToken = this.peek();
4362
+ const prefixEntry = Parser.PRATT_TABLE.get(firstToken.value);
4363
+ let left;
4364
+ if (prefixEntry?.prefix) {
4365
+ const token = this.advance();
4366
+ if (this.isAtEnd()) {
4367
+ this.addError(`Expected expression after '${token.value}' operator`);
4368
+ return this.createErrorNode();
4369
+ }
4370
+ left = prefixEntry.prefix.handler(token, this.makePrattContext());
4371
+ }
4372
+ else {
4373
+ left = this.parseCall();
4374
+ }
4375
+ while (!this.isAtEnd()) {
4376
+ const nextToken = this.peek();
4377
+ const infixEntry = Parser.PRATT_TABLE.get(nextToken.value);
4378
+ if (!infixEntry?.infix) {
4379
+ if (STOP_TOKENS.has(nextToken.value) || STOP_DELIMITERS.has(nextToken.value)) {
4380
+ break;
4381
+ }
4382
+ break;
4383
+ }
4384
+ const [leftBp] = infixEntry.infix.bp;
4385
+ if (leftBp < minBp)
4386
+ break;
4387
+ if (nextToken.value === '=') {
4388
+ if (this.current + 1 < this.tokens.length && this.tokens[this.current + 1].value === '>') {
4389
+ this.advance();
4390
+ this.advance();
4391
+ this.addError('Arrow functions (=>) are not supported in hyperscript. ' +
4392
+ 'Use "js ... end" blocks for JavaScript callbacks.');
4393
+ if (!this.isAtEnd()) {
4394
+ try {
4395
+ this.parseExpressionPratt(0);
4396
+ }
4397
+ catch {
4398
+ }
4399
+ }
4400
+ return this.createErrorNode();
4401
+ }
4402
+ }
4403
+ if (nextToken.value === '+' || nextToken.value === '-') {
4404
+ const afterOp = this.current + 1 < this.tokens.length ? this.tokens[this.current + 1] : null;
4405
+ if (afterOp && (afterOp.value === '+' || afterOp.value === '-')) {
4406
+ this.addError(`Invalid operator combination: ${nextToken.value}${afterOp.value}`);
4407
+ return left;
4408
+ }
4409
+ }
4410
+ if (nextToken.value === '*' || nextToken.value === '/' || nextToken.value === '%') {
4411
+ const afterOp = this.current + 1 < this.tokens.length ? this.tokens[this.current + 1] : null;
4412
+ if (afterOp &&
4413
+ (afterOp.value === '*' ||
4414
+ afterOp.value === '/' ||
4415
+ afterOp.value === '%' ||
4416
+ afterOp.value === '+' ||
4417
+ afterOp.value === '-')) {
4418
+ if (nextToken.value === '*' && afterOp.value === '*') {
4419
+ this.addError(`Unexpected token: ${afterOp.value}`);
4420
+ }
4421
+ else {
4422
+ this.addError(`Invalid operator combination: ${nextToken.value}${afterOp.value}`);
4423
+ }
4424
+ return left;
4425
+ }
4426
+ }
4427
+ const opToken = this.advance();
4428
+ if (this.isAtEnd() && !Parser.POSTFIX_UNARY_OPERATORS.has(opToken.value)) {
4429
+ this.addError(`Expected expression after '${opToken.value}' operator`);
4430
+ return left;
4431
+ }
4432
+ left = infixEntry.infix.handler(left, opToken, this.makePrattContext());
4433
+ }
4434
+ this.prattCache.set(cacheKey, { node: left, endPos: this.current });
4435
+ return left;
4436
+ }
4437
+ makePrattContext() {
4438
+ const self = this;
4439
+ return {
4440
+ peek: () => (self.current < self.tokens.length ? self.tokens[self.current] : undefined),
4441
+ advance: () => {
4442
+ const token = self.tokens[self.current];
4443
+ self.current++;
4444
+ return token;
4445
+ },
4446
+ parseExpr: (bp) => self.parseExpressionPratt(bp),
4447
+ isStopToken: () => {
4448
+ const t = self.tokens[self.current];
4449
+ if (!t)
4450
+ return true;
4451
+ return STOP_TOKENS.has(t.value) || STOP_DELIMITERS.has(t.value);
4452
+ },
4453
+ atEnd: () => self.current >= self.tokens.length,
4454
+ };
4129
4455
  }
4130
4456
  parseAssignment() {
4131
4457
  let expr = this.parseLogicalOr();
@@ -5644,7 +5970,23 @@ class Parser {
5644
5970
  break;
5645
5971
  }
5646
5972
  else {
5647
- this.addError(`Expected command, got: ${this.peek().value}`);
5973
+ const errorToken = this.peek();
5974
+ const errorPos = this.getPosition();
5975
+ const errorMessage = `Expected command, got: ${errorToken.value}`;
5976
+ this.addError(errorMessage);
5977
+ const errorNode = createErrorCommandNode(errorPos, errorMessage, errorToken.value);
5978
+ commands.push(errorNode);
5979
+ this.synchronizeToCommandBoundary();
5980
+ if (this.isAtEnd())
5981
+ break;
5982
+ if (this.match('then'))
5983
+ continue;
5984
+ if (this.check('end') || this.check('on'))
5985
+ break;
5986
+ if (this.checkIsCommand() ||
5987
+ (this.isCommand(this.peek().value) && !this.isKeyword(this.peek().value))) {
5988
+ continue;
5989
+ }
5648
5990
  break;
5649
5991
  }
5650
5992
  }
@@ -6275,6 +6617,20 @@ class Parser {
6275
6617
  column: Math.max(1, column),
6276
6618
  position: Math.max(0, position),
6277
6619
  };
6620
+ this.errors.push(this.error);
6621
+ }
6622
+ synchronizeToCommandBoundary() {
6623
+ while (!this.isAtEnd()) {
6624
+ const token = this.peek();
6625
+ if (token.value === 'then' || token.value === 'end' || token.value === 'on') {
6626
+ return;
6627
+ }
6628
+ if (this.checkIsCommand() || (this.isCommand(token.value) && !this.isKeyword(token.value))) {
6629
+ return;
6630
+ }
6631
+ debug.parse('⚠️ synchronize: Skipping token:', token.value);
6632
+ this.advance();
6633
+ }
6278
6634
  }
6279
6635
  parseAttributeOrArrayLiteral() {
6280
6636
  const startPos = this.previous().start;
@@ -6425,6 +6781,7 @@ Parser.POSTFIX_UNARY_OPERATORS = new Set([
6425
6781
  'is empty',
6426
6782
  'is not empty',
6427
6783
  ]);
6784
+ Parser.PRATT_TABLE = PARSER_TABLE;
6428
6785
  Parser.PSEUDO_COMMAND_PREPOSITIONS = ['from', 'on', 'with', 'into', 'at', 'to'];
6429
6786
 
6430
6787
  class FullParserImpl {