@hyperfixi/core 2.2.1 → 2.3.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 (43) hide show
  1. package/README.md +8 -11
  2. package/dist/bundle-generator/index.js +25 -4
  3. package/dist/bundle-generator/index.mjs +25 -4
  4. package/dist/chunks/{bridge-BELRwj7r.js → bridge-Clbh_xAj.js} +2 -2
  5. package/dist/chunks/browser-modular-DIOxQqhV.js +2 -0
  6. package/dist/chunks/{index-lsDi6izr.js → index-DcxoRUBe.js} +2 -2
  7. package/dist/commands/index.js +36 -6
  8. package/dist/commands/index.mjs +36 -6
  9. package/dist/core/base-expression-evaluator.d.ts +4 -0
  10. package/dist/expressions/index.js +10 -0
  11. package/dist/expressions/index.mjs +10 -0
  12. package/dist/hyperfixi-classic-i18n.js +1 -1
  13. package/dist/hyperfixi-hx.js +1 -1
  14. package/dist/hyperfixi-hybrid-complete.js +1 -1
  15. package/dist/hyperfixi-minimal.js +1 -1
  16. package/dist/hyperfixi-multilingual.js +1 -1
  17. package/dist/hyperfixi-standard.js +1 -1
  18. package/dist/hyperfixi.js +1 -1
  19. package/dist/hyperfixi.mjs +1 -1
  20. package/dist/index.js +175 -79
  21. package/dist/index.min.js +1 -1
  22. package/dist/index.mjs +175 -79
  23. package/dist/lokascript-browser-classic-i18n.js +1 -1
  24. package/dist/lokascript-browser-minimal.js +1 -1
  25. package/dist/lokascript-browser-standard.js +1 -1
  26. package/dist/lokascript-browser.js +1 -1
  27. package/dist/lokascript-hybrid-complete.js +1 -1
  28. package/dist/lokascript-hybrid-hx.js +1 -1
  29. package/dist/lokascript-multilingual.js +1 -1
  30. package/dist/parser/full-parser.js +119 -70
  31. package/dist/parser/full-parser.mjs +119 -70
  32. package/dist/parser/hybrid/index.js +7 -0
  33. package/dist/parser/hybrid/index.mjs +7 -0
  34. package/dist/parser/hybrid/parser-core.js +7 -0
  35. package/dist/parser/hybrid/parser-core.mjs +7 -0
  36. package/dist/parser/hybrid/tokenizer.js +7 -0
  37. package/dist/parser/hybrid/tokenizer.mjs +7 -0
  38. package/dist/parser/hybrid-parser.js +7 -0
  39. package/dist/parser/hybrid-parser.mjs +7 -0
  40. package/dist/registry/index.js +10 -0
  41. package/dist/registry/index.mjs +10 -0
  42. package/package.json +1 -1
  43. package/dist/chunks/browser-modular-B7Bb-ABs.js +0 -2
@@ -1,2 +1,2 @@
1
- export{O as ObjectPool,P as Parser,R as Runtime,d as debug,h as default,a as defaultAttributeProcessor,b as detectFeatures,e as evalHyperScript,c as evalHyperScriptAsync,f as evalHyperScriptSmart,g as getLoadedFeatures,i as hyperscript,j as isFeatureLoaded,l as loadRequiredFeatures,p as preloadDocumentFeatures,k as preloadFeatures,s as styleBatcher,t as tailwindExtension,m as tokenize}from"./chunks/browser-modular-B7Bb-ABs.js";import"./chunks/feature-sockets-ClOH7vk7.js";
1
+ export{O as ObjectPool,P as Parser,R as Runtime,d as debug,h as default,a as defaultAttributeProcessor,b as detectFeatures,e as evalHyperScript,c as evalHyperScriptAsync,f as evalHyperScriptSmart,g as getLoadedFeatures,i as hyperscript,j as isFeatureLoaded,l as loadRequiredFeatures,p as preloadDocumentFeatures,k as preloadFeatures,s as styleBatcher,t as tailwindExtension,m as tokenize}from"./chunks/browser-modular-DIOxQqhV.js";import"./chunks/feature-sockets-ClOH7vk7.js";
2
2
  //# sourceMappingURL=hyperfixi.mjs.map
