@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 +6 -1
- package/Readme.md +1 -0
- package/dist/Compiler.d.ts +1 -0
- package/dist/Compiler.js +37 -0
- package/dist/base-compiler.d.ts +1 -0
- package/dist/impl/blender-compiler.d.ts +1 -0
- package/dist/impl/blender-compiler.js +8 -1
- package/dist/impl/csharp-compiler.d.ts +1 -0
- package/dist/impl/csharp-compiler.js +8 -0
- package/package.json +1 -1
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` |
|
package/dist/Compiler.d.ts
CHANGED
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++) {
|
package/dist/base-compiler.d.ts
CHANGED
|
@@ -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
|
|
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)
|