@needle-tools/needle-component-compiler 3.0.0-alpha → 3.0.0-alpha.1
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 +45 -0
- package/Readme.md +46 -19
- package/dist/Compiler.js +2 -1
- package/dist/component-compiler.js +150 -38
- package/dist/impl/csharp-compiler.js +1 -0
- package/package.json +6 -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.0-alpha.1] - 2026-03-02
|
|
8
|
+
- Fix: destructured method parameters (e.g. `{xr}`) now emit as `object @obj` instead of invalid `object @{xr}`
|
|
9
|
+
- Fix: `Object3D` type now correctly maps to `UnityEngine.Transform`
|
|
10
|
+
- Add: `RectTransform` type mapping to `UnityEngine.RectTransform`
|
|
11
|
+
|
|
7
12
|
## [2.4.1-pre] - 2023-04-03
|
|
8
13
|
# Blender compiler
|
|
9
14
|
- Add: typenames
|
|
@@ -24,6 +29,46 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
24
29
|
## [2.1.0-pre] - 2022-11-12
|
|
25
30
|
- Add blender scheme compiler for creating and updating schemes (or removing them when the component gets deleted)
|
|
26
31
|
|
|
32
|
+
## [1.12.2] - 2025-06-06
|
|
33
|
+
- Fix: Private fields decorated with `@serializable()` should be annotated with `UnityEngine.SerializeField`
|
|
34
|
+
- Fix: Comment for `// @serializeField` should not affect subsequent fields
|
|
35
|
+
|
|
36
|
+
## [1.12.0] - 2025-06-02
|
|
37
|
+
- Add: Support to serialize unknown classes when annotated with `// @type object`
|
|
38
|
+
|
|
39
|
+
## [1.11.2] - 2023-12-16
|
|
40
|
+
- Fix: property setter emitting invalid C# code
|
|
41
|
+
|
|
42
|
+
## [1.11.1] - 2023-12-02
|
|
43
|
+
- Fix: Use Unity AnimatorController type
|
|
44
|
+
- Fix: method inline anonymous type declaration (e.g. `myMethod(arg: {x:number})`)
|
|
45
|
+
|
|
46
|
+
## [1.11.0] - 2023-11-18
|
|
47
|
+
- Add: support to wrap fields with `#if UNITY_EDITOR` if their namespace contains UnityEditor
|
|
48
|
+
- Add: more threejs types to generate Unity Material fields for
|
|
49
|
+
|
|
50
|
+
## [1.10.3] - 2023-09-08
|
|
51
|
+
- Add: Needle Engine type `RGBAColor` is now automatically emitted as `UnityEngine.Color`
|
|
52
|
+
|
|
53
|
+
## [1.10.2] - 2023-09-08
|
|
54
|
+
- Fix: `@type` was not properly applied for `new expression` cases (e.g. `new RGBAColor` should produce a `new Color` when decorated with `@type Color`)
|
|
55
|
+
|
|
56
|
+
## [1.10.1] - 2023-08-02
|
|
57
|
+
- Add: use `@tooltip` to emit a UnityEngine.Tooltip
|
|
58
|
+
- Update Readme
|
|
59
|
+
|
|
60
|
+
## [1.9.4] - 2023-05-24
|
|
61
|
+
- Change: `Object3D` now emits `GameObject` field instead of `Transform`
|
|
62
|
+
- Fix: ignore `static` methods
|
|
63
|
+
- Fix: ignore `abstract` methods
|
|
64
|
+
|
|
65
|
+
## [1.9.3] - 2022-12-30
|
|
66
|
+
- Add debug logs for when no file or target directory was passed in. Also wrapping core with try catch
|
|
67
|
+
|
|
68
|
+
## [1.9.2] - 2022-11-29
|
|
69
|
+
- Fix codegen deleting code added manually outside of codegen sections
|
|
70
|
+
- Fix codegen creating output directory if it does not exist yet
|
|
71
|
+
|
|
27
72
|
## [1.9.1] - 2022-11-05
|
|
28
73
|
- Fix ``new Vector2(1, .5)`` generating invalid C# where number arguments were emitted as double instead of float
|
|
29
74
|
|
package/Readme.md
CHANGED
|
@@ -1,19 +1,46 @@
|
|
|
1
|
-
##
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
## Needle Engine Component Compiler
|
|
2
|
+
|
|
3
|
+
Compiles TypeScript component definitions into **Unity C#** component stubs and **Blender** Python component schemas for Needle Engine.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
npm install @needle-tools/needle-component-compiler
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
### Supported TypeScript Features
|
|
10
|
+
|
|
11
|
+
- Classes extending `Behaviour`, `MonoBehaviour`, or implementing `IComponent`
|
|
12
|
+
- Public, protected, and private fields with type annotations
|
|
13
|
+
- Default values (primitives, `new` expressions, literals)
|
|
14
|
+
- Array types: `T[]`, `Array<T>`
|
|
15
|
+
- Union types (nullable types like `Object3D | null` resolve to the concrete type)
|
|
16
|
+
- Enums (with value initialization)
|
|
17
|
+
- Methods with parameters and return types
|
|
18
|
+
- Destructured parameters (compiled as `object`)
|
|
19
|
+
|
|
20
|
+
### Comment Directives
|
|
21
|
+
|
|
22
|
+
Use `//` comments above classes, fields, or methods to control code generation:
|
|
23
|
+
|
|
24
|
+
| Directive | Target | Description |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `@generate-component` | Class | Force generation (not required, classes are generated by default) |
|
|
27
|
+
| `@dont-generate-component` | Class | Skip generating this class entirely |
|
|
28
|
+
| `@type MyNamespace.MyType` | Class / Field | Override the resolved C# type or base class |
|
|
29
|
+
| `@abstract` | Class | Mark the generated class as `abstract` |
|
|
30
|
+
| `@serializeField` | Field | Emit `[UnityEngine.SerializeField]` attribute |
|
|
31
|
+
| `@nonSerialized` | Field / Method | Skip generating C# code for this member |
|
|
32
|
+
| `@tooltip "My text"` | Field | Emit `[UnityEngine.Tooltip("My text")]` |
|
|
33
|
+
| `@contextmenu "Label"` | Method | Emit `[UnityEngine.ContextMenu("Label")]` |
|
|
34
|
+
| `@ifdef MY_DEFINE` | Field | Wrap field in `#if MY_DEFINE` / `#endif` |
|
|
35
|
+
|
|
36
|
+
### Codegen Fences
|
|
37
|
+
|
|
38
|
+
Generated C# files are wrapped in `// NEEDLE_CODEGEN_START` and `// NEEDLE_CODEGEN_END` markers. This allows you to add custom code outside the fences that will be preserved when the file is regenerated.
|
|
39
|
+
|
|
40
|
+
# Contact ✒️
|
|
41
|
+
<b>[🌵 Needle](https://needle.tools)</b> •
|
|
42
|
+
[Github](https://github.com/needle-tools) •
|
|
43
|
+
[Twitter](https://twitter.com/NeedleTools) •
|
|
44
|
+
[Discord](https://discord.needle.tools) •
|
|
45
|
+
[Forum](https://forum.needle.tools) •
|
|
46
|
+
[Youtube](https://youtube.com/@needle-tools)
|
package/dist/Compiler.js
CHANGED
|
@@ -145,7 +145,8 @@ var Compiler = /** @class */ (function () {
|
|
|
145
145
|
var result = [];
|
|
146
146
|
for (var _i = 0, parameters_1 = parameters; _i < parameters_1.length; _i++) {
|
|
147
147
|
var parameter = parameters_1[_i];
|
|
148
|
-
|
|
148
|
+
// Destructured parameters (e.g. { xr }) get a generic name
|
|
149
|
+
var name_1 = ts.isObjectBindingPattern(parameter.name) ? "obj" : parameter.name.getText();
|
|
149
150
|
var type = this.resolveType(parameter.type, writer);
|
|
150
151
|
var defaultValue = parameter.initializer && this.resolveExpression(parameter.initializer, writer);
|
|
151
152
|
result.push({ name: name_1, type: type, defaultValue: defaultValue });
|
|
@@ -75,14 +75,22 @@ var ExportContext = /** @class */ (function () {
|
|
|
75
75
|
this.classEnd = -1;
|
|
76
76
|
this.indentLevel = 0;
|
|
77
77
|
this.emitMethodContextMenu = null;
|
|
78
|
+
this.emitTooltip = null;
|
|
78
79
|
this.outputDir = outputDir;
|
|
79
80
|
this.fileName = fileName;
|
|
80
81
|
this.reset();
|
|
81
82
|
}
|
|
83
|
+
ExportContext.prototype.onBeforeField = function (name) {
|
|
84
|
+
if (this.emitTooltip) {
|
|
85
|
+
this.appendLine("[UnityEngine.Tooltip(\"" + this.emitTooltip.trim().replace("\"", "'") + "\")]");
|
|
86
|
+
this.emitTooltip = undefined;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
82
89
|
ExportContext.prototype.onBeforeMethod = function (name) {
|
|
83
90
|
if (this.emitMethodContextMenu !== undefined) {
|
|
84
91
|
var contextMenuText = this.emitMethodContextMenu === null ? name : this.emitMethodContextMenu;
|
|
85
92
|
this.appendLine("[UnityEngine.ContextMenu(\"" + contextMenuText + "\")]");
|
|
93
|
+
this.emitMethodContextMenu = undefined;
|
|
86
94
|
}
|
|
87
95
|
};
|
|
88
96
|
ExportContext.prototype.append = function (text) {
|
|
@@ -95,18 +103,25 @@ var ExportContext = /** @class */ (function () {
|
|
|
95
103
|
this.append(text + "\n");
|
|
96
104
|
};
|
|
97
105
|
ExportContext.prototype.flush = function () {
|
|
98
|
-
if (this.textBuffer.length <= 0)
|
|
106
|
+
if (this.textBuffer.length <= 0) {
|
|
99
107
|
return;
|
|
108
|
+
}
|
|
100
109
|
this.textBuffer = CODEGEN_MARKER_START + "\n" + this.textBuffer + "\n" + CODEGEN_MARKER_END;
|
|
101
110
|
var code = this.textBuffer;
|
|
102
111
|
if (this.outputDir !== null) {
|
|
112
|
+
if (!fs.existsSync(this.outputDir))
|
|
113
|
+
fs.mkdirSync(this.outputDir);
|
|
103
114
|
var dir = this.outputDir + "/";
|
|
104
115
|
var path_1 = dir + this.fileName;
|
|
105
|
-
this.replaceGeneratedCodeSection(path_1);
|
|
116
|
+
code = this.replaceGeneratedCodeSection(path_1, code);
|
|
106
117
|
if (allowDebugLogs)
|
|
107
118
|
console.log("Write to " + path_1);
|
|
108
119
|
fs.writeFileSync(path_1, code);
|
|
109
120
|
}
|
|
121
|
+
else {
|
|
122
|
+
if (allowDebugLogs)
|
|
123
|
+
console.log("No output dir specified");
|
|
124
|
+
}
|
|
110
125
|
this.reset();
|
|
111
126
|
return code;
|
|
112
127
|
};
|
|
@@ -114,7 +129,7 @@ var ExportContext = /** @class */ (function () {
|
|
|
114
129
|
this.textBuffer = "";
|
|
115
130
|
this.classEnd = -1;
|
|
116
131
|
};
|
|
117
|
-
ExportContext.prototype.replaceGeneratedCodeSection = function (path) {
|
|
132
|
+
ExportContext.prototype.replaceGeneratedCodeSection = function (path, code) {
|
|
118
133
|
if (fs.existsSync(path)) {
|
|
119
134
|
var existing = fs.readFileSync(path, "utf8");
|
|
120
135
|
var regex = new RegExp("(?<before>.*?)\/\/ ?NEEDLE_CODEGEN_START.+\/\/ ?NEEDLE_CODEGEN_END(?<after>.*)", "s");
|
|
@@ -124,9 +139,10 @@ var ExportContext = /** @class */ (function () {
|
|
|
124
139
|
console.log("Found codegen sections");
|
|
125
140
|
var before_1 = matches.groups.before;
|
|
126
141
|
var after_1 = matches.groups.after;
|
|
127
|
-
|
|
142
|
+
return before_1 + code + after_1;
|
|
128
143
|
}
|
|
129
144
|
}
|
|
145
|
+
return code;
|
|
130
146
|
};
|
|
131
147
|
return ExportContext;
|
|
132
148
|
}());
|
|
@@ -154,7 +170,7 @@ function run(program, outputDir, sourceFile) {
|
|
|
154
170
|
}
|
|
155
171
|
return results;
|
|
156
172
|
function visit(node) {
|
|
157
|
-
var _a, _b, _c, _d, _e, _f;
|
|
173
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
158
174
|
var context = contexts.length > 0 ? contexts[contexts.length - 1] : null;
|
|
159
175
|
if (context) {
|
|
160
176
|
if ((context === null || context === void 0 ? void 0 : context.classEnd) > 0 && node.pos >= (context === null || context === void 0 ? void 0 : context.classEnd)) {
|
|
@@ -179,12 +195,21 @@ function run(program, outputDir, sourceFile) {
|
|
|
179
195
|
continue;
|
|
180
196
|
commentStarts.push(r.pos);
|
|
181
197
|
var comment = node.getSourceFile().getFullText().slice(r.pos, r.end);
|
|
198
|
+
if (allowDebugLogs)
|
|
199
|
+
console.log(comment);
|
|
182
200
|
if (context) {
|
|
183
201
|
// https://regex101.com/r/ud4oev/1
|
|
184
|
-
var emitContextMenu = comment.match("(\/{2,}|\/\*)
|
|
202
|
+
var emitContextMenu = comment.match("(\/{2,}|\/\*) {0,}@contextmenu {1,}(?<text>[a-zA-Z 0-9]+)?");
|
|
185
203
|
if (emitContextMenu) {
|
|
186
204
|
context.emitMethodContextMenu = (_b = (_a = emitContextMenu.groups) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : null;
|
|
187
205
|
}
|
|
206
|
+
// https://regex101.com/r/Sa6Q8T/3
|
|
207
|
+
var emitTooltip = comment.match("\/{2,} {0,}(@tooltip) *?(?<text>.+)");
|
|
208
|
+
if (emitTooltip) {
|
|
209
|
+
if (allowDebugLogs)
|
|
210
|
+
console.log((_c = emitTooltip.groups) === null || _c === void 0 ? void 0 : _c.text);
|
|
211
|
+
context.emitTooltip = (_e = (_d = emitTooltip.groups) === null || _d === void 0 ? void 0 : _d.text) !== null && _e !== void 0 ? _e : null;
|
|
212
|
+
}
|
|
188
213
|
else if (comment.includes(serializeCommand))
|
|
189
214
|
serializeField = true;
|
|
190
215
|
else if (comment.includes(dontSerializeCommand))
|
|
@@ -227,8 +252,6 @@ function run(program, outputDir, sourceFile) {
|
|
|
227
252
|
// case ts.SyntaxKind.SingleLineCommentTrivia:
|
|
228
253
|
// console.log("comment: " + node.getText())
|
|
229
254
|
// break;
|
|
230
|
-
case ts.SyntaxKind.Decorator:
|
|
231
|
-
break;
|
|
232
255
|
case ts.SyntaxKind.MethodDeclaration:
|
|
233
256
|
lastTypeFound = null;
|
|
234
257
|
serializeField = false;
|
|
@@ -240,12 +263,12 @@ function run(program, outputDir, sourceFile) {
|
|
|
240
263
|
var meth = node;
|
|
241
264
|
// const isCoroutine = func.asteriskToken;
|
|
242
265
|
if (!skip && meth.name) {
|
|
243
|
-
var pub_1 =
|
|
266
|
+
var pub_1 = shouldEmitMethod(meth);
|
|
244
267
|
if (!pub_1)
|
|
245
268
|
return;
|
|
246
269
|
var paramsStr = "";
|
|
247
|
-
for (var
|
|
248
|
-
var param =
|
|
270
|
+
for (var _k = 0, _l = meth.parameters; _k < _l.length; _k++) {
|
|
271
|
+
var param = _l[_k];
|
|
249
272
|
if (!param || !param.name)
|
|
250
273
|
continue;
|
|
251
274
|
if (paramsStr.length > 0)
|
|
@@ -253,7 +276,17 @@ function run(program, outputDir, sourceFile) {
|
|
|
253
276
|
var type = tryResolveTypeRecursive(param);
|
|
254
277
|
if (type === undefined)
|
|
255
278
|
type = "object";
|
|
256
|
-
|
|
279
|
+
var paramName = "";
|
|
280
|
+
var paramNameKind = param.name.kind;
|
|
281
|
+
switch (paramNameKind) {
|
|
282
|
+
case ts.SyntaxKind.ObjectBindingPattern:
|
|
283
|
+
paramName = "obj";
|
|
284
|
+
break;
|
|
285
|
+
default:
|
|
286
|
+
paramName = param.name.getText();
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
paramsStr += type + " @" + paramName;
|
|
257
290
|
}
|
|
258
291
|
var methodName = meth.name.getText();
|
|
259
292
|
switch (methodName) {
|
|
@@ -275,21 +308,24 @@ function run(program, outputDir, sourceFile) {
|
|
|
275
308
|
if (!context)
|
|
276
309
|
break;
|
|
277
310
|
if (allowDebugLogs)
|
|
278
|
-
console.log("Found variable", node.getText());
|
|
311
|
+
console.log("Found variable", ts.SyntaxKind[node.kind], "\n", node.getText());
|
|
279
312
|
var vardec = node;
|
|
280
313
|
var varName = "@" + vardec.name.getText();
|
|
281
|
-
var pub =
|
|
314
|
+
var pub = shouldEmitMethod(vardec);
|
|
282
315
|
var visibility = pub ? "public" : "private";
|
|
283
316
|
var isAccessible = pub;
|
|
284
|
-
|
|
317
|
+
if (!pub)
|
|
318
|
+
serializeField || (serializeField = testIsMarkedWithSerializable(node));
|
|
285
319
|
if (serializeField) {
|
|
286
320
|
if (allowDebugLogs)
|
|
287
|
-
console.log("[SerializeField]");
|
|
321
|
+
console.log("Emit [UnityEngine.SerializeField]");
|
|
288
322
|
context.appendLine("[UnityEngine.SerializeField]");
|
|
289
323
|
isAccessible = true;
|
|
290
324
|
}
|
|
291
325
|
else if (skip)
|
|
292
326
|
isAccessible = false;
|
|
327
|
+
dontSerialize = false;
|
|
328
|
+
serializeField = false;
|
|
293
329
|
if (!isAccessible) {
|
|
294
330
|
if (allowDebugLogs)
|
|
295
331
|
console.log("Skip because not public or serializeable");
|
|
@@ -302,21 +338,21 @@ function run(program, outputDir, sourceFile) {
|
|
|
302
338
|
break;
|
|
303
339
|
var typeString = lastTypeFound !== null && lastTypeFound !== void 0 ? lastTypeFound : tryResolveTypeRecursive(node);
|
|
304
340
|
var postFix = "";
|
|
305
|
-
var typeName = (
|
|
341
|
+
var typeName = (_f = vardec.type) === null || _f === void 0 ? void 0 : _f.getText();
|
|
306
342
|
var shouldCommentTheLine = typeString === undefined;
|
|
307
343
|
if (typeString === undefined) {
|
|
308
344
|
postFix = " → Could not resolve C# type";
|
|
309
345
|
}
|
|
310
346
|
var assignment = "";
|
|
311
347
|
if (typeString !== undefined) {
|
|
312
|
-
for (var
|
|
313
|
-
var ch =
|
|
348
|
+
for (var _m = 0, _o = node.getChildren(); _m < _o.length; _m++) {
|
|
349
|
+
var ch = _o[_m];
|
|
314
350
|
switch (ch.kind) {
|
|
315
351
|
default:
|
|
316
352
|
// console.log("Unknown assignment:", ts.SyntaxKind[ch.kind]);
|
|
317
353
|
break;
|
|
318
354
|
case ts.SyntaxKind.NewExpression:
|
|
319
|
-
assignment = " = " + getTypeForAssignment(ch);
|
|
355
|
+
assignment = " = " + getTypeForAssignment(ch, typeString);
|
|
320
356
|
break;
|
|
321
357
|
case ts.SyntaxKind.FalseKeyword:
|
|
322
358
|
case ts.SyntaxKind.TrueKeyword:
|
|
@@ -356,10 +392,18 @@ function run(program, outputDir, sourceFile) {
|
|
|
356
392
|
// assignment = " = new object[0]";
|
|
357
393
|
shouldCommentTheLine = true;
|
|
358
394
|
}
|
|
395
|
+
context.onBeforeField(varName);
|
|
359
396
|
if (allowDebugLogs)
|
|
360
397
|
console.log("EMIT member: \"" + typeString + "\" " + varName, assignment, "Last type found:", lastTypeFound);
|
|
361
398
|
var prefix = shouldCommentTheLine ? "// " : "";
|
|
399
|
+
var isUnityEditorType = typeString === null || typeString === void 0 ? void 0 : typeString.includes("UnityEditor");
|
|
400
|
+
if (isUnityEditorType) {
|
|
401
|
+
context.appendLine("#if UNITY_EDITOR");
|
|
402
|
+
}
|
|
362
403
|
context.append(prefix + visibility + " " + typeString + " " + varName + assignment + ";" + postFix + "\n");
|
|
404
|
+
if (isUnityEditorType) {
|
|
405
|
+
context.appendLine("#endif");
|
|
406
|
+
}
|
|
363
407
|
lastTypeFound = null;
|
|
364
408
|
if (requireEndIf) {
|
|
365
409
|
context.appendLine("#endif");
|
|
@@ -367,15 +411,16 @@ function run(program, outputDir, sourceFile) {
|
|
|
367
411
|
break;
|
|
368
412
|
case ts.SyntaxKind.ClassDeclaration:
|
|
369
413
|
serializeField = false;
|
|
414
|
+
dontSerialize = false;
|
|
370
415
|
var dec = node;
|
|
371
416
|
// a class must inherit a component
|
|
372
417
|
var inheritsComponent = testInheritsComponent(node);
|
|
373
418
|
if (!dontExportNextClass && (lastTypeFound || exportNextClass || inheritsComponent)) {
|
|
374
419
|
resetExportNextClass();
|
|
375
|
-
var name_2 = (
|
|
420
|
+
var name_2 = (_g = dec.name) === null || _g === void 0 ? void 0 : _g.escapedText;
|
|
376
421
|
if (allowDebugLogs)
|
|
377
422
|
console.log("Found class: ", name_2);
|
|
378
|
-
var namespace = (
|
|
423
|
+
var namespace = (_h = tryParseNamespace(node)) !== null && _h !== void 0 ? _h : "Needle.Typescript.GeneratedComponents";
|
|
379
424
|
if (allowDebugLogs)
|
|
380
425
|
console.log("NAMESPACE", namespace);
|
|
381
426
|
var newContext = new ExportContext(outputDir, name_2 + ".cs");
|
|
@@ -396,8 +441,8 @@ function run(program, outputDir, sourceFile) {
|
|
|
396
441
|
console.log(name_2 + " inherits " + typeName_1);
|
|
397
442
|
var modifiers = "";
|
|
398
443
|
if (dec.modifiers) {
|
|
399
|
-
for (var
|
|
400
|
-
var mod =
|
|
444
|
+
for (var _p = 0, _q = dec.modifiers; _p < _q.length; _p++) {
|
|
445
|
+
var mod = _q[_p];
|
|
401
446
|
switch (mod.getText()) {
|
|
402
447
|
case "abstract":
|
|
403
448
|
modifiers += " abstract";
|
|
@@ -408,6 +453,10 @@ function run(program, outputDir, sourceFile) {
|
|
|
408
453
|
}
|
|
409
454
|
}
|
|
410
455
|
modifiers += " partial";
|
|
456
|
+
// If it's a custom class and decorated with @type object then we want to make it serializable
|
|
457
|
+
if (typeName_1 === "object") {
|
|
458
|
+
newContext.appendLine("[System.Serializable]");
|
|
459
|
+
}
|
|
411
460
|
newContext.appendLine("public " + modifiers.trim() + " class " + name_2 + " : " + typeName_1);
|
|
412
461
|
newContext.appendLine("{");
|
|
413
462
|
newContext.indentLevel += 1;
|
|
@@ -416,11 +465,27 @@ function run(program, outputDir, sourceFile) {
|
|
|
416
465
|
}
|
|
417
466
|
else {
|
|
418
467
|
if (allowDebugLogs)
|
|
419
|
-
console.log("Class type is unknown and will not generate a component: ", (
|
|
468
|
+
console.log("Class type is unknown and will not generate a component: ", (_j = dec.name) === null || _j === void 0 ? void 0 : _j.escapedText);
|
|
420
469
|
}
|
|
421
470
|
lastTypeFound = null;
|
|
422
471
|
break;
|
|
423
472
|
}
|
|
473
|
+
function testIsMarkedWithSerializable(node) {
|
|
474
|
+
if (node.kind === ts.SyntaxKind.Decorator) {
|
|
475
|
+
// If a field is decorated with @serializable then we want to serialize it
|
|
476
|
+
var name_3 = node.getText();
|
|
477
|
+
if (name_3.startsWith("@serializable(")) {
|
|
478
|
+
// if(allowDebugLogs) console.log("Found @serializable decorator");
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
for (var _i = 0, _a = node.getChildren(); _i < _a.length; _i++) {
|
|
483
|
+
var ch = _a[_i];
|
|
484
|
+
if (testIsMarkedWithSerializable(ch))
|
|
485
|
+
return true;
|
|
486
|
+
}
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
424
489
|
function testInheritsComponent(node) {
|
|
425
490
|
switch (node.kind) {
|
|
426
491
|
case ts.SyntaxKind.ClassDeclaration:
|
|
@@ -449,7 +514,7 @@ function run(program, outputDir, sourceFile) {
|
|
|
449
514
|
}
|
|
450
515
|
return false;
|
|
451
516
|
}
|
|
452
|
-
function getTypeForAssignment(node) {
|
|
517
|
+
function getTypeForAssignment(node, typeString) {
|
|
453
518
|
// console.log("-------------------\nAssign", ts.SyntaxKind[node.kind]);
|
|
454
519
|
switch (node.kind) {
|
|
455
520
|
case ts.SyntaxKind.FirstLiteralToken:
|
|
@@ -460,7 +525,8 @@ function run(program, outputDir, sourceFile) {
|
|
|
460
525
|
for (var _i = 0, _a = node.getChildren(); _i < _a.length; _i++) {
|
|
461
526
|
var ch = _a[_i];
|
|
462
527
|
var text = ch.getText();
|
|
463
|
-
|
|
528
|
+
if (allowDebugLogs)
|
|
529
|
+
console.log("child", ts.SyntaxKind[ch.kind], text);
|
|
464
530
|
switch (ch.kind) {
|
|
465
531
|
case ts.SyntaxKind.Identifier:
|
|
466
532
|
case ts.SyntaxKind.PropertyAccessExpression:
|
|
@@ -471,7 +537,7 @@ function run(program, outputDir, sourceFile) {
|
|
|
471
537
|
var arg = _c[_b];
|
|
472
538
|
if (args === undefined)
|
|
473
539
|
args = "";
|
|
474
|
-
var res = getTypeForAssignment(arg);
|
|
540
|
+
var res = getTypeForAssignment(arg, typeString);
|
|
475
541
|
// handle floats being assigned with "f" suffix
|
|
476
542
|
if (Number.parseFloat(res) >= 0) {
|
|
477
543
|
args += res + "f";
|
|
@@ -487,8 +553,12 @@ function run(program, outputDir, sourceFile) {
|
|
|
487
553
|
}
|
|
488
554
|
if (!args)
|
|
489
555
|
args = "";
|
|
490
|
-
if (type) {
|
|
491
|
-
|
|
556
|
+
if (type || typeString) {
|
|
557
|
+
if (typeString) {
|
|
558
|
+
if (allowDebugLogs)
|
|
559
|
+
console.log("Override type", type, typeString);
|
|
560
|
+
type = typeString;
|
|
561
|
+
}
|
|
492
562
|
return "new " + type + "(" + args + ")";
|
|
493
563
|
}
|
|
494
564
|
// const expType = node.getChildren().find(c => c.kind === ts.SyntaxKind.Identifier);
|
|
@@ -499,16 +569,24 @@ function run(program, outputDir, sourceFile) {
|
|
|
499
569
|
console.log("Unknown assignment:", str, ts.SyntaxKind[node.kind]);
|
|
500
570
|
return str;
|
|
501
571
|
}
|
|
502
|
-
function
|
|
572
|
+
function shouldEmitMethod(node) {
|
|
503
573
|
if (node.kind === ts.SyntaxKind.PublicKeyword) {
|
|
504
574
|
return true;
|
|
505
575
|
}
|
|
506
576
|
else if (node.kind === ts.SyntaxKind.PrivateKeyword || node.kind === ts.SyntaxKind.ProtectedKeyword) {
|
|
507
577
|
return false;
|
|
508
578
|
}
|
|
579
|
+
// check if its static
|
|
580
|
+
else if (node.kind === ts.SyntaxKind.StaticKeyword) {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
// check if its abstract
|
|
584
|
+
else if (node.kind === ts.SyntaxKind.AbstractKeyword) {
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
509
587
|
for (var _i = 0, _a = node.getChildren(); _i < _a.length; _i++) {
|
|
510
588
|
var ch = _a[_i];
|
|
511
|
-
if (!
|
|
589
|
+
if (!shouldEmitMethod(ch))
|
|
512
590
|
return false;
|
|
513
591
|
}
|
|
514
592
|
return true;
|
|
@@ -574,8 +652,30 @@ function run(program, outputDir, sourceFile) {
|
|
|
574
652
|
typeName = varDec.type.getText();
|
|
575
653
|
}
|
|
576
654
|
var res = undefined;
|
|
655
|
+
// if it's a { x: number } inline object type:
|
|
656
|
+
if (typeName.startsWith("{")) {
|
|
657
|
+
// check if it has XYZW we assume it's a vector
|
|
658
|
+
var hasX = typeName.includes("x");
|
|
659
|
+
var hasY = typeName.includes("y");
|
|
660
|
+
var hasZ = typeName.includes("z");
|
|
661
|
+
var hasW = typeName.includes("w");
|
|
662
|
+
if (hasX && hasY && hasZ && hasW) {
|
|
663
|
+
return tryGetTypeFromText("Vector4");
|
|
664
|
+
}
|
|
665
|
+
else if (hasX && hasY && hasZ) {
|
|
666
|
+
return tryGetTypeFromText("Vector3");
|
|
667
|
+
}
|
|
668
|
+
else if (hasX && hasY) {
|
|
669
|
+
return tryGetTypeFromText("Vector2");
|
|
670
|
+
}
|
|
671
|
+
return "object";
|
|
672
|
+
}
|
|
673
|
+
// const kindName = ts.SyntaxKind[node.kind];
|
|
577
674
|
// console.log("Unknown type: " + typeName);
|
|
578
675
|
switch (node.kind) {
|
|
676
|
+
case ts.SyntaxKind.ObjectBindingPattern:
|
|
677
|
+
res = "object";
|
|
678
|
+
break;
|
|
579
679
|
// case ts.SyntaxKind.SyntaxList:
|
|
580
680
|
// const list = node as ts.SyntaxList;
|
|
581
681
|
// for (const ch of list._children) {
|
|
@@ -633,8 +733,14 @@ function run(program, outputDir, sourceFile) {
|
|
|
633
733
|
var isInGenericDeclaration = false;
|
|
634
734
|
for (var _b = 0, _c = node.getChildren(); _b < _c.length; _b++) {
|
|
635
735
|
var child = _c[_b];
|
|
636
|
-
//
|
|
637
|
-
|
|
736
|
+
// Fix https://linear.app/needle/issue/NE-4423
|
|
737
|
+
if (child.kind === ts.SyntaxKind.Block) {
|
|
738
|
+
if (allowDebugLogs)
|
|
739
|
+
console.log("Skip block");
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
if (allowDebugLogs)
|
|
743
|
+
console.log("Child type: " + ts.SyntaxKind[child.kind]);
|
|
638
744
|
var isGenericStart = false;
|
|
639
745
|
var isAssignment = false;
|
|
640
746
|
switch (child.kind) {
|
|
@@ -693,11 +799,17 @@ if (process) {
|
|
|
693
799
|
var outputDir_1 = process.argv[2];
|
|
694
800
|
var fileNames = process.argv.slice(3);
|
|
695
801
|
fileNames.forEach(function (fileName) {
|
|
696
|
-
|
|
802
|
+
try {
|
|
803
|
+
if (!fs.existsSync(fileName)) {
|
|
804
|
+
console.error("File not found: " + fileName);
|
|
805
|
+
}
|
|
806
|
+
else {
|
|
807
|
+
var code = (0, fs_1.readFileSync)(fileName).toString();
|
|
808
|
+
compile(code, fileName, outputDir_1);
|
|
809
|
+
}
|
|
697
810
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
compile(code, fileName, outputDir_1);
|
|
811
|
+
catch (e) {
|
|
812
|
+
console.error(e);
|
|
701
813
|
}
|
|
702
814
|
});
|
|
703
815
|
}
|
|
@@ -37,6 +37,7 @@ var TYPE_MAP = {
|
|
|
37
37
|
"GameObject": "UnityEngine.GameObject",
|
|
38
38
|
"Object3D": "UnityEngine.Transform",
|
|
39
39
|
"Transform": "UnityEngine.Transform",
|
|
40
|
+
"RectTransform": "UnityEngine.RectTransform",
|
|
40
41
|
"AssetReference": "UnityEngine.Transform",
|
|
41
42
|
"THREE.Object3D": "UnityEngine.Transform",
|
|
42
43
|
// Math types
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/needle-component-compiler",
|
|
3
|
-
"version": "3.0.0-alpha",
|
|
3
|
+
"version": "3.0.0-alpha.1",
|
|
4
4
|
"description": "Compile Editor components for Needle Engine for C# and Blender",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"tsc": "tsc",
|
|
8
8
|
"dev": "npm-watch compile",
|
|
9
9
|
"compile": "tsc",
|
|
10
|
+
"prepublishOnly": "npm run compile",
|
|
10
11
|
"test": "npm run test:csharp && npm run test:blender",
|
|
11
12
|
"test:csharp": "mocha -r ts-node/register 'test/csharp/**/*.test.ts'",
|
|
12
13
|
"test:blender": "mocha -r ts-node/register 'test/blender/**/*.test.ts'",
|
|
@@ -51,5 +52,9 @@
|
|
|
51
52
|
"repository": {
|
|
52
53
|
"type": "git",
|
|
53
54
|
"url": "git+https://github.com/needle-tools/needle-tiny-component-compiler.git"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public",
|
|
58
|
+
"registry": "https://registry.npmjs.org/"
|
|
54
59
|
}
|
|
55
60
|
}
|