@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
|
@@ -455,7 +455,10 @@ function tokenize(input) {
|
|
|
455
455
|
prevToken.value === '{' ||
|
|
456
456
|
prevToken.value === ',' ||
|
|
457
457
|
prevToken.value === ';';
|
|
458
|
-
|
|
458
|
+
const isAdjacentToPrev = prevToken && prevToken.end === tokenizer.position;
|
|
459
|
+
if (isCSSSelectorContext &&
|
|
460
|
+
!isAdjacentToPrev &&
|
|
461
|
+
(isAlpha(peek(tokenizer)) || peek(tokenizer) === '{')) {
|
|
459
462
|
tokenizeCSSSelector(tokenizer);
|
|
460
463
|
continue;
|
|
461
464
|
}
|
|
@@ -688,6 +691,17 @@ function tokenizeCSSSelector(tokenizer) {
|
|
|
688
691
|
const start = tokenizer.position;
|
|
689
692
|
const prefix = advance(tokenizer);
|
|
690
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
|
+
}
|
|
691
705
|
while (tokenizer.position < tokenizer.input.length) {
|
|
692
706
|
const char = tokenizer.input[tokenizer.position];
|
|
693
707
|
if (isAlphaNumeric(char) || char === '-' || char === '_' || char === ':') {
|
|
@@ -2378,33 +2392,14 @@ function parseTriggerCommand(ctx, identifierNode) {
|
|
|
2378
2392
|
});
|
|
2379
2393
|
}
|
|
2380
2394
|
}
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
const arg = allArgs[i];
|
|
2388
|
-
const argRecord = arg;
|
|
2389
|
-
const argValue = argRecord.name || argRecord.value;
|
|
2390
|
-
if ((arg.type === 'identifier' || arg.type === 'literal' || arg.type === 'keyword') &&
|
|
2391
|
-
(argValue === 'on' || argValue === 'to')) {
|
|
2392
|
-
operationIndex = i;
|
|
2393
|
-
operationKeyword = argValue;
|
|
2394
|
-
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());
|
|
2395
2401
|
}
|
|
2396
2402
|
}
|
|
2397
|
-
const finalArgs = [];
|
|
2398
|
-
if (operationIndex === -1) {
|
|
2399
|
-
finalArgs.push(...allArgs);
|
|
2400
|
-
}
|
|
2401
|
-
else {
|
|
2402
|
-
const eventArgs = allArgs.slice(0, operationIndex);
|
|
2403
|
-
const targetArgs = allArgs.slice(operationIndex + 1);
|
|
2404
|
-
finalArgs.push(...eventArgs);
|
|
2405
|
-
finalArgs.push(ctx.createIdentifier(operationKeyword));
|
|
2406
|
-
finalArgs.push(...targetArgs);
|
|
2407
|
-
}
|
|
2408
2403
|
return CommandNodeBuilder.fromIdentifier(identifierNode)
|
|
2409
2404
|
.withArgs(...finalArgs)
|
|
2410
2405
|
.endingAt(ctx.getPosition())
|
|
@@ -3124,8 +3119,13 @@ function parseSwapCommand(ctx, identifierNode) {
|
|
|
3124
3119
|
|
|
3125
3120
|
function parseWaitCommand(ctx, commandToken) {
|
|
3126
3121
|
const args = [];
|
|
3127
|
-
|
|
3128
|
-
|
|
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();
|
|
3129
3129
|
args.push(timeExpr);
|
|
3130
3130
|
return CommandNodeBuilder.from(commandToken)
|
|
3131
3131
|
.withArgs(...args)
|
|
@@ -3311,43 +3311,24 @@ function parsePropertyOfTarget(ctx, startPosition) {
|
|
|
3311
3311
|
return null;
|
|
3312
3312
|
const thePosition = ctx.savePosition();
|
|
3313
3313
|
ctx.advance();
|
|
3314
|
-
const
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
const propertyToken = ctx.advance();
|
|
3318
|
-
if (ctx.check(KEYWORDS.OF)) {
|
|
3319
|
-
ctx.advance();
|
|
3320
|
-
const targetToken = ctx.advance();
|
|
3321
|
-
const isIdSelector = targetToken.value.startsWith('#');
|
|
3322
|
-
return {
|
|
3323
|
-
type: 'propertyOfExpression',
|
|
3324
|
-
property: {
|
|
3325
|
-
type: 'identifier',
|
|
3326
|
-
name: propertyToken.value,
|
|
3327
|
-
start: propertyToken.start,
|
|
3328
|
-
end: propertyToken.end,
|
|
3329
|
-
},
|
|
3330
|
-
target: {
|
|
3331
|
-
type: isIdSelector ? 'idSelector' : 'cssSelector',
|
|
3332
|
-
value: targetToken.value,
|
|
3333
|
-
start: targetToken.start,
|
|
3334
|
-
end: targetToken.end,
|
|
3335
|
-
},
|
|
3336
|
-
start: startPosition,
|
|
3337
|
-
end: ctx.savePosition(),
|
|
3338
|
-
};
|
|
3339
|
-
}
|
|
3340
|
-
ctx.restorePosition(startPosition);
|
|
3314
|
+
const propertyExpr = ctx.parseExpression();
|
|
3315
|
+
if (!propertyExpr) {
|
|
3316
|
+
ctx.restorePosition(thePosition);
|
|
3341
3317
|
return null;
|
|
3342
3318
|
}
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
start:
|
|
3349
|
-
end:
|
|
3350
|
-
|
|
3319
|
+
const exprAny = propertyExpr;
|
|
3320
|
+
if (exprAny.type === 'binaryExpression' && exprAny.operator === KEYWORDS.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.TO)) {
|
|
3331
|
+
return propertyExpr;
|
|
3351
3332
|
}
|
|
3352
3333
|
ctx.restorePosition(thePosition);
|
|
3353
3334
|
return null;
|
|
@@ -3706,6 +3687,71 @@ function parseFetchNakedNamedArgs(ctx) {
|
|
|
3706
3687
|
column: startPos.column,
|
|
3707
3688
|
};
|
|
3708
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
|
+
}
|
|
3709
3755
|
function parseJsCommand(ctx, identifierNode) {
|
|
3710
3756
|
const parameters = [];
|
|
3711
3757
|
if (ctx.match('(')) {
|
|
@@ -3718,11 +3764,12 @@ function parseJsCommand(ctx, identifierNode) {
|
|
|
3718
3764
|
ctx.consume(')', 'Expected ) after js parameters');
|
|
3719
3765
|
}
|
|
3720
3766
|
const jsCodeStart = ctx.peek().start;
|
|
3721
|
-
|
|
3767
|
+
const jsCodeEnd = findJsEndBoundary(ctx, jsCodeStart);
|
|
3768
|
+
while (!ctx.isAtEnd() && !ctx.check(KEYWORDS.END)) {
|
|
3769
|
+
if (ctx.peek().start >= jsCodeEnd)
|
|
3770
|
+
break;
|
|
3722
3771
|
ctx.advance();
|
|
3723
3772
|
}
|
|
3724
|
-
const endToken = ctx.peek();
|
|
3725
|
-
const jsCodeEnd = endToken.start;
|
|
3726
3773
|
ctx.consume(KEYWORDS.END, 'Expected end after js code body');
|
|
3727
3774
|
const rawSlice = ctx.getInputSlice(jsCodeStart, jsCodeEnd);
|
|
3728
3775
|
const code = rawSlice.trim();
|
|
@@ -4625,7 +4672,12 @@ class Parser {
|
|
|
4625
4672
|
}
|
|
4626
4673
|
else {
|
|
4627
4674
|
const commandName = expr.name.toLowerCase();
|
|
4628
|
-
if (commandName === 'wait' &&
|
|
4675
|
+
if (commandName === 'wait' &&
|
|
4676
|
+
(this.checkTimeExpression() ||
|
|
4677
|
+
this.checkNumber() ||
|
|
4678
|
+
this.checkIdentifier() ||
|
|
4679
|
+
this.checkContextVar() ||
|
|
4680
|
+
this.check('('))) {
|
|
4629
4681
|
const command = this.createCommandFromIdentifier(expr);
|
|
4630
4682
|
if (command) {
|
|
4631
4683
|
expr = command;
|
|
@@ -5844,9 +5896,7 @@ class Parser {
|
|
|
5844
5896
|
while (!this.isAtEnd() && !this.check('end')) {
|
|
5845
5897
|
if (this.match('on')) {
|
|
5846
5898
|
const handlerPos = this.getPosition();
|
|
5847
|
-
const
|
|
5848
|
-
const eventName = eventToken.value;
|
|
5849
|
-
this.advance();
|
|
5899
|
+
const eventName = this.parseEventNameWithNamespace("Expected event name after 'on'");
|
|
5850
5900
|
const eventArgs = [];
|
|
5851
5901
|
if (this.check('(')) {
|
|
5852
5902
|
this.advance();
|
|
@@ -453,7 +453,10 @@ function tokenize(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.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.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.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.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.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();
|
package/dist/registry/index.js
CHANGED
|
@@ -1647,6 +1647,8 @@ class BaseExpressionEvaluator {
|
|
|
1647
1647
|
return this.evaluateIdSelector(node, context);
|
|
1648
1648
|
case 'attributeAccess':
|
|
1649
1649
|
return this.evaluateAttributeAccess(node, context);
|
|
1650
|
+
case 'asExpression':
|
|
1651
|
+
return this.evaluateAsExpression(node, context);
|
|
1650
1652
|
default:
|
|
1651
1653
|
throw new Error(`Unsupported AST node type for evaluation: ${node.type}`);
|
|
1652
1654
|
}
|
|
@@ -1932,6 +1934,14 @@ class BaseExpressionEvaluator {
|
|
|
1932
1934
|
}
|
|
1933
1935
|
return `@${node.attributeName}`;
|
|
1934
1936
|
}
|
|
1937
|
+
async evaluateAsExpression(node, context) {
|
|
1938
|
+
const value = await this.evaluate(node.expression, context);
|
|
1939
|
+
const asExpr = this.expressionRegistry.get('as');
|
|
1940
|
+
if (asExpr) {
|
|
1941
|
+
return asExpr.evaluate(context, value, node.targetType);
|
|
1942
|
+
}
|
|
1943
|
+
throw new Error(`Conversion type 'as' not registered`);
|
|
1944
|
+
}
|
|
1935
1945
|
getAvailableExpressions() {
|
|
1936
1946
|
return Array.from(this.expressionRegistry.keys());
|
|
1937
1947
|
}
|
package/dist/registry/index.mjs
CHANGED
|
@@ -1645,6 +1645,8 @@ class BaseExpressionEvaluator {
|
|
|
1645
1645
|
return this.evaluateIdSelector(node, context);
|
|
1646
1646
|
case 'attributeAccess':
|
|
1647
1647
|
return this.evaluateAttributeAccess(node, context);
|
|
1648
|
+
case 'asExpression':
|
|
1649
|
+
return this.evaluateAsExpression(node, context);
|
|
1648
1650
|
default:
|
|
1649
1651
|
throw new Error(`Unsupported AST node type for evaluation: ${node.type}`);
|
|
1650
1652
|
}
|
|
@@ -1930,6 +1932,14 @@ class BaseExpressionEvaluator {
|
|
|
1930
1932
|
}
|
|
1931
1933
|
return `@${node.attributeName}`;
|
|
1932
1934
|
}
|
|
1935
|
+
async evaluateAsExpression(node, context) {
|
|
1936
|
+
const value = await this.evaluate(node.expression, context);
|
|
1937
|
+
const asExpr = this.expressionRegistry.get('as');
|
|
1938
|
+
if (asExpr) {
|
|
1939
|
+
return asExpr.evaluate(context, value, node.targetType);
|
|
1940
|
+
}
|
|
1941
|
+
throw new Error(`Conversion type 'as' not registered`);
|
|
1942
|
+
}
|
|
1933
1943
|
getAvailableExpressions() {
|
|
1934
1944
|
return Array.from(this.expressionRegistry.keys());
|
|
1935
1945
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperfixi/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Multilingual, tree-shakeable hyperscript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -236,7 +236,7 @@
|
|
|
236
236
|
"@vitest/coverage-v8": "^4.0.17",
|
|
237
237
|
"@vitest/ui": "^4.0.17",
|
|
238
238
|
"better-sqlite3": "^12.6.2",
|
|
239
|
-
"esbuild": "0.27.
|
|
239
|
+
"esbuild": "0.27.4",
|
|
240
240
|
"eslint": "^8.57.1",
|
|
241
241
|
"eslint-config-prettier": "^9.0.0",
|
|
242
242
|
"eslint-plugin-prettier": "^5.0.0",
|