diff --git a/src/Decorator.ts b/src/Decorator.ts index e0b3b6a00..870cc9344 100644 --- a/src/Decorator.ts +++ b/src/Decorator.ts @@ -1,14 +1,30 @@ export class Decorator { + + public static isValid(decoratorKindString: string): boolean { + return this.getDecoratorKind(decoratorKindString) !== undefined; + } + + public static getDecoratorKind(decoratorKindString: string): DecoratorKind { + switch (decoratorKindString.toLowerCase()) { + case "extension": return DecoratorKind.Extension; + case "metaextension": return DecoratorKind.MetaExtension; + case "customconstructor": return DecoratorKind.CustomConstructor; + case "compilemembersonly": return DecoratorKind.CompileMembersOnly; + case "pureabstract": return DecoratorKind.PureAbstract; + case "phantom": return DecoratorKind.Phantom; + case "tuplereturn": return DecoratorKind.TupleReturn; + case "noclassor": return DecoratorKind.NoClassOr; + } + + return undefined; + } + public kind: DecoratorKind; public args: string[]; - constructor(raw: string) { - let nameEnd = raw.indexOf(" "); - if (nameEnd === -1) { - nameEnd = raw.length; - } - this.kind = DecoratorKind[raw.substring(1, nameEnd)]; - this.args = raw.split(" ").slice(1); + constructor(name: string, args: string[]) { + this.kind = Decorator.getDecoratorKind(name); + this.args = args; } } diff --git a/src/TSHelper.ts b/src/TSHelper.ts index d35973f32..203181681 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -109,14 +109,32 @@ export class TSHelper { const comments = type.symbol.getDocumentationComment(checker); const decorators = comments.filter(comment => comment.kind === "text") - .map(comment => comment.text.trim().split("\n")) + .map(comment => comment.text.split("\n")) .reduce((a, b) => a.concat(b), []) + .map(line => line.trim()) .filter(comment => comment[0] === "!"); + const decMap = new Map(); + decorators.forEach(decStr => { - const dec = new Decorator(decStr); - decMap.set(dec.kind, dec); + const [decoratorName, ...decoratorArguments] = decStr.split(" "); + if (Decorator.isValid(decoratorName.substr(1))) { + const dec = new Decorator(decoratorName.substr(1), decoratorArguments); + decMap.set(dec.kind, dec); + console.warn(`[Deprecated] Decorators with ! are being deprecated, ` + + `use @${decStr.substr(1)} instead`); + } else { + console.warn(`Encountered unknown decorator ${decStr}.`); + } }); + + type.symbol.getJsDocTags().forEach(tag => { + if (Decorator.isValid(tag.name)) { + const dec = new Decorator(tag.name, tag.text ? tag.text.split(" ") : []); + decMap.set(dec.kind, dec); + } + }); + return decMap; } return new Map(); diff --git a/src/lualib/StringReplace.ts b/src/lualib/StringReplace.ts index 7a5df979c..7324db680 100644 --- a/src/lualib/StringReplace.ts +++ b/src/lualib/StringReplace.ts @@ -1,5 +1,5 @@ declare namespace string { - /** !TupleReturn */ + /** @tupleReturn */ function gsub(source: string, searchValue: string, replaceValue: string): [string, number]; } diff --git a/test/runner.ts b/test/runner.ts index 0d5d542fc..b37dbe17f 100644 --- a/test/runner.ts +++ b/test/runner.ts @@ -1,5 +1,4 @@ -import { TestRunner, TestSet } from "alsatian"; -import { TapBark } from "tap-bark"; +import { TestRunner, TestSet, TestOutcome } from "alsatian"; import * as fs from "fs"; import * as path from "path"; @@ -21,21 +20,44 @@ fs.copyFileSync( // setup the output testRunner.outputStream - // this will use alsatian's default output if you remove this - // you'll get TAP or you can add your favourite TAP reporter in it's place - .pipe(TapBark.create().getPipeable()) - // pipe to the console - .pipe(process.stdout); + // pipe to the console + .pipe(process.stdout); + +let success = 0; +let ignored = 0; +let run = 0; +testRunner.onTestComplete(test => { + run++; + + if (test.outcome === TestOutcome.Pass) { + success++; + } else if (test.outcome === TestOutcome.Skip) { + ignored++; + } +}); // run the test set testRunner.run(testSet) - // this will be called after all tests have been run - .then(result => { - // Remove lualib bundle again - fs.unlinkSync("lualib_bundle.lua"); - }) - // this will be called if there was a problem - .catch(error => { - // Remove lualib bundle again - fs.unlinkSync("lualib_bundle.lua"); - }); + // this will be called after all tests have been run + .then(result => { + // Remove lualib bundle again + fs.unlinkSync("lualib_bundle.lua"); + + const nonIgnoredTests = run - ignored; + const failedTests = nonIgnoredTests - success; + console.log(`Ignored ${ignored}/${run} tests.`); + console.log(`Failed ${failedTests}/${nonIgnoredTests} tests.`); + console.log(`Passed ${success}/${nonIgnoredTests} tests.`); + + if (failedTests > 0) { + process.exit(1); + } + }) + // this will be called if there was a problem + .catch(error => { + // Remove lualib bundle again + fs.unlinkSync("lualib_bundle.lua"); + + console.error(error); + process.exit(1); + }); diff --git a/test/src/util.ts b/test/src/util.ts index 71f8227ac..197f87208 100644 --- a/test/src/util.ts +++ b/test/src/util.ts @@ -67,6 +67,54 @@ export function transpileAndExecute(tsStr: string): any { return executeLua(transpileString(tsStr)); } +export function parseTypeScript(typescript: string, target: LuaTarget = LuaTarget.Lua53) + : [ts.SourceFile, ts.TypeChecker] { + const compilerHost = { + directoryExists: () => true, + fileExists: (fileName): boolean => true, + getCanonicalFileName: fileName => fileName, + getCurrentDirectory: () => "", + getDefaultLibFileName: () => "lib.es6.d.ts", + getDirectories: () => [], + getNewLine: () => "\n", + + getSourceFile: (filename, languageVersion) => { + if (filename === "file.ts") { + return ts.createSourceFile(filename, typescript, ts.ScriptTarget.Latest, false); + } + if (filename === "lib.es6.d.ts") { + const libPath = path.join(path.dirname(require.resolve("typescript")), "lib.es6.d.ts"); + const libSource = fs.readFileSync(libPath).toString(); + return ts.createSourceFile(filename, libSource, ts.ScriptTarget.Latest, false); + } + return undefined; + }, + + readFile: () => "", + + useCaseSensitiveFileNames: () => false, + // Don't write output + writeFile: (name, text, writeByteOrderMark) => null, + }; + + const program = ts.createProgram(["file.ts"], { luaTarget: target }, compilerHost); + return [program.getSourceFile("file.ts"), program.getTypeChecker()]; +} + +export function findFirstChild(node: ts.Node, predicate: (node: ts.Node) => boolean): ts.Node | undefined { + for (const child of node.getChildren()) { + if (predicate(child)) { + return child; + } + + const childChild = findFirstChild(child, predicate); + if (childChild !== undefined) { + return childChild; + } + } + return undefined; +} + const jsonlib = fs.readFileSync("test/src/json.lua") + "\n"; export const minimalTestLib = jsonlib; diff --git a/test/translation/ts/assignments.ts b/test/translation/ts/assignments.ts index a8e51e59a..df4fb91db 100644 --- a/test/translation/ts/assignments.ts +++ b/test/translation/ts/assignments.ts @@ -10,7 +10,7 @@ declare function getIndex(): number; declare let xTup: [number, number]; declare let yTup: [number, number]; declare function getTup(): [number, number]; -/** !TupleReturn */ +/** @tupleReturn */ declare function getTupRet(): [number, number]; x = y; x = obj.prop; diff --git a/test/translation/ts/classExtension1.ts b/test/translation/ts/classExtension1.ts index cf293483d..5df5bdeac 100644 --- a/test/translation/ts/classExtension1.ts +++ b/test/translation/ts/classExtension1.ts @@ -1,4 +1,4 @@ -/** !Extension */ +/** @extension */ class MyClass { public myFunction() {} } diff --git a/test/translation/ts/classExtension2.ts b/test/translation/ts/classExtension2.ts index 109160d97..158f16422 100644 --- a/test/translation/ts/classExtension2.ts +++ b/test/translation/ts/classExtension2.ts @@ -1,8 +1,8 @@ -/** !Extension */ +/** @extension */ class TestClass { } -/** !Extension */ +/** @extension */ class MyClass extends TestClass { public myFunction() {} } diff --git a/test/translation/ts/classExtension3.ts b/test/translation/ts/classExtension3.ts index 287c46d3f..3fa37f05e 100644 --- a/test/translation/ts/classExtension3.ts +++ b/test/translation/ts/classExtension3.ts @@ -1,9 +1,9 @@ -/** !Extension RenamedTestClass */ +/** @extension RenamedTestClass */ class TestClass { public myFunction() {} } -/** !Extension RenamedMyClass */ +/** @extension RenamedMyClass */ class MyClass extends TestClass { public myFunction() {} } diff --git a/test/translation/ts/classExtension4.ts b/test/translation/ts/classExtension4.ts index 2183c5610..8cb996079 100644 --- a/test/translation/ts/classExtension4.ts +++ b/test/translation/ts/classExtension4.ts @@ -1,4 +1,4 @@ -/** !Extension */ +/** @extension */ class MyClass { public test: string = "test"; private testP: string = "testP"; diff --git a/test/translation/ts/classPureAbstract.ts b/test/translation/ts/classPureAbstract.ts index c511f0de2..178c23b59 100644 --- a/test/translation/ts/classPureAbstract.ts +++ b/test/translation/ts/classPureAbstract.ts @@ -1,3 +1,3 @@ -/** !PureAbstract */ +/** @pureAbstract */ declare class ClassA {} class ClassB extends ClassA {} \ No newline at end of file diff --git a/test/translation/ts/enumMembersOnly.ts b/test/translation/ts/enumMembersOnly.ts index 1032bea82..9d384dc6c 100644 --- a/test/translation/ts/enumMembersOnly.ts +++ b/test/translation/ts/enumMembersOnly.ts @@ -1,9 +1,9 @@ -/** !CompileMembersOnly */ +/** @compileMembersOnly */ enum TestEnum { val1 = 0, val2 = 2, val3, - val4 = "bye" + val4 = "bye", } const a = TestEnum.val1; diff --git a/test/translation/ts/namespacePhantom.ts b/test/translation/ts/namespacePhantom.ts index b107d3387..c99b88e8d 100644 --- a/test/translation/ts/namespacePhantom.ts +++ b/test/translation/ts/namespacePhantom.ts @@ -1,4 +1,4 @@ -/** !Phantom */ +/** @phantom */ namespace myNamespace { function nsMember() {} } \ No newline at end of file diff --git a/test/translation/ts/tupleReturn.ts b/test/translation/ts/tupleReturn.ts index 86fd32e97..0d2936071 100644 --- a/test/translation/ts/tupleReturn.ts +++ b/test/translation/ts/tupleReturn.ts @@ -1,4 +1,4 @@ -/** !TupleReturn */ +/** @tupleReturn */ function tupleReturn(): [number, string] { return [0, "foobar"]; } @@ -16,19 +16,19 @@ e = tupleReturn(); f = noTupleReturn(); foo(tupleReturn()); foo(noTupleReturn()); -/** !TupleReturn */ +/** @tupleReturn */ function tupleReturnFromVar(): [number, string] { const r: [number, string] = [1, "baz"]; return r; } -/** !TupleReturn */ +/** @tupleReturn */ function tupleReturnForward(): [number, string] { return tupleReturn(); } function tupleNoForward(): [number, string] { return tupleReturn(); } -/** !TupleReturn */ +/** @tupleReturn */ function tupleReturnUnpack(): [number, string] { return tupleNoForward(); } diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index e3ccb60c0..5ba09e62c 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -76,7 +76,7 @@ export class AssignmentTests { @Test("TupleReturn assignment") public tupleReturnFunction(): void { - const code = `/** !TupleReturn */\n` + const code = `/** @tupleReturn */\n` + `declare function abc() { return [1,2,3]; }\n` + `let [a,b] = abc();`; @@ -86,7 +86,7 @@ export class AssignmentTests { @Test("TupleReturn Single assignment") public tupleReturnSingleAssignment(): void { - const code = `/** !TupleReturn */\n` + const code = `/** @tupleReturn */\n` + `declare function abc(): [number, string]; }\n` + `let a = abc();` + `a = abc();`; @@ -98,7 +98,7 @@ export class AssignmentTests { @Test("TupleReturn interface assignment") public tupleReturnInterface(): void { const code = `interface def {\n` - + `/** !TupleReturn */\n` + + `/** @tupleReturn */\n` + `abc();\n` + `} declare const jkl : def;\n` + `let [a,b] = jkl.abc();`; @@ -110,7 +110,7 @@ export class AssignmentTests { @Test("TupleReturn namespace assignment") public tupleReturnNameSpace(): void { const code = `declare namespace def {\n` - + `/** !TupleReturn */\n` + + `/** @tupleReturn */\n` + `function abc() {}\n` + `}\n` + `let [a,b] = def.abc();`; @@ -122,7 +122,7 @@ export class AssignmentTests { @Test("TupleReturn method assignment") public tupleReturnMethod(): void { const code = `declare class def {\n` - + `/** !TupleReturn */\n` + + `/** @tupleReturn */\n` + `abc() { return [1,2,3]; }\n` + `} const jkl = new def();\n` + `let [a,b] = jkl.abc();`; @@ -133,7 +133,7 @@ export class AssignmentTests { @Test("TupleReturn functional") public tupleReturnFunctional(): void { - const code = `/** !TupleReturn */ + const code = `/** @tupleReturn */ function abc(): [number, string] { return [3, "a"]; } const [a, b] = abc(); return b + a;`; @@ -147,7 +147,7 @@ export class AssignmentTests { @Test("TupleReturn single") public tupleReturnSingle(): void { - const code = `/** !TupleReturn */ + const code = `/** @tupleReturn */ function abc(): [number, string] { return [3, "a"]; } const res = abc(); return res.length`; @@ -161,7 +161,7 @@ export class AssignmentTests { @Test("TupleReturn in expression") public tupleReturnInExpression(): void { - const code = `/** !TupleReturn */ + const code = `/** @tupleReturn */ function abc(): [number, string] { return [3, "a"]; } return abc()[1] + abc()[0];`; diff --git a/test/unit/decoratorCustomConstructor.spec.ts b/test/unit/decoratorCustomConstructor.spec.ts index b9e4c7242..5433b2f4f 100644 --- a/test/unit/decoratorCustomConstructor.spec.ts +++ b/test/unit/decoratorCustomConstructor.spec.ts @@ -9,7 +9,7 @@ export class DecoratorCustomConstructor { public customCreate(): void { // Transpile const lua = util.transpileString( - `/** !CustomConstructor Point2DCreate */ + `/** @customConstructor Point2DCreate */ class Point2D { x: number; y: number; @@ -29,7 +29,7 @@ export class DecoratorCustomConstructor { public incorrectUsage(): void { Expect(() => { util.transpileString( - `/** !CustomConstructor */ + `/** @customConstructor */ class Point2D { x: number; y: number; diff --git a/test/unit/decoratorMetaExtension.spec.ts b/test/unit/decoratorMetaExtension.spec.ts index d29f51467..eddba794b 100644 --- a/test/unit/decoratorMetaExtension.spec.ts +++ b/test/unit/decoratorMetaExtension.spec.ts @@ -14,7 +14,7 @@ export class DecoratorMetaExtension { declare namespace debug { function getregistry(): any; } - /** !MetaExtension */ + /** @metaExtension */ class LoadedExt extends _LOADED { public static test() { return 5; @@ -33,7 +33,7 @@ export class DecoratorMetaExtension { Expect(() => { util.transpileString( ` - /** !MetaExtension */ + /** @metaExtension */ class LoadedExt { public static test() { return 5; @@ -51,7 +51,7 @@ export class DecoratorMetaExtension { util.transpileString( ` declare class _LOADED; - /** !MetaExtension */ + /** @metaExtension */ class Ext extends _LOADED { } const e = new Ext(); diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 2fa26da68..7fbea1209 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -324,7 +324,7 @@ export class ExpressionTests { `let x: [string, string] = ["x0", "x1"]; let y: [string, string] = ["y0", "y1"]; function t(): [string, string] { return ["t0", "t1"] }; - /** !TupleReturn */ + /** @tupleReturn */ function tr(): [string, string] { return ["tr0", "tr1"] }; const r = ${expression}; return \`\${r[0]},\${r[1]}\``); diff --git a/test/unit/tshelper.spec.ts b/test/unit/tshelper.spec.ts index 2a14d34f2..774babd93 100644 --- a/test/unit/tshelper.spec.ts +++ b/test/unit/tshelper.spec.ts @@ -1,7 +1,10 @@ +import { Expect, Test, TestCase } from "alsatian"; +import { TSHelper as tsHelper } from "../../src/TSHelper"; + import * as ts from "typescript"; +import * as util from "../src/util"; -import { Expect, FocusTest, IgnoreTest, Test, TestCase } from "alsatian"; -import { TSHelper as tsEx } from "../../src/TSHelper"; +import { DecoratorKind } from "../../src/Decorator"; enum TestEnum { testA = 1, @@ -15,8 +18,8 @@ export class TSHelperTests { @TestCase(-1, "unknown") @TestCase(TestEnum.testA | TestEnum.testB, "unknown") @Test("EnumName") - public testEnumName(inp, expected) { - const result = tsEx.enumName(inp, TestEnum); + public testEnumName(inp, expected): void { + const result = tsHelper.enumName(inp, TestEnum); Expect(result).toEqual(expected); } @@ -26,14 +29,132 @@ export class TSHelperTests { @TestCase(TestEnum.testA | TestEnum.testC, ["testA", "testC"]) @TestCase(TestEnum.testA | TestEnum.testB | TestEnum.testC, ["testA", "testB", "testC"]) @Test("EnumNames") - public testEnumNames(inp, expected) { - const result = tsEx.enumNames(inp, TestEnum); + public testEnumNames(inp, expected): void { + const result = tsHelper.enumNames(inp, TestEnum); Expect(result).toEqual(expected); } @Test("IsFileModuleNull") - public isFileModuleNull() { - Expect(tsEx.isFileModule(null)).toEqual(false); + public isFileModuleNull(): void { + Expect(tsHelper.isFileModule(null)).toEqual(false); + } + + @Test("GetCustomDecorators single") + public GetCustomDecoratorsSingle(): void { + const source = `/** @compileMembersOnly */ + enum TestEnum { + val1 = 0, + val2 = 2, + val3, + val4 = "bye", + } + + const a = TestEnum.val1;`; + + const [sourceFile, typeChecker] = util.parseTypeScript(source); + const identifier = util.findFirstChild(sourceFile, ts.isIdentifier); + const enumType = typeChecker.getTypeAtLocation(identifier); + + const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); + + Expect(decorators.size).toBe(1); + Expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); + } + + @Test("GetCustomDecorators multiple") + public GetCustomDecoratorsMultiple(): void { + const source = `/** @compileMembersOnly + * @Phantom */ + enum TestEnum { + val1 = 0, + val2 = 2, + val3, + val4 = "bye", + } + + const a = TestEnum.val1;`; + + const [sourceFile, typeChecker] = util.parseTypeScript(source); + const identifier = util.findFirstChild(sourceFile, ts.isIdentifier); + const enumType = typeChecker.getTypeAtLocation(identifier); + + const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); + + Expect(decorators.size).toBe(2); + Expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); + Expect(decorators.has(DecoratorKind.Phantom)).toBeTruthy(); + } + + @Test("GetCustomDecorators single jsdoc") + public GetCustomDecoratorsSingleJSDoc(): void { + const source = `/** @compileMembersOnly */ + enum TestEnum { + val1 = 0, + val2 = 2, + val3, + val4 = "bye", + } + + const a = TestEnum.val1;`; + + const [sourceFile, typeChecker] = util.parseTypeScript(source); + const identifier = util.findFirstChild(sourceFile, ts.isIdentifier); + const enumType = typeChecker.getTypeAtLocation(identifier); + + const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); + + Expect(decorators.size).toBe(1); + Expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); + } + + @Test("GetCustomDecorators multiple jsdoc") + public GetCustomDecoratorsMultipleJSDoc(): void { + const source = `/** @phantom + * @CompileMembersOnly */ + enum TestEnum { + val1 = 0, + val2 = 2, + val3, + val4 = "bye", + } + + const a = TestEnum.val1;`; + + const [sourceFile, typeChecker] = util.parseTypeScript(source); + const identifier = util.findFirstChild(sourceFile, ts.isIdentifier); + const enumType = typeChecker.getTypeAtLocation(identifier); + + const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); + + Expect(decorators.size).toBe(2); + Expect(decorators.has(DecoratorKind.Phantom)).toBeTruthy(); + Expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); + } + + @Test("GetCustomDecorators multiple default jsdoc") + public GetCustomDecoratorsMultipleDefaultJSDoc(): void { + const source = `/** + * @description abc + * @phantom + * @compileMembersOnly */ + enum TestEnum { + val1 = 0, + val2 = 2, + val3, + val4 = "bye", + } + + const a = TestEnum.val1;`; + + const [sourceFile, typeChecker] = util.parseTypeScript(source); + const identifier = util.findFirstChild(sourceFile, ts.isIdentifier); + const enumType = typeChecker.getTypeAtLocation(identifier); + + const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); + + Expect(decorators.size).toBe(2); + Expect(decorators.has(DecoratorKind.Phantom)).toBeTruthy(); + Expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); } } diff --git a/test/unit/tuples.spec.ts b/test/unit/tuples.spec.ts index 067776bd5..16bef9922 100644 --- a/test/unit/tuples.spec.ts +++ b/test/unit/tuples.spec.ts @@ -82,7 +82,7 @@ export class TupleTests { public tupleDestruct(): void { // Transpile const lua = util.transpileString( - `function tuple(): [number, number, number] { return [3,5,1]; }\n + `function tuple(): [number, number, number] { return [3,5,1]; } const [a,b,c] = tuple(); return b;` ); @@ -113,8 +113,8 @@ export class TupleTests { public tupleReturnAccess(): void { // Transpile const lua = util.transpileString( - `/** !TupleReturn */\n - function tuple(): [number, number, number] { return [3,5,1]; }\n + `/** @tupleReturn */ + function tuple(): [number, number, number] { return [3,5,1]; } return tuple()[2];` ); @@ -129,8 +129,8 @@ export class TupleTests { public tupleReturnDestructDeclaration(): void { // Transpile const lua = util.transpileString( - `/** !TupleReturn */\n - function tuple(): [number, number, number] { return [3,5,1]; }\n + `/** @tupleReturn */ + function tuple(): [number, number, number] { return [3,5,1]; } const [a,b,c] = tuple(); return b;` ); @@ -146,8 +146,8 @@ export class TupleTests { public tupleReturnDestructAssignment(): void { // Transpile const lua = util.transpileString( - `/** !TupleReturn */\n - function tuple(): [number, number] { return [3,6]; }\n + `/** @tupleReturn */ + function tuple(): [number, number] { return [3,6]; } const [a,b] = [1,2]; [b,a] = tuple(); return a - b;` @@ -164,10 +164,10 @@ export class TupleTests { public tupleStaticMethodReturnDestruct(): void { // Transpile const lua = util.transpileString( - `class Test {\n - /** !TupleReturn */\n - static tuple(): [number, number, number] { return [3,5,1]; }\n - }\n + `class Test { + /** @tupleReturn */ + static tuple(): [number, number, number] { return [3,5,1]; } + } const [a,b,c] = Test.tuple(); return b;` ); @@ -183,10 +183,10 @@ export class TupleTests { public tupleMethodNonStaticReturnDestruct(): void { // Transpile const lua = util.transpileString( - `class Test {\n - /** !TupleReturn */\n - tuple(): [number, number, number] { return [3,5,1]; }\n - }\n + `class Test { + /** @tupleReturn */ + tuple(): [number, number, number] { return [3,5,1]; } + } const t = new Test(); const [a,b,c] = t.tuple(); return b;`