typescript-to-lua 1.12.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) 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/preceding-statements.d.ts +5 -1
  24. package/dist/transformation/utils/preceding-statements.js +1 -1
  25. package/dist/transformation/utils/typescript/index.d.ts +1 -0
  26. package/dist/transformation/utils/typescript/index.js +5 -1
  27. package/dist/transformation/utils/typescript/types.js +0 -3
  28. package/dist/transformation/visitors/binary-expression/assignments.js +3 -3
  29. package/dist/transformation/visitors/binary-expression/compound.d.ts +0 -7
  30. package/dist/transformation/visitors/binary-expression/compound.js +40 -22
  31. package/dist/transformation/visitors/binary-expression/destructuring-assignments.js +5 -5
  32. package/dist/transformation/visitors/binary-expression/index.d.ts +3 -2
  33. package/dist/transformation/visitors/binary-expression/index.js +12 -13
  34. package/dist/transformation/visitors/call.js +2 -2
  35. package/dist/transformation/visitors/class/index.js +1 -1
  36. package/dist/transformation/visitors/class/members/fields.js +1 -1
  37. package/dist/transformation/visitors/conditional.js +10 -10
  38. package/dist/transformation/visitors/expression-list.js +1 -1
  39. package/dist/transformation/visitors/expression-statement.d.ts +2 -2
  40. package/dist/transformation/visitors/expression-statement.js +4 -5
  41. package/dist/transformation/visitors/function.js +2 -2
  42. package/dist/transformation/visitors/identifier.js +3 -1
  43. package/dist/transformation/visitors/language-extensions/operators.js +9 -15
  44. package/dist/transformation/visitors/language-extensions/table.d.ts +2 -4
  45. package/dist/transformation/visitors/language-extensions/table.js +32 -38
  46. package/dist/transformation/visitors/loops/do-while.js +2 -2
  47. package/dist/transformation/visitors/loops/for.js +2 -2
  48. package/dist/transformation/visitors/loops/utils.js +1 -1
  49. package/dist/transformation/visitors/optional-chaining.d.ts +2 -1
  50. package/dist/transformation/visitors/optional-chaining.js +79 -33
  51. package/dist/transformation/visitors/sourceFile.js +1 -1
  52. package/dist/transformation/visitors/switch.js +15 -6
  53. package/dist/transformation/visitors/typeof.js +1 -1
  54. package/dist/transformation/visitors/variable-declaration.js +3 -3
  55. package/dist/transformation/visitors/void.js +1 -1
  56. package/dist/transpilation/diagnostics.js +1 -1
  57. package/dist/transpilation/output-collector.d.ts +1 -1
  58. package/dist/transpilation/output-collector.js +3 -3
  59. package/dist/transpilation/resolve.js +19 -10
  60. package/dist/transpilation/transpiler.d.ts +1 -0
  61. package/dist/transpilation/transpiler.js +13 -3
  62. package/package.json +1 -1
@@ -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
@@ -9,7 +9,7 @@ const transformWhileStatement = (statement, context) => {
9
9
  // Check if we need to add diagnostic about Lua truthiness
10
10
  (0, conditional_1.checkOnlyTruthyCondition)(statement.expression, context);
11
11
  const body = (0, utils_1.transformLoopBody)(context, statement);
12
- let [conditionPrecedingStatements, condition] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(statement.expression));
12
+ let { precedingStatements: conditionPrecedingStatements, result: condition } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(statement.expression));
13
13
  // If condition has preceding statements, ensure they are executed every iteration by using the form:
14
14
  //
15
15
  // while true do
@@ -31,7 +31,7 @@ const transformDoStatement = (statement, context) => {
31
31
  // Check if we need to add diagnostic about Lua truthiness
32
32
  (0, conditional_1.checkOnlyTruthyCondition)(statement.expression, context);
33
33
  const body = lua.createDoStatement((0, utils_1.transformLoopBody)(context, statement));
34
- let [conditionPrecedingStatements, condition] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, utils_1.invertCondition)(context.transformExpression(statement.expression)));
34
+ let { precedingStatements: conditionPrecedingStatements, result: condition } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, utils_1.invertCondition)(context.transformExpression(statement.expression)));
35
35
  // If condition has preceding statements, ensure they are executed every iteration by using the form:
