@needle-tools/needle-component-compiler 1.8.0 → 1.9.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 CHANGED
@@ -4,6 +4,13 @@ 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
+ ## [1.9.1] - 2022-11-05
8
+ - Fix ``new Vector2(1, .5)`` generating invalid C# where number arguments were emitted as double instead of float
9
+
10
+ ## [1.9.0] - 2022-10-18
11
+ - Change: emit ``onEnable`` as ``OnEnable`` and ``onDisable`` as ``OnDisable`` so Unity creates component checkboxes
12
+ - Change: ignore private and protected methods
13
+
7
14
  ## [1.8.0] - 2022-09-02
8
15
  - Add ``@nonSerialized`` decorator for fields and methods
9
16
  - Fix comment gen for unknown types
package/DEV.bat ADDED
@@ -0,0 +1 @@
1
+ npm install && npm run dev
package/PUBLISH.bat CHANGED
@@ -3,6 +3,6 @@ echo Press a key to publish! (close the window if you changed your mind)
3
3
  pause
4
4
  echo Publishing in 2 sec
5
5
  timeout 2
6
- npm set registry https://registry.npmjs.org && npm publish
6
+ npm run compile & npm set registry https://registry.npmjs.org && npm publish & pause
7
7
  echo Finished...
8
8
  timeout 10
File without changes
package/RUN_TESTS.bat ADDED
@@ -0,0 +1 @@
1
+ npm run test & pause
package/package.json CHANGED
@@ -1,16 +1,34 @@
1
1
  {
2
2
  "name": "@needle-tools/needle-component-compiler",
3
- "version": "1.8.0",
3
+ "version": "1.9.1",
4
4
  "description": "Compile mock unity components from typescript",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "tsc": "tsc"
7
+ "tsc": "tsc",
8
+ "dev": "npm-watch compile",
9
+ "compile" : "tsc",
10
+ "test": "mocha -r ts-node/register test/**.test.ts"
8
11
  },
9
12
  "dependencies": {
10
13
  "typescript": "^4.5.5"
11
14
  },
12
15
  "devDependencies": {
13
- "@types/node": "^17.0.16"
16
+ "@types/chai": "^4.3.3",
17
+ "@types/mocha": "^9.1.1",
18
+ "@types/node": "^18.7.18",
19
+ "chai": "^4.3.6",
20
+ "mocha": "^10.0.0",
21
+ "ts-node": "^10.9.1",
22
+ "npm-watch": "^0.11.0"
23
+ },
24
+ "watch": {
25
+ "compile": {
26
+ "patterns": [
27
+ "src/component-compiler.ts"
28
+ ],
29
+ "extensions": "ts",
30
+ "quiet": false
31
+ }
14
32
  },
