typescript-to-lua 1.6.3 → 1.7.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.
Files changed (97) hide show
  1. package/dist/CompilerOptions.d.ts +1 -0
  2. package/dist/cli/parse.js +5 -0
  3. package/dist/lualib/ArraySlice.lua +10 -2
  4. package/dist/lualib/ArraySplice.lua +5 -1
  5. package/dist/lualib/Generator.lua +8 -1
  6. package/dist/lualib/ParseFloat.lua +5 -1
  7. package/dist/lualib/SparseArraySpread.lua +5 -1
  8. package/dist/lualib/StringCharCodeAt.lua +5 -1
  9. package/dist/lualib/lualib_bundle.lua +38 -7
  10. package/dist/lualib-build/plugin.js +1 -2
  11. package/dist/measure-performance.d.ts +15 -0
  12. package/dist/measure-performance.js +83 -0
  13. package/dist/transformation/builtins/array.js +2 -1
  14. package/dist/transformation/builtins/function.js +1 -1
  15. package/dist/transformation/builtins/global.d.ts +1 -1
  16. package/dist/transformation/builtins/global.js +13 -12
  17. package/dist/transformation/builtins/index.d.ts +2 -2
  18. package/dist/transformation/builtins/index.js +87 -89
  19. package/dist/transformation/builtins/object.d.ts +1 -1
  20. package/dist/transformation/builtins/object.js +4 -4
  21. package/dist/transformation/builtins/promise.js +4 -2
  22. package/dist/transformation/builtins/string.js +2 -0
  23. package/dist/transformation/context/context.d.ts +15 -0
  24. package/dist/transformation/context/context.js +66 -24
  25. package/dist/transformation/context/visitors.d.ts +1 -1
  26. package/dist/transformation/index.js +6 -5
  27. package/dist/transformation/utils/annotations.d.ts +1 -17
  28. package/dist/transformation/utils/annotations.js +48 -88
  29. package/dist/transformation/utils/assignment-validation.js +27 -23
  30. package/dist/transformation/utils/diagnostics.d.ts +1 -4
  31. package/dist/transformation/utils/diagnostics.js +2 -3
  32. package/dist/transformation/utils/function-context.d.ts +1 -1
  33. package/dist/transformation/utils/function-context.js +57 -51
  34. package/dist/transformation/utils/language-extensions.d.ts +57 -51
  35. package/dist/transformation/utils/language-extensions.js +99 -119
  36. package/dist/transformation/utils/lualib.d.ts +0 -1
  37. package/dist/transformation/utils/lualib.js +2 -8
  38. package/dist/transformation/utils/safe-names.d.ts +1 -1
  39. package/dist/transformation/utils/safe-names.js +3 -6
  40. package/dist/transformation/utils/scope.d.ts +0 -2
  41. package/dist/transformation/utils/scope.js +10 -27
  42. package/dist/transformation/utils/symbols.d.ts +1 -1
  43. package/dist/transformation/utils/symbols.js +7 -20
  44. package/dist/transformation/utils/typescript/index.d.ts +1 -0
  45. package/dist/transformation/utils/typescript/index.js +2 -1
  46. package/dist/transformation/utils/typescript/types.d.ts +2 -5
  47. package/dist/transformation/utils/typescript/types.js +27 -37
  48. package/dist/transformation/visitors/access.js +1 -4
  49. package/dist/transformation/visitors/block.js +4 -4
  50. package/dist/transformation/visitors/call.js +7 -18
  51. package/dist/transformation/visitors/class/index.js +8 -20
  52. package/dist/transformation/visitors/class/members/constructor.js +2 -2
  53. package/dist/transformation/visitors/class/new.js +2 -5
  54. package/dist/transformation/visitors/class/setup.d.ts +1 -1
  55. package/dist/transformation/visitors/class/setup.js +4 -4
  56. package/dist/transformation/visitors/class/utils.d.ts +1 -1
  57. package/dist/transformation/visitors/class/utils.js +2 -9
  58. package/dist/transformation/visitors/conditional.js +4 -4
  59. package/dist/transformation/visitors/function.d.ts +1 -1
  60. package/dist/transformation/visitors/function.js +8 -16
  61. package/dist/transformation/visitors/identifier.d.ts +1 -0
  62. package/dist/transformation/visitors/identifier.js +40 -44
  63. package/dist/transformation/visitors/language-extensions/call-extension.d.ts +10 -0
  64. package/dist/transformation/visitors/language-extensions/call-extension.js +23 -0
  65. package/dist/transformation/visitors/language-extensions/identifier.d.ts +5 -0
  66. package/dist/transformation/visitors/language-extensions/identifier.js +27 -0
  67. package/dist/transformation/visitors/language-extensions/iterable.d.ts +2 -3
  68. package/dist/transformation/visitors/language-extensions/iterable.js +21 -22
  69. package/dist/transformation/visitors/language-extensions/multi.d.ts +0 -1
  70. package/dist/transformation/visitors/language-extensions/multi.js +10 -24
  71. package/dist/transformation/visitors/language-extensions/operators.d.ts +2 -5
  72. package/dist/transformation/visitors/language-extensions/operators.js +89 -96
  73. package/dist/transformation/visitors/language-extensions/range.js +4 -2
  74. package/dist/transformation/visitors/language-extensions/table.d.ts +6 -3
  75. package/dist/transformation/visitors/language-extensions/table.js +46 -75
  76. package/dist/transformation/visitors/language-extensions/vararg.js +7 -3
  77. package/dist/transformation/visitors/literal.js +2 -23
  78. package/dist/transformation/visitors/loops/for-of.js +18 -18
  79. package/dist/transformation/visitors/loops/utils.js +5 -5
  80. package/dist/transformation/visitors/namespace.js +5 -14
  81. package/dist/transformation/visitors/return.js +2 -3
  82. package/dist/transformation/visitors/sourceFile.js +3 -4
  83. package/dist/transformation/visitors/spread.js +0 -5
  84. package/dist/transformation/visitors/switch.js +2 -2
  85. package/dist/transformation/visitors/variable-declaration.js +1 -1
  86. package/dist/transpilation/plugins.js +3 -0
  87. package/dist/transpilation/resolve.js +144 -161
  88. package/dist/transpilation/transpile.js +10 -0
  89. package/dist/transpilation/transpiler.d.ts +1 -0
  90. package/dist/transpilation/transpiler.js +18 -5
  91. package/dist/tstl.js +21 -0
  92. package/language-extensions/index.d.ts +156 -67
  93. package/package.json +2 -2
  94. package/dist/transformation/visitors/language-extensions/index.d.ts +0 -4
  95. package/dist/transformation/visitors/language-extensions/index.js +0 -17
  96. package/dist/transformation/visitors/language-extensions/pairsIterable.d.ts +0 -5
  97. package/dist/transformation/visitors/language-extensions/pairsIterable.js +0 -53
