typescript-to-lua 1.6.2 → 1.7.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.
Files changed (101) hide show
  1. package/dist/CompilerOptions.d.ts +1 -0
  2. package/dist/cli/diagnostics.d.ts +3 -0
  3. package/dist/cli/diagnostics.js +2 -1
  4. package/dist/cli/parse.d.ts +1 -1
  5. package/dist/cli/parse.js +47 -11
  6. package/dist/lualib/ArraySlice.lua +10 -2
  7. package/dist/lualib/ArraySplice.lua +5 -1
  8. package/dist/lualib/Generator.lua +8 -1
  9. package/dist/lualib/ParseFloat.lua +5 -1
  10. package/dist/lualib/SparseArraySpread.lua +5 -1
  11. package/dist/lualib/StringCharCodeAt.lua +5 -1
  12. package/dist/lualib/lualib_bundle.lua +38 -7
  13. package/dist/lualib-build/plugin.js +1 -2
  14. package/dist/measure-performance.d.ts +15 -0
  15. package/dist/measure-performance.js +83 -0
  16. package/dist/transformation/builtins/array.js +2 -1
  17. package/dist/transformation/builtins/function.js +1 -1
  18. package/dist/transformation/builtins/global.d.ts +1 -1
  19. package/dist/transformation/builtins/global.js +13 -12
  20. package/dist/transformation/builtins/index.d.ts +2 -2
  21. package/dist/transformation/builtins/index.js +87 -89
  22. package/dist/transformation/builtins/object.d.ts +1 -1
  23. package/dist/transformation/builtins/object.js +4 -4
  24. package/dist/transformation/builtins/promise.js +4 -2
  25. package/dist/transformation/builtins/string.js +2 -0
  26. package/dist/transformation/context/context.d.ts +15 -0
  27. package/dist/transformation/context/context.js +66 -24
  28. package/dist/transformation/context/visitors.d.ts +1 -1
  29. package/dist/transformation/index.js +6 -5
  30. package/dist/transformation/utils/annotations.d.ts +1 -17
  31. package/dist/transformation/utils/annotations.js +48 -88
  32. package/dist/transformation/utils/assignment-validation.js +27 -23
  33. package/dist/transformation/utils/diagnostics.d.ts +1 -4
  34. package/dist/transformation/utils/diagnostics.js +2 -3
  35. package/dist/transformation/utils/function-context.d.ts +1 -1
  36. package/dist/transformation/utils/function-context.js +57 -51
  37. package/dist/transformation/utils/language-extensions.d.ts +57 -51
  38. package/dist/transformation/utils/language-extensions.js +99 -119
  39. package/dist/transformation/utils/lualib.d.ts +0 -1
  40. package/dist/transformation/utils/lualib.js +2 -8
  41. package/dist/transformation/utils/safe-names.d.ts +1 -1
  42. package/dist/transformation/utils/safe-names.js +3 -6
  43. package/dist/transformation/utils/scope.d.ts +0 -2
  44. package/dist/transformation/utils/scope.js +10 -27
  45. package/dist/transformation/utils/symbols.d.ts +1 -1
  46. package/dist/transformation/utils/symbols.js +7 -20
  47. package/dist/transformation/utils/typescript/index.d.ts +1 -0
  48. package/dist/transformation/utils/typescript/index.js +2 -1
  49. package/dist/transformation/utils/typescript/types.d.ts +2 -5
  50. package/dist/transformation/utils/typescript/types.js +27 -37
  51. package/dist/transformation/visitors/access.js +1 -4
  52. package/dist/transformation/visitors/block.js +4 -4
  53. package/dist/transformation/visitors/call.js +7 -18
  54. package/dist/transformation/visitors/class/index.js +8 -20
  55. package/dist/transformation/visitors/class/members/constructor.js +2 -2
  56. package/dist/transformation/visitors/class/new.js +2 -5
  57. package/dist/transformation/visitors/class/setup.d.ts +1 -1
  58. package/dist/transformation/visitors/class/setup.js +4 -4
  59. package/dist/transformation/visitors/class/utils.d.ts +1 -1
  60. package/dist/transformation/visitors/class/utils.js +2 -9
  61. package/dist/transformation/visitors/conditional.js +4 -4
  62. package/dist/transformation/visitors/function.d.ts +1 -1
  63. package/dist/transformation/visitors/function.js +8 -16
  64. package/dist/transformation/visitors/identifier.d.ts +1 -0
  65. package/dist/transformation/visitors/identifier.js +40 -44
  66. package/dist/transformation/visitors/language-extensions/call-extension.d.ts +10 -0
  67. package/dist/transformation/visitors/language-extensions/call-extension.js +23 -0
  68. package/dist/transformation/visitors/language-extensions/identifier.d.ts +5 -0
  69. package/dist/transformation/visitors/language-extensions/identifier.js +27 -0
  70. package/dist/transformation/visitors/language-extensions/iterable.d.ts +2 -3
  71. package/dist/transformation/visitors/language-extensions/iterable.js +21 -22
  72. package/dist/transformation/visitors/language-extensions/multi.d.ts +0 -1
  73. package/dist/transformation/visitors/language-extensions/multi.js +10 -24
  74. package/dist/transformation/visitors/language-extensions/operators.d.ts +2 -5
  75. package/dist/transformation/visitors/language-extensions/operators.js +89 -96
  76. package/dist/transformation/visitors/language-extensions/range.js +4 -2
  77. package/dist/transformation/visitors/language-extensions/table.d.ts +6 -3
  78. package/dist/transformation/visitors/language-extensions/table.js +46 -75
  79. package/dist/transformation/visitors/language-extensions/vararg.js +7 -3
  80. package/dist/transformation/visitors/literal.js +2 -23
  81. package/dist/transformation/visitors/loops/for-of.js +18 -18
  82. package/dist/transformation/visitors/loops/utils.js +5 -5
  83. package/dist/transformation/visitors/namespace.js +5 -14
  84. package/dist/transformation/visitors/return.js +2 -3
  85. package/dist/transformation/visitors/sourceFile.js +3 -4
  86. package/dist/transformation/visitors/spread.js +0 -5
  87. package/dist/transformation/visitors/switch.js +2 -2
  88. package/dist/transformation/visitors/variable-declaration.js +1 -1
  89. package/dist/transpilation/index.js +4 -8
  90. package/dist/transpilation/plugins.js +3 -0
  91. package/dist/transpilation/resolve.js +144 -161
  92. package/dist/transpilation/transpile.js +10 -0
  93. package/dist/transpilation/transpiler.d.ts +1 -0
  94. package/dist/transpilation/transpiler.js +18 -5
  95. package/dist/tstl.js +23 -4
  96. package/language-extensions/index.d.ts +167 -67
  97. package/package.json +2 -2
  98. package/dist/transformation/visitors/language-extensions/index.d.ts +0 -4
  99. package/dist/transformation/visitors/language-extensions/index.js +0 -17
  100. package/dist/transformation/visitors/language-extensions/pairsIterable.d.ts +0 -5
  101. package/dist/transformation/visitors/language-extensions/pairsIterable.js +0 -53
