@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
package/dist/index.mjs CHANGED
@@ -454,7 +454,9 @@ function tokenize$1(input) {
454
454
  prevToken.value === ',' ||
455
455
  prevToken.value === ';';
456
456
  const isAdjacentToPrev = prevToken && prevToken.end === tokenizer.position;
457
- if (isCSSSelectorContext && !isAdjacentToPrev && isAlpha(peek(tokenizer))) {
457
+ if (isCSSSelectorContext &&
458
+ !isAdjacentToPrev &&
459
+ (isAlpha(peek(tokenizer)) || peek(tokenizer) === '{')) {
458
460
  tokenizeCSSSelector(tokenizer);
459
461
  continue;
460
462
  }
@@ -687,6 +689,17 @@ function tokenizeCSSSelector(tokenizer) {
687
689
  const start = tokenizer.position;
688
690
  const prefix = advance(tokenizer);
689
691
  let value = prefix;
692
+ if (tokenizer.position < tokenizer.input.length && tokenizer.input[tokenizer.position] === '{') {
693
+ value += advance(tokenizer);
694
+ while (tokenizer.position < tokenizer.input.length) {
695
+ const ch = tokenizer.input[tokenizer.position];
696
+ value += advance(tokenizer);
697
+ if (ch === '}')
698
+ break;
699
+ }
700
+ addToken(tokenizer, TokenKind.SELECTOR, value, start);
701
+ return;
702
+ }
690
703
  while (tokenizer.position < tokenizer.input.length) {
691
704
  const char = tokenizer.input[tokenizer.position];
692
705
  if (isAlphaNumeric(char) || char === '-' || char === '_' || char === ':') {
@@ -2377,33 +2390,14 @@ function parseTriggerCommand(ctx, identifierNode) {
2377
2390
  });
2378
2391
  }
2379
2392
  }
2380
- while (!isCommandBoundary(ctx)) {
2381
- allArgs.push(ctx.parsePrimary());
2382
- }
2383
- let operationIndex = -1;
2384
- let operationKeyword = 'on';
2385
- for (let i = 0; i < allArgs.length; i++) {
2386
- const arg = allArgs[i];
2387
- const argRecord = arg;
2388
- const argValue = argRecord.name || argRecord.value;
2389
- if ((arg.type === 'identifier' || arg.type === 'literal' || arg.type === 'keyword') &&
2390
- (argValue === 'on' || argValue === 'to')) {
2391
- operationIndex = i;
2392
- operationKeyword = argValue;
2393
- break;
2393
+ const finalArgs = [...allArgs];
2394
+ if (ctx.check('on') || ctx.check('to')) {
2395
+ const keyword = ctx.advance().value;
2396
+ finalArgs.push(ctx.createIdentifier(keyword));
2397
+ while (!isCommandBoundary(ctx)) {
2398
+ finalArgs.push(ctx.parsePrimary());
2394
2399
  }
2395
2400
  }
2396
- const finalArgs = [];
2397
- if (operationIndex === -1) {
2398
- finalArgs.push(...allArgs);
2399
- }
2400
- else {
2401
- const eventArgs = allArgs.slice(0, operationIndex);
2402
- const targetArgs = allArgs.slice(operationIndex + 1);
2403
- finalArgs.push(...eventArgs);
2404
- finalArgs.push(ctx.createIdentifier(operationKeyword));
2405
- finalArgs.push(...targetArgs);
2406
- }
2407
2401
  return CommandNodeBuilder.fromIdentifier(identifierNode)
2408
2402
  .withArgs(...finalArgs)
2409
2403
  .endingAt(ctx.getPosition())
@@ -3123,8 +3117,13 @@ function parseSwapCommand(ctx, identifierNode) {
3123
3117
 
3124
3118
  function parseWaitCommand(ctx, commandToken) {
3125
3119
  const args = [];
3126
- if (ctx.checkTimeExpression() || ctx.checkLiteral()) {
3127
- const timeExpr = ctx.parsePrimary();
3120
+ const isExpressionStart = ctx.checkTimeExpression() ||
3121
+ ctx.checkLiteral() ||
3122
+ ctx.checkContextVar() ||
3123
+ ctx.check('(') ||
3124
+ (ctx.checkIdentifierLike() && !ctx.check('for') && !isCommandBoundary(ctx));
3125
+ if (isExpressionStart) {
3126
+ const timeExpr = ctx.parseExpression();
3128
3127
  args.push(timeExpr);
3129
3128
  return CommandNodeBuilder.from(commandToken)
3130
3129
  .withArgs(...args)
@@ -3310,43 +3309,24 @@ function parsePropertyOfTarget(ctx, startPosition) {
3310
3309
  return null;
3311
3310
  const thePosition = ctx.savePosition();
3312
3311
  ctx.advance();
3313
- const nextToken = ctx.peek();
3314
- const tokenAfterNext = ctx.peekAt(1);
3315
- if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS$1.OF) {
3316
- const propertyToken = ctx.advance();
3317
- if (ctx.check(KEYWORDS$1.OF)) {
3318
- ctx.advance();
3319
- const targetToken = ctx.advance();
3320
- const isIdSelector = targetToken.value.startsWith('#');
3321
- return {
3322
- type: 'propertyOfExpression',
3323
- property: {
3324
- type: 'identifier',
3325
- name: propertyToken.value,
3326
- start: propertyToken.start,
3327
- end: propertyToken.end,
3328
- },
3329
- target: {
3330
- type: isIdSelector ? 'idSelector' : 'cssSelector',
3331
- value: targetToken.value,
3332
- start: targetToken.start,
3333
- end: targetToken.end,
3334
- },
3335
- start: startPosition,
3336
- end: ctx.savePosition(),
3337
- };
3338
- }
3339
- ctx.restorePosition(startPosition);
3312
+ const propertyExpr = ctx.parseExpression();
3313
+ if (!propertyExpr) {
3314
+ ctx.restorePosition(thePosition);
3340
3315
  return null;
3341
3316
  }
3342
- if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS$1.TO) {
3343
- const variableToken = ctx.advance();
3344
- return {
3345
- type: 'identifier',
3346
- name: variableToken.value,
3347
- start: variableToken.start,
3348
- end: variableToken.end,
3349
- };
3317
+ const exprAny = propertyExpr;
3318
+ if (exprAny.type === 'binaryExpression' && exprAny.operator === KEYWORDS$1.OF) {
3319
+ const property = exprAny.left;
3320
+ const target = exprAny.right;
3321
+ return createPropertyOfExpression(property, target, {
3322
+ start: property.start ?? 0,
3323
+ end: target.end ?? 0,
3324
+ line: property.line ?? 1,
3325
+ column: property.column ?? 1,
3326
+ });
3327
+ }
3328
+ if (ctx.check(KEYWORDS$1.TO)) {
3329
+ return propertyExpr;
3350
3330
  }
3351
3331
  ctx.restorePosition(thePosition);
3352
3332
  return null;
@@ -3705,6 +3685,71 @@ function parseFetchNakedNamedArgs(ctx) {
3705
3685
  column: startPos.column,
3706
3686
  };
3707
3687
  }
3688
+ function findJsEndBoundary(ctx, startPos) {
3689
+ const input = ctx.getInputSlice(startPos);
3690
+ if (!input) {
3691
+ return startPos;
3692
+ }
3693
+ let i = 0;
3694
+ while (i < input.length) {
3695
+ const ch = input[i];
3696
+ if (ch === "'" || ch === '\u2019' || ch === '\u2018') {
3697
+ i++;
3698
+ while (i < input.length && input[i] !== ch) {
3699
+ if (input[i] === '\\')
3700
+ i++;
3701
+ i++;
3702
+ }
3703
+ i++;
3704
+ continue;
3705
+ }
3706
+ if (ch === '"') {
3707
+ i++;
3708
+ while (i < input.length && input[i] !== '"') {
3709
+ if (input[i] === '\\')
3710
+ i++;
3711
+ i++;
3712
+ }
3713
+ i++;
3714
+ continue;
3715
+ }
3716
+ if (ch === '`') {
3717
+ i++;
3718
+ while (i < input.length && input[i] !== '`') {
3719
+ if (input[i] === '\\')
3720
+ i++;
3721
+ i++;
3722
+ }
3723
+ i++;
3724
+ continue;
3725
+ }
3726
+ if (ch === '/' && i + 1 < input.length && input[i + 1] === '/') {
3727
+ i += 2;
3728
+ while (i < input.length && input[i] !== '\n')
3729
+ i++;
3730
+ continue;
3731
+ }
3732
+ if (ch === '/' && i + 1 < input.length && input[i + 1] === '*') {
3733
+ i += 2;
3734
+ while (i < input.length &&
3735
+ !(input[i] === '*' && i + 1 < input.length && input[i + 1] === '/'))
3736
+ i++;
3737
+ i += 2;
3738
+ continue;
3739
+ }
3740
+ if ((ch === 'e' || ch === 'E') &&
3741
+ i + 3 <= input.length &&
3742
+ input.slice(i, i + 3).toLowerCase() === 'end') {
3743
+ const before = i === 0 || !/[a-zA-Z0-9_]/.test(input[i - 1]);
3744
+ const after = i + 3 >= input.length || !/[a-zA-Z0-9_]/.test(input[i + 3]);
3745
+ if (before && after) {
3746
+ return startPos + i;
3747
+ }
3748
+ }
3749
+ i++;
3750
+ }
3751
+ return startPos + input.length;
3752
+ }
3708
3753
  function parseJsCommand(ctx, identifierNode) {
3709
3754
  const parameters = [];
3710
3755
  if (ctx.match('(')) {
@@ -3717,11 +3762,12 @@ function parseJsCommand(ctx, identifierNode) {
3717
3762
  ctx.consume(')', 'Expected ) after js parameters');
3718
3763
  }
3719
3764
  const jsCodeStart = ctx.peek().start;
3720
- while (!ctx.check(KEYWORDS$1.END) && !ctx.isAtEnd()) {
3765
+ const jsCodeEnd = findJsEndBoundary(ctx, jsCodeStart);
3766
+ while (!ctx.isAtEnd() && !ctx.check(KEYWORDS$1.END)) {
3767
+ if (ctx.peek().start >= jsCodeEnd)
3768
+ break;
3721
3769
  ctx.advance();
3722
3770
  }
3723
- const endToken = ctx.peek();
3724
- const jsCodeEnd = endToken.start;
3725
3771
  ctx.consume(KEYWORDS$1.END, 'Expected end after js code body');
3726
3772
  const rawSlice = ctx.getInputSlice(jsCodeStart, jsCodeEnd);
3727
3773
  const code = rawSlice.trim();
@@ -4624,7 +4670,12 @@ class Parser {
4624
4670
  }
4625
4671
  else {
4626
4672
  const commandName = expr.name.toLowerCase();
4627
- if (commandName === 'wait' && this.checkTimeExpression()) {
4673
+ if (commandName === 'wait' &&
4674
+ (this.checkTimeExpression() ||
4675
+ this.checkNumber() ||
4676
+ this.checkIdentifier() ||
4677
+ this.checkContextVar() ||
4678
+ this.check('('))) {
4628
4679
  const command = this.createCommandFromIdentifier(expr);
4629
4680
  if (command) {
4630
4681
  expr = command;
@@ -5843,9 +5894,7 @@ class Parser {
5843
5894
  while (!this.isAtEnd() && !this.check('end')) {
5844
5895
  if (this.match('on')) {
5845
5896
  const handlerPos = this.getPosition();
5846
- const eventToken = this.peek();
5847
- const eventName = eventToken.value;
5848
- this.advance();
5897
+ const eventName = this.parseEventNameWithNamespace("Expected event name after 'on'");
5849
5898
  const eventArgs = [];
5850
5899
  if (this.check('(')) {
5851
5900
  this.advance();
@@ -8664,6 +8713,8 @@ class BaseExpressionEvaluator {
8664
8713
  return this.evaluateIdSelector(node, context);
8665
8714
  case 'attributeAccess':
8666
8715
  return this.evaluateAttributeAccess(node, context);
8716
+ case 'asExpression':
8717
+ return this.evaluateAsExpression(node, context);
8667
8718
  default:
8668
8719
  throw new Error(`Unsupported AST node type for evaluation: ${node.type}`);
8669
8720
  }
@@ -8949,6 +9000,14 @@ class BaseExpressionEvaluator {
8949
9000
  }
8950
9001
  return `@${node.attributeName}`;
8951
9002
  }
9003
+ async evaluateAsExpression(node, context) {
9004
+ const value = await this.evaluate(node.expression, context);
9005
+ const asExpr = this.expressionRegistry.get('as');
9006
+ if (asExpr) {
9007
+ return asExpr.evaluate(context, value, node.targetType);
9008
+ }
9009
+ throw new Error(`Conversion type 'as' not registered`);
9010
+ }
8952
9011
  getAvailableExpressions() {
8953
9012
  return Array.from(this.expressionRegistry.keys());
8954
9013
  }
@@ -14529,6 +14588,8 @@ class RuntimeBase {
14529
14588
  this.behaviorAPI = {
14530
14589
  has: (name) => this.behaviorRegistry.has(name),
14531
14590
  get: (name) => this.behaviorRegistry.get(name),
14591
+ set: (name, definition) => this.behaviorRegistry.set(name, definition),
14592
+ resolve: null,
14532
14593
  install: async (behaviorName, element, parameters) => {
14533
14594
  return await this.installBehaviorOnElement(behaviorName, element, parameters);
14534
14595
  },
@@ -15010,9 +15071,14 @@ class RuntimeBase {
15010
15071
  }
15011
15072
  async installBehaviorOnElement(behaviorName, element, parameters) {
15012
15073
  debug.runtime(`BEHAVIOR: installBehaviorOnElement called: ${behaviorName}`);
15013
- const behavior = this.behaviorRegistry.get(behaviorName);
15014
- if (!behavior)
15015
- throw new Error(`Behavior "${behaviorName}" not found`);
15074
+ let behavior = this.behaviorRegistry.get(behaviorName);
15075
+ if (!behavior) {
15076
+ if (this.behaviorAPI.resolve && this.behaviorAPI.resolve(behaviorName)) {
15077
+ behavior = this.behaviorRegistry.get(behaviorName);
15078
+ }
15079
+ if (!behavior)
15080
+ throw new Error(`Behavior "${behaviorName}" not found`);
15081
+ }
15016
15082
  if (behavior.type === 'imperative' && typeof behavior.install === 'function') {
15017
15083
  debug.runtime(`BEHAVIOR: Installing imperative behavior '${behaviorName}'`);
15018
15084
  behavior.install(element, parameters);
@@ -17366,11 +17432,30 @@ let PutCommand = (() => {
17366
17432
  const obj = targetArg.object, prop = targetArg.property;
17367
17433
  if (obj?.type === 'selector')
17368
17434
  targetSelector = obj.value;
17369
- else if (obj?.type === 'identifier')
17370
- targetSelector = obj.name;
17435
+ else if (obj?.type === 'identifier') {
17436
+ const objName = obj.name;
17437
+ if (objName === 'my' || objName === 'me' || objName === 'I') {
17438
+ if (context.me && prop?.name) {
17439
+ return {
17440
+ value,
17441
+ targets: [context.me],
17442
+ position: 'replace',
17443
+ memberPath: prop.name,
17444
+ };
17445
+ }
17446
+ }
17447
+ else if (objName === 'its' || objName === 'it') {
17448
+ const ev = await evaluator.evaluate(targetArg, context);
17449
+ if (typeof ev === 'string')
17450
+ targetSelector = ev;
17451
+ }
17452
+ else {
17453
+ targetSelector = objName;
17454
+ }
17455
+ }
17371
17456
  if (targetSelector && prop?.name)
17372
17457
  memberPath = prop.name;
17373
- else {
17458
+ else if (!targetSelector && !memberPath) {
17374
17459
  const ev = await evaluator.evaluate(targetArg, context);
17375
17460
  if (typeof ev === 'string')
17376
17461
  targetSelector = ev;
@@ -20323,7 +20408,11 @@ let SetCommand = (() => {
20323
20408
  return { type: 'property', element: firstValue[0], property: 'textContent', value };
20324
20409
  }
20325
20410
  if (typeof firstValue !== 'string') {
20326
- throw new Error('set command target must be a string or object literal');
20411
+ const isMember = firstArg?.type === 'memberExpression' || firstArg?.type === 'propertyAccess';
20412
+ const hint = isMember
20413
+ ? ` (a property chain evaluated to ${firstValue === null ? 'null' : typeof firstValue} — check that all intermediate objects exist)`
20414
+ : '';
20415
+ throw new Error(`set command target must be a string or object literal${hint}`);
20327
20416
  }
20328
20417
  const value = await this.extractValue(raw, evaluator, context);
20329
20418
  return { type: 'variable', name: firstValue, value };
@@ -23532,12 +23621,19 @@ class InstallCommand {
23532
23621
  const behaviorRegistry = context.locals.get('_behaviors');
23533
23622
  if (behaviorRegistry && typeof behaviorRegistry === 'object') {
23534
23623
  const registry = behaviorRegistry;
23535
- return registry.has(behaviorName);
23624
+ if (registry.has(behaviorName))
23625
+ return true;
23626
+ if (registry.resolve && registry.resolve(behaviorName))
23627
+ return true;
23536
23628
  }
23537
23629
  if (typeof globalThis !== 'undefined') {
23538
23630
  const hyperscriptGlobal = globalThis._hyperscript;
23539
23631
  if (hyperscriptGlobal?.behaviors) {
23540
- return hyperscriptGlobal.behaviors.has(behaviorName);
23632
+ if (hyperscriptGlobal.behaviors.has(behaviorName))
23633
+ return true;
23634
+ if (hyperscriptGlobal.behaviors.resolve &&
23635
+ hyperscriptGlobal.behaviors.resolve(behaviorName))
23636
+ return true;
23541
23637
  }
23542
23638
  }
23543
23639
  return false;