typescript-to-lua 1.1.0 → 1.3.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 (141) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/LuaAST.d.ts +1 -0
  3. package/dist/LuaAST.js +10 -2
  4. package/dist/LuaLib.d.ts +3 -3
  5. package/dist/LuaLib.js +5 -5
  6. package/dist/LuaPrinter.d.ts +11 -4
  7. package/dist/LuaPrinter.js +58 -15
  8. package/dist/cli/parse.d.ts +1 -1
  9. package/dist/cli/parse.js +14 -0
  10. package/dist/lualib/ArrayFlat.lua +1 -1
  11. package/dist/lualib/ArrayFlatMap.lua +1 -1
  12. package/dist/lualib/ArrayIsArray.lua +1 -1
  13. package/dist/lualib/ArrayReduce.lua +7 -1
  14. package/dist/lualib/ArrayReduceRight.lua +7 -1
  15. package/dist/lualib/ArraySetLength.lua +1 -1
  16. package/dist/lualib/ArraySplice.lua +5 -5
  17. package/dist/lualib/Await.lua +21 -13
  18. package/dist/lualib/CloneDescriptor.lua +7 -7
  19. package/dist/lualib/Decorate.lua +1 -1
  20. package/dist/lualib/DelegatedYield.lua +1 -3
  21. package/dist/lualib/Delete.lua +6 -6
  22. package/dist/lualib/Error.lua +47 -44
  23. package/dist/lualib/Generator.lua +1 -5
  24. package/dist/lualib/InstanceOf.lua +1 -1
  25. package/dist/lualib/InstanceOfObject.lua +1 -1
  26. package/dist/lualib/Map.lua +130 -134
  27. package/dist/lualib/Number.lua +1 -1
  28. package/dist/lualib/NumberIsFinite.lua +1 -1
  29. package/dist/lualib/NumberToString.lua +3 -5
  30. package/dist/lualib/ObjectDefineProperty.lua +40 -8
  31. package/dist/lualib/ParseFloat.lua +9 -5
  32. package/dist/lualib/ParseInt.lua +15 -3
  33. package/dist/lualib/Promise.lua +28 -24
  34. package/dist/lualib/Set.lua +119 -123
  35. package/dist/lualib/SetDescriptor.lua +7 -1
  36. package/dist/lualib/SourceMapTraceBack.lua +1 -1
  37. package/dist/lualib/SparseArrayNew.lua +5 -0
  38. package/dist/lualib/SparseArrayPush.lua +9 -0
  39. package/dist/lualib/SparseArraySpread.lua +4 -0
  40. package/dist/lualib/StringAccess.lua +1 -1
  41. package/dist/lualib/StringCharCodeAt.lua +1 -1
  42. package/dist/lualib/StringEndsWith.lua +2 -2
  43. package/dist/lualib/StringPadEnd.lua +2 -2
  44. package/dist/lualib/StringPadStart.lua +2 -2
  45. package/dist/lualib/StringReplace.lua +7 -1
  46. package/dist/lualib/StringSlice.lua +2 -2
  47. package/dist/lualib/StringSplit.lua +3 -3
  48. package/dist/lualib/StringStartsWith.lua +1 -1
  49. package/dist/lualib/StringSubstr.lua +1 -1
  50. package/dist/lualib/StringSubstring.lua +2 -2
  51. package/dist/lualib/Symbol.lua +3 -5
  52. package/dist/lualib/WeakMap.lua +40 -42
  53. package/dist/lualib/WeakSet.lua +36 -38
  54. package/dist/lualib/lualib_bundle.lua +795 -735
  55. package/dist/transformation/builtins/array.js +1 -2
  56. package/dist/transformation/builtins/function.js +6 -4
  57. package/dist/transformation/builtins/index.d.ts +1 -1
  58. package/dist/transformation/builtins/index.js +41 -6
  59. package/dist/transformation/builtins/object.d.ts +2 -1
  60. package/dist/transformation/builtins/object.js +1 -2
  61. package/dist/transformation/builtins/string.js +1 -2
  62. package/dist/transformation/context/context.d.ts +12 -0
  63. package/dist/transformation/context/context.js +102 -3
  64. package/dist/transformation/utils/diagnostics.d.ts +9 -6
  65. package/dist/transformation/utils/diagnostics.js +4 -3
  66. package/dist/transformation/utils/export.d.ts +3 -2
  67. package/dist/transformation/utils/export.js +10 -3
  68. package/dist/transformation/utils/language-extensions.d.ts +2 -0
  69. package/dist/transformation/utils/language-extensions.js +7 -1
  70. package/dist/transformation/utils/lua-ast.d.ts +0 -1
  71. package/dist/transformation/utils/lua-ast.js +14 -23
  72. package/dist/transformation/utils/preceding-statements.d.ts +3 -0
  73. package/dist/transformation/utils/preceding-statements.js +11 -0
  74. package/dist/transformation/utils/safe-names.d.ts +4 -2
  75. package/dist/transformation/utils/safe-names.js +11 -5
  76. package/dist/transformation/utils/scope.d.ts +3 -1
  77. package/dist/transformation/utils/scope.js +9 -1
  78. package/dist/transformation/utils/typescript/index.d.ts +1 -0
  79. package/dist/transformation/utils/typescript/index.js +16 -1
  80. package/dist/transformation/utils/typescript/types.d.ts +3 -1
  81. package/dist/transformation/utils/typescript/types.js +40 -13
  82. package/dist/transformation/visitors/access.d.ts +3 -0
  83. package/dist/transformation/visitors/access.js +63 -36
  84. package/dist/transformation/visitors/binary-expression/assignments.d.ts +3 -2
  85. package/dist/transformation/visitors/binary-expression/assignments.js +66 -57
  86. package/dist/transformation/visitors/binary-expression/compound.d.ts +5 -4
  87. package/dist/transformation/visitors/binary-expression/compound.js +66 -68
  88. package/dist/transformation/visitors/binary-expression/destructuring-assignments.d.ts +2 -2
  89. package/dist/transformation/visitors/binary-expression/destructuring-assignments.js +54 -25
  90. package/dist/transformation/visitors/binary-expression/index.d.ts +3 -1
  91. package/dist/transformation/visitors/binary-expression/index.js +65 -23
  92. package/dist/transformation/visitors/call.d.ts +3 -2
  93. package/dist/transformation/visitors/call.js +95 -141
  94. package/dist/transformation/visitors/class/index.js +13 -9
  95. package/dist/transformation/visitors/class/new.js +4 -6
  96. package/dist/transformation/visitors/conditional.js +30 -37
  97. package/dist/transformation/visitors/delete.js +4 -0
  98. package/dist/transformation/visitors/errors.js +11 -9
  99. package/dist/transformation/visitors/expression-list.d.ts +7 -0
  100. package/dist/transformation/visitors/expression-list.js +120 -0
  101. package/dist/transformation/visitors/expression-statement.d.ts +3 -1
  102. package/dist/transformation/visitors/expression-statement.js +21 -19
  103. package/dist/transformation/visitors/function.d.ts +2 -0
  104. package/dist/transformation/visitors/function.js +63 -13
  105. package/dist/transformation/visitors/identifier.js +5 -0
  106. package/dist/transformation/visitors/language-extensions/index.d.ts +4 -0
  107. package/dist/transformation/visitors/language-extensions/index.js +17 -0
  108. package/dist/transformation/visitors/language-extensions/operators.d.ts +1 -1
  109. package/dist/transformation/visitors/language-extensions/operators.js +7 -2
  110. package/dist/transformation/visitors/language-extensions/pairsIterable.d.ts +5 -0
  111. package/dist/transformation/visitors/language-extensions/pairsIterable.js +53 -0
  112. package/dist/transformation/visitors/language-extensions/table.d.ts +1 -8
  113. package/dist/transformation/visitors/language-extensions/table.js +55 -53
  114. package/dist/transformation/visitors/literal.js +69 -16
  115. package/dist/transformation/visitors/loops/do-while.js +34 -8
  116. package/dist/transformation/visitors/loops/for-of.js +4 -0
  117. package/dist/transformation/visitors/loops/for.js +25 -5
  118. package/dist/transformation/visitors/loops/utils.d.ts +1 -0
  119. package/dist/transformation/visitors/loops/utils.js +19 -3
  120. package/dist/transformation/visitors/modules/export.js +4 -5
  121. package/dist/transformation/visitors/namespace.js +1 -1
  122. package/dist/transformation/visitors/optional-chaining.d.ts +16 -0
  123. package/dist/transformation/visitors/optional-chaining.js +172 -0
  124. package/dist/transformation/visitors/sourceFile.js +4 -1
  125. package/dist/transformation/visitors/spread.js +14 -7
  126. package/dist/transformation/visitors/switch.js +29 -9
  127. package/dist/transformation/visitors/template.js +5 -2
  128. package/dist/transformation/visitors/typeof.js +3 -1
  129. package/dist/transformation/visitors/variable-declaration.js +37 -8
  130. package/dist/transformation/visitors/void.d.ts +1 -4
  131. package/dist/transformation/visitors/void.js +7 -12
  132. package/dist/transpilation/resolve.js +1 -1
  133. package/dist/transpilation/transformers.js +4 -1
  134. package/dist/transpilation/utils.js +2 -1
  135. package/language-extensions/index.d.ts +11 -1
  136. package/package.json +5 -5
  137. package/dist/lualib/OptionalChainAccess.lua +0 -6
  138. package/dist/lualib/OptionalFunctionCall.lua +0 -6
  139. package/dist/lualib/OptionalMethodCall.lua +0 -11
  140. package/dist/transformation/utils/transform.d.ts +0 -8
  141. package/dist/transformation/utils/transform.js +0 -14