36
36
  //
37
37
  // repeat
@@ -21,9 +21,9 @@ const transformForStatement = (statement, context) => {
21
21
  const body = (0, utils_1.transformLoopBody)(context, statement);
22
22
  let condition;
23
23
  if (statement.condition) {
24
- let conditionPrecedingStatements;
25
24
  const tsCondition = statement.condition;
26
- [conditionPrecedingStatements, condition] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(tsCondition));
25
+ const { precedingStatements: conditionPrecedingStatements, result } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(tsCondition));
26
+ condition = result;
27
27
  // If condition has preceding statements, ensure they are executed every iteration by using the form:
28
28
  //
29
29
  // while true do
@@ -40,7 +40,7 @@ function transformForInitializer(context, initializer, block) {
40
40
  // Declaration of new variable
41
41
  const binding = getVariableDeclarationBinding(context, initializer);
42
42
  if (ts.isArrayBindingPattern(binding) || ts.isObjectBindingPattern(binding)) {
43
- const [precedingStatements, bindings] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, variable_declaration_1.transformBindingPattern)(context, binding, valueVariable));
43
+ const { precedingStatements, result: bindings } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, variable_declaration_1.transformBindingPattern)(context, binding, valueVariable));
44
44
  block.statements.unshift(...precedingStatements, ...bindings);
45
45
  }
