@xaendar/compiler 0.6.4 → 0.6.6
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.js +193 -119
- package/package.json +3 -3
|
@@ -55,6 +55,10 @@ var LexerState = /* @__PURE__ */ function(LexerState) {
|
|
|
55
55
|
*/
|
|
56
56
|
LexerState["FLOW_CONTROL_BLOCK"] = "flow-control-block";
|
|
57
57
|
/**
|
|
58
|
+
* Consuming an attribute literal value
|
|
59
|
+
*/
|
|
60
|
+
LexerState["ATTRIBUTE_VALUE"] = "attribute-value";
|
|
61
|
+
/**
|
|
58
62
|
* Dispatching between an expression or literal interpolation after `{`.
|
|
59
63
|
*/
|
|
60
64
|
LexerState["INTERPOLATION"] = "interpolation";
|
|
@@ -99,72 +103,100 @@ var TokenType = /* @__PURE__ */ function(TokenType) {
|
|
|
99
103
|
*/
|
|
100
104
|
TokenType[TokenType["TAG_CLOSE_NAME"] = 4] = "TAG_CLOSE_NAME";
|
|
101
105
|
/**
|
|
102
|
-
* An HTML attribute
|
|
106
|
+
* An HTML attribute
|
|
103
107
|
*/
|
|
104
108
|
TokenType[TokenType["ATTRIBUTE"] = 5] = "ATTRIBUTE";
|
|
105
109
|
/**
|
|
110
|
+
* An HTML attribute literal value
|
|
111
|
+
*/
|
|
112
|
+
TokenType[TokenType["ATTRIBUTE_VALUE"] = 6] = "ATTRIBUTE_VALUE";
|
|
113
|
+
/**
|
|
106
114
|
* A DOM event binding declared with `@eventName=handler`.
|
|
107
115
|
*/
|
|
108
|
-
TokenType[TokenType["EVENT"] =
|
|
116
|
+
TokenType[TokenType["EVENT"] = 7] = "EVENT";
|
|
109
117
|
/**
|
|
110
118
|
* A template-literal interpolation string enclosed in `` {`...`} ``.
|
|
111
119
|
*/
|
|
112
|
-
TokenType[TokenType["INTERPOLATION_LITERAL"] =
|
|
120
|
+
TokenType[TokenType["INTERPOLATION_LITERAL"] = 8] = "INTERPOLATION_LITERAL";
|
|
113
121
|
/**
|
|
114
122
|
* A JavaScript expression interpolation enclosed in `{ }`.
|
|
115
123
|
*/
|
|
116
|
-
TokenType[TokenType["INTERPOLATION_EXPRESSION"] =
|
|
124
|
+
TokenType[TokenType["INTERPOLATION_EXPRESSION"] = 9] = "INTERPOLATION_EXPRESSION";
|
|
117
125
|
/**
|
|
118
126
|
* A `@const name = expression;` template-level constant declaration.
|
|
119
127
|
*/
|
|
120
|
-
TokenType[TokenType["CONST_DECLARATION"] =
|
|
128
|
+
TokenType[TokenType["CONST_DECLARATION"] = 10] = "CONST_DECLARATION";
|
|
121
129
|
/**
|
|
122
130
|
* Opening keyword of an `@if` directive.
|
|
123
131
|
*/
|
|
124
|
-
TokenType[TokenType["IF"] =
|
|
132
|
+
TokenType[TokenType["IF"] = 11] = "IF";
|
|
125
133
|
/**
|
|
126
134
|
* Opening keyword of a `@for` directive.
|
|
127
135
|
*/
|
|
128
|
-
TokenType[TokenType["FOR"] =
|
|
136
|
+
TokenType[TokenType["FOR"] = 12] = "FOR";
|
|
129
137
|
/**
|
|
130
138
|
* Opening keyword of an `@else` branch.
|
|
131
139
|
*/
|
|
132
|
-
TokenType[TokenType["ELSE"] =
|
|
140
|
+
TokenType[TokenType["ELSE"] = 13] = "ELSE";
|
|
133
141
|
/**
|
|
134
142
|
* Opening keyword of an `@else if` branch.
|
|
135
143
|
*/
|
|
136
|
-
TokenType[TokenType["ELSE_IF"] =
|
|
144
|
+
TokenType[TokenType["ELSE_IF"] = 14] = "ELSE_IF";
|
|
137
145
|
/**
|
|
138
146
|
* Opening keyword of a `@switch` directive.
|
|
139
147
|
*/
|
|
140
|
-
TokenType[TokenType["SWITCH"] =
|
|
148
|
+
TokenType[TokenType["SWITCH"] = 15] = "SWITCH";
|
|
141
149
|
/**
|
|
142
150
|
* Opening keyword of a `@case` branch.
|
|
143
151
|
*/
|
|
144
|
-
TokenType[TokenType["CASE"] =
|
|
152
|
+
TokenType[TokenType["CASE"] = 16] = "CASE";
|
|
145
153
|
/**
|
|
146
154
|
* Opening keyword of a `@default` branch.
|
|
147
155
|
*/
|
|
148
|
-
TokenType[TokenType["DEFAULT"] =
|
|
156
|
+
TokenType[TokenType["DEFAULT"] = 17] = "DEFAULT";
|
|
149
157
|
/**
|
|
150
158
|
* The condition expression `(...)` associated with a flow-control directive.
|
|
151
159
|
*/
|
|
152
|
-
TokenType[TokenType["CONDITION"] =
|
|
160
|
+
TokenType[TokenType["CONDITION"] = 18] = "CONDITION";
|
|
153
161
|
/**
|
|
154
162
|
* The opening `{` of a flow-control block body.
|
|
155
163
|
*/
|
|
156
|
-
TokenType[TokenType["BLOCK_OPEN"] =
|
|
164
|
+
TokenType[TokenType["BLOCK_OPEN"] = 19] = "BLOCK_OPEN";
|
|
157
165
|
/**
|
|
158
166
|
* The closing `}` of a flow-control block body.
|
|
159
167
|
*/
|
|
160
|
-
TokenType[TokenType["BLOCK_CLOSE"] =
|
|
168
|
+
TokenType[TokenType["BLOCK_CLOSE"] = 20] = "BLOCK_CLOSE";
|
|
161
169
|
/**
|
|
162
170
|
* Sentinel token emitted when the end of the input is reached.
|
|
163
171
|
*/
|
|
164
|
-
TokenType[TokenType["EOF"] =
|
|
172
|
+
TokenType[TokenType["EOF"] = 21] = "EOF";
|
|
165
173
|
return TokenType;
|
|
166
174
|
}({});
|
|
167
175
|
//#endregion
|
|
176
|
+
//#region ../packages/compiler/src/lexer/states/attribute-value.state.ts
|
|
177
|
+
function consumeAttributeValue(cursor, _context) {
|
|
178
|
+
let read = true;
|
|
179
|
+
let value = "";
|
|
180
|
+
let retVal;
|
|
181
|
+
while (read) switch (cursor.peek()) {
|
|
182
|
+
case 34:
|
|
183
|
+
cursor.advance();
|
|
184
|
+
read = false;
|
|
185
|
+
retVal = {
|
|
186
|
+
state: LexerState.TAG_BODY,
|
|
187
|
+
tokens: [{
|
|
188
|
+
type: TokenType.ATTRIBUTE_VALUE,
|
|
189
|
+
parts: [value]
|
|
190
|
+
}]
|
|
191
|
+
};
|
|
192
|
+
break;
|
|
193
|
+
default:
|
|
194
|
+
cursor.advance();
|
|
195
|
+
value = `${value}${cursor.currentChar.value}`;
|
|
196
|
+
}
|
|
197
|
+
return retVal;
|
|
198
|
+
}
|
|
199
|
+
//#endregion
|
|
168
200
|
//#region ../packages/compiler/src/lexer/states/attribute.state.ts
|
|
169
201
|
/**
|
|
170
202
|
* Consumes an attribute name and optional value from the current position,
|
|
@@ -181,8 +213,8 @@ function consumeAttribute(cursor, _context) {
|
|
|
181
213
|
let retVal;
|
|
182
214
|
while (read) switch (cursor.peek()) {
|
|
183
215
|
case 32:
|
|
184
|
-
|
|
185
|
-
|
|
216
|
+
cursor.advance();
|
|
217
|
+
read = false;
|
|
186
218
|
retVal = {
|
|
187
219
|
state: LexerState.TAG_BODY,
|
|
188
220
|
tokens: [{
|
|
@@ -190,18 +222,23 @@ function consumeAttribute(cursor, _context) {
|
|
|
190
222
|
parts: [attribute]
|
|
191
223
|
}]
|
|
192
224
|
};
|
|
193
|
-
read = false;
|
|
194
225
|
break;
|
|
195
|
-
case
|
|
226
|
+
case 61:
|
|
227
|
+
cursor.advance();
|
|
228
|
+
if (cursor.peek() !== 34) {
|
|
229
|
+
const { row, column } = cursor.position;
|
|
230
|
+
throw new Error(`Attribute value must start with double quotes '"'.Row ${row} Col ${column}`);
|
|
231
|
+
}
|
|
232
|
+
cursor.advance();
|
|
233
|
+
read = false;
|
|
196
234
|
retVal = {
|
|
197
|
-
state: LexerState.INTERPOLATION,
|
|
235
|
+
state: cursor.peek() === 123 ? LexerState.INTERPOLATION : LexerState.ATTRIBUTE_VALUE,
|
|
236
|
+
pushState: true,
|
|
198
237
|
tokens: [{
|
|
199
238
|
type: TokenType.ATTRIBUTE,
|
|
200
239
|
parts: [attribute]
|
|
201
|
-
}]
|
|
202
|
-
pushState: true
|
|
240
|
+
}]
|
|
203
241
|
};
|
|
204
|
-
read = false;
|
|
205
242
|
break;
|
|
206
243
|
default:
|
|
207
244
|
cursor.advance();
|
|
@@ -319,6 +356,27 @@ function consumeConstDeclaration(cursor, _context) {
|
|
|
319
356
|
return retVal;
|
|
320
357
|
}
|
|
321
358
|
//#endregion
|
|
359
|
+
//#region ../packages/compiler/src/lexer/states/default-flow-control-condition.state.ts
|
|
360
|
+
/**
|
|
361
|
+
* Consumes the condition expression `(...)` of a flow-control directive,
|
|
362
|
+
* handling nested parentheses correctly. Emits a CONDITION token with the
|
|
363
|
+
* raw expression string and transitions to FLOW_CONTROL_BLOCK.
|
|
364
|
+
*
|
|
365
|
+
* @param cursor The lexer cursor positioned at the opening `(`.
|
|
366
|
+
* @param _context Unused lexer context.
|
|
367
|
+
* @returns Transition result with the CONDITION token and the FLOW_CONTROL_BLOCK state.
|
|
368
|
+
*/
|
|
369
|
+
function consumeDefaultFlowControlCondition(cursor, _context) {
|
|
370
|
+
return {
|
|
371
|
+
state: LexerState.FLOW_CONTROL_BLOCK,
|
|
372
|
+
tokens: [{
|
|
373
|
+
type: TokenType.CONDITION,
|
|
374
|
+
parts: [consumeFlowControlCondition(cursor, _context)]
|
|
375
|
+
}],
|
|
376
|
+
popState: true
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
//#endregion
|
|
322
380
|
//#region ../packages/compiler/src/lexer/states/event.state.ts
|
|
323
381
|
/**
|
|
324
382
|
* Consumes a DOM event binding starting with `@` and reads until a delimiter
|
|
@@ -337,7 +395,6 @@ function consumeEvent(cursor, _context) {
|
|
|
337
395
|
case 32:
|
|
338
396
|
case 47:
|
|
339
397
|
case 62:
|
|
340
|
-
if (!event.includes("=")) event = `${event}=on${event[0].toUpperCase()}${event.slice(1)}($event)`;
|
|
341
398
|
retVal = {
|
|
342
399
|
state: LexerState.TAG_BODY,
|
|
343
400
|
tokens: [{
|
|
@@ -354,50 +411,6 @@ function consumeEvent(cursor, _context) {
|
|
|
354
411
|
return retVal;
|
|
355
412
|
}
|
|
356
413
|
//#endregion
|
|
357
|
-
//#region ../packages/compiler/src/lexer/states/flow-control-block.state.ts
|
|
358
|
-
/**
|
|
359
|
-
* Consumes the opening `{` of a flow control block body,
|
|
360
|
-
* skipping any leading whitespace before it.
|
|
361
|
-
*
|
|
362
|
-
* Emits a BLOCK_OPEN token and transitions to TEXT,
|
|
363
|
-
* pushing FLOW_CONTROL_BLOCK onto the state stack.
|
|
364
|
-
* This allows consumeText to later recognise the matching `}` as a BLOCK_CLOSE
|
|
365
|
-
* rather than as an interpolation boundary.
|
|
366
|
-
*
|
|
367
|
-
* Used by: @if, @for, @switch, @case, @else, @default
|
|
368
|
-
*/
|
|
369
|
-
function consumeFlowControlBlock(cursor, _context) {
|
|
370
|
-
cursor.skipSpaces();
|
|
371
|
-
if (cursor.peek() !== 123) throw new Error(`Expected '{' but got '${String.fromCharCode(cursor.peek())}' at row ${cursor.position.row}, col ${cursor.position.column}`);
|
|
372
|
-
cursor.advance();
|
|
373
|
-
return {
|
|
374
|
-
state: LexerState.TEXT,
|
|
375
|
-
tokens: [{ type: TokenType.BLOCK_OPEN }],
|
|
376
|
-
pushState: true
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
//#endregion
|
|
380
|
-
//#region ../packages/compiler/src/lexer/states/default-flow-control-condition.state.ts
|
|
381
|
-
/**
|
|
382
|
-
* Consumes the condition expression `(...)` of a flow-control directive,
|
|
383
|
-
* handling nested parentheses correctly. Emits a CONDITION token with the
|
|
384
|
-
* raw expression string and transitions to FLOW_CONTROL_BLOCK.
|
|
385
|
-
*
|
|
386
|
-
* @param cursor The lexer cursor positioned at the opening `(`.
|
|
387
|
-
* @param _context Unused lexer context.
|
|
388
|
-
* @returns Transition result with the CONDITION token and the FLOW_CONTROL_BLOCK state.
|
|
389
|
-
*/
|
|
390
|
-
function consumeDefaultFlowControlCondition(cursor, _context) {
|
|
391
|
-
return {
|
|
392
|
-
state: LexerState.FLOW_CONTROL_BLOCK,
|
|
393
|
-
tokens: [{
|
|
394
|
-
type: TokenType.CONDITION,
|
|
395
|
-
parts: [consumeFlowControlCondition(cursor, _context)]
|
|
396
|
-
}],
|
|
397
|
-
popState: true
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
//#endregion
|
|
401
414
|
//#region ../packages/compiler/src/lexer/states/flow-control.ts
|
|
402
415
|
/**
|
|
403
416
|
* Dispatches on a `@keyword` to determine which flow-control directive begins here.
|
|
@@ -465,6 +478,29 @@ function consumeFlowControl(cursor, _context) {
|
|
|
465
478
|
return retVal;
|
|
466
479
|
}
|
|
467
480
|
//#endregion
|
|
481
|
+
//#region ../packages/compiler/src/lexer/states/flow-control-block.state.ts
|
|
482
|
+
/**
|
|
483
|
+
* Consumes the opening `{` of a flow control block body,
|
|
484
|
+
* skipping any leading whitespace before it.
|
|
485
|
+
*
|
|
486
|
+
* Emits a BLOCK_OPEN token and transitions to TEXT,
|
|
487
|
+
* pushing FLOW_CONTROL_BLOCK onto the state stack.
|
|
488
|
+
* This allows consumeText to later recognise the matching `}` as a BLOCK_CLOSE
|
|
489
|
+
* rather than as an interpolation boundary.
|
|
490
|
+
*
|
|
491
|
+
* Used by: @if, @for, @switch, @case, @else, @default
|
|
492
|
+
*/
|
|
493
|
+
function consumeFlowControlBlock(cursor, _context) {
|
|
494
|
+
cursor.skipSpaces();
|
|
495
|
+
if (cursor.peek() !== 123) throw new Error(`Expected '{' but got '${String.fromCharCode(cursor.peek())}' at row ${cursor.position.row}, col ${cursor.position.column}`);
|
|
496
|
+
cursor.advance();
|
|
497
|
+
return {
|
|
498
|
+
state: LexerState.TEXT,
|
|
499
|
+
tokens: [{ type: TokenType.BLOCK_OPEN }],
|
|
500
|
+
pushState: true
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
//#endregion
|
|
468
504
|
//#region ../packages/compiler/src/lexer/states/interpolation-expression.state.ts
|
|
469
505
|
/**
|
|
470
506
|
* Consumes a JavaScript expression interpolation `{ expression }`, tracking nested
|
|
@@ -494,8 +530,11 @@ function consumeInterpolationExpression(cursor, context) {
|
|
|
494
530
|
let state;
|
|
495
531
|
switch (previousState) {
|
|
496
532
|
case LexerState.ATTRIBUTE:
|
|
497
|
-
|
|
498
|
-
|
|
533
|
+
if (cursor.peek() !== 34) {
|
|
534
|
+
const { row, column } = cursor.position;
|
|
535
|
+
throw new Error(`Interpolation must be end with double quotes '"' Found ${String.fromCharCode(cursor.peek())}. \nRow ${row} Col ${column}`);
|
|
536
|
+
}
|
|
537
|
+
cursor.advance();
|
|
499
538
|
state = LexerState.TAG_BODY;
|
|
500
539
|
break;
|
|
501
540
|
case LexerState.TEXT: state = LexerState.TEXT;
|
|
@@ -1014,6 +1053,7 @@ var Lexer = class {
|
|
|
1014
1053
|
[LexerState.TAG_OPEN_END]: consumeTagOpenEnd,
|
|
1015
1054
|
[LexerState.TAG_CLOSE]: consumeTagClose,
|
|
1016
1055
|
[LexerState.ATTRIBUTE]: consumeAttribute,
|
|
1056
|
+
[LexerState.ATTRIBUTE_VALUE]: consumeAttributeValue,
|
|
1017
1057
|
[LexerState.FLOW_CONTROL]: consumeFlowControl,
|
|
1018
1058
|
[LexerState.FLOW_CONTROL_CONDITION]: consumeDefaultFlowControlCondition,
|
|
1019
1059
|
[LexerState.CASE_FLOW_CONTROL_CONDITION]: consumeCaseFlowControlCondition,
|
|
@@ -1415,22 +1455,21 @@ function parseInterpolation(cursor, _parseNode, token) {
|
|
|
1415
1455
|
*/
|
|
1416
1456
|
function parseAttribute(cursor, parseNode, token) {
|
|
1417
1457
|
cursor.advance();
|
|
1418
|
-
const
|
|
1419
|
-
|
|
1420
|
-
|
|
1458
|
+
const name = token.parts[0];
|
|
1459
|
+
const nextToken = cursor.peek();
|
|
1460
|
+
if (nextToken.type === TokenType.ATTRIBUTE || nextToken.type === TokenType.TAG_CLOSE_NAME || nextToken.type === TokenType.EVENT) return {
|
|
1461
|
+
name,
|
|
1421
1462
|
value: "true"
|
|
1422
1463
|
};
|
|
1423
|
-
const [name, value] = raw.split("=");
|
|
1424
|
-
if (!name) throw new Error(`[Parser] Attribute name missing in: ${raw}`);
|
|
1425
|
-
const nextToken = cursor.peek();
|
|
1426
1464
|
if (nextToken.type === TokenType.INTERPOLATION_EXPRESSION || nextToken.type === TokenType.INTERPOLATION_LITERAL) return {
|
|
1427
1465
|
name,
|
|
1428
1466
|
value: parseInterpolation(cursor, parseNode, nextToken)
|
|
1429
1467
|
};
|
|
1430
|
-
if (
|
|
1468
|
+
if (nextToken.type !== TokenType.ATTRIBUTE_VALUE) throw new Error(`[Parser] Attribute value missing for ${name} in: ${name}`);
|
|
1469
|
+
cursor.advance();
|
|
1431
1470
|
return {
|
|
1432
1471
|
name,
|
|
1433
|
-
value:
|
|
1472
|
+
value: nextToken.parts[0]
|
|
1434
1473
|
};
|
|
1435
1474
|
}
|
|
1436
1475
|
//#endregion
|
|
@@ -2189,6 +2228,9 @@ function getElementIdentifier(node, parentNode, index) {
|
|
|
2189
2228
|
function getTextIdentifier(parentNode, index, prefix = "text") {
|
|
2190
2229
|
return (parentNode !== "this._root" ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`).replace(/-/g, "_");
|
|
2191
2230
|
}
|
|
2231
|
+
function getBlockIdentifier(parentNode, index, prefix) {
|
|
2232
|
+
return (parentNode !== "this._root" ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`).replace(/-/g, "_");
|
|
2233
|
+
}
|
|
2192
2234
|
//#endregion
|
|
2193
2235
|
//#region ../packages/compiler/src/render-generator/states/process-const-declaration.state.ts
|
|
2194
2236
|
/**
|
|
@@ -2242,10 +2284,19 @@ function processElement(node, nodeName, parentNode, context) {
|
|
|
2242
2284
|
* @returns Array of generated code lines, one per attribute.
|
|
2243
2285
|
*/
|
|
2244
2286
|
function mapAttributes(attributes, nodeName, context) {
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2287
|
+
const literalsAttributes = new Array();
|
|
2288
|
+
const bindingsAttributes = new Array();
|
|
2289
|
+
attributes?.forEach(({ name, value }) => typeof value === "string" ? literalsAttributes.push({
|
|
2290
|
+
name,
|
|
2291
|
+
value
|
|
2292
|
+
}) : bindingsAttributes.push({
|
|
2293
|
+
name,
|
|
2294
|
+
value
|
|
2295
|
+
}));
|
|
2296
|
+
const mappedAttributes = literalsAttributes.map((attr) => `${nodeName}.setAttribute("${attr.name}", "${attr.value}");`);
|
|
2297
|
+
const mappedBindingAttributes = bindingsAttributes.map((attr) => `effect(() => ${nodeName}.setAttribute("${attr.name}", ${resolveExpression(attr.value.expression, context)})),`);
|
|
2298
|
+
if (mappedBindingAttributes.length) mappedAttributes.push(`unwatchFns.push(`, ...indent(mappedBindingAttributes), `);`);
|
|
2299
|
+
return mappedAttributes;
|
|
2249
2300
|
}
|
|
2250
2301
|
/**
|
|
2251
2302
|
* Generates code that attaches event listeners to a DOM element.
|
|
@@ -2313,19 +2364,12 @@ function processFor(node, nodeName, parentNode, parentContext) {
|
|
|
2313
2364
|
evenName,
|
|
2314
2365
|
oddName
|
|
2315
2366
|
], parentContext);
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
`const ${indexName} = ${counterName};`,
|
|
2320
|
-
`const ${firstName} = ${counterName} === 0;`,
|
|
2321
|
-
`const ${lastName} = ${counterName} === ${itemsName}.length - 1;`,
|
|
2322
|
-
`const ${evenName} = ${counterName} % 2 === 0;`,
|
|
2323
|
-
`const ${oddName} = !${evenName};`,
|
|
2324
|
-
...node.children.flatMap((child, i) => processNode(child, `${nodeName}_${i}`, parentNode, forContext))
|
|
2325
|
-
],
|
|
2367
|
+
const forKey = getBlockIdentifier(parentNode, nodeName, "for");
|
|
2368
|
+
functionsToProcess.set(forKey, {
|
|
2369
|
+
code: [`const { ${node.itemAlias}, ${indexName}, ${firstName}, ${lastName}, ${evenName}, ${oddName} } = _iterationVariables(${itemsName}, ${counterName});`, ...node.children.flatMap((child, i) => processNode(child, `${nodeName}_${i}`, parentNode, forContext))],
|
|
2326
2370
|
args: [itemsName, counterName]
|
|
2327
2371
|
});
|
|
2328
|
-
mainBlock.push(
|
|
2372
|
+
mainBlock.push(`_for(unwatchFns, () => ${iterableExpr}, this.${forKey}.bind(this));`);
|
|
2329
2373
|
return {
|
|
2330
2374
|
mainBlock,
|
|
2331
2375
|
fns: functionsToProcess
|
|
@@ -2362,31 +2406,42 @@ function processIf(node, nodeName, parentNode, context) {
|
|
|
2362
2406
|
const ifContext = new Context([], context);
|
|
2363
2407
|
const functionsToProcess = /* @__PURE__ */ new Map();
|
|
2364
2408
|
const mainBlock = new Array();
|
|
2365
|
-
const ifKey =
|
|
2366
|
-
mainBlock.push(
|
|
2409
|
+
const ifKey = getBlockIdentifier(parentNode, nodeName, "if");
|
|
2410
|
+
mainBlock.push({
|
|
2411
|
+
condition: resolveExpression(node.conditionNode, context),
|
|
2412
|
+
block: `this.${ifKey}.bind(this)`
|
|
2413
|
+
});
|
|
2367
2414
|
functionsToProcess.set(ifKey, processConsequent(node, nodeName, parentNode, ifContext));
|
|
2368
2415
|
let alt = node.alternate;
|
|
2369
2416
|
let index = 0;
|
|
2370
2417
|
while (alt?.type === ASTNodeType.ElseIf) {
|
|
2371
2418
|
const elseIfContext = new Context([], context);
|
|
2372
|
-
const keyElseIf =
|
|
2373
|
-
|
|
2374
|
-
mainBlock.push(
|
|
2419
|
+
const keyElseIf = getBlockIdentifier(parentNode, `${nodeName}_${index}`, "elseIf");
|
|
2420
|
+
const conditionNode = alt.conditionNode;
|
|
2421
|
+
mainBlock.push({
|
|
2422
|
+
condition: resolveExpression(conditionNode, context),
|
|
2423
|
+
block: `this.${keyElseIf}.bind(this)`
|
|
2424
|
+
});
|
|
2375
2425
|
functionsToProcess.set(keyElseIf, processConsequent(alt, nodeName, parentNode, elseIfContext));
|
|
2376
2426
|
alt = alt.alternate;
|
|
2377
2427
|
}
|
|
2378
2428
|
if (alt) {
|
|
2379
2429
|
const elseContext = new Context([], context);
|
|
2380
|
-
const keyElse =
|
|
2381
|
-
mainBlock
|
|
2382
|
-
mainBlock.push(...indent(`checkAndUpdateState(${++index}, this.${keyElse}.bind(this));`), "}");
|
|
2430
|
+
const keyElse = getBlockIdentifier(parentNode, nodeName, "else");
|
|
2431
|
+
mainBlock.push({ block: `this.${keyElse}.bind(this)` });
|
|
2383
2432
|
functionsToProcess.set(keyElse, processConsequent(alt, nodeName, parentNode, elseContext));
|
|
2384
2433
|
}
|
|
2385
2434
|
return {
|
|
2386
2435
|
mainBlock: [
|
|
2387
|
-
"(
|
|
2388
|
-
...indent(
|
|
2389
|
-
|
|
2436
|
+
"_if(unwatchFns, [",
|
|
2437
|
+
...indent(mainBlock.map(({ condition, block }) => {
|
|
2438
|
+
return [
|
|
2439
|
+
"{",
|
|
2440
|
+
...indent(condition ? [`condition: ${condition.toString()},`, `block: ${block.toString()}`] : [`block: ${block.toString()}`]),
|
|
2441
|
+
"},"
|
|
2442
|
+
];
|
|
2443
|
+
}).flat()),
|
|
2444
|
+
"])"
|
|
2390
2445
|
],
|
|
2391
2446
|
fns: functionsToProcess
|
|
2392
2447
|
};
|
|
@@ -2398,31 +2453,38 @@ function processConsequent(node, nodeName, parentNode, context) {
|
|
|
2398
2453
|
//#region ../packages/compiler/src/render-generator/states/process-switch.state.ts
|
|
2399
2454
|
/**
|
|
2400
2455
|
* Generates code for a `@switch` node.
|
|
2401
|
-
* Emits a `
|
|
2456
|
+
* Emits a `_switch(unwatchFns, () => expression, [...])` call that delegates
|
|
2457
|
+
* to the reactive `_switch` runtime utility.
|
|
2402
2458
|
*
|
|
2403
2459
|
* @param node The `SwitchNode` to process.
|
|
2404
2460
|
* @param nodeName Base variable name prefix for child nodes.
|
|
2405
2461
|
* @param parentNode Variable name of the parent DOM node.
|
|
2406
2462
|
* @param context Current render scope context.
|
|
2407
|
-
* @param processNode Recursive node processor function.
|
|
2408
2463
|
* @returns Array of generated code lines.
|
|
2409
2464
|
*/
|
|
2410
2465
|
function processSwitch(node, nodeName, parentNode, context) {
|
|
2411
|
-
const mainBlock = new Array();
|
|
2412
2466
|
const functionsToProcess = /* @__PURE__ */ new Map();
|
|
2413
|
-
|
|
2467
|
+
const blocks = new Array();
|
|
2414
2468
|
node.cases.forEach((caseNode, i) => {
|
|
2415
2469
|
const caseContext = new Context([], context);
|
|
2416
|
-
const caseName = caseNode.condition ?
|
|
2470
|
+
const caseName = caseNode.condition ? getBlockIdentifier(parentNode, `${nodeName}_${i}`, "case") : getBlockIdentifier(parentNode, nodeName, "default");
|
|
2417
2471
|
functionsToProcess.set(caseName, caseNode.children.map((child, i) => processNode(child, `${nodeName}_${i}_${i}`, parentNode, caseContext)).flat());
|
|
2418
|
-
|
|
2472
|
+
blocks.push({
|
|
2473
|
+
condition: caseNode.condition,
|
|
2474
|
+
block: `this.${caseName}.bind(this)`
|
|
2475
|
+
});
|
|
2419
2476
|
});
|
|
2420
|
-
mainBlock.push("}");
|
|
2421
2477
|
return {
|
|
2422
2478
|
mainBlock: [
|
|
2423
|
-
|
|
2424
|
-
...indent(
|
|
2425
|
-
|
|
2479
|
+
`_switch(unwatchFns, () => ${resolveExpression(node.expression, context)}, [`,
|
|
2480
|
+
...indent(blocks.map(({ condition, block }) => {
|
|
2481
|
+
return [
|
|
2482
|
+
"{",
|
|
2483
|
+
...indent(condition ? [`condition: [${condition.join(", ")}],`, `block: ${block}`] : [`condition: null,`, `block: ${block}`]),
|
|
2484
|
+
"},"
|
|
2485
|
+
];
|
|
2486
|
+
}).flat()),
|
|
2487
|
+
"])"
|
|
2426
2488
|
],
|
|
2427
2489
|
fns: functionsToProcess
|
|
2428
2490
|
};
|
|
@@ -2461,12 +2523,24 @@ function generateRenderFunction(ast, cssVariableName) {
|
|
|
2461
2523
|
nodeToProcess.clear();
|
|
2462
2524
|
const context = new Context();
|
|
2463
2525
|
const renderFunctions = ["_render() {"];
|
|
2464
|
-
if (cssVariableName) renderFunctions.push(
|
|
2465
|
-
renderFunctions.push(...indent(
|
|
2526
|
+
if (cssVariableName) renderFunctions.push(indent(`this._root.adoptedStyleSheets = [${cssVariableName}];`));
|
|
2527
|
+
renderFunctions.push(...indent([
|
|
2528
|
+
"let unwatchFns = [];",
|
|
2529
|
+
...ast.map((node, i) => [...processNode(node, i.toString(), ROOT_NODE, context)]).flat(),
|
|
2530
|
+
"return unwatchFns;"
|
|
2531
|
+
]), "}");
|
|
2466
2532
|
while (nodeToProcess.size > 0) {
|
|
2467
2533
|
const [key, fnData] = nodeToProcess.entries().next().value;
|
|
2468
|
-
if ("args" in fnData) renderFunctions.push(`${key}(${fnData.args.join(", ")}) {`, ...indent(
|
|
2469
|
-
|
|
2534
|
+
if ("args" in fnData) renderFunctions.push(`${key}(${fnData.args.join(", ")}) {`, ...indent([
|
|
2535
|
+
"let unwatchFns = [];",
|
|
2536
|
+
...fnData.fn(...fnData.args),
|
|
2537
|
+
"return unwatchFns;"
|
|
2538
|
+
]), "}");
|
|
2539
|
+
else renderFunctions.push(`${key}() {`, ...indent([
|
|
2540
|
+
"let unwatchFns = [];",
|
|
2541
|
+
...fnData.fn(),
|
|
2542
|
+
"return unwatchFns;"
|
|
2543
|
+
]), "}");
|
|
2470
2544
|
nodeToProcess.delete(key);
|
|
2471
2545
|
}
|
|
2472
2546
|
return renderFunctions.join("\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xaendar/compiler",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
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.6",
|
|
20
|
+
"@xaendar/types": "0.6.6",
|
|
21
21
|
"typescript": "^6.0.3"
|
|
22
22
|
}
|
|
23
23
|
}
|