@xaendar/compiler 0.5.6 → 0.5.8

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.
@@ -1,4 +1,4 @@
1
- import { Stack, assertIsValidElementName, indent } from "@xaendar/common";
1
+ import { Stack, indent } from "@xaendar/common";
2
2
  import ts from "typescript";
3
3
  //#region ../packages/compiler/src/lexer/types/lexer-state.enum.ts
4
4
  /**
@@ -2219,20 +2219,47 @@ function processConstDeclaration(node, _nodeName, _parentNode, context) {
2219
2219
  */
2220
2220
  function processElement(node, nodeName, parentNode, context) {
2221
2221
  const childrenContext = new Context([], context);
2222
- const tagName = node.tagName;
2223
- if (!assertIsValidElementName(tagName)) process.exit(1);
2224
2222
  return [
2225
- `const ${nodeName} = document.createElement("${tagName}");`,
2226
- ...node.attributes?.map((attr) => {
2227
- const value = attr.value;
2228
- return typeof value === "string" ? `${nodeName}.setAttribute('${attr.name}', ${value});` : `unwatchFns.push(effect(() => ${nodeName}.setAttribute('${attr.name}', ${resolveExpression(value.expression, context)})));`;
2229
- }) || [],
2230
- ...node.events?.map((event) => `${nodeName}.addEventListener("${event.name}", ($event) => this.${event.handler});`) || [],
2223
+ `const ${nodeName} = document.createElement("${node.tagName}");`,
2224
+ ...mapAttributes(node.attributes, nodeName, context),
2225
+ ...mapEvents(node.events, nodeName),
2231
2226
  `${parentNode}.appendChild(${nodeName});`,
2232
2227
  `unwatchFns.push(() => ${parentNode}.removeChild(${nodeName}));`,
2233
2228
  ...node.children.map((child, i) => processNode(child, i.toString(), nodeName, childrenContext)).flat()
2234
2229
  ];
2235
2230
  }
2231
+ /**
2232
+ * Generates code that assigns attributes to a DOM element.
2233
+ *
2234
+ * Static (string) attribute values are set once via a direct `setAttribute` call,
2235
+ * while dynamic attribute values are wrapped in an `effect` so the attribute is
2236
+ * re-evaluated and updated whenever its underlying signal dependencies change.
2237
+ * The disposer returned by the `effect` is registered in `unwatchFns` for cleanup.
2238
+ *
2239
+ * @param attributes The attribute nodes to map onto the element.
2240
+ * @param nodeName Variable name of the DOM element receiving the attributes.
2241
+ * @param context Current render scope context, used to resolve dynamic expressions.
2242
+ * @returns Array of generated code lines, one per attribute.
2243
+ */
2244
+ function mapAttributes(attributes, nodeName, context) {
2245
+ return attributes?.map((attr) => {
2246
+ const value = attr.value;
2247
+ return typeof value === "string" ? `${nodeName}.setAttribute('${attr.name}', ${value});` : `unwatchFns.push(effect(() => ${nodeName}.setAttribute('${attr.name}', ${resolveExpression(value.expression, context)})));`;
2248
+ }) ?? [];
2249
+ }
2250
+ /**
2251
+ * Generates code that attaches event listeners to a DOM element.
2252
+ *
2253
+ * For each event node an `addEventListener` call is emitted, binding the event
2254
+ * to the component instance handler and exposing the native event as `$event`.
2255
+ *
2256
+ * @param events The event nodes to bind to the element.
2257
+ * @param nodeName Variable name of the DOM element receiving the listeners.
2258
+ * @returns Array of generated code lines, one per event listener.
2259
+ */
2260
+ function mapEvents(events, nodeName) {
2261
+ return events?.map((event) => `${nodeName}.addEventListener("${event.name}", ($event) => this.${event.handler});`) ?? [];
2262
+ }
2236
2263
  //#endregion
2237
2264
  //#region ../packages/compiler/src/render-generator/states/process-for.state.ts
2238
2265
  /**
@@ -2434,12 +2461,12 @@ function generateRenderFunction(ast, cssVariableName) {
2434
2461
  nodeToProcess.clear();
2435
2462
  const context = new Context();
2436
2463
  const renderFunctions = ["_render() {"];
2437
- if (cssVariableName) renderFunctions.push(` this._root.adoptedStyleSheets = [${cssVariableName}];`);
2438
- renderFunctions.push(" let unwatchFns = [];", ...indent(...ast.map((node, i) => [...processNode(node, i.toString(), ROOT_NODE, context)]).flat()), " return unwatchFns;", "}");
2464
+ if (cssVariableName) renderFunctions.push(...indent(`this._root.adoptedStyleSheets = [${cssVariableName}];`));
2465
+ renderFunctions.push(...indent("let unwatchFns = [];", ...indent(...ast.map((node, i) => [...processNode(node, i.toString(), ROOT_NODE, context)]).flat()), "return unwatchFns;"), "}");
2439
2466
  while (nodeToProcess.size > 0) {
2440
2467
  const [key, fnData] = nodeToProcess.entries().next().value;
2441
- if ("args" in fnData) renderFunctions.push(`${key}(${fnData.args.join(", ")}) {`, " let unwatchFns = [];", ...indent(...fnData.fn(...fnData.args)), " return unwatchFns;", "}");
2442
- else renderFunctions.push(`${key}() {`, " let unwatchFns = [];", ...indent(...fnData.fn()), " return unwatchFns;", "}");
2468
+ if ("args" in fnData) renderFunctions.push(`${key}(${fnData.args.join(", ")}) {`, ...indent("let unwatchFns = [];", ...indent(...fnData.fn(...fnData.args)), "return unwatchFns;"), "}");
2469
+ else renderFunctions.push(`${key}() {`, ...indent("let unwatchFns = [];", ...indent(...fnData.fn()), "return unwatchFns;", "}"));
2443
2470
  nodeToProcess.delete(key);
2444
2471
  }
2445
2472
  return renderFunctions.join("\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xaendar/compiler",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
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.5.6",
20
- "@xaendar/types": "0.5.6",
19
+ "@xaendar/common": "0.5.8",
20
+ "@xaendar/types": "0.5.8",
21
21
  "typescript": "^6.0.3"
22
22
  }
23
23
  }