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