@xaendar/compiler 0.7.26 → 0.7.27

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,45 +342,12 @@ 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
- */
382
345
  function resolveExpression(expression, compilerContext, options) {
383
- return emitNode(expression, expression, compilerContext, mapDefaultOptions(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));
384
351
  }
385
352
  /**
386
353
  * Emits the resolved text for a node.
@@ -395,8 +362,10 @@ function resolveExpression(expression, compilerContext, options) {
395
362
  function emitNode(node, parent, compilerContext, options) {
396
363
  if (isIdentifier(node) && needsResolution(node, parent)) {
397
364
  const text = node.text;
398
- if (compilerContext.hasUnresolvableIdentifier(text) || options.skipResolution) return text;
399
- return resolveIdentifierAccess(text, compilerContext, options.resolver);
365
+ if (compilerContext?.hasUnresolvableIdentifier(text) || options.skipResolution) return text;
366
+ if (options.resolver) return `${options.resolver}.${text}`;
367
+ if (compilerContext) return resolveIdentifierAccess(text, compilerContext);
368
+ return text;
400
369
  }
401
370
  if (!containsResolvableIdentifier(node, parent)) return node.getText();
402
371
  const sourceText = node.getSourceFile().text;
@@ -427,13 +396,13 @@ function emitNode(node, parent, compilerContext, options) {
427
396
  * @param compilerContext - The active template scope context.
428
397
  * @returns The generated code expression that yields the identifier's value.
429
398
  */
