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