typescript-to-lua 1.11.1 → 1.12.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.
@@ -0,0 +1,6 @@
1
+ export interface LuaRequire {
2
+ from: number;
3
+ to: number;
4
+ requirePath: string;
5
+ }
6
+ export declare function findLuaRequires(lua: string): LuaRequire[];
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findLuaRequires = void 0;
4
+ function findLuaRequires(lua) {
5
+ return findRequire(lua, 0);
6
+ }
7
+ exports.findLuaRequires = findLuaRequires;
8
+ function findRequire(lua, offset) {
9
+ const result = [];
10
+ while (offset < lua.length) {
11
+ const c = lua[offset];
12
+ if (c === "r" &&
13
+ (offset === 0 ||
14
+ isWhitespace(lua[offset - 1]) ||
15
+ lua[offset - 1] === "]" ||
16
+ lua[offset - 1] === "(" ||
17
+ lua[offset - 1] === "[")) {
18
+ const m = matchRequire(lua, offset);
19
+ if (m.matched) {
20
+ offset = m.match.to + 1;
21
+ result.push(m.match);
22
+ }
23
+ else {
24
+ offset = m.end;
25
+ }
26
+ }
27
+ else if (c === '"' || c === "'") {
28
+ offset = readString(lua, offset, c).offset; // Skip string and surrounding quotes
29
+ }
30
+ else if (c === "-" && offset + 1 < lua.length && lua[offset + 1] === "-") {
31
+ offset = skipComment(lua, offset);
32
+ }
33
+ else {
34
+ offset++;
35
+ }
36
+ }
37
+ return result;
38
+ }
39
+ function matchRequire(lua, offset) {
40
+ const start = offset;
41
+ for (const c of "require") {
42
+ if (offset > lua.length) {
43
+ return { matched: false, end: offset };
44
+ }
45
+ if (lua[offset] !== c) {
46
+ return { matched: false, end: offset };
47
+ }
48
+ offset++;
49
+ }
50
+ offset = skipWhitespace(lua, offset);
51
+ let hasParentheses = false;
52
+ if (offset > lua.length) {
53
+ return { matched: false, end: offset };
54
+ }
55
+ else {
56
+ if (lua[offset] === "(") {
57
+ hasParentheses = true;
58
+ offset++;
59
+ offset = skipWhitespace(lua, offset);
60
+ }
61
+ else if (lua[offset] === '"' || lua[offset] === "'") {
62
+ // require without parentheses
63
+ }
64
+ else {
65
+ // otherwise fail match
66
+ return { matched: false, end: offset };
67
+ }
68
+ }
69
+ if (offset > lua.length || (lua[offset] !== '"' && lua[offset] !== "'")) {
70
+ return { matched: false, end: offset };
71
+ }
72
+ const { value: requireString, offset: offsetAfterString } = readString(lua, offset, lua[offset]);
73
+ offset = offsetAfterString; // Skip string and surrounding quotes
74
+ if (hasParentheses) {
75
+ offset = skipWhitespace(lua, offset);
76
+ if (offset > lua.length || lua[offset] !== ")") {
77
+ return { matched: false, end: offset };
78
+ }
79
+ offset++;
80
+ }
81
+ return { matched: true, match: { from: start, to: offset - 1, requirePath: requireString } };
82
+ }
83
+ function readString(lua, offset, delimiter) {
84
+ expect(lua, offset, delimiter);
85
+ offset++;
86
+ let start = offset;
87
+ let result = "";
88
+ let escaped = false;
89
+ while (offset < lua.length && (lua[offset] !== delimiter || escaped)) {
90
+ if (lua[offset] === "\\" && !escaped) {
91
+ escaped = true;
92
+ }
93
+ else {
94
+ if (lua[offset] === delimiter) {
95
+ result += lua.slice(start, offset - 1);
96
+ start = offset;
97
+ }
98
+ escaped = false;
99
+ }
100
+ offset++;
101
+ }
102
+ if (offset < lua.length) {
103
+ expect(lua, offset, delimiter);
104
+ }
105
+ result += lua.slice(start, offset);
106
+ return { value: result, offset: offset + 1 };
107
+ }
108
+ function skipWhitespace(lua, offset) {
109
+ while (offset < lua.length && isWhitespace(lua[offset])) {
110
+ offset++;
111
+ }
112
+ return offset;
113
+ }
114
+ function isWhitespace(c) {
115
+ return c === " " || c === "\t" || c === "\r" || c === "\n";
116
+ }
117
+ function skipComment(lua, offset) {
118
+ expect(lua, offset, "-");
119
+ expect(lua, offset + 1, "-");
120
+ offset += 2;
121
+ if (offset + 1 < lua.length && lua[offset] === "[" && lua[offset + 1] === "[") {
122
+ return skipMultiLineComment(lua, offset);
123
+ }
124
+ else {
125
+ return skipSingleLineComment(lua, offset);
126
+ }
127
+ }
128
+ function skipMultiLineComment(lua, offset) {
129
+ while (offset < lua.length && !(lua[offset] === "]" && lua[offset - 1] === "]")) {
130
+ offset++;
131
+ }
132
+ return offset + 1;
133
+ }
134
+ function skipSingleLineComment(lua, offset) {
135
+ while (offset < lua.length && lua[offset] !== "\n") {
136
+ offset++;
137
+ }
138
+ return offset + 1;
139
+ }
140
+ function expect(lua, offset, char) {
141
+ if (lua[offset] !== char) {
142
+ throw new Error(`Expected ${char} at position ${offset} but found ${lua[offset]}`);
143
+ }
144
+ }
145
+ //# sourceMappingURL=find-lua-requires.js.map
@@ -9,6 +9,7 @@ const transpiler_1 = require("./transpiler");
9
9
  const utils_1 = require("../utils");