46
46
  else {
@@ -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,22 +99,21 @@ 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 { precedingStatements: rightPrecedingStatements, result: 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 [leftPrecedingStatements, leftExpression] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => {
114
+ const optionalContinuationData = getOptionalContinuationData(tsTemp);
115
+ const rightContextualCall = optionalContinuationData === null || optionalContinuationData === void 0 ? void 0 : optionalContinuationData.contextualCall;
116
+ const { precedingStatements: leftPrecedingStatements, result: leftExpression } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => {
115
117
  let result;
116
118
  if (rightContextualCall) {
117
119
  ({ expression: result, thisValue: capturedThisValue } = transformExpressionWithThisValueCapture(context, tsLeftExpression, leftThisValueTemp));
@@ -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) {
@@ -15,7 +15,7 @@ const transformSourceFileNode = (node, context) => {
15
15
  const [statement] = node.statements;
16
16
  if (statement) {
17
17
  (0, utils_1.assert)(ts.isExpressionStatement(statement));
18
- const [precedingStatements, expression] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(statement.expression));
18
+ const { precedingStatements, result: expression } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(statement.expression));
19
19
  statements.push(...precedingStatements);
20
20
  statements.push(lua.createReturnStatement([expression]));
21
21
  }
@@ -25,18 +25,21 @@ const createOrExpression = (context, left, right, rightPrecedingStatements) => {
25
25
  return (0, binary_expression_1.createShortCircuitBinaryExpressionPrecedingStatements)(context, left, right, rightPrecedingStatements, ts.SyntaxKind.BarBarToken);
26
26
  }
27
27
  else {
28
- return [rightPrecedingStatements, lua.createBinaryExpression(left, right, lua.SyntaxKind.OrOperator)];
28
+ return {
29
+ precedingStatements: rightPrecedingStatements,
30
+ result: lua.createBinaryExpression(left, right, lua.SyntaxKind.OrOperator),
31
+ };
29
32
  }
30
33
  };
31
34
  const coalesceCondition = (condition, conditionPrecedingStatements, switchVariable, expression, context) => {
32
- const [precedingStatements, transformedExpression] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(expression));
35
+ const { precedingStatements, result: transformedExpression } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(expression));
33
36
  // Coalesce skipped statements
34
37
  const comparison = lua.createBinaryExpression(switchVariable, transformedExpression, lua.SyntaxKind.EqualityOperator);
35
38
  if (condition) {
36
39
  return createOrExpression(context, condition, comparison, precedingStatements);
37
40
  }
38
41
  // Next condition
39
- return [[...conditionPrecedingStatements, ...precedingStatements], comparison];
42
+ return { precedingStatements: [...conditionPrecedingStatements, ...precedingStatements], result: comparison };
40
43
  };
41
44
  const transformSwitchStatement = (statement, context) => {
42
45
  const scope = context.pushScope(scope_1.ScopeType.Switch);
@@ -77,7 +80,9 @@ const transformSwitchStatement = (statement, context) => {
77
80
  }
78
81
  // Compute the condition for the if statement
79
82
  if (!ts.isDefaultClause(clause)) {
80
- [conditionPrecedingStatements, condition] = coalesceCondition(condition, conditionPrecedingStatements, switchVariable, clause.expression, context);
83
+ const { precedingStatements, result } = coalesceCondition(condition, conditionPrecedingStatements, switchVariable, clause.expression, context);
84
+ conditionPrecedingStatements = precedingStatements;
85
+ condition = result;
81
86
  // Skip empty clauses unless final clause (i.e side-effects)
82
87
  if (i !== clauses.length - 1 && clause.statements.length === 0)
83
88
  continue;
@@ -86,7 +91,9 @@ const transformSwitchStatement = (statement, context) => {
86
91
  statements.push(...conditionPrecedingStatements, lua.createVariableDeclarationStatement(conditionVariable, condition));
87
92
  }
88
93
  else {
89
- [conditionPrecedingStatements, condition] = createOrExpression(context, conditionVariable, condition, conditionPrecedingStatements);
94
+ const { precedingStatements, result } = createOrExpression(context, conditionVariable, condition, conditionPrecedingStatements);
95
+ conditionPrecedingStatements = precedingStatements;
96
+ condition = result;
90
97
  statements.push(...conditionPrecedingStatements, lua.createAssignmentStatement(conditionVariable, condition));
91
98
  }
92
99
  isInitialCondition = false;
@@ -104,7 +111,9 @@ const transformSwitchStatement = (statement, context) => {
104
111
  if (i === clauses.length - 1) {
105
112
  // Evaluate the final condition that we may be skipping
106
113
  if (condition) {
107
- [conditionPrecedingStatements, condition] = createOrExpression(context, conditionVariable, condition, conditionPrecedingStatements);
114
+ const { precedingStatements, result } = createOrExpression(context, conditionVariable, condition, conditionPrecedingStatements);
115
+ conditionPrecedingStatements = precedingStatements;
116
+ condition = result;
108
117
  statements.push(...conditionPrecedingStatements, lua.createAssignmentStatement(conditionVariable, condition));
109
118
  }
110
119
  continue;
@@ -43,7 +43,7 @@ function transformTypeOfBinaryExpression(context, node) {
43
43
  }
44
44
  const innerExpression = context.transformExpression(typeOfExpression.expression);
45
45
  const typeCall = lua.createCallExpression(lua.createIdentifier("type"), [innerExpression], typeOfExpression);
46
- const [precedingStatements, result] = (0, binary_expression_1.transformBinaryOperation)(context, typeCall, comparedExpression, [], operator, node);
46
+ const { precedingStatements, result } = (0, binary_expression_1.transformBinaryOperation)(context, typeCall, comparedExpression, [], operator, node);
47
47
  context.addPrecedingStatements(precedingStatements);
48
48
  return result;
49
49
  }
@@ -61,7 +61,7 @@ function transformBindingPattern(context, pattern, table, propertyAccessStack =
61
61
  const variableName = (0, identifier_1.transformIdentifier)(context, element.name);
62
62
  // The field to extract
63
63
  const elementName = (_a = element.propertyName) !== null && _a !== void 0 ? _a : element.name;
64
- const [precedingStatements, propertyName] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, literal_1.transformPropertyName)(context, elementName));
64
+ const { precedingStatements, result: propertyName } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, literal_1.transformPropertyName)(context, elementName));
65
65
  result.push(...precedingStatements); // Keep property's preceding statements in order
66
66
  let expression;
67
67
  if (element.dotDotDotToken) {
@@ -101,7 +101,7 @@ function transformBindingPattern(context, pattern, table, propertyAccessStack =
101
101
  if (element.initializer) {
102
102
  const identifier = (0, export_1.addExportToIdentifier)(context, variableName);
103
103
  const tsInitializer = element.initializer;
104
- const [initializerPrecedingStatements, initializer] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(tsInitializer));
104
+ const { precedingStatements: initializerPrecedingStatements, result: initializer } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(tsInitializer));
105
105
  result.push(lua.createIfStatement(lua.createBinaryExpression(identifier, lua.createNilLiteral(), lua.SyntaxKind.EqualityOperator), lua.createBlock([
106
106
  ...initializerPrecedingStatements,
107
107
  lua.createAssignmentStatement(identifier, initializer),
@@ -124,7 +124,7 @@ function transformBindingVariableDeclaration(context, bindingPattern, initialize
124
124
  if ((0, multi_1.isMultiReturnCall)(context, initializer)) {
125
125
  expression = (0, lua_ast_1.wrapInTable)(expression);
126
126
  }
127
- const [moveStatements, movedExpr] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, expression_list_1.moveToPrecedingTemp)(context, expression, initializer));
127
+ const { precedingStatements: moveStatements, result: movedExpr } = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, expression_list_1.moveToPrecedingTemp)(context, expression, initializer));
128
128
  statements.push(...moveStatements);
129
129
  table = movedExpr;
130
130
  }
@@ -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
@@ -7,7 +7,7 @@ export interface TranspiledFile {
7
7
  declaration?: string;
8
8
  declarationMap?: string;
9
9
  }
10
- export declare function createEmitOutputCollector(): {
10
+ export declare function createEmitOutputCollector(luaExtension?: string): {
11
11
  writeFile: ts.WriteFileCallback;
12
12
  files: TranspiledFile[];
13
13
  };
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createEmitOutputCollector = void 0;
4
4
  const utils_1 = require("../utils");
5
- function createEmitOutputCollector() {
5
+ function createEmitOutputCollector(luaExtension = ".lua") {
6
6
  const files = [];
7
7
  const writeFile = (fileName, data, _bom, _onError, sourceFiles = []) => {
8
8
  let file = files.find(f => (0, utils_1.intersection)(f.sourceFiles, sourceFiles).length > 0);
@@ -13,10 +13,10 @@ function createEmitOutputCollector() {
13
13
  else {
14
14
  file.sourceFiles = (0, utils_1.union)(file.sourceFiles, sourceFiles);
15
15
  }
16
- if (fileName.endsWith(".lua")) {
16
+ if (fileName.endsWith(luaExtension)) {
17
17
  file.lua = data;
18
18
  }
19
- else if (fileName.endsWith(".lua.map")) {
19
+ else if (fileName.endsWith(`${luaExtension}.map`)) {
20
20
  file.luaSourceMap = data;
21
21
  }
22
22
  else if (fileName.endsWith(".js")) {
@@ -15,6 +15,7 @@ const resolver = resolve.ResolverFactory.createResolver({
15
15
  enforceExtension: true,
16
16
  fileSystem: { ...new resolve.CachedInputFileSystem(fs) },
17
17
  useSyncFileSystemCalls: true,
18
+ conditionNames: ["require", "node", "tstl", "default"],
18
19
  symlinks: false, // Do not resolve symlinks to their original paths (that breaks node_modules detection)
19
20
  });
20
21
  class ResolutionContext {
@@ -40,8 +41,8 @@ class ResolutionContext {
40
41
  // Remove @NoResolution prefix if not building in library mode
41
42
  if (!isBuildModeLibrary(this.program)) {
42
43
  const path = required.requirePath.replace("@NoResolution:", "");
43
- replaceRequireInCode(file, required, path);
44
- replaceRequireInSourceMap(file, required, path);
44
+ replaceRequireInCode(file, required, path, this.options.extension);
45
+ replaceRequireInSourceMap(file, required, path, this.options.extension);
45
46
  }
46
47
  // Skip
47
48
  continue;
@@ -72,8 +73,8 @@ class ResolutionContext {
72
73
  // Figure out resolved require path and dependency output path
73
74
  if (shouldRewriteRequires(dependencyPath, this.program)) {
74
75
  const resolvedRequire = (0, transpiler_1.getEmitPathRelativeToOutDir)(dependencyPath, this.program);
75
- replaceRequireInCode(file, required, resolvedRequire);
76
- replaceRequireInSourceMap(file, required, resolvedRequire);
76
+ replaceRequireInCode(file, required, resolvedRequire, this.options.extension);
77
+ replaceRequireInSourceMap(file, required, resolvedRequire, this.options.extension);
77
78
  }
78
79
  }
79
80
  processDependency(dependencyPath) {
@@ -96,8 +97,8 @@ class ResolutionContext {
96
97
  }
97
98
  couldNotResolveImport(required, file) {
98
99
  const fallbackRequire = fallbackResolve(required, (0, transpiler_1.getSourceDir)(this.program), path.dirname(file.fileName));
99
- replaceRequireInCode(file, required, fallbackRequire);
100
- replaceRequireInSourceMap(file, required, fallbackRequire);
100
+ replaceRequireInCode(file, required, fallbackRequire, this.options.extension);
101
+ replaceRequireInSourceMap(file, required, fallbackRequire, this.options.extension);
101
102
  this.diagnostics.push((0, diagnostics_1.couldNotResolveRequire)(required.requirePath, path.relative((0, transpiler_1.getProjectRoot)(this.program), file.fileName)));
102
103
  }
103
104
  resolveDependencyPath(requiringFile, dependency) {
@@ -263,19 +264,27 @@ function shouldIncludeDependency(resolvedDependency, program) {
263
264
  function isBuildModeLibrary(program) {
264
265
  return program.getCompilerOptions().buildMode === CompilerOptions_1.BuildMode.Library;
265
266
  }
266
- function replaceRequireInCode(file, originalRequire, newRequire) {
267
- const requirePath = (0, utils_1.formatPathToLuaPath)(newRequire.replace(".lua", ""));
267
+ function replaceRequireInCode(file, originalRequire, newRequire, extension) {
268
+ const requirePath = requirePathForFile(newRequire, extension);
268
269
  file.code = file.code =
269
270
  file.code.substring(0, originalRequire.from) +
270
271
  `require("${requirePath}")` +
271
272
  file.code.substring(originalRequire.to + 1);
272
273
  }
273
- function replaceRequireInSourceMap(file, originalRequire, newRequire) {
274
- const requirePath = (0, utils_1.formatPathToLuaPath)(newRequire.replace(".lua", ""));
274
+ function replaceRequireInSourceMap(file, originalRequire, newRequire, extension) {
275
+ const requirePath = requirePathForFile(newRequire, extension);
275
276
  if (file.sourceMapNode) {
276
277
  replaceInSourceMap(file.sourceMapNode, file.sourceMapNode, `"${originalRequire.requirePath}"`, `"${requirePath}"`);
277
278
  }
278
279
  }
280
+ function requirePathForFile(filePath, extension = ".lua") {
281
+ if (filePath.endsWith(extension)) {
282
+ return (0, utils_1.formatPathToLuaPath)(filePath.substring(0, filePath.length - extension.length));
283
+ }
284
+ else {
285
+ return (0, utils_1.formatPathToLuaPath)(filePath);
286
+ }
287
+ }
279
288
  function replaceInSourceMap(node, parent, require, resolvedRequire) {
280
289
  if ((!node.children || node.children.length === 0) && node.toString() === require) {
281
290
  parent.children = [new source_map_1.SourceNode(node.line, node.column, node.source, [resolvedRequire])];
@@ -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.13.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/",