typescript-to-lua
Advanced tools
Comparing version 0.16.1 to 0.17.0
@@ -5,3 +5,3 @@ # Changelog | ||
* **BREAKING CHANGE:** All functions now take a `self` parameter. This means that without further action calls to declaration functions might be given an extra argument. | ||
* To remove the self parameter from a single function add `this: void` to its declaration: | ||
* To remove the self parameter from a single function add `this: void` to its declaration: | ||
```declare function foo(this: void, ...)``` | ||
@@ -13,3 +13,3 @@ * To remove the self parameter from all methods or functions in a class/interface/namespace add `/** @noSelf */`: | ||
--- | ||
* **BREAKING CHANGE:** Directive `/** @luaIterator */` should now be put on types instead of on the functions returning them. | ||
@@ -87,3 +87,3 @@ | ||
## 0.13.0 | ||
* Reworked how functions are transpiled, see https://github.com/Perryvw/TypescriptToLua/wiki/Differences-Between-Functions-and-Methods | ||
* Reworked how functions are transpiled, see https://github.com/TypeScriptToLua/TypescriptToLua/wiki/Differences-Between-Functions-and-Methods | ||
* Improved handling of types extending Array. | ||
@@ -95,3 +95,3 @@ * Fixed several bugs with classes. | ||
* Added detection of types extending Array. | ||
* Added new JSDoc-style compiler directives, deprecated the old `!` decorators, see https://github.com/Perryvw/TypescriptToLua/wiki/Compiler-Directives | ||
* Added new JSDoc-style compiler directives, deprecated the old `!` decorators, see https://github.com/TypeScriptToLua/TypescriptToLua/wiki/Compiler-Directives | ||
* Fixed bug with constructor default values. | ||
@@ -98,0 +98,0 @@ * The Lualib is no longer included when not used. |
@@ -31,2 +31,7 @@ "use strict"; | ||
}, | ||
sourceMapTraceback: { | ||
default: false, | ||
describe: "Applies the source map to show source TS files and lines in error tracebacks.", | ||
type: "boolean", | ||
}, | ||
}; | ||
@@ -33,0 +38,0 @@ exports.version = require("../package.json").version; |
import * as ts from "typescript"; | ||
import { CompilerOptions } from "./CompilerOptions"; | ||
import { TranspileResult } from "./LuaTranspiler"; | ||
export declare function compile(argv: string[]): void; | ||
@@ -11,2 +12,2 @@ export declare function watchWithOptions(fileNames: string[], options: CompilerOptions): void; | ||
[filename: string]: string; | ||
}, options?: CompilerOptions, ignoreDiagnostics?: boolean, filePath?: string): string; | ||
}, options?: CompilerOptions, ignoreDiagnostics?: boolean, filePath?: string): TranspileResult; |
@@ -112,3 +112,3 @@ "use strict"; | ||
getCurrentDirectory: () => "", | ||
getDefaultLibFileName: () => "lib.es6.d.ts", | ||
getDefaultLibFileName: ts.getDefaultLibFileName, | ||
getDirectories: () => [], | ||
@@ -129,15 +129,10 @@ getNewLine: () => "\n", | ||
} | ||
if (filename.indexOf(".d.ts") !== -1) { | ||
if (!libCache[filename]) { | ||
const typeScriptDir = path.dirname(require.resolve("typescript")); | ||
const filePath = path.join(typeScriptDir, filename); | ||
if (fs.existsSync(filePath)) { | ||
libCache[filename] = fs.readFileSync(filePath).toString(); | ||
} | ||
else { | ||
const pathWithLibPrefix = path.join(typeScriptDir, "lib." + filename); | ||
libCache[filename] = fs.readFileSync(pathWithLibPrefix).toString(); | ||
} | ||
} | ||
return ts.createSourceFile(filename, libCache[filename], ts.ScriptTarget.Latest, false); | ||
if (filename.startsWith('lib.')) { | ||
if (libCache[filename]) | ||
return libCache[filename]; | ||
const typeScriptDir = path.dirname(require.resolve("typescript")); | ||
const filePath = path.join(typeScriptDir, filename); | ||
const content = fs.readFileSync(filePath, 'utf8'); | ||
libCache[filename] = ts.createSourceFile(filename, content, ts.ScriptTarget.Latest, false); | ||
return libCache[filename]; | ||
} | ||
@@ -166,6 +161,5 @@ return undefined; | ||
const transpiler = new LuaTranspiler_1.LuaTranspiler(program); | ||
const result = transpiler.transpileSourceFile(program.getSourceFile(filePath)); | ||
return result.trim(); | ||
return transpiler.transpileSourceFile(program.getSourceFile(filePath)); | ||
} | ||
exports.transpileString = transpileString; | ||
//# sourceMappingURL=Compiler.js.map |
@@ -7,2 +7,3 @@ import * as ts from "typescript"; | ||
noHoisting?: boolean; | ||
sourceMapTraceback?: boolean; | ||
} | ||
@@ -9,0 +10,0 @@ export declare enum LuaLibImportKind { |
export { parseCommandLine } from "./CommandLineParser"; | ||
export { compile, compileFilesWithOptions, transpileString, watchWithOptions } from "./Compiler"; | ||
export { CompilerOptions, LuaLibImportKind, LuaTarget, } from "./CompilerOptions"; | ||
export { LuaLibFeature, } from "./LuaLib"; | ||
export { LuaTranspiler, } from "./LuaTranspiler"; | ||
export { CompilerOptions, LuaLibImportKind, LuaTarget } from "./CompilerOptions"; | ||
export { LuaLibFeature } from "./LuaLib"; | ||
export { LuaTranspiler } from "./LuaTranspiler"; |
@@ -66,4 +66,4 @@ import * as ts from "typescript"; | ||
export interface TextRange { | ||
pos: number; | ||
end: number; | ||
line?: number; | ||
column?: number; | ||
} | ||
@@ -78,2 +78,3 @@ export interface Node extends TextRange { | ||
export declare function setParent(node: Node | Node[] | undefined, parent: Node): void; | ||
export declare function getOriginalPos(node: Node): TextRange; | ||
export interface Block extends Node { | ||
@@ -272,3 +273,3 @@ kind: SyntaxKind.Block; | ||
export declare function createIdentifier(text: string | ts.__String, tsOriginal?: ts.Node, symbolId?: SymbolId, parent?: Node): Identifier; | ||
export declare function cloneIdentifier(identifier: Identifier): Identifier; | ||
export declare function cloneIdentifier(identifier: Identifier, tsOriginal?: ts.Node): Identifier; | ||
export declare function createAnnonymousIdentifier(tsOriginal?: ts.Node, parent?: Node): Identifier; | ||
@@ -275,0 +276,0 @@ export interface TableIndexExpression extends Expression { |
@@ -5,2 +5,5 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// We can ellide a lot of nodes especially tokens and keyowords | ||
// becasue we dont create the AST from text | ||
const ts = require("typescript"); | ||
var SyntaxKind; | ||
@@ -75,9 +78,9 @@ (function (SyntaxKind) { | ||
function createNode(kind, tsOriginal, parent) { | ||
let pos = -1; | ||
let end = -1; | ||
if (tsOriginal) { | ||
pos = tsOriginal.pos; | ||
end = tsOriginal.end; | ||
const sourcePosition = getSourcePosition(tsOriginal); | ||
if (sourcePosition) { | ||
return { kind, parent, line: sourcePosition.line, column: sourcePosition.column }; | ||
} | ||
return { kind, parent, pos, end }; | ||
else { | ||
return { kind, parent }; | ||
} | ||
} | ||
@@ -90,4 +93,7 @@ exports.createNode = createNode; | ||
function setNodeOriginal(node, tsOriginal) { | ||
node.pos = tsOriginal.pos; | ||
node.end = tsOriginal.end; | ||
const sourcePosition = getSourcePosition(tsOriginal); | ||
if (sourcePosition) { | ||
node.line = sourcePosition.line; | ||
node.column = sourcePosition.column; | ||
} | ||
return node; | ||
@@ -103,6 +109,2 @@ } | ||
n.parent = parent; | ||
if (n.pos === -1 || n.end === -1) { | ||
n.pos = parent.pos; | ||
n.end = parent.end; | ||
} | ||
}); | ||
@@ -112,9 +114,18 @@ } | ||
node.parent = parent; | ||
if (node.pos === -1 || node.end === -1) { | ||
node.pos = parent.pos; | ||
node.end = parent.end; | ||
} | ||
} | ||
} | ||
exports.setParent = setParent; | ||
function getSourcePosition(sourceNode) { | ||
if (sourceNode !== undefined && sourceNode.getSourceFile() !== undefined && sourceNode.pos >= 0) { | ||
const { line, character } = ts.getLineAndCharacterOfPosition(sourceNode.getSourceFile(), sourceNode.pos + sourceNode.getLeadingTriviaWidth()); | ||
return { line, column: character }; | ||
} | ||
} | ||
function getOriginalPos(node) { | ||
while (node.line === undefined && node.parent !== undefined) { | ||
node = node.parent; | ||
} | ||
return { line: node.line, column: node.column }; | ||
} | ||
exports.getOriginalPos = getOriginalPos; | ||
function isBlock(node) { | ||
@@ -484,4 +495,4 @@ return node.kind === SyntaxKind.Block; | ||
exports.createIdentifier = createIdentifier; | ||
function cloneIdentifier(identifier) { | ||
return createIdentifier(identifier.text, undefined, identifier.symbolId); | ||
function cloneIdentifier(identifier, tsOriginal) { | ||
return createIdentifier(identifier.text, tsOriginal, identifier.symbolId); | ||
} | ||
@@ -488,0 +499,0 @@ exports.cloneIdentifier = cloneIdentifier; |
@@ -17,2 +17,4 @@ export declare enum LuaLibFeature { | ||
ArraySplice = "ArraySplice", | ||
ArrayFlat = "ArrayFlat", | ||
ArrayFlatMap = "ArrayFlatMap", | ||
ClassIndex = "ClassIndex", | ||
@@ -30,2 +32,3 @@ ClassNewIndex = "ClassNewIndex", | ||
ObjectEntries = "ObjectEntries", | ||
ObjectFromEntries = "ObjectFromEntries", | ||
ObjectKeys = "ObjectKeys", | ||
@@ -36,2 +39,3 @@ ObjectValues = "ObjectValues", | ||
WeakSet = "WeakSet", | ||
SourceMapTraceBack = "SourceMapTraceBack", | ||
StringReplace = "StringReplace", | ||
@@ -38,0 +42,0 @@ StringSplit = "StringSplit", |
@@ -22,2 +22,4 @@ "use strict"; | ||
LuaLibFeature["ArraySplice"] = "ArraySplice"; | ||
LuaLibFeature["ArrayFlat"] = "ArrayFlat"; | ||
LuaLibFeature["ArrayFlatMap"] = "ArrayFlatMap"; | ||
LuaLibFeature["ClassIndex"] = "ClassIndex"; | ||
@@ -35,2 +37,3 @@ LuaLibFeature["ClassNewIndex"] = "ClassNewIndex"; | ||
LuaLibFeature["ObjectEntries"] = "ObjectEntries"; | ||
LuaLibFeature["ObjectFromEntries"] = "ObjectFromEntries"; | ||
LuaLibFeature["ObjectKeys"] = "ObjectKeys"; | ||
@@ -41,2 +44,3 @@ LuaLibFeature["ObjectValues"] = "ObjectValues"; | ||
LuaLibFeature["WeakSet"] = "WeakSet"; | ||
LuaLibFeature["SourceMapTraceBack"] = "SourceMapTraceBack"; | ||
LuaLibFeature["StringReplace"] = "StringReplace"; | ||
@@ -49,3 +53,6 @@ LuaLibFeature["StringSplit"] = "StringSplit"; | ||
const luaLibDependencies = { | ||
ArrayFlat: [LuaLibFeature.ArrayConcat], | ||
ArrayFlatMap: [LuaLibFeature.ArrayConcat], | ||
Iterator: [LuaLibFeature.Symbol], | ||
ObjectFromEntries: [LuaLibFeature.Iterator, LuaLibFeature.Symbol], | ||
Map: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol], | ||
@@ -52,0 +59,0 @@ Set: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol], |
import * as tstl from "./LuaAST"; | ||
import { CompilerOptions } from "./CompilerOptions"; | ||
import { LuaLibFeature } from "./LuaLib"; | ||
import { CompilerOptions } from "./CompilerOptions"; | ||
export declare class LuaPrinter { | ||
@@ -8,7 +8,13 @@ private static operatorMap; | ||
private currentIndent; | ||
private sourceFile; | ||
constructor(options: CompilerOptions); | ||
print(block: tstl.Block, luaLibFeatures?: Set<LuaLibFeature>): string; | ||
print(block: tstl.Block, luaLibFeatures?: Set<LuaLibFeature>, sourceFile?: string): [string, string]; | ||
private printInlineSourceMap; | ||
private printStackTraceOverride; | ||
private printImplementation; | ||
private pushIndent; | ||
private popIndent; | ||
private indent; | ||
private createSourceNode; | ||
private concatNodes; | ||
private printBlock; | ||
@@ -48,2 +54,3 @@ private printStatement; | ||
private ignoreDeadStatements; | ||
private joinChunks; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const path = require("path"); | ||
const source_map_1 = require("source-map"); | ||
const tstl = require("./LuaAST"); | ||
const CompilerOptions_1 = require("./CompilerOptions"); | ||
const LuaLib_1 = require("./LuaLib"); | ||
const TSHelper_1 = require("./TSHelper"); | ||
const LuaLib_1 = require("./LuaLib"); | ||
const CompilerOptions_1 = require("./CompilerOptions"); | ||
class LuaPrinter { | ||
@@ -12,6 +14,54 @@ constructor(options) { | ||
} | ||
print(block, luaLibFeatures) { | ||
print(block, luaLibFeatures, sourceFile) { | ||
// Add traceback lualib if sourcemap traceback option is enabled | ||
if (this.options.sourceMapTraceback) { | ||
if (luaLibFeatures === undefined) { | ||
luaLibFeatures = new Set(); | ||
} | ||
luaLibFeatures.add(LuaLib_1.LuaLibFeature.SourceMapTraceBack); | ||
} | ||
const rootSourceNode = this.printImplementation(block, luaLibFeatures, sourceFile); | ||
const codeWithSourceMap = rootSourceNode | ||
// TODO is the file: part really required? and should this be handled in the printer? | ||
.toStringWithSourceMap({ file: path.basename(sourceFile, path.extname(sourceFile)) + ".lua" }); | ||
let codeResult = codeWithSourceMap.code; | ||
if (this.options.inlineSourceMap) { | ||
codeResult += "\n" + this.printInlineSourceMap(codeWithSourceMap.map); | ||
} | ||
if (this.options.sourceMapTraceback) { | ||
const stackTraceOverride = this.printStackTraceOverride(rootSourceNode); | ||
codeResult = codeResult.replace("{#SourceMapTraceback}", stackTraceOverride); | ||
} | ||
return [codeResult, codeWithSourceMap.map.toString()]; | ||
} | ||
printInlineSourceMap(sourceMap) { | ||
const map = sourceMap.toString(); | ||
const base64Map = Buffer.from(map).toString('base64'); | ||
return `//# sourceMappingURL=data:application/json;base64,${base64Map}\n`; | ||
} | ||
printStackTraceOverride(rootNode) { | ||
let line = 1; | ||
const map = {}; | ||
rootNode.walk((chunk, mappedPosition) => { | ||
if (mappedPosition.line !== undefined && mappedPosition.line > 0) { | ||
if (map[line] === undefined) { | ||
map[line] = mappedPosition.line; | ||
} | ||
else { | ||
map[line] = Math.min(map[line], mappedPosition.line); | ||
} | ||
} | ||
line += chunk.split("\n").length - 1; | ||
}); | ||
const mapItems = []; | ||
for (const lineNr in map) { | ||
mapItems.push(`["${lineNr}"] = ${map[lineNr]}`); | ||
} | ||
const mapString = "{" + mapItems.join(",") + "}"; | ||
return `__TS__SourceMapTraceBack(debug.getinfo(1).short_src, ${mapString});`; | ||
} | ||
printImplementation(block, luaLibFeatures, sourceFile) { | ||
let header = ""; | ||
if (this.options.noHeader === undefined || this.options.noHeader === false) { | ||
header += `--[[ Generated with https://github.com/Perryvw/TypescriptToLua ]]\n`; | ||
header += `--[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]\n`; | ||
} | ||
@@ -30,3 +80,8 @@ if (luaLibFeatures) { | ||
} | ||
return header + this.printBlock(block); | ||
this.sourceFile = path.basename(sourceFile); | ||
if (this.options.sourceMapTraceback) { | ||
header += "{#SourceMapTraceback}\n"; | ||
} | ||
const fileBlockNode = this.createSourceNode(block, this.printBlock(block)); | ||
return this.concatNodes(header, fileBlockNode); | ||
} | ||
@@ -39,7 +94,16 @@ pushIndent() { | ||
} | ||
indent(input) { | ||
return this.currentIndent + input; | ||
indent(input = "") { | ||
return this.concatNodes(this.currentIndent, input); | ||
} | ||
createSourceNode(node, chunks) { | ||
const originalPos = tstl.getOriginalPos(node); | ||
return originalPos !== undefined | ||
? new source_map_1.SourceNode(originalPos.line + 1, originalPos.column, this.sourceFile, chunks) | ||
: new source_map_1.SourceNode(undefined, undefined, this.sourceFile, chunks); | ||
} | ||
concatNodes(...chunks) { | ||
return new source_map_1.SourceNode(undefined, undefined, this.sourceFile, chunks); | ||
} | ||
printBlock(block) { | ||
return this.ignoreDeadStatements(block.statements).map(s => this.printStatement(s)).join(""); | ||
return this.createSourceNode(block, this.ignoreDeadStatements(block.statements).map(s => this.printStatement(s))); | ||
} | ||
@@ -74,63 +138,76 @@ printStatement(statement) { | ||
return this.printExpressionStatement(statement); | ||
default: | ||
throw new Error(`Tried to print unknown statement kind: ${tstl.SyntaxKind[statement.kind]}`); | ||
} | ||
} | ||
printDoStatement(statement) { | ||
let result = this.indent("do\n"); | ||
const chunks = []; | ||
chunks.push(this.indent("do\n")); | ||
this.pushIndent(); | ||
result += this.ignoreDeadStatements(statement.statements).map(s => this.printStatement(s)).join(""); | ||
chunks.push(...this.ignoreDeadStatements(statement.statements).map(s => this.printStatement(s))); | ||
this.popIndent(); | ||
result += this.indent("end\n"); | ||
return result; | ||
chunks.push(this.indent("end\n")); | ||
return this.concatNodes(...chunks); | ||
} | ||
printVariableDeclarationStatement(statement) { | ||
const left = this.indent(`local ${statement.left.map(e => this.printExpression(e)).join(", ")}`); | ||
const chunks = []; | ||
chunks.push(this.indent("local ")); | ||
chunks.push(...this.joinChunks(", ", statement.left.map(e => this.printExpression(e)))); | ||
if (statement.right) { | ||
return left + ` = ${statement.right.map(e => this.printExpression(e)).join(", ")};\n`; | ||
chunks.push(" = "); | ||
chunks.push(...this.joinChunks(", ", statement.right.map(e => this.printExpression(e)))); | ||
} | ||
else { | ||
return left + ";\n"; | ||
} | ||
chunks.push(";\n"); | ||
return this.concatNodes(...chunks); | ||
} | ||
printVariableAssignmentStatement(statement) { | ||
return this.indent(`${statement.left.map(e => this.printExpression(e)).join(", ")} = ` + | ||
`${statement.right.map(e => this.printExpression(e)).join(", ")};\n`); | ||
const chunks = []; | ||
chunks.push(this.indent()); | ||
chunks.push(...this.joinChunks(", ", statement.left.map(e => this.printExpression(e)))); | ||
chunks.push(" = "); | ||
chunks.push(...this.joinChunks(", ", statement.right.map(e => this.printExpression(e)))); | ||
chunks.push(";\n"); | ||
return this.createSourceNode(statement, chunks); | ||
} | ||
printIfStatement(statement, isElseIf) { | ||
const chunks = []; | ||
const prefix = isElseIf ? "elseif" : "if"; | ||
let result = this.indent(`${prefix} ${this.printExpression(statement.condtion)} then\n`); | ||
chunks.push(this.indent(prefix + " "), this.printExpression(statement.condtion), " then\n"); | ||
this.pushIndent(); | ||
result += this.printBlock(statement.ifBlock); | ||
chunks.push(this.printBlock(statement.ifBlock)); | ||
this.popIndent(); | ||
if (statement.elseBlock) { | ||
if (tstl.isIfStatement(statement.elseBlock)) { | ||
result += this.printIfStatement(statement.elseBlock, true); | ||
chunks.push(this.printIfStatement(statement.elseBlock, true)); | ||
} | ||
else { | ||
result += this.indent("else\n"); | ||
chunks.push(this.indent("else\n")); | ||
this.pushIndent(); | ||
result += this.printBlock(statement.elseBlock); | ||
chunks.push(this.printBlock(statement.elseBlock)); | ||
this.popIndent(); | ||
result += this.indent("end\n"); | ||
chunks.push(this.indent("end\n")); | ||
} | ||
} | ||
else { | ||
result += this.indent("end\n"); | ||
chunks.push(this.indent("end\n")); | ||
} | ||
return result; | ||
return this.concatNodes(...chunks); | ||
} | ||
printWhileStatement(statement) { | ||
let result = this.indent(`while ${this.printExpression(statement.condtion)} do\n`); | ||
const chunks = []; | ||
chunks.push(this.indent("while "), this.printExpression(statement.condtion), " do\n"); | ||
this.pushIndent(); | ||
result += this.printBlock(statement.body); | ||
chunks.push(this.printBlock(statement.body)); | ||
this.popIndent(); | ||
result += this.indent("end\n"); | ||
return result; | ||
chunks.push(this.indent("end\n")); | ||
return this.concatNodes(...chunks); | ||
} | ||
printRepeatStatement(statement) { | ||
let result = this.indent(`repeat\n`); | ||
const chunks = []; | ||
chunks.push(this.indent(`repeat\n`)); | ||
this.pushIndent(); | ||
result += this.printBlock(statement.body); | ||
chunks.push(this.printBlock(statement.body)); | ||
this.popIndent(); | ||
result += this.indent(`until ${this.printExpression(statement.condtion)};\n`); | ||
return result; | ||
chunks.push(this.indent("until "), this.printExpression(statement.condtion), ";\n"); | ||
return this.concatNodes(...chunks); | ||
} | ||
@@ -141,13 +218,13 @@ printForStatement(statement) { | ||
const limit = this.printExpression(statement.limitExpression); | ||
let result = this.indent(`for ${ctrlVar} = ${ctrlVarInit}, ${limit}`); | ||
const chunks = []; | ||
chunks.push(this.indent("for "), ctrlVar, " = ", ctrlVarInit, ", ", limit); | ||
if (statement.stepExpression) { | ||
const step = this.printExpression(statement.stepExpression); | ||
result += `, ${step}`; | ||
chunks.push(", ", this.printExpression(statement.stepExpression)); | ||
} | ||
result += ` do\n`; | ||
chunks.push(" do\n"); | ||
this.pushIndent(); | ||
result += this.printBlock(statement.body); | ||
chunks.push(this.printBlock(statement.body)); | ||
this.popIndent(); | ||
result += this.indent("end\n"); | ||
return result; | ||
chunks.push(this.indent("end\n")); | ||
return this.concatNodes(...chunks); | ||
} | ||
@@ -157,26 +234,30 @@ printForInStatement(statement) { | ||
const expressions = statement.expressions.map(e => this.printExpression(e)).join(", "); | ||
let result = this.indent(`for ${names} in ${expressions} do\n`); | ||
const chunks = []; | ||
chunks.push(this.indent("for "), names, " in ", expressions, " do\n"); | ||
this.pushIndent(); | ||
result += this.printBlock(statement.body); | ||
chunks.push(this.printBlock(statement.body)); | ||
this.popIndent(); | ||
result += this.indent("end\n"); | ||
return result; | ||
chunks.push(this.indent("end\n")); | ||
return this.createSourceNode(statement, chunks); | ||
} | ||
printGotoStatement(statement) { | ||
return this.indent(`goto ${statement.label};\n`); | ||
return this.createSourceNode(statement, [this.indent("goto "), statement.label, ";\n"]); | ||
} | ||
printLabelStatement(statement) { | ||
return this.indent(`::${statement.name}::\n`); | ||
return this.createSourceNode(statement, [this.indent("::"), statement.name, "::\n"]); | ||
} | ||
printReturnStatement(statement) { | ||
if (!statement.expressions) { | ||
return this.indent(`return;\n`); | ||
if (!statement.expressions || statement.expressions.length === 0) { | ||
return this.createSourceNode(statement, this.indent("return;\n")); | ||
} | ||
return this.indent(`return ${statement.expressions.map(e => this.printExpression(e)).join(", ")};\n`); | ||
const chunks = []; | ||
chunks.push(...this.joinChunks(", ", statement.expressions.map(e => this.printExpression(e)))); | ||
chunks.push(";\n"); | ||
return this.createSourceNode(statement, [this.indent(), "return ", ...chunks]); | ||
} | ||
printBreakStatement(statement) { | ||
return this.indent("break;\n"); | ||
return this.createSourceNode(statement, this.indent("break;\n")); | ||
} | ||
printExpressionStatement(statement) { | ||
return this.indent(`${this.printExpression(statement.expression)};\n`); | ||
return this.concatNodes(this.indent(), this.printExpression(statement.expression), ";\n"); | ||
} | ||
@@ -217,72 +298,102 @@ // Expressions | ||
return this.printTableIndexExpression(expression); | ||
default: | ||
throw new Error(`Tried to print unknown statement kind: ${tstl.SyntaxKind[expression.kind]}`); | ||
} | ||
} | ||
printStringLiteral(expression) { | ||
return `"${expression.value}"`; | ||
return this.createSourceNode(expression, `"${expression.value}"`); | ||
} | ||
printNumericLiteral(expression) { | ||
return `${expression.value}`; | ||
return this.createSourceNode(expression, String(expression.value)); | ||
} | ||
printNilLiteral(expression) { | ||
return "nil"; | ||
return this.createSourceNode(expression, "nil"); | ||
} | ||
printDotsLiteral(expression) { | ||
return "..."; | ||
return this.createSourceNode(expression, "..."); | ||
} | ||
printBooleanLiteral(expression) { | ||
if (expression.kind === tstl.SyntaxKind.TrueKeyword) { | ||
return "true"; | ||
return this.createSourceNode(expression, "true"); | ||
} | ||
else { | ||
return "false"; | ||
return this.createSourceNode(expression, "false"); | ||
} | ||
} | ||
printFunctionExpression(expression) { | ||
const paramterArr = expression.params ? expression.params.map(i => this.printIdentifier(i)) : []; | ||
const parameterChunks = expression.params | ||
? expression.params.map(i => this.printIdentifier(i)) | ||
: []; | ||
if (expression.dots) { | ||
paramterArr.push(this.printDotsLiteral(expression.dots)); | ||
parameterChunks.push(this.printDotsLiteral(expression.dots)); | ||
} | ||
let result = `function(${paramterArr.join(", ")})\n`; | ||
const chunks = []; | ||
chunks.push("function("); | ||
chunks.push(...this.joinChunks(", ", parameterChunks)); | ||
chunks.push(")\n"); | ||
this.pushIndent(); | ||
result += this.printBlock(expression.body); | ||
chunks.push(this.printBlock(expression.body)); | ||
this.popIndent(); | ||
result += this.indent("end"); | ||
return result; | ||
chunks.push(this.indent("end")); | ||
return this.createSourceNode(expression, chunks); | ||
} | ||
printTableFieldExpression(expression) { | ||
const chunks = []; | ||
const value = this.printExpression(expression.value); | ||
if (expression.key) { | ||
if (tstl.isStringLiteral(expression.key) && TSHelper_1.TSHelper.isValidLuaIdentifier(expression.key.value)) { | ||
return `${expression.key.value} = ${value}`; | ||
chunks.push(expression.key.value, " = ", value); | ||
} | ||
else { | ||
return `[${this.printExpression(expression.key)}] = ${value}`; | ||
chunks.push("[", this.printExpression(expression.key), "] = ", value); | ||
} | ||
} | ||
else { | ||
return value; | ||
chunks.push(value); | ||
} | ||
return this.createSourceNode(expression, chunks); | ||
} | ||
printTableExpression(expression) { | ||
let fields = ""; | ||
const chunks = []; | ||
chunks.push("{"); | ||
if (expression.fields) { | ||
fields = expression.fields.map(f => this.printTableFieldExpression(f)).join(", "); | ||
expression.fields.forEach((f, i) => { | ||
if (i < expression.fields.length - 1) { | ||
chunks.push(this.printTableFieldExpression(f), ", "); | ||
} | ||
else { | ||
chunks.push(this.printTableFieldExpression(f)); | ||
} | ||
}); | ||
} | ||
return `{${fields}}`; | ||
chunks.push("}"); | ||
return this.createSourceNode(expression, chunks); | ||
} | ||
printUnaryExpression(expression) { | ||
const operand = this.needsParentheses(expression.operand) | ||
? `(${this.printExpression(expression.operand)})` | ||
: this.printExpression(expression.operand); | ||
return `${this.printOperator(expression.operator)}${operand}`; | ||
const chunks = []; | ||
chunks.push(this.printOperator(expression.operator)); | ||
if (this.needsParentheses(expression.operand)) { | ||
chunks.push("(", this.printExpression(expression.operand), ")"); | ||
} | ||
else { | ||
chunks.push(this.printExpression(expression.operand)); | ||
} | ||
return this.createSourceNode(expression, chunks); | ||
} | ||
printBinaryExpression(expression) { | ||
const left = this.needsParentheses(expression.left) | ||
? `(${this.printExpression(expression.left)})` | ||
: this.printExpression(expression.left); | ||
const right = this.needsParentheses(expression.right) | ||
? `(${this.printExpression(expression.right)})` | ||
: this.printExpression(expression.right); | ||
const operator = this.printOperator(expression.operator); | ||
return `${left} ${operator} ${right}`; | ||
const chunks = []; | ||
if (this.needsParentheses(expression.left)) { | ||
chunks.push("(", this.printExpression(expression.left), ")"); | ||
} | ||
else { | ||
chunks.push(this.printExpression(expression.left)); | ||
} | ||
chunks.push(" ", this.printOperator(expression.operator), " "); | ||
if (this.needsParentheses(expression.right)) { | ||
chunks.push("(", this.printExpression(expression.right), ")"); | ||
} | ||
else { | ||
chunks.push(this.printExpression(expression.right)); | ||
} | ||
return this.createSourceNode(expression, chunks); | ||
} | ||
@@ -294,25 +405,34 @@ needsParentheses(expression) { | ||
printParenthesizedExpression(expression) { | ||
return `(${this.printExpression(expression.innerEpxression)})`; | ||
return this.createSourceNode(expression, ["(", this.printExpression(expression.innerEpxression), ")"]); | ||
} | ||
printCallExpression(expression) { | ||
const params = expression.params ? expression.params.map(e => this.printExpression(e)).join(", ") : ""; | ||
return this.needsParentheses(expression.expression) | ||
? `(${this.printExpression(expression.expression)})(${params})` | ||
: `${this.printExpression(expression.expression)}(${params})`; | ||
const chunks = []; | ||
const parameterChunks = this.joinChunks(", ", expression.params.map(e => this.printExpression(e))); | ||
if (this.needsParentheses(expression.expression)) { | ||
chunks.push("(", this.printExpression(expression.expression), ")(", ...parameterChunks, ")"); | ||
} | ||
else { | ||
chunks.push(this.printExpression(expression.expression), "(", ...parameterChunks, ")"); | ||
} | ||
return this.concatNodes(...chunks); | ||
} | ||
printMethodCallExpression(expression) { | ||
const params = expression.params.map(e => this.printExpression(e)).join(", "); | ||
const prefix = this.printExpression(expression.prefixExpression); | ||
const parameterChunks = this.joinChunks(", ", expression.params.map(e => this.printExpression(e))); | ||
const name = this.printIdentifier(expression.name); | ||
return `${prefix}:${name}(${params})`; | ||
return this.concatNodes(prefix, ":", name, "(", ...parameterChunks, ")"); | ||
} | ||
printIdentifier(expression) { | ||
return expression.text; | ||
return this.createSourceNode(expression, expression.text); | ||
} | ||
printTableIndexExpression(expression) { | ||
const table = this.printExpression(expression.table); | ||
const chunks = []; | ||
chunks.push(this.printExpression(expression.table)); | ||
if (tstl.isStringLiteral(expression.index) && TSHelper_1.TSHelper.isValidLuaIdentifier(expression.index.value)) { | ||
return `${table}.${expression.index.value}`; | ||
chunks.push(".", this.createSourceNode(expression.index, expression.index.value)); | ||
} | ||
return `${table}[${this.printExpression(expression.index)}]`; | ||
else { | ||
chunks.push("[", this.printExpression(expression.index), "]"); | ||
} | ||
return this.createSourceNode(expression, chunks); | ||
} | ||
@@ -332,2 +452,12 @@ printOperator(kind) { | ||
} | ||
joinChunks(separator, chunks) { | ||
const result = []; | ||
for (let i = 0; i < chunks.length; i++) { | ||
result.push(chunks[i]); | ||
if (i < chunks.length - 1) { | ||
result.push(separator); | ||
} | ||
} | ||
return result; | ||
} | ||
} | ||
@@ -334,0 +464,0 @@ /* tslint:disable:object-literal-sort-keys */ |
import * as ts from "typescript"; | ||
import * as tstl from "./LuaAST"; | ||
export interface TranspileResult { | ||
lua: string; | ||
luaAST: tstl.Node; | ||
sourceMap: string; | ||
} | ||
export declare class LuaTranspiler { | ||
@@ -14,5 +19,4 @@ private program; | ||
emitSourceFile(sourceFile: ts.SourceFile): number; | ||
transpileSourceFile(sourceFile: ts.SourceFile): string; | ||
transpileSourceFileKeepAST(sourceFile: ts.SourceFile): [tstl.Block, string]; | ||
transpileSourceFile(sourceFile: ts.SourceFile): TranspileResult; | ||
reportDiagnostic(diagnostic: ts.Diagnostic): void; | ||
} |
@@ -67,3 +67,3 @@ "use strict"; | ||
const rootDir = this.options.rootDir; | ||
const lua = this.transpileSourceFile(sourceFile); | ||
const { lua, luaAST, sourceMap } = this.transpileSourceFile(sourceFile); | ||
let outPath = sourceFile.fileName; | ||
@@ -90,2 +90,5 @@ if (this.options.outDir !== this.options.rootDir) { | ||
ts.sys.writeFile(outPath, lua); | ||
if (this.options.sourceMap) { | ||
ts.sys.writeFile(outPath + ".map", sourceMap); | ||
} | ||
} | ||
@@ -112,10 +115,5 @@ catch (exception) { | ||
// Print AST | ||
return this.luaPrinter.print(luaAST, lualibFeatureSet); | ||
const [lua, sourceMap] = this.luaPrinter.print(luaAST, lualibFeatureSet, sourceFile.fileName); | ||
return { lua, luaAST, sourceMap }; | ||
} | ||
transpileSourceFileKeepAST(sourceFile) { | ||
// Transform AST | ||
const [luaAST, lualibFeatureSet] = this.luaTransformer.transformSourceFile(sourceFile); | ||
// Print AST | ||
return [luaAST, this.luaPrinter.print(luaAST, lualibFeatureSet)]; | ||
} | ||
reportDiagnostic(diagnostic) { | ||
@@ -122,0 +120,0 @@ if (diagnostic.file) { |
import * as ts from "typescript"; | ||
export declare class TranspileError extends Error { | ||
node: ts.Node; | ||
name: string; | ||
constructor(message: string, node: ts.Node); | ||
} |
@@ -7,2 +7,3 @@ "use strict"; | ||
this.node = node; | ||
this.name = 'TranspileError'; | ||
} | ||
@@ -9,0 +10,0 @@ } |
@@ -29,5 +29,6 @@ import * as ts from "typescript"; | ||
static getContainingFunctionReturnType(node: ts.Node, checker: ts.TypeChecker): ts.Type; | ||
static collectCustomDecorators(symbol: ts.Symbol, checker: ts.TypeChecker, decMap: Map<DecoratorKind, Decorator>): void; | ||
static collectCustomDecorators(source: ts.Symbol | ts.Signature, checker: ts.TypeChecker, decMap: Map<DecoratorKind, Decorator>): void; | ||
static getCustomDecorators(type: ts.Type, checker: ts.TypeChecker): Map<DecoratorKind, Decorator>; | ||
static getCustomFileDirectives(file: ts.SourceFile): Map<DecoratorKind, Decorator>; | ||
static getCustomSignatureDirectives(signature: ts.Signature, checker: ts.TypeChecker): Map<DecoratorKind, Decorator>; | ||
static findFirstNodeAbove<T extends ts.Node>(node: ts.Node, callback: (n: ts.Node) => n is T): T; | ||
@@ -34,0 +35,0 @@ static isBinaryAssignmentToken(token: ts.SyntaxKind): [boolean, ts.BinaryOperator]; |
@@ -29,2 +29,4 @@ "use strict"; | ||
"join", | ||
"flat", | ||
"flatMap", | ||
]); | ||
@@ -151,2 +153,16 @@ const defaultArrayPropertyNames = new Set([ | ||
if (ts.isCallExpression(node)) { | ||
const signature = checker.getResolvedSignature(node); | ||
if (signature) { | ||
if (TSHelper.getCustomSignatureDirectives(signature, checker).has(Decorator_1.DecoratorKind.TupleReturn)) { | ||
return true; | ||
} | ||
// Only check function type for directive if it is declared as an interface or type alias | ||
const declaration = signature.getDeclaration(); | ||
const isInterfaceOrAlias = declaration && declaration.parent | ||
&& ((ts.isInterfaceDeclaration(declaration.parent) && ts.isCallSignatureDeclaration(declaration)) | ||
|| ts.isTypeAliasDeclaration(declaration.parent)); | ||
if (!isInterfaceOrAlias) { | ||
return false; | ||
} | ||
} | ||
const type = checker.getTypeAtLocation(node.expression); | ||
@@ -169,2 +185,7 @@ return TSHelper.getCustomDecorators(type, checker).has(Decorator_1.DecoratorKind.TupleReturn); | ||
} | ||
// Check all overloads for directive | ||
const signatures = functionType.getCallSignatures(); | ||
if (signatures && signatures.some(s => TSHelper.getCustomSignatureDirectives(s, checker).has(Decorator_1.DecoratorKind.TupleReturn))) { | ||
return true; | ||
} | ||
const decorators = TSHelper.getCustomDecorators(functionType, checker); | ||
@@ -185,4 +206,4 @@ return decorators.has(Decorator_1.DecoratorKind.TupleReturn); | ||
} | ||
static collectCustomDecorators(symbol, checker, decMap) { | ||
const comments = symbol.getDocumentationComment(checker); | ||
static collectCustomDecorators(source, checker, decMap) { | ||
const comments = source.getDocumentationComment(checker); | ||
const decorators = comments.filter(comment => comment.kind === "text") | ||
@@ -205,3 +226,3 @@ .map(comment => comment.text.split("\n")) | ||
}); | ||
symbol.getJsDocTags().forEach(tag => { | ||
source.getJsDocTags().forEach(tag => { | ||
if (Decorator_1.Decorator.isValid(tag.name)) { | ||
@@ -237,2 +258,7 @@ const dec = new Decorator_1.Decorator(tag.name, tag.text ? tag.text.split(" ") : []); | ||
} | ||
static getCustomSignatureDirectives(signature, checker) { | ||
const directivesMap = new Map(); | ||
TSHelper.collectCustomDecorators(signature, checker, directivesMap); | ||
return directivesMap; | ||
} | ||
// Search up until finding a node satisfying the callback | ||
@@ -239,0 +265,0 @@ static findFirstNodeAbove(node, callback) { |
{ | ||
"name": "typescript-to-lua", | ||
"version": "0.17.0", | ||
"description": "A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!", | ||
"repository": "https://github.com/TypeScriptToLua/TypeScriptToLua", | ||
"license": "MIT", | ||
"version": "0.16.1", | ||
"repository": "https://github.com/Perryvw/TypescriptToLua", | ||
"keywords": [ | ||
@@ -22,16 +23,13 @@ "typescript", | ||
"build-lualib": "ts-node ./build_lualib.ts", | ||
"pretest": "npm run clean && npm run style-check && npm run build && tsc -p ./test/tsconfig.json", | ||
"test": "node ./test/runner.js", | ||
"posttest": "npm run clean", | ||
"coverage": "nyc --source-map=true npm test && nyc report --reporter=text-lcov > coverage.lcov", | ||
"coverage-html": "nyc --source-map=true npm test && nyc report --reporter=html", | ||
"test-threaded": "npm run pretest && node ./test/threaded_runner.js && npm run posttest", | ||
"test-fast": "npm run pretest && node ./test/runner.js --ignoreDiagnostics && npm run posttest", | ||
"clean": "rimraf \"src/**/*.js\" \"src/**/*.js.map\" \"test/**/*.js\" \"test/**/*.js.map\" \"test/compiler/testfiles/*.lua\"", | ||
"pretest": "ts-node --transpile-only ./build_lualib.ts", | ||
"test": "jest", | ||
"lint": "npm run lint:tslint && npm run lint:prettier", | ||
"lint:prettier": "prettier --check **/*.{js,ts,yml,json} || (echo 'Run `npm run fix:prettier` to fix it.' && exit 1)", | ||
"lint:tslint": "tslint -p . && tslint -p test && tslint src/lualib/*.ts", | ||
"fix:prettier": "prettier --check --write **/*.{js,ts,yml,json}", | ||
"release-major": "npm version major", | ||
"release-minor": "npm version minor", | ||
"release-patch": "npm version patch", | ||
"release-minor": "npm version minor", | ||
"release-major": "npm version major", | ||
"preversion": "npm run build && npm test", | ||
"postversion": "git push && git push --tags", | ||
"style-check": "tslint -p . && tslint -c ./tslint.json src/lualib/*.ts" | ||
"postversion": "git push && git push --tags" | ||
}, | ||
@@ -41,14 +39,2 @@ "bin": { | ||
}, | ||
"nyc": { | ||
"all": true, | ||
"extension": [ | ||
".ts" | ||
], | ||
"include": [ | ||
"src/**/*" | ||
], | ||
"exclude": [ | ||
"src/lualib/*" | ||
] | ||
}, | ||
"engines": { | ||
@@ -58,2 +44,3 @@ "node": ">=8.5.0" | ||
"dependencies": { | ||
"source-map": "^0.7.3", | ||
"typescript": "^3.3.1" | ||
@@ -63,12 +50,11 @@ }, | ||
"@types/glob": "^5.0.35", | ||
"@types/jest": "^24.0.11", | ||
"@types/node": "^9.6.23", | ||
"alsatian": "^2.3.0", | ||
"codecov": "^3.2.0", | ||
"deep-equal": "^1.0.1", | ||
"fengari": "^0.1.2", | ||
"flatted": "^2.0.0", | ||
"glob": "^7.1.2", | ||
"nyc": "^13.3.0", | ||
"jest": "^24.5.0", | ||
"jest-circus": "^24.5.0", | ||
"prettier": "^1.16.4", | ||
"rimraf": "^2.6.3", | ||
"threads": "^0.12.0", | ||
"ts-jest": "^24.0.0", | ||
"ts-node": "^7.0.0", | ||
@@ -75,0 +61,0 @@ "tslint": "^5.10.0" |
@@ -41,11 +41,12 @@ <div align="center"> | ||
**Example tsconfig.json** | ||
``` | ||
```json | ||
{ | ||
"compilerOptions": { | ||
"noImplicitAny" : true, | ||
"noImplicitThis" : true, | ||
"alwaysStrict" : true, | ||
"strictNullChecks": true | ||
"target": "esnext", | ||
"lib": ["es2015", "es2016", "es2017", "es2018", "esnext"], | ||
"strict": true | ||
}, | ||
"luaTarget": "JIT" | ||
"tstl": { | ||
"luaTarget": "JIT" | ||
} | ||
} | ||
@@ -52,0 +53,0 @@ ``` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
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
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
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
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
398622
12
74
6452
88
2
+ Addedsource-map@^0.7.3
+ Addedsource-map@0.7.4(transitive)