15
33
  "author": {
16
34
  "name": "Needle",
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  exports.__esModule = true;
3
- exports.run = void 0;
3
+ exports.run = exports.compile = void 0;
4
4
  var fs_1 = require("fs");
5
5
  var ts = require("typescript");
6
6
  var fs = require("fs");
@@ -18,37 +18,53 @@ var typePattern = new RegExp("@type ?(?<type>.+)");
18
18
  var ifdefPattern = new RegExp("@ifdef ?(?<ifdef>.+)");
19
19
  var CODEGEN_MARKER_START = "// NEEDLE_CODEGEN_START";
20
20
  var CODEGEN_MARKER_END = "// NEEDLE_CODEGEN_END";
21
+ var allowDebugLogs = true;
21
22
  // will be set to true when e.g. a comment for export is found
22
23
  var exportNextClass = false;
23
24
  var dontExportNextClass = false;
24
25
  var serializeField = false;
25
26
  var dontSerialize = false;
27
+ var typesFileContent = undefined;
28
+ // const exportDir = "../dist";
29
+ var commentStarts = [];
30
+ var contexts = [];
31
+ var lastTypeFound = null;
32
+ var ifdefSections = [];
33
+ function resetAllState() {
34
+ exportNextClass = false;
35
+ dontExportNextClass = false;
36
+ serializeField = false;
37
+ dontSerialize = false;
38
+ typesFileContent = undefined;
39
+ commentStarts.length = 0;
40
+ contexts.length = 0;
41
+ lastTypeFound = null;
42
+ ifdefSections.length = 0;
43
+ }
26
44
  function resetExportNextClass() {
27
45
  dontExportNextClass = false;
28
46
  exportNextClass = false;
29
47
  }
30
- var typesFileContent = undefined;
31
48
  function tryGetKnownType(str) {
32
49
  if (typesFileContent === undefined) {
33
50
  typesFileContent = null;
34
51
  var filePath = path.dirname(__dirname) + "/src/types.json";
35
52
  if (fs.existsSync(filePath)) {
36
- console.log("Reading types file");
53
+ if (allowDebugLogs)
54
+ console.log("Reading types file");
37
55
  var content = fs.readFileSync(filePath, "utf8");
38
56
  typesFileContent = JSON.parse(content);
39
57
  }
40
58
  }
41
59
  if (typesFileContent) {
42
60
  var fullType = typesFileContent[str];
43
- if (fullType)
61
+ if (fullType && allowDebugLogs)
44
62
  console.log(fullType);
45
63
  return fullType;
46
64
  }
47
65
  return null;
48
66
  }
49
67
  // https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API
50
- // const exportDir = "../dist";
51
- var commentStarts = [];
52
68
  var ExportContext = /** @class */ (function () {
53
69
  function ExportContext(outputDir, fileName) {
54
70
  this.classEnd = -1;
@@ -76,46 +92,62 @@ var ExportContext = /** @class */ (function () {
76
92
  ExportContext.prototype.flush = function () {
77
93
  if (this.textBuffer.length <= 0)
78
94
  return;
79
- var dir = this.outputDir + "/";
80
- var path = dir + this.fileName;
81
- this.replaceGeneratedCodeSection(path);
82
- console.log("Write to " + path);
83
- fs.writeFileSync(path, this.textBuffer);
95
+ this.textBuffer = CODEGEN_MARKER_START + "\n" + this.textBuffer + "\n" + CODEGEN_MARKER_END;
96
+ var code = this.textBuffer;
97
+ if (this.outputDir !== null) {
98
+ var dir = this.outputDir + "/";
99
+ var path_1 = dir + this.fileName;
100
+ this.replaceGeneratedCodeSection(path_1);
101
+ if (allowDebugLogs)
102
+ console.log("Write to " + path_1);
103
+ fs.writeFileSync(path_1, code);
104
+ }
84
105
  this.reset();
106
+ return code;
85
107
  };
86
108
  ExportContext.prototype.reset = function () {
87
109
  this.textBuffer = "";
88
110
  this.classEnd = -1;
89
111
  };
90
112
  ExportContext.prototype.replaceGeneratedCodeSection = function (path) {
91
- this.textBuffer = CODEGEN_MARKER_START + "\n" + this.textBuffer + "\n" + CODEGEN_MARKER_END;
92
113
  if (fs.existsSync(path)) {
93
114
  var existing = fs.readFileSync(path, "utf8");
94
115
  var regex = new RegExp("(?<before>.*?)\/\/ ?NEEDLE_CODEGEN_START.+\/\/ ?NEEDLE_CODEGEN_END(?<after>.*)", "s");
95
116
  var matches = regex.exec(existing);
96
117
  if (matches === null || matches === void 0 ? void 0 : matches.groups) {
97
- console.log("Found codegen sections");
98
- var before = matches.groups.before;
99
- var after = matches.groups.after;
100
- this.textBuffer = before + this.textBuffer + after;
118
+ if (allowDebugLogs)
119
+ console.log("Found codegen sections");
120
+ var before_1 = matches.groups.before;
121
+ var after_1 = matches.groups.after;
122
+ this.textBuffer = before_1 + this.textBuffer + after_1;
101
123
  }
102
124
  }
103
125
  };
104
126
  return ExportContext;
105
127
  }());
106
- var contexts = [];
107
- var lastTypeFound = null;
108
- var ifdefSections = [];
128
+ function compile(code, fileName, outputDir, debugLogs) {
129
+ if (debugLogs === void 0) { debugLogs = true; }
130
+ resetAllState();
131
+ allowDebugLogs = debugLogs;
132
+ // Parse a file
133
+ var sourceFile = ts.createSourceFile(fileName, code, ts.ScriptTarget.ES2015, true);
134
+ var prog = ts.createProgram([fileName], {});
135
+ // delint it
136
+ return run(prog, outputDir, sourceFile);
137
+ }
138
+ exports.compile = compile;
109
139
  function run(program, outputDir, sourceFile) {
110
- if (!fs.existsSync(outputDir)) {
140
+ if (outputDir !== null && !fs.existsSync(outputDir)) {
111
141
  console.error("Output directory does not exist: \"" + outputDir + "\"");
112
142
  return;
113
143
  }
144
+ var results = [];
114
145
  traverseFile(sourceFile);
115
146
  function traverseFile(node) {
116
147
  visit(node);
117
148
  ts.forEachChild(node, traverseFile);
118
149
  }
150
+ return results;
119
151
  function visit(node) {
120
152
  var _a, _b, _c, _d, _e, _f;
121
153
  var context = contexts.length > 0 ? contexts[contexts.length - 1] : null;
@@ -125,12 +157,14 @@ function run(program, outputDir, sourceFile) {
125
157
  context.indentLevel -= 1;
126
158
  context.append("}\n");
127
159
  }
128
- context.flush();
160
+ var code = context.flush();
161
+ results.push(code);
129
162
  context = null;
130
163
  contexts.pop();
131
164
  }
132
165
  }
133
- console.log("\t", ts.SyntaxKind[node.kind]);
166
+ if (allowDebugLogs)
167
+ console.log("\t", ts.SyntaxKind[node.kind]);
134
168
  var commentRanges = ts.getLeadingCommentRanges(sourceFile.getFullText(), node.getFullStart());
135
169
  if (commentRanges === null || commentRanges === void 0 ? void 0 : commentRanges.length) {
136
170
  for (var _i = 0, commentRanges_1 = commentRanges; _i < commentRanges_1.length; _i++) {
@@ -159,10 +193,11 @@ function run(program, outputDir, sourceFile) {
159
193
  if (typeMatch && typeMatch.groups) {
160
194
  // for some reason our regex does also match surrounding ( ) even tho: https://regex101.com/r/PoWK6V/1
161
195
  // so we remove them
162
- var type_1 = typeMatch.groups["type"];
163
- type_1 = type_1.replace(/\(/, "").replace(/\)/, "");
164
- console.log("Found type: ", type_1);
165
- lastTypeFound = type_1;
196
+ var type = typeMatch.groups["type"];
197
+ type = type.replace(/\(/, "").replace(/\)/, "");
198
+ if (allowDebugLogs)
199
+ console.log("Found type: ", type);
200
+ lastTypeFound = type;
166
201
  }
167
202
  var ifdefMatch = ifdefPattern.exec(comment);
168
203
  if (ifdefMatch && ifdefMatch.groups) {
@@ -200,6 +235,9 @@ function run(program, outputDir, sourceFile) {
200
235
  var meth = node;
201
236
  // const isCoroutine = func.asteriskToken;
202
237
  if (!skip && meth.name) {
238
+ var pub_1 = isPublic(meth);
239
+ if (!pub_1)
240
+ return;
203
241
  var paramsStr = "";
204
242
  for (var _g = 0, _h = meth.parameters; _g < _h.length; _g++) {
205
243
  var param = _h[_g];
@@ -207,13 +245,22 @@ function run(program, outputDir, sourceFile) {
207
245
  continue;
208
246
  if (paramsStr.length > 0)
209
247
  paramsStr += ", ";
210
- var type_2 = tryResolveTypeRecursive(param);
211
- if (type_2 === undefined)
212
- type_2 = "object";
213
- paramsStr += type_2 + " @" + param.name.getText();
248
+ var type = tryResolveTypeRecursive(param);
249
+ if (type === undefined)
250
+ type = "object";
251
+ paramsStr += type + " @" + param.name.getText();
214
252
  }
215
253
  var methodName = meth.name.getText();
254
+ switch (methodName) {
255
+ case "onEnable":
256
+ methodName = "OnEnable";
257
+ break;
258
+ case "onDisable":
259
+ methodName = "OnDisable";
260
+ break;
261
+ }
216
262
  context.onBeforeMethod(methodName);
263
+ // let visibility = pub ? "public" : "private";
217
264
  context.append("public void " + methodName + "(" + paramsStr + "){}\n");
218
265
  }
219
266
  break;
@@ -222,7 +269,8 @@ function run(program, outputDir, sourceFile) {
222
269
  resetExportNextClass();
223
270
  if (!context)
224
271
  break;
225
- console.log("Found variable", node.getText());
272
+ if (allowDebugLogs)
273
+ console.log("Found variable", node.getText());
226
274
  var vardec = node;
227
275
  var varName = "@" + vardec.name.getText();
228
276
  var pub = isPublic(vardec);
@@ -230,18 +278,21 @@ function run(program, outputDir, sourceFile) {
230
278
  var isAccessible = pub;
231
279
  dontSerialize = false;
232
280
  if (serializeField) {
233
- console.log("[SerializeField]");
281
+ if (allowDebugLogs)
282
+ console.log("[SerializeField]");
234
283
  context.appendLine("[UnityEngine.SerializeField]");
235
284
  isAccessible = true;
236
285
  }
237
286
  else if (skip)
238
287
  isAccessible = false;
239
288
  if (!isAccessible) {
240
- console.log("Skip because not public or serializeable");
289
+ if (allowDebugLogs)
290
+ console.log("Skip because not public or serializeable");
241
291
  break;
242
292
  }
243
293
  var name_1 = vardec.name.getText();
244
- console.log("Variable:", name_1);
294
+ if (allowDebugLogs)
295
+ console.log("Variable:", name_1);
245
296
  if (name_1.startsWith("\"@") || name_1.startsWith("\"$") || name_1.startsWith("$"))
246
297
  break;
247
298
  var typeString = lastTypeFound !== null && lastTypeFound !== void 0 ? lastTypeFound : tryResolveTypeRecursive(node);
@@ -294,12 +345,14 @@ function run(program, outputDir, sourceFile) {
294
345
  if (typeString === undefined)
295
346
  typeString = typeName;
296
347
  if (typeString === "[]") {
297
- console.log("Unknown array type for \"" + varName + " " + typeName + "\" - your type is probably not known (did you just create it this session?) and you might need to regenerate the Typemap in Unity. Go to \"Needle Engine/Internal/Generate Type Map for component compiler");
348
+ if (allowDebugLogs)
349
+ console.log("Unknown array type for \"" + varName + " " + typeName + "\" - your type is probably not known (did you just create it this session?) and you might need to regenerate the Typemap in Unity. Go to \"Needle Engine/Internal/Generate Type Map for component compiler");
298
350
  // typeString = "object[]";
299
351
  // assignment = " = new object[0]";
300
352
  shouldCommentTheLine = true;
301
353
  }
302
- console.log("EMIT member: \"" + typeString + "\" " + varName, assignment, "Last type found:", lastTypeFound);
354
+ if (allowDebugLogs)
355
+ console.log("EMIT member: \"" + typeString + "\" " + varName, assignment, "Last type found:", lastTypeFound);
303
356
  var prefix = shouldCommentTheLine ? "// " : "";
304
357
  context.append(prefix + visibility + " " + typeString + " " + varName + assignment + ";" + postFix + "\n");
305
358
  lastTypeFound = null;
@@ -315,9 +368,11 @@ function run(program, outputDir, sourceFile) {
315
368
  if (!dontExportNextClass && (lastTypeFound || exportNextClass || inheritsComponent)) {
316
369
  resetExportNextClass();
317
370
  var name_2 = (_d = dec.name) === null || _d === void 0 ? void 0 : _d.escapedText;
318
- console.log("Found class: ", name_2);
371
+ if (allowDebugLogs)
372
+ console.log("Found class: ", name_2);
319
373
  var namespace = (_e = tryParseNamespace(node)) !== null && _e !== void 0 ? _e : "Needle.Typescript.GeneratedComponents";
320
- console.log("NAMESPACE", namespace);
374
+ if (allowDebugLogs)
375
+ console.log("NAMESPACE", namespace);
321
376
  var newContext = new ExportContext(outputDir, name_2 + ".cs");
322
377
  newContext.appendLine("// auto generated code - do not edit directly");
323
378
  newContext.appendLine("");
@@ -332,7 +387,8 @@ function run(program, outputDir, sourceFile) {
332
387
  typeName_1 = inheritsComponent;
333
388
  if (lastTypeFound)
334
389
  typeName_1 = lastTypeFound;
335
- console.log(name_2 + " inherits " + typeName_1);
390
+ if (allowDebugLogs)
391
+ console.log(name_2 + " inherits " + typeName_1);
336
392
  var modifiers = "";
337
393
  if (dec.modifiers) {
338
394
  for (var _l = 0, _m = dec.modifiers; _l < _m.length; _l++) {
@@ -340,7 +396,8 @@ function run(program, outputDir, sourceFile) {
340
396
  switch (mod.getText()) {
341
397
  case "abstract":
342
398
  modifiers += " abstract";
343
- console.log(name_2 + " is abstract");
399
+ if (allowDebugLogs)
400
+ console.log(name_2 + " is abstract");
344
401
  break;
345
402
  }
346
403
  }
@@ -353,7 +410,8 @@ function run(program, outputDir, sourceFile) {
353
410
  contexts.push(newContext);
354
411
  }
355
412
  else {
356
- console.log("Class type is unknown and will not generate a component: ", (_f = dec.name) === null || _f === void 0 ? void 0 : _f.escapedText);
413
+ if (allowDebugLogs)
414
+ console.log("Class type is unknown and will not generate a component: ", (_f = dec.name) === null || _f === void 0 ? void 0 : _f.escapedText);
357
415
  }
358
416
  lastTypeFound = null;
359
417
  break;
@@ -368,10 +426,10 @@ function run(program, outputDir, sourceFile) {
368
426
  if (h.types.length <= 0)
369
427
  continue;
370
428
  for (var _b = 0, _c = h.types; _b < _c.length; _b++) {
371
- var type_3 = _c[_b];
429
+ var type = _c[_b];
372
430
  // const symbol = program.getTypeChecker().getSymbolAtLocation(type.expression);
373
431
  // console.log(symbol);
374
- var text = type_3.expression.getText();
432
+ var text = type.expression.getText();
375
433
  if (text === "Component")
376
434
  return true;
377
435
  if (text === "Behaviour")
@@ -392,7 +450,7 @@ function run(program, outputDir, sourceFile) {
392
450
  case ts.SyntaxKind.FirstLiteralToken:
393
451
  return node.getText();
394
452
  case ts.SyntaxKind.NewExpression:
395
- var type_4 = undefined;
453
+ var type = undefined;
396
454
  var args = undefined;
397
455
  for (var _i = 0, _a = node.getChildren(); _i < _a.length; _i++) {
398
456
  var ch = _a[_i];
@@ -401,29 +459,46 @@ function run(program, outputDir, sourceFile) {
401
459
  switch (ch.kind) {
402
460
  case ts.SyntaxKind.Identifier:
403
461
  case ts.SyntaxKind.PropertyAccessExpression:
404
- type_4 = tryGetTypeFromText(text);
462
+ type = tryGetTypeFromText(text);
405
463
  break;
406
464
  case ts.SyntaxKind.SyntaxList:
407
- args = text;
465
+ for (var _b = 0, _c = ch.getChildren(); _b < _c.length; _b++) {
466
+ var arg = _c[_b];
467
+ if (args === undefined)
468
+ args = "";
469
+ var res = getTypeForAssignment(arg);
470
+ // handle floats being assigned with "f" suffix
471
+ if (Number.parseFloat(res) >= 0) {
472
+ args += res + "f";
473
+ }
474
+ else {
475
+ args += res;
476
+ if (res === ",")
477
+ args += " ";
478
+ }
479
+ }
408
480
  break;
409
481
  }
410
482
  }
411
483
  if (!args)
412
484
  args = "";
413
- if (type_4)
414
- return "new " + type_4 + "(" + args + ")";
485
+ if (type) {
486
+ console.log(type, args);
487
+ return "new " + type + "(" + args + ")";
488
+ }
415
489
  // const expType = node.getChildren().find(c => c.kind === ts.SyntaxKind.Identifier);
416
490
  break;
417
491
  }
418
492
  var str = node.getText();
419
- console.log("Unknown assignment:", str, ts.SyntaxKind[node.kind]);
493
+ if (allowDebugLogs)
494
+ console.log("Unknown assignment:", str, ts.SyntaxKind[node.kind]);
420
495
  return str;
421
496
  }
422
497
  function isPublic(node) {
423
498
  if (node.kind === ts.SyntaxKind.PublicKeyword) {
424
499
  return true;
425
500
  }
426
- else if (node.kind === ts.SyntaxKind.PrivateKeyword) {
501
+ else if (node.kind === ts.SyntaxKind.PrivateKeyword || node.kind === ts.SyntaxKind.ProtectedKeyword) {
427
502
  return false;
428
503
  }
429
504
  for (var _i = 0, _a = node.getChildren(); _i < _a.length; _i++) {
@@ -464,7 +539,8 @@ function run(program, outputDir, sourceFile) {
464
539
  var separatorIndex = typeName.lastIndexOf(".");
465
540
  if (separatorIndex > 0) {
466
541
  var newName = typeName.substring(separatorIndex + 1);
467
- console.log("Remove import name from type: \"" + typeName + "\" → \"" + newName + "\"");
542
+ if (allowDebugLogs)
543
+ console.log("Remove import name from type: \"" + typeName + "\" → \"" + newName + "\"");
468
544
  typeName = newName;
469
545
  }
470
546
  var res = dict[typeName];
@@ -516,7 +592,8 @@ function run(program, outputDir, sourceFile) {
516
592
  case ts.SyntaxKind.TypeReference:
517
593
  var typeRef = node;
518
594
  var typeName_2 = typeRef.typeName.getText();
519
- console.log("TypeReference:", typeName_2);
595
+ if (allowDebugLogs)
596
+ console.log("TypeReference:", typeName_2);
520
597
  switch (typeName_2) {
521
598
  case "Array":
522
599
  break;
@@ -574,7 +651,8 @@ function run(program, outputDir, sourceFile) {
574
651
  if (childResult !== undefined) {
575
652
  if (res === undefined)
576
653
  res = "";
577
- console.log("Child: " + ts.SyntaxKind[child.kind] + " → " + childResult);
654
+ if (allowDebugLogs)
655
+ console.log("Child: " + ts.SyntaxKind[child.kind] + " → " + childResult);
578
656
  // if the thing is a generic return as generic result
579
657
  if (isInGenericDeclaration && !res.includes("[]")) {
580
658
  res = "<" + childResult + ">";
@@ -602,18 +680,20 @@ function run(program, outputDir, sourceFile) {
602
680
  }
603
681
  }
604
682
  exports.run = run;
605
- if (process.argv.length < 4) {
606
- console.error("Missing args, call with: <output_dir> <input_files>");
607
- }
608
- else {
609
- var outputDir_1 = process.argv[2];
610
- var fileNames = process.argv.slice(3);
611
- fileNames.forEach(function (fileName) {
612
- // Parse a file
613
- var sourceFile = ts.createSourceFile(fileName, (0, fs_1.readFileSync)(fileName).toString(), ts.ScriptTarget.ES2015,
614
- /*setParentNodes */ true);
615
- var prog = ts.createProgram([fileName], {});
616
- // delint it
617
- run(prog, outputDir_1, sourceFile);
618
- });
683
+ if (process) {
684
+ if (process.argv.length < 4) {
685
+ console.error("Missing args, call with: <output_dir> <input_files>");
686
+ }
687
+ else {
688
+ var outputDir_1 = process.argv[2];
689
+ var fileNames = process.argv.slice(3);
690
+ fileNames.forEach(function (fileName) {
691
+ if (!fs.existsSync(fileName)) {
692
+ }
693
+ else {
694
+ var code = (0, fs_1.readFileSync)(fileName).toString();
695
+ compile(code, fileName, outputDir_1);
696
+ }
697
+ });
698
+ }
619
699
  }