@@ -11,7 +11,7 @@ const safe_names_1 = require("../utils/safe-names");
11
11
  const symbols_1 = require("../utils/symbols");
12
12
  const typescript_1 = require("../utils/typescript");
13
13
  const function_1 = require("./function");
14
- const call_1 = require("./call");
14
+ const expression_list_1 = require("./expression-list");
15
15
  const multi_1 = require("./language-extensions/multi");
16
16
  // TODO: Move to object-literal.ts?
17
17
  function transformPropertyName(context, node) {
@@ -61,13 +61,27 @@ const transformObjectLiteralExpression = (expression, context) => {
61
61
  context.diagnostics.push(...violations.map(e => (0, diagnostics_1.invalidMultiFunctionUse)(e)));
62
62
  return lua.createNilLiteral(expression);
63
63
  }
64
- let properties = [];
65
- const tableExpressions = [];
66
- for (const element of expression.properties) {
64
+ const properties = [];
65
+ const initializers = [];
66
+ const keyPrecedingStatements = [];
67
+ const valuePrecedingStatements = [];
68
+ let lastPrecedingStatementsIndex = -1;
69
+ for (let i = 0; i < expression.properties.length; ++i) {
70
+ const element = expression.properties[i];
71
+ // Transform key and cache preceding statements
72
+ context.pushPrecedingStatements();
67
73
  const name = element.name ? transformPropertyName(context, element.name) : undefined;
74
+ let precedingStatements = context.popPrecedingStatements();
75
+ keyPrecedingStatements.push(precedingStatements);
76
+ if (precedingStatements.length > 0) {
77
+ lastPrecedingStatementsIndex = i;
78
+ }
79
+ // Transform value and cache preceding statements
80
+ context.pushPrecedingStatements();
68
81
  if (ts.isPropertyAssignment(element)) {
69
82
  const expression = context.transformExpression(element.initializer);
70
83
  properties.push(lua.createTableFieldExpression(expression, name, element));
84
+ initializers.push(element.initializer);
71
85
  }
72
86
  else if (ts.isShorthandPropertyAssignment(element)) {
73
87
  const valueSymbol = context.checker.getShorthandAssignmentValueSymbol(element);
@@ -76,19 +90,14 @@ const transformObjectLiteralExpression = (expression, context) => {
76
90
  }
77
91
  const identifier = createShorthandIdentifier(context, valueSymbol, element.name);
78
92
  properties.push(lua.createTableFieldExpression(identifier, name, element));
93
+ initializers.push(element);
79
94
  }
80
95
  else if (ts.isMethodDeclaration(element)) {
81
96
  const expression = (0, function_1.transformFunctionLikeDeclaration)(element, context);
82
97
  properties.push(lua.createTableFieldExpression(expression, name, element));
98
+ initializers.push(element);
83
99
  }
84
100
  else if (ts.isSpreadAssignment(element)) {
85
- // Create a table for preceding properties to preserve property order
86
- // { x: 0, ...{ y: 2 }, y: 1, z: 2 } --> __TS__ObjectAssign({x = 0}, {y = 2}, {y = 1, z = 2})
87
- if (properties.length > 0) {
88
- const tableExpression = lua.createTableExpression(properties, expression);
89
- tableExpressions.push(tableExpression);
90
- properties = [];
91
- }
92
101
  const type = context.checker.getTypeAtLocation(element.expression);
93
102
  let tableExpression;
94
103
  if ((0, typescript_1.isArrayType)(context, type)) {
@@ -97,7 +106,8 @@ const transformObjectLiteralExpression = (expression, context) => {
97
106
  else {
98
107
  tableExpression = context.transformExpression(element.expression);
99
108
  }
100
- tableExpressions.push(tableExpression);
109
+ properties.push(tableExpression);
110
+ initializers.push(element.expression);
101
111
  }
102
112
  else if (ts.isAccessor(element)) {
103
113
  context.diagnostics.push((0, diagnostics_1.unsupportedAccessorInObjectLiteral)(element));
@@ -105,13 +115,56 @@ const transformObjectLiteralExpression = (expression, context) => {
105
115
  else {
106
116
  (0, utils_1.assertNever)(element);
107
117
  }
118
+ precedingStatements = context.popPrecedingStatements();
119
+ valuePrecedingStatements.push(precedingStatements);
120
+ if (precedingStatements.length > 0) {
121
+ lastPrecedingStatementsIndex = i;
122
+ }
123
+ }
124
+ // Expressions referenced before others that produced preceding statements need to be cached in temps
125
+ if (lastPrecedingStatementsIndex >= 0) {
126
+ for (let i = 0; i < properties.length; ++i) {
127
+ const property = properties[i];
128
+ // Bubble up key's preceding statements
129
+ context.addPrecedingStatements(keyPrecedingStatements[i]);
130
+ // Cache computed property name in temp if before the last expression that generated preceding statements
131
+ if (i <= lastPrecedingStatementsIndex && lua.isTableFieldExpression(property) && property.key) {
132
+ property.key = (0, expression_list_1.moveToPrecedingTemp)(context, property.key, expression.properties[i].name);
133
+ }
134
+ // Bubble up value's preceding statements
135
+ context.addPrecedingStatements(valuePrecedingStatements[i]);
136
+ // Cache property value in temp if before the last expression that generated preceding statements
137
+ if (i < lastPrecedingStatementsIndex) {
138
+ if (lua.isTableFieldExpression(property)) {
139
+ property.value = (0, expression_list_1.moveToPrecedingTemp)(context, property.value, initializers[i]);
140
+ }
141
+ else {
142
+ properties[i] = (0, expression_list_1.moveToPrecedingTemp)(context, property, initializers[i]);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ // Sort into field expressions and tables to pass into __TS__ObjectAssign
148
+ let fields = [];
149
+ const tableExpressions = [];
150
+ for (const property of properties) {
151
+ if (lua.isTableFieldExpression(property)) {
152
+ fields.push(property);
153
+ }
154
+ else {
155
+ if (fields.length > 0) {
156
+ tableExpressions.push(lua.createTableExpression(fields));
157
+ }
158
+ tableExpressions.push(property);
159
+ fields = [];
160
+ }
108
161
  }
109
162
  if (tableExpressions.length === 0) {
110
- return lua.createTableExpression(properties, expression);
163
+ return lua.createTableExpression(fields, expression);
111
164
  }
112
165
  else {
113
- if (properties.length > 0) {
114
- const tableExpression = lua.createTableExpression(properties, expression);
166
+ if (fields.length > 0) {
167
+ const tableExpression = lua.createTableExpression(fields, expression);
115
168
  tableExpressions.push(tableExpression);
116
169
  }
117
170
  if (tableExpressions[0].kind !== lua.SyntaxKind.TableExpression) {
@@ -122,7 +175,7 @@ const transformObjectLiteralExpression = (expression, context) => {
122
175
  };
123
176
  const transformArrayLiteralExpression = (expression, context) => {
124
177
  const filteredElements = expression.elements.map(e => ts.isOmittedExpression(e) ? ts.factory.createIdentifier("undefined") : e);
125
- const values = (0, call_1.flattenSpreadExpressions)(context, filteredElements).map(e => lua.createTableFieldExpression(e));
178
+ const values = (0, expression_list_1.transformExpressionList)(context, filteredElements).map(e => lua.createTableFieldExpression(e));
126
179
  return lua.createTableExpression(values, expression);
127
180
  };
128
181
  exports.literalVisitors = {
@@ -2,19 +2,45 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformDoStatement = exports.transformWhileStatement = void 0;
4
4
  const lua = require("../../../LuaAST");
5
+ const preceding_statements_1 = require("../../utils/preceding-statements");
5
6
  const utils_1 = require("./utils");
6
- const transformWhileStatement = (statement, context) => lua.createWhileStatement(lua.createBlock((0, utils_1.transformLoopBody)(context, statement)), context.transformExpression(statement.expression), statement);
7
+ const transformWhileStatement = (statement, context) => {
8
+ const body = (0, utils_1.transformLoopBody)(context, statement);
9
+ let [conditionPrecedingStatements, condition] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(statement.expression));
10
+ // If condition has preceding statements, ensure they are executed every iteration by using the form:
11
+ //
12
+ // while true do
13
+ // condition's preceding statements
14
+ // if not condition then
15
+ // break
16
+ // end
17
+ // ...
18
+ // end
19
+ if (conditionPrecedingStatements.length > 0) {
20
+ conditionPrecedingStatements.push(lua.createIfStatement((0, utils_1.invertCondition)(condition), lua.createBlock([lua.createBreakStatement()]), undefined, statement.expression));
21
+ body.unshift(...conditionPrecedingStatements);
22
+ condition = lua.createBooleanLiteral(true);
23
+ }
24
+ return lua.createWhileStatement(lua.createBlock(body), condition, statement);
25
+ };
7
26
  exports.transformWhileStatement = transformWhileStatement;
8
27
  const transformDoStatement = (statement, context) => {
9
28
  const body = lua.createDoStatement((0, utils_1.transformLoopBody)(context, statement));
10
- let condition = context.transformExpression(statement.expression);
11
- if (lua.isUnaryExpression(condition) && condition.operator === lua.SyntaxKind.NotOperator) {
12
- condition = condition.operand;
13
- }
14
- else {
15
- condition = lua.createUnaryExpression(condition, lua.SyntaxKind.NotOperator);
29
+ let [conditionPrecedingStatements, condition] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, utils_1.invertCondition)(context.transformExpression(statement.expression)));
30
+ // If condition has preceding statements, ensure they are executed every iteration by using the form:
31
+ //
32
+ // repeat
33
+ // ...
34
+ // condition's preceding statements
35
+ // if condition then
36
+ // break
37
+ // end
38
+ // end
39
+ if (conditionPrecedingStatements.length > 0) {
40
+ conditionPrecedingStatements.push(lua.createIfStatement(condition, lua.createBlock([lua.createBreakStatement()]), undefined, statement.expression));
41
+ condition = lua.createBooleanLiteral(false);
16
42
  }
17
- return lua.createRepeatStatement(lua.createBlock([body]), condition, statement);
43
+ return lua.createRepeatStatement(lua.createBlock([body, ...conditionPrecedingStatements]), condition, statement);
18
44
  };
19
45
  exports.transformDoStatement = transformDoStatement;
20
46
  //# sourceMappingURL=do-while.js.map
@@ -8,6 +8,7 @@ const diagnostics_1 = require("../../utils/diagnostics");
8
8
  const lualib_1 = require("../../utils/lualib");
9
9
  const typescript_1 = require("../../utils/typescript");
10
10
  const iterable_1 = require("../language-extensions/iterable");
11
+ const pairsIterable_1 = require("../language-extensions/pairsIterable");
11
12
  const range_1 = require("../language-extensions/range");
12
13
  const utils_1 = require("./utils");
13
14
  function transformForOfArrayStatement(context, statement, block) {
@@ -33,6 +34,9 @@ const transformForOfStatement = (node, context) => {
33
34
  else if ((0, iterable_1.isIterableExpression)(context, node.expression)) {
34
35
  return (0, iterable_1.transformForOfIterableStatement)(context, node, body);
35
36
  }
37
+ else if ((0, pairsIterable_1.isPairsIterableExpression)(context, node.expression)) {
38
+ return (0, pairsIterable_1.transformForOfPairsIterableStatement)(context, node, body);
39
+ }
36
40
  else if ((0, annotations_1.isLuaIteratorType)(context, node.expression)) {
37
41
  context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node.expression, annotations_1.AnnotationKind.LuaIterator));
38
42
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformForStatement = void 0;
4
4
  const ts = require("typescript");
5
5
  const lua = require("../../../LuaAST");
6
+ const preceding_statements_1 = require("../../utils/preceding-statements");
6
7
  const variable_declaration_1 = require("../variable-declaration");
7
8
  const utils_1 = require("./utils");
8
9
  const transformForStatement = (statement, context) => {
@@ -17,16 +18,35 @@ const transformForStatement = (statement, context) => {
17
18
  result.push(...context.transformStatements(ts.factory.createExpressionStatement(statement.initializer)));
18
19
  }
19
20
  }
20
- const condition = statement.condition
21
- ? context.transformExpression(statement.condition)
22
- : lua.createBooleanLiteral(true);
23
- // Add body
24
21
  const body = (0, utils_1.transformLoopBody)(context, statement);
22
+ let condition;
23
+ if (statement.condition) {
24
+ let conditionPrecedingStatements;
25
+ const tsCondition = statement.condition;
26
+ [conditionPrecedingStatements, condition] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(tsCondition));
27
+ // If condition has preceding statements, ensure they are executed every iteration by using the form:
28
+ //
29
+ // while true do
30
+ // condition's preceding statements
31
+ // if not condition then
32
+ // break
33
+ // end
34
+ // ...
35
+ // end
36
+ if (conditionPrecedingStatements.length > 0) {
37
+ conditionPrecedingStatements.push(lua.createIfStatement((0, utils_1.invertCondition)(condition), lua.createBlock([lua.createBreakStatement()]), undefined, statement.condition));
38
+ body.unshift(...conditionPrecedingStatements);
39
+ condition = lua.createBooleanLiteral(true);
40
+ }
41
+ }
42
+ else {
43
+ condition = lua.createBooleanLiteral(true);
44
+ }
25
45
  if (statement.incrementor) {
26
46
  body.push(...context.transformStatements(ts.factory.createExpressionStatement(statement.incrementor)));
27
47
  }
28
48
  // while (condition) do ... end
29
- result.push(lua.createWhileStatement(lua.createBlock(body), condition));
49
+ result.push(lua.createWhileStatement(lua.createBlock(body), condition, statement));
30
50
  return lua.createDoStatement(result, statement);
31
51
  };
32
52
  exports.transformForStatement = transformForStatement;
@@ -4,3 +4,4 @@ import { TransformationContext } from "../../context";
4
4
  export declare function transformLoopBody(context: TransformationContext, loop: ts.WhileStatement | ts.DoStatement | ts.ForStatement | ts.ForOfStatement | ts.ForInOrOfStatement): lua.Statement[];
5
5
  export declare function getVariableDeclarationBinding(context: TransformationContext, node: ts.VariableDeclarationList): ts.BindingName;
6
6
  export declare function transformForInitializer(context: TransformationContext, initializer: ts.ForInitializer, block: lua.Block): lua.Identifier;
7
+ export declare function invertCondition(expression: lua.Expression): lua.Expression;
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.transformForInitializer = exports.getVariableDeclarationBinding = exports.transformLoopBody = void 0;
3
+ exports.invertCondition = exports.transformForInitializer = exports.getVariableDeclarationBinding = exports.transformLoopBody = void 0;
4
4
  const ts = require("typescript");
5
5
  const lua = require("../../../LuaAST");
6
+ const preceding_statements_1 = require("../../utils/preceding-statements");
6
7
  const scope_1 = require("../../utils/scope");
7
8
  const typescript_1 = require("../../utils/typescript");
8
9
  const assignments_1 = require("../binary-expression/assignments");
@@ -34,24 +35,39 @@ function getVariableDeclarationBinding(context, node) {
34
35
  exports.getVariableDeclarationBinding = getVariableDeclarationBinding;
35
36
  function transformForInitializer(context, initializer, block) {
36
37
  const valueVariable = lua.createIdentifier("____value");
38
+ (0, scope_1.pushScope)(context, scope_1.ScopeType.LoopInitializer);
37
39
  if (ts.isVariableDeclarationList(initializer)) {
38
40
  // Declaration of new variable
39
41
  const binding = getVariableDeclarationBinding(context, initializer);
40
42
  if (ts.isArrayBindingPattern(binding) || ts.isObjectBindingPattern(binding)) {
41
- block.statements.unshift(...(0, variable_declaration_1.transformBindingPattern)(context, binding, valueVariable));
43
+ const [precedingStatements, bindings] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, variable_declaration_1.transformBindingPattern)(context, binding, valueVariable));
44
+ block.statements.unshift(...precedingStatements, ...bindings);
42
45
  }
43
46
  else {
44
47
  // Single variable declared in for loop
48
+ (0, scope_1.popScope)(context);
45
49
  return (0, identifier_1.transformIdentifier)(context, binding);
46
50
  }
47
51
  }
48
52
  else {
49
53
  // Assignment to existing variable(s)
50
54
  block.statements.unshift(...((0, typescript_1.isAssignmentPattern)(initializer)
51
- ? (0, destructuring_assignments_1.transformAssignmentPattern)(context, initializer, valueVariable)
55
+ ? (0, destructuring_assignments_1.transformAssignmentPattern)(context, initializer, valueVariable, false)
52
56
  : (0, assignments_1.transformAssignment)(context, initializer, valueVariable)));
53
57
  }
58
+ (0, scope_1.popScope)(context);
54
59
  return valueVariable;
55
60
  }
56
61
  exports.transformForInitializer = transformForInitializer;
62
+ function invertCondition(expression) {
63
+ if (lua.isUnaryExpression(expression) && expression.operator === lua.SyntaxKind.NotOperator) {
64
+ return expression.operand;
65
+ }
66
+ else {
67
+ const notExpression = lua.createUnaryExpression(expression, lua.SyntaxKind.NotOperator);
68
+ lua.setNodePosition(notExpression, lua.getOriginalPos(expression));
69
+ return notExpression;
70
+ }
71
+ }
72
+ exports.invertCondition = invertCondition;
57
73
  //# sourceMappingURL=utils.js.map
@@ -72,15 +72,14 @@ function transformExportSpecifier(context, node) {
72
72
  const exportedIdentifier = node.propertyName ? node.propertyName : node.name;
73
73
  const exportedExpression = (0, literal_1.createShorthandIdentifier)(context, exportedSymbol, exportedIdentifier);
74
74
  const isDefault = isDefaultExportSpecifier(node);
75
- const identifierToExport = isDefault
76
- ? (0, export_1.createDefaultExportIdentifier)(node)
77
- : (0, identifier_1.transformIdentifier)(context, node.name);
78
- const exportAssignmentLeftHandSide = (0, export_1.createExportedIdentifier)(context, identifierToExport);
75
+ const exportAssignmentLeftHandSide = isDefault
76
+ ? (0, export_1.createDefaultExportExpression)(node)
77
+ : (0, export_1.createExportedIdentifier)(context, (0, identifier_1.transformIdentifier)(context, node.name));
79
78
  return lua.createAssignmentStatement(exportAssignmentLeftHandSide, exportedExpression, node);
80
79
  }
81
80
  function transformExportSpecifiersFrom(context, statement, moduleSpecifier, exportSpecifiers) {
82
81
  // First transpile as import clause
83
- const importClause = ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports(exportSpecifiers.map(s => ts.factory.createImportSpecifier(s.propertyName, s.name))));
82
+ const importClause = ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports(exportSpecifiers.map(s => ts.factory.createImportSpecifier(statement.isTypeOnly, s.propertyName, s.name))));
84
83
  const importDeclaration = ts.factory.createImportDeclaration(statement.decorators, statement.modifiers, importClause, moduleSpecifier);
85
84
  // Wrap in block to prevent imports from hoisting out of `do` statement
86
85
  const [block] = (0, block_1.transformScopeBlock)(context, ts.factory.createBlock([importDeclaration]), scope_1.ScopeType.Block);
@@ -13,7 +13,7 @@ const symbols_1 = require("../utils/symbols");
13
13
  const identifier_1 = require("./identifier");
14
14
  function createModuleLocalNameIdentifier(context, declaration) {
15
15
  const moduleSymbol = context.checker.getSymbolAtLocation(declaration.name);
16
- if (moduleSymbol !== undefined && (0, safe_names_1.isUnsafeName)(moduleSymbol.name)) {
16
+ if (moduleSymbol !== undefined && (0, safe_names_1.isUnsafeName)(moduleSymbol.name, context.options)) {
17
17
  return lua.createIdentifier((0, safe_names_1.createSafeName)(declaration.name.text), declaration.name, moduleSymbol && (0, symbols_1.getSymbolIdOfSymbol)(context, moduleSymbol), declaration.name.text);
18
18
  }
19
19
  // TODO: Should synthetic name nodes be escaped as well?
@@ -0,0 +1,16 @@
1
+ import * as ts from "typescript";
2
+ import * as lua from "../../LuaAST";
3
+ import { TransformationContext } from "../context";
4
+ export interface ExpressionWithThisValue {
5
+ expression: lua.Expression;
6
+ thisValue?: lua.Expression;
7
+ }
8
+ export declare function captureThisValue(context: TransformationContext, expression: lua.Expression, thisValueCapture: lua.Identifier, tsOriginal: ts.Node): lua.Expression;
9
+ export interface OptionalContinuation {
10
+ contextualCall?: lua.CallExpression;
11
+ }
12
+ export declare function isOptionalContinuation(node: ts.Node): boolean;
13
+ export declare function getOptionalContinuationData(identifier: ts.Identifier): OptionalContinuation | undefined;
14
+ 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 transformOptionalDeleteExpression(context: TransformationContext, node: ts.DeleteExpression, innerExpression: ts.OptionalChain): lua.BooleanLiteral;
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transformOptionalDeleteExpression = exports.transformOptionalChainWithCapture = exports.transformOptionalChain = exports.getOptionalContinuationData = exports.isOptionalContinuation = exports.captureThisValue = void 0;
4
+ const ts = require("typescript");
5
+ const lua = require("../../LuaAST");
6
+ const context_1 = require("../context");
7
+ const utils_1 = require("../../utils");
8
+ const preceding_statements_1 = require("../utils/preceding-statements");
9
+ const access_1 = require("./access");
10
+ const expression_list_1 = require("./expression-list");
11
+ function skipNonNullChains(chain) {
12
+ while (ts.isNonNullChain(chain)) {
13
+ chain = chain.expression;
14
+ }
15
+ return chain;
16
+ }
17
+ function flattenChain(chain) {
18
+ chain = skipNonNullChains(chain);
19
+ const links = [chain];
20
+ while (!chain.questionDotToken && !ts.isTaggedTemplateExpression(chain)) {
21
+ const nextLink = chain.expression;
22
+ (0, utils_1.assert)(ts.isOptionalChain(nextLink));
23
+ chain = skipNonNullChains(nextLink);
24
+ links.unshift(chain);
25
+ }
26
+ return { expression: chain.expression, chain: links };
27
+ }
28
+ function transformExpressionWithThisValueCapture(context, node, thisValueCapture) {
29
+ if (ts.isParenthesizedExpression(node)) {
30
+ return transformExpressionWithThisValueCapture(context, node.expression, thisValueCapture);
31
+ }
32
+ if (ts.isPropertyAccessExpression(node)) {
33
+ return (0, access_1.transformPropertyAccessExpressionWithCapture)(context, node, thisValueCapture);
34
+ }
35
+ if (ts.isElementAccessExpression(node)) {
36
+ return (0, access_1.transformElementAccessExpressionWithCapture)(context, node, thisValueCapture);
37
+ }
38
+ return { expression: context.transformExpression(node) };
39
+ }
40
+ // returns thisValueCapture exactly if a temp variable was used.
41
+ function captureThisValue(context, expression, thisValueCapture, tsOriginal) {
42
+ if (!(0, expression_list_1.shouldMoveToTemp)(context, expression, tsOriginal) && !isOptionalContinuation(tsOriginal)) {
43
+ return expression;
44
+ }
45
+ const tempAssignment = lua.createAssignmentStatement(thisValueCapture, expression, tsOriginal);
46
+ context.addPrecedingStatements(tempAssignment);
47
+ return thisValueCapture;
48
+ }
49
+ exports.captureThisValue = captureThisValue;
50
+ const optionalContinuations = new WeakMap();
51
+ // should be translated verbatim to lua
52
+ function createOptionalContinuationIdentifier(text, tsOriginal) {
53
+ const identifier = ts.factory.createIdentifier(text);
54
+ ts.setOriginalNode(identifier, tsOriginal);
55
+ optionalContinuations.set(identifier, {});
56
+ return identifier;
57
+ }
58
+ function isOptionalContinuation(node) {
59
+ return ts.isIdentifier(node) && optionalContinuations.has(node);
60
+ }
61
+ exports.isOptionalContinuation = isOptionalContinuation;
62
+ function getOptionalContinuationData(identifier) {
63
+ return optionalContinuations.get(identifier);
64
+ }
65
+ exports.getOptionalContinuationData = getOptionalContinuationData;
66
+ function transformOptionalChain(context, node) {
67
+ return transformOptionalChainWithCapture(context, node, undefined).expression;
68
+ }
69
+ 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
+ // build temp.b.c.d
75
+ const tsTemp = createOptionalContinuationIdentifier(luaTemp.text, tsLeftExpression);
76
+ let tsRightExpression = tsTemp;
77
+ for (const link of chain) {
78
+ if (ts.isPropertyAccessExpression(link)) {
79
+ tsRightExpression = ts.factory.createPropertyAccessExpression(tsRightExpression, link.name);
80
+ }
81
+ else if (ts.isElementAccessExpression(link)) {
82
+ tsRightExpression = ts.factory.createElementAccessExpression(tsRightExpression, link.argumentExpression);
83
+ }
84
+ else if (ts.isCallExpression(link)) {
85
+ tsRightExpression = ts.factory.createCallExpression(tsRightExpression, undefined, link.arguments);
86
+ }
87
+ else {
88
+ (0, utils_1.assertNever)(link);
89
+ }
90
+ ts.setOriginalNode(tsRightExpression, link);
91
+ }
92
+ if (isDelete) {
93
+ tsRightExpression = ts.factory.createDeleteExpression(tsRightExpression);
94
+ ts.setOriginalNode(tsRightExpression, isDelete);
95
+ }
96
+ // transform right expression first to check if thisValue capture is needed
97
+ // capture and return thisValue if requested from outside
98
+ 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);
106
+ }
107
+ return lua.createAssignmentStatement(luaTemp, result);
108
+ });
109
+ // transform left expression, handle thisValue if needed by rightExpression
110
+ const thisValueCaptureName = context.createTempName("this");
111
+ const leftThisValueTemp = lua.createIdentifier(thisValueCaptureName, undefined, context_1.tempSymbolId);
112
+ 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, () => {
115
+ let result;
116
+ if (rightContextualCall) {
117
+ ({ expression: result, thisValue: capturedThisValue } = transformExpressionWithThisValueCapture(context, tsLeftExpression, leftThisValueTemp));
118
+ }
119
+ else {
120
+ result = context.transformExpression(tsLeftExpression);
121
+ }
122
+ return result;
123
+ });
124
+ // handle context
125
+ if (rightContextualCall) {
126
+ if (capturedThisValue) {
127
+ rightContextualCall.params[0] = capturedThisValue;
128
+ if (capturedThisValue === leftThisValueTemp) {
129
+ context.addPrecedingStatements(lua.createVariableDeclarationStatement(leftThisValueTemp));
130
+ }
131
+ }
132
+ else {
133
+ if (context.isStrict) {
134
+ rightContextualCall.params[0] = lua.createNilLiteral();
135
+ }
136
+ else {
137
+ const identifier = lua.createIdentifier("_G");
138
+ if (rightPrecedingStatements.length === 0) {
139
+ rightContextualCall.params[0] = identifier;
140
+ }
141
+ else {
142
+ const tempContext = context.createTempNameForLuaExpression(identifier);
143
+ rightPrecedingStatements.unshift(lua.createVariableDeclarationStatement(tempContext, identifier));
144
+ rightContextualCall.params[0] = tempContext;
145
+ }
146
+ }
147
+ }
148
+ }
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
+ };
165
+ }
166
+ exports.transformOptionalChainWithCapture = transformOptionalChainWithCapture;
167
+ function transformOptionalDeleteExpression(context, node, innerExpression) {
168
+ transformOptionalChainWithCapture(context, innerExpression, undefined, node);
169
+ return lua.createBooleanLiteral(true, node);
170
+ }
171
+ exports.transformOptionalDeleteExpression = transformOptionalDeleteExpression;
172
+ //# sourceMappingURL=optional-chaining.js.map
@@ -6,6 +6,7 @@ const lua = require("../../LuaAST");
6
6
  const utils_1 = require("../../utils");
7
7
  const lua_ast_1 = require("../utils/lua-ast");
8
8
  const lualib_1 = require("../utils/lualib");
9
+ const preceding_statements_1 = require("../utils/preceding-statements");
9
10
  const scope_1 = require("../utils/scope");
10
11
  const typescript_1 = require("../utils/typescript");
11
12
  const transformSourceFileNode = (node, context) => {
@@ -15,7 +16,9 @@ const transformSourceFileNode = (node, context) => {
15
16
  const [statement] = node.statements;
16
17
  if (statement) {
17
18
  (0, utils_1.assert)(ts.isExpressionStatement(statement));
18
- statements.push(lua.createReturnStatement([context.transformExpression(statement.expression)]));
19
+ const [precedingStatements, expression] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(statement.expression));
20
+ statements.push(...precedingStatements);
21
+ statements.push(lua.createReturnStatement([expression]));
19
22
  }
20
23
  else {
21
24
  const errorCall = lua.createCallExpression(lua.createIdentifier("error"), [
@@ -11,9 +11,15 @@ const typescript_1 = require("../utils/typescript");
11
11
  const multi_1 = require("./language-extensions/multi");
12
12
  const diagnostics_1 = require("../utils/diagnostics");
13
13
  const vararg_1 = require("./language-extensions/vararg");
14
+ function skipOuterExpressionParents(node) {
15
+ while (ts.isOuterExpression(node)) {
16
+ node = node.parent;
17
+ }
18
+ return node;
19
+ }
14
20
  function isOptimizedVarArgSpread(context, symbol, identifier) {
15
21
  var _a;
16
- if (!ts.isSpreadElement(identifier.parent)) {
22
+ if (!ts.isSpreadElement(skipOuterExpressionParents(identifier.parent))) {
17
23
  return false;
18
24
  }
19
25
  // Walk up, stopping at any scope types which could stop optimization
@@ -51,19 +57,20 @@ function isOptimizedVarArgSpread(context, symbol, identifier) {
51
57
  exports.isOptimizedVarArgSpread = isOptimizedVarArgSpread;
52
58
  // TODO: Currently it's also used as an array member
53
59
  const transformSpreadElement = (node, context) => {
54
- if (ts.isIdentifier(node.expression)) {
55
- if ((0, annotations_1.isVarargType)(context, node.expression)) {
60
+ const tsInnerExpression = ts.skipOuterExpressions(node.expression);
61
+ if (ts.isIdentifier(tsInnerExpression)) {
62
+ if ((0, annotations_1.isVarargType)(context, tsInnerExpression)) {
56
63
  context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node, annotations_1.AnnotationKind.Vararg));
57
64
  }
58
- const symbol = context.checker.getSymbolAtLocation(node.expression);
59
- if (symbol && isOptimizedVarArgSpread(context, symbol, node.expression)) {
65
+ const symbol = context.checker.getSymbolAtLocation(tsInnerExpression);
66
+ if (symbol && isOptimizedVarArgSpread(context, symbol, tsInnerExpression)) {
60
67
  return lua.createDotsLiteral(node);
61
68
  }
62
69
  }
63
70
  const innerExpression = context.transformExpression(node.expression);
64
- if ((0, multi_1.isMultiReturnCall)(context, node.expression))
71
+ if ((0, multi_1.isMultiReturnCall)(context, tsInnerExpression))
65
72
  return innerExpression;
66
- const type = context.checker.getTypeAtLocation(node.expression);
73
+ const type = context.checker.getTypeAtLocation(node.expression); // not ts-inner expression, in case of casts
67
74
  if ((0, typescript_1.isArrayType)(context, type)) {
68
75
  return (0, lua_ast_1.createUnpackCall)(context, innerExpression, node);
69
76
  }