@xaendar/compiler 0.6.7 → 0.6.10

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.
@@ -1756,26 +1756,11 @@ function isValidIdentifier(name) {
1756
1756
  * @returns The parsed `IfNode`.
1757
1757
  */
1758
1758
  function parseIfControlFlow(cursor, parseNode, token) {
1759
- return parseIfRecursively(cursor, parseNode, token);
1759
+ return parseIfOrElseIf(cursor, parseNode, token);
1760
1760
  }
1761
- function parseIfRecursively(cursor, parseNode, token) {
1761
+ function parseElseIfRecursively(cursor, parseNode, token) {
1762
1762
  switch (token.type) {
1763
- case TokenType.IF:
1764
- case TokenType.ELSE_IF:
1765
- cursor.advance();
1766
- const conditionToken = cursor.peek();
1767
- if (conditionToken.type !== TokenType.CONDITION) throw new Error(`[Parser] Expected CONDITION after ${TokenType[token.type]}, got ${TokenType[conditionToken.type]}`);
1768
- cursor.advance(2);
1769
- const condition = conditionToken.parts[0];
1770
- const validationResult = validateExpression(condition);
1771
- const consequent = parseBlockChildren(cursor, parseNode);
1772
- return {
1773
- type: token.type === TokenType.IF ? ASTNodeType.If : ASTNodeType.ElseIf,
1774
- condition,
1775
- conditionNode: validationResult.node,
1776
- consequent,
1777
- alternate: parseIfRecursively(cursor, parseNode, cursor.peek())
1778
- };
1763
+ case TokenType.ELSE_IF: return parseIfOrElseIf(cursor, parseNode, token);
1779
1764
  case TokenType.ELSE:
1780
1765
  cursor.advance(2);
1781
1766
  const elseChildren = parseBlockChildren(cursor, parseNode);
@@ -1785,6 +1770,22 @@ function parseIfRecursively(cursor, parseNode, token) {
1785
1770
  };
1786
1771
  }
1787
1772
  }
1773
+ function parseIfOrElseIf(cursor, parseNode, token) {
1774
+ cursor.advance();
1775
+ const conditionToken = cursor.peek();
1776
+ if (conditionToken.type !== TokenType.CONDITION) throw new Error(`[Parser] Expected CONDITION after ${TokenType[token.type]}, got ${TokenType[conditionToken.type]}`);
1777
+ cursor.advance(2);
1778
+ const condition = conditionToken.parts[0];
1779
+ const validationResult = validateExpression(condition);
1780
+ const consequent = parseBlockChildren(cursor, parseNode);
1781
+ return {
1782
+ type: token.type === TokenType.IF ? ASTNodeType.If : ASTNodeType.ElseIf,
1783
+ condition,
1784
+ conditionNode: validationResult.node,
1785
+ consequent,
1786
+ alternate: parseElseIfRecursively(cursor, parseNode, cursor.peek())
1787
+ };
1788
+ }
1788
1789
  //#endregion
1789
1790
  //#region ../packages/compiler/src/parser/states/parse-switch.state.ts
1790
1791
  /**
@@ -1924,39 +1925,75 @@ var Parser = class {
1924
1925
  }
1925
1926
  };
1926
1927
  //#endregion
1927
- //#region ../packages/compiler/src/render-generator/models/render-context.model.ts
1928
+ //#region ../packages/compiler/src/render-generator/states/process-const-declaration.state.ts
1928
1929
  /**
1929
- * Tracks identifier scope during render code generation.
1930
- * Each `Context` instance represents one lexical scope (e.g. a `@for` loop body)
1931
- * and can be chained to a parent context for outer-scope resolution.
1930
+ * Generates code for a `@const` declaration node.
1931
+ * Emits a `const name = expression;` JavaScript statement.
1932
+ *
1933
+ * @param node The `ConstDeclarationNode` to process.
1934
+ * @param _nodeName Unused node name.
1935
+ * @param _parentNode Unused parent node name.
1936
+ * @returns Array containing the generated const statement string.
1932
1937
  */
1933
- var Context = class {
1934
- _identifiers;
1935
- _parent;
1936
- /**
1937
- * Creates a new scope context.
1938
- *
1939
- * @param _identifiers List of loop variable names declared in this scope.
1940
- * @param _parent Optional parent context representing the enclosing scope.
1941
- */
1942
- constructor(_identifiers = new Array(), _parent) {
1943
- this._identifiers = _identifiers;
1944
- this._parent = _parent;
1945
- }
1946
- addIdentifier(name) {
1947
- if (this.getIdentifier(name)) throw new Error(`Identifier "${name}" is already declared in this scope.`);
1948
- this._identifiers.push(name);
1949
- }
1950
- /**
1951
- * Returns the innermost identifier in the current scope chain, or
1952
- * delegates to the parent context if none is found in this scope.
1953
- *
1954
- * @returns The most recently declared identifier name, or `undefined` if none exists.
1955
- */
1956
- getIdentifier(name) {
1957
- return this._identifiers.includes(name) ? name : this._parent?.getIdentifier(name);
1958
- }
1959
- };
1938
+ function processConstDeclaration(node, _nodeName, _parentNode) {
1939
+ return [`const ${node.varName} = ${node.varName};`];
1940
+ }
1941
+ //#endregion
1942
+ //#region ../packages/compiler/src/render-generator/states/process-element.state.ts
1943
+ /**
1944
+ * Generates code for an HTML element node: creates the DOM element, sets attributes,
1945
+ * attaches event listeners, appends it to the parent, and recursively processes children.
1946
+ *
1947
+ * @param node The `ElementNode` to process.
1948
+ * @param nodeName Variable name to use for the created DOM element.
1949
+ * @param parentNode Variable name of the parent DOM node to append to.
1950
+ * @returns Array of generated code lines.
1951
+ */
1952
+ function processElement(node, nodeName, parentNode) {
1953
+ const attributes = mapAttributes(node.attributes);
1954
+ const events = mapEvents(node.events);
1955
+ const code = [`renderElement(${parentNode}, context, '${node.tagName}',`];
1956
+ attributes.length ? code.push(...indent([
1957
+ "[",
1958
+ ...indent(attributes),
1959
+ "],"
1960
+ ])) : code[code.length - 1] = `${code[code.length - 1]} [],`;
1961
+ events.length ? code.push(...indent([
1962
+ "[",
1963
+ ...indent(events),
1964
+ "]"
1965
+ ]), ")") : code[code.length - 1] = `${code[code.length - 1]} [])`;
1966
+ return code;
1967
+ }
1968
+ /**
1969
+ * Generates code that assigns attributes to a DOM element.
1970
+ *
1971
+ * Static (string) attribute values are set once via a direct `setAttribute` call,
1972
+ * while dynamic attribute values are wrapped in an `effect` so the attribute is
1973
+ * re-evaluated and updated whenever its underlying signal dependencies change.
1974
+ * The disposer returned by the `effect` is registered in `unwatchFns` for cleanup.
1975
+ *
1976
+ * @param attributes The attribute nodes to map onto the element.
1977
+ * @returns Array of generated code lines, one per attribute.
1978
+ */
1979
+ function mapAttributes(attributes) {
1980
+ return attributes?.map(({ name, value }) => {
1981
+ const isLiteral = typeof value === "string";
1982
+ return `{ name: '${name}', value: '${isLiteral ? value : value.expression.text}', literal: ${isLiteral} },`;
1983
+ });
1984
+ }
1985
+ /**
1986
+ * Generates code that attaches event listeners to a DOM element.
1987
+ *
1988
+ * For each event node an `addEventListener` call is emitted, binding the event
1989
+ * to the component instance handler and exposing the native event as `$event`.
1990
+ *
1991
+ * @param events The event nodes to bind to the element.
1992
+ * @returns Array of generated code lines, one per event listener.
1993
+ */
1994
+ function mapEvents(events) {
1995
+ return events?.map((event) => `{ name: '${event.name}', handler: '${event.handler}' }`);
1996
+ }
1960
1997
  //#endregion
1961
1998
  //#region ../packages/compiler/src/render-generator/utils/render-generator.utils.ts
1962
1999
  /**
@@ -2141,7 +2178,7 @@ var GLOBAL_IDENTIFIERS = new Set([
2141
2178
  "Document",
2142
2179
  "Window"
2143
2180
  ]);
2144
- var ROOT_NODE = "this._root";
2181
+ var ROOT_NODE = "root";
2145
2182
  /**
2146
2183
  * Resolves references to component properties inside a template expression.
2147
2184
  *
@@ -2168,8 +2205,8 @@ var ROOT_NODE = "this._root";
2168
2205
  * // typeof id !== 'boolean' || pippo instanceof HTMLElement
2169
2206
  * // → typeof this.id !== 'boolean' || this.pippo instanceof HTMLElement
2170
2207
  */
2171
- function resolveExpression(expression, context) {
2172
- return emitNode(expression, expression, context);
2208
+ function resolveExpression(expression) {
2209
+ return emitNode(expression, expression);
2173
2210
  }
2174
2211
  /**
2175
2212
  * Emits the resolved text for a node.
@@ -2180,14 +2217,13 @@ function resolveExpression(expression, context) {
2180
2217
  * - If the node is a resolvable Identifier, emits the resolved name.
2181
2218
  * - Otherwise recurses into children and concatenates their output.
2182
2219
  */
2183
- function emitNode(node, parent, context) {
2184
- if (ts.isIdentifier(node) && needsResolution(node, parent)) return context.getIdentifier(node.text) ?? `this.${node.text}`;
2220
+ function emitNode(node, parent) {
2185
2221
  if (!containsResolvableIdentifier(node, parent)) return node.getText();
2186
2222
  const sourceText = node.getSourceFile().text;
2187
2223
  let result = "";
2188
2224
  let lastEnd = node.getStart();
2189
2225
  ts.forEachChild(node, (child) => {
2190
- result = `${result}${sourceText.slice(lastEnd, child.getStart())}${emitNode(child, node, context)}`;
2226
+ result = `${result}${sourceText.slice(lastEnd, child.getStart())}${emitNode(child, node)}`;
2191
2227
  lastEnd = child.getEnd();
2192
2228
  });
2193
2229
  return `${result}${sourceText.slice(lastEnd, node.getEnd())}`;
@@ -2223,93 +2259,13 @@ function needsResolution(node, parent) {
2223
2259
  * @returns A string representing the unique variable name for the element.
2224
2260
  */
2225
2261
  function getElementIdentifier(node, parentNode, index) {
2226
- return (parentNode !== "this._root" ? `${parentNode}_${node.tagName}${index}` : `${node.tagName}${index}`).replace(/-/g, "_");
2262
+ return (parentNode !== "root" ? `${parentNode}_${node.tagName}${index}` : `${node.tagName}${index}`).replace(/-/g, "_");
2227
2263
  }
2228
2264
  function getTextIdentifier(parentNode, index, prefix = "text") {
2229
- return (parentNode !== "this._root" ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`).replace(/-/g, "_");
2265
+ return (parentNode !== "root" ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`).replace(/-/g, "_");
2230
2266
  }
2231
2267
  function getBlockIdentifier(parentNode, index, prefix) {
2232
- return (parentNode !== "this._root" ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`).replace(/-/g, "_");
2233
- }
2234
- //#endregion
2235
- //#region ../packages/compiler/src/render-generator/states/process-const-declaration.state.ts
2236
- /**
2237
- * Generates code for a `@const` declaration node.
2238
- * Emits a `const name = expression;` JavaScript statement.
2239
- *
2240
- * @param node The `ConstDeclarationNode` to process.
2241
- * @param _nodeName Unused node name.
2242
- * @param _parentNode Unused parent node name.
2243
- * @param _context Unused render context.
2244
- * @returns Array containing the generated const statement string.
2245
- */
2246
- function processConstDeclaration(node, _nodeName, _parentNode, context) {
2247
- context.addIdentifier(node.varName);
2248
- return [`const ${node.varName} = ${resolveExpression(node.expression, context)};`];
2249
- }
2250
- //#endregion
2251
- //#region ../packages/compiler/src/render-generator/states/process-element.state.ts
2252
- /**
2253
- * Generates code for an HTML element node: creates the DOM element, sets attributes,
2254
- * attaches event listeners, appends it to the parent, and recursively processes children.
2255
- *
2256
- * @param node The `ElementNode` to process.
2257
- * @param nodeName Variable name to use for the created DOM element.
2258
- * @param parentNode Variable name of the parent DOM node to append to.
2259
- * @param context Current render scope context.
2260
- * @returns Array of generated code lines.
2261
- */
2262
- function processElement(node, nodeName, parentNode, context) {
2263
- const childrenContext = new Context([], context);
2264
- return [
2265
- `const ${nodeName} = document.createElement("${node.tagName}");`,
2266
- ...mapAttributes(node.attributes, nodeName, context),
2267
- ...mapEvents(node.events, nodeName),
2268
- `${parentNode}.appendChild(${nodeName});`,
2269
- `unwatchFns.push(() => ${parentNode}.removeChild(${nodeName}));`,
2270
- ...node.children.map((child, i) => processNode(child, i.toString(), nodeName, childrenContext)).flat()
2271
- ];
2272
- }
2273
- /**
2274
- * Generates code that assigns attributes to a DOM element.
2275
- *
2276
- * Static (string) attribute values are set once via a direct `setAttribute` call,
2277
- * while dynamic attribute values are wrapped in an `effect` so the attribute is
2278
- * re-evaluated and updated whenever its underlying signal dependencies change.
2279
- * The disposer returned by the `effect` is registered in `unwatchFns` for cleanup.
2280
- *
2281
- * @param attributes The attribute nodes to map onto the element.
2282
- * @param nodeName Variable name of the DOM element receiving the attributes.
2283
- * @param context Current render scope context, used to resolve dynamic expressions.
2284
- * @returns Array of generated code lines, one per attribute.
2285
- */
2286
- function mapAttributes(attributes, nodeName, context) {
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;
2300
- }
2301
- /**
2302
- * Generates code that attaches event listeners to a DOM element.
2303
- *
2304
- * For each event node an `addEventListener` call is emitted, binding the event
2305
- * to the component instance handler and exposing the native event as `$event`.
2306
- *
2307
- * @param events The event nodes to bind to the element.
2308
- * @param nodeName Variable name of the DOM element receiving the listeners.
2309
- * @returns Array of generated code lines, one per event listener.
2310
- */
2311
- function mapEvents(events, nodeName) {
2312
- return events?.map((event) => `${nodeName}.addEventListener("${event.name}", ($event) => this.${event.handler});`) ?? [];
2268
+ return (parentNode !== "root" ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`).replace(/-/g, "_");
2313
2269
  }
2314
2270
  //#endregion
2315
2271
  //#region ../packages/compiler/src/render-generator/states/process-for.state.ts
@@ -2341,14 +2297,12 @@ function mapEvents(events, nodeName) {
2341
2297
  * @param nodeName - Base variable name prefix used for child nodes and
2342
2298
  * to produce a unique loop counter identifier.
2343
2299
  * @param parentNode - Variable name of the parent DOM node.
2344
- * @param parentContext - The enclosing scope context.
2345
2300
  * @returns Array of generated code lines.
2346
2301
  */
2347
- function processFor(node, nodeName, parentNode, parentContext) {
2302
+ function processFor(node, nodeName, parentNode) {
2348
2303
  const mainBlock = new Array();
2349
2304
  const functionsToProcess = /* @__PURE__ */ new Map();
2350
2305
  const iterableSource = node.iterableSource;
2351
- const iterableExpr = parentContext.getIdentifier(iterableSource) ?? `this.${iterableSource}`;
2352
2306
  const itemsName = getTextIdentifier(parentNode, nodeName, "items");
2353
2307
  const counterName = getTextIdentifier(parentNode, nodeName, "i");
2354
2308
  const indexName = resolveImplicit(node, "$index");
@@ -2356,20 +2310,17 @@ function processFor(node, nodeName, parentNode, parentContext) {
2356
2310
  const lastName = resolveImplicit(node, "$last");
2357
2311
  const evenName = resolveImplicit(node, "$even");
2358
2312
  const oddName = resolveImplicit(node, "$odd");
2359
- const forContext = new Context([
2360
- node.itemAlias,
2361
- indexName,
2362
- firstName,
2363
- lastName,
2364
- evenName,
2365
- oddName
2366
- ], parentContext);
2367
2313
  const forKey = getBlockIdentifier(parentNode, nodeName, "for");
2368
2314
  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))],
2370
- args: [itemsName, counterName]
2315
+ code: [`const { ${node.itemAlias}, ${indexName}, ${firstName}, ${lastName}, ${evenName}, ${oddName} } = _iterationVariables(${itemsName}, ${counterName});`, ...node.children.flatMap((child, i) => processNode(child, `${nodeName}_${i}`, parentNode))],
2316
+ args: [
2317
+ parentNode,
2318
+ "parentContext",
2319
+ itemsName,
2320
+ counterName
2321
+ ]
2371
2322
  });
2372
- mainBlock.push(`_for(unwatchFns, () => ${iterableExpr}, this.${forKey}.bind(this));`);
2323
+ mainBlock.push(`_for(${parentNode}, context, '${iterableSource}', this.${forKey}.bind(this));`);
2373
2324
  return {
2374
2325
  mainBlock,
2375
2326
  fns: functionsToProcess
@@ -2399,41 +2350,46 @@ function resolveImplicit(node, implicit) {
2399
2350
  * @param node The `IfNode` to process.
2400
2351
  * @param nodeName Base variable name prefix for child nodes.
2401
2352
  * @param parentNode Variable name of the parent DOM node.
2402
- * @param context Current render scope context.
2403
2353
  * @returns Array of generated code lines.
2404
2354
  */
2405
- function processIf(node, nodeName, parentNode, context) {
2406
- const ifContext = new Context([], context);
2355
+ function processIf(node, nodeName, parentNode) {
2407
2356
  const functionsToProcess = /* @__PURE__ */ new Map();
2408
2357
  const mainBlock = new Array();
2409
2358
  const ifKey = getBlockIdentifier(parentNode, nodeName, "if");
2410
2359
  mainBlock.push({
2411
- condition: resolveExpression(node.conditionNode, context),
2360
+ condition: resolveExpression(node.conditionNode),
2412
2361
  block: `this.${ifKey}.bind(this)`
2413
2362
  });
2414
- functionsToProcess.set(ifKey, processConsequent(node, nodeName, parentNode, ifContext));
2363
+ functionsToProcess.set(ifKey, {
2364
+ code: processConsequent(node, nodeName, parentNode),
2365
+ args: [parentNode, "parentContext"]
2366
+ });
2415
2367
  let alt = node.alternate;
2416
2368
  let index = 0;
2417
2369
  while (alt?.type === ASTNodeType.ElseIf) {
2418
- const elseIfContext = new Context([], context);
2419
2370
  const keyElseIf = getBlockIdentifier(parentNode, `${nodeName}_${index}`, "elseIf");
2420
2371
  const conditionNode = alt.conditionNode;
2421
2372
  mainBlock.push({
2422
- condition: resolveExpression(conditionNode, context),
2373
+ condition: resolveExpression(conditionNode),
2423
2374
  block: `this.${keyElseIf}.bind(this)`
2424
2375
  });
2425
- functionsToProcess.set(keyElseIf, processConsequent(alt, nodeName, parentNode, elseIfContext));
2376
+ functionsToProcess.set(keyElseIf, {
2377
+ code: processConsequent(alt, nodeName, parentNode),
2378
+ args: [parentNode, "parentContext"]
2379
+ });
2426
2380
  alt = alt.alternate;
2427
2381
  }
2428
2382
  if (alt) {
2429
- const elseContext = new Context([], context);
2430
2383
  const keyElse = getBlockIdentifier(parentNode, nodeName, "else");
2431
2384
  mainBlock.push({ block: `this.${keyElse}.bind(this)` });
2432
- functionsToProcess.set(keyElse, processConsequent(alt, nodeName, parentNode, elseContext));
2385
+ functionsToProcess.set(keyElse, {
2386
+ code: processConsequent(alt, nodeName, parentNode),
2387
+ args: [parentNode, "parentContext"]
2388
+ });
2433
2389
  }
2434
2390
  return {
2435
2391
  mainBlock: [
2436
- "_if(unwatchFns, [",
2392
+ `_if(${parentNode}, context, [`,
2437
2393
  ...indent(mainBlock.map(({ condition, block }) => {
2438
2394
  return [
2439
2395
  "{",
@@ -2446,8 +2402,8 @@ function processIf(node, nodeName, parentNode, context) {
2446
2402
  fns: functionsToProcess
2447
2403
  };
2448
2404
  }
2449
- function processConsequent(node, nodeName, parentNode, context) {
2450
- return node.consequent.map((child, i) => processNode(child, `${nodeName}_${i}`, parentNode, context)).flat();
2405
+ function processConsequent(node, nodeName, parentNode) {
2406
+ return node.consequent.map((child, i) => processNode(child, `${nodeName}_${i}`, parentNode)).flat();
2451
2407
  }
2452
2408
  //#endregion
2453
2409
  //#region ../packages/compiler/src/render-generator/states/process-switch.state.ts
@@ -2459,16 +2415,17 @@ function processConsequent(node, nodeName, parentNode, context) {
2459
2415
  * @param node The `SwitchNode` to process.
2460
2416
  * @param nodeName Base variable name prefix for child nodes.
2461
2417
  * @param parentNode Variable name of the parent DOM node.
2462
- * @param context Current render scope context.
2463
2418
  * @returns Array of generated code lines.
2464
2419
  */
2465
- function processSwitch(node, nodeName, parentNode, context) {
2420
+ function processSwitch(node, nodeName, parentNode) {
2466
2421
  const functionsToProcess = /* @__PURE__ */ new Map();
2467
2422
  const blocks = new Array();
2468
2423
  node.cases.forEach((caseNode, i) => {
2469
- const caseContext = new Context([], context);
2470
2424
  const caseName = caseNode.condition ? getBlockIdentifier(parentNode, `${nodeName}_${i}`, "case") : getBlockIdentifier(parentNode, nodeName, "default");
2471
- functionsToProcess.set(caseName, caseNode.children.map((child, i) => processNode(child, `${nodeName}_${i}_${i}`, parentNode, caseContext)).flat());
2425
+ functionsToProcess.set(caseName, {
2426
+ code: caseNode.children.map((child, i) => processNode(child, `${nodeName}_${i}_${i}`, parentNode)).flat(),
2427
+ args: [parentNode, "parentContext"]
2428
+ });
2472
2429
  blocks.push({
2473
2430
  condition: caseNode.condition,
2474
2431
  block: `this.${caseName}.bind(this)`
@@ -2476,7 +2433,7 @@ function processSwitch(node, nodeName, parentNode, context) {
2476
2433
  });
2477
2434
  return {
2478
2435
  mainBlock: [
2479
- `_switch(unwatchFns, () => ${resolveExpression(node.expression, context)}, [`,
2436
+ `_switch(${parentNode}, context, () => ${resolveExpression(node.expression)}, [`,
2480
2437
  ...indent(blocks.map(({ condition, block }) => {
2481
2438
  return [
2482
2439
  "{",
@@ -2497,18 +2454,12 @@ function processSwitch(node, nodeName, parentNode, context) {
2497
2454
  * then appends it to the parent DOM node.
2498
2455
  *
2499
2456
  * @param node A `TextNode` or `InterpolationNode` to process.
2500
- * @param nodeName Variable name for the created text node.
2457
+ * @param nodeName - The identifier for the Text Node created
2501
2458
  * @param parentNode Variable name of the parent DOM node.
2502
- * @param _context Unused render context.
2503
2459
  * @returns Array of two generated code lines: the text node creation and the appendChild call.
2504
2460
  */
2505
- function processTextAndInterpolation(node, nodeName, parentNode, context) {
2506
- const textValue = node.type === ASTNodeType.Text ? JSON.stringify(node.value) : resolveExpression(node.expression, context);
2507
- return [
2508
- `const ${nodeName} = document.createTextNode(${textValue});`,
2509
- `${parentNode}.appendChild(${nodeName});`,
2510
- `unwatchFns.push(effect(() => ${nodeName}.textContent = ${textValue}));`
2511
- ];
2461
+ function processTextAndInterpolation(node, nodeName, parentNode) {
2462
+ return [`${node.type === ASTNodeType.Text ? `renderLiteralText(${parentNode}, context, '${node.value}')` : `renderText(${parentNode}, context, '${node.expression.text}')`}`];
2512
2463
  }
2513
2464
  //#endregion
2514
2465
  //#region ../packages/compiler/src/render-generator/render-generator.ts
@@ -2521,25 +2472,15 @@ var nodeToProcess = /* @__PURE__ */ new Map();
2521
2472
  */
2522
2473
  function generateRenderFunction(ast, cssVariableName) {
2523
2474
  nodeToProcess.clear();
2524
- const context = new Context();
2525
- const renderFunctions = ["_render() {"];
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
- ]), "}");
2532
- while (nodeToProcess.size > 0) {
2475
+ const renderFunctions = ["_render() {", ...indent([`const ${ROOT_NODE} = this._root;`, "const context = new Context(this)"])];
2476
+ if (cssVariableName) renderFunctions.push(indent(`${ROOT_NODE}.adoptedStyleSheets = [${cssVariableName}];`));
2477
+ renderFunctions.push(...indent([...ast.map((node, i) => [...processNode(node, i.toString(), ROOT_NODE)]).flat(), "return context;"]), "}");
2478
+ while (nodeToProcess.size) {
2533
2479
  const [key, fnData] = nodeToProcess.entries().next().value;
2534
- if ("args" in fnData) renderFunctions.push(`${key}(${fnData.args.join(", ")}) {`, ...indent([
2535
- "let unwatchFns = [];",
2480
+ renderFunctions.push(`${key}(${fnData.args.join(", ")}) {`, ...indent([
2481
+ "const context = new Context(this, parentContext)",
2536
2482
  ...fnData.fn(...fnData.args),
2537
- "return unwatchFns;"
2538
- ]), "}");
2539
- else renderFunctions.push(`${key}() {`, ...indent([
2540
- "let unwatchFns = [];",
2541
- ...fnData.fn(),
2542
- "return unwatchFns;"
2483
+ "return context"
2543
2484
  ]), "}");
2544
2485
  nodeToProcess.delete(key);
2545
2486
  }
@@ -2550,27 +2491,33 @@ function generateRenderFunction(ast, cssVariableName) {
2550
2491
  * For flow control nodes no single var is produced; instead multiple children
2551
2492
  * are appended directly inside the control flow block.
2552
2493
  */
2553
- function processNode(node, nodeName, parentNode, context) {
2494
+ function processNode(node, nodeName, parentNode) {
2554
2495
  switch (node.type) {
2555
2496
  case ASTNodeType.Text:
2556
- case ASTNodeType.Interpolation: return processTextAndInterpolation(node, getTextIdentifier(parentNode, nodeName), parentNode, context);
2557
- case ASTNodeType.Element: return processElement(node, getElementIdentifier(node, parentNode, nodeName), parentNode, context);
2497
+ case ASTNodeType.Interpolation: return processTextAndInterpolation(node, getTextIdentifier(parentNode, nodeName), parentNode);
2498
+ case ASTNodeType.Element: return processElement(node, getElementIdentifier(node, parentNode, nodeName), parentNode);
2558
2499
  case ASTNodeType.If:
2559
- const conditionalBlockData = processIf(node, nodeName, parentNode, context);
2560
- conditionalBlockData.fns.forEach((fnBody, key) => nodeToProcess.set(key, { fn: () => fnBody }));
2500
+ const conditionalBlockData = processIf(node, nodeName, parentNode);
2501
+ conditionalBlockData.fns.forEach((fnBody, key) => nodeToProcess.set(key, {
2502
+ fn: () => fnBody.code,
2503
+ args: fnBody.args
2504
+ }));
2561
2505
  return conditionalBlockData.mainBlock;
2562
2506
  case ASTNodeType.For:
2563
- const forBlockData = processFor(node, nodeName, parentNode, context);
2507
+ const forBlockData = processFor(node, nodeName, parentNode);
2564
2508
  forBlockData.fns.forEach((fnBody, key) => nodeToProcess.set(key, {
2565
2509
  fn: () => fnBody.code,
2566
2510
  args: fnBody.args
2567
2511
  }));
2568
2512
  return forBlockData.mainBlock;
2569
2513
  case ASTNodeType.Switch:
2570
- const switchBlockData = processSwitch(node, nodeName, parentNode, context);
2571
- switchBlockData.fns.forEach((fnBody, key) => nodeToProcess.set(key, { fn: () => fnBody }));
2514
+ const switchBlockData = processSwitch(node, nodeName, parentNode);
2515
+ switchBlockData.fns.forEach((fnBody, key) => nodeToProcess.set(key, {
2516
+ fn: () => fnBody.code,
2517
+ args: fnBody.args
2518
+ }));
2572
2519
  return switchBlockData.mainBlock;
2573
- case ASTNodeType.ConstDeclaration: return processConstDeclaration(node, nodeName, parentNode, context);
2520
+ case ASTNodeType.ConstDeclaration: return processConstDeclaration(node, nodeName, parentNode);
2574
2521
  default: return [];
2575
2522
  }
2576
2523
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xaendar/compiler",
3
- "version": "0.6.7",
3
+ "version": "0.6.10",
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.7",
20
- "@xaendar/types": "0.6.7",
19
+ "@xaendar/common": "0.6.10",
20
+ "@xaendar/types": "0.6.10",
21
21
  "typescript": "^6.0.3"
22
22
  }
23
23
  }