@needle-tools/needle-component-compiler 3.0.20 → 3.0.21

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/Changelog.md CHANGED
@@ -4,6 +4,11 @@ All notable changes to this package will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [3.0.21] - 2026-09-09
8
+ ### Fixed
9
+ - C# and Blender: skip function-valued fields, including arrow callbacks, even when marked serializable.
10
+ - C# and Blender: resolve intersection types (e.g. `Material & Custom`) to the first known type from left to right; skip fields when none is known.
11
+
7
12
  ## [3.0.20] - 2026-05-05
8
13
  ### Changed
9
14
  - Fields without `@serializable()` decorator (or `//@serializable` / `//@serializeField` comment directive) are no longer emitted in C# or Blender output. This prevents unresolvable types (e.g. `article: Article | undefined = undefined`) from producing compile errors in generated stubs.
@@ -256,4 +261,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
256
261
  - add mesh and texture types
257
262
 
258
263
  ## [1.0.0] - 2022-04-22
259
- - initial release
264
+ - initial release
package/Readme.md CHANGED
@@ -70,6 +70,7 @@ Use `//` comments above classes, fields, or methods to control code generation:
70
70
  | `@abstract` | Class | Mark the generated class as `abstract` |
71
71
  | `@serializeField` | Field | Emit `[UnityEngine.SerializeField]` attribute |
72
72
  | `@nonSerialized` | Field / Method | Skip generating C# code for this member |
