Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
*.js
node_modules/
*.lua
!json.lua
!dist/lualib/*.lua

coverage/
.nyc*
Expand Down
22 changes: 0 additions & 22 deletions dist/lualib/lib-typescript.d.ts

This file was deleted.

21 changes: 17 additions & 4 deletions src/Compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,32 @@ function compile(fileNames: string[], options: ts.CompilerOptions): void {
process.exit(1);
}

if (!options.rootDir) {
options.rootDir = process.cwd();
}

if (!options.outDir) {
options.outDir = options.rootDir;
}

// Copy lualib to target dir
// This isnt run in sync because copyFileSync wont report errors.
fs.copyFile(path.resolve(__dirname, "../dist/lualib/typescript.lua"), path.join(options.outDir, "typescript_lualib.lua"), (err: NodeJS.ErrnoException) => {
if (err) {
console.log("ERROR: copying lualib to output.");
}
});

program.getSourceFiles().forEach(sourceFile => {
if (!sourceFile.isDeclarationFile) {
try {
let rootDir = options.rootDir;
if (!rootDir) {
rootDir = process.cwd();
}

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

let outPath = sourceFile.fileName;
if (options.outDir) {
if (options.outDir !== options.rootDir) {
outPath = path.join(options.outDir, sourceFile.fileName.replace(rootDir, ""));
}

Expand Down
36 changes: 26 additions & 10 deletions src/Transpiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ export class TranspileError extends Error {
export class LuaTranspiler {
// Transpile a source file
static transpileSourceFile(node: ts.SourceFile, checker: ts.TypeChecker, options: ts.CompilerOptions): string {
let transpiler = new LuaTranspiler(checker, options);
let transpiler = new LuaTranspiler(checker, options, node);
let header = options.addHeader ? "--=======================================================================================\n"
+ "-- Generated by TypescriptToLua transpiler https://github.com/Perryvw/TypescriptToLua \n"
+ "-- Date: " + new Date().toDateString() + "\n"
+ "--=======================================================================================\n"
: "";
let result = header
transpiler.isModule = tsEx.isFileModule(node);
let result = header;
if (!options.dontRequireLualib) {
// require helper functions
result += `require("typescript_lualib")\n`;
}
if (transpiler.isModule) {
// Shadow exports if it already exists
result += "local exports = exports or {}\n";
Expand All @@ -43,16 +46,18 @@ export class LuaTranspiler {
namespace: string[];
importCount: number;
isModule: boolean;
sourceFile: ts.SourceFile;

constructor(checker: ts.TypeChecker, options: ts.CompilerOptions) {
constructor(checker: ts.TypeChecker, options: ts.CompilerOptions, sourceFile: ts.SourceFile) {
this.indent = "";
this.checker = checker;
this.options = options;
this.genVarCounter = 0;
this.transpilingSwitch = false;
this.namespace = [];
this.importCount = 0;
this.isModule = false;
this.sourceFile = sourceFile;
this.isModule = tsEx.isFileModule(sourceFile);
}

pushIndent(): void {
Expand Down Expand Up @@ -83,6 +88,16 @@ export class LuaTranspiler {
return result;
}

getImportPath(relativePath: string) {
// Calculate absolute path to import
let absolutePathToImport = path.resolve(path.dirname(this.sourceFile.fileName), relativePath);
if (this.options.rootDir) {
// Calculate path realtive to project root and replace path.sep with dots (lua doesn't know paths)
return `"${absolutePathToImport.replace(this.options.rootDir, "").replace(new RegExp("\\\\|\/", "g"), ".").slice(1)}"`;
}
return `"${relativePath.replace(new RegExp("\\\\|\/", "g"), ".")}"`;
}

// Transpile a block
transpileBlock(node: ts.Node): string {
let result = "";
Expand Down Expand Up @@ -152,16 +167,17 @@ export class LuaTranspiler {
}

transpileImport(node: ts.ImportDeclaration): string {
const importFile = this.transpileExpression(node.moduleSpecifier);
const importPath = this.transpileExpression(node.moduleSpecifier);
if (!node.importClause || !node.importClause.namedBindings) {
throw new TranspileError("Default Imports are not supported, please use named imports instead!", node);
}

const imports = node.importClause.namedBindings;

if (ts.isNamedImports(imports)) {
let fileImportTable = path.basename(importFile.replace(new RegExp("\"", "g"), "")) + this.importCount
let result = `local ${fileImportTable} = require(${importFile})\n`
let importPathWithoutQuotes = importPath.replace(new RegExp("\"", "g"), "");
let fileImportTable = path.basename(importPathWithoutQuotes) + this.importCount
let result = `local ${fileImportTable} = require(${this.getImportPath(importPathWithoutQuotes)})\n`
this.importCount++;
imports.elements.forEach(element => {
if (element.propertyName) {
Expand Down Expand Up @@ -375,9 +391,9 @@ export class LuaTranspiler {
this.transpilingSwitch = false;

let i = index + 1;
if (i < clauses.length && !tsEx.containsStatement(clause.statements, ts.SyntaxKind.BreakStatement)) {
if (i < clauses.length && !tsEx.containsStatement(clause.statements, ts.SyntaxKind.BreakStatement))  {
let nextClause = clauses[i];
while(i < clauses.length
while (i < clauses.length
&& ts.isCaseClause(nextClause)
&& nextClause.statements.length === 0
) {
Expand Down
7 changes: 4 additions & 3 deletions test/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ export namespace dummyTypes {
export const Number = { flags: ts.TypeFlags.Number, symbol: { escapedName: "Number" } };
}

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

Expand Down
17 changes: 6 additions & 11 deletions test/unit/expressions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ import { Expect, Test, TestCase } from "alsatian";
import * as ts from "typescript";
import {LuaTranspiler, TranspileError} from "../../dist/Transpiler";

const dummyChecker = {getTypeAtLocation: function() {return {};}}
function transpileString(str: string): string {
const file = ts.createSourceFile("", str, ts.ScriptTarget.Latest);
const result = LuaTranspiler.transpileSourceFile(file, dummyChecker, false);
return result.trim();
}
import * as util from "../src/util";

export class ExpressionTests {

Expand All @@ -20,7 +15,7 @@ export class ExpressionTests {
@TestCase("-a", "-a")
@Test("Unary expressions basic")
public unaryBasic(input: string, lua: string) {
Expect(transpileString(input)).toBe(lua);
Expect(util.transpileString(input)).toBe(lua);
}

@TestCase("1+1", "1+1")
Expand All @@ -31,7 +26,7 @@ export class ExpressionTests {
@TestCase("1==1", "1==1")
@Test("Binary expressions basic")
public binary(input: string, lua: string) {
Expect(transpileString(input)).toBe(lua);
Expect(util.transpileString(input)).toBe(lua);
}

@TestCase("a+=b", "a=a+b")
Expand All @@ -50,7 +45,7 @@ export class ExpressionTests {
@TestCase("a>>>=b", "a=bit.rshift(a,b)")
@Test("Binary expressions overridden operators")
public binaryOperatorOverride(input: string, lua: string) {
Expect(transpileString(input)).toBe(lua);
Expect(util.transpileString(input)).toBe(lua);
}

@TestCase("1+1", "1+1")
Expand All @@ -60,13 +55,13 @@ export class ExpressionTests {
@TestCase("1*(3+4*2)", "1*(3+(4*2))")
@Test("Binary expressions ordering parentheses")
public binaryParentheses(input: string, lua: string) {
Expect(transpileString(input)).toBe(lua);
Expect(util.transpileString(input)).toBe(lua);
}

@TestCase("1 + a ? 3*a : c", "TS_ITE(1+a,function() return 3*a end,function() return c end)")
@TestCase("a ? b : c", "TS_ITE(a,function() return b end,function() return c end)")
@Test("Ternary operator")
public conditional(input: string, lua: string) {
Expect(transpileString(input)).toBe(lua);
Expect(util.transpileString(input)).toBe(lua);
}
}