typescript-to-lua 1.2.0 → 1.3.3

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 (51) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/LuaLib.d.ts +1 -0
  3. package/dist/LuaLib.js +2 -1
  4. package/dist/LuaPrinter.js +4 -4
  5. package/dist/lualib/Await.lua +7 -3
  6. package/dist/lualib/CloneDescriptor.lua +6 -6
  7. package/dist/lualib/MathSign.lua +8 -0
  8. package/dist/lualib/Promise.lua +10 -2
  9. package/dist/lualib/lualib_bundle.lua +226 -205
  10. package/dist/transformation/builtins/function.js +5 -2
  11. package/dist/transformation/builtins/index.js +9 -7
  12. package/dist/transformation/builtins/math.js +7 -1
  13. package/dist/transformation/utils/diagnostics.d.ts +3 -6
  14. package/dist/transformation/utils/diagnostics.js +2 -3
  15. package/dist/transformation/utils/language-extensions.d.ts +2 -0
  16. package/dist/transformation/utils/language-extensions.js +7 -1
  17. package/dist/transformation/utils/lua-ast.js +5 -5
  18. package/dist/transformation/utils/safe-names.d.ts +4 -2
  19. package/dist/transformation/utils/safe-names.js +11 -5
  20. package/dist/transformation/utils/scope.d.ts +2 -1
  21. package/dist/transformation/utils/scope.js +1 -0
  22. package/dist/transformation/utils/typescript/types.d.ts +3 -1
  23. package/dist/transformation/utils/typescript/types.js +40 -13
  24. package/dist/transformation/visitors/binary-expression/index.js +1 -3
  25. package/dist/transformation/visitors/call.js +7 -40
  26. package/dist/transformation/visitors/class/index.js +1 -1
  27. package/dist/transformation/visitors/class/members/fields.js +12 -8
  28. package/dist/transformation/visitors/conditional.js +2 -23
  29. package/dist/transformation/visitors/errors.js +11 -9
  30. package/dist/transformation/visitors/expression-statement.d.ts +3 -1
  31. package/dist/transformation/visitors/expression-statement.js +21 -19
  32. package/dist/transformation/visitors/function.d.ts +2 -0
  33. package/dist/transformation/visitors/function.js +58 -6
  34. package/dist/transformation/visitors/identifier.js +2 -1
  35. package/dist/transformation/visitors/language-extensions/index.d.ts +4 -0
  36. package/dist/transformation/visitors/language-extensions/index.js +17 -0
  37. package/dist/transformation/visitors/language-extensions/operators.d.ts +1 -1
  38. package/dist/transformation/visitors/language-extensions/operators.js +7 -2
  39. package/dist/transformation/visitors/language-extensions/pairsIterable.d.ts +5 -0
  40. package/dist/transformation/visitors/language-extensions/pairsIterable.js +53 -0
  41. package/dist/transformation/visitors/language-extensions/table.d.ts +1 -8
  42. package/dist/transformation/visitors/language-extensions/table.js +55 -53
  43. package/dist/transformation/visitors/loops/for-of.js +4 -0
  44. package/dist/transformation/visitors/loops/utils.js +6 -1
  45. package/dist/transformation/visitors/namespace.js +1 -1
  46. package/dist/transformation/visitors/spread.js +14 -7
  47. package/dist/transformation/visitors/variable-declaration.js +16 -1
  48. package/dist/transformation/visitors/void.d.ts +1 -4
  49. package/dist/transformation/visitors/void.js +6 -8
  50. package/language-extensions/index.d.ts +11 -1
  51. package/package.json +1 -1
