@needle-tools/needle-component-compiler 1.0.0 → 1.2.0

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 ADDED
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+ All notable changes to this package will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [1.1.0] - 2022-06-15
8
+ - allow adding ``@type(MyNamespace.MyType)`` to class declaration
9
+
10
+ ## [1.1.0] - 2022-06-13
11
+ - add ``@type(MyNamespace.MyType)`` decorator for fields to specifiy C# type
12
+ - add minimal docs to readme
13
+ - dont emit comments anymore
14
+ - make created classes partial
15
+
16
+ ## [1.0.1] - 2022-05-29
17
+ - disable all warnings for generated scripts
18
+ - add mesh and texture types
19
+
20
+ ## [1.0.0] - 2022-04-22
21
+ - initial release
package/Readme.md CHANGED
@@ -4,4 +4,11 @@ Little helper package to transpile typescript files to Unity C# components.
4
4
  Please run ``npm install`` first before using.
5
5
 
6
6
  ### Usage
7
- ``node <path to>/component-compiler.js <output_directory> <path_to/my_script.ts>``
7
+ ``node <path to>/component-compiler.js <output_directory> <path_to/my_script.ts>``
8
+
9
+
10
+ ### Command decorators
11
+ - ``@dont-generate-component`` add before class to skip generating a component
12
+ - ``@generate-component`` to enforce generating a component (not required)
13
+ - ``@serializeField`` field decorator, similar to ``[SerializeField]``
14
+ - ``@type(MyNamespace.MyType)`` field decorator, specifiy C# type of field
@@ -0,0 +1,11 @@
1
+ // auto generated code - do not edit
2
+
3
+ #pragma warning disable
4
+
5
+ namespace Needle.Typescript.GeneratedComponents
6
+ {
7
+ public class MaterialColorHandler : UnityEngine.MonoBehaviour
8
+ {
9
+ public UnityEngine.Renderer[] @renderer;
10
+ }
11
+ }
@@ -0,0 +1,13 @@
1
+ // auto generated code - do not edit directly
2
+
3
+ #pragma warning disable
4
+
5
+ namespace Needle.Typescript.GeneratedComponents
6
+ {
7
+ public partial class NavigationManager : RoomEntity
8
+ {
9
+ public float @fl = 1f;
10
+ public void nav_forward(){}
11
+ public void nav_backward(){}
12
+ }
13
+ }
@@ -0,0 +1,14 @@
1
+ // auto generated code - do not edit directly
2
+
3
+ #pragma warning disable
4
+
5
+ namespace Needle.Typescript.GeneratedComponents
6
+ {
7
+ public partial class PointOfInterest : UnityEngine.MonoBehaviour
8
+ {
9
+ public float @myVal = 12f;
10
+ public void myFunction(){}
11
+ public UnityEngine.Camera @view;
12
+ public string @test = "123";
13
+ }
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/needle-component-compiler",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Compile mock unity components from typescript",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -16,6 +16,5 @@
16
16
  "name": "Needle",
17
17
  "email": "help@needle.tools",
18
18
  "url": "https://needle.tools/"
19
- },
20
- "license": "ISC"
19
+ }
21
20
  }
@@ -11,6 +11,7 @@ var exportNextClassCommand = "@generate-component";
11
11
  var dontExportNextClassCommand = "@dont-generate-component";
12
12
  // add above field to add [SerializeField] attribute
13
13
  var serializeCommand = "@serializeField";
14
+ var typePattern = new RegExp("@type ?\((?<type>.+)\)");
14
15
  // will be set to true when e.g. a comment for export is found
15
16
  var exportNextClass = false;
16
17
  var dontExportNextClass = false;
@@ -65,6 +66,7 @@ var ExportContext = /** @class */ (function () {
65
66
  return ExportContext;
66
67
  }());
67
68
  var contexts = [];
