From 9746a0495df6a3396945ac9b4c94a8c1802167eb Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 23 Mar 2019 20:46:21 +0100 Subject: [PATCH 01/11] Added override for traceback --- src/CommandLineParser.ts | 5 ++ src/CompilerOptions.ts | 1 + src/LuaLib.ts | 1 + src/LuaPrinter.ts | 50 +++++++++++++++---- src/lualib/SourceMapTraceBack.ts | 25 +++++++--- src/lualib/string.d.ts | 3 +- .../configuration/mixed/index.spec.ts | 1 + 7 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/CommandLineParser.ts b/src/CommandLineParser.ts index 2286bfae8..f0b8cf1fc 100644 --- a/src/CommandLineParser.ts +++ b/src/CommandLineParser.ts @@ -53,6 +53,11 @@ const optionDeclarations: {[key: string]: CLIOption} = { describe: "Disables hoisting.", type: "boolean", } as CLIOption, + sourceMapTraceBack: { + default: false, + describe: "Applies the source map to show source TS files and lines in error tracebacks.", + type: "boolean", + } as CLIOption, }; export const { version } = require("../package.json"); diff --git a/src/CompilerOptions.ts b/src/CompilerOptions.ts index 24fae4374..f1ba8d713 100644 --- a/src/CompilerOptions.ts +++ b/src/CompilerOptions.ts @@ -5,6 +5,7 @@ export interface CompilerOptions extends ts.CompilerOptions { luaTarget?: LuaTarget; luaLibImport?: LuaLibImportKind; noHoisting?: boolean; + sourceMapTraceBack?: boolean; } export enum LuaLibImportKind { diff --git a/src/LuaLib.ts b/src/LuaLib.ts index 3db60196c..c5614bc10 100644 --- a/src/LuaLib.ts +++ b/src/LuaLib.ts @@ -34,6 +34,7 @@ export enum LuaLibFeature { Set = "Set", WeakMap = "WeakMap", WeakSet = "WeakSet", + SourceMapTraceBack = "SourceMapTraceBack", StringReplace = "StringReplace", StringSplit = "StringSplit", StringConcat = "StringConcat", diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index a860209c5..9ed34d679 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -53,6 +53,14 @@ export class LuaPrinter { } public print(block: tstl.Block, luaLibFeatures?: Set, sourceFile?: string): string { + // Add traceback lualib if sourcemap traceback option is enabled + if (this.options.sourceMapTraceBack) { + if (luaLibFeatures === undefined) { + luaLibFeatures = new Set(); + } + luaLibFeatures.add(LuaLibFeature.SourceMapTraceBack); + } + if (this.options.inlineSourceMap === true) { const rootSourceNode = this.printImplementation(block, luaLibFeatures, sourceFile); @@ -60,11 +68,7 @@ export class LuaPrinter { // 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 inlineSourceMap = this.printInlineSourceMap(codeWithMap.map); - - // TODO: Put this behind a compiler option? - const stackTraceOverride = this.printStackTraceOverride(rootSourceNode); - inlineSourceMap = stackTraceOverride + inlineSourceMap; + const inlineSourceMap = this.printInlineSourceMap(codeWithMap.map); return codeWithMap.code + "\n" + inlineSourceMap; } else { @@ -95,7 +99,7 @@ export class LuaPrinter { private printStackTraceOverride(rootNode: SourceNode): string { let line = 1; - const map = {}; + const map: {[line: number]: number} = {}; rootNode.walk((chunk, mappedPosition) => { if (mappedPosition.line !== undefined && mappedPosition.line > 0) { if (map[line] === undefined) { @@ -106,8 +110,15 @@ export class LuaPrinter { } line += chunk.split("\n").length - 1; }); - console.log(map); - return ""; + + const mapItems = []; + for (const lineNr in map) { + mapItems.push(`["${lineNr}"] = ${map[lineNr]}`); + } + + const mapString = "{" + mapItems.join(",") + "}"; + + return `__TS__SourceMapTraceBack("${this.sourceFile}", ${mapString});\n`; } private printImplementation( @@ -136,11 +147,30 @@ export class LuaPrinter { } } - this.sourceFile = path.basename(sourceFile); + this.sourceFile = path.basename(sourceFile, ".ts"); const blockNode = this.createSourceNode(block, this.printBlock(block)); - return this.concatNodes(header, blockNode); + let sourceNode = this.concatNodes(header, blockNode); + + if (this.options.sourceMapTraceBack) { + const lastNode = block.statements[block.statements.length - 1]; + if (tstl.isReturnStatement(lastNode)) { + const stackTraceOverride = this.printStackTraceOverride(sourceNode); + + const leadingNodes = block.statements.slice(0, -1); + + const leadingBlock = this.printBlock(tstl.createBlock(leadingNodes)); + const returnNode = this.printReturnStatement(lastNode); + + sourceNode = this.concatNodes(header, leadingBlock, stackTraceOverride, returnNode); + } else { + const stackTraceOverride = this.printStackTraceOverride(sourceNode); + sourceNode = this.concatNodes(sourceNode, stackTraceOverride); + } + } + + return sourceNode; } private pushIndent(): void { diff --git a/src/lualib/SourceMapTraceBack.ts b/src/lualib/SourceMapTraceBack.ts index 35478bf39..de5ed9ea1 100644 --- a/src/lualib/SourceMapTraceBack.ts +++ b/src/lualib/SourceMapTraceBack.ts @@ -2,17 +2,28 @@ declare const debug: { traceback: (this: void, ...args: any[]) => string; }; -declare function getfenv(obj: any): {[key: string]: any}; +type FileTracebackTable = {[filename: string]: (this: void, ...args: any[]) => string}; +declare const _G: {[key: string]: any} & {["traceback"]: FileTracebackTable}; + +declare function print(this: void, ...messages: any[]): void; + +function __TS__SourceMapTraceBack(this: void, fileName: string, sourceMap: {[line: number]: number}): void { + _G["traceback"] = _G["traceback"] || {}; + _G["traceback"][fileName] = _G["traceback"][fileName] || debug.traceback; -function __TS__SourceMapTraceBack(fileName: string, sourceMap: {[line: number]: number}): void { - getfenv(1)["traceback"] = getfenv(1)["traceback"] || {}; - getfenv(1)["traceback"][fileName] = getfenv(1)["traceback"][fileName] || debug.traceback; debug.traceback = (...args: any[]) => { - let trace = getfenv(1)["traceback"][fileName](...args); + let trace = _G["traceback"][fileName](...args); const matches = string.gmatch(trace, `${fileName}.lua:(%d+)`); - for (const match in matches) { - trace = string.gsub(trace, `${fileName}.lua:${match}`, `${fileName}.ts:${sourceMap[match] || "??"}`); + for (const match of matches) { + if (match in sourceMap) { + const [result, _] = string.gsub( + trace, + `${fileName}.lua:${match}`, + `${fileName}.ts:${sourceMap[match] || "??"}` + ); + trace = result; + } } return trace; diff --git a/src/lualib/string.d.ts b/src/lualib/string.d.ts index 4361889b3..2dc316af0 100644 --- a/src/lualib/string.d.ts +++ b/src/lualib/string.d.ts @@ -1,6 +1,7 @@ /** @luaIterator */ -interface GMatchResult extends Iterable { } +interface GMatchResult extends Array { } +/** @noSelf */ declare namespace string { /** @tupleReturn */ function gsub(source: string, searchValue: string, replaceValue: string): [string, number]; diff --git a/test/unit/compiler/configuration/mixed/index.spec.ts b/test/unit/compiler/configuration/mixed/index.spec.ts index 179a8ac77..5ebf33a35 100644 --- a/test/unit/compiler/configuration/mixed/index.spec.ts +++ b/test/unit/compiler/configuration/mixed/index.spec.ts @@ -38,6 +38,7 @@ export class MixedConfigurationTests noHeader: false, project: tsConfigPath, noHoisting: false, + sourceMapTraceBack: false, } as CompilerOptions); } else { Expect(parsedArgs.isValid).toBeTruthy(); From 91401470bfd38666bf5fff38084b25a4d8b87666 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Mon, 25 Mar 2019 22:46:40 +0100 Subject: [PATCH 02/11] Improved sourcemap override --- src/lualib/SourceMapTraceBack.ts | 43 ++++++++++++++++---------------- src/lualib/string.d.ts | 1 + 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/lualib/SourceMapTraceBack.ts b/src/lualib/SourceMapTraceBack.ts index de5ed9ea1..61dfe0c37 100644 --- a/src/lualib/SourceMapTraceBack.ts +++ b/src/lualib/SourceMapTraceBack.ts @@ -2,30 +2,31 @@ declare const debug: { traceback: (this: void, ...args: any[]) => string; }; -type FileTracebackTable = {[filename: string]: (this: void, ...args: any[]) => string}; -declare const _G: {[key: string]: any} & {["traceback"]: FileTracebackTable}; - -declare function print(this: void, ...messages: any[]): void; +declare const _G: {[key: string]: any} & {__originalTraceback: (this: void, ...args: any[]) => string}; +// TODO: In the future, change this to __TS__RegisterFileInfo and provide tstl interface to +// get some metadata about transpilation. function __TS__SourceMapTraceBack(this: void, fileName: string, sourceMap: {[line: number]: number}): void { - _G["traceback"] = _G["traceback"] || {}; - _G["traceback"][fileName] = _G["traceback"][fileName] || debug.traceback; + _G["__sourcemap"] = _G["__sourcemap"] || {}; + _G["__sourcemap"][fileName] = sourceMap; - debug.traceback = (...args: any[]) => { - let trace = _G["traceback"][fileName](...args); + if (_G.__originalTraceback === undefined) { + _G.__originalTraceback = debug.traceback; + debug.traceback = (...args: any[]) => { + const trace = _G["__originalTraceback"](...args); - const matches = string.gmatch(trace, `${fileName}.lua:(%d+)`); - for (const match of matches) { - if (match in sourceMap) { - const [result, _] = string.gsub( - trace, - `${fileName}.lua:${match}`, - `${fileName}.ts:${sourceMap[match] || "??"}` - ); - trace = result; - } - } + const [result, occurrences] = string.gsub( + trace, + "([^\\]+).lua:(%d+)", + (file, line) => { + if (_G["__sourcemap"][file] && _G["__sourcemap"][file][line]) { + return `${file}.ts:${_G["__sourcemap"][file][line]}`; + } + return `${file}.lua:${line}`; + } + ); - return trace; - }; + return result; + }; + } } diff --git a/src/lualib/string.d.ts b/src/lualib/string.d.ts index 2dc316af0..111eca9b8 100644 --- a/src/lualib/string.d.ts +++ b/src/lualib/string.d.ts @@ -5,6 +5,7 @@ interface GMatchResult extends Array { } declare namespace string { /** @tupleReturn */ function gsub(source: string, searchValue: string, replaceValue: string): [string, number]; + function gsub(source: string, searchValue: string, replaceValue: (this: void, ...groups: string[]) => string): [string, number]; function gmatch(haystack: string, pattern: string): GMatchResult; } From 075352487e0da3d40aac05cd263cce81e6997b4c Mon Sep 17 00:00:00 2001 From: Perryvw Date: Mon, 25 Mar 2019 22:53:42 +0100 Subject: [PATCH 03/11] Removed obsolete argument --- src/lualib/string.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lualib/string.d.ts b/src/lualib/string.d.ts index 111eca9b8..350f22b7c 100644 --- a/src/lualib/string.d.ts +++ b/src/lualib/string.d.ts @@ -5,7 +5,7 @@ interface GMatchResult extends Array { } declare namespace string { /** @tupleReturn */ function gsub(source: string, searchValue: string, replaceValue: string): [string, number]; - function gsub(source: string, searchValue: string, replaceValue: (this: void, ...groups: string[]) => string): [string, number]; + function gsub(source: string, searchValue: string, replaceValue: (...groups: string[]) => string): [string, number]; function gmatch(haystack: string, pattern: string): GMatchResult; } From 765dcc19e52e270f2efdb007bedfdd9b4811a888 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Tue, 26 Mar 2019 20:56:55 +0100 Subject: [PATCH 04/11] put traceback override at start of the file after headers --- src/LuaPrinter.ts | 62 ++++++++++++++------------------------------ src/LuaTranspiler.ts | 8 +++--- 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index 9ed34d679..82fcb76d3 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -52,7 +52,7 @@ export class LuaPrinter { this.currentIndent = ""; } - public print(block: tstl.Block, luaLibFeatures?: Set, sourceFile?: string): string { + public print(block: tstl.Block, luaLibFeatures?: Set, sourceFile?: string): [string, string] { // Add traceback lualib if sourcemap traceback option is enabled if (this.options.sourceMapTraceBack) { if (luaLibFeatures === undefined) { @@ -61,40 +61,31 @@ export class LuaPrinter { luaLibFeatures.add(LuaLibFeature.SourceMapTraceBack); } - if (this.options.inlineSourceMap === true) { - const rootSourceNode = this.printImplementation(block, luaLibFeatures, sourceFile); + const rootSourceNode = this.printImplementation(block, luaLibFeatures, sourceFile); - const codeWithMap = 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"}); + 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"}); - const inlineSourceMap = this.printInlineSourceMap(codeWithMap.map); + let codeResult = codeWithSourceMap.code; - return codeWithMap.code + "\n" + inlineSourceMap; - } else { - return this.printImplementation(block, luaLibFeatures, sourceFile).toString(); + if (this.options.inlineSourceMap) { + codeResult += "\n" + this.printInlineSourceMap(codeWithSourceMap.map); } - } - - public printWithSourceMap( - block: tstl.Block, - luaLibFeatures?: Set, - sourceFile?: string): [string, string] { - - const codeWithMap = - this.printImplementation(block, luaLibFeatures, sourceFile) - // TODO is the file: part really required? and should this be handled in the printer? - .toStringWithSourceMap({file: path.basename(sourceFile, path.extname(sourceFile)) + ".lua"}); + if (this.options.sourceMapTraceBack) { + const stackTraceOverride = this.printStackTraceOverride(rootSourceNode); + codeResult = codeResult.replace("{#SourceMapTraceback}", stackTraceOverride); + } - return [codeWithMap.code, codeWithMap.map.toString()]; + return [codeResult, codeWithSourceMap.map.toString()]; } private printInlineSourceMap(sourceMap: SourceMapGenerator): string { const map = sourceMap.toString(); const base64Map = Buffer.from(map).toString('base64'); - return "//# sourceMappingURL=data:application/json;base64," + base64Map; + return `//# sourceMappingURL=data:application/json;base64,${base64Map}\n`; } private printStackTraceOverride(rootNode: SourceNode): string { @@ -118,7 +109,7 @@ export class LuaPrinter { const mapString = "{" + mapItems.join(",") + "}"; - return `__TS__SourceMapTraceBack("${this.sourceFile}", ${mapString});\n`; + return `__TS__SourceMapTraceBack("${this.sourceFile}", ${mapString});`; } private printImplementation( @@ -149,28 +140,13 @@ export class LuaPrinter { this.sourceFile = path.basename(sourceFile, ".ts"); - const blockNode = this.createSourceNode(block, this.printBlock(block)); - - let sourceNode = this.concatNodes(header, blockNode); - if (this.options.sourceMapTraceBack) { - const lastNode = block.statements[block.statements.length - 1]; - if (tstl.isReturnStatement(lastNode)) { - const stackTraceOverride = this.printStackTraceOverride(sourceNode); - - const leadingNodes = block.statements.slice(0, -1); - - const leadingBlock = this.printBlock(tstl.createBlock(leadingNodes)); - const returnNode = this.printReturnStatement(lastNode); - - sourceNode = this.concatNodes(header, leadingBlock, stackTraceOverride, returnNode); - } else { - const stackTraceOverride = this.printStackTraceOverride(sourceNode); - sourceNode = this.concatNodes(sourceNode, stackTraceOverride); - } + header += "{#SourceMapTraceback}\n"; } - return sourceNode; + const fileBlockNode = this.createSourceNode(block, this.printBlock(block)); + + return this.concatNodes(header, fileBlockNode); } private pushIndent(): void { diff --git a/src/LuaTranspiler.ts b/src/LuaTranspiler.ts index 80b34e9dd..80251e40a 100644 --- a/src/LuaTranspiler.ts +++ b/src/LuaTranspiler.ts @@ -143,21 +143,23 @@ export class LuaTranspiler { // Transform AST const [luaAST, lualibFeatureSet] = this.luaTransformer.transformSourceFile(sourceFile); // Print AST - return this.luaPrinter.print(luaAST, lualibFeatureSet, sourceFile.fileName); + const [code, sourceMap] = this.luaPrinter.print(luaAST, lualibFeatureSet, sourceFile.fileName); + return code; } public transpileSourceFileWithSourceMap(sourceFile: ts.SourceFile): [string, string] { // Transform AST const [luaAST, lualibFeatureSet] = this.luaTransformer.transformSourceFile(sourceFile); // Print AST - return this.luaPrinter.printWithSourceMap(luaAST, lualibFeatureSet, sourceFile.fileName); + return this.luaPrinter.print(luaAST, lualibFeatureSet, sourceFile.fileName); } public transpileSourceFileKeepAST(sourceFile: ts.SourceFile): [tstl.Block, string] { // Transform AST const [luaAST, lualibFeatureSet] = this.luaTransformer.transformSourceFile(sourceFile); // Print AST - return [luaAST, this.luaPrinter.print(luaAST, lualibFeatureSet, sourceFile.fileName)]; + const [code, sourceMap] = this.luaPrinter.print(luaAST, lualibFeatureSet, sourceFile.fileName); + return [luaAST, code]; } public reportDiagnostic(diagnostic: ts.Diagnostic): void { From 09ce51f9b95ee895d2c0d871390199402d9bc122 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Tue, 26 Mar 2019 22:23:34 +0100 Subject: [PATCH 05/11] changed 2 underscore identifiers --- src/lualib/SourceMapTraceBack.ts | 16 +++++++++------- src/lualib/string.d.ts | 1 + 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/lualib/SourceMapTraceBack.ts b/src/lualib/SourceMapTraceBack.ts index 61dfe0c37..6aff32c71 100644 --- a/src/lualib/SourceMapTraceBack.ts +++ b/src/lualib/SourceMapTraceBack.ts @@ -2,25 +2,27 @@ declare const debug: { traceback: (this: void, ...args: any[]) => string; }; -declare const _G: {[key: string]: any} & {__originalTraceback: (this: void, ...args: any[]) => string}; +type TraceBackFunction = (this: void, thread?: any, message?: string, level?: number) => string; + +declare const _G: {[key: string]: any} & {__TS__originalTraceback: TraceBackFunction}; // TODO: In the future, change this to __TS__RegisterFileInfo and provide tstl interface to // get some metadata about transpilation. function __TS__SourceMapTraceBack(this: void, fileName: string, sourceMap: {[line: number]: number}): void { - _G["__sourcemap"] = _G["__sourcemap"] || {}; - _G["__sourcemap"][fileName] = sourceMap; + _G["__TS__sourcemap"] = _G["__TS__sourcemap"] || {}; + _G["__TS__sourcemap"][fileName] = sourceMap; if (_G.__originalTraceback === undefined) { _G.__originalTraceback = debug.traceback; - debug.traceback = (...args: any[]) => { - const trace = _G["__originalTraceback"](...args); + debug.traceback = (thread, message, level) => { + const trace = _G["__TS__originalTraceback"](thread, message, level); const [result, occurrences] = string.gsub( trace, "([^\\]+).lua:(%d+)", (file, line) => { - if (_G["__sourcemap"][file] && _G["__sourcemap"][file][line]) { - return `${file}.ts:${_G["__sourcemap"][file][line]}`; + if (_G["__TS__sourcemap"][file] && _G["__TS__sourcemap"][file][line]) { + return `${file}.ts:${_G["__TS__sourcemap"][file][line]}`; } return `${file}.lua:${line}`; } diff --git a/src/lualib/string.d.ts b/src/lualib/string.d.ts index 350f22b7c..6e387692b 100644 --- a/src/lualib/string.d.ts +++ b/src/lualib/string.d.ts @@ -5,6 +5,7 @@ interface GMatchResult extends Array { } declare namespace string { /** @tupleReturn */ function gsub(source: string, searchValue: string, replaceValue: string): [string, number]; + /** @tupleReturn */ function gsub(source: string, searchValue: string, replaceValue: (...groups: string[]) => string): [string, number]; function gmatch(haystack: string, pattern: string): GMatchResult; From debca18bf0fd356fb310d040ac86ce753e003aab Mon Sep 17 00:00:00 2001 From: Perryvw Date: Wed, 27 Mar 2019 21:06:03 +0100 Subject: [PATCH 06/11] Added test for sourceMapTraceback --- build_lualib.ts | 2 +- src/CommandLineParser.ts | 2 +- src/CompilerOptions.ts | 2 +- src/LuaPrinter.ts | 6 +- src/lualib/{ => declarations}/string.d.ts | 0 .../configuration/mixed/index.spec.ts | 2 +- test/unit/sourcemaps.spec.ts | 70 +++++++++++++++++++ 7 files changed, 77 insertions(+), 7 deletions(-) rename src/lualib/{ => declarations}/string.d.ts (100%) create mode 100644 test/unit/sourcemaps.spec.ts diff --git a/build_lualib.ts b/build_lualib.ts index f968f5968..be376fef6 100644 --- a/build_lualib.ts +++ b/build_lualib.ts @@ -20,7 +20,7 @@ compile([ "./src/lualib", "--noHeader", "true", - ...glob.sync("./src/lualib/*.ts"), + ...glob.sync("./src/lualib/**/*.ts"), ]); if (fs.existsSync(bundlePath)) { diff --git a/src/CommandLineParser.ts b/src/CommandLineParser.ts index a947f923c..50a1fa738 100644 --- a/src/CommandLineParser.ts +++ b/src/CommandLineParser.ts @@ -52,7 +52,7 @@ const optionDeclarations: {[key: string]: CLIOption} = { describe: "Disables hoisting.", type: "boolean", } as CLIOption, - sourceMapTraceBack: { + sourceMapTraceback: { default: false, describe: "Applies the source map to show source TS files and lines in error tracebacks.", type: "boolean", diff --git a/src/CompilerOptions.ts b/src/CompilerOptions.ts index f1ba8d713..49ad4eabf 100644 --- a/src/CompilerOptions.ts +++ b/src/CompilerOptions.ts @@ -5,7 +5,7 @@ export interface CompilerOptions extends ts.CompilerOptions { luaTarget?: LuaTarget; luaLibImport?: LuaLibImportKind; noHoisting?: boolean; - sourceMapTraceBack?: boolean; + sourceMapTraceback?: boolean; } export enum LuaLibImportKind { diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index 630d1ef62..9a663d6f1 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -52,7 +52,7 @@ export class LuaPrinter { public print(block: tstl.Block, luaLibFeatures?: Set, sourceFile?: string): [string, string] { // Add traceback lualib if sourcemap traceback option is enabled - if (this.options.sourceMapTraceBack) { + if (this.options.sourceMapTraceback) { if (luaLibFeatures === undefined) { luaLibFeatures = new Set(); } @@ -71,7 +71,7 @@ export class LuaPrinter { codeResult += "\n" + this.printInlineSourceMap(codeWithSourceMap.map); } - if (this.options.sourceMapTraceBack) { + if (this.options.sourceMapTraceback) { const stackTraceOverride = this.printStackTraceOverride(rootSourceNode); codeResult = codeResult.replace("{#SourceMapTraceback}", stackTraceOverride); } @@ -138,7 +138,7 @@ export class LuaPrinter { this.sourceFile = path.basename(sourceFile, ".ts"); - if (this.options.sourceMapTraceBack) { + if (this.options.sourceMapTraceback) { header += "{#SourceMapTraceback}\n"; } diff --git a/src/lualib/string.d.ts b/src/lualib/declarations/string.d.ts similarity index 100% rename from src/lualib/string.d.ts rename to src/lualib/declarations/string.d.ts diff --git a/test/unit/compiler/configuration/mixed/index.spec.ts b/test/unit/compiler/configuration/mixed/index.spec.ts index a7fac4870..cb98a7d45 100644 --- a/test/unit/compiler/configuration/mixed/index.spec.ts +++ b/test/unit/compiler/configuration/mixed/index.spec.ts @@ -32,7 +32,7 @@ test("tsconfig.json mixed with cmd line args", () => { noHeader: false, project: tsConfigPath, noHoisting: false, - sourceMapTraceBack: false, + sourceMapTraceback: false, } as CompilerOptions); } else { expect(parsedArgs.isValid).toBeTruthy(); diff --git a/test/unit/sourcemaps.spec.ts b/test/unit/sourcemaps.spec.ts new file mode 100644 index 000000000..a92843907 --- /dev/null +++ b/test/unit/sourcemaps.spec.ts @@ -0,0 +1,70 @@ +import * as util from "../util"; +import { LuaLibImportKind } from "../../src/CompilerOptions"; + +test("sourceMapTraceback saves sourcemap in _G", () => { + const typeScriptSource = ` + function abc() { + return "foo"; + } + return JSONStringify(_G.__TS__sourcemap);`; + + const options = {sourceMapTraceback: true, luaLibImport: LuaLibImportKind.Inline}; + + const transpiledLua = util.transpileString(typeScriptSource, options); + + const sourceMapJson = util.transpileAndExecute( + typeScriptSource, + options, + undefined, + "declare const _G: {__TS__sourcemap: any};" + ); + + expect(sourceMapJson).toBeDefined(); + + const sourceMap = JSON.parse(sourceMapJson); + + expect(sourceMap["file"]).toBeDefined(); + + expectCorrectMapping(typeScriptSource, transpiledLua, sourceMap, [ + ["function abc()", "abc = function("], + ["return \"foo\"", "return \"foo\""] + ]); +}); + +// Helper functions + +function expectCorrectMapping( + original: string, + lua: string, + sourceMap: {[line: string]: number}, + patterns: Array<[string, string]> +): void { + for (const [tsPattern, luaPattern] of patterns) { + const originalLine = lineOf(original, "function abc()") + 1; // Add 1 for util-added header + const luaLine = lineOf(lua, "abc = function("); + const mappedLuaLine = sourceMap["file"][luaLine.toString()]; + + expect(mappedLuaLine).toBe(originalLine); + } +} + +// Find the line of the first occurrence of a pattern. +function lineOf(text: string, pattern: string): number { + const pos = text.indexOf(pattern); + if (pos === -1) { + return pos; + } + + const lineLengths = text.split("\n").map(s => s.length); + + let totalPos = 0; + for (let line = 1; line <= lineLengths.length; line++) { + // Add length of the line + 1 for the removed \n + totalPos += lineLengths[line - 1] + 1; + if (pos < totalPos) { + return line; + } + } + + return -1; +} \ No newline at end of file From bc051eca1603737a05aa42dd76e419e7e2141ddd Mon Sep 17 00:00:00 2001 From: Perryvw Date: Wed, 27 Mar 2019 23:28:03 +0100 Subject: [PATCH 07/11] don't enforce prettier linting --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d38187f3c..76b1ec51a 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "build-lualib": "ts-node ./build_lualib.ts", "pretest": "ts-node --transpile-only ./build_lualib.ts", "test": "jest", - "lint": "npm run lint:tslint && npm run lint:prettier", + "lint": "npm run lint:tslint", "lint:prettier": "prettier --check **/*.{js,ts,yml,json}", "lint:tslint": "tslint -p . && tslint -p test && tslint src/lualib/*.ts", "release-major": "npm version major", From 346720a8a23b8406cfb33fbb20f7e2af31a5ced0 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Thu, 28 Mar 2019 23:50:42 +0100 Subject: [PATCH 08/11] use debug.getinfo for file names --- src/LuaPrinter.ts | 4 ++-- src/lualib/SourceMapTraceBack.ts | 11 +++++------ test/unit/sourcemaps.spec.ts | 5 +++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index 9a663d6f1..8ea637c2a 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -107,7 +107,7 @@ export class LuaPrinter { const mapString = "{" + mapItems.join(",") + "}"; - return `__TS__SourceMapTraceBack("${this.sourceFile}", ${mapString});`; + return `__TS__SourceMapTraceBack(debug.getinfo(1).short_src, ${mapString});`; } private printImplementation( @@ -136,7 +136,7 @@ export class LuaPrinter { } } - this.sourceFile = path.basename(sourceFile, ".ts"); + this.sourceFile = path.basename(sourceFile); if (this.options.sourceMapTraceback) { header += "{#SourceMapTraceback}\n"; diff --git a/src/lualib/SourceMapTraceBack.ts b/src/lualib/SourceMapTraceBack.ts index 6aff32c71..eb5215d64 100644 --- a/src/lualib/SourceMapTraceBack.ts +++ b/src/lualib/SourceMapTraceBack.ts @@ -12,17 +12,16 @@ function __TS__SourceMapTraceBack(this: void, fileName: string, sourceMap: {[lin _G["__TS__sourcemap"] = _G["__TS__sourcemap"] || {}; _G["__TS__sourcemap"][fileName] = sourceMap; - if (_G.__originalTraceback === undefined) { - _G.__originalTraceback = debug.traceback; + if (_G.__TS__originalTraceback === undefined) { + _G.__TS__originalTraceback = debug.traceback; debug.traceback = (thread, message, level) => { const trace = _G["__TS__originalTraceback"](thread, message, level); - const [result, occurrences] = string.gsub( trace, - "([^\\]+).lua:(%d+)", + "(%S+).lua:(%d+)", (file, line) => { - if (_G["__TS__sourcemap"][file] && _G["__TS__sourcemap"][file][line]) { - return `${file}.ts:${_G["__TS__sourcemap"][file][line]}`; + if (_G["__TS__sourcemap"][file + ".lua"] && _G["__TS__sourcemap"][file + ".lua"][line]) { + return `${file}.ts:${_G["__TS__sourcemap"][file + ".lua"][line]}`; } return `${file}.lua:${line}`; } diff --git a/test/unit/sourcemaps.spec.ts b/test/unit/sourcemaps.spec.ts index a92843907..b3d1e92c2 100644 --- a/test/unit/sourcemaps.spec.ts +++ b/test/unit/sourcemaps.spec.ts @@ -23,7 +23,8 @@ test("sourceMapTraceback saves sourcemap in _G", () => { const sourceMap = JSON.parse(sourceMapJson); - expect(sourceMap["file"]).toBeDefined(); + // Yes, this is the filename the test VM gives this file... + expect(sourceMap[`[string "--\r..."]`]).toBeDefined(); expectCorrectMapping(typeScriptSource, transpiledLua, sourceMap, [ ["function abc()", "abc = function("], @@ -42,7 +43,7 @@ function expectCorrectMapping( for (const [tsPattern, luaPattern] of patterns) { const originalLine = lineOf(original, "function abc()") + 1; // Add 1 for util-added header const luaLine = lineOf(lua, "abc = function("); - const mappedLuaLine = sourceMap["file"][luaLine.toString()]; + const mappedLuaLine = sourceMap[`[string "--\r..."]`][luaLine.toString()]; expect(mappedLuaLine).toBe(originalLine); } From e731c8fd22cdb1565dd1f168b271f962562c0719 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Fri, 29 Mar 2019 00:00:30 +0100 Subject: [PATCH 09/11] Trying to diagnose test issue --- test/unit/sourcemaps.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/sourcemaps.spec.ts b/test/unit/sourcemaps.spec.ts index b3d1e92c2..688c8e569 100644 --- a/test/unit/sourcemaps.spec.ts +++ b/test/unit/sourcemaps.spec.ts @@ -24,6 +24,7 @@ test("sourceMapTraceback saves sourcemap in _G", () => { const sourceMap = JSON.parse(sourceMapJson); // Yes, this is the filename the test VM gives this file... + console.log(sourceMap); expect(sourceMap[`[string "--\r..."]`]).toBeDefined(); expectCorrectMapping(typeScriptSource, transpiledLua, sourceMap, [ From 2861bae4187e326f91ed8e61efeea82b7c53a649 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Fri, 29 Mar 2019 20:43:54 +0100 Subject: [PATCH 10/11] No longer check filename in sourcemap test --- test/unit/sourcemaps.spec.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/unit/sourcemaps.spec.ts b/test/unit/sourcemaps.spec.ts index 688c8e569..f111f6e7b 100644 --- a/test/unit/sourcemaps.spec.ts +++ b/test/unit/sourcemaps.spec.ts @@ -23,9 +23,10 @@ test("sourceMapTraceback saves sourcemap in _G", () => { const sourceMap = JSON.parse(sourceMapJson); - // Yes, this is the filename the test VM gives this file... - console.log(sourceMap); - expect(sourceMap[`[string "--\r..."]`]).toBeDefined(); + const sourceMapFiles = Object.keys(sourceMap); + + expect(sourceMapFiles.length).toBe(1); + expect(sourceMap[sourceMapFiles[0]]).toBeDefined(); expectCorrectMapping(typeScriptSource, transpiledLua, sourceMap, [ ["function abc()", "abc = function("], From 37ab9bfc3465672d6a6b53bdfcd0060911218769 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Fri, 29 Mar 2019 21:11:06 +0100 Subject: [PATCH 11/11] Another stab at fixing tests --- test/unit/sourcemaps.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/sourcemaps.spec.ts b/test/unit/sourcemaps.spec.ts index f111f6e7b..88910e622 100644 --- a/test/unit/sourcemaps.spec.ts +++ b/test/unit/sourcemaps.spec.ts @@ -28,7 +28,7 @@ test("sourceMapTraceback saves sourcemap in _G", () => { expect(sourceMapFiles.length).toBe(1); expect(sourceMap[sourceMapFiles[0]]).toBeDefined(); - expectCorrectMapping(typeScriptSource, transpiledLua, sourceMap, [ + expectCorrectMapping(typeScriptSource, transpiledLua, sourceMap[sourceMapFiles[0]], [ ["function abc()", "abc = function("], ["return \"foo\"", "return \"foo\""] ]); @@ -45,7 +45,7 @@ function expectCorrectMapping( for (const [tsPattern, luaPattern] of patterns) { const originalLine = lineOf(original, "function abc()") + 1; // Add 1 for util-added header const luaLine = lineOf(lua, "abc = function("); - const mappedLuaLine = sourceMap[`[string "--\r..."]`][luaLine.toString()]; + const mappedLuaLine = sourceMap[luaLine.toString()]; expect(mappedLuaLine).toBe(originalLine); }