typescript-to-lua 1.12.0 → 1.12.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 (38) hide show
  1. package/dist/CompilerOptions.d.ts +2 -1
  2. package/dist/CompilerOptions.js +1 -0
  3. package/dist/LuaLib.d.ts +4 -0
  4. package/dist/LuaLib.js +69 -19
  5. package/dist/LuaPrinter.js +2 -1
  6. package/dist/lualib/5.0/ArraySlice.lua +2 -10
  7. package/dist/lualib/5.0/ArraySplice.lua +1 -5
  8. package/dist/lualib/5.0/ParseFloat.lua +1 -5
  9. package/dist/lualib/5.0/StringCharCodeAt.lua +1 -5
  10. package/dist/lualib/5.0/lualib_bundle.lua +5 -25
  11. package/dist/lualib/universal/ArraySlice.lua +2 -10
  12. package/dist/lualib/universal/ArraySplice.lua +1 -5
  13. package/dist/lualib/universal/ParseFloat.lua +1 -5
  14. package/dist/lualib/universal/SparseArraySpread.lua +1 -5
  15. package/dist/lualib/universal/StringCharCodeAt.lua +1 -5
  16. package/dist/lualib/universal/lualib_bundle.lua +6 -30
  17. package/dist/lualib-build/plugin.js +1 -1
  18. package/dist/transformation/builtins/array.js +1 -1
  19. package/dist/transformation/utils/diagnostics.d.ts +6 -0
  20. package/dist/transformation/utils/diagnostics.js +3 -1
  21. package/dist/transformation/utils/language-extensions.d.ts +4 -0
  22. package/dist/transformation/utils/language-extensions.js +66 -1
  23. package/dist/transformation/utils/typescript/index.d.ts +1 -0
  24. package/dist/transformation/utils/typescript/index.js +5 -1
  25. package/dist/transformation/utils/typescript/types.js +0 -3
  26. package/dist/transformation/visitors/expression-statement.d.ts +2 -2
  27. package/dist/transformation/visitors/expression-statement.js +4 -5
  28. package/dist/transformation/visitors/identifier.js +3 -1
  29. package/dist/transformation/visitors/language-extensions/operators.js +9 -15
  30. package/dist/transformation/visitors/language-extensions/table.d.ts +2 -4
  31. package/dist/transformation/visitors/language-extensions/table.js +32 -38
  32. package/dist/transformation/visitors/optional-chaining.d.ts +2 -1
  33. package/dist/transformation/visitors/optional-chaining.js +78 -32
  34. package/dist/transformation/visitors/void.js +1 -1
  35. package/dist/transpilation/diagnostics.js +1 -1
  36. package/dist/transpilation/transpiler.d.ts +1 -0
  37. package/dist/transpilation/transpiler.js +13 -3
  38. package/package.json +1 -1
@@ -39,7 +39,8 @@ export type CompilerOptions = OmitIndexSignature<ts.CompilerOptions> & TypeScrip
39
39
  export declare enum LuaLibImportKind {
40
40
  None = "none",
41
41
  Inline = "inline",
42
- Require = "require"
42
+ Require = "require",
43
+ RequireMinimal = "require-minimal"
43
44
  }
44
45
  export declare enum LuaTarget {
45
46
  Universal = "universal",
@@ -8,6 +8,7 @@ var LuaLibImportKind;
8
8
  LuaLibImportKind["None"] = "none";
9
9
  LuaLibImportKind["Inline"] = "inline";
10
10
  LuaLibImportKind["Require"] = "require";
11
+ LuaLibImportKind["RequireMinimal"] = "require-minimal";
11
12
  })(LuaLibImportKind = exports.LuaLibImportKind || (exports.LuaLibImportKind = {}));
12
13
  var LuaTarget;
