@xaendar/compiler 0.7.28 → 0.7.30

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.
@@ -342,12 +342,45 @@ var GLOBAL_IDENTIFIERS = /* @__PURE__ */ new Set([
342
342
  "Window"
343
343
  ]);
344
344
  var ROOT_NODE = "root";
345
+ /**
346
+ * Resolves references to component properties inside a template expression.
347
+ *
348
+ * Identifiers that are not found in the active scope chain and are not
349
+ * well-known globals are prefixed with `this.` so they resolve against
350
+ * the component instance at runtime. Identifiers found in the scope chain
351
+ * are resolved either as a bare local reference (if declared directly in
352
+ * the current generated function's own scope) or via a runtime
353
+ * `parentContext.get(...)` traversal (if inherited from an enclosing
354
+ * scope) — and a trailing `()` is appended in either case if the
355
+ * identifier was declared as a signal, so the generated code always
356
+ * correctly unwraps it.
357
+ *
358
+ * The original formatting of the expression — parentheses, spacing,
359
+ * operator tokens, member access dots — is preserved verbatim by delegating
360
+ * to `node.getText()` for any subtree that contains no resolvable identifiers.
361
+ *
362
+ * @param expression - Either a raw identifier string or a validated
363
+ * `Expression` node produced by `validateExpression`.
364
+ * @param compilerContext - The active template scope context.
365
+ * @returns The resolved expression as a JavaScript string ready for codegen.
366
+ *
367
+ * @example
368
+ * // Simple identifier
369
+ * resolveExpression('items', context) // → 'this.items'
370
+ *
371
+ * @example
372
+ * // Signal identifier inherited from an ancestor scope (e.g. `$index` in a
373
+ * // nested @for body)
374
+ * resolveExpression('$index', context) // → "parentContext.get('$index')()"
375
+ *
376
+ * @example
377
+ * // Complex expression — formatting preserved
378
+ * resolveExpression(node, context)
379
+ * // typeof id !== 'boolean' || pippo instanceof HTMLElement
380
+ * // → typeof this.id !== 'boolean' || this.pippo instanceof HTMLElement
381
+ */
345
382
  function resolveExpression(expression, compilerContext, options) {
346
- let actualCompilerContext;
347
- let actualOptions;
348
- if (compilerContext instanceof CompilerContext) actualCompilerContext = compilerContext;
349
- else actualOptions = compilerContext;
350
- return emitNode(expression, expression, actualCompilerContext, mapDefaultOptions(actualOptions));
383
+ return emitNode(expression, expression, compilerContext, mapDefaultOptions(options));
351
384
  }
352
385
  /**
353
386
  * Emits the resolved text for a node.
@@ -2879,17 +2912,17 @@ var Parser = class {
2879
2912
  * emitted as bare statements, validated in place.
2880
2913
  */
2881
2914
  function typeCheckElement(node, processNode, context) {
2882
- const lines = [];
2915
+ const lines = new Array();
2883
2916
  node.attributes.forEach(({ value }) => {
2884
- if (typeof value !== "string") lines.push(`${resolveExpression(value.expression, { resolver: "root" })};`);
2917
+ if (typeof value !== "string") lines.push(`${resolveExpression(value.expression, context, { resolver: "root" })};`);
2885
2918
  });
2886
2919
  node.events.forEach(({ handler, parameters }) => {
2887
- const args = parameters.map((parameter) => resolveExpression(parameter, { resolver: "root" })).join(", ");
2920
+ const eventContext = new CompilerContext([], context);
2921
+ eventContext.addUnresolvableIdentifier("$event");
2922
+ const args = parameters.map((parameter) => resolveExpression(parameter, eventContext, { resolver: "root" })).join(", ");
2888
2923
  lines.push(`root.${handler}(${args});`);
2889
2924
  });
2890
- node.children.forEach((child, i) => {
2891
- lines.push(...processNode(child, context));
2892
- });
2925
+ node.children.forEach((child) => lines.push(...processNode(child, context)));
2893
2926
  return lines;
2894
2927
  }
2895
2928
  //#endregion
@@ -2919,7 +2952,7 @@ function typeCheckFor(node, processNode, context) {
2919
2952
  oddName,
2920
2953
  node.itemAlias
2921
2954
  ].forEach((identifier) => forContext.addUnresolvableIdentifier(identifier));
2922
- const lines = [];
2955
+ const lines = new Array();
2923
2956
  lines.push(`for (const ${node.itemAlias} of root.${node.iterableSource}) {`);
