@needle-tools/needle-component-compiler 1.9.1 → 2.0.0-pre

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.
@@ -1,734 +0,0 @@
1
- import { readFileSync } from "fs";
2
- import * as ts from "typescript";
3
- import * as fs from "fs";
4
- import * as path from 'path';
5
-
6
- import * as types from "./types";
7
- const dict = types.dict;
8
-
9
- // add either of these two comments above a class to enforce code gen or disable it for the next class
10
- const exportNextClassCommand = "@generate-component";
11
- const dontExportNextClassCommand = "@dont-generate-component";
12
- // add above field to add [SerializeField] attribute
13
- const serializeCommand = "@serializeField";
14
- const dontSerializeCommand = "@nonSerialized";
15
- // https://regex101.com/r/ltpcKT/2
16
- const typePattern = new RegExp("@type ?(?<type>.+)");
17
- const ifdefPattern = new RegExp("@ifdef ?(?<ifdef>.+)")
18
-
19
- const CODEGEN_MARKER_START = "// NEEDLE_CODEGEN_START";
20
- const CODEGEN_MARKER_END = "// NEEDLE_CODEGEN_END";
21
-
22
- let allowDebugLogs = true;
23
-
24
- // will be set to true when e.g. a comment for export is found
25
- let exportNextClass: boolean = false;
26
- let dontExportNextClass: boolean = false;
27
- let serializeField: boolean = false;
28
- let dontSerialize: boolean = false;
29
- let typesFileContent: object | undefined | null = undefined;
30
-
31
- // const exportDir = "../dist";
32
- const commentStarts: Array<number> = [];
33
- const contexts: ExportContext[] = [];
34
- let lastTypeFound: string | null = null;
35
- let ifdefSections: string[] = [];
36
-
37
- function resetAllState() {
38
- exportNextClass = false;
39
- dontExportNextClass = false;
40
- serializeField = false;
41
- dontSerialize = false;
42
- typesFileContent = undefined;
43
-
44
- commentStarts.length = 0;
45
- contexts.length = 0;
46
- lastTypeFound = null;
47
- ifdefSections.length = 0;
48
- }
49
-
50
- function resetExportNextClass() {
51
- dontExportNextClass = false;
52
- exportNextClass = false;
53
- }
54
-
55
- function tryGetKnownType(str: string): string | null {
56
- if (typesFileContent === undefined) {
57
- typesFileContent = null;
58
- const filePath = path.dirname(__dirname) + "/src/types.json";
59
- if (fs.existsSync(filePath)) {
60
- if (allowDebugLogs)
61
- console.log("Reading types file");
62
- const content = fs.readFileSync(filePath, "utf8");
63
- typesFileContent = JSON.parse(content);
64
- }
65
- }
66
-
67
- if (typesFileContent) {
68
- const fullType = typesFileContent[str];
69
- if (fullType && allowDebugLogs)
70
- console.log(fullType);
71
- return fullType;
72
- }
73
- return null;
74
- }
75
-
76
- // https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API
77
-
78
-
79
- class ExportContext {
80
- outputDir: string | null;
81
- fileName: string;
82
- textBuffer: string;
83
- classEnd: number = -1;
84
- indentLevel: number = 0;
85
-
86
- constructor(outputDir: string | null, fileName: string) {
87
- this.outputDir = outputDir;
88
- this.fileName = fileName;
89
- this.reset();
90
- }
91
-
92
- emitMethodContextMenu: string | null | undefined = null;
93
-
94
- onBeforeMethod(name: string) {
95
- if (this.emitMethodContextMenu !== undefined) {
96
- const contextMenuText = this.emitMethodContextMenu === null ? name : this.emitMethodContextMenu;
97
- this.appendLine("[UnityEngine.ContextMenu(\"" + contextMenuText + "\")]");
98
- }
99
- }
100
-
101
- append(text: string) {
102
- for (let i = 0; i < this.indentLevel; i++)
103
- text = "\t" + text;
104
- this.textBuffer += text;
105
- this.emitMethodContextMenu = undefined;
106
- }
107
-
108
- appendLine(text: string) {
109
- this.append(text + "\n");
110
- }
111
-
112
- flush(): string {
113
- if (this.textBuffer.length <= 0) return;
114
- this.textBuffer = CODEGEN_MARKER_START + "\n" + this.textBuffer + "\n" + CODEGEN_MARKER_END;
115
- const code = this.textBuffer;
116
- if (this.outputDir !== null) {
117
- const dir = this.outputDir + "/";
118
- const path = dir + this.fileName;
119
- this.replaceGeneratedCodeSection(path);
120
- if (allowDebugLogs)
121
- console.log("Write to " + path);
122
- fs.writeFileSync(path, code);
123
- }
124
- this.reset();
125
- return code;
126
- }
127
-
128
- reset() {
129
- this.textBuffer = "";
130
- this.classEnd = -1;
131
- }
132
-
133
- private replaceGeneratedCodeSection(path: string) {
134
- if (fs.existsSync(path)) {
135
- const existing = fs.readFileSync(path, "utf8");
136
- const regex = new RegExp("(?<before>.*?)\/\/ ?NEEDLE_CODEGEN_START.+\/\/ ?NEEDLE_CODEGEN_END(?<after>.*)", "s");
137
- const matches = regex.exec(existing);
138
- if (matches?.groups) {
139
- if (allowDebugLogs)
140
- console.log("Found codegen sections")
141
- const before = matches.groups.before;
142
- const after = matches.groups.after;
143
- this.textBuffer = before + this.textBuffer + after;
144
- }
145
- }
146
- }
147
- }
148
-
149
- export function compile(code: string, fileName: string, outputDir: string | null, debugLogs: boolean = true): string[] {
150
-
151
- resetAllState();
152
- allowDebugLogs = debugLogs;
153
-
154
- // Parse a file
155
- const sourceFile = ts.createSourceFile(
156
- fileName,
157
- code,
158
- ts.ScriptTarget.ES2015,
159
- true, /*setParentNodes */
160
- );
161
-
162
- const prog = ts.createProgram([fileName], {});
163
-
164
- // delint it
165
- return run(prog, outputDir, sourceFile);
166
- }
167
-
168
- export function run(program: ts.Program, outputDir: string | null, sourceFile: ts.SourceFile): string[] {
169
-
170
- if (outputDir !== null && !fs.existsSync(outputDir)) {
171
- console.error("Output directory does not exist: \"" + outputDir + "\"");
172
- return;
173
- }
174
-
175
- const results: string[] = [];
176
-
177
- traverseFile(sourceFile);
178
- function traverseFile(node: ts.Node) {
179
-
180
- visit(node);
181
- ts.forEachChild(node, traverseFile);
182
- }
183
-
184
- return results;
185
-
186
- function visit(node: ts.Node) {
187
- let context: ExportContext | null = contexts.length > 0 ? contexts[contexts.length - 1] : null;
188
-
189
- if (context) {
190
- if (context?.classEnd > 0 && node.pos >= context?.classEnd) {
191
- while (context.indentLevel > 0) {
192
- context.indentLevel -= 1;
193
- context.append("}\n");
194
- }
195
- const code = context.flush();
196
- results.push(code);
197
- context = null;
198
- contexts.pop();
199
- }
200
- }
201
- if (allowDebugLogs)
202
- console.log("\t", ts.SyntaxKind[node.kind]);
203
-
204
- const commentRanges = ts.getLeadingCommentRanges(
205
- sourceFile.getFullText(),
206
- node.getFullStart());
207
- if (commentRanges?.length) {
208
- for (const r of commentRanges) {
209
- // avoid emitting comments multiple times
210
- if (commentStarts.includes(r.pos)) continue;
211
- commentStarts.push(r.pos);
212
- const comment = node.getSourceFile().getFullText().slice(r.pos, r.end);
213
- if (context) {
214
- // https://regex101.com/r/ud4oev/1
215
- const emitContextMenu = comment.match("(\/{2,}|\/\*)\s*@contextmenu {0,}(?<text>[a-zA-Z 0-9]+)?");
216
- if (emitContextMenu) {
217
- context.emitMethodContextMenu = emitContextMenu.groups?.text ?? null;
218
- }
219
- else if (comment.includes(serializeCommand))
220
- serializeField = true;
221
- else if (comment.includes(dontSerializeCommand))
222
- dontSerialize = true;
223
- }
224
- if (comment.includes(exportNextClassCommand))
225
- exportNextClass = true;
226
- if (comment.includes(dontExportNextClassCommand))
227
- dontExportNextClass = true;
228
- const typeMatch = typePattern.exec(comment);
229
- if (typeMatch && typeMatch.groups) {
230
- // for some reason our regex does also match surrounding ( ) even tho: https://regex101.com/r/PoWK6V/1
231
- // so we remove them
232
- let type = typeMatch.groups["type"];
233
- type = type.replace(/\(/, "").replace(/\)/, "");
234
- if (allowDebugLogs)
235
- console.log("Found type: ", type);
236
- lastTypeFound = type;
237
- }
238
-
239
- const ifdefMatch = ifdefPattern.exec(comment);
240
- if (ifdefMatch && ifdefMatch.groups) {
241
- const ifdef = ifdefMatch.groups["ifdef"];
242
- if (ifdef)
243
- ifdefSections.push(ifdef);
244
- }
245
- }
246
- }
247
-
248
- const skip = dontSerialize;
249
- switch (node.kind) {
250
- // Namespace
251
- // case ts.SyntaxKind.ModuleDeclaration:
252
- // const mod = node as ts.ModuleDeclaration;
253
- // console.log(ts.SyntaxKind[mod.getChildAt(1).kind])
254
- // const type = mod.getChildAt(1) as ts.Identifier;
255
- // console.log("MODULE", type.text)
256
- // break;
257
- // case ts.SyntaxKind.Identifier:
258
- // break;
259
- // case ts.SyntaxKind.ClassDeclaration:
260
- // case ts.SyntaxKind.SingleLineCommentTrivia:
261
- // console.log("comment: " + node.getText())
262
- // break;
263
- case ts.SyntaxKind.Decorator:
264
- break;
265
- case ts.SyntaxKind.MethodDeclaration:
266
- lastTypeFound = null;
267
- serializeField = false;
268
- dontSerialize = false;
269
- resetExportNextClass();
270
- if (!context) break;
271
- // TODO: always emit at least OnEnable method per class so generated components have toggle in editor
272
- const meth = node as ts.MethodDeclaration;
273
- // const isCoroutine = func.asteriskToken;
274
- if (!skip && meth.name) {
275
- const pub = isPublic(meth);
276
- if (!pub) return;
277
-
278
- let paramsStr = "";
279
- for (let param of meth.parameters) {
280
- if (!param || !param.name) continue;
281
- if (paramsStr.length > 0) paramsStr += ", ";
282
- let type = tryResolveTypeRecursive(param);
283
- if (type === undefined) type = "object";
284
- paramsStr += type + " @" + param.name.getText();
285
- }
286
- let methodName = meth.name.getText();
287
- switch (methodName) {
288
- case "onEnable": methodName = "OnEnable"; break;
289
- case "onDisable": methodName = "OnDisable"; break;
290
- }
291
- context.onBeforeMethod(methodName);
292
- // let visibility = pub ? "public" : "private";
293
- context.append("public void " + methodName + "(" + paramsStr + "){}\n");
294
- }
295
- break;
296
-
297
-
298
- case ts.SyntaxKind.SetAccessor:
299
- case ts.SyntaxKind.PropertyDeclaration:
300
- resetExportNextClass();
301
- if (!context) break;
302
- if (allowDebugLogs)
303
- console.log("Found variable", node.getText());
304
- const vardec = node as ts.VariableDeclaration;
305
-
306
- const varName = "@" + vardec.name.getText();
307
- const pub = isPublic(vardec);
308
- const visibility = pub ? "public" : "private";
309
- let isAccessible = pub;
310
- dontSerialize = false;
311
- if (serializeField) {
312
- if (allowDebugLogs)
313
- console.log("[SerializeField]");
314
- context.appendLine("[UnityEngine.SerializeField]");
315
- isAccessible = true;
316
- }
317
- else if (skip)
318
- isAccessible = false;
319
-
320
- if (!isAccessible) {
321
- if (allowDebugLogs)
322
- console.log("Skip because not public or serializeable")
323
- break;
324
- }
325
-
326
- const name = vardec.name.getText();
327
- if (allowDebugLogs)
328
- console.log("Variable:", name);
329
- if (name.startsWith("\"@") || name.startsWith("\"$") || name.startsWith("$")) break;
330
- let typeString = lastTypeFound ?? tryResolveTypeRecursive(node);
331
- let postFix = "";
332
- let typeName = vardec.type?.getText();
333
- let shouldCommentTheLine = typeString === undefined;
334
- if (typeString === undefined) {
335
- postFix = " → Could not resolve C# type";
336
- }
337
- let assignment = "";
338
- if (typeString !== undefined) {
339
- for (const ch of node.getChildren()) {
340
- switch (ch.kind) {
341
- default:
342
- // console.log("Unknown assignment:", ts.SyntaxKind[ch.kind]);
343
- break;
344
- case ts.SyntaxKind.NewExpression:
345
- assignment = " = " + getTypeForAssignment(ch);
346
- break;
347
- case ts.SyntaxKind.FalseKeyword:
348
- case ts.SyntaxKind.TrueKeyword:
349
- assignment = " = " + ch.getText();
350
- break;
351
- case ts.SyntaxKind.StringLiteral:
352
- const str = ch as ts.StringLiteral;
353
- assignment = " = \"" + str.text + "\"";
354
- break;
355
- case ts.SyntaxKind.FirstLiteralToken:
356
- const lit = ch as ts.LiteralExpression;
357
- assignment = " = " + lit.text;
358
- if (ts.isNumericLiteral(lit))
359
- assignment += "f";
360
- break;
361
- case ts.SyntaxKind.ArrayLiteralExpression:
362
- const arr = ch as ts.ArrayLiteralExpression;
363
- assignment = " = new " + typeString;
364
- // if (arr.elements.length > 0) {
365
- assignment += "{" + arr.elements.map(e => " " + getTypeForAssignment(e)) + " }";
366
- // }
367
- break;
368
- }
369
- }
370
- }
371
- let requireEndIf = false;
372
- if (ifdefSections.length > 0) {
373
- requireEndIf = true;
374
- context.appendLine("#ifdef " + ifdefSections.pop());
375
- }
376
- if (typeString === undefined) typeString = typeName;
377
- if (typeString === "[]") {
378
- if (allowDebugLogs)
379
- 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")
380
- // typeString = "object[]";
381
- // assignment = " = new object[0]";
382
- shouldCommentTheLine = true;
383
- }
384
- if (allowDebugLogs)
385
- console.log("EMIT member: \"" + typeString + "\" " + varName, assignment, "Last type found:", lastTypeFound);
386
- const prefix = shouldCommentTheLine ? "// " : "";
387
- context.append(prefix + visibility + " " + typeString + " " + varName + assignment + ";" + postFix + "\n");
388
- lastTypeFound = null;
389
- if (requireEndIf) {
390
- context.appendLine("#endif");
391
- }
392
- break;
393
-
394
- case ts.SyntaxKind.ClassDeclaration:
395
- serializeField = false;
396
- const dec = <ts.ClassDeclaration>node;
397
- // a class must inherit a component
398
- const inheritsComponent = testInheritsComponent(node);
399
- if (!dontExportNextClass && (lastTypeFound || exportNextClass || inheritsComponent)) {
400
- resetExportNextClass();
401
- const name = dec.name?.escapedText;
402
- if (allowDebugLogs)
403
- console.log("Found class: ", name);
404
- const namespace = tryParseNamespace(node) ?? "Needle.Typescript.GeneratedComponents";
405
- if (allowDebugLogs)
406
- console.log("NAMESPACE", namespace);
407
- const newContext = new ExportContext(outputDir, name + ".cs");
408
- newContext.appendLine("// auto generated code - do not edit directly");
409
- newContext.appendLine("");
410
- newContext.appendLine("#pragma warning disable");
411
- newContext.appendLine("");
412
- newContext.appendLine("namespace " + namespace);
413
- newContext.appendLine("{");
414
- newContext.indentLevel += 1;
415
- // newContext.appendLine("// source: " + path.resolve(sourceFile.fileName));
416
- let typeName = "UnityEngine.MonoBehaviour";
417
- if (typeof inheritsComponent === "string") typeName = inheritsComponent;
418
- if (lastTypeFound) typeName = lastTypeFound;
419
- if (allowDebugLogs)
420
- console.log(name + " inherits " + typeName);
421
- let modifiers = "";
422
- if (dec.modifiers) {
423
- for (const mod of dec.modifiers) {
424
- switch (mod.getText()) {
425
- case "abstract":
426
- modifiers += " abstract";
427
- if (allowDebugLogs)
428
- console.log(name + " is abstract");
429
- break;
430
- }
431
- }
432
- }
433
- modifiers += " partial";
434
- newContext.appendLine("public " + modifiers.trim() + " class " + name + " : " + typeName);
435
- newContext.appendLine("{");
436
- newContext.indentLevel += 1;
437
- newContext.classEnd = dec.end;
438
- contexts.push(newContext);
439
- }
440
- else {
441
- if (allowDebugLogs)
442
- console.log("Class type is unknown and will not generate a component: ", dec.name?.escapedText);
443
- }
444
- lastTypeFound = null;
445
- break;
446
- }
447
-
448
- function testInheritsComponent(node: ts.Node): boolean | string {
449
- switch (node.kind) {
450
- case ts.SyntaxKind.ClassDeclaration:
451
- const dec = <ts.ClassDeclaration>node;
452
- if (dec.heritageClauses) {
453
- for (const h of dec.heritageClauses) {
454
- if (h.types.length <= 0) continue;
455
- for (const type of h.types) {
456
- // const symbol = program.getTypeChecker().getSymbolAtLocation(type.expression);
457
- // console.log(symbol);
458
- const text = type.expression.getText();
459
- if (text === "Component") return true;
460
- if (text === "Behaviour") return true;
461
- const known = tryGetKnownType(text);
462
- if (known) return known;
463
- }
464
- }
465
- }
466
- return false;
467
- }
468
- return false;
469
- }
470
-
471
- function getTypeForAssignment(node: ts.Node) {
472
- // console.log("-------------------\nAssign", ts.SyntaxKind[node.kind]);
473
- switch (node.kind) {
474
- case ts.SyntaxKind.FirstLiteralToken:
475
- return node.getText();
476
- case ts.SyntaxKind.NewExpression:
477
- let type: string | undefined = undefined;
478
- let args: string | undefined = undefined;
479
- for (const ch of node.getChildren()) {
480
- const text = ch.getText();
481
- // console.log("child", ts.SyntaxKind[ch.kind], text);
482
- switch (ch.kind) {
483
- case ts.SyntaxKind.Identifier:
484
- case ts.SyntaxKind.PropertyAccessExpression:
485
- type = tryGetTypeFromText(text);
486
- break;
487
- case ts.SyntaxKind.SyntaxList:
488
- for (const arg of ch.getChildren()) {
489
- if (args === undefined) args = "";
490
- const res = getTypeForAssignment(arg);
491
- // handle floats being assigned with "f" suffix
492
- if (Number.parseFloat(res) >= 0) {
493
- args += res + "f";
494
- }
495
- else {
496
- args += res;
497
- if (res === ",") args += " ";
498
- }
499
- }
500
- break;
501
- }
502
- }
503
- if (!args) args = "";
504
- if (type) {
505
- console.log(type, args)
506
- return "new " + type + "(" + args + ")";
507
- }
508
- // const expType = node.getChildren().find(c => c.kind === ts.SyntaxKind.Identifier);
509
- break;
510
- }
511
- const str = node.getText();
512
- if (allowDebugLogs)
513
- console.log("Unknown assignment:", str, ts.SyntaxKind[node.kind]);
514
- return str;
515
- }
516
-
517
- function isPublic(node: ts.Node): boolean {
518
- if (node.kind === ts.SyntaxKind.PublicKeyword) {
519
- return true;
520
- }
521
- else if (node.kind === ts.SyntaxKind.PrivateKeyword || node.kind === ts.SyntaxKind.ProtectedKeyword) {
522
- return false;
523
- }
524
-
525
- for (const ch of node.getChildren()) {
526
- if (!isPublic(ch)) return false;
527
- }
528
- return true;
529
- }
530
-
531
- function tryParseNamespace(node: ts.Node, namespace?: string): string | null | undefined {
532
- // console.log("TRAVERSE - " + ts.SyntaxKind[node.kind]);
533
- switch (node.kind) {
534
- case ts.SyntaxKind.ModuleDeclaration:
535
- for (const ch of node.getChildren()) {
536
- // console.log("-- TRAVERSE - " + ts.SyntaxKind[ch.kind]);
537
- switch (ch.kind) {
538
- case ts.SyntaxKind.Identifier:
539
- const id = ch as ts.Identifier;
540
- if (id.text) {
541
- if (!namespace) namespace = "";
542
- namespace = id.text + (namespace ? "." : "") + namespace;
543
- }
544
- break;
545
- }
546
- }
547
- break;
548
- }
549
- if (node.parent) {
550
- return tryParseNamespace(node.parent, namespace);
551
- }
552
- return namespace;
553
- }
554
-
555
- function tryGetTypeFromText(typeName: string) {
556
-
557
- // if a type is imported via some namespace e.g. THREE.AnimationClip
558
- // we want to remove that namespace / import name
559
- const separatorIndex = typeName.lastIndexOf(".");
560
- if (separatorIndex > 0) {
561
- let newName = typeName.substring(separatorIndex + 1);
562
- if (allowDebugLogs)
563
- console.log("Remove import name from type: \"" + typeName + "\" → \"" + newName + "\"");
564
- typeName = newName;
565
- }
566
-
567
- let res = dict[typeName];
568
- if (res === undefined) {
569
- switch (typeName) {
570
- case "Array":
571
- break;
572
- default:
573
- const knownType = tryGetKnownType(typeName);
574
- res = knownType ?? undefined;
575
- break;
576
- }
577
- }
578
- // console.log(typeName, res);
579
- return res;
580
- }
581
-
582
- function tryResolveTypeRecursive(node: ts.Node | ts.VariableDeclaration): string | undefined {
583
- if (!node) return undefined;
584
-
585
- // skip decorators (e.g. @serializable() may break array generation)
586
- if (node.kind === ts.SyntaxKind.Decorator)
587
- return undefined;
588
-
589
- let typeName = node?.getText();
590
-
591
- const varDec: ts.VariableDeclaration = node as ts.VariableDeclaration;
592
- if (varDec.type) {
593
- typeName = varDec.type.getText();
594
- }
595
-
596
- let res: string | undefined = undefined;
597
-
598
-
599
-
600
- // console.log("Unknown type: " + typeName);
601
-
602
- switch (node.kind) {
603
- // case ts.SyntaxKind.SyntaxList:
604
- // const list = node as ts.SyntaxList;
605
- // for (const ch of list._children) {
606
- // res = tryResolveTypeRecursive(ch);
607
- // }
608
- // break;
609
- case ts.SyntaxKind.UnionType:
610
- const union = node as ts.UnionTypeNode;
611
- for (const t of union.types) {
612
- res = tryResolveTypeRecursive(t);
613
- if (res !== undefined) return res;
614
- }
615
- break;
616
-
617
- case ts.SyntaxKind.ArrayType:
618
- res = "[]";
619
- break;
620
-
621
- case ts.SyntaxKind.TypeReference:
622
- const typeRef = node as ts.TypeReferenceNode;
623
- const typeName = typeRef.typeName.getText();
624
- if (allowDebugLogs)
625
- console.log("TypeReference:", typeName);
626
- switch (typeName) {
627
- case "Array":
628
- break;
629
- default:
630
- return tryGetTypeFromText(typeName);
631
- }
632
- // return res;
633
- break;
634
-
635
- case ts.SyntaxKind.BooleanKeyword:
636
- case ts.SyntaxKind.NumberKeyword:
637
- case ts.SyntaxKind.StringKeyword:
638
- case ts.SyntaxKind.ObjectKeyword:
639
- const keyword = node.getText();
640
- // the basic keywords are declared in the static dictionary
641
- // no need for a complex lookup
642
- res = dict[keyword];
643
- break;
644
-
645
- case ts.SyntaxKind.Identifier:
646
- const id = node as ts.Identifier;
647
- switch (id.text) {
648
- // if we have an array we dont want to use the System.Array as a type but just make it to the array syntax
649
- case "Array":
650
- res = "[]";
651
- break;
652
- default:
653
- // console.log(id.text);
654
- // res = tryGetTypeFromText(id.text);
655
- break;
656
- }
657
- break;
658
- }
659
-
660
- let isInGenericDeclaration = false;
661
- for (const child of node.getChildren()) {
662
- // if (res !== undefined) break;
663
- // console.log("Child type: " + ts.SyntaxKind[child.kind]);
664
- let isGenericStart = false;
665
- let isAssignment = false;
666
- switch (child.kind) {
667
- case ts.SyntaxKind.FirstAssignment:
668
- isAssignment = true;
669
- break;
670
- case ts.SyntaxKind.FirstBinaryOperator:
671
- // console.log("Generic start: " + child.getText());
672
- isInGenericDeclaration = true;
673
- isGenericStart = true;
674
- break;
675
- case ts.SyntaxKind.GreaterThanGreaterThanToken:
676
- isInGenericDeclaration = false;
677
- // console.log("Generic end: " + child.getText());
678
- break;
679
- }
680
- // if (isAssignment) break;
681
- const childResult = tryResolveTypeRecursive(child);
682
- if (childResult !== undefined) {
683
- if (res === undefined) res = "";
684
- if (allowDebugLogs)
685
- console.log("Child: " + ts.SyntaxKind[child.kind] + " → " + childResult);
686
- // if the thing is a generic return as generic result
687
- if (isInGenericDeclaration && !res.includes("[]")) {
688
- res = "<" + childResult + ">";
689
- }
690
- // we got a generic result, these need to be appended
691
- else if (childResult.startsWith("<")) {
692
- res += childResult;
693
- }
694
- // concat default
695
- else
696
- res = childResult + res;
697
- }
698
- }
699
-
700
- // if (ts.isTypeReferenceNode(node)) {
701
- // const typeRef = node as ts.TypeReferenceNode;
702
- // const typeName = typeRef.typeName.getText();
703
- // switch (typeName) {
704
- // case "Array":
705
- // res += "[]";
706
- // return res;
707
- // }
708
- // }
709
-
710
- return res;
711
- }
712
- }
713
- }
714
-
715
-
716
- if (process) {
717
-
718
- if (process.argv.length < 4) {
719
- console.error("Missing args, call with: <output_dir> <input_files>");
720
- }
721
- else {
722
- const outputDir = process.argv[2];
723
- const fileNames = process.argv.slice(3);
724
- fileNames.forEach(fileName => {
725
- if (!fs.existsSync(fileName)) {
726
-
727
- }
728
- else {
729
- const code = readFileSync(fileName).toString();
730
- compile(code, fileName, outputDir);
731
- }
732
- });
733
- }
734
- }