@hyperfixi/core 2.9.0 → 2.9.1
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/ast-utils/index.js +905 -882
- package/dist/ast-utils/index.mjs +905 -882
- package/dist/chunks/{bridge-D9JLmPkk.js → bridge-BYhqTOnL.js} +2 -2
- package/dist/chunks/browser-modular-D2BHzZFB.js +2 -0
- package/dist/chunks/feature-eventsource-Bxg_UNZo.js +2 -0
- package/dist/chunks/feature-sockets-CcTxD5sT.js +2 -0
- package/dist/chunks/feature-webworker-DoqZ0Grg.js +2 -0
- package/dist/chunks/{index-6DUg7Qjm.js → index-DXgJaDj-.js} +2 -2
- package/dist/commands/index.js +168 -112
- package/dist/commands/index.mjs +168 -112
- 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-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 +1505 -1402
- package/dist/index.min.js +1 -1
- package/dist/index.mjs +1505 -1402
- 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/lsp-metadata.js +5 -5
- package/dist/lsp-metadata.mjs +5 -5
- package/dist/metadata.js +25 -25
- package/dist/metadata.mjs +25 -25
- package/dist/multilingual/index.js +17 -17
- package/dist/multilingual/index.mjs +17 -17
- package/dist/parser/command-parsers/utility-commands.d.ts +1 -0
- package/dist/parser/full-parser.js +155 -106
- package/dist/parser/full-parser.mjs +155 -106
- package/dist/parser/parser.d.ts +1 -0
- package/dist/reference/index.js +1 -0
- package/dist/reference/index.mjs +1 -0
- package/dist/registry/index.js +155 -106
- package/dist/registry/index.mjs +155 -106
- package/dist/types/base-types.d.ts +3 -0
- package/package.json +5 -5
- package/dist/chunks/browser-modular-CPiVQXM0.js +0 -2
- package/dist/chunks/feature-eventsource-BpZvPy_K.js +0 -2
- package/dist/chunks/feature-sockets-CrYvjZ4j.js +0 -2
- package/dist/chunks/feature-webworker-BSYguEIW.js +0 -2
package/dist/registry/index.mjs
CHANGED
|
@@ -31,39 +31,39 @@ const DEBUG = {
|
|
|
31
31
|
const debug = {
|
|
32
32
|
command: (...args) => {
|
|
33
33
|
if (DEBUG.commands)
|
|
34
|
-
console.log('
|
|
34
|
+
console.log('\ud83d\udd27', ...args);
|
|
35
35
|
},
|
|
36
36
|
event: (...args) => {
|
|
37
37
|
if (DEBUG.events)
|
|
38
|
-
console.log('
|
|
38
|
+
console.log('\ud83c\udfaf', ...args);
|
|
39
39
|
},
|
|
40
40
|
parse: (...args) => {
|
|
41
41
|
if (DEBUG.parsing)
|
|
42
|
-
console.log('
|
|
42
|
+
console.log('\ud83d\udcdd', ...args);
|
|
43
43
|
},
|
|
44
44
|
expr: (...args) => {
|
|
45
45
|
if (DEBUG.expressions)
|
|
46
|
-
console.log('
|
|
46
|
+
console.log('\ud83d\udd0d', ...args);
|
|
47
47
|
},
|
|
48
48
|
expressions: (...args) => {
|
|
49
49
|
if (DEBUG.expressions)
|
|
50
|
-
console.log('
|
|
50
|
+
console.log('\ud83d\udd0d', ...args);
|
|
51
51
|
},
|
|
52
52
|
style: (...args) => {
|
|
53
53
|
if (DEBUG.styles)
|
|
54
|
-
console.log('
|
|
54
|
+
console.log('\ud83c\udfa8', ...args);
|
|
55
55
|
},
|
|
56
56
|
runtime: (...args) => {
|
|
57
57
|
if (DEBUG.runtime)
|
|
58
|
-
console.log('
|
|
58
|
+
console.log('\ud83d\ude80', ...args);
|
|
59
59
|
},
|
|
60
60
|
loop: (...args) => {
|
|
61
61
|
if (DEBUG.loops)
|
|
62
|
-
console.log('
|
|
62
|
+
console.log('\ud83d\udd01', ...args);
|
|
63
63
|
},
|
|
64
64
|
async: (...args) => {
|
|
65
65
|
if (DEBUG.async)
|
|
66
|
-
console.log('
|
|
66
|
+
console.log('\u23f3', ...args);
|
|
67
67
|
},
|
|
68
68
|
};
|
|
69
69
|
|
|
@@ -4046,6 +4046,7 @@ function tokenize(input) {
|
|
|
4046
4046
|
const prevToken = tokenizer.tokens[tokenizer.tokens.length - 1];
|
|
4047
4047
|
const isPossessive = nextChar === 's' &&
|
|
4048
4048
|
prevToken &&
|
|
4049
|
+
!/\s/.test(tokenizer.input[tokenizer.position - 1] ?? ' ') &&
|
|
4049
4050
|
(prevToken.kind === TokenKind.IDENTIFIER ||
|
|
4050
4051
|
prevToken.kind === TokenKind.SELECTOR ||
|
|
4051
4052
|
prevToken.value === ']' ||
|
|
@@ -5770,9 +5771,9 @@ function createPartialCommandNode(name, pos) {
|
|
|
5770
5771
|
};
|
|
5771
5772
|
}
|
|
5772
5773
|
function createProgramNode(statements) {
|
|
5773
|
-
debug.parse(
|
|
5774
|
+
debug.parse(`\u2705 createProgramNode: Called with ${statements.length} statements`);
|
|
5774
5775
|
if (statements.length === 0) {
|
|
5775
|
-
debug.parse(
|
|
5776
|
+
debug.parse(`\u2705 createProgramNode: Returning error node (0 statements)`);
|
|
5776
5777
|
return {
|
|
5777
5778
|
type: 'identifier',
|
|
5778
5779
|
name: '__ERROR__',
|
|
@@ -5783,7 +5784,7 @@ function createProgramNode(statements) {
|
|
|
5783
5784
|
};
|
|
5784
5785
|
}
|
|
5785
5786
|
if (statements.length === 1) {
|
|
5786
|
-
debug.parse(
|
|
5787
|
+
debug.parse(`\u2705 createProgramNode: Returning single statement (type=${statements[0].type})`);
|
|
5787
5788
|
return statements[0];
|
|
5788
5789
|
}
|
|
5789
5790
|
const programNode = {
|
|
@@ -5794,7 +5795,7 @@ function createProgramNode(statements) {
|
|
|
5794
5795
|
line: statements[0]?.line || 1,
|
|
5795
5796
|
column: statements[0]?.column || 1,
|
|
5796
5797
|
};
|
|
5797
|
-
debug.parse(
|
|
5798
|
+
debug.parse(`\u2705 createProgramNode: Returning Program node with ${statements.length} statements, type=${programNode.type}`);
|
|
5798
5799
|
return programNode;
|
|
5799
5800
|
}
|
|
5800
5801
|
|
|
@@ -6183,37 +6184,37 @@ function parseRepeatCommand(ctx, commandToken) {
|
|
|
6183
6184
|
ctx.advance();
|
|
6184
6185
|
loopType = 'until-event';
|
|
6185
6186
|
const eventToken = ctx.peek();
|
|
6186
|
-
debug.parse('
|
|
6187
|
+
debug.parse('\ud83d\udccd Parsing event name, current token:', {
|
|
6187
6188
|
value: eventToken.value,
|
|
6188
6189
|
kind: eventToken.kind,
|
|
6189
6190
|
});
|
|
6190
6191
|
if (isIdentifierLike(eventToken) || isEvent(eventToken)) {
|
|
6191
6192
|
eventName = eventToken.value;
|
|
6192
6193
|
ctx.advance();
|
|
6193
|
-
debug.parse('
|
|
6194
|
+
debug.parse('\u2705 Got event name:', eventName, 'Next token:', ctx.peek().value);
|
|
6194
6195
|
}
|
|
6195
6196
|
else {
|
|
6196
6197
|
throw new Error('Expected event name after "event"');
|
|
6197
6198
|
}
|
|
6198
|
-
debug.parse('
|
|
6199
|
+
debug.parse('\ud83d\udd0d Checking for "from", current token:', ctx.peek().value);
|
|
6199
6200
|
if (ctx.check(KEYWORDS.FROM)) {
|
|
6200
|
-
debug.parse('
|
|
6201
|
+
debug.parse('\u2705 Found "from", advancing...');
|
|
6201
6202
|
ctx.advance();
|
|
6202
|
-
debug.parse('
|
|
6203
|
+
debug.parse('\ud83d\udccd After consuming "from", current token:', ctx.peek().value);
|
|
6203
6204
|
if (consumeOptionalKeyword(ctx, KEYWORDS.THE)) {
|
|
6204
|
-
debug.parse('
|
|
6205
|
+
debug.parse('\u2705 Found "the", advancing...');
|
|
6205
6206
|
}
|
|
6206
6207
|
const beforePrimary = ctx.peek();
|
|
6207
|
-
debug.parse('
|
|
6208
|
+
debug.parse('\ud83d\udd0d Before parsePrimary for event target:', {
|
|
6208
6209
|
value: beforePrimary.value,
|
|
6209
6210
|
kind: beforePrimary.kind,
|
|
6210
6211
|
position: beforePrimary.start,
|
|
6211
6212
|
});
|
|
6212
6213
|
eventTarget = ctx.parsePrimary();
|
|
6213
|
-
debug.parse('
|
|
6214
|
+
debug.parse('\u2705 After parsePrimary, eventTarget:', eventTarget);
|
|
6214
6215
|
}
|
|
6215
6216
|
else {
|
|
6216
|
-
debug.parse('
|
|
6217
|
+
debug.parse('\u274c No "from" found, skipping target parsing');
|
|
6217
6218
|
}
|
|
6218
6219
|
}
|
|
6219
6220
|
else {
|
|
@@ -7314,16 +7315,6 @@ function stringNode(value, tok) {
|
|
|
7314
7315
|
column: tok.column,
|
|
7315
7316
|
};
|
|
7316
7317
|
}
|
|
7317
|
-
function isNakedURLStart(ctx) {
|
|
7318
|
-
const tok = ctx.peek();
|
|
7319
|
-
if (tok.value === '/')
|
|
7320
|
-
return true;
|
|
7321
|
-
if (ctx.checkIdentifierLike()) {
|
|
7322
|
-
const next = ctx.peekAt(1);
|
|
7323
|
-
return !!next && next.value === ':' && next.start === tok.end;
|
|
7324
|
-
}
|
|
7325
|
-
return false;
|
|
7326
|
-
}
|
|
7327
7318
|
function parseGoCommand(ctx, identifierNode) {
|
|
7328
7319
|
const args = [];
|
|
7329
7320
|
while (!isCommandBoundary(ctx, ['when', 'where', 'catch', 'finally'])) {
|
|
@@ -7482,6 +7473,16 @@ function isFetchURLTerminator(ctx) {
|
|
|
7482
7473
|
return (['as', 'with', '{', 'then', 'end', 'else', 'otherwise', ')'].includes(val) ||
|
|
7483
7474
|
isCommandBoundary(ctx));
|
|
7484
7475
|
}
|
|
7476
|
+
function isNakedURLStart(ctx) {
|
|
7477
|
+
const tok = ctx.peek();
|
|
7478
|
+
if (tok.value === '/')
|
|
7479
|
+
return true;
|
|
7480
|
+
if (ctx.checkIdentifierLike()) {
|
|
7481
|
+
const next = ctx.peekAt(1);
|
|
7482
|
+
return !!next && next.value === ':' && next.start === tok.end;
|
|
7483
|
+
}
|
|
7484
|
+
return false;
|
|
7485
|
+
}
|
|
7485
7486
|
function parseBareURLPath(ctx, isTerminator = isFetchURLTerminator) {
|
|
7486
7487
|
const startPos = ctx.savePosition();
|
|
7487
7488
|
let path = '';
|
|
@@ -7503,7 +7504,7 @@ function parseBareURLPath(ctx, isTerminator = isFetchURLTerminator) {
|
|
|
7503
7504
|
function parseFetchCommand(ctx, commandToken) {
|
|
7504
7505
|
const modifiers = {};
|
|
7505
7506
|
let url = null;
|
|
7506
|
-
if (!ctx.isAtEnd() && ctx
|
|
7507
|
+
if (!ctx.isAtEnd() && isNakedURLStart(ctx)) {
|
|
7507
7508
|
url = parseBareURLPath(ctx);
|
|
7508
7509
|
}
|
|
7509
7510
|
if (!url) {
|
|
@@ -8069,26 +8070,26 @@ class Parser {
|
|
|
8069
8070
|
const commandSequence = this.parseCommandSequence();
|
|
8070
8071
|
if (commandSequence) {
|
|
8071
8072
|
if (!this.isAtEnd() && this.check('on')) {
|
|
8072
|
-
debug.parse('
|
|
8073
|
+
debug.parse('\u2705 PARSER: Found event handlers after command sequence, parsing as program');
|
|
8073
8074
|
const statements = [commandSequence];
|
|
8074
|
-
debug.parse(
|
|
8075
|
+
debug.parse(`\u2705 PARSER: Starting with ${statements.length} statement(s) from command sequence`);
|
|
8075
8076
|
let eventHandlerCount = 0;
|
|
8076
8077
|
while (!this.isAtEnd() && this.check('on')) {
|
|
8077
|
-
debug.parse(
|
|
8078
|
+
debug.parse(`\u2705 PARSER: Parsing event handler #${eventHandlerCount + 1}, current token: ${this.peek().value}`);
|
|
8078
8079
|
this.advance();
|
|
8079
8080
|
const eventHandler = this.parseEventHandler();
|
|
8080
|
-
debug.parse(
|
|
8081
|
+
debug.parse(`\u2705 PARSER: parseEventHandler returned:`, eventHandler
|
|
8081
8082
|
? `type=${eventHandler.type}, event=${eventHandler.event}`
|
|
8082
8083
|
: 'null');
|
|
8083
8084
|
if (eventHandler) {
|
|
8084
8085
|
statements.push(eventHandler);
|
|
8085
8086
|
eventHandlerCount++;
|
|
8086
|
-
debug.parse(
|
|
8087
|
+
debug.parse(`\u2705 PARSER: Added event handler, now have ${statements.length} statements total`);
|
|
8087
8088
|
}
|
|
8088
|
-
debug.parse(
|
|
8089
|
+
debug.parse(`\u2705 PARSER: After parsing event handler, current token: ${this.isAtEnd() ? 'END' : this.peek().value}, isAtEnd=${this.isAtEnd()}, check('on')=${this.check('on')}`);
|
|
8089
8090
|
if (!this.isAtEnd() && !this.check('on')) {
|
|
8090
8091
|
if (!this.isAtEnd()) {
|
|
8091
|
-
debug.parse(
|
|
8092
|
+
debug.parse(`\u26a0\ufe0f PARSER: Unexpected token after event handlers: ${this.peek().value}`);
|
|
8092
8093
|
this.addError(`Unexpected token after event handlers: ${this.peek().value}`);
|
|
8093
8094
|
return {
|
|
8094
8095
|
success: false,
|
|
@@ -8097,11 +8098,11 @@ class Parser {
|
|
|
8097
8098
|
error: this.error,
|
|
8098
8099
|
};
|
|
8099
8100
|
}
|
|
8100
|
-
debug.parse(
|
|
8101
|
+
debug.parse(`\u2705 PARSER: No more event handlers, at end of input`);
|
|
8101
8102
|
break;
|
|
8102
8103
|
}
|
|
8103
8104
|
}
|
|
8104
|
-
debug.parse(
|
|
8105
|
+
debug.parse(`\u2705 PARSER: Finished parsing, creating Program node with ${statements.length} statements`);
|
|
8105
8106
|
if (this.error) {
|
|
8106
8107
|
return {
|
|
8107
8108
|
success: false,
|
|
@@ -8496,41 +8497,41 @@ class Parser {
|
|
|
8496
8497
|
parseCommandListUntilTerminator(extraStops) {
|
|
8497
8498
|
const commands = [];
|
|
8498
8499
|
const isStop = () => this.check('end') || extraStops.some(s => this.check(s));
|
|
8499
|
-
debug.parse('
|
|
8500
|
+
debug.parse('\ud83d\udd04 parseCommandListUntilTerminator: Starting (extraStops:', extraStops.join(','), ')');
|
|
8500
8501
|
while (!this.isAtEnd() && !isStop()) {
|
|
8501
|
-
debug.parse('
|
|
8502
|
+
debug.parse('\ud83d\udccd Loop iteration, current token:', this.peek().value, 'kind:', this.peek().kind);
|
|
8502
8503
|
let parsedCommand = false;
|
|
8503
8504
|
const isCommandToken = this.checkIsCommand();
|
|
8504
8505
|
const isCommandIdentifier = !isCommandToken && this.checkIdentifier() && this.isCommand(this.peek().value);
|
|
8505
8506
|
if (isCommandToken || isCommandIdentifier) {
|
|
8506
|
-
debug.parse(isCommandToken ? '
|
|
8507
|
+
debug.parse(isCommandToken ? '\u2705 Found COMMAND token:' : '\u2705 Found IDENTIFIER that is a command:', this.peek().value);
|
|
8507
8508
|
this.advance();
|
|
8508
8509
|
const savedError = this.error;
|
|
8509
8510
|
try {
|
|
8510
8511
|
const cmd = this.parseCommand();
|
|
8511
8512
|
if (this.error && this.error !== savedError) {
|
|
8512
|
-
debug.parse('
|
|
8513
|
+
debug.parse('\u26a0\ufe0f parseCommandListUntilTerminator: Command parsing added error, restoring. Error was:', this.error.message);
|
|
8513
8514
|
this.error = savedError;
|
|
8514
8515
|
}
|
|
8515
8516
|
if (cmd) {
|
|
8516
|
-
debug.parse('
|
|
8517
|
+
debug.parse('\u2705 Parsed command:', cmd.name);
|
|
8517
8518
|
commands.push(cmd);
|
|
8518
8519
|
parsedCommand = true;
|
|
8519
8520
|
}
|
|
8520
8521
|
}
|
|
8521
8522
|
catch (error) {
|
|
8522
|
-
debug.parse('
|
|
8523
|
+
debug.parse('\u26a0\ufe0f parseCommandListUntilTerminator: Command parsing threw, restoring:', error instanceof Error ? error.message : String(error));
|
|
8523
8524
|
this.error = savedError;
|
|
8524
8525
|
}
|
|
8525
8526
|
}
|
|
8526
8527
|
else if (this.checkIdentifier()) {
|
|
8527
|
-
debug.parse('
|
|
8528
|
+
debug.parse('\u274c IDENTIFIER is not a command:', this.peek().value);
|
|
8528
8529
|
}
|
|
8529
8530
|
if (!parsedCommand) {
|
|
8530
|
-
debug.parse('
|
|
8531
|
+
debug.parse('\u274c No command parsed, breaking. Current token:', this.peek().value);
|
|
8531
8532
|
break;
|
|
8532
8533
|
}
|
|
8533
|
-
debug.parse('
|
|
8534
|
+
debug.parse('\ud83d\udccd After parsing command, current token:', this.peek().value);
|
|
8534
8535
|
while (!this.isAtEnd() &&
|
|
8535
8536
|
!isStop() &&
|
|
8536
8537
|
!this.checkIsCommand() &&
|
|
@@ -8538,19 +8539,19 @@ class Parser {
|
|
|
8538
8539
|
!this.check('then') &&
|
|
8539
8540
|
!this.check('and') &&
|
|
8540
8541
|
!this.check(',')) {
|
|
8541
|
-
debug.parse('
|
|
8542
|
+
debug.parse('\u26a0\ufe0f Skipping unexpected token:', this.peek().value);
|
|
8542
8543
|
this.advance();
|
|
8543
8544
|
}
|
|
8544
8545
|
if (this.match('then', 'and', ',')) {
|
|
8545
|
-
debug.parse('
|
|
8546
|
+
debug.parse('\u2705 Found separator, continuing');
|
|
8546
8547
|
continue;
|
|
8547
8548
|
}
|
|
8548
8549
|
else if (this.checkIsCommand() || this.isCommand(this.peek().value)) {
|
|
8549
|
-
debug.parse('
|
|
8550
|
+
debug.parse('\u2705 Next token is a command, continuing without separator');
|
|
8550
8551
|
continue;
|
|
8551
8552
|
}
|
|
8552
8553
|
else {
|
|
8553
|
-
debug.parse('
|
|
8554
|
+
debug.parse('\ud83d\udccd No separator and no command, breaking. Current token:', this.peek().value);
|
|
8554
8555
|
break;
|
|
8555
8556
|
}
|
|
8556
8557
|
}
|
|
@@ -8564,18 +8565,18 @@ class Parser {
|
|
|
8564
8565
|
if (!this.check('end') && !extraStops.some(s => this.check(s))) {
|
|
8565
8566
|
terminator = '';
|
|
8566
8567
|
}
|
|
8567
|
-
debug.parse('
|
|
8568
|
+
debug.parse('\u2705 parseCommandListUntilTerminator: parsed', commands.length, 'commands (terminator:', terminator, ')');
|
|
8568
8569
|
return { commands, terminator };
|
|
8569
8570
|
}
|
|
8570
8571
|
parseCommandListUntilEnd() {
|
|
8571
8572
|
const { commands } = this.parseCommandListUntilTerminator([]);
|
|
8572
|
-
debug.parse('
|
|
8573
|
+
debug.parse('\ud83d\udd0d After loop, checking for "end". Current token:', this.peek().value);
|
|
8573
8574
|
if (this.check('end')) {
|
|
8574
|
-
debug.parse('
|
|
8575
|
+
debug.parse('\u2705 Found "end", consuming it');
|
|
8575
8576
|
this.advance();
|
|
8576
8577
|
}
|
|
8577
8578
|
else {
|
|
8578
|
-
debug.parse('
|
|
8579
|
+
debug.parse('\u274c ERROR: Expected "end" but got:', this.peek().value, 'at position:', this.peek().start);
|
|
8579
8580
|
throw new Error('Expected "end" to close repeat block');
|
|
8580
8581
|
}
|
|
8581
8582
|
return commands;
|
|
@@ -9248,6 +9249,23 @@ class Parser {
|
|
|
9248
9249
|
this.consume(')', "Expected ')' after parameter list");
|
|
9249
9250
|
}
|
|
9250
9251
|
const bodyCommands = this.parseCommandBlock(['end', 'catch', 'finally']);
|
|
9252
|
+
const { errorSymbol, errorHandler, finallyHandler } = this.parseErrorAndFinallyBlocks();
|
|
9253
|
+
this.consume('end', "Expected 'end' after function definition");
|
|
9254
|
+
return {
|
|
9255
|
+
type: 'def',
|
|
9256
|
+
name: funcName,
|
|
9257
|
+
params,
|
|
9258
|
+
body: bodyCommands,
|
|
9259
|
+
...(errorSymbol !== undefined && { errorSymbol }),
|
|
9260
|
+
...(errorHandler !== undefined && { errorHandler }),
|
|
9261
|
+
...(finallyHandler !== undefined && { finallyHandler }),
|
|
9262
|
+
start: pos.start,
|
|
9263
|
+
end: this.getPosition().end,
|
|
9264
|
+
line: pos.line,
|
|
9265
|
+
column: pos.column,
|
|
9266
|
+
};
|
|
9267
|
+
}
|
|
9268
|
+
parseErrorAndFinallyBlocks() {
|
|
9251
9269
|
let errorSymbol;
|
|
9252
9270
|
let errorHandler;
|
|
9253
9271
|
if (this.check('catch')) {
|
|
@@ -9262,19 +9280,10 @@ class Parser {
|
|
|
9262
9280
|
this.advance();
|
|
9263
9281
|
finallyHandler = this.parseCommandBlock(['end']);
|
|
9264
9282
|
}
|
|
9265
|
-
this.consume('end', "Expected 'end' after function definition");
|
|
9266
9283
|
return {
|
|
9267
|
-
type: 'def',
|
|
9268
|
-
name: funcName,
|
|
9269
|
-
params,
|
|
9270
|
-
body: bodyCommands,
|
|
9271
9284
|
...(errorSymbol !== undefined && { errorSymbol }),
|
|
9272
9285
|
...(errorHandler !== undefined && { errorHandler }),
|
|
9273
9286
|
...(finallyHandler !== undefined && { finallyHandler }),
|
|
9274
|
-
start: pos.start,
|
|
9275
|
-
end: this.getPosition().end,
|
|
9276
|
-
line: pos.line,
|
|
9277
|
-
column: pos.column,
|
|
9278
9287
|
};
|
|
9279
9288
|
}
|
|
9280
9289
|
parseEventNameWithNamespace(errorMessage) {
|
|
@@ -9419,13 +9428,13 @@ class Parser {
|
|
|
9419
9428
|
try {
|
|
9420
9429
|
const cmd = this.parseCommand();
|
|
9421
9430
|
if (this.error && this.error !== savedError) {
|
|
9422
|
-
debug.parse('
|
|
9431
|
+
debug.parse('\u26a0\ufe0f Command parsing added error, restoring error state. Error was:', this.error.message);
|
|
9423
9432
|
this.error = savedError;
|
|
9424
9433
|
}
|
|
9425
9434
|
return cmd;
|
|
9426
9435
|
}
|
|
9427
9436
|
catch (error) {
|
|
9428
|
-
debug.parse('
|
|
9437
|
+
debug.parse('\u26a0\ufe0f Command parsing threw exception, restoring error state:', error instanceof Error ? error.message : String(error));
|
|
9429
9438
|
this.error = savedError;
|
|
9430
9439
|
return null;
|
|
9431
9440
|
}
|
|
@@ -9442,12 +9451,12 @@ class Parser {
|
|
|
9442
9451
|
const timeToken = this.advance();
|
|
9443
9452
|
const delayMs = parseTimeToMs(timeToken.value);
|
|
9444
9453
|
modifiers[modifierKey] = delayMs;
|
|
9445
|
-
debug.parse(
|
|
9454
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed '${modName} at ${timeToken.value}' (${delayMs}ms)`);
|
|
9446
9455
|
}
|
|
9447
9456
|
else if (this.matchNumber()) {
|
|
9448
9457
|
const delayMs = parseInt(this.previous().value, 10);
|
|
9449
9458
|
modifiers[modifierKey] = delayMs;
|
|
9450
|
-
debug.parse(
|
|
9459
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed '${modName} at ${delayMs}'`);
|
|
9451
9460
|
}
|
|
9452
9461
|
else {
|
|
9453
9462
|
this.addError(`Expected time expression after '${modName} at', got: ${this.peek().value}`);
|
|
@@ -9458,7 +9467,7 @@ class Parser {
|
|
|
9458
9467
|
}
|
|
9459
9468
|
}
|
|
9460
9469
|
parseEventHandler() {
|
|
9461
|
-
debug.parse(
|
|
9470
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: ENTRY - parsing event handler`);
|
|
9462
9471
|
const eventNames = [];
|
|
9463
9472
|
let firstOnceAlias = false;
|
|
9464
9473
|
if (this.check('first') && !this.checkIsCommand() && this.current + 1 < this.tokens.length) {
|
|
@@ -9467,27 +9476,27 @@ class Parser {
|
|
|
9467
9476
|
if (peek2Value && peek2Value !== 'of' && peek2Value !== 'in' && peek2Value !== 'from') {
|
|
9468
9477
|
this.advance();
|
|
9469
9478
|
firstOnceAlias = true;
|
|
9470
|
-
debug.parse(
|
|
9479
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed 'first' as .once alias`);
|
|
9471
9480
|
}
|
|
9472
9481
|
}
|
|
9473
9482
|
const event = this.parseEventNameWithNamespace("Expected event name after 'on'");
|
|
9474
9483
|
eventNames.push(event);
|
|
9475
|
-
debug.parse(
|
|
9484
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed first event name: ${event}`);
|
|
9476
9485
|
while (this.check('or')) {
|
|
9477
9486
|
this.advance();
|
|
9478
|
-
debug.parse(
|
|
9487
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Found 'or', parsing additional event name`);
|
|
9479
9488
|
const additionalEvent = this.parseEventNameWithNamespace("Expected event name after 'or'");
|
|
9480
9489
|
eventNames.push(additionalEvent);
|
|
9481
|
-
debug.parse(
|
|
9490
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed additional event name: ${additionalEvent}`);
|
|
9482
9491
|
}
|
|
9483
|
-
debug.parse(
|
|
9492
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Total events parsed: ${eventNames.join(', ')}`);
|
|
9484
9493
|
let customEventSource;
|
|
9485
9494
|
if (this.registryIntegration) {
|
|
9486
9495
|
const firstEvent = eventNames[0];
|
|
9487
9496
|
if (this.registryIntegration.hasEventSource(firstEvent)) {
|
|
9488
9497
|
const source = this.registryIntegration.getEventSource(firstEvent);
|
|
9489
9498
|
customEventSource = source?.name;
|
|
9490
|
-
debug.parse(
|
|
9499
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Detected custom event source '${customEventSource}' for event '${firstEvent}'`);
|
|
9491
9500
|
}
|
|
9492
9501
|
}
|
|
9493
9502
|
const eventParams = [];
|
|
@@ -9499,7 +9508,7 @@ class Parser {
|
|
|
9499
9508
|
} while (this.match(','));
|
|
9500
9509
|
}
|
|
9501
9510
|
this.consume(')', "Expected ')' after event parameters");
|
|
9502
|
-
debug.parse(
|
|
9511
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed event parameters: ${eventParams.join(', ')}`);
|
|
9503
9512
|
}
|
|
9504
9513
|
const modifiers = {};
|
|
9505
9514
|
while (this.check('.')) {
|
|
@@ -9508,15 +9517,15 @@ class Parser {
|
|
|
9508
9517
|
const modName = modToken.value.toLowerCase();
|
|
9509
9518
|
if (modName === 'once') {
|
|
9510
9519
|
modifiers.once = true;
|
|
9511
|
-
debug.parse(
|
|
9520
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.once'`);
|
|
9512
9521
|
}
|
|
9513
9522
|
else if (modName === 'prevent') {
|
|
9514
9523
|
modifiers.prevent = true;
|
|
9515
|
-
debug.parse(
|
|
9524
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.prevent'`);
|
|
9516
9525
|
}
|
|
9517
9526
|
else if (modName === 'stop') {
|
|
9518
9527
|
modifiers.stop = true;
|
|
9519
|
-
debug.parse(
|
|
9528
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.stop'`);
|
|
9520
9529
|
}
|
|
9521
9530
|
else if (modName === 'debounce' || modName === 'throttle') {
|
|
9522
9531
|
if (this.check('(')) {
|
|
@@ -9528,11 +9537,11 @@ class Parser {
|
|
|
9528
9537
|
}
|
|
9529
9538
|
if (modName === 'debounce') {
|
|
9530
9539
|
modifiers.debounce = delayMs;
|
|
9531
|
-
debug.parse(
|
|
9540
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.debounce(${delayMs})'`);
|
|
9532
9541
|
}
|
|
9533
9542
|
else {
|
|
9534
9543
|
modifiers.throttle = delayMs;
|
|
9535
|
-
debug.parse(
|
|
9544
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.throttle(${delayMs})'`);
|
|
9536
9545
|
}
|
|
9537
9546
|
this.consume(')', `Expected ')' after ${modName} delay`);
|
|
9538
9547
|
}
|
|
@@ -9541,7 +9550,7 @@ class Parser {
|
|
|
9541
9550
|
}
|
|
9542
9551
|
}
|
|
9543
9552
|
else {
|
|
9544
|
-
debug.parse(
|
|
9553
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Warning - unknown modifier '.${modName}'`);
|
|
9545
9554
|
}
|
|
9546
9555
|
}
|
|
9547
9556
|
this.parseTemporalKeywordModifiers(modifiers);
|
|
@@ -9549,7 +9558,7 @@ class Parser {
|
|
|
9549
9558
|
modifiers.once = true;
|
|
9550
9559
|
}
|
|
9551
9560
|
if (Object.keys(modifiers).length > 0) {
|
|
9552
|
-
debug.parse(
|
|
9561
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifiers:`, modifiers);
|
|
9553
9562
|
}
|
|
9554
9563
|
let condition;
|
|
9555
9564
|
if (this.match('[')) {
|
|
@@ -9560,7 +9569,7 @@ class Parser {
|
|
|
9560
9569
|
if (this.match('from')) {
|
|
9561
9570
|
const targetToken = this.advance();
|
|
9562
9571
|
target = targetToken.value;
|
|
9563
|
-
debug.parse(
|
|
9572
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed 'from' target: ${target} (kind: ${targetToken.kind})`);
|
|
9564
9573
|
this.parseTemporalKeywordModifiers(modifiers);
|
|
9565
9574
|
}
|
|
9566
9575
|
let attributeName;
|
|
@@ -9572,32 +9581,36 @@ class Parser {
|
|
|
9572
9581
|
else {
|
|
9573
9582
|
attributeName = attrToken.value;
|
|
9574
9583
|
}
|
|
9575
|
-
debug.parse(
|
|
9584
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed attribute name: ${attributeName}`);
|
|
9576
9585
|
}
|
|
9577
9586
|
let watchTarget;
|
|
9578
9587
|
if (this.match('in')) {
|
|
9579
|
-
debug.parse(
|
|
9588
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Found 'in' keyword, parsing watch target`);
|
|
9580
9589
|
watchTarget = this.parseExpression();
|
|
9581
|
-
debug.parse(
|
|
9590
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed watch target expression`);
|
|
9582
9591
|
}
|
|
9583
9592
|
const commands = [];
|
|
9584
|
-
debug.parse(
|
|
9593
|
+
debug.parse(`\u2705 parseEventHandler: About to parse commands, current token: ${this.isAtEnd() ? 'END' : this.peek().value}, isAtEnd: ${this.isAtEnd()}`);
|
|
9585
9594
|
while (!this.isAtEnd()) {
|
|
9586
|
-
debug.parse(
|
|
9595
|
+
debug.parse(`\u2705 parseEventHandler: Loop iteration, current token: ${this.peek().value}, kind: ${this.peek().kind}`);
|
|
9587
9596
|
if (this.check('on')) {
|
|
9588
|
-
debug.parse(
|
|
9597
|
+
debug.parse(`\u2705 parseEventHandler: Stopping command parsing, found next event handler 'on'`);
|
|
9589
9598
|
break;
|
|
9590
9599
|
}
|
|
9591
9600
|
if (this.checkComment()) {
|
|
9592
|
-
debug.parse(
|
|
9601
|
+
debug.parse(`\u2705 parseEventHandler: Skipping comment token: ${this.peek().value}`);
|
|
9593
9602
|
this.advance();
|
|
9594
9603
|
continue;
|
|
9595
9604
|
}
|
|
9596
9605
|
if (this.check('end')) {
|
|
9597
|
-
debug.parse(
|
|
9606
|
+
debug.parse(`\u2705 parseEventHandler: Stopping command parsing, found 'end' keyword`);
|
|
9598
9607
|
this.advance();
|
|
9599
9608
|
break;
|
|
9600
9609
|
}
|
|
9610
|
+
if (this.check('catch') || this.check('finally')) {
|
|
9611
|
+
debug.parse(`\u2705 parseEventHandler: Stopping command parsing, found '${this.peek().value}'`);
|
|
9612
|
+
break;
|
|
9613
|
+
}
|
|
9601
9614
|
if (this.checkIsCommand()) {
|
|
9602
9615
|
const nextIsOpenParen = this.tokens[this.current + 1]?.value === '(';
|
|
9603
9616
|
const commandName = this.peek().value.toLowerCase();
|
|
@@ -9626,7 +9639,7 @@ class Parser {
|
|
|
9626
9639
|
const cmd = this.parseCommandWithErrorRecovery();
|
|
9627
9640
|
if (cmd) {
|
|
9628
9641
|
commands.push(cmd);
|
|
9629
|
-
debug.parse(
|
|
9642
|
+
debug.parse(`\u2705 parseEventHandler: Parsed command, next token: ${this.isAtEnd() ? 'END' : this.peek().value}`);
|
|
9630
9643
|
}
|
|
9631
9644
|
}
|
|
9632
9645
|
}
|
|
@@ -9644,7 +9657,7 @@ class Parser {
|
|
|
9644
9657
|
expr = this.parseExpression();
|
|
9645
9658
|
}
|
|
9646
9659
|
catch (error) {
|
|
9647
|
-
debug.parse('
|
|
9660
|
+
debug.parse('\u26a0\ufe0f Expression parsing error, restoring error state:', error instanceof Error ? error.message : String(error));
|
|
9648
9661
|
this.error = savedError;
|
|
9649
9662
|
break;
|
|
9650
9663
|
}
|
|
@@ -9691,7 +9704,9 @@ class Parser {
|
|
|
9691
9704
|
!this.check('then') &&
|
|
9692
9705
|
!this.check('and') &&
|
|
9693
9706
|
!this.check(',') &&
|
|
9694
|
-
!this.check('on')
|
|
9707
|
+
!this.check('on') &&
|
|
9708
|
+
!this.check('catch') &&
|
|
9709
|
+
!this.check('finally')) {
|
|
9695
9710
|
this.advance();
|
|
9696
9711
|
}
|
|
9697
9712
|
if (this.match('then', 'and', ',')) {
|
|
@@ -9704,12 +9719,24 @@ class Parser {
|
|
|
9704
9719
|
break;
|
|
9705
9720
|
}
|
|
9706
9721
|
}
|
|
9722
|
+
let errorSymbol;
|
|
9723
|
+
let errorHandler;
|
|
9724
|
+
let finallyHandler;
|
|
9725
|
+
if (!this.isAtEnd() && (this.check('catch') || this.check('finally'))) {
|
|
9726
|
+
({ errorSymbol, errorHandler, finallyHandler } = this.parseErrorAndFinallyBlocks());
|
|
9727
|
+
if (this.check('end')) {
|
|
9728
|
+
this.advance();
|
|
9729
|
+
}
|
|
9730
|
+
}
|
|
9707
9731
|
const pos = this.getPosition();
|
|
9708
9732
|
const node = {
|
|
9709
9733
|
type: 'eventHandler',
|
|
9710
9734
|
event: eventNames.length === 1 ? eventNames[0] : eventNames.join('|'),
|
|
9711
9735
|
events: eventNames,
|
|
9712
9736
|
commands,
|
|
9737
|
+
...(errorSymbol !== undefined && { errorSymbol }),
|
|
9738
|
+
...(errorHandler !== undefined && { errorHandler }),
|
|
9739
|
+
...(finallyHandler !== undefined && { finallyHandler }),
|
|
9713
9740
|
...(eventParams.length > 0 && { args: eventParams }),
|
|
9714
9741
|
...(condition && { condition }),
|
|
9715
9742
|
...(target && { target }),
|
|
@@ -9722,7 +9749,7 @@ class Parser {
|
|
|
9722
9749
|
line: pos.line,
|
|
9723
9750
|
column: pos.column,
|
|
9724
9751
|
};
|
|
9725
|
-
debug.parse(
|
|
9752
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Created node with events: ${eventNames.join(', ')}, attributeName: ${attributeName || 'none'}, watchTarget: ${watchTarget ? 'yes' : 'none'}`);
|
|
9726
9753
|
return node;
|
|
9727
9754
|
}
|
|
9728
9755
|
parseBehaviorDefinition() {
|
|
@@ -9787,11 +9814,33 @@ class Parser {
|
|
|
9787
9814
|
}
|
|
9788
9815
|
}
|
|
9789
9816
|
}
|
|
9790
|
-
const handlerCommands = this.
|
|
9817
|
+
const { commands: handlerCommands, terminator } = this.parseCommandListUntilTerminator([
|
|
9818
|
+
'catch',
|
|
9819
|
+
'finally',
|
|
9820
|
+
]);
|
|
9821
|
+
let handlerErrorSymbol;
|
|
9822
|
+
let handlerErrorHandler;
|
|
9823
|
+
let handlerFinallyHandler;
|
|
9824
|
+
if (terminator === 'catch' || terminator === 'finally') {
|
|
9825
|
+
({
|
|
9826
|
+
errorSymbol: handlerErrorSymbol,
|
|
9827
|
+
errorHandler: handlerErrorHandler,
|
|
9828
|
+
finallyHandler: handlerFinallyHandler,
|
|
9829
|
+
} = this.parseErrorAndFinallyBlocks());
|
|
9830
|
+
}
|
|
9831
|
+
if (this.check('end')) {
|
|
9832
|
+
this.advance();
|
|
9833
|
+
}
|
|
9834
|
+
else {
|
|
9835
|
+
throw new Error('Expected "end" to close behavior event handler');
|
|
9836
|
+
}
|
|
9791
9837
|
const handlerNode = {
|
|
9792
9838
|
type: 'eventHandler',
|
|
9793
9839
|
event: eventName,
|
|
9794
9840
|
commands: handlerCommands,
|
|
9841
|
+
...(handlerErrorSymbol !== undefined && { errorSymbol: handlerErrorSymbol }),
|
|
9842
|
+
...(handlerErrorHandler !== undefined && { errorHandler: handlerErrorHandler }),
|
|
9843
|
+
...(handlerFinallyHandler !== undefined && { finallyHandler: handlerFinallyHandler }),
|
|
9795
9844
|
...(eventSource !== undefined && { target: eventSource }),
|
|
9796
9845
|
...(eventArgs.length > 0 && { args: eventArgs }),
|
|
9797
9846
|
start: handlerPos.start,
|
|
@@ -9846,7 +9895,7 @@ class Parser {
|
|
|
9846
9895
|
this.error.message.includes('unclosed parenthes') ||
|
|
9847
9896
|
this.error.message.includes('Unclosed parenthes');
|
|
9848
9897
|
if (!isCriticalError) {
|
|
9849
|
-
debug.parse('
|
|
9898
|
+
debug.parse('\u26a0\ufe0f parseCommandSequence: Command parsing added non-critical error, restoring error state. Error was:', this.error.message);
|
|
9850
9899
|
this.error = savedError;
|
|
9851
9900
|
}
|
|
9852
9901
|
}
|
|
@@ -9856,11 +9905,11 @@ class Parser {
|
|
|
9856
9905
|
!this.isCommand(this.peek().value) &&
|
|
9857
9906
|
!this.check('then') &&
|
|
9858
9907
|
!this.check('on')) {
|
|
9859
|
-
debug.parse('
|
|
9908
|
+
debug.parse('\u26a0\ufe0f parseCommandSequence: Skipping unexpected token:', this.peek().value);
|
|
9860
9909
|
this.advance();
|
|
9861
9910
|
}
|
|
9862
9911
|
if (this.check('on')) {
|
|
9863
|
-
debug.parse('
|
|
9912
|
+
debug.parse('\u2705 parseCommandSequence: Found "on" token, stopping command sequence to allow event handler parsing');
|
|
9864
9913
|
break;
|
|
9865
9914
|
}
|
|
9866
9915
|
if (this.match('then')) {
|
|
@@ -10304,7 +10353,7 @@ class Parser {
|
|
|
10304
10353
|
if (!this.check(')') && callee.type === 'identifier') {
|
|
10305
10354
|
const funcName = callee.name;
|
|
10306
10355
|
if (CommandClassification.isCSSFunction(funcName)) {
|
|
10307
|
-
debug.parse(
|
|
10356
|
+
debug.parse(`\ud83d\udca1 Tip: CSS functions like ${funcName}() should be quoted for clean parsing. ` +
|
|
10308
10357
|
`Use '${funcName}(...)' or \`${funcName}(...)\` instead.`);
|
|
10309
10358
|
}
|
|
10310
10359
|
}
|
|
@@ -10606,7 +10655,7 @@ class Parser {
|
|
|
10606
10655
|
if (this.checkIsCommand() || (this.isCommand(token.value) && !this.isKeyword(token.value))) {
|
|
10607
10656
|
return;
|
|
10608
10657
|
}
|
|
10609
|
-
debug.parse('
|
|
10658
|
+
debug.parse('\u26a0\ufe0f synchronize: Skipping token:', token.value);
|
|
10610
10659
|
this.advance();
|
|
10611
10660
|
}
|
|
10612
10661
|
}
|