@hyperfixi/core 2.9.1 → 2.9.3
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/bundle-generator/index.js +6 -0
- package/dist/bundle-generator/index.mjs +6 -0
- package/dist/bundle-generator/parser-templates.d.ts +1 -1
- package/dist/chunks/{bridge-BYhqTOnL.js → bridge-DwtNLKK3.js} +2 -2
- package/dist/chunks/browser-modular-6HT1r2AH.js +2 -0
- package/dist/chunks/{index-DXgJaDj-.js → index-B8jwvuj_.js} +2 -2
- package/dist/commands/index.js +133 -74
- package/dist/commands/index.mjs +133 -74
- package/dist/hyperfixi-browser-classic-i18n.js +1 -1
- package/dist/hyperfixi-browser-minimal.js +1 -1
- package/dist/hyperfixi-browser-standard.js +1 -1
- package/dist/hyperfixi-browser.js +1 -1
- package/dist/hyperfixi-classic-i18n.js +1 -1
- package/dist/hyperfixi-hx-v4.js +1 -1
- package/dist/hyperfixi-hx.js +1 -1
- package/dist/hyperfixi-hybrid-complete.js +1 -1
- package/dist/hyperfixi-hybrid-hx.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 +233 -79
- package/dist/index.min.js +1 -1
- package/dist/index.mjs +233 -79
- 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-hybrid-complete.js +1 -1
- package/dist/lokascript-hybrid-hx.js +1 -1
- package/dist/lokascript-multilingual.js +1 -1
- package/dist/parser/command-parsers/utility-commands.d.ts +1 -1
- package/dist/parser/full-parser.js +133 -74
- package/dist/parser/full-parser.mjs +133 -74
- package/dist/parser/hybrid/index.js +3 -0
- package/dist/parser/hybrid/index.mjs +3 -0
- package/dist/parser/hybrid/parser-core.js +3 -0
- package/dist/parser/hybrid/parser-core.mjs +3 -0
- package/dist/parser/hybrid-parser.js +3 -0
- package/dist/parser/hybrid-parser.mjs +3 -0
- package/dist/reference/index.js +1 -0
- package/dist/reference/index.mjs +1 -0
- package/dist/registry/index.js +133 -74
- package/dist/registry/index.mjs +133 -74
- package/dist/runtime/runtime-base.d.ts +2 -1
- package/dist/types/core.d.ts +1 -0
- package/package.json +6 -6
- package/dist/chunks/browser-modular-D2BHzZFB.js +0 -2
package/dist/hyperfixi.mjs
CHANGED
|
@@ -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 tokenize}from"./chunks/browser-modular-
|
|
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 tokenize}from"./chunks/browser-modular-6HT1r2AH.js";import"./chunks/feature-sockets-CcTxD5sT.js";
|
|
2
2
|
//# sourceMappingURL=hyperfixi.mjs.map
|
package/dist/index.js
CHANGED
|
@@ -516,13 +516,13 @@ function tokenize$1(input) {
|
|
|
516
516
|
continue;
|
|
517
517
|
}
|
|
518
518
|
if (char === '{') {
|
|
519
|
-
addToken(tokenizer, TokenKind.OPERATOR, '{');
|
|
520
519
|
advance(tokenizer);
|
|
520
|
+
addToken(tokenizer, TokenKind.OPERATOR, '{');
|
|
521
521
|
continue;
|
|
522
522
|
}
|
|
523
523
|
if (char === '}') {
|
|
524
|
-
addToken(tokenizer, TokenKind.OPERATOR, '}');
|
|
525
524
|
advance(tokenizer);
|
|
525
|
+
addToken(tokenizer, TokenKind.OPERATOR, '}');
|
|
526
526
|
continue;
|
|
527
527
|
}
|
|
528
528
|
if (char === '[') {
|
|
@@ -538,24 +538,24 @@ function tokenize$1(input) {
|
|
|
538
538
|
prevToken.value === ']') &&
|
|
539
539
|
!isEventCondition;
|
|
540
540
|
if (isMemberAccess) {
|
|
541
|
-
addToken(tokenizer, TokenKind.OPERATOR, '[');
|
|
542
541
|
advance(tokenizer);
|
|
542
|
+
addToken(tokenizer, TokenKind.OPERATOR, '[');
|
|
543
543
|
}
|
|
544
544
|
else {
|
|
545
545
|
if (isEventCondition) {
|
|
546
|
-
addToken(tokenizer, TokenKind.SYMBOL, '[');
|
|
547
546
|
advance(tokenizer);
|
|
547
|
+
addToken(tokenizer, TokenKind.SYMBOL, '[');
|
|
548
548
|
}
|
|
549
549
|
else {
|
|
550
|
-
addToken(tokenizer, TokenKind.OPERATOR, '[');
|
|
551
550
|
advance(tokenizer);
|
|
551
|
+
addToken(tokenizer, TokenKind.OPERATOR, '[');
|
|
552
552
|
}
|
|
553
553
|
}
|
|
554
554
|
continue;
|
|
555
555
|
}
|
|
556
556
|
if (char === ']') {
|
|
557
|
-
addToken(tokenizer, TokenKind.OPERATOR, ']');
|
|
558
557
|
advance(tokenizer);
|
|
558
|
+
addToken(tokenizer, TokenKind.OPERATOR, ']');
|
|
559
559
|
continue;
|
|
560
560
|
}
|
|
561
561
|
if (char === '$') {
|
|
@@ -2982,7 +2982,6 @@ const MULTI_WORD_PATTERNS = [
|
|
|
2982
2982
|
keywords: ['a', 'an', 'from', 'called'],
|
|
2983
2983
|
syntax: 'make (a|an) <type> [from <args>] [called <name>]',
|
|
2984
2984
|
},
|
|
2985
|
-
{ command: 'send', keywords: ['to'], syntax: 'send <event> to <target>' },
|
|
2986
2985
|
{ command: 'throw', keywords: [], syntax: 'throw <error>' },
|
|
2987
2986
|
];
|
|
2988
2987
|
function getMultiWordPattern(commandName) {
|
|
@@ -3283,7 +3282,13 @@ function parseTriggerCommand(ctx, identifierNode) {
|
|
|
3283
3282
|
finalArgs.push(ctx.createIdentifier(keyword));
|
|
3284
3283
|
continue;
|
|
3285
3284
|
}
|
|
3286
|
-
|
|
3285
|
+
const before = ctx.savePosition();
|
|
3286
|
+
const expr = ctx.parsePrimary();
|
|
3287
|
+
if (expr)
|
|
3288
|
+
finalArgs.push(expr);
|
|
3289
|
+
if (ctx.savePosition() === before) {
|
|
3290
|
+
ctx.advance();
|
|
3291
|
+
}
|
|
3287
3292
|
}
|
|
3288
3293
|
return CommandNodeBuilder.fromIdentifier(identifierNode)
|
|
3289
3294
|
.withArgs(...finalArgs)
|
|
@@ -3502,11 +3507,64 @@ function parseRepeatCommand(ctx, commandToken) {
|
|
|
3502
3507
|
}
|
|
3503
3508
|
return builder.endingAt(ctx.getPosition()).build();
|
|
3504
3509
|
}
|
|
3510
|
+
function parseIfBranchCommands(ctx, stopAtElse) {
|
|
3511
|
+
const commands = [];
|
|
3512
|
+
const atTerminator = () => ctx.check(KEYWORDS$1.END) || (stopAtElse && ctx.check(KEYWORDS$1.ELSE));
|
|
3513
|
+
while (!ctx.isAtEnd() && !atTerminator()) {
|
|
3514
|
+
if (isComment(ctx.peek())) {
|
|
3515
|
+
ctx.advance();
|
|
3516
|
+
continue;
|
|
3517
|
+
}
|
|
3518
|
+
if (!ctx.checkIsCommand() && !ctx.isCommand(ctx.peek().value))
|
|
3519
|
+
break;
|
|
3520
|
+
ctx.advance();
|
|
3521
|
+
const cmd = ctx.parseCommand();
|
|
3522
|
+
if (cmd) {
|
|
3523
|
+
commands.push(cmd);
|
|
3524
|
+
}
|
|
3525
|
+
if (ctx.check(KEYWORDS$1.THEN) || ctx.check(KEYWORDS$1.AND) || ctx.check(',')) {
|
|
3526
|
+
ctx.advance();
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
return commands;
|
|
3530
|
+
}
|
|
3531
|
+
const OPERAND_INTRODUCERS = new Set([
|
|
3532
|
+
'is',
|
|
3533
|
+
'am',
|
|
3534
|
+
'are',
|
|
3535
|
+
'not',
|
|
3536
|
+
'no',
|
|
3537
|
+
'and',
|
|
3538
|
+
'or',
|
|
3539
|
+
'==',
|
|
3540
|
+
'===',
|
|
3541
|
+
'!=',
|
|
3542
|
+
'!==',
|
|
3543
|
+
'<',
|
|
3544
|
+
'>',
|
|
3545
|
+
'<=',
|
|
3546
|
+
'>=',
|
|
3547
|
+
'+',
|
|
3548
|
+
'-',
|
|
3549
|
+
'*',
|
|
3550
|
+
'/',
|
|
3551
|
+
'mod',
|
|
3552
|
+
]);
|
|
3553
|
+
function isBodyCommandStart(ctx, prevToken, token) {
|
|
3554
|
+
if (prevToken === null) {
|
|
3555
|
+
return false;
|
|
3556
|
+
}
|
|
3557
|
+
if (OPERAND_INTRODUCERS.has(prevToken.value?.toLowerCase?.() ?? '')) {
|
|
3558
|
+
return false;
|
|
3559
|
+
}
|
|
3560
|
+
return ctx.checkIsCommand() || ctx.isCommand(token.value?.toLowerCase());
|
|
3561
|
+
}
|
|
3505
3562
|
function parseIfCommand(ctx, commandToken) {
|
|
3506
3563
|
const args = [];
|
|
3507
3564
|
let hasThen = false;
|
|
3508
3565
|
const savedPosForThen = ctx.savePosition();
|
|
3509
3566
|
const maxThenLookahead = 500;
|
|
3567
|
+
let prevForThen = null;
|
|
3510
3568
|
for (let i = 0; i < maxThenLookahead && !ctx.isAtEnd(); i++) {
|
|
3511
3569
|
const token = ctx.peek();
|
|
3512
3570
|
if (token.value === KEYWORDS$1.THEN) {
|
|
@@ -3519,6 +3577,14 @@ function parseIfCommand(ctx, commandToken) {
|
|
|
3519
3577
|
token.value === KEYWORDS$1.ON) {
|
|
3520
3578
|
break;
|
|
3521
3579
|
}
|
|
3580
|
+
if (token.line !== undefined &&
|
|
3581
|
+
token.line !== commandToken.line &&
|
|
3582
|
+
isBodyCommandStart(ctx, prevForThen, token)) {
|
|
3583
|
+
break;
|
|
3584
|
+
}
|
|
3585
|
+
if (!isComment(token)) {
|
|
3586
|
+
prevForThen = token;
|
|
3587
|
+
}
|
|
3522
3588
|
ctx.advance();
|
|
3523
3589
|
}
|
|
3524
3590
|
ctx.restorePosition(savedPosForThen);
|
|
@@ -3527,9 +3593,14 @@ function parseIfCommand(ctx, commandToken) {
|
|
|
3527
3593
|
const savedPosition = ctx.savePosition();
|
|
3528
3594
|
const ifStatementLine = commandToken.line;
|
|
3529
3595
|
const maxLookahead = 100;
|
|
3596
|
+
let firstCommandOnIfLine = false;
|
|
3597
|
+
let prevToken = null;
|
|
3530
3598
|
while (!ctx.isAtEnd() && ctx.current - savedPosition < maxLookahead) {
|
|
3531
3599
|
const token = ctx.peek();
|
|
3532
3600
|
const tokenValue = token.value?.toLowerCase();
|
|
3601
|
+
if (firstCommandOnIfLine && token.line !== undefined && token.line !== ifStatementLine) {
|
|
3602
|
+
break;
|
|
3603
|
+
}
|
|
3533
3604
|
if (tokenValue === KEYWORDS$1.BEHAVIOR ||
|
|
3534
3605
|
tokenValue === KEYWORDS$1.DEF ||
|
|
3535
3606
|
tokenValue === KEYWORDS$1.ON) {
|
|
@@ -3541,11 +3612,15 @@ function parseIfCommand(ctx, commandToken) {
|
|
|
3541
3612
|
}
|
|
3542
3613
|
break;
|
|
3543
3614
|
}
|
|
3544
|
-
if (ctx
|
|
3615
|
+
if (isBodyCommandStart(ctx, prevToken, token)) {
|
|
3545
3616
|
if (token.line !== undefined && token.line !== ifStatementLine) {
|
|
3546
3617
|
hasImplicitMultiLineEnd = true;
|
|
3547
3618
|
break;
|
|
3548
3619
|
}
|
|
3620
|
+
firstCommandOnIfLine = true;
|
|
3621
|
+
}
|
|
3622
|
+
if (!isComment(token)) {
|
|
3623
|
+
prevToken = token;
|
|
3549
3624
|
}
|
|
3550
3625
|
ctx.advance();
|
|
3551
3626
|
}
|
|
@@ -3560,11 +3635,12 @@ function parseIfCommand(ctx, commandToken) {
|
|
|
3560
3635
|
const conditionTokens = [];
|
|
3561
3636
|
const maxIterations = 20;
|
|
3562
3637
|
let iterations = 0;
|
|
3638
|
+
let firstConditionParse = true;
|
|
3563
3639
|
while (!ctx.isAtEnd() &&
|
|
3564
|
-
!ctx.checkIsCommand() &&
|
|
3565
|
-
!ctx.isCommand(ctx.peek().value) &&
|
|
3566
3640
|
!ctx.check(KEYWORDS$1.THEN) &&
|
|
3641
|
+
(firstConditionParse || (!ctx.checkIsCommand() && !ctx.isCommand(ctx.peek().value))) &&
|
|
3567
3642
|
iterations < maxIterations) {
|
|
3643
|
+
firstConditionParse = false;
|
|
3568
3644
|
const beforePos = ctx.savePosition();
|
|
3569
3645
|
conditionTokens.push(ctx.parseLogicalAnd());
|
|
3570
3646
|
if (ctx.savePosition() === beforePos) {
|
|
@@ -3591,22 +3667,8 @@ function parseIfCommand(ctx, commandToken) {
|
|
|
3591
3667
|
}
|
|
3592
3668
|
args.push(condition);
|
|
3593
3669
|
if (isMultiLine) {
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
}
|
|
3597
|
-
const thenCommands = [];
|
|
3598
|
-
while (!ctx.isAtEnd() && !ctx.check(KEYWORDS$1.ELSE) && !ctx.check(KEYWORDS$1.END)) {
|
|
3599
|
-
if (ctx.checkIsCommand() || ctx.isCommand(ctx.peek().value)) {
|
|
3600
|
-
ctx.advance();
|
|
3601
|
-
const cmd = ctx.parseCommand();
|
|
3602
|
-
if (cmd) {
|
|
3603
|
-
thenCommands.push(cmd);
|
|
3604
|
-
}
|
|
3605
|
-
}
|
|
3606
|
-
else {
|
|
3607
|
-
break;
|
|
3608
|
-
}
|
|
3609
|
-
}
|
|
3670
|
+
consumeOptionalKeyword(ctx, KEYWORDS$1.THEN);
|
|
3671
|
+
const thenCommands = parseIfBranchCommands(ctx, true);
|
|
3610
3672
|
if (thenCommands.length === 0 && ctx.isAtEnd()) {
|
|
3611
3673
|
throw new Error("Expected command after 'then' in if statement - incomplete conditional");
|
|
3612
3674
|
}
|
|
@@ -3632,19 +3694,7 @@ function parseIfCommand(ctx, commandToken) {
|
|
|
3632
3694
|
consumedElseIf = true;
|
|
3633
3695
|
}
|
|
3634
3696
|
else {
|
|
3635
|
-
const elseCommands =
|
|
3636
|
-
while (!ctx.isAtEnd() && !ctx.check(KEYWORDS$1.END)) {
|
|
3637
|
-
if (ctx.checkIsCommand() || ctx.isCommand(ctx.peek().value)) {
|
|
3638
|
-
ctx.advance();
|
|
3639
|
-
const cmd = ctx.parseCommand();
|
|
3640
|
-
if (cmd) {
|
|
3641
|
-
elseCommands.push(cmd);
|
|
3642
|
-
}
|
|
3643
|
-
}
|
|
3644
|
-
else {
|
|
3645
|
-
break;
|
|
3646
|
-
}
|
|
3647
|
-
}
|
|
3697
|
+
const elseCommands = parseIfBranchCommands(ctx, false);
|
|
3648
3698
|
args.push(createBlock(elseCommands, {
|
|
3649
3699
|
start: commandToken.start,
|
|
3650
3700
|
end: ctx.getPosition().end,
|
|
@@ -4466,21 +4516,6 @@ const GO_KEYWORDS = new Set([
|
|
|
4466
4516
|
'back',
|
|
4467
4517
|
'forward',
|
|
4468
4518
|
]);
|
|
4469
|
-
const GO_URL_STOP = new Set([
|
|
4470
|
-
'in',
|
|
4471
|
-
'then',
|
|
4472
|
-
'and',
|
|
4473
|
-
'else',
|
|
4474
|
-
'end',
|
|
4475
|
-
'otherwise',
|
|
4476
|
-
'when',
|
|
4477
|
-
'where',
|
|
4478
|
-
'catch',
|
|
4479
|
-
'finally',
|
|
4480
|
-
]);
|
|
4481
|
-
function isGoURLTerminator(ctx) {
|
|
4482
|
-
return ctx.isAtEnd() || GO_URL_STOP.has(ctx.peek().value);
|
|
4483
|
-
}
|
|
4484
4519
|
function stringNode(value, tok) {
|
|
4485
4520
|
return {
|
|
4486
4521
|
type: 'string',
|
|
@@ -4502,7 +4537,7 @@ function parseGoCommand(ctx, identifierNode) {
|
|
|
4502
4537
|
continue;
|
|
4503
4538
|
}
|
|
4504
4539
|
if (isNakedURLStart(ctx)) {
|
|
4505
|
-
const url = parseBareURLPath(ctx
|
|
4540
|
+
const url = parseBareURLPath(ctx);
|
|
4506
4541
|
if (url) {
|
|
4507
4542
|
args.push(url);
|
|
4508
4543
|
continue;
|
|
@@ -4642,13 +4677,6 @@ function parseMultiWordCommand(ctx, commandToken, commandName) {
|
|
|
4642
4677
|
}
|
|
4643
4678
|
return builder.build();
|
|
4644
4679
|
}
|
|
4645
|
-
function isFetchURLTerminator(ctx) {
|
|
4646
|
-
if (ctx.isAtEnd())
|
|
4647
|
-
return true;
|
|
4648
|
-
const val = ctx.peek().value;
|
|
4649
|
-
return (['as', 'with', '{', 'then', 'end', 'else', 'otherwise', ')'].includes(val) ||
|
|
4650
|
-
isCommandBoundary(ctx));
|
|
4651
|
-
}
|
|
4652
4680
|
function isNakedURLStart(ctx) {
|
|
4653
4681
|
const tok = ctx.peek();
|
|
4654
4682
|
if (tok.value === '/')
|
|
@@ -4659,23 +4687,50 @@ function isNakedURLStart(ctx) {
|
|
|
4659
4687
|
}
|
|
4660
4688
|
return false;
|
|
4661
4689
|
}
|
|
4662
|
-
|
|
4690
|
+
const URL_HARD_STOPS = new Set(['{', ')']);
|
|
4691
|
+
function parseBareURLPath(ctx) {
|
|
4663
4692
|
const startPos = ctx.savePosition();
|
|
4693
|
+
const firstTok = ctx.peek();
|
|
4664
4694
|
let path = '';
|
|
4665
|
-
|
|
4666
|
-
|
|
4695
|
+
let prev = null;
|
|
4696
|
+
while (!ctx.isAtEnd()) {
|
|
4697
|
+
const tok = ctx.peek();
|
|
4698
|
+
if (prev && tok.start !== prev.end)
|
|
4699
|
+
break;
|
|
4700
|
+
if (tok.value === '$' && ctx.peekAt(1)?.value === '{') {
|
|
4701
|
+
ctx.advance();
|
|
4702
|
+
let last = ctx.advance();
|
|
4703
|
+
let depth = 1;
|
|
4704
|
+
while (!ctx.isAtEnd() && depth > 0) {
|
|
4705
|
+
last = ctx.advance();
|
|
4706
|
+
if (last.value === '{')
|
|
4707
|
+
depth++;
|
|
4708
|
+
else if (last.value === '}')
|
|
4709
|
+
depth--;
|
|
4710
|
+
}
|
|
4711
|
+
path += ctx.getInputSlice(tok.start, last.end);
|
|
4712
|
+
prev = last;
|
|
4713
|
+
continue;
|
|
4714
|
+
}
|
|
4715
|
+
if (URL_HARD_STOPS.has(tok.value))
|
|
4716
|
+
break;
|
|
4717
|
+
prev = ctx.advance();
|
|
4718
|
+
path += prev.value;
|
|
4667
4719
|
}
|
|
4668
4720
|
if (!path || path === '/') {
|
|
4669
4721
|
ctx.restorePosition(startPos);
|
|
4670
4722
|
return null;
|
|
4671
4723
|
}
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
end: ctx.savePosition(),
|
|
4724
|
+
const span = {
|
|
4725
|
+
start: firstTok.start,
|
|
4726
|
+
end: prev ? prev.end : firstTok.end,
|
|
4727
|
+
line: firstTok.line,
|
|
4728
|
+
column: firstTok.column,
|
|
4678
4729
|
};
|
|
4730
|
+
if (path.includes('${')) {
|
|
4731
|
+
return { type: 'templateLiteral', value: path, ...span };
|
|
4732
|
+
}
|
|
4733
|
+
return { type: 'literal', value: path, raw: path, ...span };
|
|
4679
4734
|
}
|
|
4680
4735
|
function parseFetchCommand(ctx, commandToken) {
|
|
4681
4736
|
const modifiers = {};
|
|
@@ -4906,10 +4961,10 @@ function parseTellCommand(ctx, identifierNode) {
|
|
|
4906
4961
|
catch {
|
|
4907
4962
|
break;
|
|
4908
4963
|
}
|
|
4909
|
-
if (ctx.match(KEYWORDS$1.AND)) {
|
|
4964
|
+
if (ctx.match(KEYWORDS$1.AND) || ctx.match(KEYWORDS$1.THEN)) {
|
|
4910
4965
|
continue;
|
|
4911
4966
|
}
|
|
4912
|
-
if (ctx.check(KEYWORDS$1.
|
|
4967
|
+
if (ctx.check(KEYWORDS$1.ELSE) || ctx.check(KEYWORDS$1.END)) {
|
|
4913
4968
|
break;
|
|
4914
4969
|
}
|
|
4915
4970
|
if (ctx.checkIsCommand()) {
|
|
@@ -5112,6 +5167,7 @@ class Parser {
|
|
|
5112
5167
|
const result = this.parseInternal();
|
|
5113
5168
|
if (this.errors.length > 0) {
|
|
5114
5169
|
result.errors = [...this.errors];
|
|
5170
|
+
result.recovered = true;
|
|
5115
5171
|
}
|
|
5116
5172
|
return result;
|
|
5117
5173
|
}
|
|
@@ -7143,6 +7199,9 @@ class Parser {
|
|
|
7143
7199
|
this.advance();
|
|
7144
7200
|
const cmd = this.parseCommand();
|
|
7145
7201
|
commands.push(cmd);
|
|
7202
|
+
if (this.match('then', 'and', ',')) {
|
|
7203
|
+
continue;
|
|
7204
|
+
}
|
|
7146
7205
|
}
|
|
7147
7206
|
else {
|
|
7148
7207
|
break;
|
|
@@ -13049,6 +13108,25 @@ function isImplicitCommand(val) {
|
|
|
13049
13108
|
return val !== null && typeof val === 'object' && 'command' in val && 'selector' in val;
|
|
13050
13109
|
}
|
|
13051
13110
|
const eventRecursionDepth = new WeakMap();
|
|
13111
|
+
function collectIdentifierNames(node, out = new Set()) {
|
|
13112
|
+
if (node === null || typeof node !== 'object')
|
|
13113
|
+
return out;
|
|
13114
|
+
if (Array.isArray(node)) {
|
|
13115
|
+
for (const item of node)
|
|
13116
|
+
collectIdentifierNames(item, out);
|
|
13117
|
+
return out;
|
|
13118
|
+
}
|
|
13119
|
+
const obj = node;
|
|
13120
|
+
if (obj.type === 'identifier' && typeof obj.name === 'string') {
|
|
13121
|
+
out.add(obj.name);
|
|
13122
|
+
}
|
|
13123
|
+
for (const key of Object.keys(obj)) {
|
|
13124
|
+
if (key === 'start' || key === 'end' || key === 'line' || key === 'column')
|
|
13125
|
+
continue;
|
|
13126
|
+
collectIdentifierNames(obj[key], out);
|
|
13127
|
+
}
|
|
13128
|
+
return out;
|
|
13129
|
+
}
|
|
13052
13130
|
class RuntimeBase {
|
|
13053
13131
|
constructor(options) {
|
|
13054
13132
|
this.autoCleanupObserver = null;
|
|
@@ -13240,6 +13318,9 @@ class RuntimeBase {
|
|
|
13240
13318
|
case 'behavior': {
|
|
13241
13319
|
return await this.executeBehaviorDefinition(node, context);
|
|
13242
13320
|
}
|
|
13321
|
+
case 'def': {
|
|
13322
|
+
return this.installFunction(node, context);
|
|
13323
|
+
}
|
|
13243
13324
|
case 'Program': {
|
|
13244
13325
|
return await this.executeProgram(node, context);
|
|
13245
13326
|
}
|
|
@@ -13455,17 +13536,64 @@ class RuntimeBase {
|
|
|
13455
13536
|
};
|
|
13456
13537
|
return this.processCommand(commandNode, context);
|
|
13457
13538
|
}
|
|
13539
|
+
installFunction(node, context) {
|
|
13540
|
+
const runtime = this;
|
|
13541
|
+
const params = node.params ?? [];
|
|
13542
|
+
const body = (node.body ?? []);
|
|
13543
|
+
const errorHandler = node.errorHandler;
|
|
13544
|
+
const finallyHandler = node.finallyHandler;
|
|
13545
|
+
const errorSymbol = node.errorSymbol;
|
|
13546
|
+
const fn = async (...args) => {
|
|
13547
|
+
const fnContext = {
|
|
13548
|
+
...context,
|
|
13549
|
+
locals: new Map(context.locals),
|
|
13550
|
+
};
|
|
13551
|
+
params.forEach((name, i) => {
|
|
13552
|
+
if (name)
|
|
13553
|
+
fnContext.locals.set(name, args[i]);
|
|
13554
|
+
});
|
|
13555
|
+
const run = async (commands) => {
|
|
13556
|
+
const result = await runtime.executeCommandSequenceWithResult(commands, fnContext);
|
|
13557
|
+
if (!isOk(result))
|
|
13558
|
+
throw asControlFlowError(result.error);
|
|
13559
|
+
return result.value;
|
|
13560
|
+
};
|
|
13561
|
+
if (!errorHandler && !finallyHandler) {
|
|
13562
|
+
return await run(body);
|
|
13563
|
+
}
|
|
13564
|
+
try {
|
|
13565
|
+
return await run(body);
|
|
13566
|
+
}
|
|
13567
|
+
catch (e) {
|
|
13568
|
+
if (!errorHandler || isControlFlowError(e))
|
|
13569
|
+
throw e;
|
|
13570
|
+
if (errorSymbol)
|
|
13571
|
+
fnContext.locals.set(errorSymbol, e);
|
|
13572
|
+
return await run(errorHandler);
|
|
13573
|
+
}
|
|
13574
|
+
finally {
|
|
13575
|
+
if (finallyHandler) {
|
|
13576
|
+
await run(finallyHandler);
|
|
13577
|
+
}
|
|
13578
|
+
}
|
|
13579
|
+
};
|
|
13580
|
+
context.globals.set(node.name, fn);
|
|
13581
|
+
}
|
|
13458
13582
|
async executeProgram(node, context) {
|
|
13459
13583
|
if (!node.statements || !Array.isArray(node.statements))
|
|
13460
13584
|
return;
|
|
13461
13585
|
let lastResult = undefined;
|
|
13462
13586
|
const eventHandlers = [];
|
|
13587
|
+
const defs = [];
|
|
13463
13588
|
const initBlocks = [];
|
|
13464
13589
|
const otherStatements = [];
|
|
13465
13590
|
for (const statement of node.statements) {
|
|
13466
13591
|
if (statement.type === 'eventHandler') {
|
|
13467
13592
|
eventHandlers.push(statement);
|
|
13468
13593
|
}
|
|
13594
|
+
else if (statement.type === 'def') {
|
|
13595
|
+
defs.push(statement);
|
|
13596
|
+
}
|
|
13469
13597
|
else if (statement.type === 'initBlock') {
|
|
13470
13598
|
initBlocks.push(statement);
|
|
13471
13599
|
}
|
|
@@ -13473,6 +13601,9 @@ class RuntimeBase {
|
|
|
13473
13601
|
otherStatements.push(statement);
|
|
13474
13602
|
}
|
|
13475
13603
|
}
|
|
13604
|
+
for (const def of defs) {
|
|
13605
|
+
this.execute(def, context);
|
|
13606
|
+
}
|
|
13476
13607
|
for (const handler of eventHandlers) {
|
|
13477
13608
|
try {
|
|
13478
13609
|
await this.execute(handler, context);
|
|
@@ -13668,7 +13799,7 @@ class RuntimeBase {
|
|
|
13668
13799
|
debug.runtime(`BEHAVIOR: Finished installing ${behaviorName}`);
|
|
13669
13800
|
}
|
|
13670
13801
|
async executeEventHandler(node, context) {
|
|
13671
|
-
const { event, events, commands, target, args, selector, attributeName, watchTarget, modifiers, errorSymbol, errorHandler, finallyHandler, } = node;
|
|
13802
|
+
const { event, events, commands, target, args, selector, condition, attributeName, watchTarget, modifiers, errorSymbol, errorHandler, finallyHandler, } = node;
|
|
13672
13803
|
const eventNames = events && events.length > 0 ? events : [event];
|
|
13673
13804
|
debug.runtime(`BEHAVIOR: executeEventHandler: event='${event}', target='${target}'`);
|
|
13674
13805
|
let targets = [];
|
|
@@ -13751,7 +13882,8 @@ class RuntimeBase {
|
|
|
13751
13882
|
}
|
|
13752
13883
|
return;
|
|
13753
13884
|
}
|
|
13754
|
-
const
|
|
13885
|
+
const applicableCondition = eventNames.length === 1 ? condition : undefined;
|
|
13886
|
+
const baseEventHandler = RuntimeBase.createEventHandler(this, commands, context, selector, args, { errorSymbol, errorHandler, finallyHandler }, applicableCondition);
|
|
13755
13887
|
let eventHandler;
|
|
13756
13888
|
let debounceCleanup = null;
|
|
13757
13889
|
if (modifiers) {
|
|
@@ -13855,7 +13987,7 @@ class RuntimeBase {
|
|
|
13855
13987
|
}
|
|
13856
13988
|
}
|
|
13857
13989
|
}
|
|
13858
|
-
static createEventHandler(runtime, commands, context, selector, args, errorBlocks) {
|
|
13990
|
+
static createEventHandler(runtime, commands, context, selector, args, errorBlocks, condition) {
|
|
13859
13991
|
return async (domEvent) => {
|
|
13860
13992
|
const currentDepth = eventRecursionDepth.get(domEvent) ?? 0;
|
|
13861
13993
|
if (currentDepth >= 100) {
|
|
@@ -13891,6 +14023,25 @@ class RuntimeBase {
|
|
|
13891
14023
|
eventContext.locals.set(argName, value);
|
|
13892
14024
|
}
|
|
13893
14025
|
}
|
|
14026
|
+
if (condition) {
|
|
14027
|
+
const eventProps = domEvent;
|
|
14028
|
+
for (const name of collectIdentifierNames(condition)) {
|
|
14029
|
+
if (!eventContext.locals.has(name) && name in eventProps) {
|
|
14030
|
+
eventContext.locals.set(name, eventProps[name]);
|
|
14031
|
+
}
|
|
14032
|
+
}
|
|
14033
|
+
let filterResult;
|
|
14034
|
+
try {
|
|
14035
|
+
filterResult = await runtime.evaluateExpression(condition, eventContext);
|
|
14036
|
+
}
|
|
14037
|
+
catch (e) {
|
|
14038
|
+
debug.runtime(`Event filter threw; skipping handler body:`, e);
|
|
14039
|
+
return;
|
|
14040
|
+
}
|
|
14041
|
+
if (!filterResult) {
|
|
14042
|
+
return;
|
|
14043
|
+
}
|
|
14044
|
+
}
|
|
13894
14045
|
const runCommands = async (toRun) => {
|
|
13895
14046
|
for (const command of toRun) {
|
|
13896
14047
|
try {
|
|
@@ -80809,9 +80960,11 @@ function compileSync(code, options) {
|
|
|
80809
80960
|
const parseResult = parse$1(code, parserOptions);
|
|
80810
80961
|
const timeMs = performance.now() - startTime;
|
|
80811
80962
|
if (parseResult.success && parseResult.node) {
|
|
80963
|
+
const recovered = parseResult.errors ?? [];
|
|
80812
80964
|
const result = {
|
|
80813
80965
|
ok: true,
|
|
80814
80966
|
ast: parseResult.node,
|
|
80967
|
+
...(recovered.length > 0 ? { errors: recovered.map(toCompileError) } : {}),
|
|
80815
80968
|
meta: {
|
|
80816
80969
|
parser: usesSemanticParser ? 'semantic' : 'traditional',
|
|
80817
80970
|
language: lang,
|
|
@@ -80937,9 +81090,10 @@ async function evalCode(code, context, options) {
|
|
|
80937
81090
|
}
|
|
80938
81091
|
async function validate(code, options) {
|
|
80939
81092
|
const result = await compileAsync(code, options);
|
|
81093
|
+
const errors = result.errors ?? [];
|
|
80940
81094
|
return {
|
|
80941
|
-
valid: result.ok,
|
|
80942
|
-
errors:
|
|
81095
|
+
valid: result.ok && errors.length === 0,
|
|
81096
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
80943
81097
|
};
|
|
80944
81098
|
}
|
|
80945
81099
|
function createContextWithParent(element, parent) {
|