@@ -60,7 +60,6 @@ const transformReturnStatement = (statement, context) => {
60
60
  };
61
61
  exports.transformReturnStatement = transformReturnStatement;
62
62
  function createReturnStatement(context, values, node) {
63
- const results = [...values];
64
63
  if ((0, typescript_1.isInAsyncFunction)(node)) {
65
64
  return lua.createReturnStatement([
66
65
  lua.createCallExpression(lua.createIdentifier("____awaiter_resolve"), [lua.createNilLiteral(), ...values]),
@@ -68,9 +67,9 @@ function createReturnStatement(context, values, node) {
68
67
  }
69
68
  if (isInTryCatch(context)) {
70
69
  // Bubble up explicit return flag and check if we're inside a try/catch block
71
- results.unshift(lua.createBooleanLiteral(true));
70
+ values = [lua.createBooleanLiteral(true), ...values];
72
71
  }
73
- return lua.createReturnStatement(results, node);
72
+ return lua.createReturnStatement(values, node);
74
73
  }
75
74
  exports.createReturnStatement = createReturnStatement;
76
75
  function isInTryCatch(context) {
@@ -5,7 +5,6 @@ const ts = require("typescript");
5
5
  const lua = require("../../LuaAST");
6
6
  const utils_1 = require("../../utils");
7
7
  const lua_ast_1 = require("../utils/lua-ast");
8
- const lualib_1 = require("../utils/lualib");
9
8
  const preceding_statements_1 = require("../utils/preceding-statements");
10
9
  const scope_1 = require("../utils/scope");
11
10
  const typescript_1 = require("../utils/typescript");
@@ -28,9 +27,9 @@ const transformSourceFileNode = (node, context) => {
28
27
  }
29
28
  }
30
29
  else {
31
- (0, scope_1.pushScope)(context, scope_1.ScopeType.File);
30
+ context.pushScope(scope_1.ScopeType.File);
32
31
  statements = (0, scope_1.performHoisting)(context, context.transformStatements(node.statements));
33
- (0, scope_1.popScope)(context);
32
+ context.popScope();
34
33
  if (context.isModule) {
35
34
  // If export equals was not used. Create the exports table.
36
35
  // local ____exports = {}
@@ -42,7 +41,7 @@ const transformSourceFileNode = (node, context) => {
42
41
  }
43
42
  }
44
43
  const trivia = (_b = (_a = node.getFullText().match(/^#!.*\r?\n/)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : "";
45
- return lua.createFile(statements, (0, lualib_1.getUsedLuaLibFeatures)(context), trivia, node);
44
+ return lua.createFile(statements, context.usedLuaLibFeatures, trivia, node);
46
45
  };
47
46
  exports.transformSourceFileNode = transformSourceFileNode;
48
47
  //# sourceMappingURL=sourceFile.js.map
@@ -3,13 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformSpreadElement = exports.isOptimizedVarArgSpread = void 0;
4
4
  const ts = require("typescript");
5
5
  const lua = require("../../LuaAST");
6
- const annotations_1 = require("../utils/annotations");
7
6
  const lua_ast_1 = require("../utils/lua-ast");
8
7
  const lualib_1 = require("../utils/lualib");
9
8
  const scope_1 = require("../utils/scope");
10
9
  const typescript_1 = require("../utils/typescript");
11
10
  const multi_1 = require("./language-extensions/multi");
12
- const diagnostics_1 = require("../utils/diagnostics");
13
11
  const vararg_1 = require("./language-extensions/vararg");
14
12
  function isOptimizedVarArgSpread(context, symbol, identifier) {
15
13
  var _a;
@@ -53,9 +51,6 @@ exports.isOptimizedVarArgSpread = isOptimizedVarArgSpread;
53
51
  const transformSpreadElement = (node, context) => {
54
52
  const tsInnerExpression = ts.skipOuterExpressions(node.expression);
55
53
  if (ts.isIdentifier(tsInnerExpression)) {
56
- if ((0, annotations_1.isVarargType)(context, tsInnerExpression)) {
57
- context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node, annotations_1.AnnotationKind.Vararg));
58
- }
59
54
  const symbol = context.checker.getSymbolAtLocation(tsInnerExpression);
60
55
  if (symbol && isOptimizedVarArgSpread(context, symbol, tsInnerExpression)) {
61
56
  return lua.createDotsLiteral(node);
@@ -39,7 +39,7 @@ const coalesceCondition = (condition, conditionPrecedingStatements, switchVariab
39
39
  return [[...conditionPrecedingStatements, ...precedingStatements], comparison];
40
40
  };
41
41
  const transformSwitchStatement = (statement, context) => {
42
- const scope = (0, scope_1.pushScope)(context, scope_1.ScopeType.Switch);
42
+ const scope = context.pushScope(scope_1.ScopeType.Switch);
43
43
  // Give the switch and condition accumulator a unique name to prevent nested switches from acting up.
44
44
  const switchName = `____switch${scope.id}`;
45
45
  const conditionName = `____cond${scope.id}`;
@@ -158,7 +158,7 @@ const transformSwitchStatement = (statement, context) => {
158
158
  if (hoistedIdentifiers.length > 0) {
159
159
  statements.unshift(lua.createVariableDeclarationStatement(hoistedIdentifiers));
160
160
  }
161
- (0, scope_1.popScope)(context);
161
+ context.popScope();
162
162
  // Add the switch expression after hoisting
163
163
  const expression = context.transformExpression(statement.expression);
164
164
  statements.unshift(lua.createVariableDeclarationStatement(switchVariable, expression));
@@ -201,7 +201,7 @@ function transformVariableDeclaration(context, statement) {
201
201
  // Skip named function expressions because they will have been wrapped already
202
202
  if (ts.isFunctionExpression(initializer) && initializer.name)
203
203
  return false;
204
- return (0, function_1.isFunctionTypeWithProperties)(context.checker.getTypeAtLocation(statement.name));
204
+ return (0, function_1.isFunctionTypeWithProperties)(context, context.checker.getTypeAtLocation(statement.name));
205
205
  }
206
206
  }
207
207
  exports.transformVariableDeclaration = transformVariableDeclaration;
@@ -2,8 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getPlugins = void 0;
4
4
  const utils_1 = require("./utils");
5
+ const performance = require("../measure-performance");
5
6
  function getPlugins(program) {
6
7
  var _a;
8
+ performance.startSection("getPlugins");
7
9
  const diagnostics = [];
8
10
  const pluginsFromOptions = [];
9
11
  const options = program.getCompilerOptions();
@@ -20,6 +22,7 @@ function getPlugins(program) {
20
22
  if (options.tstlVerbose) {
21
23
  console.log(`Loaded ${pluginsFromOptions.length} plugins`);
22
24
  }
25
+ performance.endSection("getPlugins");
23
26
  return { diagnostics, plugins: pluginsFromOptions };
24
27
  }
25
28
  exports.getPlugins = getPlugins;
@@ -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
  }