73
+ | `@header "My text"` | Field | Emit `[UnityEngine.Header("My text")]` (C# only) |
73
74
  | `@tooltip "My text"` | Field | Emit `[UnityEngine.Tooltip("My text")]` (C#) or `"description"` (Blender) |
74
75
  | `@contextmenu "Label"` | Method | Emit `[UnityEngine.ContextMenu("Label")]` |
75
76
  | `@ifdef MY_DEFINE` | Field | Wrap field in `#if MY_DEFINE` / `#endif` |
@@ -22,6 +22,7 @@ export declare class Compiler {
22
22
  private tryResolveTypeFromExpression;
23
23
  private resolveType;
24
24
  private resolveTypeFromString;
25
+ private resolveKnownIntersectionType;
25
26
  private isArrayType;
26
27
  private resolveExpression;
27
28
  }
package/dist/Compiler.js CHANGED
@@ -127,6 +127,15 @@ var Compiler = /** @class */ (function () {
127
127
  };
128
128
  Compiler.prototype.visitPropertyDeclaration = function (node, writer) {
129
129
  var _a;
130
+ // Function-valued properties are runtime callbacks, not serialized fields.
131
+ var initializer = node.initializer;
132
+ while (initializer && ts.isParenthesizedExpression(initializer)) {
133
+ initializer = initializer.expression;
134
+ }
135
+ if ((initializer && (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer))) ||
136
+ (node.type && ts.isFunctionTypeNode(node.type))) {
137
+ return;
138
+ }
130
139
  // Skip static and abstract properties — they don't map to serialized fields
131
140
  if (node.modifiers) {
132
141
  for (var _i = 0, _b = node.modifiers; _i < _b.length; _i++) {
@@ -343,6 +352,12 @@ var Compiler = /** @class */ (function () {
343
352
  Compiler.prototype.resolveType = function (typeNode, writer) {
344
353
  if (!typeNode)
345
354
  return undefined;
355
+ if (ts.isParenthesizedTypeNode(typeNode)) {
356
+ return this.resolveType(typeNode.type, writer);
357
+ }
358
+ if (ts.isIntersectionTypeNode(typeNode)) {
359
+ return this.resolveKnownIntersectionType(typeNode, writer);
360
+ }
346
361
  // check if its an array
347
362
  if (this.isArrayType(typeNode)) {
348
363
  // Unwrap union types (e.g. Texture[] | null) to find the array member
@@ -435,9 +450,31 @@ var Compiler = /** @class */ (function () {
435
450
  var resolved = writer.resolveNeedleTypeName(type);
436
451
  return resolved || type;
437
452
  };
453
+ Compiler.prototype.resolveKnownIntersectionType = function (node, writer) {
454
+ if (ts.isParenthesizedTypeNode(node)) {
455
+ return this.resolveKnownIntersectionType(node.type, writer);
456
+ }
457
+ if (ts.isIntersectionTypeNode(node)) {
458
+ for (var _i = 0, _a = node.types; _i < _a.length; _i++) {
459
+ var member = _a[_i];
460
+ var resolved = this.resolveKnownIntersectionType(member, writer);
461
+ if (resolved)
462
+ return resolved;
463
+ }
464
+ return undefined;
465
+ }
466
+ // Do not use resolveTypeFromString: its fallback preserves unknown TS types.
467
+ var name = ts.isTypeReferenceNode(node) ? node.typeName.getText() : node.getText();
468
+ return writer.resolveKnownTypeName
469
+ ? writer.resolveKnownTypeName(name)
470
+ : writer.resolveNeedleTypeName(name) || undefined;
471
+ };
438
472
  Compiler.prototype.isArrayType = function (typeNode) {
439
473
  if (!typeNode)
440
474
  return false;
475
+ if (ts.isParenthesizedTypeNode(typeNode)) {
476
+ return this.isArrayType(typeNode.type);
477
+ }
441
478
  // Unwrap union types (e.g. Texture[] | null → Texture[])
442
479
  if (ts.isUnionTypeNode(typeNode)) {
443
480
  for (var _i = 0, _a = typeNode.types; _i < _a.length; _i++) {
@@ -45,6 +45,7 @@ export interface IWriter {
45
45
  get outputInfo(): TypeSourceInformation;
46
46
  begin(filePath: string | null): void;
47
47
  resolveNeedleTypeName(typescriptTypeName: string, baseTypes?: string[]): string | void;
48
+ resolveKnownTypeName?(typescriptTypeName: string): string | undefined;
48
49
  end(filePath: string | null): void;
49
50
  startNewType(filePath: string | null, typeName: string, baseType: string[], comments?: string[]): void | boolean;
50
51
  endNewType(filePath: string | null, typeName: string): void;
@@ -2,6 +2,7 @@ import { Visibility } from "../base-compiler";
2
2
  import { BaseWriter } from "../BaseWriter";
3
3
  export declare class BlenderWriter extends BaseWriter {
4
4
  resolveNeedleTypeName(typeName: string, comments?: string[]): string | void;
5
+ resolveKnownTypeName(typeName: string): string | undefined;
5
6
  startNewType(filePath: string | null, typeName: string, baseTypes: string[], comments?: string[]): void | boolean;
6
7
  endNewType(filePath: string | null, typeName: string): void;
7
8
  writeMember(visibility: Visibility, name: string, isArray: boolean, type: string, initialValue?: string, comments?: string[]): void;
@@ -27,6 +27,13 @@ var BlenderWriter = /** @class */ (function (_super) {
27
27
  return _super !== null && _super.apply(this, arguments) || this;
28
28
  }
29
29
  BlenderWriter.prototype.resolveNeedleTypeName = function (typeName, comments) {
30
+ var known = this.resolveKnownTypeName(typeName);
31
+ if (known)
32
+ return known;
33
+ typeName = typeName.toLocaleLowerCase();
34
+ return typeName.startsWith("three.") ? typeName.substring("three.".length) : typeName;
35
+ };
36
+ BlenderWriter.prototype.resolveKnownTypeName = function (typeName) {
30
37
  typeName = typeName.toLocaleLowerCase();
31
38
  if (typeName.startsWith("three."))
32
39
  typeName = typeName.substring("three.".length);
@@ -104,7 +111,7 @@ var BlenderWriter = /** @class */ (function (_super) {
104
111
  case "timelineasset":
105
112
  return "timeline";
106
113
  }
107
- return typeName;
114
+ return undefined;
108
115
  };
109
116
  BlenderWriter.prototype.startNewType = function (filePath, typeName, baseTypes, comments) {
110
117
  if (comments === null || comments === void 0 ? void 0 : comments.includes("@dont-generate-component"))
@@ -4,6 +4,7 @@ export declare class CSharpWriter extends BaseWriter {
4
4
  private externalTypes;
5
5
  constructor(sink?: ISink, externalTypes?: Record<string, string>);
6
6
  resolveNeedleTypeName(typescriptTypeName: string): string | void;
7
+ resolveKnownTypeName(typeName: string): string | undefined;
7
8
  /** Tries to resolve a C# type name; returns undefined if the type is not known.
8
9
  * Checks TYPE_MAP keys/values and the enum registry. */
9
10
  resolveKnownCSharpTypeName(typeName: string): string | undefined;
@@ -148,6 +148,9 @@ var CSharpWriter = /** @class */ (function (_super) {
148
148
  return typescriptTypeName;
149
149
  return (_e = (_c = (_b = this.externalTypes) === null || _b === void 0 ? void 0 : _b[typescriptTypeName]) !== null && _c !== void 0 ? _c : (_d = this.externalTypes) === null || _d === void 0 ? void 0 : _d[stripped]) !== null && _e !== void 0 ? _e : typescriptTypeName;
150
150
  };
151
+ CSharpWriter.prototype.resolveKnownTypeName = function (typeName) {
152
+ return this.resolveKnownCSharpTypeName(typeName);
153
+ };
151
154
  /** Tries to resolve a C# type name; returns undefined if the type is not known.
152
155
  * Checks TYPE_MAP keys/values and the enum registry. */
153
156
  CSharpWriter.prototype.resolveKnownCSharpTypeName = function (typeName) {
@@ -230,6 +233,9 @@ var CSharpWriter = /** @class */ (function (_super) {
230
233
  }
231
234
  // @serializeField → add attribute + force private becomes serialized
232
235
  var serializeField = comments === null || comments === void 0 ? void 0 : comments.some(function (c) { return c.startsWith("@serializeField") || c.startsWith("@serializable"); });
236
+ // @header
237
+ var headerComment = comments === null || comments === void 0 ? void 0 : comments.find(function (c) { return c.startsWith("@header "); });
238
+ var header = headerComment ? headerComment.substring("@header ".length).trim().replace(/^["']|["']$/g, "") : null;
233
239
  // @tooltip
234
240
  var tooltipComment = comments === null || comments === void 0 ? void 0 : comments.find(function (c) { return c.startsWith("@tooltip "); });
235
241
  var tooltip = tooltipComment ? tooltipComment.substring("@tooltip ".length).trim().replace(/^["']|["']$/g, "") : null;
@@ -302,6 +308,8 @@ var CSharpWriter = /** @class */ (function (_super) {
302
308
  if (needsEditorWrap)
303
309
  this.writer.writeLine("#if UNITY_EDITOR");
304
310
  // Emit attributes
311
+ if (header)
312
+ this.writer.writeLine("[UnityEngine.Header(\"".concat(header, "\")]"));
305
313
  if (tooltip)
306
314
  this.writer.writeLine("[UnityEngine.Tooltip(\"".concat(tooltip, "\")]"));
307
315
  if (contextMenu)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/needle-component-compiler",
3
- "version": "3.0.20",
3
+ "version": "3.0.21",
4
4
  "description": "Compile Editor components for Needle Engine for C# and Blender",
5
5
  "main": "dist/index.js",
6
6
  "bin": "dist/cli.js",