10
10
  const diagnostics_1 = require("./diagnostics");
11
11
  const CompilerOptions_1 = require("../CompilerOptions");
12
+ const find_lua_requires_1 = require("./find-lua-requires");
12
13
  const resolver = resolve.ResolverFactory.createResolver({
13
14
  extensions: [".lua"],
14
15
  enforceExtension: true,
@@ -32,12 +33,13 @@ class ResolutionContext {
32
33
  if (this.resolvedFiles.has(file.fileName))
33
34
  return;
34
35
  this.resolvedFiles.set(file.fileName, file);
35
- for (const required of findRequiredPaths(file.code)) {
36
+ // Do this backwards so the replacements do not mess with the positions of the previous requires
37
+ for (const required of (0, find_lua_requires_1.findLuaRequires)(file.code).reverse()) {
36
38
  // Do not resolve noResolution paths
37
- if (required.startsWith("@NoResolution:")) {
39
+ if (required.requirePath.startsWith("@NoResolution:")) {
38
40
  // Remove @NoResolution prefix if not building in library mode
39
41
  if (!isBuildModeLibrary(this.program)) {
40
- const path = required.replace("@NoResolution:", "");
42
+ const path = required.requirePath.replace("@NoResolution:", "");
41
43
  replaceRequireInCode(file, required, path);
42
44
  replaceRequireInSourceMap(file, required, path);
43
45
  }
@@ -50,21 +52,21 @@ class ResolutionContext {
50
52
  }
51
53
  resolveImport(file, required) {
52
54
  // Do no resolve lualib - always use the lualib of the application entry point, not the lualib from external packages
53
- if (required === "lualib_bundle") {
55
+ if (required.requirePath === "lualib_bundle") {
54
56
  this.resolvedFiles.set("lualib_bundle", { fileName: "lualib_bundle", code: "" });
55
57
  return;
56
58
  }
57
- if (this.noResolvePaths.has(required)) {
59
+ if (this.noResolvePaths.has(required.requirePath)) {
58
60
  if (this.options.tstlVerbose) {
59
- console.log(`Skipping module resolution of ${required} as it is in the tsconfig noResolvePaths.`);
61
+ console.log(`Skipping module resolution of ${required.requirePath} as it is in the tsconfig noResolvePaths.`);
60
62
  }
61
63
  return;
62
64
  }
63
- const dependencyPath = this.resolveDependencyPath(file, required);
65
+ const dependencyPath = this.resolveDependencyPath(file, required.requirePath);
64
66
  if (!dependencyPath)
65
67
  return this.couldNotResolveImport(required, file);
66
68
  if (this.options.tstlVerbose) {
67
- console.log(`Resolved ${required} to ${(0, utils_1.normalizeSlashes)(dependencyPath)}`);
69
+ console.log(`Resolved ${required.requirePath} to ${(0, utils_1.normalizeSlashes)(dependencyPath)}`);
68
70
  }
69
71
  this.processDependency(dependencyPath);
70
72
  // Figure out resolved require path and dependency output path
@@ -96,7 +98,7 @@ class ResolutionContext {
96
98
  const fallbackRequire = fallbackResolve(required, (0, transpiler_1.getSourceDir)(this.program), path.dirname(file.fileName));
97
99
  replaceRequireInCode(file, required, fallbackRequire);
98
100
  replaceRequireInSourceMap(file, required, fallbackRequire);
99
- this.diagnostics.push((0, diagnostics_1.couldNotResolveRequire)(required, path.relative((0, transpiler_1.getProjectRoot)(this.program), file.fileName)));
101
+ this.diagnostics.push((0, diagnostics_1.couldNotResolveRequire)(required.requirePath, path.relative((0, transpiler_1.getProjectRoot)(this.program), file.fileName)));
100
102
  }
101
103
  resolveDependencyPath(requiringFile, dependency) {
102
104
  var _a;
@@ -261,27 +263,17 @@ function shouldIncludeDependency(resolvedDependency, program) {
261
263
  function isBuildModeLibrary(program) {
262
264
  return program.getCompilerOptions().buildMode === CompilerOptions_1.BuildMode.Library;
263
265
  }
264
- function findRequiredPaths(code) {
265
- // Find all require("<path>") paths in a lua code string
266
- const paths = [];
267
- const pattern = /(^|\s|;|=|\()require\s*\(?(["|'])(.+?)\2\)?/g;
268
- // eslint-disable-next-line @typescript-eslint/ban-types
269
- let match;
270
- while ((match = pattern.exec(code))) {
271
- paths.push(match[3]);
272
- }
273
- return paths;
274
- }
275
266
  function replaceRequireInCode(file, originalRequire, newRequire) {
276
267
  const requirePath = (0, utils_1.formatPathToLuaPath)(newRequire.replace(".lua", ""));
277
- // Escape special characters to prevent the regex from breaking...
278
- const escapedRequire = originalRequire.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
279
- file.code = file.code.replace(new RegExp(`(^|\\s|;|=|\\()require\\s*\\(?["|']${escapedRequire}["|']\\)?`), `$1require("${requirePath}")`);
268
+ file.code = file.code =
269
+ file.code.substring(0, originalRequire.from) +
270
+ `require("${requirePath}")` +
271
+ file.code.substring(originalRequire.to + 1);
280
272
  }
281
273
  function replaceRequireInSourceMap(file, originalRequire, newRequire) {
282
274
  const requirePath = (0, utils_1.formatPathToLuaPath)(newRequire.replace(".lua", ""));
283
275
  if (file.sourceMapNode) {
284
- replaceInSourceMap(file.sourceMapNode, file.sourceMapNode, `"${originalRequire}"`, `"${requirePath}"`);
276
+ replaceInSourceMap(file.sourceMapNode, file.sourceMapNode, `"${originalRequire.requirePath}"`, `"${requirePath}"`);
285
277
  }
286
278
  }
287
279
  function replaceInSourceMap(node, parent, require, resolvedRequire) {
@@ -316,7 +308,7 @@ function hasSourceFileInProject(filePath, program) {
316
308
  // Transform an import path to a lua require that is probably not correct, but can be used as fallback when regular resolution fails
317
309
  function fallbackResolve(required, sourceRootDir, fileDir) {
318
310
  return (0, utils_1.formatPathToLuaPath)(path
319
- .normalize(path.join(path.relative(sourceRootDir, fileDir), required))
311
+ .normalize(path.join(path.relative(sourceRootDir, fileDir), required.requirePath))
320
312
  .split(path.sep)
321
313
  .filter(s => s !== "." && s !== "..")
322
314
  .join(path.sep));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typescript-to-lua",
3
- "version": "1.11.1",
3
+ "version": "1.12.0",
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/",