430
- function resolveIdentifierAccess(text, compilerContext, resolver) {
399
+ function resolveIdentifierAccess(text, compilerContext) {
431
400
  if (compilerContext.hasIdentifier(text)) {
432
401
  const kind = compilerContext.getIdentifierKind(text);
433
402
  const access = `context.get('${text}')`;
434
403
  return kind === "signal" ? `${access}()` : access;
435
404
  }
436
- return `${resolver}.${text}`;
405
+ return text;
437
406
  }
438
407
  /**
439
408
  * Returns true if the subtree rooted at `node` contains at least one
@@ -2909,18 +2878,17 @@ var Parser = class {
2909
2878
  * `TypeChecker` for why) — attribute expressions and event calls are
2910
2879
  * emitted as bare statements, validated in place.
2911
2880
  */
2912
- function typeCheckElement(node, context, index, processNode) {
2881
+ function typeCheckElement(node, processNode) {
2913
2882
  const lines = [];
2914
2883
  node.attributes.forEach(({ value }) => {
2915
- if (typeof value !== "string") lines.push(`${resolveExpression(value.expression, context, { resolver: "root" })};`);
2884
+ if (typeof value !== "string") lines.push(`${resolveExpression(value.expression, { resolver: "root" })};`);
2916
2885
  });
2917
- context.addUnresolvableIdentifier("$event");
2918
2886
  node.events.forEach(({ handler, parameters }) => {
2919
- const args = parameters.map((parameter) => resolveExpression(parameter, context, { resolver: "root" })).join(", ");
2887
+ const args = parameters.map((parameter) => resolveExpression(parameter, { resolver: "root" })).join(", ");
2920
2888
  lines.push(`root.${handler}(${args});`);
2921
2889
  });
2922
2890
  node.children.forEach((child, i) => {
2923
- lines.push(...processNode(child, context, i.toString()));
2891
+ lines.push(...processNode(child));
2924
2892
  });
2925
2893
  return lines;
2926
2894
  }
@@ -2936,31 +2904,22 @@ function typeCheckElement(node, context, index, processNode) {
2936
2904
  * exactly like it would for a loop written by hand — with no synthetic
2937
2905
  * function boundary needed.
2938
2906
  */
2939
- function typeCheckFor(node, context, index, processNode) {
2940
- const iterableExpr = context.hasIdentifier(node.iterableSource) ? node.iterableSource : `root.${node.iterableSource}`;
2907
+ function typeCheckFor(node, processNode) {
2941
2908
  const indexName = resolveImplicit(node, "$index");
2942
2909
  const firstName = resolveImplicit(node, "$first");
2943
2910
  const lastName = resolveImplicit(node, "$last");
2944
2911
  const evenName = resolveImplicit(node, "$even");
2945
2912
  const oddName = resolveImplicit(node, "$odd");
2946
- const forContext = new CompilerContext([
2947
- node.itemAlias,
2948
- [indexName, "signal"],
2949
- [firstName, "signal"],
2950
- [lastName, "signal"],
2951
- [evenName, "signal"],
2952
- [oddName, "signal"]
2953
- ], context);
2954
2913
  const lines = [];
2955
- lines.push(`for (const ${node.itemAlias} of ${iterableExpr}) {`);
2914
+ lines.push(`for (const ${node.itemAlias} of root.${node.iterableSource}) {`);
2956
2915
  lines.push(...indent([
2957
2916
  `let ${indexName}!: number;`,
2958
2917
  `let ${firstName}!: boolean;`,
2959
2918
  `let ${lastName}!: boolean;`,
2960
2919
  `let ${evenName}!: boolean;`,
2961
2920
  `let ${oddName}!: boolean;`,
2962
- `${resolveExpression(node.trackExpression, forContext, { skipResolution: true })};`,
2963
- ...node.children.flatMap((child, i) => processNode(child, forContext, i.toString()))
2921
+ `${resolveExpression(node.trackExpression, { skipResolution: true })};`,
2922
+ ...node.children.flatMap((child, i) => processNode(child))
2964
2923
  ]));
2965
2924
  lines.push("}");
2966
2925
  return lines;
@@ -2993,26 +2952,23 @@ function resolveImplicit(node, implicit) {
2993
2952
  * `else if`, TS already knows the first condition was false) — something
2994
2953
  * flat sibling functions could never express.
2995
2954
  */
2996
- function typeCheckIf(node, context, index, processNode) {
2955
+ function typeCheckIf(node, processNode) {
2997
2956
  const lines = [];
2998
- const condition = resolveExpression(node.conditionNode, context, { resolver: "root" });
2999
- const ifContext = new CompilerContext([], context);
2957
+ const condition = resolveExpression(node.conditionNode, { resolver: "root" });
3000
2958
  lines.push(`if (${condition}) {`);
3001
- lines.push(...indent(node.children.flatMap((child, i) => processNode(child, ifContext, i.toString()))));
2959
+ lines.push(...indent(node.children.flatMap((child) => processNode(child))));
3002
2960
  lines.push("}");
3003
2961
  let alt = node.alternate;
3004
2962
  while (alt?.type === ASTNodeType.ElseIf) {
3005
- const elseIfCondition = resolveExpression(alt.conditionNode, context, { resolver: "root" });
3006
- const elseIfContext = new CompilerContext([], context);
2963
+ const elseIfCondition = resolveExpression(alt.conditionNode, { resolver: "root" });
3007
2964
  lines.push(`else if (${elseIfCondition}) {`);
3008
- lines.push(...indent(alt.children.flatMap((child, i) => processNode(child, elseIfContext, i.toString()))));
2965
+ lines.push(...indent(alt.children.flatMap((child) => processNode(child))));
3009
2966
  lines.push("}");
3010
2967
  alt = alt.alternate;
3011
2968
  }
3012
2969
  if (alt) {
3013
- const elseContext = new CompilerContext([], context);
3014
2970
  lines.push("else {");
3015
- lines.push(...indent(alt.children.flatMap((child, i) => processNode(child, elseContext, i.toString()))));
2971
+ lines.push(...indent(alt.children.flatMap((child) => processNode(child))));
3016
2972
  lines.push("}");
3017
2973
  }
3018
2974
  return lines;
@@ -3034,15 +2990,14 @@ function typeCheckIf(node, context, index, processNode) {
3034
2990
  * emitted as stacked `case` labels sharing that same body, matching real
3035
2991
  * JS/TS fallthrough syntax directly.
3036
2992
  */
3037
- function typeCheckSwitch(node, context, index, processNode) {
3038
- const lines = [`switch (${resolveExpression(node.expression, context, { resolver: "root" })}) {`];
2993
+ function typeCheckSwitch(node, processNode) {
2994
+ const lines = [`switch (${resolveExpression(node.expression, { resolver: "root" })}) {`];
3039
2995
  node.children.forEach((caseNode, i) => {
3040
- const caseContext = new CompilerContext([], context);
3041
2996
  if (caseNode.condition?.length) caseNode.condition.forEach((conditionValue) => {
3042
2997
  lines.push(` case ${conditionValue}:`);
3043
2998
  });
3044
2999
  else lines.push(" default:");
3045
- lines.push(...indent(indent([...caseNode.children.flatMap((child, ci) => processNode(child, caseContext, ci.toString())), "break;"])));
3000
+ lines.push(...indent(indent([...caseNode.children.flatMap((child) => processNode(child)), "break;"])));
3046
3001
  });
3047
3002
  lines.push("}");
3048
3003
  return lines;
@@ -3056,8 +3011,8 @@ function typeCheckSwitch(node, context, index, processNode) {
3056
3011
  * interpolation's expression is emitted as a bare statement — enough for
3057
3012
  * TS to validate it, with no name needing to be bound to the result.
3058
3013
  */
3059
- function typeCheckTextAndInterpolation(node, context, index, processNode) {
3060
- return node.type === ASTNodeType.Interpolation ? [`${resolveExpression(node.expression, context, { resolver: "root" })};`] : [];
3014
+ function typeCheckTextAndInterpolation(node, _processNode) {
3015
+ return node.type === ASTNodeType.Interpolation ? [`${resolveExpression(node.expression, { resolver: "root" })};`] : [];
3061
3016
  }
3062
3017
  //#endregion
3063
3018
  //#region ../packages/compiler/src/type-checker/type-checker.ts
@@ -3107,8 +3062,7 @@ var TypeChecker = class {
3107
3062
  * relevant if the consuming project has `noUnusedLocals` enabled.
3108
3063
  */
3109
3064
  generate() {
3110
- const context = new CompilerContext();
3111
- const body = this._ast.flatMap((node, i) => this._processNode(node, context, i.toString()));
3065
+ const body = this._ast.flatMap((node, i) => this._processNode(node));
3112
3066
  return [
3113
3067
  "function typeCheck() {",
3114
3068
  ...indent(body.some((line) => line.includes("$event")) ? ["let $event!: Event;", ...body] : body),
@@ -3120,10 +3074,10 @@ var TypeChecker = class {
3120
3074
  * back down as `processNode` so state functions can recurse into their
3121
3075
  * own children inline.
3122
3076
  */
3123
- _processNode = (node, context, index) => {
3077
+ _processNode = (node) => {
3124
3078
  const state = this._states[node.type];
3125
3079
  if (!state) throw new Error(`[Type Checker] No transition function for token type ${ASTNodeType[node.type]}`);
3126
- return state(node, context, index, this._processNode);
3080
+ return state(node, this._processNode);
3127
3081
  };
3128
3082
  };
3129
3083
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xaendar/compiler",
3
- "version": "0.7.26",
3
+ "version": "0.7.27",
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.26",
20
- "@xaendar/types": "0.7.26",
19
+ "@xaendar/common": "0.7.27",
20
+ "@xaendar/types": "0.7.27",
21
21
  "typescript": "^6.0.3"
22
22
  }
23
23
  }