@hyperfixi/core 2.2.0 → 2.3.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.
- package/dist/chunks/{bridge-D2DBo02Z.js → bridge-BlRqsZT4.js} +2 -2
- package/dist/chunks/browser-modular-AbV0Ql4i.js +2 -0
- package/dist/chunks/{index-C6Fn0jGB.js → index-BDYQHwCF.js} +2 -2
- package/dist/commands/index.js +14 -3
- package/dist/commands/index.mjs +14 -3
- package/dist/core/base-expression-evaluator.d.ts +4 -0
- package/dist/expressions/index.js +10 -0
- package/dist/expressions/index.mjs +10 -0
- package/dist/hyperfixi-classic-i18n.js +1 -1
- package/dist/hyperfixi-minimal.js +1 -1
- package/dist/hyperfixi-multilingual.js +1 -1
- package/dist/hyperfixi-standard.js +1 -1
- package/dist/hyperfixi.js +1 -1
- package/dist/hyperfixi.mjs +1 -1
- package/dist/index.js +154 -76
- package/dist/index.min.js +1 -1
- package/dist/index.mjs +154 -76
- package/dist/lokascript-browser-classic-i18n.js +1 -1
- package/dist/lokascript-browser-minimal.js +1 -1
- package/dist/lokascript-browser-standard.js +1 -1
- package/dist/lokascript-browser.js +1 -1
- package/dist/lokascript-multilingual.js +1 -1
- package/dist/parser/full-parser.js +120 -70
- package/dist/parser/full-parser.mjs +120 -70
- package/dist/registry/index.js +10 -0
- package/dist/registry/index.mjs +10 -0
- package/package.json +2 -2
- package/dist/chunks/browser-modular-BA3JFmkq.js +0 -2
package/dist/index.mjs
CHANGED
|
@@ -453,7 +453,10 @@ function tokenize$1(input) {
|
|
|
453
453
|
prevToken.value === '{' ||
|
|
454
454
|
prevToken.value === ',' ||
|
|
455
455
|
prevToken.value === ';';
|
|
456
|
-
|
|
456
|
+
const isAdjacentToPrev = prevToken && prevToken.end === tokenizer.position;
|
|
457
|
+
if (isCSSSelectorContext &&
|
|
458
|
+
!isAdjacentToPrev &&
|
|
459
|
+
(isAlpha(peek(tokenizer)) || peek(tokenizer) === '{')) {
|
|
457
460
|
tokenizeCSSSelector(tokenizer);
|
|
458
461
|
continue;
|
|
459
462
|
}
|
|
@@ -686,6 +689,17 @@ function tokenizeCSSSelector(tokenizer) {
|
|
|
686
689
|
const start = tokenizer.position;
|
|
687
690
|
const prefix = advance(tokenizer);
|
|
688
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
|
+
}
|
|
689
703
|
while (tokenizer.position < tokenizer.input.length) {
|
|
690
704
|
const char = tokenizer.input[tokenizer.position];
|
|
691
705
|
if (isAlphaNumeric(char) || char === '-' || char === '_' || char === ':') {
|
|
@@ -2376,33 +2390,14 @@ function parseTriggerCommand(ctx, identifierNode) {
|
|
|
2376
2390
|
});
|
|
2377
2391
|
}
|
|
2378
2392
|
}
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
const arg = allArgs[i];
|
|
2386
|
-
const argRecord = arg;
|
|
2387
|
-
const argValue = argRecord.name || argRecord.value;
|
|
2388
|
-
if ((arg.type === 'identifier' || arg.type === 'literal' || arg.type === 'keyword') &&
|
|
2389
|
-
(argValue === 'on' || argValue === 'to')) {
|
|
2390
|
-
operationIndex = i;
|
|
2391
|
-
operationKeyword = argValue;
|
|
2392
|
-
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());
|
|
2393
2399
|
}
|
|
2394
2400
|
}
|
|
2395
|
-
const finalArgs = [];
|
|
2396
|
-
if (operationIndex === -1) {
|
|
2397
|
-
finalArgs.push(...allArgs);
|
|
2398
|
-
}
|
|
2399
|
-
else {
|
|
2400
|
-
const eventArgs = allArgs.slice(0, operationIndex);
|
|
2401
|
-
const targetArgs = allArgs.slice(operationIndex + 1);
|
|
2402
|
-
finalArgs.push(...eventArgs);
|
|
2403
|
-
finalArgs.push(ctx.createIdentifier(operationKeyword));
|
|
2404
|
-
finalArgs.push(...targetArgs);
|
|
2405
|
-
}
|
|
2406
2401
|
return CommandNodeBuilder.fromIdentifier(identifierNode)
|
|
2407
2402
|
.withArgs(...finalArgs)
|
|
2408
2403
|
.endingAt(ctx.getPosition())
|
|
@@ -3122,8 +3117,13 @@ function parseSwapCommand(ctx, identifierNode) {
|
|
|
3122
3117
|
|
|
3123
3118
|
function parseWaitCommand(ctx, commandToken) {
|
|
3124
3119
|
const args = [];
|
|
3125
|
-
|
|
3126
|
-
|
|
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();
|
|
3127
3127
|
args.push(timeExpr);
|
|
3128
3128
|
return CommandNodeBuilder.from(commandToken)
|
|
3129
3129
|
.withArgs(...args)
|
|
@@ -3309,43 +3309,24 @@ function parsePropertyOfTarget(ctx, startPosition) {
|
|
|
3309
3309
|
return null;
|
|
3310
3310
|
const thePosition = ctx.savePosition();
|
|
3311
3311
|
ctx.advance();
|
|
3312
|
-
const
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
const propertyToken = ctx.advance();
|
|
3316
|
-
if (ctx.check(KEYWORDS$1.OF)) {
|
|
3317
|
-
ctx.advance();
|
|
3318
|
-
const targetToken = ctx.advance();
|
|
3319
|
-
const isIdSelector = targetToken.value.startsWith('#');
|
|
3320
|
-
return {
|
|
3321
|
-
type: 'propertyOfExpression',
|
|
3322
|
-
property: {
|
|
3323
|
-
type: 'identifier',
|
|
3324
|
-
name: propertyToken.value,
|
|
3325
|
-
start: propertyToken.start,
|
|
3326
|
-
end: propertyToken.end,
|
|
3327
|
-
},
|
|
3328
|
-
target: {
|
|
3329
|
-
type: isIdSelector ? 'idSelector' : 'cssSelector',
|
|
3330
|
-
value: targetToken.value,
|
|
3331
|
-
start: targetToken.start,
|
|
3332
|
-
end: targetToken.end,
|
|
3333
|
-
},
|
|
3334
|
-
start: startPosition,
|
|
3335
|
-
end: ctx.savePosition(),
|
|
3336
|
-
};
|
|
3337
|
-
}
|
|
3338
|
-
ctx.restorePosition(startPosition);
|
|
3312
|
+
const propertyExpr = ctx.parseExpression();
|
|
3313
|
+
if (!propertyExpr) {
|
|
3314
|
+
ctx.restorePosition(thePosition);
|
|
3339
3315
|
return null;
|
|
3340
3316
|
}
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
start:
|
|
3347
|
-
end:
|
|
3348
|
-
|
|
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;
|
|
3349
3330
|
}
|
|
3350
3331
|
ctx.restorePosition(thePosition);
|
|
3351
3332
|
return null;
|
|
@@ -3704,6 +3685,71 @@ function parseFetchNakedNamedArgs(ctx) {
|
|
|
3704
3685
|
column: startPos.column,
|
|
3705
3686
|
};
|
|
3706
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
|
+
}
|
|
3707
3753
|
function parseJsCommand(ctx, identifierNode) {
|
|
3708
3754
|
const parameters = [];
|
|
3709
3755
|
if (ctx.match('(')) {
|
|
@@ -3716,11 +3762,12 @@ function parseJsCommand(ctx, identifierNode) {
|
|
|
3716
3762
|
ctx.consume(')', 'Expected ) after js parameters');
|
|
3717
3763
|
}
|
|
3718
3764
|
const jsCodeStart = ctx.peek().start;
|
|
3719
|
-
|
|
3765
|
+
const jsCodeEnd = findJsEndBoundary(ctx, jsCodeStart);
|
|
3766
|
+
while (!ctx.isAtEnd() && !ctx.check(KEYWORDS$1.END)) {
|
|
3767
|
+
if (ctx.peek().start >= jsCodeEnd)
|
|
3768
|
+
break;
|
|
3720
3769
|
ctx.advance();
|
|
3721
3770
|
}
|
|
3722
|
-
const endToken = ctx.peek();
|
|
3723
|
-
const jsCodeEnd = endToken.start;
|
|
3724
3771
|
ctx.consume(KEYWORDS$1.END, 'Expected end after js code body');
|
|
3725
3772
|
const rawSlice = ctx.getInputSlice(jsCodeStart, jsCodeEnd);
|
|
3726
3773
|
const code = rawSlice.trim();
|
|
@@ -4623,7 +4670,12 @@ class Parser {
|
|
|
4623
4670
|
}
|
|
4624
4671
|
else {
|
|
4625
4672
|
const commandName = expr.name.toLowerCase();
|
|
4626
|
-
if (commandName === 'wait' &&
|
|
4673
|
+
if (commandName === 'wait' &&
|
|
4674
|
+
(this.checkTimeExpression() ||
|
|
4675
|
+
this.checkNumber() ||
|
|
4676
|
+
this.checkIdentifier() ||
|
|
4677
|
+
this.checkContextVar() ||
|
|
4678
|
+
this.check('('))) {
|
|
4627
4679
|
const command = this.createCommandFromIdentifier(expr);
|
|
4628
4680
|
if (command) {
|
|
4629
4681
|
expr = command;
|
|
@@ -5842,9 +5894,7 @@ class Parser {
|
|
|
5842
5894
|
while (!this.isAtEnd() && !this.check('end')) {
|
|
5843
5895
|
if (this.match('on')) {
|
|
5844
5896
|
const handlerPos = this.getPosition();
|
|
5845
|
-
const
|
|
5846
|
-
const eventName = eventToken.value;
|
|
5847
|
-
this.advance();
|
|
5897
|
+
const eventName = this.parseEventNameWithNamespace("Expected event name after 'on'");
|
|
5848
5898
|
const eventArgs = [];
|
|
5849
5899
|
if (this.check('(')) {
|
|
5850
5900
|
this.advance();
|
|
@@ -8663,6 +8713,8 @@ class BaseExpressionEvaluator {
|
|
|
8663
8713
|
return this.evaluateIdSelector(node, context);
|
|
8664
8714
|
case 'attributeAccess':
|
|
8665
8715
|
return this.evaluateAttributeAccess(node, context);
|
|
8716
|
+
case 'asExpression':
|
|
8717
|
+
return this.evaluateAsExpression(node, context);
|
|
8666
8718
|
default:
|
|
8667
8719
|
throw new Error(`Unsupported AST node type for evaluation: ${node.type}`);
|
|
8668
8720
|
}
|
|
@@ -8948,6 +9000,14 @@ class BaseExpressionEvaluator {
|
|
|
8948
9000
|
}
|
|
8949
9001
|
return `@${node.attributeName}`;
|
|
8950
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
|
+
}
|
|
8951
9011
|
getAvailableExpressions() {
|
|
8952
9012
|
return Array.from(this.expressionRegistry.keys());
|
|
8953
9013
|
}
|
|
@@ -14528,6 +14588,8 @@ class RuntimeBase {
|
|
|
14528
14588
|
this.behaviorAPI = {
|
|
14529
14589
|
has: (name) => this.behaviorRegistry.has(name),
|
|
14530
14590
|
get: (name) => this.behaviorRegistry.get(name),
|
|
14591
|
+
set: (name, definition) => this.behaviorRegistry.set(name, definition),
|
|
14592
|
+
resolve: null,
|
|
14531
14593
|
install: async (behaviorName, element, parameters) => {
|
|
14532
14594
|
return await this.installBehaviorOnElement(behaviorName, element, parameters);
|
|
14533
14595
|
},
|
|
@@ -15009,9 +15071,14 @@ class RuntimeBase {
|
|
|
15009
15071
|
}
|
|
15010
15072
|
async installBehaviorOnElement(behaviorName, element, parameters) {
|
|
15011
15073
|
debug.runtime(`BEHAVIOR: installBehaviorOnElement called: ${behaviorName}`);
|
|
15012
|
-
|
|
15013
|
-
if (!behavior)
|
|
15014
|
-
|
|
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
|
+
}
|
|
15015
15082
|
if (behavior.type === 'imperative' && typeof behavior.install === 'function') {
|
|
15016
15083
|
debug.runtime(`BEHAVIOR: Installing imperative behavior '${behaviorName}'`);
|
|
15017
15084
|
behavior.install(element, parameters);
|
|
@@ -20322,7 +20389,11 @@ let SetCommand = (() => {
|
|
|
20322
20389
|
return { type: 'property', element: firstValue[0], property: 'textContent', value };
|
|
20323
20390
|
}
|
|
20324
20391
|
if (typeof firstValue !== 'string') {
|
|
20325
|
-
|
|
20392
|
+
const isMember = firstArg?.type === 'memberExpression' || firstArg?.type === 'propertyAccess';
|
|
20393
|
+
const hint = isMember
|
|
20394
|
+
? ` (a property chain evaluated to ${firstValue === null ? 'null' : typeof firstValue} — check that all intermediate objects exist)`
|
|
20395
|
+
: '';
|
|
20396
|
+
throw new Error(`set command target must be a string or object literal${hint}`);
|
|
20326
20397
|
}
|
|
20327
20398
|
const value = await this.extractValue(raw, evaluator, context);
|
|
20328
20399
|
return { type: 'variable', name: firstValue, value };
|
|
@@ -23531,12 +23602,19 @@ class InstallCommand {
|
|
|
23531
23602
|
const behaviorRegistry = context.locals.get('_behaviors');
|
|
23532
23603
|
if (behaviorRegistry && typeof behaviorRegistry === 'object') {
|
|
23533
23604
|
const registry = behaviorRegistry;
|
|
23534
|
-
|
|
23605
|
+
if (registry.has(behaviorName))
|
|
23606
|
+
return true;
|
|
23607
|
+
if (registry.resolve && registry.resolve(behaviorName))
|
|
23608
|
+
return true;
|
|
23535
23609
|
}
|
|
23536
23610
|
if (typeof globalThis !== 'undefined') {
|
|
23537
23611
|
const hyperscriptGlobal = globalThis._hyperscript;
|
|
23538
23612
|
if (hyperscriptGlobal?.behaviors) {
|
|
23539
|
-
|
|
23613
|
+
if (hyperscriptGlobal.behaviors.has(behaviorName))
|
|
23614
|
+
return true;
|
|
23615
|
+
if (hyperscriptGlobal.behaviors.resolve &&
|
|
23616
|
+
hyperscriptGlobal.behaviors.resolve(behaviorName))
|
|
23617
|
+
return true;
|
|
23540
23618
|
}
|
|
23541
23619
|
}
|
|
23542
23620
|
return false;
|