@hyperfixi/core 2.0.0 → 2.1.0

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 (62) hide show
  1. package/dist/api/hyperscript-api.d.ts +2 -0
  2. package/dist/ast-utils/index.d.ts +1 -1
  3. package/dist/ast-utils/index.js +11 -1
  4. package/dist/ast-utils/index.mjs +11 -1
  5. package/dist/ast-utils/interchange/index.d.ts +1 -1
  6. package/dist/ast-utils/interchange/lsp.d.ts +4 -1
  7. package/dist/behaviors/index.js +13 -5
  8. package/dist/behaviors/index.mjs +13 -5
  9. package/dist/bundle-generator/index.js +9 -0
  10. package/dist/bundle-generator/index.mjs +9 -0
  11. package/dist/chunks/{bridge-I6ceoWxV.js → bridge-CZfeDyEz.js} +2 -2
  12. package/dist/chunks/browser-modular-CwTpxqdt.js +2 -0
  13. package/dist/chunks/feature-eventsource-B5F2-H1r.js +2 -0
  14. package/dist/chunks/feature-sockets-ClOH7vk7.js +2 -0
  15. package/dist/chunks/feature-webworker-3bAp0ac9.js +2 -0
  16. package/dist/commands/index.js +27 -6
  17. package/dist/commands/index.mjs +27 -6
  18. package/dist/debug/debug-controller.d.ts +62 -0
  19. package/dist/debug/index.d.ts +5 -0
  20. package/dist/expressions/index.js +16 -52
  21. package/dist/expressions/index.mjs +16 -52
  22. package/dist/hyperfixi-classic-i18n.js +1 -1
  23. package/dist/hyperfixi-hx.js +1 -1
  24. package/dist/hyperfixi-hybrid-complete.js +1 -1
  25. package/dist/hyperfixi-minimal.js +1 -1
  26. package/dist/hyperfixi-multilingual.js +1 -1
  27. package/dist/hyperfixi-standard.js +1 -1
  28. package/dist/hyperfixi.js +1 -1
  29. package/dist/hyperfixi.mjs +1 -1
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.js +10112 -6941
  32. package/dist/index.min.js +1 -1
  33. package/dist/index.mjs +10111 -6942
  34. package/dist/lokascript-browser-classic-i18n.js +1 -1
  35. package/dist/lokascript-browser-minimal.js +1 -1
  36. package/dist/lokascript-browser-standard.js +1 -1
  37. package/dist/lokascript-browser.js +1 -1
  38. package/dist/lokascript-hybrid-complete.js +1 -1
  39. package/dist/lokascript-hybrid-hx.js +1 -1
  40. package/dist/lokascript-multilingual.js +1 -1
  41. package/dist/metadata.d.ts +4 -4
  42. package/dist/metadata.js +4 -4
  43. package/dist/metadata.mjs +4 -4
  44. package/dist/parser/full-parser.js +12 -31
  45. package/dist/parser/full-parser.mjs +12 -31
  46. package/dist/parser/hybrid/index.js +35 -2
  47. package/dist/parser/hybrid/index.mjs +35 -2
  48. package/dist/parser/hybrid/parser-core.d.ts +1 -0
  49. package/dist/parser/hybrid/parser-core.js +35 -2
  50. package/dist/parser/hybrid/parser-core.mjs +35 -2
  51. package/dist/parser/hybrid/tokenizer.js +5 -0
  52. package/dist/parser/hybrid/tokenizer.mjs +5 -0
  53. package/dist/parser/hybrid-parser.js +35 -2
  54. package/dist/parser/hybrid-parser.mjs +35 -2
  55. package/dist/registry/index.js +16 -52
  56. package/dist/registry/index.mjs +16 -52
  57. package/dist/runtime/runtime-base.d.ts +1 -0
  58. package/package.json +5 -5
  59. package/dist/chunks/browser-modular-Dv6PAV3c.js +0 -2
  60. package/dist/chunks/feature-eventsource-DWb514fy.js +0 -2
  61. package/dist/chunks/feature-sockets-3PFuvCVY.js +0 -2
  62. package/dist/chunks/feature-webworker-DTm_eh-E.js +0 -2
