Skip to content

Commit 7dc1bb4

Browse files
committed
Merge branch 'master' into feature/decorator-tests
2 parents 4f9dc66 + 11a2c11 commit 7dc1bb4

File tree

11 files changed

+113
-59
lines changed

11 files changed

+113
-59
lines changed

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
*.js
22
node_modules/
3-
*.lua
4-
!json.lua
5-
!dist/lualib/*.lua
63

74
coverage/
85
.nyc*

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# TypescriptToLua
2+
A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!
3+
24
[![Build Status](https://travis-ci.org/Perryvw/TypescriptToLua.svg?branch=master)](https://travis-ci.org/Perryvw/TypescriptToLua) [![Coverage](https://codecov.io/gh/perryvw/typescripttolua/branch/master/graph/badge.svg)](https://codecov.io/gh/perryvw/typescripttolua)
35

4-
Typescript to lua transpiler.
6+
## Documentation
7+
More detailed documentation and info on writing declarations can be found [on the wiki](https://github.com/Perryvw/TypescriptToLua/wiki).
58

69
## Usage Guide
710

dist/lualib/lib-typescript.d.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "typescript-to-lua",
33
"license": "MIT",
4-
"version": "0.0.7",
4+
"version": "0.0.8",
55
"repository": "https://github.com/Perryvw/TypescriptToLua",
66
"scripts": {
77
"build": "tsc -p tsconfig.json",

src/Compiler.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,33 @@ function compile(fileNames: string[], options: ts.CompilerOptions): void {
3434
process.exit(1);
3535
}
3636

37+
if (!options.rootDir) {
38+
options.rootDir = process.cwd();
39+
}
40+
41+
if (!options.outDir) {
42+
options.outDir = options.rootDir;
43+
}
44+
45+
// Copy lualib to target dir
46+
// This isnt run in sync because copyFileSync wont report errors.
47+
fs.copyFile(path.resolve(__dirname, "../dist/lualib/typescript.lua"), path.join(options.outDir, "typescript_lualib.lua"), (err: NodeJS.ErrnoException) => {
48+
if (err) {
49+
console.log("ERROR: copying lualib to output.");
50+
}
51+
});
52+
3753
program.getSourceFiles().forEach(sourceFile => {
3854
if (!sourceFile.isDeclarationFile) {
3955
try {
4056
let rootDir = options.rootDir;
41-
if (!rootDir) {
42-
rootDir = process.cwd();
43-
}
4457

4558
// Transpile AST
4659
let lua = LuaTranspiler.transpileSourceFile(sourceFile, checker, options);
4760

4861
let outPath = sourceFile.fileName;
49-
if (options.outDir) {
50-
outPath = path.join(options.outDir, sourceFile.fileName.replace(rootDir, ""));
62+
if (options.outDir !== options.rootDir) {
63+
outPath = path.join(options.outDir, path.resolve(sourceFile.fileName).replace(rootDir, ""));
5164
}
5265

5366
// change extension

src/Transpiler.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@ export class TranspileError extends Error {
1616
export class LuaTranspiler {
1717
// Transpile a source file
1818
static transpileSourceFile(node: ts.SourceFile, checker: ts.TypeChecker, options: ts.CompilerOptions): string {
19-
let transpiler = new LuaTranspiler(checker, options);
19+
let transpiler = new LuaTranspiler(checker, options, node);
2020
let header = options.addHeader ? "--=======================================================================================\n"
2121
+ "-- Generated by TypescriptToLua transpiler https://github.com/Perryvw/TypescriptToLua \n"
2222
+ "-- Date: " + new Date().toDateString() + "\n"
2323
+ "--=======================================================================================\n"
2424
: "";
25-
let result = header
26-
transpiler.isModule = tsEx.isFileModule(node);
25+
let result = header;
26+
if (!options.dontRequireLualib) {
27+
// require helper functions
28+
result += `require("typescript_lualib")\n`;
29+
}
2730
if (transpiler.isModule) {
2831
// Shadow exports if it already exists
2932
result += "local exports = exports or {}\n";
@@ -43,16 +46,18 @@ export class LuaTranspiler {
4346
namespace: string[];
4447
importCount: number;
4548
isModule: boolean;
49+
sourceFile: ts.SourceFile;
4650

47-
constructor(checker: ts.TypeChecker, options: ts.CompilerOptions) {
51+
constructor(checker: ts.TypeChecker, options: ts.CompilerOptions, sourceFile: ts.SourceFile) {
4852
this.indent = "";
4953
this.checker = checker;
5054
this.options = options;
5155
this.genVarCounter = 0;
5256
this.transpilingSwitch = false;
5357
this.namespace = [];
5458
this.importCount = 0;
55-
this.isModule = false;
59+
this.sourceFile = sourceFile;
60+
this.isModule = tsEx.isFileModule(sourceFile);
5661
}
5762

5863
pushIndent(): void {
@@ -83,6 +88,16 @@ export class LuaTranspiler {
8388
return result;
8489
}
8590

91+
getImportPath(relativePath: string) {
92+
// Calculate absolute path to import
93+
let absolutePathToImport = path.resolve(path.dirname(this.sourceFile.fileName), relativePath);
94+
if (this.options.rootDir) {
95+
// Calculate path realtive to project root and replace path.sep with dots (lua doesn't know paths)
96+
return `"${absolutePathToImport.replace(this.options.rootDir, "").replace(new RegExp("\\\\|\/", "g"), ".").slice(1)}"`;
97+
}
98+
return `"${relativePath.replace(new RegExp("\\\\|\/", "g"), ".")}"`;
99+
}
100+
86101
// Transpile a block
87102
transpileBlock(node: ts.Node): string {
88103
let result = "";
@@ -152,16 +167,18 @@ export class LuaTranspiler {
152167
}
153168

154169
transpileImport(node: ts.ImportDeclaration): string {
155-
const importFile = this.transpileExpression(node.moduleSpecifier);
170+
const importPath = this.transpileExpression(node.moduleSpecifier);
171+
let importPathWithoutQuotes = importPath.replace(new RegExp("\"", "g"), "");
172+
156173
if (!node.importClause || !node.importClause.namedBindings) {
157174
throw new TranspileError("Default Imports are not supported, please use named imports instead!", node);
158175
}
159176

160177
const imports = node.importClause.namedBindings;
161178

162179
if (ts.isNamedImports(imports)) {
163-
let fileImportTable = path.basename(importFile.replace(new RegExp("\"", "g"), "")) + this.importCount
164-
let result = `local ${fileImportTable} = require(${importFile})\n`
180+
let fileImportTable = path.basename(importPathWithoutQuotes) + this.importCount
181+
let result = `local ${fileImportTable} = require(${this.getImportPath(importPathWithoutQuotes)})\n`
165182
this.importCount++;
166183
imports.elements.forEach(element => {
167184
if (element.propertyName) {
@@ -171,6 +188,8 @@ export class LuaTranspiler {
171188
}
172189
});
173190
return result;
191+
} else if (ts.isNamespaceImport(imports)) {
192+
return `local ${imports.name.escapedText} = require(${this.getImportPath(importPathWithoutQuotes)})\n`;
174193
} else {
175194
throw new TranspileError("Unsupported import type.", node);
176195
}
@@ -375,9 +394,9 @@ export class LuaTranspiler {
375394
this.transpilingSwitch = false;
376395

377396
let i = index + 1;
378-
if (i < clauses.length && !tsEx.containsStatement(clause.statements, ts.SyntaxKind.BreakStatement)) {
397+
if (i < clauses.length && !tsEx.containsStatement(clause.statements, ts.SyntaxKind.BreakStatement))  {
379398
let nextClause = clauses[i];
380-
while(i < clauses.length
399+
while (i < clauses.length
381400
&& ts.isCaseClause(nextClause)
382401
&& nextClause.statements.length === 0
383402
) {
@@ -741,7 +760,12 @@ export class LuaTranspiler {
741760
case "splice":
742761
return `TS_splice(${caller}, ${params})`;
743762
case "join":
744-
return `table.concat(${caller}, ${params})`;
763+
if (node.arguments.length === 0) {
764+
// if seperator is omitted default seperator is ","
765+
return `table.concat(${caller}, ",")`;
766+
} else {
767+
return `table.concat(${caller}, ${params})`;
768+
}
745769
default:
746770
throw new TranspileError("Unsupported array function: " + expression.name.escapedText, node);
747771
}

test/integration/lua/lualib.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,35 @@ export class LuaLibArrayTests {
138138
Expect(result).toBe(JSON.stringify(inp.splice(start)));
139139
}
140140
}
141+
142+
@TestCase([], "")
143+
@TestCase(["test1"], "test1")
144+
@TestCase(["test1", "test2"], "test1,test2")
145+
@TestCase(["test1", "test2"], "test1;test2", ";")
146+
@TestCase(["test1", "test2"], "test1test2", "")
147+
@Test("array.join")
148+
public join<T>(inp: T[], expected: string, seperator?: string) {
149+
let seperatorLua;
150+
if (seperator === "") {
151+
seperatorLua = "\"\"";
152+
} else if (seperator) {
153+
seperatorLua = "\"" + seperator + "\"";
154+
} else {
155+
seperatorLua = "";
156+
}
157+
// Transpile
158+
let lua = util.transpileString(
159+
`let joinTestTable = ${JSON.stringify(inp)};
160+
return joinTestTable.join(${seperatorLua});`,
161+
util.dummyTypes.Array
162+
);
163+
164+
// Execute
165+
let result = util.executeLua(lua);
166+
167+
// Assert
168+
let joinedInp = inp.join(seperator);
169+
Expect(result).toBe(joinedInp);
170+
}
171+
141172
}

test/integration/lua/modules.spec.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ export class LuaModuleTests {
4040
`local test0 = require("test")
4141
local TestClass = test0.TestClass`
4242
)
43+
@TestCase(
44+
`import * as Test from "test"`,
45+
46+
`local Test = require("test")`
47+
)
4348
@TestCase(
4449
`import {TestClass as RenamedClass} from "test"`,
4550

@@ -127,12 +132,19 @@ export class LuaModuleTests {
127132
return exports`
128133
)
129134
@Test("modules")
130-
public modules<T>(inp: string, expected: string) {
135+
public modules(inp: string, expected: string) {
131136
// Transpile
132137
let lua = util.transpileString(inp, util.dummyTypes.Object);
133138

134139
// Assert
135140
// Dont test for correct indention this allows easier test case definition
136141
Expect(dedent(lua)).toBe(dedent(expected));
137142
}
143+
144+
@Test("defaultImport")
145+
public defaultImport() {
146+
Expect(() => {
147+
let lua = util.transpileString(`import TestClass from "test"`, util.dummyTypes.Object);
148+
}).toThrowError(Error, "Default Imports are not supported, please use named imports instead!");
149+
}
138150
}

test/src/util.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ export namespace dummyTypes {
1111
export const Number = { flags: ts.TypeFlags.Number, symbol: { escapedName: "Number" } };
1212
}
1313

14-
export function transpileString(str: string, dummyType: any): string {
14+
export function transpileString(str: string, dummyType: any = dummyTypes.None): string {
1515
const dummyChecker = { getTypeAtLocation: function() { return dummyType; } }
16-
const file = ts.createSourceFile("temp.ts", str, ts.ScriptTarget.Latest);
17-
const result = LuaTranspiler.transpileSourceFile(file, dummyChecker, false);
16+
const file = ts.createSourceFile("____internal_test_file.tstl", str, ts.ScriptTarget.Latest);
17+
const options: ts.CompilerOptions = { dontRequireLualib: true };
18+
const result = LuaTranspiler.transpileSourceFile(file, dummyChecker, options);
1819
return result.trim();
1920
}
2021

0 commit comments

Comments
 (0)