@hyperfixi/core 2.2.1 → 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-BELRwj7r.js → bridge-BlRqsZT4.js} +2 -2
- package/dist/chunks/browser-modular-AbV0Ql4i.js +2 -0
- package/dist/chunks/{index-lsDi6izr.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 +153 -76
- package/dist/index.min.js +1 -1
- package/dist/index.mjs +153 -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 +119 -70
- package/dist/parser/full-parser.mjs +119 -70
- package/dist/registry/index.js +10 -0
- package/dist/registry/index.mjs +10 -0
- package/package.json +1 -1
- 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 &&
|
|
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
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
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
|
-
|
|
3127
|
-
|
|
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
|
|
3314
|
-
|
|
3315
|
-
|
|
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
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
start:
|
|
3348
|
-
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
|
-
|
|
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' &&
|
|
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
|
|
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
|
-
|
|
15014
|
-
if (!behavior)
|
|
15015
|
-
|
|
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);
|
|
@@ -20323,7 +20389,11 @@ let SetCommand = (() => {
|
|
|
20323
20389
|
return { type: 'property', element: firstValue[0], property: 'textContent', value };
|
|
20324
20390
|
}
|
|
20325
20391
|
if (typeof firstValue !== 'string') {
|
|
20326
|
-
|
|
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}`);
|
|
20327
20397
|
}
|
|
20328
20398
|
const value = await this.extractValue(raw, evaluator, context);
|
|
20329
20399
|
return { type: 'variable', name: firstValue, value };
|
|
@@ -23532,12 +23602,19 @@ class InstallCommand {
|
|
|
23532
23602
|
const behaviorRegistry = context.locals.get('_behaviors');
|
|
23533
23603
|
if (behaviorRegistry && typeof behaviorRegistry === 'object') {
|
|
23534
23604
|
const registry = behaviorRegistry;
|
|
23535
|
-
|
|
23605
|
+
if (registry.has(behaviorName))
|
|
23606
|
+
return true;
|
|
23607
|
+
if (registry.resolve && registry.resolve(behaviorName))
|
|
23608
|
+
return true;
|
|
23536
23609
|
}
|
|
23537
23610
|
if (typeof globalThis !== 'undefined') {
|
|
23538
23611
|
const hyperscriptGlobal = globalThis._hyperscript;
|
|
23539
23612
|
if (hyperscriptGlobal?.behaviors) {
|
|
23540
|
-
|
|
23613
|
+
if (hyperscriptGlobal.behaviors.has(behaviorName))
|
|
23614
|
+
return true;
|
|
23615
|
+
if (hyperscriptGlobal.behaviors.resolve &&
|
|
23616
|
+
hyperscriptGlobal.behaviors.resolve(behaviorName))
|
|
23617
|
+
return true;
|
|
23541
23618
|
}
|
|
23542
23619
|
}
|
|
23543
23620
|
return false;
|