2924
2957
  lines.push(...indent([
2925
2958
  `let ${indexName}!: number;`,
@@ -2927,8 +2960,8 @@ function typeCheckFor(node, processNode, context) {
2927
2960
  `let ${lastName}!: boolean;`,
2928
2961
  `let ${evenName}!: boolean;`,
2929
2962
  `let ${oddName}!: boolean;`,
2930
- `${resolveExpression(node.trackExpression, { skipResolution: true })};`,
2931
- ...node.children.flatMap((child) => processNode(child, context))
2963
+ `${resolveExpression(node.trackExpression, context, { skipResolution: true })};`,
2964
+ ...node.children.flatMap((child) => processNode(child, forContext))
2932
2965
  ]));
2933
2966
  lines.push("}");
2934
2967
  return lines;
@@ -2962,14 +2995,14 @@ function resolveImplicit(node, implicit) {
2962
2995
  * flat sibling functions could never express.
2963
2996
  */
2964
2997
  function typeCheckIf(node, processNode, context) {
2965
- const lines = [];
2966
- const condition = resolveExpression(node.conditionNode, { resolver: "root" });
2998
+ const lines = new Array();
2999
+ const condition = resolveExpression(node.conditionNode, context, { resolver: "root" });
2967
3000
  lines.push(`if (${condition}) {`);
2968
3001
  lines.push(...indent(node.children.flatMap((child) => processNode(child, context))));
2969
3002
  lines.push("}");
2970
3003
  let alt = node.alternate;
2971
3004
  while (alt?.type === ASTNodeType.ElseIf) {
2972
- const elseIfCondition = resolveExpression(alt.conditionNode, { resolver: "root" });
3005
+ const elseIfCondition = resolveExpression(alt.conditionNode, context, { resolver: "root" });
2973
3006
  lines.push(`else if (${elseIfCondition}) {`);
2974
3007
  lines.push(...indent(alt.children.flatMap((child) => processNode(child, context))));
2975
3008
  lines.push("}");
@@ -3000,7 +3033,7 @@ function typeCheckIf(node, processNode, context) {
3000
3033
  * JS/TS fallthrough syntax directly.
3001
3034
  */
3002
3035
  function typeCheckSwitch(node, processNode, context) {
3003
- const lines = [`switch (${resolveExpression(node.expression, { resolver: "root" })}) {`];
3036
+ const lines = [`switch (${resolveExpression(node.expression, context, { resolver: "root" })}) {`];
3004
3037
  node.children.forEach((caseNode) => {
3005
3038
  caseNode.condition?.length ? caseNode.condition.forEach((conditionValue) => lines.push(` case ${conditionValue}:`)) : lines.push(" default:");
3006
3039
  lines.push(...indent(indent([...caseNode.children.flatMap((child) => processNode(child, context)), "break;"])));
@@ -3017,8 +3050,8 @@ function typeCheckSwitch(node, processNode, context) {
3017
3050
  * interpolation's expression is emitted as a bare statement — enough for
3018
3051
  * TS to validate it, with no name needing to be bound to the result.
3019
3052
  */
3020
- function typeCheckTextAndInterpolation(node, _processNode, _context) {
3021
- return node.type === ASTNodeType.Interpolation ? [`${resolveExpression(node.expression, { resolver: "root" })};`] : [];
3053
+ function typeCheckTextAndInterpolation(node, _processNode, context) {
3054
+ return node.type === ASTNodeType.Interpolation ? [`${resolveExpression(node.expression, context, { resolver: "root" })};`] : [];
3022
3055
  }
3023
3056
  //#endregion
3024
3057
  //#region ../packages/compiler/src/type-checker/type-checker.ts
@@ -3068,10 +3101,9 @@ var TypeChecker = class {
3068
3101
  * relevant if the consuming project has `noUnusedLocals` enabled.
3069
3102
  */
3070
3103
  generate() {
3071
- const body = this._ast.flatMap((node) => this._processNode(node));
3072
3104
  return [
3073
3105
  "function typeCheck() {",
3074
- ...indent(body.some((line) => line.includes("$event")) ? ["let $event!: Event;", ...body] : body),
3106
+ ...indent(this._ast.flatMap((node) => this._processNode(node))),
3075
3107
  "}"
3076
3108
  ].join("\n");
3077
3109
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xaendar/compiler",
3
- "version": "0.7.28",
3
+ "version": "0.7.30",
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.7.28",
20
- "@xaendar/types": "0.7.28",
19
+ "@xaendar/common": "0.7.30",
20
+ "@xaendar/types": "0.7.30",
21
21
  "typescript": "^6.0.3"
22
22
  }
23
23
  }