@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
@@ -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 };
@@ -767,8 +767,9 @@ const SPECIAL_DOM_PROPERTIES = {
767
767
  outerhtml: el => el.outerHTML,
768
768
  value: el => (isFormElement(el) ? el.value : undefined),
769
769
  checked: el => (isInputElement(el) ? el.checked : undefined),
770
- disabled: el => (isFormElement(el) ? el.disabled : undefined),
770
+ disabled: el => ('disabled' in el ? el.disabled : undefined),
771
771
  selected: el => (isOptionElement(el) ? el.selected : undefined),
772
+ tabindex: el => (isHTMLElement$1(el) ? el.tabIndex : undefined),
772
773
  hidden: el => (isHTMLElement$1(el) ? el.hidden : undefined),
773
774
  style: el => getComputedStyle(el),
774
775
  children: el => Array.from(el.children),
@@ -777,7 +778,19 @@ const SPECIAL_DOM_PROPERTIES = {
777
778
  lastchild: el => el.lastElementChild,
778
779
  nextsibling: el => el.nextElementSibling,
779
780
  previoussibling: el => el.previousElementSibling,
781
+ values: el => collectFormValues(el),
780
782
  };
783
+ function collectFormValues(el) {
784
+ if (el instanceof HTMLFormElement)
785
+ return new FormData(el);
786
+ const fd = new FormData();
787
+ el.querySelectorAll('input, select, textarea').forEach((input) => {
788
+ const name = input.getAttribute('name');
789
+ if (name && 'value' in input)
790
+ fd.append(name, input.value);
791
+ });
792
+ return fd;
793
+ }
781
794
  function getElementProperty(element, property) {
782
795
  if (property.startsWith('computed-')) {
783
796
  const cssProperty = property.slice('computed-'.length);
@@ -5027,7 +5040,7 @@ const enhancedConverters = {
5027
5040
  Values: (value, _context) => {
5028
5041
  try {
5029
5042
  if (value instanceof HTMLFormElement) {
5030
- return success(extractFormValues(value), 'object');
5043
+ return success(getFormValuesProcessed(value), 'object');
5031
5044
  }
5032
5045
  if (value instanceof HTMLElement) {
5033
5046
  const inputs = value.querySelectorAll('input, select, textarea');
@@ -5035,7 +5048,7 @@ const enhancedConverters = {
5035
5048
  inputs.forEach((input) => {
5036
5049
  const htmlInput = input;
5037
5050
  if (htmlInput.name) {
5038
- const inputValue = extractInputValue(htmlInput);
5051
+ const inputValue = getInputValue(htmlInput);
5039
5052
  if (inputValue !== undefined) {
5040
5053
  values[htmlInput.name] = inputValue;
5041
5054
  }
@@ -5490,55 +5503,6 @@ class IsExpression extends BaseExpressionImpl {
5490
5503
  }
5491
5504
  }
5492
5505
  }
5493
- function extractFormValues(form) {
5494
- const values = {};
5495
- const elements = form.querySelectorAll('input, select, textarea');
5496
- elements.forEach(element => {
5497
- const input = element;
5498
- if (input.name) {
5499
- const value = extractInputValue(input);
5500
- if (value !== undefined) {
5501
- if (values[input.name] !== undefined) {
5502
- if (!Array.isArray(values[input.name])) {
5503
- values[input.name] = [values[input.name]];
5504
- }
5505
- values[input.name].push(value);
5506
- }
5507
- else {
5508
- values[input.name] = value;
5509
- }
5510
- }
5511
- }
5512
- });
5513
- return values;
5514
- }
5515
- function extractInputValue(input) {
5516
- if (input instanceof HTMLInputElement) {
5517
- switch (input.type) {
5518
- case 'checkbox':
5519
- return input.checked;
5520
- case 'radio':
5521
- return input.checked ? input.value : undefined;
5522
- case 'number':
5523
- case 'range':
5524
- return input.valueAsNumber;
5525
- case 'date':
5526
- case 'datetime-local':
5527
- return input.valueAsDate;
5528
- case 'file':
5529
- return input.files;
5530
- default:
5531
- return input.value;
5532
- }
5533
- }
5534
- if (input instanceof HTMLSelectElement) {
5535
- if (input.multiple) {
5536
- return Array.from(input.selectedOptions).map(option => option.value);
5537
- }
5538
- return input.value;
5539
- }
5540
- return input.value;
5541
- }
5542
5506
  ({
5543
5507
  as: new AsExpression(),
5544
5508
  is: new IsExpression(),
@@ -765,8 +765,9 @@ const SPECIAL_DOM_PROPERTIES = {
765
765
  outerhtml: el => el.outerHTML,
766
766
  value: el => (isFormElement(el) ? el.value : undefined),
767
767
  checked: el => (isInputElement(el) ? el.checked : undefined),
768
- disabled: el => (isFormElement(el) ? el.disabled : undefined),
768
+ disabled: el => ('disabled' in el ? el.disabled : undefined),
769
769
  selected: el => (isOptionElement(el) ? el.selected : undefined),
770
+ tabindex: el => (isHTMLElement$1(el) ? el.tabIndex : undefined),
770
771
  hidden: el => (isHTMLElement$1(el) ? el.hidden : undefined),
771
772
  style: el => getComputedStyle(el),
772
773
  children: el => Array.from(el.children),
@@ -775,7 +776,19 @@ const SPECIAL_DOM_PROPERTIES = {
775
776
  lastchild: el => el.lastElementChild,
776
777
  nextsibling: el => el.nextElementSibling,
777
778
  previoussibling: el => el.previousElementSibling,
779
+ values: el => collectFormValues(el),
778
780
  };
781
+ function collectFormValues(el) {
782
+ if (el instanceof HTMLFormElement)
783
+ return new FormData(el);
784
+ const fd = new FormData();
785
+ el.querySelectorAll('input, select, textarea').forEach((input) => {
786
+ const name = input.getAttribute('name');
787
+ if (name && 'value' in input)
788
+ fd.append(name, input.value);
789
+ });
790
+ return fd;
791
+ }
779
792
  function getElementProperty(element, property) {
780
793
  if (property.startsWith('computed-')) {
781
794
  const cssProperty = property.slice('computed-'.length);
@@ -5025,7 +5038,7 @@ const enhancedConverters = {
5025
5038
  Values: (value, _context) => {
5026
5039
  try {
5027
5040
  if (value instanceof HTMLFormElement) {
5028
- return success(extractFormValues(value), 'object');
5041
+ return success(getFormValuesProcessed(value), 'object');
5029
5042
  }
5030
5043
  if (value instanceof HTMLElement) {
5031
5044
  const inputs = value.querySelectorAll('input, select, textarea');
@@ -5033,7 +5046,7 @@ const enhancedConverters = {
5033
5046
  inputs.forEach((input) => {
5034
5047
  const htmlInput = input;
5035
5048
  if (htmlInput.name) {
5036
- const inputValue = extractInputValue(htmlInput);
5049
+ const inputValue = getInputValue(htmlInput);
5037
5050
  if (inputValue !== undefined) {
5038
5051
  values[htmlInput.name] = inputValue;
5039
5052
  }
@@ -5488,55 +5501,6 @@ class IsExpression extends BaseExpressionImpl {
5488
5501
  }
5489
5502
  }
5490
5503
  }
5491
- function extractFormValues(form) {
5492
- const values = {};
5493
- const elements = form.querySelectorAll('input, select, textarea');
5494
- elements.forEach(element => {
5495
- const input = element;
5496
- if (input.name) {
5497
- const value = extractInputValue(input);
5498
- if (value !== undefined) {
5499
- if (values[input.name] !== undefined) {
5500
- if (!Array.isArray(values[input.name])) {
5501
- values[input.name] = [values[input.name]];
5502
- }
5503
- values[input.name].push(value);
5504
- }
5505
- else {
5506
- values[input.name] = value;
5507
- }
5508
- }
5509
- }
5510
- });
5511
- return values;
5512
- }
5513
- function extractInputValue(input) {
5514
- if (input instanceof HTMLInputElement) {
5515
- switch (input.type) {
5516
- case 'checkbox':
5517
- return input.checked;
5518
- case 'radio':
5519
- return input.checked ? input.value : undefined;
5520
- case 'number':
5521
- case 'range':
5522
- return input.valueAsNumber;
5523
- case 'date':
5524
- case 'datetime-local':
5525
- return input.valueAsDate;
5526
- case 'file':
5527
- return input.files;
5528
- default:
5529
- return input.value;
5530
- }
5531
- }
5532
- if (input instanceof HTMLSelectElement) {
5533
- if (input.multiple) {
5534
- return Array.from(input.selectedOptions).map(option => option.value);
5535
- }
5536
- return input.value;
5537
- }
5538
- return input.value;
5539
- }
5540
5504
  ({
5541
5505
  as: new AsExpression(),
5542
5506
  is: new IsExpression(),
@@ -66,6 +66,7 @@ export declare class RuntimeBase {
66
66
  parameters?: string[];
67
67
  eventHandlers?: EventHandlerNode[];
68
68
  initBlock?: ASTNode;
69
+ imperativeInstaller?: (element: HTMLElement, parameters: Record<string, any>) => void;
69
70
  }, _context: ExecutionContext): Promise<void>;
70
71
  protected installBehaviorOnElement(behaviorName: string, element: HTMLElement, parameters: Record<string, any>): Promise<void>;
71
72
  protected executeEventHandler(node: EventHandlerNode, context: ExecutionContext): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperfixi/core",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Multilingual, tree-shakeable hyperscript",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -231,7 +231,7 @@
231
231
  "@vitest/coverage-v8": "^4.0.17",
232
232
  "@vitest/ui": "^4.0.17",
233
233
  "better-sqlite3": "^12.6.2",
234
- "esbuild": "0.25.11",
234
+ "esbuild": "0.27.3",
235
235
  "eslint": "^8.57.1",
236
236
  "eslint-config-prettier": "^9.0.0",
237
237
  "eslint-plugin-prettier": "^5.0.0",
@@ -240,7 +240,7 @@
240
240
  "jsdom": "^26.1.0",
241
241
  "prettier": "^3.0.0",
242
242
  "rollup": "^4.28.1",
243
- "rollup-plugin-visualizer": "^6.0.5",
243
+ "rollup-plugin-visualizer": "^7.0.0",
244
244
  "tsx": "^4.0.0",
245
245
  "typescript": "^5.8.3",
246
246
  "vite": "^7.1.12",
@@ -279,10 +279,10 @@
279
279
  "tslib": "^2.8.1"
280
280
  },
281
281
  "peerDependencies": {
282
- "@lokascript/patterns-reference": "*"
282
+ "@hyperfixi/patterns-reference": "*"
283
283
  },
284
284
  "peerDependenciesMeta": {
285
- "@lokascript/patterns-reference": {
285
+ "@hyperfixi/patterns-reference": {
286
286
  "optional": true
287
287
  }
288
288
  },