13
14
  (function (LuaTarget) {
package/dist/LuaLib.d.ts CHANGED
@@ -110,8 +110,12 @@ export type LuaLibModulesInfo = Record<LuaLibFeature, LuaLibFeatureInfo>;
110
110
  export declare function resolveLuaLibDir(luaTarget: LuaTarget): string;
111
111
  export declare const luaLibModulesInfoFileName = "lualib_module_info.json";
112
112
  export declare function getLuaLibModulesInfo(luaTarget: LuaTarget, emitHost: EmitHost): LuaLibModulesInfo;
113
+ export declare function getLuaLibExportToFeatureMap(luaTarget: LuaTarget, emitHost: EmitHost): ReadonlyMap<string, LuaLibFeature>;
113
114
  export declare function readLuaLibFeature(feature: LuaLibFeature, luaTarget: LuaTarget, emitHost: EmitHost): string;
114
115
  export declare function resolveRecursiveLualibFeatures(features: Iterable<LuaLibFeature>, luaTarget: LuaTarget, emitHost: EmitHost, luaLibModulesInfo?: LuaLibModulesInfo): LuaLibFeature[];
115
116
  export declare function loadInlineLualibFeatures(features: Iterable<LuaLibFeature>, luaTarget: LuaTarget, emitHost: EmitHost): string;
116
117
  export declare function loadImportedLualibFeatures(features: Iterable<LuaLibFeature>, luaTarget: LuaTarget, emitHost: EmitHost): lua.Statement[];
117
118
  export declare function getLuaLibBundle(luaTarget: LuaTarget, emitHost: EmitHost): string;
119
+ export declare function getLualibBundleReturn(exportedValues: string[]): string;
120
+ export declare function buildMinimalLualibBundle(features: Iterable<LuaLibFeature>, luaTarget: LuaTarget, emitHost: EmitHost): string;
121
+ export declare function findUsedLualibFeatures(luaTarget: LuaTarget, emitHost: EmitHost, luaContents: string[]): Set<LuaLibFeature>;
package/dist/LuaLib.js CHANGED
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getLuaLibBundle = exports.loadImportedLualibFeatures = exports.loadInlineLualibFeatures = exports.resolveRecursiveLualibFeatures = exports.readLuaLibFeature = exports.getLuaLibModulesInfo = exports.luaLibModulesInfoFileName = exports.resolveLuaLibDir = exports.LuaLibFeature = void 0;
3
+ exports.findUsedLualibFeatures = exports.buildMinimalLualibBundle = exports.getLualibBundleReturn = exports.getLuaLibBundle = exports.loadImportedLualibFeatures = exports.loadInlineLualibFeatures = exports.resolveRecursiveLualibFeatures = exports.readLuaLibFeature = exports.getLuaLibExportToFeatureMap = exports.getLuaLibModulesInfo = exports.luaLibModulesInfoFileName = exports.resolveLuaLibDir = exports.LuaLibFeature = void 0;
4
4
  const path = require("path");
5
5
  const lua = require("./LuaAST");
6
6
  const CompilerOptions_1 = require("./CompilerOptions");
7
+ const utils_1 = require("./utils");
7
8
  var LuaLibFeature;
8
9
  (function (LuaLibFeature) {
9
10
  LuaLibFeature["ArrayConcat"] = "ArrayConcat";
@@ -114,26 +115,47 @@ exports.resolveLuaLibDir = resolveLuaLibDir;
114
115
  exports.luaLibModulesInfoFileName = "lualib_module_info.json";
115
116
  const luaLibModulesInfo = new Map();
116
117
  function getLuaLibModulesInfo(luaTarget, emitHost) {
117
- const lualibPath = path.join(resolveLuaLibDir(luaTarget), exports.luaLibModulesInfoFileName);
118
- if (!luaLibModulesInfo.has(lualibPath)) {
118
+ if (!luaLibModulesInfo.has(luaTarget)) {
119
+ const lualibPath = path.join(resolveLuaLibDir(luaTarget), exports.luaLibModulesInfoFileName);
119
120
  const result = emitHost.readFile(lualibPath);
120
121
  if (result !== undefined) {
121
- luaLibModulesInfo.set(lualibPath, JSON.parse(result));
122
+ luaLibModulesInfo.set(luaTarget, JSON.parse(result));
122
123
  }
123
124
  else {
124
125
  throw new Error(`Could not load lualib dependencies from '${lualibPath}'`);
125
126
  }
126
127
  }
127
- return luaLibModulesInfo.get(lualibPath);
128
+ return luaLibModulesInfo.get(luaTarget);
128
129
  }
129
130
  exports.getLuaLibModulesInfo = getLuaLibModulesInfo;
131
+ // This caches the names of lualib exports to their LuaLibFeature, avoiding a linear search for every lookup
132
+ const lualibExportToFeature = new Map();
133
+ function getLuaLibExportToFeatureMap(luaTarget, emitHost) {
134
+ if (!lualibExportToFeature.has(luaTarget)) {
135
+ const luaLibModulesInfo = getLuaLibModulesInfo(luaTarget, emitHost);
136
+ const map = new Map();
137
+ for (const [feature, info] of Object.entries(luaLibModulesInfo)) {
138
+ for (const exportName of info.exports) {
139
+ map.set(exportName, feature);
140
+ }
141
+ }
142
+ lualibExportToFeature.set(luaTarget, map);
143
+ }
144
+ return lualibExportToFeature.get(luaTarget);
145
+ }
146
+ exports.getLuaLibExportToFeatureMap = getLuaLibExportToFeatureMap;
147
+ const lualibFeatureCache = new Map();
130
148
  function readLuaLibFeature(feature, luaTarget, emitHost) {
131
- const featurePath = path.join(resolveLuaLibDir(luaTarget), `${feature}.lua`);
132
- const luaLibFeature = emitHost.readFile(featurePath);
133
- if (luaLibFeature === undefined) {
134
- throw new Error(`Could not load lualib feature from '${featurePath}'`);
149
+ const featureMap = (0, utils_1.getOrUpdate)(lualibFeatureCache, luaTarget, () => new Map());
150
+ if (!featureMap.has(feature)) {
151
+ const featurePath = path.join(resolveLuaLibDir(luaTarget), `${feature}.lua`);
152
+ const luaLibFeature = emitHost.readFile(featurePath);
153
+ if (luaLibFeature === undefined) {
154
+ throw new Error(`Could not load lualib feature from '${featurePath}'`);
155
+ }
156
+ featureMap.set(feature, luaLibFeature);
135
157
  }
136
- return luaLibFeature;
158
+ return featureMap.get(feature);
137
159
  }
138
160
  exports.readLuaLibFeature = readLuaLibFeature;
139
161
  function resolveRecursiveLualibFeatures(features, luaTarget, emitHost, luaLibModulesInfo = getLuaLibModulesInfo(luaTarget, emitHost)) {
@@ -157,23 +179,20 @@ function resolveRecursiveLualibFeatures(features, luaTarget, emitHost, luaLibMod
157
179
  }
158
180
  exports.resolveRecursiveLualibFeatures = resolveRecursiveLualibFeatures;
159
181
  function loadInlineLualibFeatures(features, luaTarget, emitHost) {
160
- let result = "";
161
- for (const feature of resolveRecursiveLualibFeatures(features, luaTarget, emitHost)) {
162
- const luaLibFeature = readLuaLibFeature(feature, luaTarget, emitHost);
163
- result += luaLibFeature + "\n";
164
- }
165
- return result;
182
+ return resolveRecursiveLualibFeatures(features, luaTarget, emitHost)
183
+ .map(feature => readLuaLibFeature(feature, luaTarget, emitHost))
184
+ .join("\n");
166
185
  }
167
186
  exports.loadInlineLualibFeatures = loadInlineLualibFeatures;
168
187
  function loadImportedLualibFeatures(features, luaTarget, emitHost) {
169
188
  const luaLibModuleInfo = getLuaLibModulesInfo(luaTarget, emitHost);
170
189
  const imports = Array.from(features).flatMap(feature => luaLibModuleInfo[feature].exports);
171
- const requireCall = lua.createCallExpression(lua.createIdentifier("require"), [
172
- lua.createStringLiteral("lualib_bundle"),
173
- ]);
174
190
  if (imports.length === 0) {
175
191
  return [];
176
192
  }
193
+ const requireCall = lua.createCallExpression(lua.createIdentifier("require"), [
194
+ lua.createStringLiteral("lualib_bundle"),
195
+ ]);
177
196
  const luaLibId = lua.createIdentifier("____lualib");
178
197
  const importStatement = lua.createVariableDeclarationStatement(luaLibId, requireCall);
179
198
  const statements = [importStatement];
@@ -199,4 +218,35 @@ function getLuaLibBundle(luaTarget, emitHost) {
199
218
  return luaLibBundleContent.get(lualibPath);
200
219
  }
201
220
  exports.getLuaLibBundle = getLuaLibBundle;
221
+ function getLualibBundleReturn(exportedValues) {
222
+ return `\nreturn {\n${exportedValues.map(exportName => ` ${exportName} = ${exportName}`).join(",\n")}\n}\n`;
223
+ }
224
+ exports.getLualibBundleReturn = getLualibBundleReturn;
225
+ function buildMinimalLualibBundle(features, luaTarget, emitHost) {
226
+ const code = loadInlineLualibFeatures(features, luaTarget, emitHost);
227
+ const moduleInfo = getLuaLibModulesInfo(luaTarget, emitHost);
228
+ const exports = Array.from(features).flatMap(feature => moduleInfo[feature].exports);
229
+ return code + getLualibBundleReturn(exports);
230
+ }
231
+ exports.buildMinimalLualibBundle = buildMinimalLualibBundle;
232
+ function findUsedLualibFeatures(luaTarget, emitHost, luaContents) {
233
+ const features = new Set();
234
+ const exportToFeatureMap = getLuaLibExportToFeatureMap(luaTarget, emitHost);
235
+ for (const lua of luaContents) {
236
+ const regex = /^local (\w+) = ____lualib\.(\w+)$/gm;
237
+ while (true) {
238
+ const match = regex.exec(lua);
239
+ if (!match)
240
+ break;
241
+ const [, localName, exportName] = match;
242
+ if (localName !== exportName)
243
+ continue;
244
+ const feature = exportToFeatureMap.get(exportName);
245
+ if (feature)
246
+ features.add(feature);
247
+ }
248
+ }
249
+ return features;
250
+ }
251
+ exports.findUsedLualibFeatures = findUsedLualibFeatures;
202
252
  //# sourceMappingURL=LuaLib.js.map
@@ -135,7 +135,8 @@ class LuaPrinter {
135
135
  }
136
136
  const luaTarget = (_a = this.options.luaTarget) !== null && _a !== void 0 ? _a : CompilerOptions_1.LuaTarget.Universal;
137
137
  const luaLibImport = (_b = this.options.luaLibImport) !== null && _b !== void 0 ? _b : CompilerOptions_1.LuaLibImportKind.Require;
138
- if (luaLibImport === CompilerOptions_1.LuaLibImportKind.Require && file.luaLibFeatures.size > 0) {
138
+ if ((luaLibImport === CompilerOptions_1.LuaLibImportKind.Require || luaLibImport === CompilerOptions_1.LuaLibImportKind.RequireMinimal) &&
139
+ file.luaLibFeatures.size > 0) {
139
140
  // Import lualib features
140
141
  sourceChunks = this.printStatementArray((0, LuaLib_1.loadImportedLualibFeatures)(file.luaLibFeatures, luaTarget, this.emitHost));
141
142
  }
@@ -1,10 +1,6 @@
1
1
  local function __TS__ArraySlice(self, first, last)
2
2
  local len = table.getn(self)
3
- local ____first_0 = first
4
- if ____first_0 == nil then
5
- ____first_0 = 0
6
- end
7
- first = ____first_0
3
+ first = first or 0
8
4
  if first < 0 then
9
5
  first = len + first
10
6
  if first < 0 then
@@ -15,11 +11,7 @@ local function __TS__ArraySlice(self, first, last)
15
11
  first = len
16
12
  end
17
13
  end
18
- local ____last_1 = last
19
- if ____last_1 == nil then
20
- ____last_1 = len
21
- end
22
- last = ____last_1
14
+ last = last or len
23
15
  if last < 0 then
24
16
  last = len + last
25
17
  if last < 0 then
@@ -22,11 +22,7 @@ local function __TS__ArraySplice(self, ...)
22
22
  elseif actualArgumentCount == 1 then
23
23
  actualDeleteCount = len - start
24
24
  else
25
- local ____deleteCount_0 = deleteCount
26
- if ____deleteCount_0 == nil then
27
- ____deleteCount_0 = 0
28
- end
29
- actualDeleteCount = ____deleteCount_0
25
+ actualDeleteCount = deleteCount or 0
30
26
  if actualDeleteCount < 0 then
31
27
  actualDeleteCount = 0
32
28
  end
@@ -10,9 +10,5 @@ local function __TS__ParseFloat(numberString)
10
10
  return ____temp_0
11
11
  end
12
12
  local number = tonumber(__TS__Match(numberString, "^%s*(-?%d+%.?%d*)"))
13
- local ____number_1 = number
14
- if ____number_1 == nil then
15
- ____number_1 = 0 / 0
16
- end
17
- return ____number_1
13
+ return number or 0 / 0
18
14
  end
@@ -5,9 +5,5 @@ local function __TS__StringCharCodeAt(self, index)
5
5
  if index < 0 then
6
6
  return 0 / 0
7
7
  end
8
- local ____string_byte_result_0 = string.byte(self, index + 1)
9
- if ____string_byte_result_0 == nil then
10
- ____string_byte_result_0 = 0 / 0
11
- end
12
- return ____string_byte_result_0
8
+ return string.byte(self, index + 1) or 0 / 0
13
9
  end
@@ -350,11 +350,7 @@ end
350
350
 
351
351
  local function __TS__ArraySlice(self, first, last)
352
352
  local len = table.getn(self)
353
- local ____first_0 = first
354
- if ____first_0 == nil then
355
- ____first_0 = 0
356
- end
357
- first = ____first_0
353
+ first = first or 0
358
354
  if first < 0 then
359
355
  first = len + first
360
356
  if first < 0 then
@@ -365,11 +361,7 @@ local function __TS__ArraySlice(self, first, last)
365
361
  first = len
366
362
  end
367
363
  end
368
- local ____last_1 = last
369
- if ____last_1 == nil then
370
- ____last_1 = len
371
- end
372
- last = ____last_1
364
+ last = last or len
373
365
  if last < 0 then
374
366
  last = len + last
375
367
  if last < 0 then
@@ -425,11 +417,7 @@ local function __TS__ArraySplice(self, ...)
425
417
  elseif actualArgumentCount == 1 then
426
418
  actualDeleteCount = len - start
427
419
  else
428
- local ____deleteCount_0 = deleteCount
429
- if ____deleteCount_0 == nil then
430
- ____deleteCount_0 = 0
431
- end
432
- actualDeleteCount = ____deleteCount_0
420
+ actualDeleteCount = deleteCount or 0
433
421
  if actualDeleteCount < 0 then
434
422
  actualDeleteCount = 0
435
423
  end
@@ -1661,11 +1649,7 @@ local function __TS__ParseFloat(numberString)
1661
1649
  return ____temp_0
1662
1650
  end
1663
1651
  local number = tonumber(__TS__Match(numberString, "^%s*(-?%d+%.?%d*)"))
1664
- local ____number_1 = number
1665
- if ____number_1 == nil then
1666
- ____number_1 = 0 / 0
1667
- end
1668
- return ____number_1
1652
+ return number or 0 / 0
1669
1653
  end
1670
1654
 
1671
1655
  local function __TS__StringSubstring(self, start, ____end)
@@ -2230,11 +2214,7 @@ local function __TS__StringCharCodeAt(self, index)
2230
2214
  if index < 0 then
2231
2215
  return 0 / 0
2232
2216
  end
2233
- local ____string_byte_result_0 = string.byte(self, index + 1)
2234
- if ____string_byte_result_0 == nil then
2235
- ____string_byte_result_0 = 0 / 0
2236
- end
2237
- return ____string_byte_result_0
2217
+ return string.byte(self, index + 1) or 0 / 0
2238
2218
  end
2239
2219
 
2240
2220
  local function __TS__StringEndsWith(self, searchString, endPosition)
@@ -1,10 +1,6 @@
1
1
  local function __TS__ArraySlice(self, first, last)
2
2
  local len = #self
3
- local ____first_0 = first
4
- if ____first_0 == nil then
5
- ____first_0 = 0
6
- end
7
- first = ____first_0
3
+ first = first or 0
8
4
  if first < 0 then
9
5
  first = len + first
10
6
  if first < 0 then
@@ -15,11 +11,7 @@ local function __TS__ArraySlice(self, first, last)
15
11
  first = len
16
12
  end
17
13
  end
18
- local ____last_1 = last
19
- if ____last_1 == nil then
20
- ____last_1 = len
21
- end
22
- last = ____last_1
14
+ last = last or len
23
15
  if last < 0 then
24
16
  last = len + last
25
17
  if last < 0 then
@@ -22,11 +22,7 @@ local function __TS__ArraySplice(self, ...)
22
22
  elseif actualArgumentCount == 1 then
23
23
  actualDeleteCount = len - start
24
24
  else
25
- local ____deleteCount_0 = deleteCount
26
- if ____deleteCount_0 == nil then
27
- ____deleteCount_0 = 0
28
- end
29
- actualDeleteCount = ____deleteCount_0
25
+ actualDeleteCount = deleteCount or 0
30
26
  if actualDeleteCount < 0 then
31
27
  actualDeleteCount = 0
32
28
  end
@@ -10,9 +10,5 @@ local function __TS__ParseFloat(numberString)
10
10
  return ____temp_0
11
11
  end
12
12
  local number = tonumber(__TS__Match(numberString, "^%s*(-?%d+%.?%d*)"))
13
- local ____number_1 = number
14
- if ____number_1 == nil then
15
- ____number_1 = 0 / 0
16
- end
17
- return ____number_1
13
+ return number or 0 / 0
18
14
  end
@@ -1,8 +1,4 @@
1
1
  local function __TS__SparseArraySpread(sparseArray)
2
- local ____unpack_0 = unpack
3
- if ____unpack_0 == nil then
4
- ____unpack_0 = table.unpack
5
- end
6
- local _unpack = ____unpack_0
2
+ local _unpack = unpack or table.unpack
7
3
  return _unpack(sparseArray, 1, sparseArray.sparseLength)
8
4
  end
@@ -5,9 +5,5 @@ local function __TS__StringCharCodeAt(self, index)
5
5
  if index < 0 then
6
6
  return 0 / 0
7
7
  end
8
- local ____string_byte_result_0 = string.byte(self, index + 1)
9
- if ____string_byte_result_0 == nil then
10
- ____string_byte_result_0 = 0 / 0
11
- end
12
- return ____string_byte_result_0
8
+ return string.byte(self, index + 1) or 0 / 0
13
9
  end
@@ -349,11 +349,7 @@ end
349
349
 
350
350
  local function __TS__ArraySlice(self, first, last)
351
351
  local len = #self
352
- local ____first_0 = first
353
- if ____first_0 == nil then
354
- ____first_0 = 0
355
- end
356
- first = ____first_0
352
+ first = first or 0
357
353
  if first < 0 then
358
354
  first = len + first
359
355
  if first < 0 then
@@ -364,11 +360,7 @@ local function __TS__ArraySlice(self, first, last)
364
360
  first = len
365
361
  end
366
362
  end
367
- local ____last_1 = last
368
- if ____last_1 == nil then
369
- ____last_1 = len
370
- end
371
- last = ____last_1
363
+ last = last or len
372
364
  if last < 0 then
373
365
  last = len + last
374
366
  if last < 0 then
@@ -424,11 +416,7 @@ local function __TS__ArraySplice(self, ...)
424
416
  elseif actualArgumentCount == 1 then
425
417
  actualDeleteCount = len - start
426
418
  else
427
- local ____deleteCount_0 = deleteCount
428
- if ____deleteCount_0 == nil then
429
- ____deleteCount_0 = 0
430
- end
431
- actualDeleteCount = ____deleteCount_0
419
+ actualDeleteCount = deleteCount or 0
432
420
  if actualDeleteCount < 0 then
433
421
  actualDeleteCount = 0
434
422
  end
@@ -1597,11 +1585,7 @@ local function __TS__ParseFloat(numberString)
1597
1585
  return ____temp_0
1598
1586
  end
1599
1587
  local number = tonumber(__TS__Match(numberString, "^%s*(-?%d+%.?%d*)"))
1600
- local ____number_1 = number
1601
- if ____number_1 == nil then
1602
- ____number_1 = 0 / 0
1603
- end
1604
- return ____number_1
1588
+ return number or 0 / 0
1605
1589
  end
1606
1590
 
1607
1591
  local function __TS__StringSubstring(self, start, ____end)
@@ -1979,11 +1963,7 @@ local function __TS__SparseArrayPush(sparseArray, ...)
1979
1963
  end
1980
1964
 
1981
1965
  local function __TS__SparseArraySpread(sparseArray)
1982
- local ____unpack_0 = unpack
1983
- if ____unpack_0 == nil then
1984
- ____unpack_0 = table.unpack
1985
- end
1986
- local _unpack = ____unpack_0
1966
+ local _unpack = unpack or table.unpack
1987
1967
  return _unpack(sparseArray, 1, sparseArray.sparseLength)
1988
1968
  end
1989
1969
 
@@ -2165,11 +2145,7 @@ local function __TS__StringCharCodeAt(self, index)
2165
2145
  if index < 0 then
2166
2146
  return 0 / 0
2167
2147
  end
2168
- local ____string_byte_result_0 = string.byte(self, index + 1)
2169
- if ____string_byte_result_0 == nil then
2170
- ____string_byte_result_0 = 0 / 0
2171
- end
2172
- return ____string_byte_result_0
2148
+ return string.byte(self, index + 1) or 0 / 0
2173
2149
  end
2174
2150
 
2175
2151
  local function __TS__StringEndsWith(self, searchString, endPosition)
@@ -49,7 +49,7 @@ class LuaLibPlugin {
49
49
  // Concatenate lualib files into bundle with exports table and add lualib_bundle.lua to results
50
50
  let lualibBundle = orderedFeatures.map(f => exportedLualibFeatures.get(LuaLib_1.LuaLibFeature[f])).join("\n");
51
51
  const exports = allFeatures.flatMap(feature => luaLibModuleInfo[feature].exports);
52
- lualibBundle += `\nreturn {\n${exports.map(exportName => ` ${exportName} = ${exportName}`).join(",\n")}\n}\n`;
52
+ lualibBundle += (0, LuaLib_1.getLualibBundleReturn)(exports);
53
53
  result.push({ fileName: "lualib_bundle.lua", code: lualibBundle });
54
54
  return diagnostics;
55
55
  }
@@ -42,10 +42,10 @@ function createTableLengthExpression(context, expression, node) {
42
42
  * return (#array + 1)
43
43
  */
44
44
  function transformSingleElementArrayPush(context, node, caller, param) {
45
- const expressionIsUsed = !ts.isExpressionStatement((0, typescript_1.findFirstNonOuterParent)(node));
46
45
  const arrayIdentifier = lua.isIdentifier(caller) ? caller : (0, expression_list_1.moveToPrecedingTemp)(context, caller);
47
46
  // #array + 1
48
47
  let lengthExpression = lua.createBinaryExpression(createTableLengthExpression(context, arrayIdentifier), lua.createNumericLiteral(1), lua.SyntaxKind.AdditionOperator);
48
+ const expressionIsUsed = (0, typescript_1.expressionResultIsUsed)(node);
49
49
  if (expressionIsUsed) {
50
50
  // store length in a temp
51
51
  lengthExpression = (0, expression_list_1.moveToPrecedingTemp)(context, lengthExpression);
@@ -91,3 +91,9 @@ export declare const unsupportedOptionalCompileMembersOnly: ((node: ts.Node, ...
91
91
  export declare const undefinedInArrayLiteral: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
92
92
  code: number;
93
93
  };
94
+ export declare const invalidMethodCallExtensionUse: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
95
+ code: number;
96
+ };
97
+ export declare const invalidSpreadInCallExtension: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
98
+ code: number;
99
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.undefinedInArrayLiteral = exports.unsupportedOptionalCompileMembersOnly = exports.unsupportedBuiltinOptionalCall = exports.awaitMustBeInAsyncFunction = exports.notAllowedOptionalAssignment = exports.truthyOnlyConditionalValue = exports.annotationDeprecated = exports.invalidCallExtensionUse = exports.invalidMultiReturnAccess = exports.invalidMultiFunctionReturnType = exports.invalidMultiFunctionUse = exports.unsupportedVarDeclaration = exports.invalidAmbientIdentifierName = exports.unsupportedProperty = exports.unsupportedForTargetButOverrideAvailable = exports.unsupportedForTarget = exports.unsupportedRightShiftOperator = exports.unsupportedAccessorInObjectLiteral = exports.invalidPairsIterableWithoutDestructuring = exports.invalidMultiIterableWithoutDestructuring = exports.invalidRangeControlVariable = exports.invalidVarargUse = exports.invalidRangeUse = exports.annotationInvalidArgumentCount = exports.decoratorInvalidContext = exports.unsupportedOverloadAssignment = exports.unsupportedSelfFunctionConversion = exports.unsupportedNoSelfFunctionConversion = exports.forbiddenForIn = exports.unsupportedNodeKind = void 0;
3
+ exports.invalidSpreadInCallExtension = exports.invalidMethodCallExtensionUse = exports.undefinedInArrayLiteral = exports.unsupportedOptionalCompileMembersOnly = exports.unsupportedBuiltinOptionalCall = exports.awaitMustBeInAsyncFunction = exports.notAllowedOptionalAssignment = exports.truthyOnlyConditionalValue = exports.annotationDeprecated = exports.invalidCallExtensionUse = exports.invalidMultiReturnAccess = exports.invalidMultiFunctionReturnType = exports.invalidMultiFunctionUse = exports.unsupportedVarDeclaration = exports.invalidAmbientIdentifierName = exports.unsupportedProperty = exports.unsupportedForTargetButOverrideAvailable = exports.unsupportedForTarget = exports.unsupportedRightShiftOperator = exports.unsupportedAccessorInObjectLiteral = exports.invalidPairsIterableWithoutDestructuring = exports.invalidMultiIterableWithoutDestructuring = exports.invalidRangeControlVariable = exports.invalidVarargUse = exports.invalidRangeUse = exports.annotationInvalidArgumentCount = exports.decoratorInvalidContext = exports.unsupportedOverloadAssignment = exports.unsupportedSelfFunctionConversion = exports.unsupportedNoSelfFunctionConversion = exports.forbiddenForIn = exports.unsupportedNodeKind = void 0;
4
4
  const ts = require("typescript");
5
5
  const CompilerOptions_1 = require("../../CompilerOptions");
6
6
  const utils_1 = require("../../utils");
@@ -59,4 +59,6 @@ exports.awaitMustBeInAsyncFunction = createErrorDiagnosticFactory("Await can onl
59
59
  exports.unsupportedBuiltinOptionalCall = createErrorDiagnosticFactory("Optional calls are not supported for builtin or language extension functions.");
60
60
  exports.unsupportedOptionalCompileMembersOnly = createErrorDiagnosticFactory("Optional calls are not supported on enums marked with @compileMembersOnly.");
61
61
  exports.undefinedInArrayLiteral = createErrorDiagnosticFactory("Array literals may not contain undefined or null.");
62
+ exports.invalidMethodCallExtensionUse = createErrorDiagnosticFactory("This language extension must be called as a method.");
63
+ exports.invalidSpreadInCallExtension = createErrorDiagnosticFactory("Spread elements are not supported in call extensions.");
62
64
  //# sourceMappingURL=diagnostics.js.map
@@ -63,3 +63,7 @@ export declare enum IterableExtensionKind {
63
63
  export declare function isLuaIterable(context: TransformationContext, type: ts.Type): boolean;
64
64
  export declare function getIterableExtensionTypeForType(context: TransformationContext, type: ts.Type): IterableExtensionKind | undefined;
65
65
  export declare function getIterableExtensionKindForNode(context: TransformationContext, node: ts.Node): IterableExtensionKind | undefined;
66
+ export declare const methodExtensionKinds: ReadonlySet<ExtensionKind>;
67
+ export declare function getNaryCallExtensionArgs(context: TransformationContext, node: ts.CallExpression, kind: ExtensionKind, numArgs: number): readonly ts.Expression[] | undefined;
68
+ export declare function getUnaryCallExtensionArg(context: TransformationContext, node: ts.CallExpression, kind: ExtensionKind): ts.Expression | undefined;
69
+ export declare function getBinaryCallExtensionArgs(context: TransformationContext, node: ts.CallExpression, kind: ExtensionKind): readonly [ts.Expression, ts.Expression] | undefined;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getIterableExtensionKindForNode = exports.getIterableExtensionTypeForType = exports.isLuaIterable = exports.IterableExtensionKind = exports.getExtensionKindForSymbol = exports.getExtensionKindForNode = exports.getExtensionKindForType = exports.ExtensionKind = void 0;
3
+ exports.getBinaryCallExtensionArgs = exports.getUnaryCallExtensionArg = exports.getNaryCallExtensionArgs = exports.methodExtensionKinds = 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
+ const diagnostics_1 = require("./diagnostics");
5
6
  var ExtensionKind;
6
7
  (function (ExtensionKind) {
7
8
  ExtensionKind["MultiFunction"] = "MultiFunction";
@@ -112,4 +113,68 @@ function getIterableExtensionKindForNode(context, node) {
112
113
  return getIterableExtensionTypeForType(context, type);
113
114
  }
114
115
  exports.getIterableExtensionKindForNode = getIterableExtensionKindForNode;
116
+ exports.methodExtensionKinds = new Set([
117
+ ExtensionKind.AdditionOperatorMethodType,
118
+ ExtensionKind.SubtractionOperatorMethodType,
119
+ ExtensionKind.MultiplicationOperatorMethodType,
120
+ ExtensionKind.DivisionOperatorMethodType,
121
+ ExtensionKind.ModuloOperatorMethodType,
122
+ ExtensionKind.PowerOperatorMethodType,
123
+ ExtensionKind.FloorDivisionOperatorMethodType,
124
+ ExtensionKind.BitwiseAndOperatorMethodType,
125
+ ExtensionKind.BitwiseOrOperatorMethodType,
126
+ ExtensionKind.BitwiseExclusiveOrOperatorMethodType,
127
+ ExtensionKind.BitwiseLeftShiftOperatorMethodType,
128
+ ExtensionKind.BitwiseRightShiftOperatorMethodType,
129
+ ExtensionKind.ConcatOperatorMethodType,
130
+ ExtensionKind.LessThanOperatorMethodType,
131
+ ExtensionKind.GreaterThanOperatorMethodType,
132
+ ExtensionKind.NegationOperatorMethodType,
133
+ ExtensionKind.BitwiseNotOperatorMethodType,
134
+ ExtensionKind.LengthOperatorMethodType,
135
+ ExtensionKind.TableDeleteMethodType,
136
+ ExtensionKind.TableGetMethodType,
137
+ ExtensionKind.TableHasMethodType,
138
+ ExtensionKind.TableSetMethodType,
139
+ ExtensionKind.TableAddKeyMethodType,
140
+ ]);
141
+ function getNaryCallExtensionArgs(context, node, kind, numArgs) {
142
+ let expressions;
143
+ if (node.arguments.some(ts.isSpreadElement)) {
144
+ context.diagnostics.push((0, diagnostics_1.invalidSpreadInCallExtension)(node));
145
+ return undefined;
146
+ }
147
+ if (exports.methodExtensionKinds.has(kind)) {
148
+ if (!(ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression))) {
149
+ context.diagnostics.push((0, diagnostics_1.invalidMethodCallExtensionUse)(node));
150
+ return undefined;
151
+ }
152
+ if (node.arguments.length < numArgs - 1) {
153
+ // assumed to be TS error
154
+ return undefined;
155
+ }
156
+ expressions = [node.expression.expression, ...node.arguments];
157
+ }
158
+ else {
159
+ if (node.arguments.length < numArgs) {
160
+ // assumed to be TS error
161
+ return undefined;
162
+ }
163
+ expressions = node.arguments;
164
+ }
165
+ return expressions;
166
+ }
167
+ exports.getNaryCallExtensionArgs = getNaryCallExtensionArgs;
168
+ function getUnaryCallExtensionArg(context, node, kind) {
169
+ var _a;
170
+ return (_a = getNaryCallExtensionArgs(context, node, kind, 1)) === null || _a === void 0 ? void 0 : _a[0];
171
+ }
172
+ exports.getUnaryCallExtensionArg = getUnaryCallExtensionArg;
173
+ function getBinaryCallExtensionArgs(context, node, kind) {
174
+ const expressions = getNaryCallExtensionArgs(context, node, kind, 2);
175
+ if (expressions === undefined)
176
+ return undefined;
177
+ return [expressions[0], expressions[1]];
178
+ }
179
+ exports.getBinaryCallExtensionArgs = getBinaryCallExtensionArgs;
115
180
  //# sourceMappingURL=language-extensions.js.map
@@ -8,6 +8,7 @@ export declare function hasExportEquals(sourceFile: ts.SourceFile): boolean;
8
8
  */
9
9
  export declare function findFirstNodeAbove<T extends ts.Node>(node: ts.Node, callback: (n: ts.Node) => n is T): T | undefined;
10
10
  export declare function findFirstNonOuterParent(node: ts.Node): ts.Node;
11
+ export declare function expressionResultIsUsed(node: ts.Expression): boolean;
11
12
  export declare function getFirstDeclarationInFile(symbol: ts.Symbol, sourceFile: ts.SourceFile): ts.Declaration | undefined;
12
13
  export declare function isStandardLibraryDeclaration(context: TransformationContext, declaration: ts.Declaration): boolean;
13
14
  export declare function isStandardLibraryType(context: TransformationContext, type: ts.Type, name: string | undefined): boolean;
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.isConstIdentifier = exports.getFunctionTypeForCall = exports.isExpressionWithEvaluationEffect = exports.getAllCallSignatures = exports.inferAssignedType = exports.hasStandardLibrarySignature = exports.isStandardLibraryType = exports.isStandardLibraryDeclaration = exports.getFirstDeclarationInFile = exports.findFirstNonOuterParent = exports.findFirstNodeAbove = exports.hasExportEquals = void 0;
17
+ exports.isConstIdentifier = exports.getFunctionTypeForCall = exports.isExpressionWithEvaluationEffect = exports.getAllCallSignatures = exports.inferAssignedType = exports.hasStandardLibrarySignature = exports.isStandardLibraryType = exports.isStandardLibraryDeclaration = exports.getFirstDeclarationInFile = exports.expressionResultIsUsed = exports.findFirstNonOuterParent = exports.findFirstNodeAbove = exports.hasExportEquals = void 0;
18
18
  const ts = require("typescript");
19
19
  __exportStar(require("./nodes"), exports);
20
20
  __exportStar(require("./types"), exports);
@@ -46,6 +46,10 @@ function findFirstNonOuterParent(node) {
46
46
  return current;
47
47
  }
48
48
  exports.findFirstNonOuterParent = findFirstNonOuterParent;
49
+ function expressionResultIsUsed(node) {
50
+ return !ts.isExpressionStatement(findFirstNonOuterParent(node));
51
+ }
52
+ exports.expressionResultIsUsed = expressionResultIsUsed;
49
53
  function getFirstDeclarationInFile(symbol, sourceFile) {
50
54
  var _a, _b;
51
55
  const originalSourceFile = (_a = ts.getParseTreeNode(sourceFile)) !== null && _a !== void 0 ? _a : sourceFile;
@@ -103,9 +103,6 @@ function canBeFalsy(context, type) {
103
103
  }
104
104
  exports.canBeFalsy = canBeFalsy;
105
105
  function canBeFalsyWhenNotNull(context, type) {
106
- const strictNullChecks = context.options.strict === true || context.options.strictNullChecks === true;
107
- if (!strictNullChecks && !type.isLiteral())
108
- return true;
109
106
  const falsyFlags = ts.TypeFlags.Boolean |
110
107
  ts.TypeFlags.BooleanLiteral |
111
108
  ts.TypeFlags.Never |
@@ -1,5 +1,5 @@
1
1
  import * as ts from "typescript";
2
2
  import * as lua from "../../LuaAST";
3
- import { FunctionVisitor, TransformationContext } from "../context";
3
+ import { FunctionVisitor } from "../context";
4
4
  export declare const transformExpressionStatement: FunctionVisitor<ts.ExpressionStatement>;
5
- export declare function transformExpressionToStatement(context: TransformationContext, expression: ts.Expression): lua.Statement | undefined;
5
+ export declare function wrapInStatement(result: lua.Expression): lua.Statement | undefined;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.transformExpressionToStatement = exports.transformExpressionStatement = void 0;
3
+ exports.wrapInStatement = exports.transformExpressionStatement = void 0;
4
4
  const lua = require("../../LuaAST");
5
5
  const context_1 = require("../context");
6
6
  const binary_expression_1 = require("./binary-expression");
@@ -14,11 +14,10 @@ const transformExpressionStatement = (node, context) => {
14
14
  if (binaryExpressionResult) {
15
15
  return binaryExpressionResult;
16
16
  }
17
- return transformExpressionToStatement(context, node.expression);
17
+ return wrapInStatement(context.transformExpression(node.expression));
18
18
  };
19
19
  exports.transformExpressionStatement = transformExpressionStatement;
20
- function transformExpressionToStatement(context, expression) {
21
- const result = context.transformExpression(expression);
20
+ function wrapInStatement(result) {
22
21
  const isTempVariable = lua.isIdentifier(result) && result.symbolId === context_1.tempSymbolId;
23
22
  if (isTempVariable) {
24
23
  return undefined;
@@ -34,5 +33,5 @@ function transformExpressionToStatement(context, expression) {
34
33
  // Assign expression statements to dummy to make sure they're legal Lua
35
34
  return lua.createVariableDeclarationStatement(lua.createAnonymousIdentifier(), result);
36
35
  }
37
- exports.transformExpressionToStatement = transformExpressionToStatement;
36
+ exports.wrapInStatement = wrapInStatement;
38
37
  //# sourceMappingURL=expression-statement.js.map
@@ -21,7 +21,9 @@ function transformIdentifier(context, identifier) {
21
21
  exports.transformIdentifier = transformIdentifier;
22
22
  function transformNonValueIdentifier(context, identifier, symbol) {
23
23
  if ((0, optional_chaining_1.isOptionalContinuation)(identifier)) {
24
- return lua.createIdentifier(identifier.text, undefined, context_1.tempSymbolId);
24
+ const result = lua.createIdentifier(identifier.text, undefined, context_1.tempSymbolId);
25
+ (0, optional_chaining_1.getOptionalContinuationData)(identifier).usedIdentifiers.push(result);
26
+ return result;
25
27
  }
26
28
  const extensionKind = symbol
27
29
  ? (0, language_extensions_1.getExtensionKindForSymbol)(context, symbol)
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.operatorExtensionTransformers = void 0;
4
- const ts = require("typescript");
5
4
  const lua = require("../../../LuaAST");
6
5
  const utils_1 = require("../../../utils");
7
6
  const CompilerOptions_1 = require("../../../CompilerOptions");
8
7
  const diagnostics_1 = require("../../utils/diagnostics");
9
8
  const language_extensions_1 = require("../../utils/language-extensions");
9
+ const expression_list_1 = require("../expression-list");
10
10
  const binaryOperatorMappings = new Map([
11
11
  [language_extensions_1.ExtensionKind.AdditionOperatorType, lua.SyntaxKind.AdditionOperator],
12
12
  [language_extensions_1.ExtensionKind.AdditionOperatorMethodType, lua.SyntaxKind.AdditionOperator],
@@ -76,26 +76,20 @@ for (const kind of unaryOperatorMappings.keys()) {
76
76
  function transformBinaryOperator(context, node, kind) {
77
77
  if (requiresLua53.has(kind))
78
78
  checkHasLua53(context, node, kind);
79
- let args = node.arguments;
80
- if (args.length === 1 &&
81
- (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression))) {
82
- args = [node.expression.expression, ...args];
83
- }
79
+ const args = (0, language_extensions_1.getBinaryCallExtensionArgs)(context, node, kind);
80
+ if (!args)
81
+ return lua.createNilLiteral();
82
+ const [left, right] = (0, expression_list_1.transformOrderedExpressions)(context, args);
84
83
  const luaOperator = binaryOperatorMappings.get(kind);
85
84
  (0, utils_1.assert)(luaOperator);
86
- return lua.createBinaryExpression(context.transformExpression(args[0]), context.transformExpression(args[1]), luaOperator);
85
+ return lua.createBinaryExpression(left, right, luaOperator);
87
86
  }
88
87
  function transformUnaryOperator(context, node, kind) {
89
88
  if (requiresLua53.has(kind))
90
89
  checkHasLua53(context, node, kind);
91
- let arg;
92
- if (node.arguments.length === 0 &&
93
- (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression))) {
94
- arg = node.expression.expression;
95
- }
96
- else {
97
- arg = node.arguments[0];
98
- }
90
+ const arg = (0, language_extensions_1.getUnaryCallExtensionArg)(context, node, kind);
91
+ if (!arg)
92
+ return lua.createNilLiteral();
99
93
  const luaOperator = unaryOperatorMappings.get(kind);
100
94
  (0, utils_1.assert)(luaOperator);
101
95
  return lua.createUnaryExpression(context.transformExpression(arg), luaOperator);
@@ -1,9 +1,7 @@
1
1
  import * as ts from "typescript";
2
2
  import { TransformationContext } from "../../context";
3
3
  import { ExtensionKind } from "../../utils/language-extensions";
4
- import { LanguageExtensionCallTransformer } from "./call-extension";
4
+ import { LanguageExtensionCallTransformerMap } from "./call-extension";
5
5
  export declare function isTableNewCall(context: TransformationContext, node: ts.NewExpression): boolean;
6
6
  export declare const tableNewExtensions: ExtensionKind[];
7
- export declare const tableExtensionTransformers: {
8
- [P in ExtensionKind]?: LanguageExtensionCallTransformer;
9
- };
7
+ export declare const tableExtensionTransformers: LanguageExtensionCallTransformerMap;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.tableExtensionTransformers = exports.tableNewExtensions = exports.isTableNewCall = void 0;
4
- const ts = require("typescript");
5
4
  const lua = require("../../../LuaAST");
6
5
  const language_extensions_1 = require("../../utils/language-extensions");
7
6
  const expression_list_1 = require("../expression-list");
@@ -19,62 +18,57 @@ exports.tableExtensionTransformers = {
19
18
  [language_extensions_1.ExtensionKind.TableHasMethodType]: transformTableHasExpression,
20
19
  [language_extensions_1.ExtensionKind.TableSetType]: transformTableSetExpression,
21
20
  [language_extensions_1.ExtensionKind.TableSetMethodType]: transformTableSetExpression,
22
- [language_extensions_1.ExtensionKind.TableAddKeyType]: transformTableAddExpression,
23
- [language_extensions_1.ExtensionKind.TableAddKeyMethodType]: transformTableAddExpression,
21
+ [language_extensions_1.ExtensionKind.TableAddKeyType]: transformTableAddKeyExpression,
22
+ [language_extensions_1.ExtensionKind.TableAddKeyMethodType]: transformTableAddKeyExpression,
24
23
  };
25
24
  function transformTableDeleteExpression(context, node, extensionKind) {
26
- const args = node.arguments.slice();
27
- if (extensionKind === language_extensions_1.ExtensionKind.TableDeleteMethodType &&
28
- (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression))) {
29
- // In case of method (no table argument), push method owner to front of args list
30
- args.unshift(node.expression.expression);
25
+ const args = (0, language_extensions_1.getBinaryCallExtensionArgs)(context, node, extensionKind);
26
+ if (!args) {
27
+ return lua.createNilLiteral();
31
28
  }
32
- const [table, accessExpression] = (0, expression_list_1.transformExpressionList)(context, args);
29
+ const [table, key] = (0, expression_list_1.transformOrderedExpressions)(context, args);
33
30
  // arg0[arg1] = nil
34
- context.addPrecedingStatements(lua.createAssignmentStatement(lua.createTableIndexExpression(table, accessExpression), lua.createNilLiteral(), node));
31
+ context.addPrecedingStatements(lua.createAssignmentStatement(lua.createTableIndexExpression(table, key), lua.createNilLiteral(), node));
35
32
  return lua.createBooleanLiteral(true);
36
33
  }
37
- function transformWithTableArgument(context, node) {
38
- if (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression)) {
39
- return (0, expression_list_1.transformExpressionList)(context, [node.expression.expression, ...node.arguments]);
40
- }
41
- // todo: report diagnostic?
42
- return [lua.createNilLiteral(), ...(0, expression_list_1.transformExpressionList)(context, node.arguments)];
43
- }
44
34
  function transformTableGetExpression(context, node, extensionKind) {
45
- const args = extensionKind === language_extensions_1.ExtensionKind.TableGetMethodType
46
- ? transformWithTableArgument(context, node)
47
- : (0, expression_list_1.transformExpressionList)(context, node.arguments);
48
- const [table, accessExpression] = args;
35
+ const args = (0, language_extensions_1.getBinaryCallExtensionArgs)(context, node, extensionKind);
36
+ if (!args) {
37
+ return lua.createNilLiteral();
38
+ }
39
+ const [table, key] = (0, expression_list_1.transformOrderedExpressions)(context, args);
49
40
  // arg0[arg1]
50
- return lua.createTableIndexExpression(table, accessExpression, node);
41
+ return lua.createTableIndexExpression(table, key, node);
51
42
  }
52
43
  function transformTableHasExpression(context, node, extensionKind) {
53
- const args = extensionKind === language_extensions_1.ExtensionKind.TableHasMethodType
54
- ? transformWithTableArgument(context, node)
55
- : (0, expression_list_1.transformExpressionList)(context, node.arguments);
56
- const [table, accessExpression] = args;
44
+ const args = (0, language_extensions_1.getBinaryCallExtensionArgs)(context, node, extensionKind);
45
+ if (!args) {
46
+ return lua.createNilLiteral();
47
+ }
48
+ const [table, key] = (0, expression_list_1.transformOrderedExpressions)(context, args);
57
49
  // arg0[arg1]
58
- const tableIndexExpression = lua.createTableIndexExpression(table, accessExpression);
50
+ const tableIndexExpression = lua.createTableIndexExpression(table, key);
59
51
  // arg0[arg1] ~= nil
60
52
  return lua.createBinaryExpression(tableIndexExpression, lua.createNilLiteral(), lua.SyntaxKind.InequalityOperator, node);
61
53
  }
62
54
  function transformTableSetExpression(context, node, extensionKind) {
63
- const args = extensionKind === language_extensions_1.ExtensionKind.TableSetMethodType
64
- ? transformWithTableArgument(context, node)
65
- : (0, expression_list_1.transformExpressionList)(context, node.arguments);
66
- const [table, accessExpression, value] = args;
55
+ const args = (0, language_extensions_1.getNaryCallExtensionArgs)(context, node, extensionKind, 3);
56
+ if (!args) {
57
+ return lua.createNilLiteral();
58
+ }
59
+ const [table, key, value] = (0, expression_list_1.transformOrderedExpressions)(context, args);
67
60
  // arg0[arg1] = arg2
68
- context.addPrecedingStatements(lua.createAssignmentStatement(lua.createTableIndexExpression(table, accessExpression), value, node));
61
+ context.addPrecedingStatements(lua.createAssignmentStatement(lua.createTableIndexExpression(table, key), value, node));
69
62
  return lua.createNilLiteral();
70
63
  }
71
- function transformTableAddExpression(context, node, extensionKind) {
72
- const args = extensionKind === language_extensions_1.ExtensionKind.TableAddKeyMethodType
73
- ? transformWithTableArgument(context, node)
74
- : (0, expression_list_1.transformExpressionList)(context, node.arguments);
75
- const [table, value] = args;
64
+ function transformTableAddKeyExpression(context, node, extensionKind) {
65
+ const args = (0, language_extensions_1.getNaryCallExtensionArgs)(context, node, extensionKind, 2);
66
+ if (!args) {
67
+ return lua.createNilLiteral();
68
+ }
69
+ const [table, key] = (0, expression_list_1.transformOrderedExpressions)(context, args);
76
70
  // arg0[arg1] = true
77
- context.addPrecedingStatements(lua.createAssignmentStatement(lua.createTableIndexExpression(table, value), lua.createBooleanLiteral(true), node));
71
+ context.addPrecedingStatements(lua.createAssignmentStatement(lua.createTableIndexExpression(table, key), lua.createBooleanLiteral(true), node));
78
72
  return lua.createNilLiteral();
79
73
  }
80
74
  //# sourceMappingURL=table.js.map
@@ -8,9 +8,10 @@ export interface ExpressionWithThisValue {
8
8
  export declare function captureThisValue(context: TransformationContext, expression: lua.Expression, thisValueCapture: lua.Identifier, tsOriginal: ts.Node): lua.Expression;
9
9
  export interface OptionalContinuation {
10
10
  contextualCall?: lua.CallExpression;
11
+ usedIdentifiers: lua.Identifier[];
11
12
  }
12
13
  export declare function isOptionalContinuation(node: ts.Node): boolean;
13
14
  export declare function getOptionalContinuationData(identifier: ts.Identifier): OptionalContinuation | undefined;
14
15
  export declare function transformOptionalChain(context: TransformationContext, node: ts.OptionalChain): lua.Expression;
15
- export declare function transformOptionalChainWithCapture(context: TransformationContext, node: ts.OptionalChain, thisValueCapture: lua.Identifier | undefined, isDelete?: ts.DeleteExpression): ExpressionWithThisValue;
16
+ export declare function transformOptionalChainWithCapture(context: TransformationContext, tsNode: ts.OptionalChain, thisValueCapture: lua.Identifier | undefined, isDelete?: ts.DeleteExpression): ExpressionWithThisValue;
16
17
  export declare function transformOptionalDeleteExpression(context: TransformationContext, node: ts.DeleteExpression, innerExpression: ts.OptionalChain): lua.BooleanLiteral;
@@ -8,6 +8,8 @@ const utils_1 = require("../../utils");
8
8
  const preceding_statements_1 = require("../utils/preceding-statements");
9
9
  const access_1 = require("./access");
10
10
  const expression_list_1 = require("./expression-list");
11
+ const typescript_1 = require("../utils/typescript");
12
+ const expression_statement_1 = require("./expression-statement");
11
13
  function skipNonNullChains(chain) {
12
14
  while (ts.isNonNullChain(chain)) {
13
15
  chain = chain.expression;
@@ -39,7 +41,7 @@ function transformExpressionWithThisValueCapture(context, node, thisValueCapture
39
41
  }
40
42
  // returns thisValueCapture exactly if a temp variable was used.
41
43
  function captureThisValue(context, expression, thisValueCapture, tsOriginal) {
42
- if (!(0, expression_list_1.shouldMoveToTemp)(context, expression, tsOriginal) && !isOptionalContinuation(tsOriginal)) {
44
+ if (!(0, expression_list_1.shouldMoveToTemp)(context, expression, tsOriginal)) {
43
45
  return expression;
44
46
  }
45
47
  const tempAssignment = lua.createAssignmentStatement(thisValueCapture, expression, tsOriginal);
@@ -52,7 +54,9 @@ const optionalContinuations = new WeakMap();
52
54
  function createOptionalContinuationIdentifier(text, tsOriginal) {
53
55
  const identifier = ts.factory.createIdentifier(text);
54
56
  ts.setOriginalNode(identifier, tsOriginal);
55
- optionalContinuations.set(identifier, {});
57
+ optionalContinuations.set(identifier, {
58
+ usedIdentifiers: [],
59
+ });
56
60
  return identifier;
57
61
  }
58
62
  function isOptionalContinuation(node) {
@@ -67,12 +71,11 @@ function transformOptionalChain(context, node) {
67
71
  return transformOptionalChainWithCapture(context, node, undefined).expression;
68
72
  }
69
73
  exports.transformOptionalChain = transformOptionalChain;
70
- function transformOptionalChainWithCapture(context, node, thisValueCapture, isDelete) {
71
- var _a;
72
- const luaTemp = context.createTempNameForNode(node);
73
- const { expression: tsLeftExpression, chain } = flattenChain(node);
74
+ function transformOptionalChainWithCapture(context, tsNode, thisValueCapture, isDelete) {
75
+ const luaTempName = context.createTempName("opt");
76
+ const { expression: tsLeftExpression, chain } = flattenChain(tsNode);
74
77
  // build temp.b.c.d
75
- const tsTemp = createOptionalContinuationIdentifier(luaTemp.text, tsLeftExpression);
78
+ const tsTemp = createOptionalContinuationIdentifier(luaTempName, tsLeftExpression);
76
79
  let tsRightExpression = tsTemp;
77
80
  for (const link of chain) {
78
81
  if (ts.isPropertyAccessExpression(link)) {
@@ -96,21 +99,20 @@ function transformOptionalChainWithCapture(context, node, thisValueCapture, isDe
96
99
  // transform right expression first to check if thisValue capture is needed
97
100
  // capture and return thisValue if requested from outside
98
101
  let returnThisValue;
99
- const [rightPrecedingStatements, rightAssignment] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => {
100
- let result;
101
- if (thisValueCapture) {
102
- ({ expression: result, thisValue: returnThisValue } = transformExpressionWithThisValueCapture(context, tsRightExpression, thisValueCapture));
103
- }
104
- else {
105
- result = context.transformExpression(tsRightExpression);
102
+ const [rightPrecedingStatements, rightExpression] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => {
103
+ if (!thisValueCapture) {
104
+ return context.transformExpression(tsRightExpression);
106
105
  }
107
- return lua.createAssignmentStatement(luaTemp, result);
106
+ const { expression: result, thisValue } = transformExpressionWithThisValueCapture(context, tsRightExpression, thisValueCapture);
107
+ returnThisValue = thisValue;
108
+ return result;
108
109
  });
109
110
  // transform left expression, handle thisValue if needed by rightExpression
110
111
  const thisValueCaptureName = context.createTempName("this");
111
112
  const leftThisValueTemp = lua.createIdentifier(thisValueCaptureName, undefined, context_1.tempSymbolId);
112
113
  let capturedThisValue;
113
- const rightContextualCall = (_a = getOptionalContinuationData(tsTemp)) === null || _a === void 0 ? void 0 : _a.contextualCall;
114
+ const optionalContinuationData = getOptionalContinuationData(tsTemp);
115
+ const rightContextualCall = optionalContinuationData === null || optionalContinuationData === void 0 ? void 0 : optionalContinuationData.contextualCall;
114
116
  const [leftPrecedingStatements, leftExpression] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => {
115
117
  let result;
116
118
  if (rightContextualCall) {
@@ -146,22 +148,66 @@ function transformOptionalChainWithCapture(context, node, thisValueCapture, isDe
146
148
  }
147
149
  }
148
150
  }
149
- // <left preceding statements>
150
- // local temp = <left>
151
- // if temp ~= nil then
152
- // <right preceding statements>
153
- // temp = temp.b.c.d
154
- // end
155
- // return temp
156
- context.addPrecedingStatements([
157
- ...leftPrecedingStatements,
158
- lua.createVariableDeclarationStatement(luaTemp, leftExpression),
159
- lua.createIfStatement(lua.createBinaryExpression(luaTemp, lua.createNilLiteral(), lua.SyntaxKind.InequalityOperator), lua.createBlock([...rightPrecedingStatements, rightAssignment])),
160
- ]);
161
- return {
162
- expression: luaTemp,
163
- thisValue: returnThisValue,
164
- };
151
+ // evaluate optional chain
152
+ context.addPrecedingStatements(leftPrecedingStatements);
153
+ // try use existing variable instead of creating new one, if possible
154
+ let leftIdentifier;
155
+ const usedLuaIdentifiers = optionalContinuationData === null || optionalContinuationData === void 0 ? void 0 : optionalContinuationData.usedIdentifiers;
156
+ const reuseLeftIdentifier = usedLuaIdentifiers &&
157
+ usedLuaIdentifiers.length > 0 &&
158
+ lua.isIdentifier(leftExpression) &&
159
+ (rightPrecedingStatements.length === 0 || !(0, expression_list_1.shouldMoveToTemp)(context, leftExpression, tsLeftExpression));
160
+ if (reuseLeftIdentifier) {
161
+ leftIdentifier = leftExpression;
162
+ for (const usedIdentifier of usedLuaIdentifiers) {
163
+ usedIdentifier.text = leftIdentifier.text;
164
+ }
165
+ }
166
+ else {
167
+ leftIdentifier = lua.createIdentifier(luaTempName, undefined, context_1.tempSymbolId);
168
+ context.addPrecedingStatements(lua.createVariableDeclarationStatement(leftIdentifier, leftExpression));
169
+ }
170
+ if (!(0, typescript_1.expressionResultIsUsed)(tsNode) || isDelete) {
171
+ // if left ~= nil then
172
+ // <right preceding statements>
173
+ // <right expression>
174
+ // end
175
+ const innerExpression = (0, expression_statement_1.wrapInStatement)(rightExpression);
176
+ const innerStatements = rightPrecedingStatements;
177
+ if (innerExpression)
178
+ innerStatements.push(innerExpression);
179
+ context.addPrecedingStatements(lua.createIfStatement(lua.createBinaryExpression(leftIdentifier, lua.createNilLiteral(), lua.SyntaxKind.InequalityOperator), lua.createBlock(innerStatements)));
180
+ return { expression: lua.createNilLiteral(), thisValue: returnThisValue };
181
+ }
182
+ else if (rightPrecedingStatements.length === 0 &&
183
+ !(0, typescript_1.canBeFalsyWhenNotNull)(context, context.checker.getTypeAtLocation(tsLeftExpression))) {
184
+ // return a && a.b
185
+ return {
186
+ expression: lua.createBinaryExpression(leftIdentifier, rightExpression, lua.SyntaxKind.AndOperator, tsNode),
187
+ thisValue: returnThisValue,
188
+ };
189
+ }
190
+ else {
191
+ let resultIdentifier;
192
+ if (!reuseLeftIdentifier) {
193
+ // reuse temp variable for output
194
+ resultIdentifier = leftIdentifier;
195
+ }
196
+ else {
197
+ resultIdentifier = lua.createIdentifier(context.createTempName("opt_result"), undefined, context_1.tempSymbolId);
198
+ context.addPrecedingStatements(lua.createVariableDeclarationStatement(resultIdentifier));
199
+ }
200
+ // if left ~= nil then
201
+ // <right preceding statements>
202
+ // result = <right expression>
203
+ // end
204
+ // return result
205
+ context.addPrecedingStatements(lua.createIfStatement(lua.createBinaryExpression(leftIdentifier, lua.createNilLiteral(), lua.SyntaxKind.InequalityOperator), lua.createBlock([
206
+ ...rightPrecedingStatements,
207
+ lua.createAssignmentStatement(resultIdentifier, rightExpression),
208
+ ])));
209
+ return { expression: resultIdentifier, thisValue: returnThisValue };
210
+ }
165
211
  }
166
212
  exports.transformOptionalChainWithCapture = transformOptionalChainWithCapture;
167
213
  function transformOptionalDeleteExpression(context, node, innerExpression) {
@@ -8,7 +8,7 @@ const expression_statement_1 = require("./expression-statement");
8
8
  const transformVoidExpression = (node, context) => {
9
9
  // If content is a literal it is safe to replace the entire expression with nil
10
10
  if (!ts.isLiteralExpression(node.expression)) {
11
- const statements = (0, expression_statement_1.transformExpressionToStatement)(context, node.expression);
11
+ const statements = (0, expression_statement_1.wrapInStatement)(context.transformExpression(node.expression));
12
12
  if (statements)
13
13
  context.addPrecedingStatements(statements);
14
14
  }
@@ -17,7 +17,7 @@ exports.usingLuaBundleWithInlineMightGenerateDuplicateCode = (0, utils_1.createS
17
17
  messageText: "Using 'luaBundle' with 'luaLibImport: \"inline\"' might generate duplicate code. " +
18
18
  "It is recommended to use 'luaLibImport: \"require\"'.",
19
19
  }));
20
- exports.cannotBundleLibrary = createDiagnosticFactory(() => 'Cannot bundle probjects with"buildmode": "library". Projects including the library can still bundle (which will include external library files).');
20
+ exports.cannotBundleLibrary = createDiagnosticFactory(() => 'Cannot bundle projects 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
22
  exports.pathsWithoutBaseUrl = createDiagnosticFactory(() => "When configuring 'paths' in tsconfig.json, the option 'baseUrl' must also be provided.");
23
23
  //# sourceMappingURL=diagnostics.js.map
@@ -19,6 +19,7 @@ export declare class Transpiler {
19
19
  protected getEmitPlan(program: ts.Program, diagnostics: ts.Diagnostic[], files: ProcessedFile[]): {
20
20
  emitPlan: EmitFile[];
21
21
  };
22
+ private getLuaLibBundleContent;
22
23
  }
23
24
  export declare function getEmitPath(file: string, program: ts.Program): string;
24
25
  export declare function getEmitPathRelativeToOutDir(fileName: string, program: ts.Program): string;
@@ -61,7 +61,6 @@ class Transpiler {
61
61
  return diagnostics;
62
62
  }
63
63
  getEmitPlan(program, diagnostics, files) {
64
- var _a;
65
64
  performance.startSection("getEmitPlan");
66
65
  const options = program.getCompilerOptions();
67
66
  if (options.tstlVerbose) {
@@ -79,8 +78,8 @@ class Transpiler {
79
78
  }
80
79
  // Add lualib bundle to source dir 'virtually', will be moved to correct output dir in emitPlan
81
80
  const fileName = (0, utils_1.normalizeSlashes)(path.resolve(getSourceDir(program), "lualib_bundle.lua"));
82
- const luaTarget = (_a = options.luaTarget) !== null && _a !== void 0 ? _a : CompilerOptions_1.LuaTarget.Universal;
83
- resolutionResult.resolvedFiles.unshift({ fileName, code: (0, LuaLib_1.getLuaLibBundle)(luaTarget, this.emitHost) });
81
+ const code = this.getLuaLibBundleContent(options, resolutionResult.resolvedFiles);
82
+ resolutionResult.resolvedFiles.unshift({ fileName, code });
84
83
  }
85
84
  let emitPlan;
86
85
  if ((0, CompilerOptions_1.isBundleEnabled)(options)) {
@@ -97,6 +96,17 @@ class Transpiler {
97
96
  performance.endSection("getEmitPlan");
98
97
  return { emitPlan };
99
98
  }
99
+ getLuaLibBundleContent(options, resolvedFiles) {
100
+ var _a;
101
+ const luaTarget = (_a = options.luaTarget) !== null && _a !== void 0 ? _a : CompilerOptions_1.LuaTarget.Universal;
102
+ if (options.luaLibImport === CompilerOptions_1.LuaLibImportKind.RequireMinimal) {
103
+ const usedFeatures = (0, LuaLib_1.findUsedLualibFeatures)(luaTarget, this.emitHost, resolvedFiles.map(f => f.code));
104
+ return (0, LuaLib_1.buildMinimalLualibBundle)(usedFeatures, luaTarget, this.emitHost);
105
+ }
106
+ else {
107
+ return (0, LuaLib_1.getLuaLibBundle)(luaTarget, this.emitHost);
108
+ }
109
+ }
100
110
  }
101
111
  exports.Transpiler = Transpiler;
102
112
  function getEmitPath(file, program) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typescript-to-lua",
3
- "version": "1.12.0",
3
+ "version": "1.12.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/",