@@ -28,7 +28,7 @@ function transformBuiltinPropertyAccessExpression(context, node) {
28
28
  if ((0, typescript_1.isArrayType)(context, ownerType)) {
29
29
  return (0, array_1.transformArrayProperty)(context, node);
30
30
  }
31
- if ((0, typescript_1.isFunctionType)(context, ownerType)) {
31
+ if ((0, typescript_1.isFunctionType)(ownerType)) {
32
32
  return (0, function_1.transformFunctionProperty)(context, node);
33
33
  }
34
34
  if (ts.isIdentifier(node.expression) && (0, typescript_1.isStandardLibraryType)(context, ownerType, undefined)) {
@@ -42,12 +42,18 @@ function transformBuiltinPropertyAccessExpression(context, node) {
42
42
  }
43
43
  exports.transformBuiltinPropertyAccessExpression = transformBuiltinPropertyAccessExpression;
44
44
  function transformBuiltinCallExpression(context, node, isOptionalCall) {
45
+ const unsupportedOptionalCall = () => {
46
+ context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(node));
47
+ return lua.createNilLiteral();
48
+ };
45
49
  const expressionType = context.checker.getTypeAtLocation(node.expression);
46
50
  if (ts.isIdentifier(node.expression) && (0, typescript_1.isStandardLibraryType)(context, expressionType, undefined)) {
47
51
  // TODO:
48
52
  (0, new_1.checkForLuaLibType)(context, expressionType);
49
53
  const result = (0, global_1.transformGlobalCall)(context, node);
50
54
  if (result) {
55
+ if (isOptionalCall)
56
+ return unsupportedOptionalCall();
51
57
  return result;
52
58
  }
53
59
  }
@@ -55,12 +61,8 @@ function transformBuiltinCallExpression(context, node, isOptionalCall) {
55
61
  if (!ts.isPropertyAccessExpression(expression)) {
56
62
  return;
57
63
  }
58
- (0, utils_1.assume)(node);
59
64
  const isOptionalAccess = expression.questionDotToken;
60
- const unsupportedOptionalCall = () => {
61
- context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(node));
62
- return lua.createNilLiteral();
63
- };
65
+ (0, utils_1.assume)(node);
64
66
  // If the function being called is of type owner.func, get the type of owner
65
67
  const ownerType = context.checker.getTypeAtLocation(expression.expression);
66
68
  if ((0, typescript_1.isStandardLibraryType)(context, ownerType, undefined)) {
@@ -115,7 +117,7 @@ function transformBuiltinCallExpression(context, node, isOptionalCall) {
115
117
  return unsupportedOptionalCall();
116
118
  return (0, array_1.transformArrayPrototypeCall)(context, node);
117
119
  }
118
- if ((0, typescript_1.isFunctionType)(context, ownerType) && (0, typescript_1.hasStandardLibrarySignature)(context, node)) {
120
+ if ((0, typescript_1.isFunctionType)(ownerType) && (0, typescript_1.hasStandardLibrarySignature)(context, node)) {
119
121
  if (isOptionalCall)
120
122
  return unsupportedOptionalCall();
121
123
  return (0, function_1.transformFunctionPrototypeCall)(context, node);
@@ -57,6 +57,10 @@ function transformMathCall(context, node) {
57
57
  const add = lua.createBinaryExpression(one, params[0], lua.SyntaxKind.AdditionOperator);
58
58
  return lua.createCallExpression(lua.createTableIndexExpression(math, log), [add], node);
59
59
  }
60
+ case "pow": {
61
+ // Translate to base ^ power
62
+ return lua.createBinaryExpression(params[0], params[1], lua.SyntaxKind.PowerOperator, node);
63
+ }
60
64
  // math.floor(x + 0.5)
61
65
  case "round": {
62
66
  const floor = lua.createStringLiteral("floor");
@@ -64,6 +68,9 @@ function transformMathCall(context, node) {
64
68
  const add = lua.createBinaryExpression(params[0], half, lua.SyntaxKind.AdditionOperator);
65
69
  return lua.createCallExpression(lua.createTableIndexExpression(math, floor), [add], node);
66
70
  }
71
+ case "sign": {
72
+ return (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.MathSign, node, ...params);
73
+ }
67
74
  case "abs":
68
75
  case "acos":
69
76
  case "asin":
@@ -75,7 +82,6 @@ function transformMathCall(context, node) {
75
82
  case "log":
76
83
  case "max":
77
84
  case "min":
78
- case "pow":
79
85
  case "random":
80
86
  case "sin":
81
87
  case "sqrt":
@@ -34,6 +34,9 @@ export declare const invalidRangeControlVariable: ((node: ts.Node, ...args: any[
34
34
  export declare const invalidMultiIterableWithoutDestructuring: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
35
35
  code: number;
36
36
  };
37
+ export declare const invalidPairsIterableWithoutDestructuring: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
38
+ code: number;
39
+ };
37
40
  export declare const unsupportedAccessorInObjectLiteral: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
38
41
  code: number;
39
42
  };
@@ -73,12 +76,6 @@ export declare const invalidOperatorMappingUse: ((node: ts.Node, ...args: any[])
73
76
  export declare const invalidTableExtensionUse: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
74
77
  code: number;
75
78
  };
76
- export declare const invalidTableDeleteExpression: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
77
- code: number;
78
- };
79
- export declare const invalidTableSetExpression: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
80
- code: number;
81
- };
82
79
  export declare const annotationRemoved: ((node: ts.Node, kind: AnnotationKind) => ts.Diagnostic) & {
83
80
  code: number;
84
81
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.unsupportedOptionalCompileMembersOnly = exports.unsupportedBuiltinOptionalCall = exports.awaitMustBeInAsyncFunction = exports.notAllowedOptionalAssignment = exports.annotationDeprecated = exports.annotationRemoved = exports.invalidTableSetExpression = exports.invalidTableDeleteExpression = exports.invalidTableExtensionUse = exports.invalidOperatorMappingUse = exports.invalidMultiReturnAccess = exports.invalidMultiTypeToEmptyPatternOrArrayLiteral = exports.invalidMultiTypeToNonArrayLiteral = exports.invalidMultiFunctionReturnType = exports.invalidMultiFunctionUse = exports.unsupportedVarDeclaration = exports.invalidAmbientIdentifierName = exports.unsupportedProperty = exports.unsupportedForTarget = exports.unsupportedRightShiftOperator = exports.unsupportedAccessorInObjectLiteral = 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.unsupportedOptionalCompileMembersOnly = exports.unsupportedBuiltinOptionalCall = exports.awaitMustBeInAsyncFunction = exports.notAllowedOptionalAssignment = exports.annotationDeprecated = exports.annotationRemoved = exports.invalidTableExtensionUse = exports.invalidOperatorMappingUse = exports.invalidMultiReturnAccess = exports.invalidMultiTypeToEmptyPatternOrArrayLiteral = exports.invalidMultiTypeToNonArrayLiteral = exports.invalidMultiFunctionReturnType = exports.invalidMultiFunctionUse = exports.unsupportedVarDeclaration = exports.invalidAmbientIdentifierName = exports.unsupportedProperty = 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");
@@ -36,6 +36,7 @@ exports.invalidRangeUse = createErrorDiagnosticFactory("$range can only be used
36
36
  exports.invalidVarargUse = createErrorDiagnosticFactory("$vararg can only be used in a spread element ('...$vararg') in global scope.");
37
37
  exports.invalidRangeControlVariable = createErrorDiagnosticFactory("For loop using $range must declare a single control variable.");
38
38
  exports.invalidMultiIterableWithoutDestructuring = createErrorDiagnosticFactory("LuaIterable with a LuaMultiReturn return value type must be destructured.");
39
+ exports.invalidPairsIterableWithoutDestructuring = createErrorDiagnosticFactory("LuaPairsIterable type must be destructured in a for...of statement.");
39
40
  exports.unsupportedAccessorInObjectLiteral = createErrorDiagnosticFactory("Accessors in object literal are not supported.");
40
41
  exports.unsupportedRightShiftOperator = createErrorDiagnosticFactory("Right shift operator is not supported for target Lua 5.3. Use `>>>` instead.");
41
42
  const getLuaTargetName = (version) => (version === CompilerOptions_1.LuaTarget.LuaJIT ? "LuaJIT" : `Lua ${version}`);
@@ -50,8 +51,6 @@ exports.invalidMultiTypeToEmptyPatternOrArrayLiteral = createErrorDiagnosticFact
50
51
  exports.invalidMultiReturnAccess = createErrorDiagnosticFactory("The LuaMultiReturn type can only be accessed via an element access expression of a numeric type.");
51
52
  exports.invalidOperatorMappingUse = createErrorDiagnosticFactory("This function must always be directly called and cannot be referred to.");
52
53
  exports.invalidTableExtensionUse = createErrorDiagnosticFactory("This function must be called directly and cannot be referred to.");
53
- exports.invalidTableDeleteExpression = createErrorDiagnosticFactory("Table delete extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement.");
54
- exports.invalidTableSetExpression = createErrorDiagnosticFactory("Table set extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement.");
55
54
  exports.annotationRemoved = createErrorDiagnosticFactory((kind) => `'@${kind}' has been removed and will no longer have any effect.` +
56
55
  `See https://typescripttolua.github.io/docs/advanced/compiler-annotations#${kind.toLowerCase()} for more information.`);
57
56
  exports.annotationDeprecated = createWarningDiagnosticFactory((kind) => `'@${kind}' is deprecated and will be removed in a future update. Please update your code before upgrading to the next release, otherwise your project will no longer compile. ` +
@@ -6,6 +6,7 @@ export declare enum ExtensionKind {
6
6
  RangeFunction = "RangeFunction",
7
7
  VarargConstant = "VarargConstant",
8
8
  IterableType = "IterableType",
9
+ PairsIterableType = "PairsIterableType",
9
10
  AdditionOperatorType = "AdditionOperatorType",
10
11
  AdditionOperatorMethodType = "AdditionOperatorMethodType",
11
12
  SubtractionOperatorType = "SubtractionOperatorType",
@@ -53,4 +54,5 @@ export declare enum ExtensionKind {
53
54
  TableSetMethodType = "TableSetMethodType"
54
55
  }
55
56
  export declare function isExtensionType(type: ts.Type, extensionKind: ExtensionKind): boolean;
57
+ export declare function getExtensionKinds(type: ts.Type): ExtensionKind[];
56
58
  export declare function isExtensionValue(context: TransformationContext, symbol: ts.Symbol, extensionKind: ExtensionKind): boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isExtensionValue = exports.isExtensionType = exports.ExtensionKind = void 0;
3
+ exports.isExtensionValue = exports.getExtensionKinds = exports.isExtensionType = exports.ExtensionKind = void 0;
4
4
  var ExtensionKind;
5
5
  (function (ExtensionKind) {
6
6
  ExtensionKind["MultiFunction"] = "MultiFunction";
@@ -8,6 +8,7 @@ var ExtensionKind;
8
8
  ExtensionKind["RangeFunction"] = "RangeFunction";
9
9
  ExtensionKind["VarargConstant"] = "VarargConstant";
10
10
  ExtensionKind["IterableType"] = "IterableType";
11
+ ExtensionKind["PairsIterableType"] = "PairsIterableType";
11
12
  ExtensionKind["AdditionOperatorType"] = "AdditionOperatorType";
12
13
  ExtensionKind["AdditionOperatorMethodType"] = "AdditionOperatorMethodType";
13
14
  ExtensionKind["SubtractionOperatorType"] = "SubtractionOperatorType";
@@ -65,6 +66,7 @@ const extensionKindToTypeBrand = {
65
66
  [ExtensionKind.RangeFunction]: "__luaRangeFunctionBrand",
66
67
  [ExtensionKind.VarargConstant]: "__luaVarargConstantBrand",
67
68
  [ExtensionKind.IterableType]: "__luaIterableBrand",
69
+ [ExtensionKind.PairsIterableType]: "__luaPairsIterableBrand",
68
70
  [ExtensionKind.AdditionOperatorType]: "__luaAdditionBrand",
69
71
  [ExtensionKind.AdditionOperatorMethodType]: "__luaAdditionMethodBrand",
70
72
  [ExtensionKind.SubtractionOperatorType]: "__luaSubtractionBrand",
@@ -116,6 +118,10 @@ function isExtensionType(type, extensionKind) {
116
118
  return typeBrand !== undefined && type.getProperty(typeBrand) !== undefined;
117
119
  }
118
120
  exports.isExtensionType = isExtensionType;
121
+ function getExtensionKinds(type) {
122
+ return Object.keys(extensionKindToTypeBrand).filter(e => type.getProperty(extensionKindToTypeBrand[e]) !== undefined);
123
+ }
124
+ exports.getExtensionKinds = getExtensionKinds;
119
125
  function isExtensionValue(context, symbol, extensionKind) {
120
126
  var _a;
121
127
  return (symbol.getName() === extensionKindToValueName[extensionKind] &&
@@ -119,7 +119,9 @@ function createLocalOrExportedOrGlobalDeclaration(context, lhs, rhs, tsOriginal,
119
119
  const scope = (0, scope_1.peekScope)(context);
120
120
  const isTopLevelVariable = scope.type === scope_1.ScopeType.File;
121
121
  if (context.isModule || !isTopLevelVariable) {
122
- if (!isFunctionDeclaration && hasMultipleReferences(scope, lhs)) {
122
+ const isLuaFunctionExpression = rhs && !Array.isArray(rhs) && lua.isFunctionExpression(rhs);
123
+ const isSafeRecursiveFunctionDeclaration = isFunctionDeclaration && isLuaFunctionExpression;
124
+ if (!isSafeRecursiveFunctionDeclaration && hasMultipleReferences(scope, lhs)) {
123
125
  // Split declaration and assignment of identifiers that reference themselves in their declaration.
124
126
  // Put declaration above preceding statements in case the identifier is referenced in those.
125
127
  const precedingDeclaration = lua.createVariableDeclarationStatement(lhs, undefined, tsOriginal);
@@ -127,10 +129,8 @@ function createLocalOrExportedOrGlobalDeclaration(context, lhs, rhs, tsOriginal,
127
129
  if (rhs) {
128
130
  assignment = lua.createAssignmentStatement(lhs, rhs, tsOriginal);
129
131
  }
130
- if (!isFunctionDeclaration) {
131
- // Remember local variable declarations for hoisting later
132
- (0, scope_1.addScopeVariableDeclaration)(scope, precedingDeclaration);
133
- }
132
+ // Remember local variable declarations for hoisting later
133
+ (0, scope_1.addScopeVariableDeclaration)(scope, precedingDeclaration);
134
134
  }
135
135
  else {
136
136
  declaration = lua.createVariableDeclarationStatement(lhs, rhs, tsOriginal);
@@ -1,8 +1,10 @@
1
1
  import * as ts from "typescript";
2
+ import { CompilerOptions } from "../..";
2
3
  import { TransformationContext } from "../context";
3
- export declare const isValidLuaIdentifier: (name: string) => boolean;
4
+ export declare const shouldAllowUnicode: (options: CompilerOptions) => boolean;
5
+ export declare const isValidLuaIdentifier: (name: string, options: CompilerOptions) => boolean;
4
6
  export declare const luaKeywords: ReadonlySet<string>;
5
- export declare const isUnsafeName: (name: string) => boolean;
7
+ export declare const isUnsafeName: (name: string, options: CompilerOptions) => boolean;
6
8
  export declare function hasUnsafeSymbolName(context: TransformationContext, symbol: ts.Symbol, tsOriginal: ts.Identifier): boolean;
7
9
  export declare function hasUnsafeIdentifierName(context: TransformationContext, identifier: ts.Identifier, checkSymbol?: boolean): boolean;
8
10
  export declare const createSafeName: (name: string) => string;
@@ -1,10 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createSafeName = exports.hasUnsafeIdentifierName = exports.hasUnsafeSymbolName = exports.isUnsafeName = exports.luaKeywords = exports.isValidLuaIdentifier = void 0;
3
+ exports.createSafeName = exports.hasUnsafeIdentifierName = exports.hasUnsafeSymbolName = exports.isUnsafeName = exports.luaKeywords = exports.isValidLuaIdentifier = exports.shouldAllowUnicode = void 0;
4
+ const __1 = require("../..");
4
5
  const diagnostics_1 = require("./diagnostics");
5
6
  const export_1 = require("./export");
6
7
  const typescript_1 = require("./typescript");
7
- const isValidLuaIdentifier = (name) => !exports.luaKeywords.has(name) && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name);
8
+ const shouldAllowUnicode = (options) => options.luaTarget === __1.LuaTarget.LuaJIT;
9
+ exports.shouldAllowUnicode = shouldAllowUnicode;
10
+ const isValidLuaIdentifier = (name, options) => !exports.luaKeywords.has(name) &&
11
+ ((0, exports.shouldAllowUnicode)(options)
12
+ ? /^[a-zA-Z_\u007F-\uFFFD][a-zA-Z0-9_\u007F-\uFFFD]*$/
13
+ : /^[a-zA-Z_][a-zA-Z0-9_]*$/).test(name);
8
14
  exports.isValidLuaIdentifier = isValidLuaIdentifier;
9
15
  exports.luaKeywords = new Set([
10
16
  "and",
@@ -51,10 +57,10 @@ const luaBuiltins = new Set([
51
57
  "type",
52
58
  "unpack",
53
59
  ]);
54
- const isUnsafeName = (name) => !(0, exports.isValidLuaIdentifier)(name) || luaBuiltins.has(name);
60
+ const isUnsafeName = (name, options) => !(0, exports.isValidLuaIdentifier)(name, options) || luaBuiltins.has(name);
55
61
  exports.isUnsafeName = isUnsafeName;
56
62
  function checkName(context, name, node) {
57
- const isInvalid = !(0, exports.isValidLuaIdentifier)(name);
63
+ const isInvalid = !(0, exports.isValidLuaIdentifier)(name, context.options);
58
64
  if (isInvalid) {
59
65
  // Empty identifier is a TypeScript error
60
66
  if (name !== "") {
@@ -71,7 +77,7 @@ function hasUnsafeSymbolName(context, symbol, tsOriginal) {
71
77
  return true;
72
78
  }
73
79
  // only unsafe when non-ambient and not exported
74
- return (0, exports.isUnsafeName)(symbol.name) && !isAmbient && !(0, export_1.isSymbolExported)(context, symbol);
80
+ return (0, exports.isUnsafeName)(symbol.name, context.options) && !isAmbient && !(0, export_1.isSymbolExported)(context, symbol);
75
81
  }
76
82
  exports.hasUnsafeSymbolName = hasUnsafeSymbolName;
77
83
  function hasUnsafeIdentifierName(context, identifier, checkSymbol = true) {
@@ -9,7 +9,8 @@ export declare enum ScopeType {
9
9
  Conditional = 16,
10
10
  Block = 32,
11
11
  Try = 64,
12
- Catch = 128
12
+ Catch = 128,
13
+ LoopInitializer = 256
13
14
  }
14
15
  interface FunctionDefinitionInfo {
15
16
  referencedSymbols: Map<lua.SymbolId, ts.Node[]>;
@@ -16,6 +16,7 @@ var ScopeType;
16
16
  ScopeType[ScopeType["Block"] = 32] = "Block";
17
17
  ScopeType[ScopeType["Try"] = 64] = "Try";
18
18
  ScopeType[ScopeType["Catch"] = 128] = "Catch";
19
+ ScopeType[ScopeType["LoopInitializer"] = 256] = "LoopInitializer";
19
20
  })(ScopeType = exports.ScopeType || (exports.ScopeType = {}));
20
21
  const scopeStacks = new WeakMap();
21
22
  function getScopeStack(context) {
@@ -10,4 +10,6 @@ export declare function isNumberType(context: TransformationContext, type: ts.Ty
10
10
  */
11
11
  export declare function forTypeOrAnySupertype(context: TransformationContext, type: ts.Type, predicate: (type: ts.Type) => boolean): boolean;
12
12
  export declare function isArrayType(context: TransformationContext, type: ts.Type): boolean;
13
- export declare function isFunctionType(context: TransformationContext, type: ts.Type): boolean;
13
+ export declare function isFunctionType(type: ts.Type): boolean;
14
+ export declare function canBeFalsy(context: TransformationContext, type: ts.Type): boolean;
15
+ export declare function canBeFalsyWhenNotNull(context: TransformationContext, type: ts.Type): boolean;
@@ -1,21 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isFunctionType = exports.isArrayType = exports.forTypeOrAnySupertype = exports.isNumberType = exports.isStringType = exports.typeCanSatisfy = exports.typeAlwaysSatisfies = exports.isTypeWithFlags = void 0;
3
+ exports.canBeFalsyWhenNotNull = exports.canBeFalsy = exports.isFunctionType = exports.isArrayType = exports.forTypeOrAnySupertype = exports.isNumberType = exports.isStringType = exports.typeCanSatisfy = exports.typeAlwaysSatisfies = exports.isTypeWithFlags = void 0;
4
4
  const ts = require("typescript");
5
5
  function isTypeWithFlags(context, type, flags) {
6
- const predicate = (type) => {
7
- if (type.symbol) {
8
- const baseConstraint = context.checker.getBaseConstraintOfType(type);
9
- if (baseConstraint && baseConstraint !== type) {
10
- return isTypeWithFlags(context, baseConstraint, flags);
11
- }
12
- }
13
- return (type.flags & flags) !== 0;
14
- };
6
+ const predicate = (type) => (type.flags & flags) !== 0;
15
7
  return typeAlwaysSatisfies(context, type, predicate);
16
8
  }
17
9
  exports.isTypeWithFlags = isTypeWithFlags;
18
10
  function typeAlwaysSatisfies(context, type, predicate) {
11
+ const baseConstraint = context.checker.getBaseConstraintOfType(type);
12
+ if (baseConstraint) {
13
+ type = baseConstraint;
14
+ }
19
15
  if (predicate(type)) {
20
16
  return true;
21
17
  }
@@ -29,6 +25,15 @@ function typeAlwaysSatisfies(context, type, predicate) {
29
25
  }
30
26
  exports.typeAlwaysSatisfies = typeAlwaysSatisfies;
31
27
  function typeCanSatisfy(context, type, predicate) {
28
+ const baseConstraint = context.checker.getBaseConstraintOfType(type);
29
+ if (!baseConstraint) {
30
+ // type parameter with no constraint can be anything, assume it might satisfy predicate
31
+ if (type.isTypeParameter())
32
+ return true;
33
+ }
34
+ else {
35
+ type = baseConstraint;
36
+ }
32
37
  if (predicate(type)) {
33
38
  return true;
34
39
  }
@@ -84,9 +89,31 @@ function isArrayType(context, type) {
84
89
  return forTypeOrAnySupertype(context, type, t => isExplicitArrayType(context, t));
85
90
  }
86
91
  exports.isArrayType = isArrayType;
87
- function isFunctionType(context, type) {
88
- const typeNode = context.checker.typeToTypeNode(type, undefined, ts.NodeBuilderFlags.InTypeAlias);
89
- return typeNode !== undefined && ts.isFunctionTypeNode(typeNode);
92
+ function isFunctionType(type) {
93
+ return type.getCallSignatures().length > 0;
90
94
  }
91
95
  exports.isFunctionType = isFunctionType;
96
+ function canBeFalsy(context, type) {
97
+ const strictNullChecks = context.options.strict === true || context.options.strictNullChecks === true;
98
+ const falsyFlags = ts.TypeFlags.Boolean |
99
+ ts.TypeFlags.BooleanLiteral |
100
+ ts.TypeFlags.Never |
101
+ ts.TypeFlags.Void |
102
+ ts.TypeFlags.Unknown |
103
+ ts.TypeFlags.Any |
104
+ ts.TypeFlags.Undefined |
105
+ ts.TypeFlags.Null;
106
+ return typeCanSatisfy(context, type, type => (type.flags & falsyFlags) !== 0 || (!strictNullChecks && !type.isLiteral()));
107
+ }
108
+ exports.canBeFalsy = canBeFalsy;
109
+ function canBeFalsyWhenNotNull(context, type) {
110
+ const falsyFlags = ts.TypeFlags.Boolean |
111
+ ts.TypeFlags.BooleanLiteral |
112
+ ts.TypeFlags.Never |
113
+ ts.TypeFlags.Void |
114
+ ts.TypeFlags.Unknown |
115
+ ts.TypeFlags.Any;
116
+ return typeCanSatisfy(context, type, type => (type.flags & falsyFlags) !== 0);
117
+ }
118
+ exports.canBeFalsyWhenNotNull = canBeFalsyWhenNotNull;
92
119
  //# sourceMappingURL=types.js.map
@@ -167,9 +167,7 @@ exports.transformBinaryExpressionStatement = transformBinaryExpressionStatement;
167
167
  function transformNullishCoalescingOperationNoPrecedingStatements(context, node, transformedLeft, transformedRight) {
168
168
  const lhsType = context.checker.getTypeAtLocation(node.left);
169
169
  // Check if we can take a shortcut to 'lhs or rhs' if the left-hand side cannot be 'false'.
170
- const typeCanBeFalse = (type) => (type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Boolean)) !== 0 ||
171
- (type.flags & ts.TypeFlags.BooleanLiteral & ts.TypeFlags.PossiblyFalsy) !== 0;
172
- if ((0, typescript_1.typeCanSatisfy)(context, lhsType, typeCanBeFalse)) {
170
+ if ((0, typescript_1.canBeFalsyWhenNotNull)(context, lhsType)) {
173
171
  // reuse logic from case with preceding statements
174
172
  const [precedingStatements, result] = createShortCircuitBinaryExpressionPrecedingStatements(context, transformedLeft, transformedRight, [], ts.SyntaxKind.QuestionQuestionToken, node);
175
173
  context.addPrecedingStatements(precedingStatements);
@@ -12,12 +12,11 @@ const safe_names_1 = require("../utils/safe-names");
12
12
  const typescript_1 = require("../utils/typescript");
13
13
  const access_1 = require("./access");
14
14
  const multi_1 = require("./language-extensions/multi");
15
- const operators_1 = require("./language-extensions/operators");
16
- const table_1 = require("./language-extensions/table");
17
15
  const diagnostics_1 = require("../utils/diagnostics");
18
16
  const expression_list_1 = require("./expression-list");
19
17
  const preceding_statements_1 = require("../utils/preceding-statements");
20
18
  const optional_chaining_1 = require("./optional-chaining");
19
+ const language_extensions_1 = require("./language-extensions");
21
20
  function validateArguments(context, params, signature) {
22
21
  if (!signature || signature.parameters.length < params.length) {
23
22
  return;
@@ -86,7 +85,7 @@ function transformContextualCallExpression(context, node, args, signature) {
86
85
  let [argPrecedingStatements, transformedArguments] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => transformArguments(context, args, signature));
87
86
  if (ts.isPropertyAccessExpression(left) &&
88
87
  ts.isIdentifier(left.name) &&
89
- (0, safe_names_1.isValidLuaIdentifier)(left.name.text) &&
88
+ (0, safe_names_1.isValidLuaIdentifier)(left.name.text, context.options) &&
90
89
  argPrecedingStatements.length === 0) {
91
90
  // table:name()
92
91
  const table = context.transformExpression(left.expression);
@@ -145,6 +144,7 @@ function transformElementCall(context, node) {
145
144
  }
146
145
  }
147
146
  const transformCallExpression = (node, context) => {
147
+ var _a;
148
148
  if (ts.isOptionalChain(node)) {
149
149
  return (0, optional_chaining_1.transformOptionalChain)(context, node);
150
150
  }
@@ -152,46 +152,13 @@ const transformCallExpression = (node, context) => {
152
152
  ? (0, optional_chaining_1.getOptionalContinuationData)(node.expression)
153
153
  : undefined;
154
154
  const wrapResultInTable = (0, multi_1.isMultiReturnCall)(context, node) && (0, multi_1.shouldMultiReturnCallBeWrapped)(context, node);
155
- const builtinResult = (0, builtins_1.transformBuiltinCallExpression)(context, node, optionalContinuation !== undefined);
156
- if (builtinResult) {
157
- if (optionalContinuation) {
158
- context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(node));
159
- }
160
- return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(builtinResult) : builtinResult;
161
- }
162
155
  if ((0, annotations_1.isTupleReturnCall)(context, node)) {
163
156
  context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node, annotations_1.AnnotationKind.TupleReturn));
164
157
  }
165
- if ((0, operators_1.isOperatorMapping)(context, node)) {
166
- if (optionalContinuation) {
167
- context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(node));
168
- return lua.createNilLiteral();
169
- }
170
- return (0, operators_1.transformOperatorMappingExpression)(context, node);
171
- }
172
- if ((0, table_1.isTableDeleteCall)(context, node)) {
173
- context.diagnostics.push((0, diagnostics_1.invalidTableDeleteExpression)(node));
174
- context.addPrecedingStatements((0, table_1.transformTableDeleteExpression)(context, node));
175
- return lua.createNilLiteral();
176
- }
177
- if ((0, table_1.isTableGetCall)(context, node)) {
178
- if (optionalContinuation) {
179
- context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(node));
180
- return lua.createNilLiteral();
181
- }
182
- return (0, table_1.transformTableGetExpression)(context, node);
183
- }
184
- if ((0, table_1.isTableHasCall)(context, node)) {
185
- if (optionalContinuation) {
186
- context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(node));
187
- return lua.createNilLiteral();
188
- }
189
- return (0, table_1.transformTableHasExpression)(context, node);
190
- }
191
- if ((0, table_1.isTableSetCall)(context, node)) {
192
- context.diagnostics.push((0, diagnostics_1.invalidTableSetExpression)(node));
193
- context.addPrecedingStatements((0, table_1.transformTableSetExpression)(context, node));
194
- return lua.createNilLiteral();
158
+ const builtinOrExtensionResult = (_a = (0, builtins_1.transformBuiltinCallExpression)(context, node, optionalContinuation !== undefined)) !== null && _a !== void 0 ? _a : (0, language_extensions_1.transformLanguageExtensionCallExpression)(context, node, optionalContinuation !== undefined);
159
+ if (builtinOrExtensionResult) {
160
+ // unsupportedOptionalCall diagnostic already present
161
+ return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(builtinOrExtensionResult) : builtinOrExtensionResult;
195
162
  }
196
163
  if (ts.isPropertyAccessExpression(node.expression)) {
197
164
  const ownerType = context.checker.getTypeAtLocation(node.expression.expression);
@@ -70,7 +70,7 @@ function transformClassLikeDeclaration(classDeclaration, context, nameOverride)
70
70
  const instanceFields = properties.filter(prop => !(0, utils_2.isStaticNode)(prop));
71
71
  const result = [];
72
72
  let localClassName;
73
- if ((0, safe_names_1.isUnsafeName)(className.text)) {
73
+ if ((0, safe_names_1.isUnsafeName)(className.text, context.options)) {
74
74
  localClassName = lua.createIdentifier((0, safe_names_1.createSafeName)(className.text), undefined, className.symbolId, className.text);
75
75
  lua.setNodePosition(localClassName, className);
76
76
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformStaticPropertyDeclaration = exports.transformClassInstanceFields = exports.createPropertyDecoratingExpression = void 0;
4
4
  const lua = require("../../../../LuaAST");
5
5
  const lua_ast_1 = require("../../../utils/lua-ast");
6
+ const preceding_statements_1 = require("../../../utils/preceding-statements");
6
7
  const literal_1 = require("../../literal");
7
8
  const decorators_1 = require("../decorators");
8
9
  const method_1 = require("./method");
@@ -17,14 +18,17 @@ exports.createPropertyDecoratingExpression = createPropertyDecoratingExpression;
17
18
  function transformClassInstanceFields(context, instanceFields) {
18
19
  const statements = [];
19
20
  for (const f of instanceFields) {
20
- // Get identifier
21
- const fieldName = (0, literal_1.transformPropertyName)(context, f.name);
22
- const value = f.initializer ? context.transformExpression(f.initializer) : undefined;
23
- // self[fieldName]
24
- const selfIndex = lua.createTableIndexExpression((0, lua_ast_1.createSelfIdentifier)(), fieldName);
25
- // self[fieldName] = value
26
- const assignClassField = lua.createAssignmentStatement(selfIndex, value, f);
27
- statements.push(assignClassField);
21
+ const [precedingStatements, statement] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => {
22
+ // Get identifier
23
+ const fieldName = (0, literal_1.transformPropertyName)(context, f.name);
24
+ const value = f.initializer ? context.transformExpression(f.initializer) : undefined;
25
+ // self[fieldName]
26
+ const selfIndex = lua.createTableIndexExpression((0, lua_ast_1.createSelfIdentifier)(), fieldName);
27
+ // self[fieldName] = value
28
+ const assignClassField = lua.createAssignmentStatement(selfIndex, value, f);
29
+ return assignClassField;
30
+ });
31
+ statements.push(...precedingStatements, statement);
28
32
  }
29
33
  return statements;
30
34
  }
@@ -6,28 +6,7 @@ const lua = require("../../LuaAST");
6
6
  const preceding_statements_1 = require("../utils/preceding-statements");
7
7
  const scope_1 = require("../utils/scope");
8
8
  const block_1 = require("./block");
9
- function canBeFalsy(context, type) {
10
- const strictNullChecks = context.options.strict === true || context.options.strictNullChecks === true;
11
- const falsyFlags = ts.TypeFlags.Boolean |
12
- ts.TypeFlags.BooleanLiteral |
13
- ts.TypeFlags.Undefined |
14
- ts.TypeFlags.Null |
15
- ts.TypeFlags.Never |
16
- ts.TypeFlags.Void |
17
- ts.TypeFlags.Any;
18
- if (type.flags & falsyFlags) {
19
- return true;
20
- }
21
- else if (!strictNullChecks && !type.isLiteral()) {
22
- return true;
23
- }
24
- else if (type.isUnion()) {
25
- return type.types.some(subType => canBeFalsy(context, subType));
26
- }
27
- else {
28
- return false;
29
- }
30
- }
9
+ const typescript_1 = require("../utils/typescript");
31
10
  function transformProtectedConditionalExpression(context, expression) {
32
11
  const tempVar = context.createTempNameForNode(expression.condition);
33
12
  const condition = context.transformExpression(expression.condition);
@@ -42,7 +21,7 @@ function transformProtectedConditionalExpression(context, expression) {
42
21
  return lua.cloneIdentifier(tempVar);
43
22
  }
44
23
  const transformConditionalExpression = (expression, context) => {
45
- if (canBeFalsy(context, context.checker.getTypeAtLocation(expression.whenTrue))) {
24
+ if ((0, typescript_1.canBeFalsy)(context, context.checker.getTypeAtLocation(expression.whenTrue))) {
46
25
  return transformProtectedConditionalExpression(context, expression);
47
26
  }
48
27
  const condition = context.transformExpression(expression.condition);
@@ -12,6 +12,7 @@ const identifier_1 = require("./identifier");
12
12
  const multi_1 = require("./language-extensions/multi");
13
13
  const return_1 = require("./return");
14
14
  const transformTryStatement = (statement, context) => {
15
+ var _a;
15
16
  const [tryBlock, tryScope] = (0, block_1.transformScopeBlock)(context, statement.tryBlock, scope_1.ScopeType.Try);
16
17
  if (context.options.luaTarget === __1.LuaTarget.Lua51 && (0, typescript_1.isInAsyncFunction)(statement)) {
17
18
  context.diagnostics.push((0, diagnostics_1.unsupportedForTarget)(statement, "try/catch inside async functions", __1.LuaTarget.Lua51));
@@ -34,24 +35,25 @@ const transformTryStatement = (statement, context) => {
34
35
  const catchParameter = statement.catchClause.variableDeclaration
35
36
  ? (0, identifier_1.transformIdentifier)(context, statement.catchClause.variableDeclaration.name)
36
37
  : undefined;
37
- const catchParameters = () => (catchParameter ? [lua.cloneIdentifier(catchParameter)] : []);
38
+ const catchFunction = lua.createFunctionExpression(catchBlock, catchParameter ? [lua.cloneIdentifier(catchParameter)] : []);
38
39
  const catchIdentifier = lua.createIdentifier("____catch");
39
- const catchFunction = lua.createFunctionExpression(catchBlock, catchParameters());
40
40
  result.push(lua.createVariableDeclarationStatement(catchIdentifier, catchFunction));
41
+ const hasReturn = (_a = tryScope.functionReturned) !== null && _a !== void 0 ? _a : catchScope.functionReturned;
41
42
  const tryReturnIdentifiers = [tryResultIdentifier]; // ____try
42
- if (returnedIdentifier) {
43
- tryReturnIdentifiers.push(returnedIdentifier); // ____returned or catch variable
44
- if (tryScope.functionReturned || catchScope.functionReturned) {
43
+ if (hasReturn || statement.catchClause.variableDeclaration) {
44
+ tryReturnIdentifiers.push(returnedIdentifier); // ____returned
45
+ if (hasReturn) {
45
46
  tryReturnIdentifiers.push(returnValueIdentifier); // ____returnValue
46
47
  returnCondition = lua.cloneIdentifier(returnedIdentifier);
47
48
  }
48
49
  }
49
50
  result.push(lua.createVariableDeclarationStatement(tryReturnIdentifiers, tryCall));
50
- // Wrap catch in function if try or catch has return
51
- const catchCall = lua.createCallExpression(catchIdentifier, [lua.cloneIdentifier(returnedIdentifier)]);
52
- const catchAssign = lua.createAssignmentStatement([lua.cloneIdentifier(returnedIdentifier), lua.cloneIdentifier(returnValueIdentifier)], catchCall);
51
+ const catchCall = lua.createCallExpression(catchIdentifier, statement.catchClause.variableDeclaration ? [lua.cloneIdentifier(returnedIdentifier)] : []);
52
+ const catchCallStatement = hasReturn
53
+ ? lua.createAssignmentStatement([lua.cloneIdentifier(returnedIdentifier), lua.cloneIdentifier(returnValueIdentifier)], catchCall)
54
+ : lua.createExpressionStatement(catchCall);
53
55
  const notTryCondition = lua.createUnaryExpression(tryResultIdentifier, lua.SyntaxKind.NotOperator);
54
- result.push(lua.createIfStatement(notTryCondition, lua.createBlock([catchAssign])));
56
+ result.push(lua.createIfStatement(notTryCondition, lua.createBlock([catchCallStatement])));
55
57
  }
56
58
  else if (tryScope.functionReturned) {
57
59
  // try with return, but no catch
@@ -1,3 +1,5 @@
1
1
  import * as ts from "typescript";
2
- import { FunctionVisitor } from "../context";
2
+ import * as lua from "../../LuaAST";
3
+ import { FunctionVisitor, TransformationContext } from "../context";
3
4
  export declare const transformExpressionStatement: FunctionVisitor<ts.ExpressionStatement>;
5
+ export declare function transformExpressionToStatement(context: TransformationContext, expression: ts.Expression): lua.Statement | undefined;