69
+ var lastTypeFound = null;
68
70
  function run(program, outputDir, sourceFile) {
69
71
  if (!fs.existsSync(outputDir)) {
70
72
  console.error("Output directory does not exist: \"" + outputDir + "\"");
@@ -76,16 +78,18 @@ function run(program, outputDir, sourceFile) {
76
78
  ts.forEachChild(node, traverseFile);
77
79
  }
78
80
  function visit(node) {
79
- var _a, _b, _c;
81
+ var _a, _b, _c, _d;
80
82
  var context = contexts.length > 0 ? contexts[contexts.length - 1] : null;
81
- if ((context === null || context === void 0 ? void 0 : context.classEnd) > 0 && node.pos >= (context === null || context === void 0 ? void 0 : context.classEnd)) {
82
- while (context.indentLevel > 0) {
83
- context.indentLevel -= 1;
84
- context.append("}\n");
83
+ if (context) {
84
+ if ((context === null || context === void 0 ? void 0 : context.classEnd) > 0 && node.pos >= (context === null || context === void 0 ? void 0 : context.classEnd)) {
85
+ while (context.indentLevel > 0) {
86
+ context.indentLevel -= 1;
87
+ context.append("}\n");
88
+ }
89
+ context.flush();
90
+ context = null;
91
+ contexts.pop();
85
92
  }
86
- context.flush();
87
- context = null;
88
- contexts.pop();
89
93
  }
90
94
  console.log("\t", ts.SyntaxKind[node.kind]);
91
95
  var commentRanges = ts.getLeadingCommentRanges(sourceFile.getFullText(), node.getFullStart());
@@ -105,13 +109,23 @@ function run(program, outputDir, sourceFile) {
105
109
  }
106
110
  else if (comment.includes(serializeCommand))
107
111
  serializeField = true;
108
- else
109
- context.appendLine(comment);
110
112
  }
111
113
  if (comment.includes(exportNextClassCommand))
112
114
  exportNextClass = true;
113
115
  if (comment.includes(dontExportNextClassCommand))
114
116
  dontExportNextClass = true;
117
+ var match = typePattern.exec(comment);
118
+ if (match && match.groups) {
119
+ // for some reason our regex does also match surrounding ( ) even tho: https://regex101.com/r/PoWK6V/1
120
+ // so we remove them
121
+ var type = match.groups["type"];
122
+ if (type.startsWith("("))
123
+ type = type.slice(1);
124
+ if (type.endsWith(")"))
125
+ type = type.slice(0, -1);
126
+ console.log("found type: ", type);
127
+ lastTypeFound = type;
128
+ }
115
129
  }
116
130
  }
117
131
  switch (node.kind) {
@@ -122,6 +136,7 @@ function run(program, outputDir, sourceFile) {
122
136
  case ts.SyntaxKind.Decorator:
123
137
  break;
124
138
  case ts.SyntaxKind.MethodDeclaration:
139
+ lastTypeFound = null;
125
140
  serializeField = false;
126
141
  resetExportNextClass();
127
142
  if (!context)
@@ -131,8 +146,8 @@ function run(program, outputDir, sourceFile) {
131
146
  // const isCoroutine = func.asteriskToken;
132
147
  if (meth.name) {
133
148
  var paramsStr = "";
134
- for (var _d = 0, _e = meth.parameters; _d < _e.length; _d++) {
135
- var param = _e[_d];
149
+ for (var _e = 0, _f = meth.parameters; _e < _f.length; _e++) {
150
+ var param = _f[_e];
136
151
  if (!param || !param.name)
137
152
  continue;
138
153
  if (paramsStr.length > 0)
@@ -158,15 +173,15 @@ function run(program, outputDir, sourceFile) {
158
173
  console.log(name_1);
159
174
  if (name_1.startsWith("\"@") || name_1.startsWith("\"$") || name_1.startsWith("$"))
160
175
  break;
161
- var typeString = tryResolveTypeRecursive(node);
176
+ var typeString = lastTypeFound !== null && lastTypeFound !== void 0 ? lastTypeFound : tryResolveTypeRecursive(node);
162
177
  if (typeString === undefined) {
163
178
  context.append("// Could not resolve type \"" + ((_c = vardec.type) === null || _c === void 0 ? void 0 : _c.getText()) + "\"\n");
164
179
  }
165
180
  var prefix = typeString === undefined ? "// " : "";
166
181
  var assignment = "";
167
182
  if (typeString !== undefined) {
168
- for (var _f = 0, _g = node.getChildren(); _f < _g.length; _f++) {
169
- var ch = _g[_f];
183
+ for (var _g = 0, _h = node.getChildren(); _g < _h.length; _g++) {
184
+ var ch = _h[_g];
170
185
  switch (ch.kind) {
171
186
  case ts.SyntaxKind.FalseKeyword:
172
187
  case ts.SyntaxKind.TrueKeyword:
@@ -197,27 +212,34 @@ function run(program, outputDir, sourceFile) {
197
212
  context.appendLine("[UnityEngine.SerializeField]");
198
213
  }
199
214
  context.append(prefix + visibility + " " + typeString + " " + varName + assignment + ";\n");
215
+ lastTypeFound = null;
200
216
  break;
201
217
  case ts.SyntaxKind.ClassDeclaration:
202
218
  serializeField = false;
203
219
  var dec = node;
204
220
  // a class must inherit a component
205
- if (!dontExportNextClass && (exportNextClass || testInheritsComponent(node))) {
221
+ if (!dontExportNextClass && (lastTypeFound || exportNextClass || testInheritsComponent(node))) {
206
222
  resetExportNextClass();
207
- var name_2 = dec.name.escapedText;
223
+ var name_2 = (_d = dec.name) === null || _d === void 0 ? void 0 : _d.escapedText;
208
224
  console.log("Found class: ", name_2);
209
225
  var newContext = new ExportContext(outputDir, name_2 + ".cs");
210
- newContext.appendLine("// auto generated code - do not edit");
226
+ newContext.appendLine("// auto generated code - do not edit directly");
227
+ newContext.appendLine("");
228
+ newContext.appendLine("#pragma warning disable");
229
+ newContext.appendLine("");
211
230
  newContext.appendLine("namespace Needle.Typescript.GeneratedComponents");
212
231
  newContext.appendLine("{");
213
232
  newContext.indentLevel += 1;
214
233
  // newContext.appendLine("// source: " + path.resolve(sourceFile.fileName));
215
- newContext.appendLine("public class " + name_2 + " : UnityEngine.MonoBehaviour");
234
+ var typeName = lastTypeFound !== null && lastTypeFound !== void 0 ? lastTypeFound : "UnityEngine.MonoBehaviour";
235
+ console.log(name_2 + " inherits " + typeName);
236
+ newContext.appendLine("public partial class " + name_2 + " : " + typeName);
216
237
  newContext.appendLine("{");
217
238
  newContext.indentLevel += 1;
218
239
  newContext.classEnd = dec.end;
219
240
  contexts.push(newContext);
220
241
  }
242
+ lastTypeFound = null;
221
243
  break;
222
244
  }
223
245
  function testInheritsComponent(node) {
@@ -11,6 +11,7 @@ const exportNextClassCommand = "@generate-component";
11
11
  const dontExportNextClassCommand = "@dont-generate-component";
12
12
  // add above field to add [SerializeField] attribute
13
13
  const serializeCommand = "@serializeField";
14
+ const typePattern = new RegExp("@type ?\((?<type>.+)\)");
14
15
 
15
16
  // will be set to true when e.g. a comment for export is found
16
17
  let exportNextClass: boolean = false;
@@ -80,6 +81,8 @@ class ExportContext {
80
81
 
81
82
  const contexts: ExportContext[] = [];
82
83
 
84
+ let lastTypeFound: string | null = null;
85
+
83
86
  export function run(program: ts.Program, outputDir: string, sourceFile: ts.SourceFile) {
84
87
 
85
88
  if (!fs.existsSync(outputDir)) {
@@ -97,14 +100,16 @@ export function run(program: ts.Program, outputDir: string, sourceFile: ts.Sourc
97
100
  function visit(node: ts.Node) {
98
101
  let context: ExportContext | null = contexts.length > 0 ? contexts[contexts.length - 1] : null;
99
102
 
100
- if (context?.classEnd > 0 && node.pos >= context?.classEnd) {
101
- while (context.indentLevel > 0) {
102
- context.indentLevel -= 1;
103
- context.append("}\n");
103
+ if (context) {
104
+ if (context?.classEnd > 0 && node.pos >= context?.classEnd) {
105
+ while (context.indentLevel > 0) {
106
+ context.indentLevel -= 1;
107
+ context.append("}\n");
108
+ }
109
+ context.flush();
110
+ context = null;
111
+ contexts.pop();
104
112
  }
105
- context.flush();
106
- context = null;
107
- contexts.pop();
108
113
  }
109
114
  console.log("\t", ts.SyntaxKind[node.kind]);
110
115
 
@@ -125,13 +130,21 @@ export function run(program: ts.Program, outputDir: string, sourceFile: ts.Sourc
125
130
  }
126
131
  else if (comment.includes(serializeCommand))
127
132
  serializeField = true;
128
- else
129
- context.appendLine(comment);
130
133
  }
131
134
  if (comment.includes(exportNextClassCommand))
132
135
  exportNextClass = true;
133
136
  if (comment.includes(dontExportNextClassCommand))
134
137
  dontExportNextClass = true;
138
+ const match = typePattern.exec(comment);
139
+ if (match && match.groups) {
140
+ // for some reason our regex does also match surrounding ( ) even tho: https://regex101.com/r/PoWK6V/1
141
+ // so we remove them
142
+ let type = match.groups["type"];
143
+ if (type.startsWith("(")) type = type.slice(1);
144
+ if (type.endsWith(")")) type = type.slice(0, -1);
145
+ console.log("found type: ", type);
146
+ lastTypeFound = type;
147
+ }
135
148
  }
136
149
  }
137
150
 
@@ -143,6 +156,7 @@ export function run(program: ts.Program, outputDir: string, sourceFile: ts.Sourc
143
156
  case ts.SyntaxKind.Decorator:
144
157
  break;
145
158
  case ts.SyntaxKind.MethodDeclaration:
159
+ lastTypeFound = null;
146
160
  serializeField = false;
147
161
  resetExportNextClass();
148
162
  if (!context) break;
@@ -174,7 +188,7 @@ export function run(program: ts.Program, outputDir: string, sourceFile: ts.Sourc
174
188
  const name = vardec.name.getText();
175
189
  console.log(name);
176
190
  if (name.startsWith("\"@") || name.startsWith("\"$") || name.startsWith("$")) break;
177
- let typeString = tryResolveTypeRecursive(node);
191
+ let typeString = lastTypeFound ?? tryResolveTypeRecursive(node);
178
192
  if (typeString === undefined) {
179
193
  context.append("// Could not resolve type \"" + vardec.type?.getText() + "\"\n");
180
194
  }
@@ -212,28 +226,35 @@ export function run(program: ts.Program, outputDir: string, sourceFile: ts.Sourc
212
226
  context.appendLine("[UnityEngine.SerializeField]");
213
227
  }
214
228
  context.append(prefix + visibility + " " + typeString + " " + varName + assignment + ";\n");
229
+ lastTypeFound = null;
215
230
  break;
216
231
 
217
232
  case ts.SyntaxKind.ClassDeclaration:
218
233
  serializeField = false;
219
234
  const dec = <ts.ClassDeclaration>node;
220
235
  // a class must inherit a component
221
- if (!dontExportNextClass && (exportNextClass || testInheritsComponent(node))) {
236
+ if (!dontExportNextClass && (lastTypeFound || exportNextClass || testInheritsComponent(node))) {
222
237
  resetExportNextClass();
223
- const name = dec.name.escapedText;
238
+ const name = dec.name?.escapedText;
224
239
  console.log("Found class: ", name);
225
240
  const newContext = new ExportContext(outputDir, name + ".cs");
226
- newContext.appendLine("// auto generated code - do not edit")
241
+ newContext.appendLine("// auto generated code - do not edit directly");
242
+ newContext.appendLine("");
243
+ newContext.appendLine("#pragma warning disable");
244
+ newContext.appendLine("");
227
245
  newContext.appendLine("namespace Needle.Typescript.GeneratedComponents");
228
246
  newContext.appendLine("{");
229
247
  newContext.indentLevel += 1;
230
248
  // newContext.appendLine("// source: " + path.resolve(sourceFile.fileName));
231
- newContext.appendLine("public class " + name + " : UnityEngine.MonoBehaviour");
249
+ const typeName = lastTypeFound ?? "UnityEngine.MonoBehaviour";
250
+ console.log(name + " inherits " + typeName);
251
+ newContext.appendLine("public partial class " + name + " : " + typeName);
232
252
  newContext.appendLine("{");
233
253
  newContext.indentLevel += 1;
234
254
  newContext.classEnd = dec.end;
235
255
  contexts.push(newContext);
236
256
  }
257
+ lastTypeFound = null;
237
258
  break;
238
259
  }
239
260
 
@@ -275,7 +296,7 @@ export function run(program: ts.Program, outputDir: string, sourceFile: ts.Sourc
275
296
  if (!node) return undefined;
276
297
 
277
298
  // skip decorators (e.g. @serializable() may break array generation)
278
- if(node.kind === ts.SyntaxKind.Decorator)
299
+ if (node.kind === ts.SyntaxKind.Decorator)
279
300
  return undefined;
280
301
 
281
302
  let typeName = node?.getText();
@@ -323,12 +344,11 @@ export function run(program: ts.Program, outputDir: string, sourceFile: ts.Sourc
323
344
  console.log("Child type: " + ts.SyntaxKind[child.kind]);
324
345
  res = tryResolveTypeRecursive(child);
325
346
  }
326
-
327
- if(ts.isTypeReferenceNode(node)){
347
+
348
+ if (ts.isTypeReferenceNode(node)) {
328
349
  const typeRef = node as ts.TypeReferenceNode;
329
350
  const typeName = typeRef.typeName.getText();
330
- switch(typeName)
331
- {
351
+ switch (typeName) {
332
352
  case "Array":
333
353
  res += "[]";
334
354
  return res;
package/src/test.ts CHANGED
@@ -1,13 +1,42 @@
1
1
 
2
2
  // @generate-component
3
3
 
4
+ //@type (RoomEntity)
5
+ export class NavigationManager extends RoomEntity {
4
6
 
5
- export class MaterialColorHandler extends Behaviour {
7
+ fl:number = 1;
6
8
 
7
- @serializeable(Renderer)
8
- renderer?: Renderer[];
9
+ nav_forward() {
10
+
11
+ }
12
+
13
+ nav_backward() {
14
+
15
+ }
9
16
  }
10
17
 
18
+
19
+ // export class PointOfInterest extends Behaviour {
20
+
21
+ // myVal:number = 12;
22
+
23
+ // // @type(HELLO)
24
+ // myFunction(){
25
+
26
+ // }
27
+
28
+ // // @type(UnityEngine.Camera)
29
+ // view?:Camera;
30
+ // test:string = "123";
31
+ // // test
32
+ // }
33
+
34
+ // export class MaterialColorHandler extends Behaviour {
35
+
36
+ // @serializeable(Renderer)
37
+ // renderer?: Renderer[];
38
+ // }
39
+
11
40
  // export class MyArray extends Behaviour {
12
41
 
13
42
  // arr? : Array<number> = [1,2,3];
package/src/types.js CHANGED
@@ -37,6 +37,8 @@ const dict = {
37
37
  // Rendering
38
38
  "Renderer" : "UnityEngine.Renderer",
39
39
  "Material" : "UnityEngine.Material",
40
+ "Mesh" : "UnityEngine.Mesh",
41
+ "Texture" : "UnityEngine.Texture",
40
42
  // UI
41
43
  "Text" : "UnityEngine.UI.Text",
42
44
  "Image" : "UnityEngine.UI.Image",