@@ -79,14 +79,14 @@ export declare const ecosystem: {
79
79
  readonly npm: "https://www.npmjs.com/package/@hyperfixi/vite-plugin";
80
80
  };
81
81
  readonly patternsReference: {
82
- readonly name: "@lokascript/patterns-reference";
82
+ readonly name: "@hyperfixi/patterns-reference";
83
83
  readonly description: "Pattern database with 212 LLM examples";
84
- readonly npm: "https://www.npmjs.com/package/@lokascript/patterns-reference";
84
+ readonly npm: "https://www.npmjs.com/package/@hyperfixi/patterns-reference";
85
85
  };
86
86
  readonly mcpServer: {
87
- readonly name: "@lokascript/mcp-server";
87
+ readonly name: "@hyperfixi/mcp-server";
88
88
  readonly description: "Model Context Protocol server for AI assistants";
89
- readonly npm: "https://www.npmjs.com/package/@lokascript/mcp-server";
89
+ readonly npm: "https://www.npmjs.com/package/@hyperfixi/mcp-server";
90
90
  };
91
91
  };
92
92
  export declare const supportedLanguages: readonly [{
package/dist/metadata.js CHANGED
@@ -329,14 +329,14 @@ const ecosystem = {
329
329
  npm: 'https://www.npmjs.com/package/@hyperfixi/vite-plugin',
330
330
  },
331
331
  patternsReference: {
332
- name: '@lokascript/patterns-reference',
332
+ name: '@hyperfixi/patterns-reference',
333
333
  description: 'Pattern database with 212 LLM examples',
334
- npm: 'https://www.npmjs.com/package/@lokascript/patterns-reference',
334
+ npm: 'https://www.npmjs.com/package/@hyperfixi/patterns-reference',
335
335
  },
336
336
  mcpServer: {
337
- name: '@lokascript/mcp-server',
337
+ name: '@hyperfixi/mcp-server',
338
338
  description: 'Model Context Protocol server for AI assistants',
339
- npm: 'https://www.npmjs.com/package/@lokascript/mcp-server',
339
+ npm: 'https://www.npmjs.com/package/@hyperfixi/mcp-server',
340
340
  },
341
341
  };
342
342
  const supportedLanguages = [
package/dist/metadata.mjs CHANGED
@@ -327,14 +327,14 @@ const ecosystem = {
327
327
  npm: 'https://www.npmjs.com/package/@hyperfixi/vite-plugin',
328
328
  },
329
329
  patternsReference: {
330
- name: '@lokascript/patterns-reference',
330
+ name: '@hyperfixi/patterns-reference',
331
331
  description: 'Pattern database with 212 LLM examples',
332
- npm: 'https://www.npmjs.com/package/@lokascript/patterns-reference',
332
+ npm: 'https://www.npmjs.com/package/@hyperfixi/patterns-reference',
333
333
  },
334
334
  mcpServer: {
335
- name: '@lokascript/mcp-server',
335
+ name: '@hyperfixi/mcp-server',
336
336
  description: 'Model Context Protocol server for AI assistants',
337
- npm: 'https://www.npmjs.com/package/@lokascript/mcp-server',
337
+ npm: 'https://www.npmjs.com/package/@hyperfixi/mcp-server',
338
338
  },
339
339
  };
340
340
  const supportedLanguages = [
@@ -4744,6 +4744,17 @@ class Parser {
4744
4744
  if (token.value === 'the') {
4745
4745
  return this.parseTheXofY();
4746
4746
  }
4747
+ if (token.value === 'values' && this.check('of')) {
4748
+ this.advance();
4749
+ const target = this.parsePrimary();
4750
+ return {
4751
+ type: 'propertyOfExpression',
4752
+ property: { type: 'identifier', name: 'values' },
4753
+ target,
4754
+ line: token.line,
4755
+ column: token.column,
4756
+ };
4757
+ }
4747
4758
  return this.createIdentifier(token.value);
4748
4759
  }
4749
4760
  if (this.match('$')) {
@@ -5549,36 +5560,7 @@ class Parser {
5549
5560
  }
5550
5561
  }
5551
5562
  }
5552
- const handlerCommands = [];
5553
- while (!this.isAtEnd() && !this.check('end')) {
5554
- if (this.checkIsCommand() || this.isCommand(this.peek().value)) {
5555
- this.advance();
5556
- const savedError = this.error;
5557
- try {
5558
- const cmd = this.parseCommand();
5559
- if (this.error && this.error !== savedError) {
5560
- this.error = savedError;
5561
- }
5562
- handlerCommands.push(cmd);
5563
- while (!this.isAtEnd() &&
5564
- !this.check('end') &&
5565
- !this.checkIsCommand() &&
5566
- !this.isCommand(this.peek().value)) {
5567
- this.advance();
5568
- }
5569
- }
5570
- catch (error) {
5571
- this.error = savedError;
5572
- break;
5573
- }
5574
- }
5575
- else {
5576
- if (!this.check('end')) {
5577
- this.addError(`Unexpected token in event handler: ${this.peek().value}`);
5578
- }
5579
- break;
5580
- }
5581
- }
5563
+ const handlerCommands = this.parseCommandListUntilEnd();
5582
5564
  const handlerNode = {
5583
5565
  type: 'eventHandler',
5584
5566
  event: eventName,
@@ -5591,7 +5573,6 @@ class Parser {
5591
5573
  column: handlerPos.column,
5592
5574
  };
5593
5575
  eventHandlers.push(handlerNode);
5594
- this.consume('end', "Expected 'end' after event handler body");
5595
5576
  }
5596
5577
  else if (this.match('init')) {
5597
5578
  const initCommands = this.parseCommandBlock(['end']);
@@ -4742,6 +4742,17 @@ class Parser {
4742
4742
  if (token.value === 'the') {
4743
4743
  return this.parseTheXofY();
4744
4744
  }
4745
+ if (token.value === 'values' && this.check('of')) {
4746
+ this.advance();
4747
+ const target = this.parsePrimary();
4748
+ return {
4749
+ type: 'propertyOfExpression',
4750
+ property: { type: 'identifier', name: 'values' },
4751
+ target,
4752
+ line: token.line,
4753
+ column: token.column,
4754
+ };
4755
+ }
4745
4756
  return this.createIdentifier(token.value);
4746
4757
  }
4747
4758
  if (this.match('$')) {
@@ -5547,36 +5558,7 @@ class Parser {
5547
5558
  }
5548
5559
  }
5549
5560
  }
5550
- const handlerCommands = [];
5551
- while (!this.isAtEnd() && !this.check('end')) {
5552
- if (this.checkIsCommand() || this.isCommand(this.peek().value)) {
5553
- this.advance();
5554
- const savedError = this.error;
5555
- try {
5556
- const cmd = this.parseCommand();
5557
- if (this.error && this.error !== savedError) {
5558
- this.error = savedError;
5559
- }
5560
- handlerCommands.push(cmd);
5561
- while (!this.isAtEnd() &&
5562
- !this.check('end') &&
5563
- !this.checkIsCommand() &&
5564
- !this.isCommand(this.peek().value)) {
5565
- this.advance();
5566
- }
5567
- }
5568
- catch (error) {
5569
- this.error = savedError;
5570
- break;
5571
- }
5572
- }
5573
- else {
5574
- if (!this.check('end')) {
5575
- this.addError(`Unexpected token in event handler: ${this.peek().value}`);
5576
- }
5577
- break;
5578
- }
5579
- }
5561
+ const handlerCommands = this.parseCommandListUntilEnd();
5580
5562
  const handlerNode = {
5581
5563
  type: 'eventHandler',
5582
5564
  event: eventName,
@@ -5589,7 +5571,6 @@ class Parser {
5589
5571
  column: handlerPos.column,
5590
5572
  };
5591
5573
  eventHandlers.push(handlerNode);
5592
- this.consume('end', "Expected 'end' after event handler body");
5593
5574
  }
5594
5575
  else if (this.match('init')) {
5595
5576
  const initCommands = this.parseCommandBlock(['end']);
@@ -78,6 +78,11 @@ const KEYWORDS = new Set([
78
78
  'init',
79
79
  'every',
80
80
  'by',
81
+ 'halt',
82
+ 'via',
83
+ 'values',
84
+ 'default',
85
+ 'event',
81
86
  ]);
82
87
  function tokenize(code) {
83
88
  const tokens = [];
@@ -403,6 +408,7 @@ class HybridParser {
403
408
  go: () => this.parseGo(),
404
409
  return: () => this.parseReturn(),
405
410
  transition: () => this.parseTransition(),
411
+ halt: () => this.parseHalt(),
406
412
  };
407
413
  const normalized = normalizeCommand(this.peek().value);
408
414
  if (cmdMap[normalized]) {
@@ -470,11 +476,17 @@ class HybridParser {
470
476
  const url = this.parseExpression();
471
477
  let responseType = { type: 'literal', value: 'text' };
472
478
  let options;
479
+ let method;
473
480
  if (this.match('{')) {
474
481
  this.pos--;
475
482
  options = this.parseExpression();
476
483
  }
477
- for (let i = 0; i < 2; i++) {
484
+ for (let i = 0; i < 3; i++) {
485
+ if (this.match('via') && !method) {
486
+ this.advance();
487
+ method = this.parseExpression();
488
+ continue;
489
+ }
478
490
  if (this.match('as')) {
479
491
  this.advance();
480
492
  if (this.match('a') || this.match('an'))
@@ -492,7 +504,11 @@ class HybridParser {
492
504
  if (this.match('then'))
493
505
  this.advance();
494
506
  const body = this.parseCommandSequence();
495
- return { type: 'fetch', condition: { type: 'fetchConfig', url, responseType, options }, body };
507
+ return {
508
+ type: 'fetch',
509
+ condition: { type: 'fetchConfig', url, responseType, options, method },
510
+ body,
511
+ };
496
512
  }
497
513
  parseToggle() {
498
514
  this.expect('toggle');
@@ -683,6 +699,14 @@ class HybridParser {
683
699
  }
684
700
  return { type: 'command', name: 'return', args: value ? [value] : [] };
685
701
  }
702
+ parseHalt() {
703
+ this.expect('halt');
704
+ if (this.match('the'))
705
+ this.advance();
706
+ if (this.match('event', 'default'))
707
+ this.advance();
708
+ return { type: 'command', name: 'halt', args: [] };
709
+ }
686
710
  parseTransition() {
687
711
  this.expect('transition');
688
712
  let target;
@@ -959,6 +983,15 @@ class HybridParser {
959
983
  const target = this.parsePositionalTarget();
960
984
  return { type: 'positional', position, target };
961
985
  }
986
+ if (this.match('values')) {
987
+ this.advance();
988
+ if (this.match('of')) {
989
+ this.advance();
990
+ const target = this.parseExpression();
991
+ return { type: 'valuesOf', target };
992
+ }
993
+ return { type: 'identifier', value: token.value };
994
+ }
962
995
  if (token.type === 'identifier' || token.type === 'keyword') {
963
996
  this.advance();
964
997
  return { type: 'identifier', value: token.value };
@@ -76,6 +76,11 @@ const KEYWORDS = new Set([
76
76
  'init',
77
77
  'every',
78
78
  'by',
79
+ 'halt',
80
+ 'via',
81
+ 'values',
82
+ 'default',
83
+ 'event',
79
84
  ]);
80
85
  function tokenize(code) {
81
86
  const tokens = [];
@@ -401,6 +406,7 @@ class HybridParser {
401
406
  go: () => this.parseGo(),
402
407
  return: () => this.parseReturn(),
403
408
  transition: () => this.parseTransition(),
409
+ halt: () => this.parseHalt(),
404
410
  };
405
411
  const normalized = normalizeCommand(this.peek().value);
406
412
  if (cmdMap[normalized]) {
@@ -468,11 +474,17 @@ class HybridParser {
468
474
  const url = this.parseExpression();
469
475
  let responseType = { type: 'literal', value: 'text' };
470
476
  let options;
477
+ let method;
471
478
  if (this.match('{')) {
472
479
  this.pos--;
473
480
  options = this.parseExpression();
474
481
  }
475
- for (let i = 0; i < 2; i++) {
482
+ for (let i = 0; i < 3; i++) {
483
+ if (this.match('via') && !method) {
484
+ this.advance();
485
+ method = this.parseExpression();
486
+ continue;
487
+ }
476
488
  if (this.match('as')) {
477
489
  this.advance();
478
490
  if (this.match('a') || this.match('an'))
@@ -490,7 +502,11 @@ class HybridParser {
490
502
  if (this.match('then'))
491
503
  this.advance();
492
504
  const body = this.parseCommandSequence();
493
- return { type: 'fetch', condition: { type: 'fetchConfig', url, responseType, options }, body };
505
+ return {
506
+ type: 'fetch',
507
+ condition: { type: 'fetchConfig', url, responseType, options, method },
508
+ body,
509
+ };
494
510
  }
495
511
  parseToggle() {
496
512
  this.expect('toggle');
@@ -681,6 +697,14 @@ class HybridParser {
681
697
  }
682
698
  return { type: 'command', name: 'return', args: value ? [value] : [] };
683
699
  }
700
+ parseHalt() {
701
+ this.expect('halt');
702
+ if (this.match('the'))
703
+ this.advance();
704
+ if (this.match('event', 'default'))
705
+ this.advance();
706
+ return { type: 'command', name: 'halt', args: [] };
707
+ }
684
708
  parseTransition() {
685
709
  this.expect('transition');
686
710
  let target;
@@ -957,6 +981,15 @@ class HybridParser {
957
981
  const target = this.parsePositionalTarget();
958
982
  return { type: 'positional', position, target };
959
983
  }
984
+ if (this.match('values')) {
985
+ this.advance();
986
+ if (this.match('of')) {
987
+ this.advance();
988
+ const target = this.parseExpression();
989
+ return { type: 'valuesOf', target };
990
+ }
991
+ return { type: 'identifier', value: token.value };
992
+ }
960
993
  if (token.type === 'identifier' || token.type === 'keyword') {
961
994
  this.advance();
962
995
  return { type: 'identifier', value: token.value };
@@ -37,6 +37,7 @@ export declare class HybridParser {
37
37
  private parseFocusBlur;
38
38
  private parseGo;
39
39
  private parseReturn;
40
+ private parseHalt;
40
41
  private parseTransition;
41
42
  private parseTransitionRest;
42
43
  private parseExpression;
@@ -78,6 +78,11 @@ const KEYWORDS = new Set([
78
78
  'init',
79
79
  'every',
80
80
  'by',
81
+ 'halt',
82
+ 'via',
83
+ 'values',
84
+ 'default',
85
+ 'event',
81
86
  ]);
82
87
  function tokenize(code) {
83
88
  const tokens = [];
@@ -397,6 +402,7 @@ class HybridParser {
397
402
  go: () => this.parseGo(),
398
403
  return: () => this.parseReturn(),
399
404
  transition: () => this.parseTransition(),
405
+ halt: () => this.parseHalt(),
400
406
  };
401
407
  const normalized = normalizeCommand(this.peek().value);
402
408
  if (cmdMap[normalized]) {
@@ -464,11 +470,17 @@ class HybridParser {
464
470
  const url = this.parseExpression();
465
471
  let responseType = { type: 'literal', value: 'text' };
466
472
  let options;
473
+ let method;
467
474
  if (this.match('{')) {
468
475
  this.pos--;
469
476
  options = this.parseExpression();
470
477
  }
471
- for (let i = 0; i < 2; i++) {
478
+ for (let i = 0; i < 3; i++) {
479
+ if (this.match('via') && !method) {
480
+ this.advance();
481
+ method = this.parseExpression();
482
+ continue;
483
+ }
472
484
  if (this.match('as')) {
473
485
  this.advance();
474
486
  if (this.match('a') || this.match('an'))
@@ -486,7 +498,11 @@ class HybridParser {
486
498
  if (this.match('then'))
487
499
  this.advance();
488
500
  const body = this.parseCommandSequence();
489
- return { type: 'fetch', condition: { type: 'fetchConfig', url, responseType, options }, body };
501
+ return {
502
+ type: 'fetch',
503
+ condition: { type: 'fetchConfig', url, responseType, options, method },
504
+ body,
505
+ };
490
506
  }
491
507
  parseToggle() {
492
508
  this.expect('toggle');
@@ -677,6 +693,14 @@ class HybridParser {
677
693
  }
678
694
  return { type: 'command', name: 'return', args: value ? [value] : [] };
679
695
  }
696
+ parseHalt() {
697
+ this.expect('halt');
698
+ if (this.match('the'))
699
+ this.advance();
700
+ if (this.match('event', 'default'))
701
+ this.advance();
702
+ return { type: 'command', name: 'halt', args: [] };
703
+ }
680
704
  parseTransition() {
681
705
  this.expect('transition');
682
706
  let target;
@@ -953,6 +977,15 @@ class HybridParser {
953
977
  const target = this.parsePositionalTarget();
954
978
  return { type: 'positional', position, target };
955
979
  }
980
+ if (this.match('values')) {
981
+ this.advance();
982
+ if (this.match('of')) {
983
+ this.advance();
984
+ const target = this.parseExpression();
985
+ return { type: 'valuesOf', target };
986
+ }
987
+ return { type: 'identifier', value: token.value };
988
+ }
956
989
  if (token.type === 'identifier' || token.type === 'keyword') {
957
990
  this.advance();
958
991
  return { type: 'identifier', value: token.value };
@@ -76,6 +76,11 @@ const KEYWORDS = new Set([
76
76
  'init',
77
77
  'every',
78
78
  'by',
79
+ 'halt',
80
+ 'via',
81
+ 'values',
82
+ 'default',
83
+ 'event',
79
84
  ]);
80
85
  function tokenize(code) {
81
86
  const tokens = [];
@@ -395,6 +400,7 @@ class HybridParser {
395
400
  go: () => this.parseGo(),
396
401
  return: () => this.parseReturn(),
397
402
  transition: () => this.parseTransition(),
403
+ halt: () => this.parseHalt(),
398
404
  };
399
405
  const normalized = normalizeCommand(this.peek().value);
400
406
  if (cmdMap[normalized]) {
@@ -462,11 +468,17 @@ class HybridParser {
462
468
  const url = this.parseExpression();
463
469
  let responseType = { type: 'literal', value: 'text' };
464
470
  let options;
471
+ let method;
465
472
  if (this.match('{')) {
466
473
  this.pos--;
467
474
  options = this.parseExpression();
468
475
  }
469
- for (let i = 0; i < 2; i++) {
476
+ for (let i = 0; i < 3; i++) {
477
+ if (this.match('via') && !method) {
478
+ this.advance();
479
+ method = this.parseExpression();
480
+ continue;
481
+ }
470
482
  if (this.match('as')) {
471
483
  this.advance();
472
484
  if (this.match('a') || this.match('an'))
@@ -484,7 +496,11 @@ class HybridParser {
484
496
  if (this.match('then'))
485
497
  this.advance();
486
498
  const body = this.parseCommandSequence();
487
- return { type: 'fetch', condition: { type: 'fetchConfig', url, responseType, options }, body };
499
+ return {
500
+ type: 'fetch',
501
+ condition: { type: 'fetchConfig', url, responseType, options, method },
502
+ body,
503
+ };
488
504
  }
489
505
  parseToggle() {
490
506
  this.expect('toggle');
@@ -675,6 +691,14 @@ class HybridParser {
675
691
  }
676
692
  return { type: 'command', name: 'return', args: value ? [value] : [] };
677
693
  }
694
+ parseHalt() {
695
+ this.expect('halt');
696
+ if (this.match('the'))
697
+ this.advance();
698
+ if (this.match('event', 'default'))
699
+ this.advance();
700
+ return { type: 'command', name: 'halt', args: [] };
701
+ }
678
702
  parseTransition() {
679
703
  this.expect('transition');
680
704
  let target;
@@ -951,6 +975,15 @@ class HybridParser {
951
975
  const target = this.parsePositionalTarget();
952
976
  return { type: 'positional', position, target };
953
977
  }
978
+ if (this.match('values')) {
979
+ this.advance();
980
+ if (this.match('of')) {
981
+ this.advance();
982
+ const target = this.parseExpression();
983
+ return { type: 'valuesOf', target };
984
+ }
985
+ return { type: 'identifier', value: token.value };
986
+ }
954
987
  if (token.type === 'identifier' || token.type === 'keyword') {
955
988
  this.advance();
956
989
  return { type: 'identifier', value: token.value };
@@ -78,6 +78,11 @@ const KEYWORDS = new Set([
78
78
  'init',
79
79
  'every',
80
80
  'by',
81
+ 'halt',
82
+ 'via',
83
+ 'values',
84
+ 'default',
85
+ 'event',
81
86
  ]);
82
87
  function tokenize(code) {
83
88
  const tokens = [];
@@ -76,6 +76,11 @@ const KEYWORDS = new Set([
76
76
  'init',
77
77
  'every',
78
78
  'by',
79
+ 'halt',
80
+ 'via',
81
+ 'values',
82
+ 'default',
83
+ 'event',
79
84
  ]);
80
85
  function tokenize(code) {
81
86
  const tokens = [];
@@ -78,6 +78,11 @@ const KEYWORDS = new Set([
78
78
  'init',
79
79
  'every',
80
80
  'by',
81
+ 'halt',
82
+ 'via',
83
+ 'values',
84
+ 'default',
85
+ 'event',
81
86
  ]);
82
87
  function tokenize(code) {
83
88
  const tokens = [];
@@ -403,6 +408,7 @@ class HybridParser {
403
408
  go: () => this.parseGo(),
404
409
  return: () => this.parseReturn(),
405
410
  transition: () => this.parseTransition(),
411
+ halt: () => this.parseHalt(),
406
412
  };
407
413
  const normalized = normalizeCommand(this.peek().value);
408
414
  if (cmdMap[normalized]) {
@@ -470,11 +476,17 @@ class HybridParser {
470
476
  const url = this.parseExpression();
471
477
  let responseType = { type: 'literal', value: 'text' };
472
478
  let options;
479
+ let method;
473
480
  if (this.match('{')) {
474
481
  this.pos--;
475
482
  options = this.parseExpression();
476
483
  }
477
- for (let i = 0; i < 2; i++) {
484
+ for (let i = 0; i < 3; i++) {
485
+ if (this.match('via') && !method) {
486
+ this.advance();
487
+ method = this.parseExpression();
488
+ continue;
489
+ }
478
490
  if (this.match('as')) {
479
491
  this.advance();
480
492
  if (this.match('a') || this.match('an'))
@@ -492,7 +504,11 @@ class HybridParser {
492
504
  if (this.match('then'))
493
505
  this.advance();
494
506
  const body = this.parseCommandSequence();
495
- return { type: 'fetch', condition: { type: 'fetchConfig', url, responseType, options }, body };
507
+ return {
508
+ type: 'fetch',
509
+ condition: { type: 'fetchConfig', url, responseType, options, method },
510
+ body,
511
+ };
496
512
  }
497
513
  parseToggle() {
498
514
  this.expect('toggle');
@@ -683,6 +699,14 @@ class HybridParser {
683
699
  }
684
700
  return { type: 'command', name: 'return', args: value ? [value] : [] };
685
701
  }
702
+ parseHalt() {
703
+ this.expect('halt');
704
+ if (this.match('the'))
705
+ this.advance();
706
+ if (this.match('event', 'default'))
707
+ this.advance();
708
+ return { type: 'command', name: 'halt', args: [] };
709
+ }
686
710
  parseTransition() {
687
711
  this.expect('transition');
688
712
  let target;
@@ -959,6 +983,15 @@ class HybridParser {
959
983
  const target = this.parsePositionalTarget();
960
984
  return { type: 'positional', position, target };
961
985
  }
986
+ if (this.match('values')) {
987
+ this.advance();
988
+ if (this.match('of')) {
989
+ this.advance();
990
+ const target = this.parseExpression();
991
+ return { type: 'valuesOf', target };
992
+ }
993
+ return { type: 'identifier', value: token.value };
994
+ }
962
995
  if (token.type === 'identifier' || token.type === 'keyword') {
963
996
  this.advance();
964
997
  return { type: 'identifier', value: token.value };