package/dist/index.js CHANGED
@@ -456,7 +456,9 @@ function tokenize$1(input) {
456
456
  prevToken.value === ',' ||
457
457
  prevToken.value === ';';
458
458
  const isAdjacentToPrev = prevToken && prevToken.end === tokenizer.position;
459
- if (isCSSSelectorContext && !isAdjacentToPrev && isAlpha(peek(tokenizer))) {
459
+ if (isCSSSelectorContext &&
460
+ !isAdjacentToPrev &&
461
+ (isAlpha(peek(tokenizer)) || peek(tokenizer) === '{')) {
460
462
  tokenizeCSSSelector(tokenizer);
461
463
  continue;
462
464
  }
@@ -689,6 +691,17 @@ function tokenizeCSSSelector(tokenizer) {
689
691
  const start = tokenizer.position;
690
692
  const prefix = advance(tokenizer);
691
693
  let value = prefix;
694
+ if (tokenizer.position < tokenizer.input.length && tokenizer.input[tokenizer.position] === '{') {
695
+ value += advance(tokenizer);
696
+ while (tokenizer.position < tokenizer.input.length) {
697
+ const ch = tokenizer.input[tokenizer.position];
698
+ value += advance(tokenizer);
699
+ if (ch === '}')
700
+ break;
701
+ }
702
+ addToken(tokenizer, TokenKind.SELECTOR, value, start);
703
+ return;
704
+ }
692
705
  while (tokenizer.position < tokenizer.input.length) {
693
706
  const char = tokenizer.input[tokenizer.position];
694
707
  if (isAlphaNumeric(char) || char === '-' || char === '_' || char === ':') {
@@ -2379,33 +2392,14 @@ function parseTriggerCommand(ctx, identifierNode) {
2379
2392
  });
2380
2393
  }
2381
2394
  }
2382
- while (!isCommandBoundary(ctx)) {
2383
- allArgs.push(ctx.parsePrimary());
2384
- }
2385
- let operationIndex = -1;
2386
- let operationKeyword = 'on';
2387
- for (let i = 0; i < allArgs.length; i++) {
2388
- const arg = allArgs[i];
2389
- const argRecord = arg;
2390
- const argValue = argRecord.name || argRecord.value;
2391
- if ((arg.type === 'identifier' || arg.type === 'literal' || arg.type === 'keyword') &&
2392
- (argValue === 'on' || argValue === 'to')) {
2393
- operationIndex = i;
2394
- operationKeyword = argValue;
2395
- break;
2395
+ const finalArgs = [...allArgs];
2396
+ if (ctx.check('on') || ctx.check('to')) {
2397
+ const keyword = ctx.advance().value;
2398
+ finalArgs.push(ctx.createIdentifier(keyword));
2399
+ while (!isCommandBoundary(ctx)) {
2400
+ finalArgs.push(ctx.parsePrimary());
2396
2401
  }
2397
2402
  }
2398
- const finalArgs = [];
2399
- if (operationIndex === -1) {
2400
- finalArgs.push(...allArgs);
2401
- }
2402
- else {
2403
- const eventArgs = allArgs.slice(0, operationIndex);
2404
- const targetArgs = allArgs.slice(operationIndex + 1);
2405
- finalArgs.push(...eventArgs);
2406
- finalArgs.push(ctx.createIdentifier(operationKeyword));
2407
- finalArgs.push(...targetArgs);
2408
- }
2409
2403
  return CommandNodeBuilder.fromIdentifier(identifierNode)
2410
2404
  .withArgs(...finalArgs)
2411
2405
  .endingAt(ctx.getPosition())
@@ -3125,8 +3119,13 @@ function parseSwapCommand(ctx, identifierNode) {
3125
3119
 
3126
3120
  function parseWaitCommand(ctx, commandToken) {
3127
3121
  const args = [];
3128
- if (ctx.checkTimeExpression() || ctx.checkLiteral()) {
3129
- const timeExpr = ctx.parsePrimary();
3122
+ const isExpressionStart = ctx.checkTimeExpression() ||
3123
+ ctx.checkLiteral() ||
3124
+ ctx.checkContextVar() ||
3125
+ ctx.check('(') ||
3126
+ (ctx.checkIdentifierLike() && !ctx.check('for') && !isCommandBoundary(ctx));
3127
+ if (isExpressionStart) {
3128
+ const timeExpr = ctx.parseExpression();
3130
3129
  args.push(timeExpr);
3131
3130
  return CommandNodeBuilder.from(commandToken)
3132
3131
  .withArgs(...args)
@@ -3312,43 +3311,24 @@ function parsePropertyOfTarget(ctx, startPosition) {
3312
3311
  return null;
3313
3312
  const thePosition = ctx.savePosition();
3314
3313
  ctx.advance();
3315
- const nextToken = ctx.peek();
3316
- const tokenAfterNext = ctx.peekAt(1);
3317
- if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS$1.OF) {
3318
- const propertyToken = ctx.advance();
3319
- if (ctx.check(KEYWORDS$1.OF)) {
3320
- ctx.advance();
3321
- const targetToken = ctx.advance();
3322
- const isIdSelector = targetToken.value.startsWith('#');
3323
- return {
3324
- type: 'propertyOfExpression',
3325
- property: {
3326
- type: 'identifier',
3327
- name: propertyToken.value,
3328
- start: propertyToken.start,
3329
- end: propertyToken.end,
3330
- },
3331
- target: {
3332
- type: isIdSelector ? 'idSelector' : 'cssSelector',
3333
- value: targetToken.value,
3334
- start: targetToken.start,
3335
- end: targetToken.end,
3336
- },
3337
- start: startPosition,
3338
- end: ctx.savePosition(),
3339
- };
3340
- }
3341
- ctx.restorePosition(startPosition);
3314
+ const propertyExpr = ctx.parseExpression();
3315
+ if (!propertyExpr) {
3316
+ ctx.restorePosition(thePosition);
3342
3317
  return null;
3343
3318
  }
3344
- if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS$1.TO) {
3345
- const variableToken = ctx.advance();
3346
- return {
3347
- type: 'identifier',
3348
- name: variableToken.value,
3349
- start: variableToken.start,
3350
- end: variableToken.end,
3351
- };
3319
+ const exprAny = propertyExpr;
3320
+ if (exprAny.type === 'binaryExpression' && exprAny.operator === KEYWORDS$1.OF) {
3321
+ const property = exprAny.left;
3322
+ const target = exprAny.right;
3323
+ return createPropertyOfExpression(property, target, {
3324
+ start: property.start ?? 0,
3325
+ end: target.end ?? 0,
3326
+ line: property.line ?? 1,
3327
+ column: property.column ?? 1,
3328
+ });
3329
+ }
3330
+ if (ctx.check(KEYWORDS$1.TO)) {
3331
+ return propertyExpr;
3352
3332
  }
3353
3333
  ctx.restorePosition(thePosition);
3354
3334
  return null;
@@ -3707,6 +3687,71 @@ function parseFetchNakedNamedArgs(ctx) {
3707
3687
  column: startPos.column,
3708
3688
  };
3709
3689
  }
3690
+ function findJsEndBoundary(ctx, startPos) {
3691
+ const input = ctx.getInputSlice(startPos);
3692
+ if (!input) {
3693
+ return startPos;
3694
+ }
3695
+ let i = 0;
3696
+ while (i < input.length) {
3697
+ const ch = input[i];
3698
+ if (ch === "'" || ch === '\u2019' || ch === '\u2018') {
3699
+ i++;
3700
+ while (i < input.length && input[i] !== ch) {
3701
+ if (input[i] === '\\')
3702
+ i++;
3703
+ i++;
3704
+ }
3705
+ i++;
3706
+ continue;
3707
+ }
3708
+ if (ch === '"') {
3709
+ i++;
3710
+ while (i < input.length && input[i] !== '"') {
3711
+ if (input[i] === '\\')
3712
+ i++;
3713
+ i++;
3714
+ }
3715
+ i++;
3716
+ continue;
3717
+ }
3718
+ if (ch === '`') {
3719
+ i++;
3720
+ while (i < input.length && input[i] !== '`') {
3721
+ if (input[i] === '\\')
3722
+ i++;
3723
+ i++;
3724
+ }
3725
+ i++;
3726
+ continue;
3727
+ }
3728
+ if (ch === '/' && i + 1 < input.length && input[i + 1] === '/') {
3729
+ i += 2;
3730
+ while (i < input.length && input[i] !== '\n')
3731
+ i++;
3732
+ continue;
3733
+ }
3734
+ if (ch === '/' && i + 1 < input.length && input[i + 1] === '*') {
3735
+ i += 2;
3736
+ while (i < input.length &&
3737
+ !(input[i] === '*' && i + 1 < input.length && input[i + 1] === '/'))
3738
+ i++;
3739
+ i += 2;
3740
+ continue;
3741
+ }
3742
+ if ((ch === 'e' || ch === 'E') &&
3743
+ i + 3 <= input.length &&
3744
+ input.slice(i, i + 3).toLowerCase() === 'end') {
3745
+ const before = i === 0 || !/[a-zA-Z0-9_]/.test(input[i - 1]);
3746
+ const after = i + 3 >= input.length || !/[a-zA-Z0-9_]/.test(input[i + 3]);
3747
+ if (before && after) {
3748
+ return startPos + i;
3749
+ }
3750
+ }
3751
+ i++;
3752
+ }
3753
+ return startPos + input.length;
3754
+ }
3710
3755
  function parseJsCommand(ctx, identifierNode) {
3711
3756
  const parameters = [];
3712
3757
  if (ctx.match('(')) {
@@ -3719,11 +3764,12 @@ function parseJsCommand(ctx, identifierNode) {
3719
3764
  ctx.consume(')', 'Expected ) after js parameters');
3720
3765
  }
3721
3766
  const jsCodeStart = ctx.peek().start;
3722
- while (!ctx.check(KEYWORDS$1.END) && !ctx.isAtEnd()) {
3767
+ const jsCodeEnd = findJsEndBoundary(ctx, jsCodeStart);
3768
+ while (!ctx.isAtEnd() && !ctx.check(KEYWORDS$1.END)) {
3769
+ if (ctx.peek().start >= jsCodeEnd)
3770
+ break;
3723
3771
  ctx.advance();
3724
3772
  }
3725
- const endToken = ctx.peek();
3726
- const jsCodeEnd = endToken.start;
3727
3773
  ctx.consume(KEYWORDS$1.END, 'Expected end after js code body');
3728
3774
  const rawSlice = ctx.getInputSlice(jsCodeStart, jsCodeEnd);
3729
3775
  const code = rawSlice.trim();
@@ -4626,7 +4672,12 @@ class Parser {
4626
4672
  }
4627
4673
  else {
4628
4674
  const commandName = expr.name.toLowerCase();
4629
- if (commandName === 'wait' && this.checkTimeExpression()) {
4675
+ if (commandName === 'wait' &&
4676
+ (this.checkTimeExpression() ||
4677
+ this.checkNumber() ||
4678
+ this.checkIdentifier() ||
4679
+ this.checkContextVar() ||
4680
+ this.check('('))) {
4630
4681
  const command = this.createCommandFromIdentifier(expr);
4631
4682
  if (command) {
4632
4683
  expr = command;
@@ -5845,9 +5896,7 @@ class Parser {
5845
5896
  while (!this.isAtEnd() && !this.check('end')) {
5846
5897
  if (this.match('on')) {
5847
5898
  const handlerPos = this.getPosition();
5848
- const eventToken = this.peek();
5849
- const eventName = eventToken.value;
5850
- this.advance();
5899
+ const eventName = this.parseEventNameWithNamespace("Expected event name after 'on'");
5851
5900
  const eventArgs = [];
5852
5901
  if (this.check('(')) {
5853
5902
  this.advance();
@@ -8666,6 +8715,8 @@ class BaseExpressionEvaluator {
8666
8715
  return this.evaluateIdSelector(node, context);
8667
8716
  case 'attributeAccess':
8668
8717
  return this.evaluateAttributeAccess(node, context);
8718
+ case 'asExpression':
8719
+ return this.evaluateAsExpression(node, context);
8669
8720
  default:
8670
8721
  throw new Error(`Unsupported AST node type for evaluation: ${node.type}`);
8671
8722
  }
@@ -8951,6 +9002,14 @@ class BaseExpressionEvaluator {
8951
9002
  }
8952
9003
  return `@${node.attributeName}`;
8953
9004
  }
9005
+ async evaluateAsExpression(node, context) {
9006
+ const value = await this.evaluate(node.expression, context);
9007
+ const asExpr = this.expressionRegistry.get('as');
9008
+ if (asExpr) {
9009
+ return asExpr.evaluate(context, value, node.targetType);
9010
+ }
9011
+ throw new Error(`Conversion type 'as' not registered`);
9012
+ }
8954
9013
  getAvailableExpressions() {
8955
9014
  return Array.from(this.expressionRegistry.keys());
8956
9015
  }
@@ -14531,6 +14590,8 @@ class RuntimeBase {
14531
14590
  this.behaviorAPI = {
14532
14591
  has: (name) => this.behaviorRegistry.has(name),
14533
14592
  get: (name) => this.behaviorRegistry.get(name),
14593
+ set: (name, definition) => this.behaviorRegistry.set(name, definition),
14594
+ resolve: null,
14534
14595
  install: async (behaviorName, element, parameters) => {
14535
14596
  return await this.installBehaviorOnElement(behaviorName, element, parameters);
14536
14597
  },
@@ -15012,9 +15073,14 @@ class RuntimeBase {
15012
15073
  }
15013
15074
  async installBehaviorOnElement(behaviorName, element, parameters) {
15014
15075
  debug.runtime(`BEHAVIOR: installBehaviorOnElement called: ${behaviorName}`);
15015
- const behavior = this.behaviorRegistry.get(behaviorName);
15016
- if (!behavior)
15017
- throw new Error(`Behavior "${behaviorName}" not found`);
15076
+ let behavior = this.behaviorRegistry.get(behaviorName);
15077
+ if (!behavior) {
15078
+ if (this.behaviorAPI.resolve && this.behaviorAPI.resolve(behaviorName)) {
15079
+ behavior = this.behaviorRegistry.get(behaviorName);
15080
+ }
15081
+ if (!behavior)
15082
+ throw new Error(`Behavior "${behaviorName}" not found`);
15083
+ }
15018
15084
  if (behavior.type === 'imperative' && typeof behavior.install === 'function') {
15019
15085
  debug.runtime(`BEHAVIOR: Installing imperative behavior '${behaviorName}'`);
15020
15086
  behavior.install(element, parameters);
@@ -17368,11 +17434,30 @@ let PutCommand = (() => {
17368
17434
  const obj = targetArg.object, prop = targetArg.property;
17369
17435
  if (obj?.type === 'selector')
17370
17436
  targetSelector = obj.value;
17371
- else if (obj?.type === 'identifier')
17372
- targetSelector = obj.name;
17437
+ else if (obj?.type === 'identifier') {
17438
+ const objName = obj.name;
17439
+ if (objName === 'my' || objName === 'me' || objName === 'I') {
17440
+ if (context.me && prop?.name) {
17441
+ return {
17442
+ value,
17443
+ targets: [context.me],
17444
+ position: 'replace',
17445
+ memberPath: prop.name,
17446
+ };
17447
+ }
17448
+ }
17449
+ else if (objName === 'its' || objName === 'it') {
17450
+ const ev = await evaluator.evaluate(targetArg, context);
17451
+ if (typeof ev === 'string')
17452
+ targetSelector = ev;
17453
+ }
17454
+ else {
17455
+ targetSelector = objName;
17456
+ }
17457
+ }
17373
17458
  if (targetSelector && prop?.name)
17374
17459
  memberPath = prop.name;
17375
- else {
17460
+ else if (!targetSelector && !memberPath) {
17376
17461
  const ev = await evaluator.evaluate(targetArg, context);
17377
17462
  if (typeof ev === 'string')
17378
17463
  targetSelector = ev;
@@ -20325,7 +20410,11 @@ let SetCommand = (() => {
20325
20410
  return { type: 'property', element: firstValue[0], property: 'textContent', value };
20326
20411
  }
20327
20412
  if (typeof firstValue !== 'string') {
20328
- throw new Error('set command target must be a string or object literal');
20413
+ const isMember = firstArg?.type === 'memberExpression' || firstArg?.type === 'propertyAccess';
20414
+ const hint = isMember
20415
+ ? ` (a property chain evaluated to ${firstValue === null ? 'null' : typeof firstValue} — check that all intermediate objects exist)`
20416
+ : '';
20417
+ throw new Error(`set command target must be a string or object literal${hint}`);
20329
20418
  }
20330
20419
  const value = await this.extractValue(raw, evaluator, context);
20331
20420
  return { type: 'variable', name: firstValue, value };
@@ -23534,12 +23623,19 @@ class InstallCommand {
23534
23623
  const behaviorRegistry = context.locals.get('_behaviors');
23535
23624
  if (behaviorRegistry && typeof behaviorRegistry === 'object') {
23536
23625
  const registry = behaviorRegistry;
23537
- return registry.has(behaviorName);
23626
+ if (registry.has(behaviorName))
23627
+ return true;
23628
+ if (registry.resolve && registry.resolve(behaviorName))
23629
+ return true;
23538
23630
  }
23539
23631
  if (typeof globalThis !== 'undefined') {
23540
23632
  const hyperscriptGlobal = globalThis._hyperscript;
23541
23633
  if (hyperscriptGlobal?.behaviors) {
23542
- return hyperscriptGlobal.behaviors.has(behaviorName);
23634
+ if (hyperscriptGlobal.behaviors.has(behaviorName))
23635
+ return true;
23636
+ if (hyperscriptGlobal.behaviors.resolve &&
23637
+ hyperscriptGlobal.behaviors.resolve(behaviorName))
23638
+ return true;
23543
23639
  }
23544
23640
  }
23545
23641
  return false;