typescript-to-lua 1.7.1 → 1.8.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.
@@ -39,6 +39,9 @@ function validateOptions(options) {
39
39
  if (options.jsx && options.jsx !== typescript_1.JsxEmit.React) {
40
40
  diagnostics.push(diagnosticFactories.unsupportedJsxEmit());
41
41
  }
42
+ if (options.paths && !options.baseUrl) {
43
+ diagnostics.push(diagnosticFactories.pathsWithoutBaseUrl());
44
+ }
42
45
  return diagnostics;
43
46
  }
44
47
  exports.validateOptions = validateOptions;
package/dist/LuaLib.d.ts CHANGED
@@ -42,6 +42,7 @@ export declare enum LuaLibFeature {
42
42
  InstanceOf = "InstanceOf",
43
43
  InstanceOfObject = "InstanceOfObject",
44
44
  Iterator = "Iterator",
45
+ LuaIteratorSpread = "LuaIteratorSpread",
45
46
  Map = "Map",
46
47
  MathAtan2 = "MathAtan2",
47
48
  MathSign = "MathSign",
package/dist/LuaLib.js CHANGED
@@ -46,6 +46,7 @@ var LuaLibFeature;
46
46
  LuaLibFeature["InstanceOf"] = "InstanceOf";
47
47
  LuaLibFeature["InstanceOfObject"] = "InstanceOfObject";
48
48
  LuaLibFeature["Iterator"] = "Iterator";
49
+ LuaLibFeature["LuaIteratorSpread"] = "LuaIteratorSpread";
49
50
  LuaLibFeature["Map"] = "Map";
50
51
  LuaLibFeature["MathAtan2"] = "MathAtan2";
51
52
  LuaLibFeature["MathSign"] = "MathSign";
@@ -0,0 +1,9 @@
1
+ local function __TS__LuaIteratorSpread(self, state, firstKey)
2
+ local results = {}
3
+ local key, value = self(state, firstKey)
4
+ while key do
5
+ results[#results + 1] = {key, value}
6
+ key, value = self(state, key)
7
+ end
8
+ return __TS__Unpack(results)
9
+ end
@@ -1207,6 +1207,16 @@ local function __TS__InstanceOfObject(value)
1207
1207
  return valueType == "table" or valueType == "function"
1208
1208
  end
1209
1209
 
1210
+ local function __TS__LuaIteratorSpread(self, state, firstKey)
1211
+ local results = {}
1212
+ local key, value = self(state, firstKey)
1213
+ while key do
1214
+ results[#results + 1] = {key, value}
1215
+ key, value = self(state, key)
1216
+ end
1217
+ return __TS__Unpack(results)
1218
+ end
1219
+
1210
1220
  local Map
1211
1221
  do
1212
1222
  Map = __TS__Class()
@@ -2448,6 +2458,7 @@ return {
2448
2458
  __TS__InstanceOf = __TS__InstanceOf,
2449
2459
  __TS__InstanceOfObject = __TS__InstanceOfObject,
2450
2460
  __TS__Iterator = __TS__Iterator,
2461
+ __TS__LuaIteratorSpread = __TS__LuaIteratorSpread,
2451
2462
  Map = Map,
2452
2463
  __TS__MathAtan2 = __TS__MathAtan2,
2453
2464
  __TS__MathSign = __TS__MathSign,
@@ -264,6 +264,14 @@
264
264
  "Symbol"
265
265
  ]
266
266
  },
267
+ "LuaIteratorSpread": {
268
+ "exports": [
269
+ "__TS__LuaIteratorSpread"
270
+ ],
271
+ "dependencies": [
272
+ "Unpack"
273
+ ]
274
+ },
267
275
  "Map": {
268
276
  "exports": [
269
277
  "Map"
@@ -60,5 +60,6 @@ export declare enum IterableExtensionKind {
60
60
  Pairs = "Pairs",
61
61
  PairsKey = "PairsKey"
62
62
  }
63
+ export declare function isLuaIterable(context: TransformationContext, type: ts.Type): boolean;
63
64
  export declare function getIterableExtensionTypeForType(context: TransformationContext, type: ts.Type): IterableExtensionKind | undefined;
64
65
  export declare function getIterableExtensionKindForNode(context: TransformationContext, node: ts.Node): IterableExtensionKind | undefined;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getIterableExtensionKindForNode = exports.getIterableExtensionTypeForType = exports.IterableExtensionKind = exports.getExtensionKindForSymbol = exports.getExtensionKindForNode = exports.getExtensionKindForType = exports.ExtensionKind = void 0;
3
+ exports.getIterableExtensionKindForNode = exports.getIterableExtensionTypeForType = exports.isLuaIterable = exports.IterableExtensionKind = exports.getExtensionKindForSymbol = exports.getExtensionKindForNode = exports.getExtensionKindForType = exports.ExtensionKind = void 0;
4
4
  const ts = require("typescript");
5
5
  var ExtensionKind;
6
6
  (function (ExtensionKind) {
@@ -96,6 +96,10 @@ var IterableExtensionKind;
96
96
  IterableExtensionKind["Pairs"] = "Pairs";
97
97
  IterableExtensionKind["PairsKey"] = "PairsKey";
98
98
  })(IterableExtensionKind = exports.IterableExtensionKind || (exports.IterableExtensionKind = {}));
99
+ function isLuaIterable(context, type) {
100
+ return getPropertyValue(context, type, "__tstlIterable") !== undefined;
101
+ }
102
+ exports.isLuaIterable = isLuaIterable;
99
103
  function getIterableExtensionTypeForType(context, type) {
100
104
  const value = getPropertyValue(context, type, "__tstlIterable");
101
105
  if (value && value in IterableExtensionKind) {
@@ -117,7 +117,7 @@ function transformPropertyCall(context, node, calledMethod) {
117
117
  if (calledMethod.expression.kind === ts.SyntaxKind.SuperKeyword) {
118
118
  // Super calls take the format of super.call(self,...)
119
119
  const parameters = transformArguments(context, node.arguments, signature, ts.factory.createThis());
120
- return lua.createCallExpression(context.transformExpression(node.expression), parameters);
120
+ return lua.createCallExpression(context.transformExpression(node.expression), parameters, node);
121
121
  }
122
122
  const signatureDeclaration = signature === null || signature === void 0 ? void 0 : signature.getDeclaration();
123
123
  if (!signatureDeclaration || (0, function_context_1.getDeclarationContextType)(context, signatureDeclaration) !== function_context_1.ContextType.Void) {
@@ -140,7 +140,7 @@ function transformElementCall(context, node) {
140
140
  else {
141
141
  // No context
142
142
  const [expression, parameters] = transformCallAndArguments(context, node.expression, node.arguments, signature);
143
- return lua.createCallExpression(expression, parameters);
143
+ return lua.createCallExpression(expression, parameters, node);
144
144
  }
145
145
  }
146
146
  const transformCallExpression = (node, context) => {
@@ -175,7 +175,7 @@ const transformCallExpression = (node, context) => {
175
175
  // Handle super calls properly
176
176
  if (calledExpression.kind === ts.SyntaxKind.SuperKeyword) {
177
177
  const parameters = transformArguments(context, node.arguments, signature, ts.factory.createThis());
178
- return lua.createCallExpression(lua.createTableIndexExpression(context.transformExpression(ts.factory.createSuper()), lua.createStringLiteral("____constructor")), parameters);
178
+ return lua.createCallExpression(lua.createTableIndexExpression(context.transformExpression(ts.factory.createSuper()), lua.createStringLiteral("____constructor")), parameters, node);
179
179
  }
180
180
  let callPath;
181
181
  let parameters;
@@ -9,6 +9,7 @@ const diagnostics_1 = require("../../utils/diagnostics");
9
9
  const utils_2 = require("../../../utils");
10
10
  const multi_1 = require("./multi");
11
11
  function transformForOfMultiIterableStatement(context, statement, block, luaIterator, invalidMultiUseDiagnostic) {
12
+ context.pushPrecedingStatements();
12
13
  let identifiers = [];
13
14
  if (ts.isVariableDeclarationList(statement.initializer)) {
14
15
  // Variables declared in for loop
@@ -36,6 +37,7 @@ function transformForOfMultiIterableStatement(context, statement, block, luaIter
36
37
  if (identifiers.length === 0) {
37
38
  identifiers.push(lua.createAnonymousIdentifier());
38
39
  }
40
+ block.statements.unshift(...context.popPrecedingStatements());
39
41
  return lua.createForInStatement(block, identifiers, [luaIterator], statement);
40
42
  }
41
43
  function transformForOfIterableStatement(context, statement, block) {
@@ -117,8 +117,8 @@ const transformImportEqualsDeclaration = (node, context) => {
117
117
  exports.transformImportEqualsDeclaration = transformImportEqualsDeclaration;
118
118
  const transformImportExpression = (node, context) => {
119
119
  (0, lualib_1.importLuaLibFeature)(context, lualib_1.LuaLibFeature.Promise);
120
- const importPath = node.arguments.map(a => context.transformExpression(a));
121
- return lua.createCallExpression((0, promise_1.createStaticPromiseFunctionAccessor)("resolve", node), importPath, node);
120
+ const moduleRequire = node.arguments.length > 0 ? createModuleRequire(context, node.arguments[0], node) : lua.createNilLiteral();
121
+ return lua.createCallExpression((0, promise_1.createStaticPromiseFunctionAccessor)("resolve", node), [moduleRequire], node);
122
122
  };
123
123
  exports.transformImportExpression = transformImportExpression;
124
124
  //# sourceMappingURL=import.js.map
@@ -3,6 +3,7 @@ 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 language_extensions_1 = require("../utils/language-extensions");
6
7
  const lua_ast_1 = require("../utils/lua-ast");
7
8
  const lualib_1 = require("../utils/lualib");
8
9
  const scope_1 = require("../utils/scope");
@@ -60,6 +61,9 @@ const transformSpreadElement = (node, context) => {
60
61
  if ((0, multi_1.isMultiReturnCall)(context, tsInnerExpression))
61
62
  return innerExpression;
62
63
  const type = context.checker.getTypeAtLocation(node.expression); // not ts-inner expression, in case of casts
64
+ if ((0, language_extensions_1.isLuaIterable)(context, type)) {
65
+ return (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.LuaIteratorSpread, node, innerExpression);
66
+ }
63
67
  if ((0, typescript_1.isArrayType)(context, type)) {
64
68
  return (0, lua_ast_1.createUnpackCall)(context, innerExpression, node);
65
69
  }
@@ -32,3 +32,6 @@ export declare const cannotBundleLibrary: (() => ts.Diagnostic) & {
32
32
  export declare const unsupportedJsxEmit: (() => ts.Diagnostic) & {
33
33
  code: number;
34
34
  };
35
+ export declare const pathsWithoutBaseUrl: (() => ts.Diagnostic) & {
36
+ code: number;
37
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.unsupportedJsxEmit = exports.cannotBundleLibrary = exports.usingLuaBundleWithInlineMightGenerateDuplicateCode = exports.luaBundleEntryIsRequired = exports.couldNotFindBundleEntryPoint = exports.transformerShouldBeATsTransformerFactory = exports.shouldHaveAExport = exports.couldNotResolveFrom = exports.toLoadItShouldBeTranspiled = exports.couldNotReadDependency = exports.couldNotResolveRequire = void 0;
3
+ exports.pathsWithoutBaseUrl = exports.unsupportedJsxEmit = exports.cannotBundleLibrary = exports.usingLuaBundleWithInlineMightGenerateDuplicateCode = exports.luaBundleEntryIsRequired = exports.couldNotFindBundleEntryPoint = exports.transformerShouldBeATsTransformerFactory = exports.shouldHaveAExport = exports.couldNotResolveFrom = exports.toLoadItShouldBeTranspiled = exports.couldNotReadDependency = exports.couldNotResolveRequire = void 0;
4
4
  const ts = require("typescript");
5
5
  const utils_1 = require("../utils");
6
6
  const createDiagnosticFactory = (getMessage, category = ts.DiagnosticCategory.Error) => (0, utils_1.createSerialDiagnosticFactory)((...args) => ({ messageText: getMessage(...args), category }));
@@ -19,4 +19,5 @@ exports.usingLuaBundleWithInlineMightGenerateDuplicateCode = (0, utils_1.createS
19
19
  }));
20
20
  exports.cannotBundleLibrary = createDiagnosticFactory(() => 'Cannot bundle probjects with"buildmode": "library". Projects including the library can still bundle (which will include external library files).');
21
21
  exports.unsupportedJsxEmit = createDiagnosticFactory(() => 'JSX is only supported with "react" jsx option.');
22
+ exports.pathsWithoutBaseUrl = createDiagnosticFactory(() => "When configuring 'paths' in tsconfig.json, the option 'baseUrl' must also be provided.");
22
23
  //# sourceMappingURL=diagnostics.js.map
@@ -104,26 +104,33 @@ class ResolutionContext {
104
104
  if (this.options.tstlVerbose) {
105
105
  console.log(`Resolving "${dependency}" from ${(0, utils_1.normalizeSlashes)(requiringFile.fileName)}`);
106
106
  }
107
+ const requiredFromLuaFile = requiringFile.fileName.endsWith(".lua");
108
+ const dependencyPath = requiredFromLuaFile ? luaRequireToPath(dependency) : dependency;
109
+ if (requiredFromLuaFile && isNodeModulesFile(requiringFile.fileName)) {
110
+ // If requiring file is in lua module, try to resolve sibling in that file first
111
+ const resolvedNodeModulesFile = this.resolveLuaDependencyPathFromNodeModules(requiringFile, dependencyPath);
112
+ if (resolvedNodeModulesFile)
113
+ return resolvedNodeModulesFile;
114
+ }
107
115
  // Check if the import is relative
108
116
  const isRelative = ["/", "./", "../"].some(p => dependency.startsWith(p));
109
117
  // If the import is relative, always resolve it relative to the requiring file
110
118
  // If the import is not relative, resolve it relative to options.baseUrl if it is set
111
119
  const relativeTo = isRelative ? fileDirectory : (_a = this.options.baseUrl) !== null && _a !== void 0 ? _a : fileDirectory;
112
120
  // Check if file is a file in the project
113
- const resolvedPath = path.join(relativeTo, dependency);
121
+ const resolvedPath = path.join(relativeTo, dependencyPath);
114
122
  const fileFromPath = this.getFileFromPath(resolvedPath);
115
123
  if (fileFromPath)
116
124
  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;
122
- }
125
+ if (this.options.paths && this.options.baseUrl) {
126
+ // If no file found yet and paths are present, try to find project file via paths mappings
127
+ const fileFromPaths = this.tryGetModuleNameFromPaths(dependencyPath, this.options.paths, this.options.baseUrl);
128
+ if (fileFromPaths)
129
+ return fileFromPaths;
123
130
  }
124
131
  // Not a TS file in our project sources, use resolver to check if we can find dependency
125
132
  try {
126
- const resolveResult = resolver.resolveSync({}, fileDirectory, dependency);
133
+ const resolveResult = resolver.resolveSync({}, fileDirectory, dependencyPath);
127
134
  if (resolveResult)
128
135
  return resolveResult;
129
136
  }
@@ -132,6 +139,25 @@ class ResolutionContext {
132
139
  }
133
140
  return undefined;
134
141
  }
142
+ resolveLuaDependencyPathFromNodeModules(requiringFile, dependency) {
143
+ // We don't know for sure where the lua root is, so guess it is at package root
144
+ const splitPath = path.normalize(requiringFile.fileName).split(path.sep);
145
+ let packageRootIndex = splitPath.lastIndexOf("node_modules") + 2;
146
+ let packageRoot = splitPath.slice(0, packageRootIndex).join(path.sep);
147
+ while (packageRootIndex < splitPath.length) {
148
+ // Try to find lua file relative to currently guessed Lua root
149
+ const resolvedPath = path.join(packageRoot, dependency);
150
+ const fileFromPath = this.getFileFromPath(resolvedPath);
151
+ if (fileFromPath) {
152
+ return fileFromPath;
153
+ }
154
+ else {
155
+ // Did not find file at current root, try again one directory deeper
156
+ packageRoot = path.join(packageRoot, splitPath[packageRootIndex++]);
157
+ }
158
+ }
159
+ return undefined;
160
+ }
135
161
  getFileFromPath(resolvedPath) {
136
162
  const existingFile = this.pathToFile.get(resolvedPath);
137
163
  if (existingFile)
@@ -167,6 +193,40 @@ class ResolutionContext {
167
193
  }
168
194
  }
169
195
  }
196
+ // Taken from TS and modified: https://github.com/microsoft/TypeScript/blob/88a1e3a1dd8d2d86e844ff1c16d5f041cebcfdb9/src/compiler/moduleSpecifiers.ts#L562
197
+ tryGetModuleNameFromPaths(relativeToBaseUrl, paths, baseUrl) {
198
+ const relativeImport = removeTrailingDirectorySeparator((0, utils_1.normalizeSlashes)(relativeToBaseUrl));
199
+ for (const [importPattern, targetPatterns] of Object.entries(paths)) {
200
+ const pattern = removeFileExtension((0, utils_1.normalizeSlashes)(importPattern));
201
+ const indexOfStar = pattern.indexOf("*");
202
+ if (indexOfStar !== -1) {
203
+ // Try to match <prefix>*<suffix> to relativeImport
204
+ const prefix = pattern.substring(0, indexOfStar);
205
+ const suffix = pattern.substring(indexOfStar + 1);
206
+ if ((relativeImport.length >= prefix.length + suffix.length &&
207
+ relativeImport.startsWith(prefix) &&
208
+ relativeImport.endsWith(suffix)) ||
209
+ (!suffix && relativeImport === removeTrailingDirectorySeparator(prefix))) {
210
+ // If import matches <prefix>*<suffix>, extract the matched * path
211
+ const matchedStar = relativeImport.substring(prefix.length, relativeImport.length - suffix.length);
212
+ // Try to resolve to the target patterns with filled in * pattern
213
+ for (const target of targetPatterns) {
214
+ const file = this.getFileFromPath(path.join(baseUrl, target.replace("*", matchedStar)));
215
+ if (file)
216
+ return file;
217
+ }
218
+ }
219
+ }
220
+ else if (pattern === relativeImport) {
221
+ // If there is no * pattern, check for exact matches and try those targets
222
+ for (const target of targetPatterns) {
223
+ const file = this.getFileFromPath(path.join(baseUrl, target));
224
+ if (file)
225
+ return file;
226
+ }
227
+ }
228
+ }
229
+ }
170
230
  }
171
231
  function resolveDependencies(program, files, emitHost) {
172
232
  const options = program.getCompilerOptions();
@@ -181,34 +241,6 @@ function resolveDependencies(program, files, emitHost) {
181
241
  return { resolvedFiles: [...resolutionContext.resolvedFiles.values()], diagnostics: resolutionContext.diagnostics };
182
242
  }
183
243
  exports.resolveDependencies = resolveDependencies;
184
- function resolveLuaPath(fromPath, dependency, emitHost) {
185
- const splitDependency = dependency.split(".");
186
- if (splitDependency.length === 1) {
187
- // If dependency has just one part (the file), look for a lua file with that name
188
- const fileDirectory = walkUpFileTreeUntil(fromPath, dir => emitHost.fileExists(path.join(dir, dependency) + ".lua"));
189
- if (fileDirectory) {
190
- return path.join(fileDirectory, dependency) + ".lua";
191
- }
192
- }
193
- else {
194
- // If dependency has multiple parts, look for the first directory of the require path, which must be in the lua root
195
- const luaRoot = walkUpFileTreeUntil(fromPath, dir => emitHost.directoryExists(path.join(dir, splitDependency[0])));
196
- if (luaRoot) {
197
- return path.join(luaRoot, dependency.replace(/\./g, path.sep)) + ".lua";
198
- }
199
- }
200
- }
201
- function walkUpFileTreeUntil(fromDirectory, predicate) {
202
- const currentDir = path.normalize(fromDirectory).split(path.sep);
203
- while (currentDir.length > 0) {
204
- const dir = currentDir.join(path.sep);
205
- if (predicate(dir)) {
206
- return dir;
207
- }
208
- currentDir.pop();
209
- }
210
- return undefined;
211
- }
212
244
  function shouldRewriteRequires(resolvedDependency, program) {
213
245
  return !isBuildModeLibrary(program) || !isNodeModulesFile(resolvedDependency);
214
246
  }
@@ -228,7 +260,7 @@ function isBuildModeLibrary(program) {
228
260
  function findRequiredPaths(code) {
229
261
  // Find all require("<path>") paths in a lua code string
230
262
  const paths = [];
231
- const pattern = /(^|\s|;|=)require\("(.+?)"\)/g;
263
+ const pattern = /(^|\s|;|=|\()require\("(.+?)"\)/g;
232
264
  // eslint-disable-next-line @typescript-eslint/ban-types
233
265
  let match;
234
266
  while ((match = pattern.exec(code))) {
@@ -240,7 +272,7 @@ function replaceRequireInCode(file, originalRequire, newRequire) {
240
272
  const requirePath = (0, utils_1.formatPathToLuaPath)(newRequire.replace(".lua", ""));
241
273
  // Escape special characters to prevent the regex from breaking...
242
274
  const escapedRequire = originalRequire.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
243
- file.code = file.code.replace(new RegExp(`(^|\\s|;|=)require\\("${escapedRequire}"\\)`), `$1require("${requirePath}")`);
275
+ file.code = file.code.replace(new RegExp(`(^|\\s|;|=|\\()require\\("${escapedRequire}"\\)`), `$1require("${requirePath}")`);
244
276
  }
245
277
  function replaceRequireInSourceMap(file, originalRequire, newRequire) {
246
278
  const requirePath = (0, utils_1.formatPathToLuaPath)(newRequire.replace(".lua", ""));
@@ -285,4 +317,13 @@ function fallbackResolve(required, sourceRootDir, fileDir) {
285
317
  .filter(s => s !== "." && s !== "..")
286
318
  .join(path.sep));
287
319
  }
320
+ function luaRequireToPath(requirePath) {
321
+ return requirePath.replace(/\./g, path.sep);
322
+ }
323
+ function removeFileExtension(path) {
324
+ return path.includes(".") ? (0, utils_1.trimExtension)(path) : path;
325
+ }
326
+ function removeTrailingDirectorySeparator(path) {
327
+ return path.endsWith("/") || path.endsWith("\\") ? path.substring(0, -1) : path;
328
+ }
288
329
  //# sourceMappingURL=resolve.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typescript-to-lua",
3
- "version": "1.7.1",
3
+ "version": "1.8.1",
4
4
  "description": "A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!",
5
5
  "repository": "https://github.com/TypeScriptToLua/TypeScriptToLua",
6
6
  "homepage": "https://typescripttolua.github.io/",