@xaendar/compiler 0.6.14 → 0.6.15
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/xaendar-compiler.es.d.ts +13 -0
- package/dist/xaendar-compiler.es.js +249 -290
- package/package.json +3 -3
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compiles a template string into a TypeScript render function body.
|
|
3
|
+
*
|
|
4
|
+
* Runs the three-stage pipeline:
|
|
5
|
+
* 1. **Lexer** — tokenises the raw template text.
|
|
6
|
+
* 2. **Parser** — transforms the token stream into an AST.
|
|
7
|
+
* 3. **Render generator** — emits TypeScript source lines from the AST.
|
|
8
|
+
*
|
|
9
|
+
* @param input - The raw HTML-like template source to compile.
|
|
10
|
+
* @param cssVariableName - Optional name of the CSS variable to inject
|
|
11
|
+
* into the generated `adoptedStyleSheets` assignment.
|
|
12
|
+
* @returns A string containing the compiled TypeScript render method body.
|
|
13
|
+
*/
|
|
1
14
|
export declare function compile(input: string, cssVariableName?: string): string;
|
|
2
15
|
|
|
3
16
|
/**
|
|
@@ -70,10 +70,6 @@ var LexerState = /* @__PURE__ */ function(LexerState) {
|
|
|
70
70
|
* Consuming a template-literal string inside `` {`...`} ``.
|
|
71
71
|
*/
|
|
72
72
|
LexerState["INTERPOLATION_LITERAL"] = "interpolation-literal";
|
|
73
|
-
/**
|
|
74
|
-
* Consuming a `@const name = expression;` declaration.
|
|
75
|
-
*/
|
|
76
|
-
LexerState["CONST_DECLARATION"] = "const-declaration";
|
|
77
73
|
return LexerState;
|
|
78
74
|
}({});
|
|
79
75
|
//#endregion
|
|
@@ -123,57 +119,62 @@ var TokenType = /* @__PURE__ */ function(TokenType) {
|
|
|
123
119
|
*/
|
|
124
120
|
TokenType[TokenType["INTERPOLATION_EXPRESSION"] = 9] = "INTERPOLATION_EXPRESSION";
|
|
125
121
|
/**
|
|
126
|
-
* A `@const name = expression;` template-level constant declaration.
|
|
127
|
-
*/
|
|
128
|
-
TokenType[TokenType["CONST_DECLARATION"] = 10] = "CONST_DECLARATION";
|
|
129
|
-
/**
|
|
130
122
|
* Opening keyword of an `@if` directive.
|
|
131
123
|
*/
|
|
132
|
-
TokenType[TokenType["IF"] =
|
|
124
|
+
TokenType[TokenType["IF"] = 10] = "IF";
|
|
133
125
|
/**
|
|
134
126
|
* Opening keyword of a `@for` directive.
|
|
135
127
|
*/
|
|
136
|
-
TokenType[TokenType["FOR"] =
|
|
128
|
+
TokenType[TokenType["FOR"] = 11] = "FOR";
|
|
137
129
|
/**
|
|
138
130
|
* Opening keyword of an `@else` branch.
|
|
139
131
|
*/
|
|
140
|
-
TokenType[TokenType["ELSE"] =
|
|
132
|
+
TokenType[TokenType["ELSE"] = 12] = "ELSE";
|
|
141
133
|
/**
|
|
142
134
|
* Opening keyword of an `@else if` branch.
|
|
143
135
|
*/
|
|
144
|
-
TokenType[TokenType["ELSE_IF"] =
|
|
136
|
+
TokenType[TokenType["ELSE_IF"] = 13] = "ELSE_IF";
|
|
145
137
|
/**
|
|
146
138
|
* Opening keyword of a `@switch` directive.
|
|
147
139
|
*/
|
|
148
|
-
TokenType[TokenType["SWITCH"] =
|
|
140
|
+
TokenType[TokenType["SWITCH"] = 14] = "SWITCH";
|
|
149
141
|
/**
|
|
150
142
|
* Opening keyword of a `@case` branch.
|
|
151
143
|
*/
|
|
152
|
-
TokenType[TokenType["CASE"] =
|
|
144
|
+
TokenType[TokenType["CASE"] = 15] = "CASE";
|
|
153
145
|
/**
|
|
154
146
|
* Opening keyword of a `@default` branch.
|
|
155
147
|
*/
|
|
156
|
-
TokenType[TokenType["DEFAULT"] =
|
|
148
|
+
TokenType[TokenType["DEFAULT"] = 16] = "DEFAULT";
|
|
157
149
|
/**
|
|
158
150
|
* The condition expression `(...)` associated with a flow-control directive.
|
|
159
151
|
*/
|
|
160
|
-
TokenType[TokenType["CONDITION"] =
|
|
152
|
+
TokenType[TokenType["CONDITION"] = 17] = "CONDITION";
|
|
161
153
|
/**
|
|
162
154
|
* The opening `{` of a flow-control block body.
|
|
163
155
|
*/
|
|
164
|
-
TokenType[TokenType["BLOCK_OPEN"] =
|
|
156
|
+
TokenType[TokenType["BLOCK_OPEN"] = 18] = "BLOCK_OPEN";
|
|
165
157
|
/**
|
|
166
158
|
* The closing `}` of a flow-control block body.
|
|
167
159
|
*/
|
|
168
|
-
TokenType[TokenType["BLOCK_CLOSE"] =
|
|
160
|
+
TokenType[TokenType["BLOCK_CLOSE"] = 19] = "BLOCK_CLOSE";
|
|
169
161
|
/**
|
|
170
162
|
* Sentinel token emitted when the end of the input is reached.
|
|
171
163
|
*/
|
|
172
|
-
TokenType[TokenType["EOF"] =
|
|
164
|
+
TokenType[TokenType["EOF"] = 20] = "EOF";
|
|
173
165
|
return TokenType;
|
|
174
166
|
}({});
|
|
175
167
|
//#endregion
|
|
176
168
|
//#region ../packages/compiler/src/lexer/states/attribute-value.state.ts
|
|
169
|
+
/**
|
|
170
|
+
* Consumes a quoted attribute value `"..."`, collecting characters until
|
|
171
|
+
* the closing `"` is found. Emits an ATTRIBUTE_VALUE token and transitions
|
|
172
|
+
* back to TAG_BODY.
|
|
173
|
+
*
|
|
174
|
+
* @param cursor - The lexer cursor positioned at the first character of the value (after the opening `"`).
|
|
175
|
+
* @param _context - Unused lexer context.
|
|
176
|
+
* @returns Transition result with the ATTRIBUTE_VALUE token and the TAG_BODY state.
|
|
177
|
+
*/
|
|
177
178
|
function consumeAttributeValue(cursor, _context) {
|
|
178
179
|
let read = true;
|
|
179
180
|
let value = "";
|
|
@@ -203,8 +204,8 @@ function consumeAttributeValue(cursor, _context) {
|
|
|
203
204
|
* transitioning back to TAG_BODY when a space, `/`, or `>` is encountered.
|
|
204
205
|
* If the attribute value is an interpolation, pushes the INTERPOLATION state.
|
|
205
206
|
*
|
|
206
|
-
* @param cursor The lexer cursor positioned at the start of the attribute.
|
|
207
|
-
* @param _context Unused lexer context.
|
|
207
|
+
* @param cursor - The lexer cursor positioned at the start of the attribute.
|
|
208
|
+
* @param _context - Unused lexer context.
|
|
208
209
|
* @returns Transition result with the ATTRIBUTE token and next state.
|
|
209
210
|
*/
|
|
210
211
|
function consumeAttribute(cursor, _context) {
|
|
@@ -248,6 +249,18 @@ function consumeAttribute(cursor, _context) {
|
|
|
248
249
|
}
|
|
249
250
|
//#endregion
|
|
250
251
|
//#region ../packages/compiler/src/lexer/utils/consume-flow-control-condition.utils.ts
|
|
252
|
+
/**
|
|
253
|
+
* Consumes a parenthesised flow-control condition expression from the cursor.
|
|
254
|
+
*
|
|
255
|
+
* Skips leading whitespace, then expects `(` followed by a balanced
|
|
256
|
+
* parenthesised expression. Handles nested parentheses and returns the
|
|
257
|
+
* raw expression string (excluding the outer `(` and `)`).
|
|
258
|
+
*
|
|
259
|
+
* @param cursor - The lexer cursor positioned before the opening `(`.
|
|
260
|
+
* @param _context - Unused lexer context (kept for signature consistency).
|
|
261
|
+
* @returns The raw expression string extracted from inside the parentheses.
|
|
262
|
+
* @throws When the next non-space character is not `(`.
|
|
263
|
+
*/
|
|
251
264
|
function consumeFlowControlCondition(cursor, _context) {
|
|
252
265
|
cursor.skipSpaces();
|
|
253
266
|
if (cursor.peek() !== 40) throw new Error(`Expected '(' but got '${String.fromCharCode(cursor.peek())}' at row ${cursor.position.row}, col ${cursor.position.column}`);
|
|
@@ -274,9 +287,9 @@ function consumeFlowControlCondition(cursor, _context) {
|
|
|
274
287
|
/**
|
|
275
288
|
* Advances the cursor by one character and appends it to the accumulator string.
|
|
276
289
|
*
|
|
277
|
-
* @param cursor The lexer cursor to advance.
|
|
278
|
-
* @param expression The current accumulated string.
|
|
279
|
-
* @returns The updated string with the
|
|
290
|
+
* @param cursor - The lexer cursor to advance.
|
|
291
|
+
* @param expression - The current accumulated expression string.
|
|
292
|
+
* @returns The updated string with the newly consumed character appended.
|
|
280
293
|
*/
|
|
281
294
|
function addCharacter$2(cursor, expression) {
|
|
282
295
|
cursor.advance();
|
|
@@ -289,8 +302,8 @@ function addCharacter$2(cursor, expression) {
|
|
|
289
302
|
* handling nested parentheses correctly. Emits a CONDITION token with the
|
|
290
303
|
* raw expression string and transitions to FLOW_CONTROL_BLOCK.
|
|
291
304
|
*
|
|
292
|
-
* @param cursor The lexer cursor positioned at the opening `(`.
|
|
293
|
-
* @param _context Unused lexer context.
|
|
305
|
+
* @param cursor - The lexer cursor positioned at the opening `(`.
|
|
306
|
+
* @param _context - Unused lexer context.
|
|
294
307
|
* @returns Transition result with the CONDITION token and the FLOW_CONTROL_BLOCK state.
|
|
295
308
|
*/
|
|
296
309
|
function consumeCaseFlowControlCondition(cursor, _context) {
|
|
@@ -306,64 +319,14 @@ function consumeCaseFlowControlCondition(cursor, _context) {
|
|
|
306
319
|
};
|
|
307
320
|
}
|
|
308
321
|
//#endregion
|
|
309
|
-
//#region ../packages/compiler/src/lexer/states/const-declaration.ts
|
|
310
|
-
/**
|
|
311
|
-
* Consumes a `@const name = expression;` declaration from the current position.
|
|
312
|
-
* Expects the cursor to be positioned after the `@const ` keyword.
|
|
313
|
-
* Emits a CONST_DECLARATION token containing the variable name and initializer expression.
|
|
314
|
-
*
|
|
315
|
-
* @param cursor The lexer cursor positioned at the start of the variable name.
|
|
316
|
-
* @param _context Unused lexer context.
|
|
317
|
-
* @returns Transition result with the CONST_DECLARATION token and the TEXT state.
|
|
318
|
-
*/
|
|
319
|
-
function consumeConstDeclaration(cursor, _context) {
|
|
320
|
-
let read = true;
|
|
321
|
-
let varName = "";
|
|
322
|
-
let expression = "";
|
|
323
|
-
let retVal;
|
|
324
|
-
cursor.skipSpaces();
|
|
325
|
-
while (read) switch (cursor.peek()) {
|
|
326
|
-
case 32:
|
|
327
|
-
read = false;
|
|
328
|
-
break;
|
|
329
|
-
default:
|
|
330
|
-
cursor.advance();
|
|
331
|
-
varName = `${varName}${cursor.currentChar.value}`;
|
|
332
|
-
}
|
|
333
|
-
cursor.skipSpaces();
|
|
334
|
-
const nextChar = cursor.peek();
|
|
335
|
-
if (nextChar !== 61) throw new Error(`Unexpected character ${String.fromCharCode(nextChar)}.\nExpected '=' `);
|
|
336
|
-
cursor.advance();
|
|
337
|
-
cursor.skipSpaces();
|
|
338
|
-
read = true;
|
|
339
|
-
while (read) switch (cursor.peek()) {
|
|
340
|
-
case 59:
|
|
341
|
-
retVal = {
|
|
342
|
-
state: LexerState.TEXT,
|
|
343
|
-
tokens: [{
|
|
344
|
-
type: TokenType.CONST_DECLARATION,
|
|
345
|
-
parts: [varName, expression]
|
|
346
|
-
}]
|
|
347
|
-
};
|
|
348
|
-
read = false;
|
|
349
|
-
break;
|
|
350
|
-
default:
|
|
351
|
-
cursor.advance();
|
|
352
|
-
expression = `${expression}${cursor.currentChar.value}`;
|
|
353
|
-
}
|
|
354
|
-
cursor.advance();
|
|
355
|
-
expression = `${expression};`;
|
|
356
|
-
return retVal;
|
|
357
|
-
}
|
|
358
|
-
//#endregion
|
|
359
322
|
//#region ../packages/compiler/src/lexer/states/default-flow-control-condition.state.ts
|
|
360
323
|
/**
|
|
361
324
|
* Consumes the condition expression `(...)` of a flow-control directive,
|
|
362
325
|
* handling nested parentheses correctly. Emits a CONDITION token with the
|
|
363
326
|
* raw expression string and transitions to FLOW_CONTROL_BLOCK.
|
|
364
327
|
*
|
|
365
|
-
* @param cursor The lexer cursor positioned at the opening `(`.
|
|
366
|
-
* @param _context Unused lexer context.
|
|
328
|
+
* @param cursor - The lexer cursor positioned at the opening `(`.
|
|
329
|
+
* @param _context - Unused lexer context.
|
|
367
330
|
* @returns Transition result with the CONDITION token and the FLOW_CONTROL_BLOCK state.
|
|
368
331
|
*/
|
|
369
332
|
function consumeDefaultFlowControlCondition(cursor, _context) {
|
|
@@ -382,8 +345,8 @@ function consumeDefaultFlowControlCondition(cursor, _context) {
|
|
|
382
345
|
* Consumes a DOM event binding starting with `@` and reads until a delimiter
|
|
383
346
|
* (space, `/`, or `>`) is found. Emits an EVENT token containing the raw binding string.
|
|
384
347
|
*
|
|
385
|
-
* @param cursor The lexer cursor positioned on the `@` character.
|
|
386
|
-
* @param _context Unused lexer context.
|
|
348
|
+
* @param cursor - The lexer cursor positioned on the `@` character.
|
|
349
|
+
* @param _context - Unused lexer context.
|
|
387
350
|
* @returns Transition result with the EVENT token and the TAG_BODY state.
|
|
388
351
|
*/
|
|
389
352
|
function consumeEvent(cursor, _context) {
|
|
@@ -428,8 +391,8 @@ function consumeEvent(cursor, _context) {
|
|
|
428
391
|
* Recognises `@if`, `@for`, `@else`, `@switch`, `@case`, `@default`, and `@const`.
|
|
429
392
|
* Advances the cursor past the keyword and transitions to the appropriate next state.
|
|
430
393
|
*
|
|
431
|
-
* @param cursor The lexer cursor positioned on the `@` character.
|
|
432
|
-
* @param _context Unused lexer context.
|
|
394
|
+
* @param cursor - The lexer cursor positioned on the `@` character.
|
|
395
|
+
* @param _context - Unused lexer context.
|
|
433
396
|
* @returns Transition result with the matching flow-control token and next state.
|
|
434
397
|
*/
|
|
435
398
|
function consumeFlowControl(cursor, _context) {
|
|
@@ -482,24 +445,24 @@ function consumeFlowControl(cursor, _context) {
|
|
|
482
445
|
state: LexerState.FLOW_CONTROL_BLOCK,
|
|
483
446
|
tokens: [{ type: TokenType.DEFAULT }]
|
|
484
447
|
};
|
|
485
|
-
} else if (cursor.peekMatch("const ")) {
|
|
486
|
-
cursor.advance(6);
|
|
487
|
-
retVal = { state: LexerState.CONST_DECLARATION };
|
|
488
448
|
}
|
|
489
449
|
return retVal;
|
|
490
450
|
}
|
|
491
451
|
//#endregion
|
|
492
452
|
//#region ../packages/compiler/src/lexer/states/flow-control-block.state.ts
|
|
493
453
|
/**
|
|
494
|
-
* Consumes the opening `{` of a flow
|
|
454
|
+
* Consumes the opening `{` of a flow-control block body,
|
|
495
455
|
* skipping any leading whitespace before it.
|
|
496
456
|
*
|
|
497
|
-
* Emits a BLOCK_OPEN token and transitions to TEXT,
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
* rather than as an interpolation boundary.
|
|
457
|
+
* Emits a BLOCK_OPEN token and transitions to TEXT, pushing FLOW_CONTROL_BLOCK
|
|
458
|
+
* onto the state stack so that `consumeText` later recognises the matching `}`
|
|
459
|
+
* as a BLOCK_CLOSE rather than an interpolation boundary.
|
|
501
460
|
*
|
|
502
|
-
* Used by:
|
|
461
|
+
* Used by: `@if`, `@for`, `@switch`, `@case`, `@else`, `@default`.
|
|
462
|
+
*
|
|
463
|
+
* @param cursor - The lexer cursor positioned before the opening `{`.
|
|
464
|
+
* @param _context - Unused lexer context.
|
|
465
|
+
* @returns Transition result with the BLOCK_OPEN token and the TEXT state.
|
|
503
466
|
*/
|
|
504
467
|
function consumeFlowControlBlock(cursor, _context) {
|
|
505
468
|
cursor.skipSpaces();
|
|
@@ -518,8 +481,8 @@ function consumeFlowControlBlock(cursor, _context) {
|
|
|
518
481
|
* brace depth. Emits an INTERPOLATION_EXPRESSION token and pops the state stack to
|
|
519
482
|
* return to the previous state (ATTRIBUTE or TEXT).
|
|
520
483
|
*
|
|
521
|
-
* @param cursor The lexer cursor positioned at the first character of the expression.
|
|
522
|
-
* @param context
|
|
484
|
+
* @param cursor - The lexer cursor positioned at the first character of the expression.
|
|
485
|
+
* @param context - The lexer context used to retrieve the previous state for restoration.
|
|
523
486
|
* @returns Transition result with the INTERPOLATION_EXPRESSION token and restored state.
|
|
524
487
|
*/
|
|
525
488
|
function consumeInterpolationExpression(cursor, context) {
|
|
@@ -568,9 +531,9 @@ function consumeInterpolationExpression(cursor, context) {
|
|
|
568
531
|
/**
|
|
569
532
|
* Advances the cursor by one character and appends it to the accumulator string.
|
|
570
533
|
*
|
|
571
|
-
* @param cursor The lexer cursor to advance.
|
|
572
|
-
* @param interpolation The current accumulated string.
|
|
573
|
-
* @returns The updated string with the
|
|
534
|
+
* @param cursor - The lexer cursor to advance.
|
|
535
|
+
* @param interpolation - The current accumulated expression string.
|
|
536
|
+
* @returns The updated string with the newly consumed character appended.
|
|
574
537
|
*/
|
|
575
538
|
function addCharacter$1(cursor, interpolation) {
|
|
576
539
|
cursor.advance(1);
|
|
@@ -583,8 +546,8 @@ function addCharacter$1(cursor, interpolation) {
|
|
|
583
546
|
* until the closing backtick followed by `}`. Emits an INTERPOLATION_LITERAL token
|
|
584
547
|
* and pops the state stack to return to the previous state.
|
|
585
548
|
*
|
|
586
|
-
* @param cursor The lexer cursor positioned at the opening backtick.
|
|
587
|
-
* @param context
|
|
549
|
+
* @param cursor - The lexer cursor positioned at the opening backtick.
|
|
550
|
+
* @param context - The lexer context used to retrieve the previous state for restoration.
|
|
588
551
|
* @returns Transition result with the INTERPOLATION_LITERAL token and restored state.
|
|
589
552
|
*/
|
|
590
553
|
function consumeInterpolationliteral(cursor, context) {
|
|
@@ -623,9 +586,9 @@ function consumeInterpolationliteral(cursor, context) {
|
|
|
623
586
|
/**
|
|
624
587
|
* Advances the cursor by one character and appends it to the accumulator string.
|
|
625
588
|
*
|
|
626
|
-
* @param cursor The lexer cursor to advance.
|
|
627
|
-
* @param interpolation The current accumulated string.
|
|
628
|
-
* @returns The updated string with the
|
|
589
|
+
* @param cursor - The lexer cursor to advance.
|
|
590
|
+
* @param interpolation - The current accumulated expression string.
|
|
591
|
+
* @returns The updated string with the newly consumed character appended.
|
|
629
592
|
*/
|
|
630
593
|
function addCharacter(cursor, interpolation) {
|
|
631
594
|
cursor.advance();
|
|
@@ -634,24 +597,22 @@ function addCharacter(cursor, interpolation) {
|
|
|
634
597
|
//#endregion
|
|
635
598
|
//#region ../packages/compiler/src/utils/chars.utils.ts
|
|
636
599
|
/**
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
* \v
|
|
644
|
-
* @param str String to check
|
|
645
|
-
* @returns True if string is not blank, false otherwise
|
|
600
|
+
* Checks whether a string contains at least one non-whitespace character.
|
|
601
|
+
*
|
|
602
|
+
* Whitespace characters include space, `\n`, `\r`, `\t`, `\f`, and `\v`.
|
|
603
|
+
*
|
|
604
|
+
* @param str - The string to check.
|
|
605
|
+
* @returns `true` if the string is not blank, `false` if it consists entirely of whitespace.
|
|
646
606
|
*/
|
|
647
607
|
function isNotBlank(str) {
|
|
648
608
|
return /\S/.test(str);
|
|
649
609
|
}
|
|
650
610
|
/**
|
|
651
|
-
*
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
* @
|
|
611
|
+
* Checks whether the given ASCII code is a valid first character for a
|
|
612
|
+
* JavaScript identifier (`A`–`Z`, `a`–`z`, `$`, `_`).
|
|
613
|
+
*
|
|
614
|
+
* @param code - The ASCII code to evaluate.
|
|
615
|
+
* @returns `true` if the code can start a JS identifier, `false` otherwise.
|
|
655
616
|
*/
|
|
656
617
|
function isJSIdentifierStart(code) {
|
|
657
618
|
return code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 36 || code === 95;
|
|
@@ -663,8 +624,8 @@ function isJSIdentifierStart(code) {
|
|
|
663
624
|
* Advances past `{` and any leading spaces, then inspects the next character:
|
|
664
625
|
* a backtick routes to INTERPOLATION_LITERAL, a JS identifier start routes to INTERPOLATION_EXPRESSION.
|
|
665
626
|
*
|
|
666
|
-
* @param cursor The lexer cursor positioned on the `{` character.
|
|
667
|
-
* @param _context Unused lexer context.
|
|
627
|
+
* @param cursor - The lexer cursor positioned on the `{` character.
|
|
628
|
+
* @param _context - Unused lexer context.
|
|
668
629
|
* @returns Transition result with the appropriate interpolation sub-state.
|
|
669
630
|
*/
|
|
670
631
|
function consumeInterpolation(cursor, _context) {
|
|
@@ -684,8 +645,8 @@ function consumeInterpolation(cursor, _context) {
|
|
|
684
645
|
* an event binding (`@`), an attribute, the end of the tag (`>` or `/`), or whitespace.
|
|
685
646
|
* Transitions to the appropriate state without emitting any tokens.
|
|
686
647
|
*
|
|
687
|
-
* @param cursor The lexer cursor positioned inside a tag body.
|
|
688
|
-
* @param _context Unused lexer context.
|
|
648
|
+
* @param cursor - The lexer cursor positioned inside a tag body.
|
|
649
|
+
* @param _context - Unused lexer context.
|
|
689
650
|
* @returns Transition result with the next state and no tokens.
|
|
690
651
|
*/
|
|
691
652
|
function consumeTagBody(cursor, _context) {
|
|
@@ -716,8 +677,8 @@ function consumeTagBody(cursor, _context) {
|
|
|
716
677
|
* Consumes a closing tag `</tagName>`, skipping the `</` prefix and any surrounding
|
|
717
678
|
* whitespace. Emits a TAG_CLOSE_NAME token with the tag name and transitions to TEXT.
|
|
718
679
|
*
|
|
719
|
-
* @param cursor The lexer cursor positioned at the `<` of a closing tag.
|
|
720
|
-
* @param _context Unused lexer context.
|
|
680
|
+
* @param cursor - The lexer cursor positioned at the `<` of a closing tag.
|
|
681
|
+
* @param _context - Unused lexer context.
|
|
721
682
|
* @returns Transition result with the TAG_CLOSE_NAME token and the TEXT state.
|
|
722
683
|
*/
|
|
723
684
|
function consumeTagClose(cursor, _context) {
|
|
@@ -751,8 +712,8 @@ function consumeTagClose(cursor, _context) {
|
|
|
751
712
|
* Consumes the closing characters of an open tag: `>` emits TAG_OPEN_END and
|
|
752
713
|
* transitions to TEXT, while `/>` emits TAG_SELF_CLOSE and also transitions to TEXT.
|
|
753
714
|
*
|
|
754
|
-
* @param cursor The lexer cursor positioned at `>` or `/`.
|
|
755
|
-
* @param _context Unused lexer context.
|
|
715
|
+
* @param cursor - The lexer cursor positioned at `>` or `/`.
|
|
716
|
+
* @param _context - Unused lexer context.
|
|
756
717
|
* @returns Transition result with TAG_OPEN_END or TAG_SELF_CLOSE and the TEXT state.
|
|
757
718
|
*/
|
|
758
719
|
function consumeTagOpenEnd(cursor, _context) {
|
|
@@ -788,8 +749,8 @@ function consumeTagOpenEnd(cursor, _context) {
|
|
|
788
749
|
* Consumes an opening tag name after `<`, reading until a space, `/`, or `>` is found.
|
|
789
750
|
* Emits a TAG_OPEN_NAME token with the tag name and transitions to TAG_BODY.
|
|
790
751
|
*
|
|
791
|
-
* @param cursor The lexer cursor positioned at the `<` character.
|
|
792
|
-
* @param _context Unused lexer context.
|
|
752
|
+
* @param cursor - The lexer cursor positioned at the `<` character.
|
|
753
|
+
* @param _context - Unused lexer context.
|
|
793
754
|
* @returns Transition result with the TAG_OPEN_NAME token and the TAG_BODY state.
|
|
794
755
|
*/
|
|
795
756
|
function consumeTagOpenName(cursor, _context) {
|
|
@@ -824,8 +785,8 @@ function consumeTagOpenName(cursor, _context) {
|
|
|
824
785
|
* is reached: `<` (tag open/close), `{` (interpolation), `@` (flow-control or event),
|
|
825
786
|
* or `}` (block close). Emits a TEXT token if non-blank text was accumulated.
|
|
826
787
|
*
|
|
827
|
-
* @param cursor The lexer cursor positioned at the start of text content.
|
|
828
|
-
* @param context
|
|
788
|
+
* @param cursor - The lexer cursor positioned at the start of text content.
|
|
789
|
+
* @param context - The lexer context used to detect flow-control block boundaries.
|
|
829
790
|
* @returns Transition result with an optional TEXT token and the next state.
|
|
830
791
|
*/
|
|
831
792
|
function consumeText(cursor, context) {
|
|
@@ -941,7 +902,7 @@ var LexerCursor = class {
|
|
|
941
902
|
/**
|
|
942
903
|
* Creates a new cursor for the given input source.
|
|
943
904
|
*
|
|
944
|
-
* @param input Full source string to be
|
|
905
|
+
* @param input - Full source string to be tokenised.
|
|
945
906
|
*/
|
|
946
907
|
constructor(input) {
|
|
947
908
|
this.input = input;
|
|
@@ -955,9 +916,8 @@ var LexerCursor = class {
|
|
|
955
916
|
* - Detects line breaks (LF / CR)
|
|
956
917
|
* - Throws an EOF error when the end of the input is reached
|
|
957
918
|
*
|
|
958
|
-
* @param chars Number of characters to consume
|
|
959
|
-
*
|
|
960
|
-
* @throws Error with cause `EOF` when advancing past input length
|
|
919
|
+
* @param chars - Number of characters to consume. Must be >= 1.
|
|
920
|
+
* @throws When `chars` is less than 1 or when advancing past the end of the input.
|
|
961
921
|
*/
|
|
962
922
|
advance(chars = 1) {
|
|
963
923
|
if (chars < 1) throw new Error(`${chars} is not a valid value. Please enter a number equal or greater than 1`);
|
|
@@ -1072,13 +1032,12 @@ var Lexer = class {
|
|
|
1072
1032
|
[LexerState.EVENT]: consumeEvent,
|
|
1073
1033
|
[LexerState.INTERPOLATION]: consumeInterpolation,
|
|
1074
1034
|
[LexerState.INTERPOLATION_EXPRESSION]: consumeInterpolationExpression,
|
|
1075
|
-
[LexerState.INTERPOLATION_LITERAL]: consumeInterpolationliteral
|
|
1076
|
-
[LexerState.CONST_DECLARATION]: consumeConstDeclaration
|
|
1035
|
+
[LexerState.INTERPOLATION_LITERAL]: consumeInterpolationliteral
|
|
1077
1036
|
};
|
|
1078
1037
|
/**
|
|
1079
|
-
* Creates a new
|
|
1038
|
+
* Creates a new Lexer instance for the given template content.
|
|
1080
1039
|
*
|
|
1081
|
-
* @param input The full template text
|
|
1040
|
+
* @param input - The full template text to tokenise.
|
|
1082
1041
|
*/
|
|
1083
1042
|
constructor(input) {
|
|
1084
1043
|
this.input = input;
|
|
@@ -1147,7 +1106,7 @@ var ParserCursor = class {
|
|
|
1147
1106
|
/**
|
|
1148
1107
|
* Creates a new ParserCursor for the given token array.
|
|
1149
1108
|
*
|
|
1150
|
-
* @param _tokens
|
|
1109
|
+
* @param _tokens - The array of tokens to navigate.
|
|
1151
1110
|
*/
|
|
1152
1111
|
constructor(_tokens) {
|
|
1153
1112
|
this._tokens = _tokens;
|
|
@@ -1155,11 +1114,10 @@ var ParserCursor = class {
|
|
|
1155
1114
|
/**
|
|
1156
1115
|
* Advances the cursor by the specified number of tokens.
|
|
1157
1116
|
*
|
|
1158
|
-
* Updates the current token and index.
|
|
1117
|
+
* Updates the current token and its index.
|
|
1159
1118
|
*
|
|
1160
|
-
* @param chars Number of tokens to advance
|
|
1161
|
-
*
|
|
1162
|
-
* @throws Error with cause `EOF` when advancing past the end
|
|
1119
|
+
* @param chars - Number of tokens to advance. Must be >= 1.
|
|
1120
|
+
* @throws When `chars` is less than 1.
|
|
1163
1121
|
*/
|
|
1164
1122
|
advance(chars = 1) {
|
|
1165
1123
|
if (chars < 1) throw new Error(`${chars} is not a valid value. Please enter a number equal or greater than 1`);
|
|
@@ -1235,10 +1193,6 @@ var ASTNodeType = /* @__PURE__ */ function(ASTNodeType) {
|
|
|
1235
1193
|
* A `@case` or `@default` branch inside a `@switch`.
|
|
1236
1194
|
*/
|
|
1237
1195
|
ASTNodeType[ASTNodeType["Case"] = 8] = "Case";
|
|
1238
|
-
/**
|
|
1239
|
-
* A `@const` declaration node.
|
|
1240
|
-
*/
|
|
1241
|
-
ASTNodeType[ASTNodeType["ConstDeclaration"] = 9] = "ConstDeclaration";
|
|
1242
1196
|
return ASTNodeType;
|
|
1243
1197
|
}({});
|
|
1244
1198
|
//#endregion
|
|
@@ -1419,31 +1373,13 @@ function isAssignmentOperator(kind) {
|
|
|
1419
1373
|
return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;
|
|
1420
1374
|
}
|
|
1421
1375
|
//#endregion
|
|
1422
|
-
//#region ../packages/compiler/src/parser/states/parse-const-declaration.state.ts
|
|
1423
|
-
/**
|
|
1424
|
-
* Parses a CONST_DECLARATION token into a `ConstDeclarationNode`.
|
|
1425
|
-
*
|
|
1426
|
-
* @param cursor Parser cursor; advanced past the CONST_DECLARATION token.
|
|
1427
|
-
* @param _parseNode Unused parser function.
|
|
1428
|
-
* @param token The CONST_DECLARATION token containing variable name and expression.
|
|
1429
|
-
* @returns The parsed `ConstDeclarationNode`.
|
|
1430
|
-
*/
|
|
1431
|
-
function parseConstDeclaration(cursor, _parseNode, token) {
|
|
1432
|
-
cursor.advance();
|
|
1433
|
-
return {
|
|
1434
|
-
type: ASTNodeType.ConstDeclaration,
|
|
1435
|
-
varName: token.parts[0],
|
|
1436
|
-
expression: validateExpression(token.parts[1]).node
|
|
1437
|
-
};
|
|
1438
|
-
}
|
|
1439
|
-
//#endregion
|
|
1440
1376
|
//#region ../packages/compiler/src/parser/states/parse-interpolation.state.ts
|
|
1441
1377
|
/**
|
|
1442
1378
|
* Parses an interpolation expression or literal token into an `InterpolationNode`.
|
|
1443
1379
|
*
|
|
1444
|
-
* @param cursor Parser cursor; advanced past the interpolation token.
|
|
1445
|
-
* @param _parseNode Unused parser function.
|
|
1446
|
-
* @param token The INTERPOLATION_EXPRESSION or INTERPOLATION_LITERAL token.
|
|
1380
|
+
* @param cursor - Parser cursor; advanced past the interpolation token.
|
|
1381
|
+
* @param _parseNode - Unused parser function (kept for signature consistency).
|
|
1382
|
+
* @param token - The INTERPOLATION_EXPRESSION or INTERPOLATION_LITERAL token.
|
|
1447
1383
|
* @returns The parsed `InterpolationNode`.
|
|
1448
1384
|
*/
|
|
1449
1385
|
function parseInterpolation(cursor, _parseNode, token) {
|
|
@@ -1459,9 +1395,9 @@ function parseInterpolation(cursor, _parseNode, token) {
|
|
|
1459
1395
|
* Parses an ATTRIBUTE token into an `AttributeNode`.
|
|
1460
1396
|
* Handles boolean attributes (no `=`), string values, and interpolation values.
|
|
1461
1397
|
*
|
|
1462
|
-
* @param cursor Parser cursor; advanced past the ATTRIBUTE token.
|
|
1463
|
-
* @param parseNode Parser
|
|
1464
|
-
* @param token The ATTRIBUTE token to parse.
|
|
1398
|
+
* @param cursor - Parser cursor; advanced past the ATTRIBUTE token.
|
|
1399
|
+
* @param parseNode - Parser function for recursive child parsing.
|
|
1400
|
+
* @param token - The ATTRIBUTE token to parse.
|
|
1465
1401
|
* @returns The parsed `AttributeNode`.
|
|
1466
1402
|
*/
|
|
1467
1403
|
function parseAttribute(cursor, parseNode, token) {
|
|
@@ -1489,9 +1425,9 @@ function parseAttribute(cursor, parseNode, token) {
|
|
|
1489
1425
|
* Parses an EVENT token into an `EventNode` by splitting the raw
|
|
1490
1426
|
* `eventName=handler` string.
|
|
1491
1427
|
*
|
|
1492
|
-
* @param cursor Parser cursor; advanced past the EVENT token.
|
|
1493
|
-
* @param _parseNode Unused parser function.
|
|
1494
|
-
* @param token The EVENT token to parse.
|
|
1428
|
+
* @param cursor - Parser cursor; advanced past the EVENT token.
|
|
1429
|
+
* @param _parseNode - Unused parser function (kept for signature consistency).
|
|
1430
|
+
* @param token - The EVENT token to parse.
|
|
1495
1431
|
* @returns The parsed `EventNode`.
|
|
1496
1432
|
*/
|
|
1497
1433
|
function parseEvent(cursor, _parseNode, token) {
|
|
@@ -1510,9 +1446,9 @@ function parseEvent(cursor, _parseNode, token) {
|
|
|
1510
1446
|
* Parses a TAG_OPEN_NAME token and the subsequent attributes, events, and children
|
|
1511
1447
|
* into an `ElementNode`. Handles both regular and self-closing tags.
|
|
1512
1448
|
*
|
|
1513
|
-
* @param cursor Parser cursor positioned at the TAG_OPEN_NAME token.
|
|
1514
|
-
* @param
|
|
1515
|
-
* @param token The TAG_OPEN_NAME token containing the tag name.
|
|
1449
|
+
* @param cursor - Parser cursor positioned at the TAG_OPEN_NAME token.
|
|
1450
|
+
* @param parseNode - Parser function for recursive child parsing.
|
|
1451
|
+
* @param token - The TAG_OPEN_NAME token containing the tag name.
|
|
1516
1452
|
* @returns The parsed `ElementNode`.
|
|
1517
1453
|
*/
|
|
1518
1454
|
function parseElement(cursor, parseNode, token) {
|
|
@@ -1561,8 +1497,8 @@ function parseElement(cursor, parseNode, token) {
|
|
|
1561
1497
|
/**
|
|
1562
1498
|
* Returns `true` if the next token in the stream is a closing tag for the given tag name.
|
|
1563
1499
|
*
|
|
1564
|
-
* @param cursor Parser cursor to peek from.
|
|
1565
|
-
* @param tagName The expected tag name to match.
|
|
1500
|
+
* @param cursor - Parser cursor to peek from.
|
|
1501
|
+
* @param tagName - The expected tag name to match.
|
|
1566
1502
|
* @returns `true` if the next token is TAG_CLOSE_NAME matching `tagName`.
|
|
1567
1503
|
*/
|
|
1568
1504
|
function isTagClose(cursor, tagName) {
|
|
@@ -1575,8 +1511,8 @@ function isTagClose(cursor, tagName) {
|
|
|
1575
1511
|
* Parses child AST nodes inside a flow-control block until a BLOCK_CLOSE token is reached.
|
|
1576
1512
|
* Consumes the BLOCK_CLOSE token before returning.
|
|
1577
1513
|
*
|
|
1578
|
-
* @param cursor Parser cursor positioned at the first token inside the block.
|
|
1579
|
-
* @param parseNode Parser function for recursive child parsing.
|
|
1514
|
+
* @param cursor - Parser cursor positioned at the first token inside the block.
|
|
1515
|
+
* @param parseNode - Parser function for recursive child parsing.
|
|
1580
1516
|
* @returns Array of parsed child `ASTNode`s.
|
|
1581
1517
|
*/
|
|
1582
1518
|
function parseBlockChildren(cursor, parseNode) {
|
|
@@ -1594,9 +1530,9 @@ function parseBlockChildren(cursor, parseNode) {
|
|
|
1594
1530
|
* Parses a `@for` directive, consuming the FOR token, the CONDITION token,
|
|
1595
1531
|
* the BLOCK_OPEN token, and all child nodes until BLOCK_CLOSE.
|
|
1596
1532
|
*
|
|
1597
|
-
* @param cursor Parser cursor positioned at the FOR token.
|
|
1598
|
-
* @param
|
|
1599
|
-
* @param _token The FOR token (
|
|
1533
|
+
* @param cursor - Parser cursor positioned at the FOR token.
|
|
1534
|
+
* @param parseNode - Parser function for recursive child parsing.
|
|
1535
|
+
* @param _token - The FOR token (consumed for position advancement).
|
|
1600
1536
|
* @returns The parsed `ForNode`.
|
|
1601
1537
|
*/
|
|
1602
1538
|
function parseForControlFlow(cursor, parseNode, _token) {
|
|
@@ -1656,12 +1592,10 @@ function parseForExpression(source, baseOffset) {
|
|
|
1656
1592
|
* aliases for implicit loop variables (e.g. `$index = i, $last = l, $even = isEven`).
|
|
1657
1593
|
*
|
|
1658
1594
|
* Valid entries are comma-separated pairs in the form `$implicit = alias`.
|
|
1659
|
-
* Diagnostics are pushed to `diagnostics` for any malformed or duplicate entry.
|
|
1660
1595
|
*
|
|
1661
|
-
* @param source
|
|
1662
|
-
* @param baseOffset
|
|
1663
|
-
* @param out
|
|
1664
|
-
* @param diagnostics - Array to collect any parse errors.
|
|
1596
|
+
* @param source - The raw alias-declarations string (everything after the second `;`).
|
|
1597
|
+
* @param baseOffset - Character offset of `source` within the original template.
|
|
1598
|
+
* @param out - Map to populate with `alias → implicit-variable` entries.
|
|
1665
1599
|
*/
|
|
1666
1600
|
function parseImplicitAliases(source, baseOffset, out) {
|
|
1667
1601
|
const entries = source.split(",");
|
|
@@ -1761,9 +1695,9 @@ function isValidIdentifier(name) {
|
|
|
1761
1695
|
* Parses an `@if` directive, consuming the IF token, the CONDITION token,
|
|
1762
1696
|
* the BLOCK_OPEN token, all consequent children, and an optional `@else` branch.
|
|
1763
1697
|
*
|
|
1764
|
-
* @param cursor Parser cursor positioned at the IF token.
|
|
1765
|
-
* @param context Parser
|
|
1766
|
-
* @param token The IF token (
|
|
1698
|
+
* @param cursor - Parser cursor positioned at the IF token.
|
|
1699
|
+
* @param context - Parser function for recursive child parsing.
|
|
1700
|
+
* @param token - The IF token (consumed for position advancement).
|
|
1767
1701
|
* @returns The parsed `IfNode`.
|
|
1768
1702
|
*/
|
|
1769
1703
|
function parseIfControlFlow(cursor, parseNode, token) {
|
|
@@ -1803,9 +1737,9 @@ function parseIfOrElseIf(cursor, parseNode, token) {
|
|
|
1803
1737
|
* Parses a `@switch` directive, consuming the SWITCH token, the CONDITION token,
|
|
1804
1738
|
* the outer BLOCK_OPEN, all `@case` and `@default` branches, and the outer BLOCK_CLOSE.
|
|
1805
1739
|
*
|
|
1806
|
-
* @param cursor Parser cursor positioned at the SWITCH token.
|
|
1807
|
-
* @param parseNode Parser function for recursive child parsing.
|
|
1808
|
-
* @param _token The SWITCH token (
|
|
1740
|
+
* @param cursor - Parser cursor positioned at the SWITCH token.
|
|
1741
|
+
* @param parseNode - Parser function for recursive child parsing.
|
|
1742
|
+
* @param _token - The SWITCH token (consumed for position advancement).
|
|
1809
1743
|
* @returns The parsed `SwitchNode`.
|
|
1810
1744
|
*/
|
|
1811
1745
|
function parseSwitchControlFlow(cursor, parseNode, _token) {
|
|
@@ -1853,9 +1787,9 @@ function parseSwitchControlFlow(cursor, parseNode, _token) {
|
|
|
1853
1787
|
/**
|
|
1854
1788
|
* Parses a TEXT token into a `TextNode`.
|
|
1855
1789
|
*
|
|
1856
|
-
* @param cursor Parser cursor; advanced past the TEXT token.
|
|
1857
|
-
* @param _parseNode
|
|
1858
|
-
* @param token The TEXT token containing the raw text content.
|
|
1790
|
+
* @param cursor - Parser cursor; advanced past the TEXT token.
|
|
1791
|
+
* @param _parseNode - Unused parser function (kept for signature consistency).
|
|
1792
|
+
* @param token - The TEXT token containing the raw text content.
|
|
1859
1793
|
* @returns The parsed `TextNode`.
|
|
1860
1794
|
*/
|
|
1861
1795
|
function parseText(cursor, _parseNode, token) {
|
|
@@ -1896,13 +1830,12 @@ var Parser = class {
|
|
|
1896
1830
|
[TokenType.TAG_OPEN_NAME]: parseElement,
|
|
1897
1831
|
[TokenType.IF]: parseIfControlFlow,
|
|
1898
1832
|
[TokenType.FOR]: parseForControlFlow,
|
|
1899
|
-
[TokenType.SWITCH]: parseSwitchControlFlow
|
|
1900
|
-
[TokenType.CONST_DECLARATION]: parseConstDeclaration
|
|
1833
|
+
[TokenType.SWITCH]: parseSwitchControlFlow
|
|
1901
1834
|
};
|
|
1902
1835
|
/**
|
|
1903
1836
|
* Creates a new Parser instance.
|
|
1904
1837
|
*
|
|
1905
|
-
* @param tokens Array of tokens produced by the Lexer
|
|
1838
|
+
* @param tokens - Array of tokens produced by the Lexer.
|
|
1906
1839
|
*/
|
|
1907
1840
|
constructor(tokens) {
|
|
1908
1841
|
this.tokens = tokens;
|
|
@@ -1911,7 +1844,7 @@ var Parser = class {
|
|
|
1911
1844
|
/**
|
|
1912
1845
|
* Entry point for parsing the token stream into AST nodes.
|
|
1913
1846
|
*
|
|
1914
|
-
* @returns Array of top-level AST nodes
|
|
1847
|
+
* @returns Array of top-level AST nodes.
|
|
1915
1848
|
*/
|
|
1916
1849
|
parse() {
|
|
1917
1850
|
const nodes = new Array();
|
|
@@ -1924,8 +1857,8 @@ var Parser = class {
|
|
|
1924
1857
|
/**
|
|
1925
1858
|
* Parses the next AST node based on the current token.
|
|
1926
1859
|
*
|
|
1927
|
-
* @returns
|
|
1928
|
-
* @throws
|
|
1860
|
+
* @returns The parsed AST node, or `undefined` for EOF.
|
|
1861
|
+
* @throws When no transition function is registered for the current token type.
|
|
1929
1862
|
*/
|
|
1930
1863
|
parseNode() {
|
|
1931
1864
|
const token = this._cursor.peek();
|
|
@@ -1936,6 +1869,47 @@ var Parser = class {
|
|
|
1936
1869
|
}
|
|
1937
1870
|
};
|
|
1938
1871
|
//#endregion
|
|
1872
|
+
//#region ../packages/compiler/src/render-generator/models/compiler-context.model.ts
|
|
1873
|
+
/**
|
|
1874
|
+
* Tracks identifier scope during render code generation.
|
|
1875
|
+
* Each `Context` instance represents one lexical scope (e.g. a `@for` loop body)
|
|
1876
|
+
* and can be chained to a parent context for outer-scope resolution.
|
|
1877
|
+
*/
|
|
1878
|
+
var CompilerContext = class {
|
|
1879
|
+
_identifiers;
|
|
1880
|
+
_parent;
|
|
1881
|
+
/**
|
|
1882
|
+
* Creates a new scope context.
|
|
1883
|
+
*
|
|
1884
|
+
* @param _identifiers - Named identifier bindings declared in this scope.
|
|
1885
|
+
* @param _parent - Optional parent context representing the enclosing scope.
|
|
1886
|
+
*/
|
|
1887
|
+
constructor(_identifiers = new Array(), _parent) {
|
|
1888
|
+
this._identifiers = _identifiers;
|
|
1889
|
+
this._parent = _parent;
|
|
1890
|
+
}
|
|
1891
|
+
/**
|
|
1892
|
+
* Registers a new identifier name in this scope.
|
|
1893
|
+
*
|
|
1894
|
+
* @param name - The identifier name to register.
|
|
1895
|
+
* @throws When an identifier with the same name is already declared in this scope.
|
|
1896
|
+
*/
|
|
1897
|
+
addIdentifier(name) {
|
|
1898
|
+
if (this.hasIdentifier(name)) throw new Error(`Identifier "${name}" is already declared in this scope.`);
|
|
1899
|
+
this._identifiers.push(name);
|
|
1900
|
+
}
|
|
1901
|
+
/**
|
|
1902
|
+
* Returns `true` if an identifier with the given name is declared in this
|
|
1903
|
+
* scope or any of its ancestor scopes.
|
|
1904
|
+
*
|
|
1905
|
+
* @param name - The identifier name to look up.
|
|
1906
|
+
* @returns `true` if the identifier exists in the scope chain, `false` otherwise.
|
|
1907
|
+
*/
|
|
1908
|
+
hasIdentifier(name) {
|
|
1909
|
+
return this._identifiers.includes(name) || (this._parent?.hasIdentifier(name) ?? false);
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1912
|
+
//#endregion
|
|
1939
1913
|
//#region ../packages/compiler/src/render-generator/utils/render-generator.utils.ts
|
|
1940
1914
|
/**
|
|
1941
1915
|
* Complete set of JavaScript global identifiers up to ES2026.
|
|
@@ -2193,37 +2167,44 @@ function needsResolution(node, parent) {
|
|
|
2193
2167
|
return !(ts.isPropertyAccessExpression(parent) && parent.name === node || GLOBAL_IDENTIFIERS.has(node.text));
|
|
2194
2168
|
}
|
|
2195
2169
|
/**
|
|
2196
|
-
* Generates a unique variable name for
|
|
2197
|
-
*
|
|
2198
|
-
*
|
|
2199
|
-
*
|
|
2200
|
-
*
|
|
2201
|
-
*
|
|
2170
|
+
* Generates a unique variable name for a DOM element based on its tag name
|
|
2171
|
+
* and parent node context.
|
|
2172
|
+
*
|
|
2173
|
+
* When the parent is the root node (`this._root`), the identifier is based
|
|
2174
|
+
* solely on the tag name; otherwise the parent name is prepended to ensure
|
|
2175
|
+
* uniqueness within nested structures. Hyphens in tag names are replaced
|
|
2176
|
+
* with underscores to produce a valid JavaScript identifier.
|
|
2177
|
+
*
|
|
2178
|
+
* @param node - The `ElementNode` for which to generate the identifier.
|
|
2179
|
+
* @param parentNode - The variable name of the parent node.
|
|
2180
|
+
* @param index - A numeric suffix to disambiguate sibling elements of the same type.
|
|
2181
|
+
* @returns A unique variable name string for the element.
|
|
2202
2182
|
*/
|
|
2203
2183
|
function getElementIdentifier(node, parentNode, index) {
|
|
2204
2184
|
return (parentNode !== "root" ? `${parentNode}_${node.tagName}${index}` : `${node.tagName}${index}`).replace(/-/g, "_");
|
|
2205
2185
|
}
|
|
2186
|
+
/**
|
|
2187
|
+
* Generates a unique variable name for a text or interpolation node.
|
|
2188
|
+
*
|
|
2189
|
+
* @param parentNode - The variable name of the parent node.
|
|
2190
|
+
* @param index - A numeric suffix to disambiguate sibling text nodes.
|
|
2191
|
+
* @param prefix - Optional prefix to use instead of the default `'text'`.
|
|
2192
|
+
* @returns A unique variable name string for the text node.
|
|
2193
|
+
*/
|
|
2206
2194
|
function getTextIdentifier(parentNode, index, prefix = "text") {
|
|
2207
2195
|
return (parentNode !== "root" ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`).replace(/-/g, "_");
|
|
2208
2196
|
}
|
|
2209
|
-
function getBlockIdentifier(parentNode, index, prefix) {
|
|
2210
|
-
return (parentNode !== "root" ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`).replace(/-/g, "_");
|
|
2211
|
-
}
|
|
2212
|
-
//#endregion
|
|
2213
|
-
//#region ../packages/compiler/src/render-generator/states/process-const-declaration.state.ts
|
|
2214
2197
|
/**
|
|
2215
|
-
* Generates
|
|
2216
|
-
*
|
|
2198
|
+
* Generates a unique variable name for a control-flow block (if, else-if, else,
|
|
2199
|
+
* for, switch, case, or default).
|
|
2217
2200
|
*
|
|
2218
|
-
* @param
|
|
2219
|
-
* @param
|
|
2220
|
-
* @param
|
|
2221
|
-
* @
|
|
2222
|
-
* @returns Array containing the generated const statement string.
|
|
2201
|
+
* @param parentNode - The variable name of the parent node.
|
|
2202
|
+
* @param index - A suffix to disambiguate sibling blocks.
|
|
2203
|
+
* @param prefix - The block type prefix (`'if'`, `'elseIf'`, `'else'`, etc.).
|
|
2204
|
+
* @returns A unique variable name string for the block.
|
|
2223
2205
|
*/
|
|
2224
|
-
function
|
|
2225
|
-
|
|
2226
|
-
return [`declareConst(context, ${node.varName}, () => ${resolveExpression(node.expression, compilerContext)});`];
|
|
2206
|
+
function getBlockIdentifier(parentNode, index, prefix) {
|
|
2207
|
+
return (parentNode !== "root" ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`).replace(/-/g, "_");
|
|
2227
2208
|
}
|
|
2228
2209
|
//#endregion
|
|
2229
2210
|
//#region ../packages/compiler/src/render-generator/states/process-element.state.ts
|
|
@@ -2231,10 +2212,10 @@ function processConstDeclaration(node, _nodeName, _parentNode, compilerContext)
|
|
|
2231
2212
|
* Generates code for an HTML element node: creates the DOM element, sets attributes,
|
|
2232
2213
|
* attaches event listeners, appends it to the parent, and recursively processes children.
|
|
2233
2214
|
*
|
|
2234
|
-
* @param node The `ElementNode` to process.
|
|
2235
|
-
* @param nodeName Variable name to use for the created DOM element.
|
|
2236
|
-
* @param parentNode Variable name of the parent DOM node to append to.
|
|
2237
|
-
* @param compilerContext Current render scope context.
|
|
2215
|
+
* @param node - The `ElementNode` to process.
|
|
2216
|
+
* @param nodeName - Variable name to use for the created DOM element.
|
|
2217
|
+
* @param parentNode - Variable name of the parent DOM node to append to.
|
|
2218
|
+
* @param compilerContext - Current render scope context.
|
|
2238
2219
|
* @returns Array of generated code lines.
|
|
2239
2220
|
*/
|
|
2240
2221
|
function processElement(node, nodeName, parentNode, compilerContext) {
|
|
@@ -2255,15 +2236,11 @@ function processElement(node, nodeName, parentNode, compilerContext) {
|
|
|
2255
2236
|
return code;
|
|
2256
2237
|
}
|
|
2257
2238
|
/**
|
|
2258
|
-
*
|
|
2259
|
-
*
|
|
2260
|
-
* Static (string) attribute values are set once via a direct `setAttribute` call,
|
|
2261
|
-
* while dynamic attribute values are wrapped in an `effect` so the attribute is
|
|
2262
|
-
* re-evaluated and updated whenever its underlying signal dependencies change.
|
|
2263
|
-
* The disposer returned by the `effect` is registered in `unwatchFns` for cleanup.
|
|
2239
|
+
* Maps attribute nodes to their corresponding generated code lines.
|
|
2264
2240
|
*
|
|
2265
|
-
* @param attributes The attribute nodes to map onto the element.
|
|
2266
|
-
* @
|
|
2241
|
+
* @param attributes - The attribute nodes to map onto the element.
|
|
2242
|
+
* @param compilerContext - Current render scope context, used to resolve identifier references.
|
|
2243
|
+
* @returns Array of generated code strings, one per attribute.
|
|
2267
2244
|
*/
|
|
2268
2245
|
function mapAttributes(attributes, compilerContext) {
|
|
2269
2246
|
return attributes?.map(({ name, value }) => {
|
|
@@ -2277,47 +2254,13 @@ function mapAttributes(attributes, compilerContext) {
|
|
|
2277
2254
|
* For each event node an `addEventListener` call is emitted, binding the event
|
|
2278
2255
|
* to the component instance handler and exposing the native event as `$event`.
|
|
2279
2256
|
*
|
|
2280
|
-
* @param events The event nodes to bind to the element.
|
|
2257
|
+
* @param events - The event nodes to bind to the element.
|
|
2281
2258
|
* @returns Array of generated code lines, one per event listener.
|
|
2282
2259
|
*/
|
|
2283
2260
|
function mapEvents(events) {
|
|
2284
2261
|
return events?.map((event) => `{ name: '${event.name}', handler: '${event.handler}' }`);
|
|
2285
2262
|
}
|
|
2286
2263
|
//#endregion
|
|
2287
|
-
//#region ../packages/compiler/src/render-generator/models/compiler-context.model.ts
|
|
2288
|
-
/**
|
|
2289
|
-
* Tracks identifier scope during render code generation.
|
|
2290
|
-
* Each `Context` instance represents one lexical scope (e.g. a `@for` loop body)
|
|
2291
|
-
* and can be chained to a parent context for outer-scope resolution.
|
|
2292
|
-
*/
|
|
2293
|
-
var CompilerContext = class {
|
|
2294
|
-
_identifiers;
|
|
2295
|
-
_parent;
|
|
2296
|
-
/**
|
|
2297
|
-
* Creates a new scope context.
|
|
2298
|
-
*
|
|
2299
|
-
* @param _identifiers List of loop variable names declared in this scope.
|
|
2300
|
-
* @param _parent Optional parent context representing the enclosing scope.
|
|
2301
|
-
*/
|
|
2302
|
-
constructor(_identifiers = new Array(), _parent) {
|
|
2303
|
-
this._identifiers = _identifiers;
|
|
2304
|
-
this._parent = _parent;
|
|
2305
|
-
}
|
|
2306
|
-
addIdentifier(name) {
|
|
2307
|
-
if (this.hasIdentifier(name)) throw new Error(`Identifier "${name}" is already declared in this scope.`);
|
|
2308
|
-
this._identifiers.push(name);
|
|
2309
|
-
}
|
|
2310
|
-
/**
|
|
2311
|
-
* Returns the innermost identifier in the current scope chain, or
|
|
2312
|
-
* delegates to the parent context if none is found in this scope.
|
|
2313
|
-
*
|
|
2314
|
-
* @returns The most recently declared identifier name, or `undefined` if none exists.
|
|
2315
|
-
*/
|
|
2316
|
-
hasIdentifier(name) {
|
|
2317
|
-
return this._identifiers.includes(name) || (this._parent?.hasIdentifier(name) ?? false);
|
|
2318
|
-
}
|
|
2319
|
-
};
|
|
2320
|
-
//#endregion
|
|
2321
2264
|
//#region ../packages/compiler/src/render-generator/states/process-for.state.ts
|
|
2322
2265
|
/**
|
|
2323
2266
|
* Generates code for a `@for` iteration node.
|
|
@@ -2405,12 +2348,13 @@ function resolveImplicit(node, implicit) {
|
|
|
2405
2348
|
//#region ../packages/compiler/src/render-generator/states/process-if.state.ts
|
|
2406
2349
|
/**
|
|
2407
2350
|
* Generates code for an `@if` conditional node.
|
|
2408
|
-
* Emits an `
|
|
2351
|
+
* Emits an `_if(...)` call wrapping the resolved condition blocks.
|
|
2409
2352
|
*
|
|
2410
|
-
* @param node The `IfNode` to process.
|
|
2411
|
-
* @param nodeName Base variable name prefix for child nodes.
|
|
2412
|
-
* @param parentNode Variable name of the parent DOM node.
|
|
2413
|
-
* @
|
|
2353
|
+
* @param node - The `IfNode` to process.
|
|
2354
|
+
* @param nodeName - Base variable name prefix for child nodes.
|
|
2355
|
+
* @param parentNode - Variable name of the parent DOM node.
|
|
2356
|
+
* @param compilerContext - Current render scope context.
|
|
2357
|
+
* @returns An object with the main block code lines and a map of helper functions to register.
|
|
2414
2358
|
*/
|
|
2415
2359
|
function processIf(node, nodeName, parentNode, compilerContext) {
|
|
2416
2360
|
const ifContext = new CompilerContext([], compilerContext);
|
|
@@ -2472,14 +2416,13 @@ function processConsequent(node, nodeName, parentNode, compilerContext) {
|
|
|
2472
2416
|
//#region ../packages/compiler/src/render-generator/states/process-switch.state.ts
|
|
2473
2417
|
/**
|
|
2474
2418
|
* Generates code for a `@switch` node.
|
|
2475
|
-
* Emits a `_switch(
|
|
2476
|
-
* to the reactive `_switch` runtime utility.
|
|
2419
|
+
* Emits a `_switch(...)` call that delegates to the reactive `_switch` runtime utility.
|
|
2477
2420
|
*
|
|
2478
|
-
* @param node The `SwitchNode` to process.
|
|
2479
|
-
* @param nodeName Base variable name prefix for child nodes.
|
|
2480
|
-
* @param parentNode Variable name of the parent DOM node.
|
|
2421
|
+
* @param node - The `SwitchNode` to process.
|
|
2422
|
+
* @param nodeName - Base variable name prefix for child nodes.
|
|
2423
|
+
* @param parentNode - Variable name of the parent DOM node.
|
|
2481
2424
|
* @param compilerContext - Current render scope context.
|
|
2482
|
-
* @returns
|
|
2425
|
+
* @returns An object with the main block code lines and a map of helper functions to register.
|
|
2483
2426
|
*/
|
|
2484
2427
|
function processSwitch(node, nodeName, parentNode, compilerContext) {
|
|
2485
2428
|
const functionsToProcess = /* @__PURE__ */ new Map();
|
|
@@ -2515,15 +2458,17 @@ function processSwitch(node, nodeName, parentNode, compilerContext) {
|
|
|
2515
2458
|
//#region ../packages/compiler/src/render-generator/states/process-text-and-interpolation.state.ts
|
|
2516
2459
|
/**
|
|
2517
2460
|
* Generates code for a text or interpolation node.
|
|
2518
|
-
* Creates a DOM text node with either a JSON-stringified literal or a resolved expression,
|
|
2519
|
-
* then appends it to the parent DOM node.
|
|
2520
2461
|
*
|
|
2521
|
-
*
|
|
2522
|
-
*
|
|
2523
|
-
*
|
|
2462
|
+
* Emits a `_renderLiteralText` call for plain text nodes and a
|
|
2463
|
+
* `_renderText` call for interpolation nodes, both appending a DOM text
|
|
2464
|
+
* node to the parent.
|
|
2465
|
+
*
|
|
2466
|
+
* @param node - A `TextNode` or `InterpolationNode` to process.
|
|
2467
|
+
* @param parentNode - Variable name of the parent DOM node to append to.
|
|
2468
|
+
* @returns Array of generated code lines.
|
|
2524
2469
|
*/
|
|
2525
|
-
function processTextAndInterpolation(node, parentNode) {
|
|
2526
|
-
return [`${node.type === ASTNodeType.Text ? `_renderLiteralText(${parentNode}, context, '${node.value}')` : `_renderText(${parentNode}, context,
|
|
2470
|
+
function processTextAndInterpolation(node, parentNode, compilerContext) {
|
|
2471
|
+
return [`${node.type === ASTNodeType.Text ? `_renderLiteralText(${parentNode}, context, '${node.value}')` : `_renderText(${parentNode}, context, () => ${resolveExpression(node.expression, compilerContext)})`}`];
|
|
2527
2472
|
}
|
|
2528
2473
|
//#endregion
|
|
2529
2474
|
//#region ../packages/compiler/src/render-generator/render-generator.ts
|
|
@@ -2531,8 +2476,10 @@ var nodeToProcess = /* @__PURE__ */ new Map();
|
|
|
2531
2476
|
/**
|
|
2532
2477
|
* Generates the TypeScript body of a render function from an AST.
|
|
2533
2478
|
*
|
|
2534
|
-
* @param ast Top-level AST nodes produced by the Parser
|
|
2535
|
-
* @
|
|
2479
|
+
* @param ast - Top-level AST nodes produced by the Parser.
|
|
2480
|
+
* @param cssVariableName - Optional name of the CSS variable to inject into
|
|
2481
|
+
* the generated `adoptedStyleSheets` assignment.
|
|
2482
|
+
* @returns A string containing the render function body.
|
|
2536
2483
|
*/
|
|
2537
2484
|
function generateRenderFunction(ast, cssVariableName) {
|
|
2538
2485
|
nodeToProcess.clear();
|
|
@@ -2559,7 +2506,7 @@ function generateRenderFunction(ast, cssVariableName) {
|
|
|
2559
2506
|
function processNode(node, nodeName, parentNode, compilerContext) {
|
|
2560
2507
|
switch (node.type) {
|
|
2561
2508
|
case ASTNodeType.Text:
|
|
2562
|
-
case ASTNodeType.Interpolation: return processTextAndInterpolation(node, parentNode);
|
|
2509
|
+
case ASTNodeType.Interpolation: return processTextAndInterpolation(node, parentNode, compilerContext);
|
|
2563
2510
|
case ASTNodeType.Element: return processElement(node, getElementIdentifier(node, parentNode, nodeName), parentNode, compilerContext);
|
|
2564
2511
|
case ASTNodeType.If:
|
|
2565
2512
|
const conditionalBlockData = processIf(node, nodeName, parentNode, compilerContext);
|
|
@@ -2582,12 +2529,24 @@ function processNode(node, nodeName, parentNode, compilerContext) {
|
|
|
2582
2529
|
args: fnBody.args
|
|
2583
2530
|
}));
|
|
2584
2531
|
return switchBlockData.mainBlock;
|
|
2585
|
-
case ASTNodeType.ConstDeclaration: return processConstDeclaration(node, nodeName, parentNode, compilerContext);
|
|
2586
2532
|
default: return [];
|
|
2587
2533
|
}
|
|
2588
2534
|
}
|
|
2589
2535
|
//#endregion
|
|
2590
2536
|
//#region ../packages/compiler/src/compile.ts
|
|
2537
|
+
/**
|
|
2538
|
+
* Compiles a template string into a TypeScript render function body.
|
|
2539
|
+
*
|
|
2540
|
+
* Runs the three-stage pipeline:
|
|
2541
|
+
* 1. **Lexer** — tokenises the raw template text.
|
|
2542
|
+
* 2. **Parser** — transforms the token stream into an AST.
|
|
2543
|
+
* 3. **Render generator** — emits TypeScript source lines from the AST.
|
|
2544
|
+
*
|
|
2545
|
+
* @param input - The raw HTML-like template source to compile.
|
|
2546
|
+
* @param cssVariableName - Optional name of the CSS variable to inject
|
|
2547
|
+
* into the generated `adoptedStyleSheets` assignment.
|
|
2548
|
+
* @returns A string containing the compiled TypeScript render method body.
|
|
2549
|
+
*/
|
|
2591
2550
|
function compile(input, cssVariableName) {
|
|
2592
2551
|
return generateRenderFunction(new Parser(new Lexer(input).tokenize()).parse(), cssVariableName);
|
|
2593
2552
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xaendar/compiler",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.15",
|
|
4
4
|
"description": "A library for transpiling Xaendar Templates into JavaScript code",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@xaendar/common": "0.6.
|
|
20
|
-
"@xaendar/types": "0.6.
|
|
19
|
+
"@xaendar/common": "0.6.15",
|
|
20
|
+
"@xaendar/types": "0.6.15",
|
|
21
21
|
"typescript": "^6.0.3"
|
|
22
22
|
}
|
|
23
23
|
}
|