diff --git a/package.json b/package.json index b37192df9..e401dcab6 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "tstl", "transpiler" ], + "main": "dist/tstl.js", + "types": "dist/tstl.d.ts", "scripts": { "build": "tsc -p tsconfig.json && npm run build-lualib", "build-lualib": "ts-node ./build_lualib.ts", @@ -41,7 +43,7 @@ "node": ">=8.5.0" }, "dependencies": { - "typescript": "^2.9.2", + "typescript": "2.9.2", "yargs": "^12.0.1" }, "devDependencies": { diff --git a/src/CommandLineParser.ts b/src/CommandLineParser.ts index 7fac341a9..a743d66ad 100644 --- a/src/CommandLineParser.ts +++ b/src/CommandLineParser.ts @@ -1,23 +1,15 @@ +import { CompilerOptions } from "./CompilerOptions"; + import * as fs from "fs"; import * as path from "path"; import * as ts from "typescript"; import * as yargs from "yargs"; -export interface CompilerOptions extends ts.CompilerOptions { - addHeader?: boolean; - luaTarget?: string; - luaLibImport?: string; -} - -export interface ParsedCommandLine extends ts.ParsedCommandLine { +interface ParsedCommandLine extends ts.ParsedCommandLine { options: CompilerOptions; } -export class CLIError extends Error { - -} - -export interface YargsOptions { +interface YargsOptions { [key: string]: yargs.Options; } @@ -42,6 +34,10 @@ export const optionDeclarations: YargsOptions = { }, }; +class CLIError extends Error { + +} + /** * Removes defaults from the arguments. * Returns a tuple where [0] is a copy of the options without defaults and [1] is the extracted defaults. diff --git a/src/Compiler.ts b/src/Compiler.ts index 7d01f0ea9..b15c3850f 100644 --- a/src/Compiler.ts +++ b/src/Compiler.ts @@ -2,12 +2,11 @@ import * as fs from "fs"; import * as path from "path"; import * as ts from "typescript"; -import { CompilerOptions, parseCommandLine } from "./CommandLineParser"; -import { LuaTranspiler51 } from "./targets/Transpiler.51"; -import { LuaTranspiler52 } from "./targets/Transpiler.52"; -import { LuaTranspiler53 } from "./targets/Transpiler.53"; -import { LuaTranspilerJIT } from "./targets/Transpiler.JIT"; -import { LuaLibImportKind, LuaTarget, LuaTranspiler } from "./Transpiler"; +import { parseCommandLine } from "./CommandLineParser"; +import { CompilerOptions } from "./CompilerOptions"; +import { LuaLibImportKind, LuaTarget } from "./Transpiler"; + +import { createTranspiler } from "./TranspilerFactory"; export function compile(argv: string[]): void { const commandLine = parseCommandLine(argv); @@ -154,27 +153,57 @@ function emitFilesAndReportErrors(program: ts.Program): number { return 0; } -export function createTranspiler(checker: ts.TypeChecker, - options: CompilerOptions, - sourceFile: ts.SourceFile): LuaTranspiler { - let luaTargetTranspiler: LuaTranspiler; - const target = options.luaTarget ? options.luaTarget.toLowerCase() : ""; - switch (target) { - case LuaTarget.Lua51: - luaTargetTranspiler = new LuaTranspiler51(checker, options, sourceFile); - break; - case LuaTarget.Lua52: - luaTargetTranspiler = new LuaTranspiler52(checker, options, sourceFile); - break; - case LuaTarget.Lua53: - luaTargetTranspiler = new LuaTranspiler53(checker, options, sourceFile); - break; - default: - luaTargetTranspiler = new LuaTranspilerJIT(checker, options, sourceFile); - break; - } +const libSource = fs.readFileSync(path.join(path.dirname(require.resolve("typescript")), "lib.es6.d.ts")).toString(); + +export function transpileString(str: string, + options: CompilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + }): string { + 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, str, ts.ScriptTarget.Latest, false); + } + if (filename === "lib.es6.d.ts") { + 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"], options, compilerHost); + + const result = createTranspiler(program.getTypeChecker(), + options, + program.getSourceFile("file.ts")).transpileSourceFile(); + return result.trim(); +} + +export function transpileFile(filePath: string): string { + const program = ts.createProgram([filePath], {}); + const checker = program.getTypeChecker(); + + // Output errors + const diagnostics = ts.getPreEmitDiagnostics(program).filter(diag => diag.code !== 6054); + diagnostics.forEach(diagnostic => console.log(`${ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`)); - return luaTargetTranspiler; + const options: ts.CompilerOptions = { luaLibImport: "none" }; + const result = createTranspiler(checker, options, program.getSourceFile(filePath)).transpileSourceFile(); + return result.trim(); } function reportDiagnostic(diagnostic: ts.Diagnostic): void { diff --git a/src/CompilerOptions.ts b/src/CompilerOptions.ts new file mode 100644 index 000000000..e40291aa0 --- /dev/null +++ b/src/CompilerOptions.ts @@ -0,0 +1,7 @@ +import * as ts from "typescript"; + +export interface CompilerOptions extends ts.CompilerOptions { + addHeader?: boolean; + luaTarget?: string; + luaLibImport?: string; +} diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 9bc655566..02b5762df 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -47,6 +47,7 @@ export class TSHelper { if (sourceFile) { // Vanilla ts flags files as external module if they have an import or // export statement, we only check for export statements + // TODO will break in 3.x return sourceFile.statements.some(statement => (ts.getCombinedModifierFlags(statement) & ts.ModifierFlags.Export) !== 0 || statement.kind === ts.SyntaxKind.ExportAssignment diff --git a/src/Transpiler.ts b/src/Transpiler.ts index b2bad2685..ccafbaf81 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -2,7 +2,7 @@ import * as fs from "fs"; import * as path from "path"; import * as ts from "typescript"; -import { CompilerOptions } from "./CommandLineParser"; +import { CompilerOptions } from "./CompilerOptions"; import { DecoratorKind } from "./Decorator"; import { TSTLErrors } from "./Errors"; import { TSHelper as tsHelper } from "./TSHelper"; @@ -124,7 +124,7 @@ export abstract class LuaTranspiler { if (node && node.modifiers && this.isModule && this.namespace.length === 0 && - (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) + (ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export) ) { if (dummy) { result = this.indent + `exports.${this.definitionName(name)} = {}\n`; @@ -133,7 +133,7 @@ export abstract class LuaTranspiler { } } if (this.namespace.length !== 0 && - (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export)) { + (ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export)) { if (dummy) { result += this.indent + `${this.namespace[this.namespace.length - 1]}.${name} = {}\n`; } else { diff --git a/src/TranspilerFactory.ts b/src/TranspilerFactory.ts new file mode 100644 index 000000000..580438962 --- /dev/null +++ b/src/TranspilerFactory.ts @@ -0,0 +1,33 @@ +import { LuaTranspiler51 } from "./targets/Transpiler.51"; +import { LuaTranspiler52 } from "./targets/Transpiler.52"; +import { LuaTranspiler53 } from "./targets/Transpiler.53"; +import { LuaTranspilerJIT } from "./targets/Transpiler.JIT"; + +import { LuaTarget, LuaTranspiler } from "./Transpiler"; + +import { CompilerOptions } from "./CompilerOptions"; + +import * as ts from "typescript"; + +export function createTranspiler( + checker: ts.TypeChecker, options: CompilerOptions, + sourceFile: ts.SourceFile): LuaTranspiler { + let luaTargetTranspiler: LuaTranspiler; + const target = options.luaTarget ? options.luaTarget.toLowerCase() : ""; + switch (target) { + case LuaTarget.Lua51: + luaTargetTranspiler = new LuaTranspiler51(checker, options, sourceFile); + break; + case LuaTarget.Lua52: + luaTargetTranspiler = new LuaTranspiler52(checker, options, sourceFile); + break; + case LuaTarget.Lua53: + luaTargetTranspiler = new LuaTranspiler53(checker, options, sourceFile); + break; + default: + luaTargetTranspiler = new LuaTranspilerJIT(checker, options, sourceFile); + break; + } + + return luaTargetTranspiler; +} diff --git a/src/tstl.ts b/src/tstl.ts new file mode 100644 index 000000000..cef7e8cc0 --- /dev/null +++ b/src/tstl.ts @@ -0,0 +1,31 @@ +export { + parseCommandLine +} from "./CommandLineParser"; + +export { + CompilerOptions +} from "./CompilerOptions"; + +export { + compile, + compileFilesWithOptions, + transpileFile, + transpileString, + watchWithOptions +} from "./Compiler"; + +export {LuaTranspiler51} from "./targets/Transpiler.51"; +export {LuaTranspiler52} from "./targets/Transpiler.52"; +export {LuaTranspiler53} from "./targets/Transpiler.53"; +export {LuaTranspilerJIT} from "./targets/Transpiler.JIT"; + +export { + LuaLibFeature, + LuaLibImportKind, + LuaTarget, + LuaTranspiler, +} from "./Transpiler"; + +export { + createTranspiler +} from "./TranspilerFactory"; diff --git a/test/src/util.ts b/test/src/util.ts index a7dce9101..71f8227ac 100644 --- a/test/src/util.ts +++ b/test/src/util.ts @@ -3,62 +3,15 @@ import * as ts from "typescript"; import { Expect } from "alsatian"; -import { CompilerOptions } from "../../src/CommandLineParser"; -import { createTranspiler } from "../../src/Compiler"; -import { LuaLibImportKind, LuaTarget, LuaTranspiler } from "../../src/Transpiler"; +import { transpileString } from "../../src/Compiler"; +import { LuaTarget, LuaTranspiler } from "../../src/Transpiler"; +import { createTranspiler } from "../../src/TranspilerFactory"; import {lauxlib, lua, lualib, to_jsstring, to_luastring } from "fengari"; -const fs = require("fs"); - -const libSource = fs.readFileSync(path.join(path.dirname(require.resolve("typescript")), "lib.es6.d.ts")).toString(); - -export function transpileString(str: string, options: CompilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53 }): string { - 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, str, ts.ScriptTarget.Latest, false); - } - if (filename === "lib.es6.d.ts") { - 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"], options, compilerHost); - - const result = createTranspiler(program.getTypeChecker(), - options, - program.getSourceFile("file.ts")).transpileSourceFile(); - return result.trim(); -} - -export function transpileFile(filePath: string): string { - const program = ts.createProgram([filePath], {}); - const checker = program.getTypeChecker(); +import * as fs from "fs"; - // Output errors - const diagnostics = ts.getPreEmitDiagnostics(program).filter(diag => diag.code !== 6054); - diagnostics.forEach(diagnostic => console.log(`${ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`)); - - const options: ts.CompilerOptions = { luaLibImport: "none" }; - const result = createTranspiler(checker, options, program.getSourceFile(filePath)).transpileSourceFile(); - return result.trim(); -} +export { transpileString }; export function executeLua(luaStr: string, withLib = true): any { if (withLib) { @@ -91,7 +44,7 @@ export function executeLua(luaStr: string, withLib = true): any { } } -export function expectCodeEqual(code1: string, code2: string) { +export function expectCodeEqual(code1: string, code2: string): void { // Trim leading/trailing whitespace let c1 = code1.trim(); let c2 = code2.trim(); @@ -104,14 +57,14 @@ export function expectCodeEqual(code1: string, code2: string) { } // Get a mock transpiler to use for testing -export function makeTestTranspiler(target: LuaTarget = LuaTarget.Lua53) { +export function makeTestTranspiler(target: LuaTarget = LuaTarget.Lua53): LuaTranspiler { return createTranspiler({} as ts.TypeChecker, { luaLibImport: "none", luaTarget: target } as any, { statements: [] } as any as ts.SourceFile); } -export function transpileAndExecute(ts: string): any { - return executeLua(transpileString(ts)); +export function transpileAndExecute(tsStr: string): any { + return executeLua(transpileString(tsStr)); } const jsonlib = fs.readFileSync("test/src/json.lua") + "\n"; diff --git a/test/unit/cli.spec.ts b/test/unit/cli.spec.ts index f8ebcb7c2..98e842b6c 100644 --- a/test/unit/cli.spec.ts +++ b/test/unit/cli.spec.ts @@ -1,6 +1,6 @@ -import { Expect, Test, TestCase, Teardown } from "alsatian"; +import { Expect, Test, TestCase } from "alsatian"; -import { CompilerOptions, findConfigFile, parseCommandLine, ParsedCommandLine } from "../../src/CommandLineParser"; +import { findConfigFile, parseCommandLine } from "../../src/CommandLineParser"; export class CLITests { diff --git a/test/unit/compiler/configuration/mixed/index.spec.ts b/test/unit/compiler/configuration/mixed/index.spec.ts index 71c2c40ee..18e52b677 100644 --- a/test/unit/compiler/configuration/mixed/index.spec.ts +++ b/test/unit/compiler/configuration/mixed/index.spec.ts @@ -1,9 +1,10 @@ -import { Expect, Test, TestCase, Teardown } from "alsatian"; -import * as path from 'path'; -import * as fs from 'fs'; +import { Expect, Test } from "alsatian"; +import * as fs from "fs"; +import * as path from "path"; import * as ts from "typescript"; -import { CompilerOptions, findConfigFile, parseCommandLine, ParsedCommandLine, optionDeclarations } from "../../../../../src/CommandLineParser"; +import { CompilerOptions } from "../../../../../src/CompilerOptions"; +import { optionDeclarations, parseCommandLine } from "../../../../../src/CommandLineParser"; import { LuaLibImportKind } from "../../../../../src/Transpiler"; export class MixedConfigurationTests { @@ -16,17 +17,17 @@ export class MixedConfigurationTests { ts.parseConfigFileTextToJson(tsConfigPath, fs.readFileSync(tsConfigPath).toString()).config, ts.sys, path.dirname(tsConfigPath) - ); + ); const parsedArgs = parseCommandLine([ "-p", `"${tsConfigPath}"`, "--luaLibImport", LuaLibImportKind.Inline, - `${path.join(rootPath, 'test.ts')}`, + `${path.join(rootPath, "test.ts")}`, ]); - - Expect(parsedArgs.options).toEqual({ + + Expect(parsedArgs.options).toEqual({ ...expectedTsConfig.options, // Overridden by cmd args (set to "none" in project-tsconfig.json) luaLibImport: LuaLibImportKind.Inline, @@ -35,6 +36,6 @@ export class MixedConfigurationTests { // Only present in TSTL dfaults noHeader: optionDeclarations["noHeader"].default, project: tsConfigPath - }); + } as CompilerOptions); } } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 1d2eb76cc..09ebff3e9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,10 +4,11 @@ "alwaysStrict" : true, "outDir": "./dist/", "rootDir": "./src/", + "declaration": true, "sourceMap": true, "experimentalDecorators": true, "target": "es6", "module": "commonjs" }, - "exclude": ["test/**/*", "build_lualib.ts", "src/lualib"] + "exclude": ["test/**/*", "build_lualib.ts", "src/lualib", "dist/**/*"] }