typescript-to-lua
Advanced tools
Comparing version 0.40.1 to 0.41.0
# Changelog | ||
## 0.41.0 | ||
- Added support for [optional chaining](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html) `a?.b`, `a?.[b]` and `a?.()`. | ||
- Added an error when trying to bundle a library (`"buildmode": "library"`) project. | ||
- Added `--tstlVerbose` CLI flag to help with diagnosing problems. | ||
- Fixed a bug where vararg (`...`) was not correctly optimized. | ||
- Fixed .tsx files not correctly being resolved. | ||
- Fixed a bug where files were emitted to the wrong location if no `outDir` was specified. | ||
## 0.40.0 | ||
@@ -4,0 +13,0 @@ |
@@ -57,2 +57,7 @@ "use strict"; | ||
}, | ||
{ | ||
name: "tstlVerbose", | ||
description: "Provide verbose output useful for diagnosing problems.", | ||
type: "boolean", | ||
}, | ||
]; | ||
@@ -59,0 +64,0 @@ function updateParsedConfigFile(parsedConfigFile) { |
import * as ts from "typescript"; | ||
declare type KnownKeys<T> = { | ||
[K in keyof T]: string extends K ? never : number extends K ? never : K; | ||
} extends { | ||
[K in keyof T]: infer U; | ||
} ? U : never; | ||
declare type OmitIndexSignature<T extends Record<any, any>> = Pick<T, KnownKeys<T>>; | ||
declare type OmitIndexSignature<T> = { | ||
[K in keyof T as string extends K ? never : number extends K ? never : K]: T[K]; | ||
}; | ||
export interface TransformerImport { | ||
@@ -32,2 +29,3 @@ transform: string; | ||
plugins?: Array<ts.PluginImport | TransformerImport>; | ||
tstlVerbose?: boolean; | ||
[option: string]: any; | ||
@@ -34,0 +32,0 @@ }; |
@@ -36,2 +36,5 @@ "use strict"; | ||
} | ||
if (options.luaBundle && options.buildMode === BuildMode.Library) { | ||
diagnostics.push(diagnosticFactories.cannotBundleLibrary()); | ||
} | ||
return diagnostics; | ||
@@ -38,0 +41,0 @@ } |
@@ -58,2 +58,5 @@ import { EmitHost } from "./transpilation"; | ||
ObjectValues = "ObjectValues", | ||
OptionalChainAccess = "OptionalChainAccess", | ||
OptionalFunctionCall = "OptionalFunctionCall", | ||
OptionalMethodCall = "OptionalMethodCall", | ||
ParseFloat = "ParseFloat", | ||
@@ -60,0 +63,0 @@ ParseInt = "ParseInt", |
@@ -62,2 +62,5 @@ "use strict"; | ||
LuaLibFeature["ObjectValues"] = "ObjectValues"; | ||
LuaLibFeature["OptionalChainAccess"] = "OptionalChainAccess"; | ||
LuaLibFeature["OptionalFunctionCall"] = "OptionalFunctionCall"; | ||
LuaLibFeature["OptionalMethodCall"] = "OptionalMethodCall"; | ||
LuaLibFeature["ParseFloat"] = "ParseFloat"; | ||
@@ -64,0 +67,0 @@ LuaLibFeature["ParseInt"] = "ParseInt"; |
@@ -31,3 +31,3 @@ import * as ts from "typescript"; | ||
readonly isModule: boolean; | ||
readonly isStrict: any; | ||
readonly isStrict: boolean; | ||
constructor(program: ts.Program, sourceFile: ts.SourceFile, visitorMap: VisitorMap); | ||
@@ -34,0 +34,0 @@ private currentNodeVisitors; |
@@ -17,4 +17,3 @@ "use strict"; | ||
this.diagnostics = []; | ||
this.checker = this | ||
.program.getDiagnosticsProducingTypeChecker(); | ||
this.checker = this.program.getDiagnosticsProducingTypeChecker(); | ||
this.options = this.program.getCompilerOptions(); | ||
@@ -21,0 +20,0 @@ this.luaTarget = (_a = this.options.luaTarget) !== null && _a !== void 0 ? _a : CompilerOptions_1.LuaTarget.Universal; |
@@ -88,4 +88,1 @@ import * as ts from "typescript"; | ||
}; | ||
export declare const optionalChainingNotSupported: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & { | ||
code: number; | ||
}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.optionalChainingNotSupported = 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; | ||
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; | ||
const ts = require("typescript"); | ||
@@ -59,3 +59,2 @@ const CompilerOptions_1 = require("../../CompilerOptions"); | ||
`See https://typescripttolua.github.io/docs/advanced/compiler-annotations#${kind.toLowerCase()} for more information.`); | ||
exports.optionalChainingNotSupported = createErrorDiagnosticFactory("Optional chaining is not supported yet."); | ||
//# sourceMappingURL=diagnostics.js.map |
@@ -73,3 +73,3 @@ "use strict"; | ||
var _a; | ||
return (_a = symbol === null || symbol === void 0 ? void 0 : symbol.declarations) === null || _a === void 0 ? void 0 : _a.some(d => typescript_1.findFirstNodeAbove(d, (n) => n === scopeNode)); | ||
return (_a = symbol === null || symbol === void 0 ? void 0 : symbol.declarations) === null || _a === void 0 ? void 0 : _a.some(d => typescript_1.findFirstNodeAbove(d, (n) => n === scopeNode) && !ts.isParameter(d.parent)); | ||
} | ||
@@ -76,0 +76,0 @@ // Checks for references to local functions which haven't been defined yet, |
@@ -46,2 +46,5 @@ "use strict"; | ||
} | ||
if (ts.isOptionalChain(node)) { | ||
return lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.OptionalChainAccess, node, table, accessExpression); | ||
} | ||
return lua.createTableIndexExpression(table, accessExpression, node); | ||
@@ -57,5 +60,2 @@ }; | ||
} | ||
if (ts.isOptionalChain(node)) { | ||
context.diagnostics.push(diagnostics_1.optionalChainingNotSupported(node)); | ||
} | ||
const constEnumValue = enum_1.tryGetConstEnumValue(context, node); | ||
@@ -82,2 +82,6 @@ if (constEnumValue) { | ||
} | ||
if (ts.isOptionalChain(node)) { | ||
// Only handle full optional chains separately, not partial ones | ||
return transformOptionalChain(context, node); | ||
} | ||
const callPath = context.transformExpression(node.expression); | ||
@@ -87,2 +91,7 @@ return lua.createTableIndexExpression(callPath, lua.createStringLiteral(property), node); | ||
exports.transformPropertyAccessExpression = transformPropertyAccessExpression; | ||
function transformOptionalChain(context, node) { | ||
const left = context.transformExpression(node.expression); | ||
const right = lua.createStringLiteral(node.name.text, node.name); | ||
return lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.OptionalChainAccess, node, left, right); | ||
} | ||
const transformQualifiedName = (node, context) => { | ||
@@ -89,0 +98,0 @@ const right = lua.createStringLiteral(node.right.text, node.right); |
@@ -39,3 +39,3 @@ "use strict"; | ||
utils_1.assert(ts.isBinaryExpression(node)); | ||
return transformNullishCoalescingExpression(context, node); | ||
return transformNullishCoalescingExpression(context, node, left, right); | ||
} | ||
@@ -117,3 +117,3 @@ let luaOperator = simpleOperatorsToLua[operator]; | ||
exports.transformBinaryExpressionStatement = transformBinaryExpressionStatement; | ||
function transformNullishCoalescingExpression(context, node) { | ||
function transformNullishCoalescingExpression(context, node, transformedLeft, transformedRight) { | ||
const lhsType = context.checker.getTypeAtLocation(node.left); | ||
@@ -128,6 +128,6 @@ // Check if we can take a shortcut to 'lhs or rhs' if the left-hand side cannot be 'false'. | ||
// if ____ == nil then return rhs else return ____ end | ||
const ifStatement = lua.createIfStatement(nilComparison, lua.createBlock([lua.createReturnStatement([context.transformExpression(node.right)])]), lua.createBlock([lua.createReturnStatement([lua.cloneIdentifier(lhsIdentifier)])])); | ||
const ifStatement = lua.createIfStatement(nilComparison, lua.createBlock([lua.createReturnStatement([transformedRight])]), lua.createBlock([lua.createReturnStatement([lua.cloneIdentifier(lhsIdentifier)])])); | ||
// (function(lhs') if lhs' == nil then return rhs else return lhs' end)(lhs) | ||
return lua.createCallExpression(lua.createFunctionExpression(lua.createBlock([ifStatement]), [lhsIdentifier]), [ | ||
context.transformExpression(node.left), | ||
transformedLeft, | ||
]); | ||
@@ -137,5 +137,5 @@ } | ||
// lhs or rhs | ||
return lua.createBinaryExpression(context.transformExpression(node.left), context.transformExpression(node.right), lua.SyntaxKind.OrOperator, node); | ||
return lua.createBinaryExpression(transformedLeft, transformedRight, lua.SyntaxKind.OrOperator, node); | ||
} | ||
} | ||
//# sourceMappingURL=index.js.map |
@@ -9,3 +9,3 @@ import * as ts from "typescript"; | ||
export declare function transformArguments(context: TransformationContext, params: readonly ts.Expression[], signature?: ts.Signature, callContext?: ts.Expression): lua.Expression[]; | ||
export declare function transformContextualCallExpression(context: TransformationContext, node: ts.CallExpression | ts.TaggedTemplateExpression, args: ts.Expression[] | ts.NodeArray<ts.Expression>, signature?: ts.Signature): lua.Expression; | ||
export declare function transformContextualCallExpression(context: TransformationContext, node: ts.CallExpression | ts.TaggedTemplateExpression, args: ts.Expression[] | ts.NodeArray<ts.Expression>, signature?: ts.Signature): lua.CallExpression | lua.MethodCallExpression; | ||
export declare const transformCallExpression: FunctionVisitor<ts.CallExpression>; |
@@ -106,3 +106,8 @@ "use strict"; | ||
const table = context.transformExpression(left.expression); | ||
return lua.createMethodCallExpression(table, lua.createIdentifier(left.name.text, left.name), transformArguments(context, args, signature), node); | ||
if (ts.isOptionalChain(node)) { | ||
return lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.OptionalMethodCall, node, table, lua.createStringLiteral(left.name.text, left.name), ...transformArguments(context, args, signature)); | ||
} | ||
else { | ||
return lua.createMethodCallExpression(table, lua.createIdentifier(left.name.text, left.name), transformArguments(context, args, signature), node); | ||
} | ||
} | ||
@@ -144,8 +149,11 @@ else if (ts.isElementAccessExpression(left) || ts.isPropertyAccessExpression(left)) { | ||
else { | ||
const table = context.transformExpression(node.expression.expression); | ||
// table.name() | ||
const name = node.expression.name.text; | ||
const callPath = lua.createTableIndexExpression(table, lua.createStringLiteral(name), node.expression); | ||
const callPath = context.transformExpression(node.expression); | ||
const parameters = transformArguments(context, node.arguments, signature); | ||
return lua.createCallExpression(callPath, parameters, node); | ||
if (ts.isOptionalChain(node)) { | ||
return lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.OptionalFunctionCall, node, callPath, ...parameters); | ||
} | ||
else { | ||
return lua.createCallExpression(callPath, parameters, node); | ||
} | ||
} | ||
@@ -173,6 +181,7 @@ } | ||
const wrapTupleReturn = isTupleReturn && !isTupleReturnForward && !typescript_1.isInDestructingAssignment(node) && !isInSpread && returnValueIsUsed; | ||
const wrapResult = wrapTupleReturn || multi_1.shouldMultiReturnCallBeWrapped(context, node); | ||
const wrapResultInTable = wrapTupleReturn || multi_1.shouldMultiReturnCallBeWrapped(context, node); | ||
const wrapResultInOptional = ts.isOptionalChain(node); | ||
const builtinResult = builtins_1.transformBuiltinCallExpression(context, node); | ||
if (builtinResult) { | ||
return wrapResult ? lua_ast_1.wrapInTable(builtinResult) : builtinResult; | ||
return wrapResultInTable ? lua_ast_1.wrapInTable(builtinResult) : builtinResult; | ||
} | ||
@@ -203,7 +212,8 @@ if (operators_1.isOperatorMapping(context, node)) { | ||
const result = transformPropertyCall(context, node); | ||
return wrapResult ? lua_ast_1.wrapInTable(result) : result; | ||
// transformPropertyCall already wraps optional so no need to do so here | ||
return wrapResultInTable ? lua_ast_1.wrapInTable(result) : result; | ||
} | ||
if (ts.isElementAccessExpression(node.expression)) { | ||
const result = transformElementCall(context, node); | ||
return wrapResult ? lua_ast_1.wrapInTable(result) : result; | ||
return wrapIfRequired(context, wrapResultInTable, wrapResultInOptional, result, node); | ||
} | ||
@@ -227,5 +237,17 @@ const signature = context.checker.getResolvedSignature(node); | ||
const callExpression = lua.createCallExpression(callPath, parameters, node); | ||
return wrapResult ? lua_ast_1.wrapInTable(callExpression) : callExpression; | ||
return wrapIfRequired(context, wrapResultInTable, wrapResultInOptional, callExpression, node); | ||
}; | ||
exports.transformCallExpression = transformCallExpression; | ||
function wrapIfRequired(context, shouldWrapInTable, shouldWrapOptional, call, node) { | ||
const wrappedOptional = shouldWrapOptional ? wrapOptionalCall(context, call, node) : call; | ||
return shouldWrapInTable ? lua_ast_1.wrapInTable(wrappedOptional) : wrappedOptional; | ||
} | ||
function wrapOptionalCall(context, call, node) { | ||
if (lua.isMethodCallExpression(call)) { | ||
return lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.OptionalMethodCall, node, call.prefixExpression, lua.createStringLiteral(call.name.text), ...call.params); | ||
} | ||
else { | ||
return lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.OptionalFunctionCall, node, call.expression, ...call.params); | ||
} | ||
} | ||
//# sourceMappingURL=call.js.map |
@@ -29,1 +29,4 @@ import * as ts from "typescript"; | ||
}; | ||
export declare const cannotBundleLibrary: (() => ts.Diagnostic) & { | ||
code: number; | ||
}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.usingLuaBundleWithInlineMightGenerateDuplicateCode = exports.luaBundleEntryIsRequired = exports.couldNotFindBundleEntryPoint = exports.transformerShouldBeATsTransformerFactory = exports.shouldHaveAExport = exports.couldNotResolveFrom = exports.toLoadItShouldBeTranspiled = exports.couldNotReadDependency = exports.couldNotResolveRequire = void 0; | ||
exports.cannotBundleLibrary = exports.usingLuaBundleWithInlineMightGenerateDuplicateCode = exports.luaBundleEntryIsRequired = exports.couldNotFindBundleEntryPoint = exports.transformerShouldBeATsTransformerFactory = exports.shouldHaveAExport = exports.couldNotResolveFrom = exports.toLoadItShouldBeTranspiled = exports.couldNotReadDependency = exports.couldNotResolveRequire = void 0; | ||
const ts = require("typescript"); | ||
@@ -20,2 +20,3 @@ const utils_1 = require("../utils"); | ||
})); | ||
exports.cannotBundleLibrary = createDiagnosticFactory(() => 'Cannot bundle probjects with"buildmode": "library". Projects including the library can still bundle (which will include external library files).'); | ||
//# sourceMappingURL=diagnostics.js.map |
@@ -21,4 +21,8 @@ "use strict"; | ||
const diagnostics = []; | ||
const options = program.getCompilerOptions(); | ||
// Resolve dependencies for all processed files | ||
for (const file of files) { | ||
if (options.tstlVerbose) { | ||
console.log(`Resolving dependencies for ${utils_1.normalizeSlashes(file.fileName)}`); | ||
} | ||
const resolutionResult = resolveFileDependencies(file, program, emitHost); | ||
@@ -34,2 +38,3 @@ outFiles.push(...resolutionResult.resolvedFiles); | ||
const diagnostics = []; | ||
const options = program.getCompilerOptions(); | ||
for (const required of findRequiredPaths(file.code)) { | ||
@@ -51,2 +56,5 @@ // Do no resolve lualib | ||
if (resolvedDependency) { | ||
if (options.tstlVerbose) { | ||
console.log(`Resolved ${required} to ${utils_1.normalizeSlashes(resolvedDependency)}`); | ||
} | ||
// Figure out resolved require path and dependency output path | ||
@@ -86,2 +94,6 @@ const resolvedRequire = transpiler_1.getEmitPathRelativeToOutDir(resolvedDependency, program); | ||
function resolveDependency(fileDirectory, dependency, program, emitHost) { | ||
const options = program.getCompilerOptions(); | ||
if (options.tstlVerbose) { | ||
console.log(`Resolving "${dependency}" from ${utils_1.normalizeSlashes(fileDirectory)}`); | ||
} | ||
// Check if file is a file in the project | ||
@@ -88,0 +100,0 @@ const resolvedPath = path.join(fileDirectory, dependency); |
@@ -14,2 +14,5 @@ "use strict"; | ||
const options = program.getCompilerOptions(); | ||
if (options.tstlVerbose) { | ||
console.log("Parsing project settings"); | ||
} | ||
const diagnostics = CompilerOptions_1.validateOptions(options); | ||
@@ -41,8 +44,17 @@ let transpiledFiles = []; | ||
const plugins = plugins_1.getPlugins(program, diagnostics, customPlugins); | ||
if (options.tstlVerbose) { | ||
console.log(`Successfully loaded ${plugins.length} plugins`); | ||
} | ||
const visitorMap = transformation_1.createVisitorMap(plugins.map(p => p.visitors).filter(utils_1.isNonNull)); | ||
const printer = LuaPrinter_1.createPrinter(plugins.map(p => p.printer).filter(utils_1.isNonNull)); | ||
const processSourceFile = (sourceFile) => { | ||
if (options.tstlVerbose) { | ||
console.log(`Transforming ${sourceFile.fileName}`); | ||
} | ||
const { file, diagnostics: transformDiagnostics } = transformation_1.transformSourceFile(program, sourceFile, visitorMap); | ||
diagnostics.push(...transformDiagnostics); | ||
if (!options.noEmit && !options.emitDeclarationOnly) { | ||
if (options.tstlVerbose) { | ||
console.log(`Printing ${sourceFile.fileName}`); | ||
} | ||
const printResult = printer(program, emitHost, sourceFile.fileName, file); | ||
@@ -49,0 +61,0 @@ transpiledFiles.push({ |
@@ -19,7 +19,14 @@ "use strict"; | ||
const { program, writeFile = this.emitHost.writeFile } = emitOptions; | ||
const verbose = program.getCompilerOptions().tstlVerbose; | ||
const { diagnostics, transpiledFiles: freshFiles } = transpile_1.getProgramTranspileResult(this.emitHost, writeFile, emitOptions); | ||
const { emitPlan } = this.getEmitPlan(program, diagnostics, freshFiles); | ||
if (verbose) { | ||
console.log("Emitting output"); | ||
} | ||
const options = program.getCompilerOptions(); | ||
const emitBOM = (_a = options.emitBOM) !== null && _a !== void 0 ? _a : false; | ||
for (const { outputPath, code, sourceMap, sourceFiles } of emitPlan) { | ||
if (verbose) { | ||
console.log(`Emitting ${utils_1.normalizeSlashes(outputPath)}`); | ||
} | ||
writeFile(outputPath, code, emitBOM, undefined, sourceFiles); | ||
@@ -30,2 +37,5 @@ if (options.sourceMap && sourceMap !== undefined) { | ||
} | ||
if (verbose) { | ||
console.log("Emit finished!"); | ||
} | ||
return { diagnostics, emitSkipped: emitPlan.length === 0 }; | ||
@@ -35,4 +45,10 @@ } | ||
const options = program.getCompilerOptions(); | ||
if (options.tstlVerbose) { | ||
console.log("Constructing emit plan"); | ||
} | ||
const lualibRequired = files.some(f => f.code.includes('require("lualib_bundle")')); | ||
if (lualibRequired) { | ||
if (options.tstlVerbose) { | ||
console.log("Including lualib bundle"); | ||
} | ||
// Add lualib bundle to source dir 'virtually', will be moved to correct output dir in emitPlan | ||
@@ -39,0 +55,0 @@ const fileName = utils_1.normalizeSlashes(path.resolve(getSourceDir(program), "lualib_bundle.lua")); |
{ | ||
"name": "typescript-to-lua", | ||
"version": "0.40.1", | ||
"version": "0.41.0", | ||
"description": "A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!", | ||
@@ -67,3 +67,3 @@ "repository": "https://github.com/TypeScriptToLua/TypeScriptToLua", | ||
"lua-wasm-bindings": "^0.2.2", | ||
"prettier": "^2.0.5", | ||
"prettier": "^2.3.2", | ||
"ts-jest": "^26.3.0", | ||
@@ -70,0 +70,0 @@ "ts-node": "^8.6.2" |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
741264
295
11307