@@ -21,79 +21,154 @@ class ResolutionContext {
21
21
  this.program = program;
22
22
  this.options = options;
23
23
  this.emitHost = emitHost;
24
- this.resultsCache = new Map();
24
+ this.diagnostics = [];
25
+ this.resolvedFiles = new Map();
26
+ this.processedDependencies = new Set();
27
+ // value is false if already searched but not found
28
+ this.pathToFile = new Map();
25
29
  this.noResolvePaths = new Set(options.noResolvePaths);
26
30
  }
27
- resolve(file, required) {
31
+ addAndResolveDependencies(file) {
32
+ if (this.resolvedFiles.has(file.fileName))
33
+ return;
34
+ this.resolvedFiles.set(file.fileName, file);
35
+ for (const required of findRequiredPaths(file.code)) {
36
+ // Do not resolve noResolution paths
37
+ if (required.startsWith("@NoResolution:")) {
38
+ // Remove @NoResolution prefix if not building in library mode
39
+ if (!isBuildModeLibrary(this.program)) {
40
+ const path = required.replace("@NoResolution:", "");
41
+ replaceRequireInCode(file, required, path);
42
+ replaceRequireInSourceMap(file, required, path);
43
+ }
44
+ // Skip
45
+ continue;
46
+ }
47
+ // Try to resolve the import starting from the directory `file` is in
48
+ this.resolveImport(file, required);
49
+ }
50
+ }
51
+ resolveImport(file, required) {
52
+ // Do no resolve lualib - always use the lualib of the application entry point, not the lualib from external packages
53
+ if (required === "lualib_bundle") {
54
+ this.resolvedFiles.set("lualib_bundle", { fileName: "lualib_bundle", code: "" });
55
+ return;
56
+ }
28
57
  if (this.noResolvePaths.has(required)) {
29
58
  if (this.options.tstlVerbose) {
30
59
  console.log(`Skipping module resolution of ${required} as it is in the tsconfig noResolvePaths.`);
31
60
  }
32
- return { resolvedFiles: [], diagnostics: [] };
61
+ return;
33
62
  }
34
- const resolvedDependency = resolveDependency(file, required, this.program, this.emitHost);
35
- if (resolvedDependency) {
36
- if (this.options.tstlVerbose) {
37
- console.log(`Resolved ${required} to ${(0, utils_1.normalizeSlashes)(resolvedDependency)}`);
38
- }
39
- // Figure out resolved require path and dependency output path
40
- const resolvedRequire = (0, transpiler_1.getEmitPathRelativeToOutDir)(resolvedDependency, this.program);
41
- if (shouldRewriteRequires(resolvedDependency, this.program)) {
42
- replaceRequireInCode(file, required, resolvedRequire);
43
- replaceRequireInSourceMap(file, required, resolvedRequire);
44
- }
45
- // Check cache to prevent resolving nested dependencies double to break dependency loops
46
- if (this.resultsCache.has(resolvedDependency)) {
47
- if (this.options.tstlVerbose) {
48
- console.log(`Resolution cache hit for ${(0, utils_1.normalizeSlashes)(resolvedDependency)}`);
49
- }
50
- return this.resultsCache.get(resolvedDependency);
51
- }
52
- // If dependency is not part of project, add dependency to output and resolve its dependencies recursively
53
- if (shouldIncludeDependency(resolvedDependency, this.program)) {
54
- // If dependency resolved successfully, read its content
55
- const dependencyContent = this.emitHost.readFile(resolvedDependency);
56
- if (dependencyContent === undefined) {
57
- return { resolvedFiles: [], diagnostics: [(0, diagnostics_1.couldNotReadDependency)(resolvedDependency)] };
58
- }
59
- const dependency = {
60
- fileName: resolvedDependency,
61
- code: dependencyContent,
62
- };
63
- const nestedDependencies = resolveFileDependencies(dependency, this);
64
- // Cache result and return
65
- const result = {
66
- resolvedFiles: [dependency, ...nestedDependencies.resolvedFiles],
67
- diagnostics: [...nestedDependencies.diagnostics],
68
- };
69
- this.resultsCache.set(resolvedDependency, result);
70
- return result;
63
+ const dependencyPath = this.resolveDependencyPath(file, required);
64
+ if (!dependencyPath)
65
+ return this.couldNotResolveImport(required, file);
66
+ if (this.options.tstlVerbose) {
67
+ console.log(`Resolved ${required} to ${(0, utils_1.normalizeSlashes)(dependencyPath)}`);
68
+ }
69
+ this.processDependency(dependencyPath);
70
+ // Figure out resolved require path and dependency output path
71
+ if (shouldRewriteRequires(dependencyPath, this.program)) {
72
+ const resolvedRequire = (0, transpiler_1.getEmitPathRelativeToOutDir)(dependencyPath, this.program);
73
+ replaceRequireInCode(file, required, resolvedRequire);
74
+ replaceRequireInSourceMap(file, required, resolvedRequire);
75
+ }
76
+ }
77
+ processDependency(dependencyPath) {
78
+ if (this.processedDependencies.has(dependencyPath))
79
+ return;
80
+ this.processedDependencies.add(dependencyPath);
81
+ if (!shouldIncludeDependency(dependencyPath, this.program))
82
+ return;
83
+ // If dependency is not part of project, add dependency to output and resolve its dependencies recursively
84
+ const dependencyContent = this.emitHost.readFile(dependencyPath);
85
+ if (dependencyContent === undefined) {
86
+ this.diagnostics.push((0, diagnostics_1.couldNotReadDependency)(dependencyPath));
87
+ return;
88
+ }
89
+ const dependency = {
90
+ fileName: dependencyPath,
91
+ code: dependencyContent,
92
+ };
93
+ this.addAndResolveDependencies(dependency);
94
+ }
95
+ couldNotResolveImport(required, file) {
96
+ const fallbackRequire = fallbackResolve(required, (0, transpiler_1.getSourceDir)(this.program), path.dirname(file.fileName));
97
+ replaceRequireInCode(file, required, fallbackRequire);
98
+ replaceRequireInSourceMap(file, required, fallbackRequire);
99
+ this.diagnostics.push((0, diagnostics_1.couldNotResolveRequire)(required, path.relative((0, transpiler_1.getProjectRoot)(this.program), file.fileName)));
100
+ }
101
+ resolveDependencyPath(requiringFile, dependency) {
102
+ var _a;
103
+ const fileDirectory = path.dirname(requiringFile.fileName);
104
+ if (this.options.tstlVerbose) {
105
+ console.log(`Resolving "${dependency}" from ${(0, utils_1.normalizeSlashes)(requiringFile.fileName)}`);
106
+ }
107
+ // Check if the import is relative
108
+ const isRelative = ["/", "./", "../"].some(p => dependency.startsWith(p));
109
+ // If the import is relative, always resolve it relative to the requiring file
110
+ // If the import is not relative, resolve it relative to options.baseUrl if it is set
111
+ const relativeTo = isRelative ? fileDirectory : (_a = this.options.baseUrl) !== null && _a !== void 0 ? _a : fileDirectory;
112
+ // Check if file is a file in the project
113
+ const resolvedPath = path.join(relativeTo, dependency);
114
+ const fileFromPath = this.getFileFromPath(resolvedPath);
115
+ if (fileFromPath)
116
+ return fileFromPath;
117
+ // Check if this is a sibling of a required lua file
118
+ if (requiringFile.fileName.endsWith(".lua")) {
119
+ const luaFilePath = resolveLuaPath(fileDirectory, dependency, this.emitHost);
120
+ if (luaFilePath) {
121
+ return luaFilePath;
71
122
  }
72
- else {
73
- const result = {
74
- resolvedFiles: [],
75
- diagnostics: [],
76
- };
77
- this.resultsCache.set(resolvedDependency, result);
78
- return result;
123
+ }
124
+ // Not a TS file in our project sources, use resolver to check if we can find dependency
125
+ try {
126
+ const resolveResult = resolver.resolveSync({}, fileDirectory, dependency);
127
+ if (resolveResult)
128
+ return resolveResult;
129
+ }
130
+ catch (e) {
131
+ // resolveSync errors if it fails to resolve
132
+ }
133
+ return undefined;
134
+ }
135
+ getFileFromPath(resolvedPath) {
136
+ const existingFile = this.pathToFile.get(resolvedPath);
137
+ if (existingFile)
138
+ return existingFile;
139
+ if (existingFile === false)
140
+ return undefined;
141
+ const file = this.searchForFileFromPath(resolvedPath);
142
+ this.pathToFile.set(resolvedPath, file !== null && file !== void 0 ? file : false);
143
+ return file;
144
+ }
145
+ searchForFileFromPath(resolvedPath) {
146
+ const possibleProjectFiles = [
147
+ resolvedPath,
148
+ resolvedPath + ".ts",
149
+ path.join(resolvedPath, "index.ts"),
150
+ resolvedPath + ".tsx",
151
+ path.join(resolvedPath, "index.tsx"), // tsx index
152
+ ];
153
+ for (const possibleFile of possibleProjectFiles) {
154
+ if (isProjectFile(possibleFile, this.program)) {
155
+ return possibleFile;
79
156
  }
80
157
  }
81
- else {
82
- const fallbackRequire = fallbackResolve(required, (0, transpiler_1.getSourceDir)(this.program), path.dirname(file.fileName));
83
- replaceRequireInCode(file, required, fallbackRequire);
84
- replaceRequireInSourceMap(file, required, fallbackRequire);
85
- return {
86
- resolvedFiles: [],
87
- diagnostics: [
88
- (0, diagnostics_1.couldNotResolveRequire)(required, path.relative((0, transpiler_1.getProjectRoot)(this.program), file.fileName)),
89
- ],
90
- };
158
+ // Check if this is a lua file in the project sources
159
+ const possibleLuaProjectFiles = [
160
+ resolvedPath + ".lua",
161
+ path.join(resolvedPath, "index.lua"),
162
+ path.join(resolvedPath, "init.lua"), // lua looks for <require>/init.lua if it cannot find <require>.lua
163
+ ];
164
+ for (const possibleFile of possibleLuaProjectFiles) {
165
+ if (this.emitHost.fileExists(possibleFile)) {
166
+ return possibleFile;
167
+ }
91
168
  }
92
169
  }
93
170
  }
94
171
  function resolveDependencies(program, files, emitHost) {
95
- const outFiles = [...files];
96
- const diagnostics = [];
97
172
  const options = program.getCompilerOptions();
98
173
  const resolutionContext = new ResolutionContext(program, options, emitHost);
99
174
  // Resolve dependencies for all processed files
@@ -101,99 +176,11 @@ function resolveDependencies(program, files, emitHost) {
101
176
  if (options.tstlVerbose) {
102
177
  console.log(`Resolving dependencies for ${(0, utils_1.normalizeSlashes)(file.fileName)}`);
103
178
  }
104
- const resolutionResult = resolveFileDependencies(file, resolutionContext);
105
- outFiles.push(...resolutionResult.resolvedFiles);
106
- diagnostics.push(...resolutionResult.diagnostics);
179
+ resolutionContext.addAndResolveDependencies(file);
107
180
  }
108
- return { resolvedFiles: deduplicateResolvedFiles(outFiles), diagnostics };
181
+ return { resolvedFiles: [...resolutionContext.resolvedFiles.values()], diagnostics: resolutionContext.diagnostics };
109
182
  }
110
183
  exports.resolveDependencies = resolveDependencies;
111
- function deduplicateResolvedFiles(files) {
112
- return [...new Map(files.map(f => [f.fileName, f])).values()];
113
- }
114
- function resolveFileDependencies(file, context) {
115
- const dependencies = [];
116
- const diagnostics = [];
117
- for (const required of findRequiredPaths(file.code)) {
118
- // Do no resolve lualib - always use the lualib of the application entry point, not the lualib from external packages
119
- if (required === "lualib_bundle") {
120
- dependencies.push({ fileName: "lualib_bundle", code: "" });
121
- continue;
122
- }
123
- // Do not resolve noResolution paths
124
- if (required.startsWith("@NoResolution:")) {
125
- // Remove @NoResolution prefix if not building in library mode
126
- if (!isBuildModeLibrary(context.program)) {
127
- const path = required.replace("@NoResolution:", "");
128
- replaceRequireInCode(file, required, path);
129
- replaceRequireInSourceMap(file, required, path);
130
- }
131
- // Skip
132
- continue;
133
- }
134
- // Try to resolve the import starting from the directory `file` is in
135
- const resolvedDependency = context.resolve(file, required);
136
- dependencies.push(...resolvedDependency.resolvedFiles);
137
- diagnostics.push(...resolvedDependency.diagnostics);
138
- }
139
- return { resolvedFiles: deduplicateResolvedFiles(dependencies), diagnostics };
140
- }
141
- function resolveDependency(requiringFile, dependency, program, emitHost) {
142
- var _a;
143
- const options = program.getCompilerOptions();
144
- const fileDirectory = path.dirname(requiringFile.fileName);
145
- if (options.tstlVerbose) {
146
- console.log(`Resolving "${dependency}" from ${(0, utils_1.normalizeSlashes)(requiringFile.fileName)}`);
147
- }
148
- // Check if the import is relative
149
- const isRelative = ["/", "./", "../"].some(p => dependency.startsWith(p));
150
- // If the import is relative, always resolve it relative to the requiring file
151
- // If the import is not relative, resolve it relative to options.baseUrl if it is set
152
- const relativeTo = isRelative ? fileDirectory : (_a = options.baseUrl) !== null && _a !== void 0 ? _a : fileDirectory;
153
- // Check if file is a file in the project
154
- const resolvedPath = path.join(relativeTo, dependency);
155
- const possibleProjectFiles = [
156
- resolvedPath,
157
- resolvedPath + ".ts",
158
- path.join(resolvedPath, "index.ts"),
159
- resolvedPath + ".tsx",
160
- path.join(resolvedPath, "index.tsx"), // tsx index
161
- ];
162
- for (const possibleFile of possibleProjectFiles) {
163
- if (isProjectFile(possibleFile, program)) {
164
- return possibleFile;
165
- }
166
- }
167
- // Check if this is a lua file in the project sources
168
- const possibleLuaProjectFiles = [
169
- resolvedPath + ".lua",
170
- path.join(resolvedPath, "index.lua"),
171
- path.join(resolvedPath, "init.lua"), // lua looks for <require>/init.lua if it cannot find <require>.lua
172
- ];
173
- for (const possibleFile of possibleLuaProjectFiles) {
174
- if (emitHost.fileExists(possibleFile)) {
175
- return possibleFile;
176
- }
177
- }
178
- // Check if this is a sibling of a required lua file
179
- if (requiringFile.fileName.endsWith(".lua")) {
180
- const luaFilePath = resolveLuaPath(fileDirectory, dependency, emitHost);
181
- if (luaFilePath) {
182
- return luaFilePath;
183
- }
184
- }
185
- // Not a TS file in our project sources, use resolver to check if we can find dependency
186
- try {
187
- const resolveResult = resolver.resolveSync({}, fileDirectory, dependency);
188
- if (resolveResult) {
189
- return resolveResult;
190
- }
191
- }
192
- catch (e) {
193
- // resolveSync errors if it fails to resolve
194
- }
195
- return undefined;
196
- }
197
184
  function resolveLuaPath(fromPath, dependency, emitHost) {
198
185
  const splitDependency = dependency.split(".");
199
186
  if (splitDependency.length === 1) {
@@ -223,21 +210,17 @@ function walkUpFileTreeUntil(fromDirectory, predicate) {
223
210
  return undefined;
224
211
  }
225
212
  function shouldRewriteRequires(resolvedDependency, program) {
226
- return !isNodeModulesFile(resolvedDependency) || !isBuildModeLibrary(program);
213
+ return !isBuildModeLibrary(program) || !isNodeModulesFile(resolvedDependency);
227
214
  }
228
215
  function shouldIncludeDependency(resolvedDependency, program) {
229
216
  // Never include lua files (again) that are transpiled from project sources
230
- if (!hasSourceFileInProject(resolvedDependency, program)) {
231
- // Always include lua files not in node_modules (internal lua sources)
232
- if (!isNodeModulesFile(resolvedDependency)) {
233
- return true;
234
- }
235
- else {
236
- // Only include node_modules files if not in library mode
237
- return !isBuildModeLibrary(program);
238
- }
239
- }
240
- return false;
217
+ if (hasSourceFileInProject(resolvedDependency, program))
218
+ return false;
219
+ // Always include lua files not in node_modules (internal lua sources)
220
+ if (!isNodeModulesFile(resolvedDependency))
221
+ return true;
222
+ // Only include node_modules files if not in library mode
223
+ return !isBuildModeLibrary(program);
241
224
  }
242
225
  function isBuildModeLibrary(program) {
243
226
  return program.getCompilerOptions().buildMode === CompilerOptions_1.BuildMode.Library;
@@ -8,8 +8,10 @@ const LuaPrinter_1 = require("../LuaPrinter");
8
8
  const transformation_1 = require("../transformation");
9
9
  const utils_1 = require("../utils");
10
10
  const transformers_1 = require("./transformers");
11
+ const performance = require("../measure-performance");
11
12
  function getProgramTranspileResult(emitHost, writeFileResult, { program, sourceFiles: targetSourceFiles, customTransformers = {}, plugins = [] }) {
12
13
  var _a, _b;
14
+ performance.startSection("beforeTransform");
13
15
  const options = program.getCompilerOptions();
14
16
  if (options.tstlVerbose) {
15
17
  console.log("Parsing project settings");
@@ -36,6 +38,7 @@ function getProgramTranspileResult(emitHost, writeFileResult, { program, sourceF
36
38
  preEmitDiagnostics.push(...program.getDeclarationDiagnostics());
37
39
  }
38
40
  if (preEmitDiagnostics.length > 0) {
41
+ performance.endSection("beforeTransform");
39
42
  return { diagnostics: preEmitDiagnostics, transpiledFiles };
40
43
  }
41
44
  }
@@ -51,9 +54,12 @@ function getProgramTranspileResult(emitHost, writeFileResult, { program, sourceF
51
54
  if (options.tstlVerbose) {
52
55
  console.log(`Transforming ${sourceFile.fileName}`);
53
56
  }
57
+ performance.startSection("transpile");
54
58
  const { file, diagnostics: transformDiagnostics } = (0, transformation_1.transformSourceFile)(program, sourceFile, visitorMap);
55
59
  diagnostics.push(...transformDiagnostics);
60
+ performance.endSection("transpile");
56
61
  if (!options.noEmit && !options.emitDeclarationOnly) {
62
+ performance.startSection("print");
57
63
  if (options.tstlVerbose) {
58
64
  console.log(`Printing ${sourceFile.fileName}`);
59
65
  }
@@ -64,6 +70,7 @@ function getProgramTranspileResult(emitHost, writeFileResult, { program, sourceF
64
70
  luaAst: file,
65
71
  ...printResult,
66
72
  });
73
+ performance.endSection("print");
67
74
  }
68
75
  };
69
76
  const transformers = (0, transformers_1.getTransformers)(program, diagnostics, customTransformers, processSourceFile);
@@ -78,6 +85,7 @@ function getProgramTranspileResult(emitHost, writeFileResult, { program, sourceF
78
85
  writeFileResult(fileName, ...rest);
79
86
  }
80
87
  };
88
+ performance.endSection("beforeTransform");
81
89
  if (targetSourceFiles) {
82
90
  for (const file of targetSourceFiles) {
83
91
  if (isEmittableJsonFile(file)) {
@@ -93,6 +101,7 @@ function getProgramTranspileResult(emitHost, writeFileResult, { program, sourceF
93
101
  // JSON files don't get through transformers and aren't written when outDir is the same as rootDir
94
102
  program.getSourceFiles().filter(isEmittableJsonFile).forEach(processSourceFile);
95
103
  }
104
+ performance.startSection("afterPrint");
96
105
  options.noEmit = oldNoEmit;
97
106
  if (options.noEmit || (options.noEmitOnError && diagnostics.length > 0)) {
98
107
  transpiledFiles = [];
@@ -103,6 +112,7 @@ function getProgramTranspileResult(emitHost, writeFileResult, { program, sourceF
103
112
  diagnostics.push(...pluginDiagnostics);
104
113
  }
105
114
  }
115
+ performance.endSection("afterPrint");
106
116
  return { diagnostics, transpiledFiles };
107
117
  }
108
118
  exports.getProgramTranspileResult = getProgramTranspileResult;
@@ -15,6 +15,7 @@ export declare class Transpiler {
15
15
  protected emitHost: EmitHost;
16
16
  constructor({ emitHost }?: TranspilerOptions);
17
17
  emit(emitOptions: EmitOptions): EmitResult;
18
+ private emitFiles;
18
19
  protected getEmitPlan(program: ts.Program, diagnostics: ts.Diagnostic[], files: ProcessedFile[]): {
19
20
  emitPlan: EmitFile[];
20
21
  };
@@ -10,24 +10,34 @@ const bundle_1 = require("./bundle");
10
10
  const plugins_1 = require("./plugins");
11
11
  const resolve_1 = require("./resolve");
12
12
  const transpile_1 = require("./transpile");
13
+ const performance = require("../measure-performance");
13
14
  class Transpiler {
14
15
  constructor({ emitHost = ts.sys } = {}) {
15
16
  this.emitHost = emitHost;
16
17
  }
17
18
  emit(emitOptions) {
18
- var _a, _b;
19
19
  const { program, writeFile = this.emitHost.writeFile, plugins: optionsPlugins = [] } = emitOptions;
20
- const options = program.getCompilerOptions();
21
20
  const { diagnostics: getPluginsDiagnostics, plugins: configPlugins } = (0, plugins_1.getPlugins)(program);
22
21
  const plugins = [...optionsPlugins, ...configPlugins];
23
- const { diagnostics, transpiledFiles: freshFiles } = (0, transpile_1.getProgramTranspileResult)(this.emitHost, writeFile, {
22
+ const { diagnostics: transpileDiagnostics, transpiledFiles: freshFiles } = (0, transpile_1.getProgramTranspileResult)(this.emitHost, writeFile, {
24
23
  ...emitOptions,
25
24
  plugins,
26
25
  });
27
- const { emitPlan } = this.getEmitPlan(program, diagnostics, freshFiles);
26
+ const { emitPlan } = this.getEmitPlan(program, transpileDiagnostics, freshFiles);
27
+ const emitDiagnostics = this.emitFiles(program, plugins, emitPlan, writeFile);
28
+ return {
29
+ diagnostics: getPluginsDiagnostics.concat(transpileDiagnostics, emitDiagnostics),
30
+ emitSkipped: emitPlan.length === 0,
31
+ };
32
+ }
33
+ emitFiles(program, plugins, emitPlan, writeFile) {
34
+ var _a, _b;
35
+ performance.startSection("emit");
36
+ const options = program.getCompilerOptions();
28
37
  if (options.tstlVerbose) {
29
38
  console.log("Emitting output");
30
39
  }
40
+ const diagnostics = [];
31
41
  for (const plugin of plugins) {
32
42
  if (plugin.beforeEmit) {
33
43
  const beforeEmitPluginDiagnostics = (_a = plugin.beforeEmit(program, options, this.emitHost, emitPlan)) !== null && _a !== void 0 ? _a : [];
@@ -47,9 +57,11 @@ class Transpiler {
47
57
  if (options.tstlVerbose) {
48
58
  console.log("Emit finished!");
49
59
  }
50
- return { diagnostics: getPluginsDiagnostics.concat(diagnostics), emitSkipped: emitPlan.length === 0 };
60
+ performance.endSection("emit");
61
+ return diagnostics;
51
62
  }
52
63
  getEmitPlan(program, diagnostics, files) {
64
+ performance.startSection("getEmitPlan");
53
65
  const options = program.getCompilerOptions();
54
66
  if (options.tstlVerbose) {
55
67
  console.log("Constructing emit plan");
@@ -80,6 +92,7 @@ class Transpiler {
80
92
  outputPath: getEmitPath(file.fileName, program),
81
93
  }));
82
94
  }
95
+ performance.endSection("getEmitPlan");
83
96
  return { emitPlan };
84
97
  }
85
98
  }
package/dist/tstl.js CHANGED
@@ -9,6 +9,7 @@ const parse_1 = require("./cli/parse");
9
9
  const report_1 = require("./cli/report");
10
10
  const tsconfig_1 = require("./cli/tsconfig");
11
11
  const CompilerOptions_1 = require("./CompilerOptions");
12
+ const performance = require("./measure-performance");
12
13
  const shouldBePretty = ({ pretty } = {}) => { var _a, _b, _c; return pretty !== undefined ? pretty : (_c = (_b = (_a = ts.sys).writeOutputIsTTY) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : false; };
13
14
  let reportDiagnostic = (0, report_1.createDiagnosticReporter)(false);
14
15
  function updateReportDiagnostic(options) {
@@ -75,18 +76,22 @@ function performBuild(_args) {
75
76
  return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped);
76
77
  }
77
78
  function performCompilation(rootNames, projectReferences, options, configFileParsingDiagnostics) {
79
+ if (options.measurePerformance)
80
+ performance.enableMeasurement();
81
+ performance.startSection("createProgram");
78
82
  const program = ts.createProgram({
79
83
  rootNames,
80
84
  options,
81
85
  projectReferences,
82
86
  configFileParsingDiagnostics,
83
87
  });
88
+ const preEmitDiagnostics = ts.getPreEmitDiagnostics(program);
89
+ performance.endSection("createProgram");
84
90
  const { diagnostics: transpileDiagnostics, emitSkipped } = new tstl.Transpiler().emit({ program });
85
- const diagnostics = ts.sortAndDeduplicateDiagnostics([
86
- ...ts.getPreEmitDiagnostics(program),
87
- ...transpileDiagnostics,
88
- ]);
91
+ const diagnostics = ts.sortAndDeduplicateDiagnostics([...preEmitDiagnostics, ...transpileDiagnostics]);
89
92
  diagnostics.forEach(reportDiagnostic);
93
+ if (options.measurePerformance)
94
+ reportPerformance();
90
95
  const exitCode = diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error).length === 0
91
96
  ? ts.ExitStatus.Success
92
97
  : emitSkipped
@@ -111,6 +116,8 @@ function updateWatchCompilationHost(host, optionsToExtend) {
111
116
  host.afterProgramCreate = builderProgram => {
112
117
  const program = builderProgram.getProgram();
113
118
  const options = builderProgram.getCompilerOptions();
119
+ if (options.measurePerformance)
120
+ performance.enableMeasurement();
114
121
  const configFileParsingDiagnostics = updateConfigFile(options);
115
122
  let sourceFiles;
116
123
  if (!(0, CompilerOptions_1.isBundleEnabled)(options) && !hadErrorLastTime) {
@@ -137,11 +144,23 @@ function updateWatchCompilationHost(host, optionsToExtend) {
137
144
  ...emitDiagnostics,
138
145
  ]);
139
146
  diagnostics.forEach(reportDiagnostic);
147
+ if (options.measurePerformance)
148
+ reportPerformance();
140
149
  const errors = diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error);
141
150
  hadErrorLastTime = errors.length > 0;
142
151
  host.onWatchStatusChange(cliDiagnostics.watchErrorSummary(errors.length), host.getNewLine(), options);
143
152
  };
144
153
  }
154
+ function reportPerformance() {
155
+ if (performance.isMeasurementEnabled()) {
156
+ console.log("Performance measurements: ");
157
+ performance.forEachMeasure((name, duration) => {
158
+ console.log(` ${name}: ${duration.toFixed(2)}ms`);
159
+ });
160
+ console.log(`Total: ${performance.getTotalDuration().toFixed(2)}ms`);
161
+ performance.disableMeasurement();
162
+ }
163
+ }
145
164
  function checkNodeVersion() {
146
165
  const [major, minor] = process.version.slice(1).split(".").map(Number);
147
166
  const isValid = major > 12 || (major === 12 && minor >= 13);