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
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"jest-circus": "^25.1.0",
"lua-types": "^2.8.0",
"lua-wasm-bindings": "^0.2.2",
"prettier": "^2.0.5",
"prettier": "^2.3.2",
"ts-jest": "^26.3.0",
"ts-node": "^8.6.2"
}
Expand Down
15 changes: 8 additions & 7 deletions src/CompilerOptions.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import * as ts from "typescript";
import * as diagnosticFactories from "./transpilation/diagnostics";

type KnownKeys<T> = { [K in keyof T]: string extends K ? never : number extends K ? never : K } extends {
[K in keyof T]: infer U;
}
? U
: never;

type OmitIndexSignature<T extends Record<any, any>> = Pick<T, KnownKeys<T>>;
type OmitIndexSignature<T> = {
[K in keyof T as string extends K ? never : number extends K ? never : K]: T[K];
};

export interface TransformerImport {
transform: string;
Expand Down Expand Up @@ -35,6 +31,7 @@ export type CompilerOptions = OmitIndexSignature<ts.CompilerOptions> & {
sourceMapTraceback?: boolean;
luaPlugins?: LuaPluginImport[];
plugins?: Array<ts.PluginImport | TransformerImport>;
tstlVerbose?: boolean;
[option: string]: any;
};

Expand Down Expand Up @@ -73,5 +70,9 @@ export function validateOptions(options: CompilerOptions): ts.Diagnostic[] {
diagnostics.push(diagnosticFactories.usingLuaBundleWithInlineMightGenerateDuplicateCode());
}

if (options.luaBundle && options.buildMode === BuildMode.Library) {
diagnostics.push(diagnosticFactories.cannotBundleLibrary());
}

return diagnostics;
}
5 changes: 5 additions & 0 deletions src/cli/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ export const optionDeclarations: CommandLineOption[] = [
description: "List of TypeScriptToLua plugins.",
type: "object",
},
{
name: "tstlVerbose",
description: "Provide verbose output useful for diagnosing problems.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
description: "Provide verbose output useful for diagnosing problems.",
description: "Provide verbose output, useful for diagnosing problems.",

?

type: "boolean",
},
];

export function updateParsedConfigFile(parsedConfigFile: ts.ParsedCommandLine): ParsedCommandLine {
Expand Down
3 changes: 1 addition & 2 deletions src/transformation/context/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ export interface DiagnosticsProducingTypeChecker extends ts.TypeChecker {

export class TransformationContext {
public readonly diagnostics: ts.Diagnostic[] = [];
public readonly checker: DiagnosticsProducingTypeChecker = (this
.program as any).getDiagnosticsProducingTypeChecker();
public readonly checker: DiagnosticsProducingTypeChecker = this.program.getDiagnosticsProducingTypeChecker();
public readonly resolver: EmitResolver;

public readonly options: CompilerOptions = this.program.getCompilerOptions();
Expand Down
5 changes: 5 additions & 0 deletions src/transpilation/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,8 @@ export const usingLuaBundleWithInlineMightGenerateDuplicateCode = createSerialDi
"Using 'luaBundle' with 'luaLibImport: \"inline\"' might generate duplicate code. " +
"It is recommended to use 'luaLibImport: \"require\"'.",
}));

export const cannotBundleLibrary = createDiagnosticFactory(
() =>
'Cannot bundle probjects with"buildmode": "library". Projects including the library can still bundle (which will include external library files).'
);
19 changes: 17 additions & 2 deletions src/transpilation/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import * as fs from "fs";
import { EmitHost, ProcessedFile } from "./utils";
import { SourceNode } from "source-map";
import { getEmitPathRelativeToOutDir, getProjectRoot, getSourceDir } from "./transpiler";
import { formatPathToLuaPath, trimExtension } from "../utils";
import { formatPathToLuaPath, normalizeSlashes, trimExtension } from "../utils";
import { couldNotReadDependency, couldNotResolveRequire } from "./diagnostics";
import { BuildMode } from "../CompilerOptions";
import { BuildMode, CompilerOptions } from "../CompilerOptions";

const resolver = resolve.ResolverFactory.createResolver({
extensions: [".lua"],
Expand All @@ -24,9 +24,14 @@ interface ResolutionResult {
export function resolveDependencies(program: ts.Program, files: ProcessedFile[], emitHost: EmitHost): ResolutionResult {
const outFiles: ProcessedFile[] = [...files];
const diagnostics: ts.Diagnostic[] = [];
const options = program.getCompilerOptions() as CompilerOptions;

// Resolve dependencies for all processed files
for (const file of files) {
if (options.tstlVerbose) {
console.log(`Resolving dependencies for ${normalizeSlashes(file.fileName)}`);
}

const resolutionResult = resolveFileDependencies(file, program, emitHost);
outFiles.push(...resolutionResult.resolvedFiles);
diagnostics.push(...resolutionResult.diagnostics);
Expand All @@ -38,6 +43,7 @@ export function resolveDependencies(program: ts.Program, files: ProcessedFile[],
function resolveFileDependencies(file: ProcessedFile, program: ts.Program, emitHost: EmitHost): ResolutionResult {
const dependencies: ProcessedFile[] = [];
const diagnostics: ts.Diagnostic[] = [];
const options = program.getCompilerOptions() as CompilerOptions;

for (const required of findRequiredPaths(file.code)) {
// Do no resolve lualib
Expand All @@ -57,6 +63,10 @@ function resolveFileDependencies(file: ProcessedFile, program: ts.Program, emitH
const fileDir = path.dirname(file.fileName);
const resolvedDependency = resolveDependency(fileDir, required, program, emitHost);
if (resolvedDependency) {
if (options.tstlVerbose) {
console.log(`Resolved ${required} to ${normalizeSlashes(resolvedDependency)}`);
}

// Figure out resolved require path and dependency output path
const resolvedRequire = getEmitPathRelativeToOutDir(resolvedDependency, program);

Expand Down Expand Up @@ -100,6 +110,11 @@ function resolveDependency(
program: ts.Program,
emitHost: EmitHost
): string | undefined {
const options = program.getCompilerOptions() as CompilerOptions;
if (options.tstlVerbose) {
console.log(`Resolving "${dependency}" from ${normalizeSlashes(fileDirectory)}`);
}

// Check if file is a file in the project
const resolvedPath = path.join(fileDirectory, dependency);

Expand Down
17 changes: 17 additions & 0 deletions src/transpilation/transpile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export function getProgramTranspileResult(
): TranspileResult {
const options = program.getCompilerOptions() as CompilerOptions;

if (options.tstlVerbose) {
console.log("Parsing project settings");
}

const diagnostics = validateOptions(options);
let transpiledFiles: ProcessedFile[] = [];

Expand Down Expand Up @@ -57,13 +61,26 @@ export function getProgramTranspileResult(
}

const plugins = getPlugins(program, diagnostics, customPlugins);

if (options.tstlVerbose) {
console.log(`Successfully loaded ${plugins.length} plugins`);
}

const visitorMap = createVisitorMap(plugins.map(p => p.visitors).filter(isNonNull));
const printer = createPrinter(plugins.map(p => p.printer).filter(isNonNull));
const processSourceFile = (sourceFile: ts.SourceFile) => {
if (options.tstlVerbose) {
console.log(`Transforming ${sourceFile.fileName}`);
}

const { file, diagnostics: transformDiagnostics } = transformSourceFile(program, sourceFile, visitorMap);

diagnostics.push(...transformDiagnostics);
if (!options.noEmit && !options.emitDeclarationOnly) {
if (options.tstlVerbose) {
console.log(`Printing ${sourceFile.fileName}`);
}

const printResult = printer(program, emitHost, sourceFile.fileName, file);
transpiledFiles.push({
sourceFiles: [sourceFile],
Expand Down
25 changes: 23 additions & 2 deletions src/transpilation/transpiler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as path from "path";
import * as ts from "typescript";
import { isBundleEnabled } from "../CompilerOptions";
import { CompilerOptions, isBundleEnabled } from "../CompilerOptions";
import { getLuaLibBundle } from "../LuaLib";
import { normalizeSlashes, trimExtension } from "../utils";
import { getBundleResult } from "./bundle";
Expand Down Expand Up @@ -29,6 +29,7 @@ export class Transpiler {

public emit(emitOptions: EmitOptions): EmitResult {
const { program, writeFile = this.emitHost.writeFile } = emitOptions;
const verbose = (program.getCompilerOptions() as CompilerOptions).tstlVerbose;
const { diagnostics, transpiledFiles: freshFiles } = getProgramTranspileResult(
this.emitHost,
writeFile,
Expand All @@ -37,15 +38,27 @@ export class Transpiler {

const { emitPlan } = this.getEmitPlan(program, diagnostics, freshFiles);

if (verbose) {
console.log("Emitting output");
}

const options = program.getCompilerOptions();
const emitBOM = options.emitBOM ?? false;
for (const { outputPath, code, sourceMap, sourceFiles } of emitPlan) {
if (verbose) {
console.log(`Emitting ${normalizeSlashes(outputPath)}`);
}

writeFile(outputPath, code, emitBOM, undefined, sourceFiles);
if (options.sourceMap && sourceMap !== undefined) {
writeFile(outputPath + ".map", sourceMap, emitBOM, undefined, sourceFiles);
}
}

if (verbose) {
console.log("Emit finished!");
}

return { diagnostics, emitSkipped: emitPlan.length === 0 };
}

Expand All @@ -54,10 +67,18 @@ export class Transpiler {
diagnostics: ts.Diagnostic[],
files: ProcessedFile[]
): { emitPlan: EmitFile[] } {
const options = program.getCompilerOptions();
const options = program.getCompilerOptions() as CompilerOptions;

if (options.tstlVerbose) {
console.log("Constructing emit plan");
}

const lualibRequired = files.some(f => f.code.includes('require("lualib_bundle")'));
if (lualibRequired) {
if (options.tstlVerbose) {
console.log("Including lualib bundle");
}

// Add lualib bundle to source dir 'virtually', will be moved to correct output dir in emitPlan
const fileName = normalizeSlashes(path.resolve(getSourceDir(program), "lualib_bundle.lua"));
files.unshift({ fileName, code: getLuaLibBundle(this.emitHost) });
Expand Down
3 changes: 3 additions & 0 deletions src/typescript-internal.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { DiagnosticsProducingTypeChecker } from "./transformation/context";

export {};

declare module "typescript" {
Expand All @@ -14,6 +16,7 @@ declare module "typescript" {

interface Program {
getCommonSourceDirectory(): string;
getDiagnosticsProducingTypeChecker(): DiagnosticsProducingTypeChecker;
}

interface CompilerOptions {
Expand Down
2 changes: 2 additions & 0 deletions test/cli/parse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ describe("command line", () => {
["noHeader", "true", { noHeader: true }],
["sourceMapTraceback", "false", { sourceMapTraceback: false }],
["sourceMapTraceback", "true", { sourceMapTraceback: true }],
["tstlVerbose", "true", { tstlVerbose: true }],
["tstlVerbose", "false", { tstlVerbose: false }],

["buildMode", "default", { buildMode: tstl.BuildMode.Default }],
["buildMode", "library", { buildMode: tstl.BuildMode.Library }],
Expand Down
20 changes: 20 additions & 0 deletions test/transpile/__snapshots__/project.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should give verbose output 1`] = `
Array [
"Parsing project settings",
"Successfully loaded 0 plugins",
"Transforming <cwd>/test/transpile/project/otherFile.ts",
"Printing <cwd>/test/transpile/project/otherFile.ts",
"Transforming <cwd>/test/transpile/project/index.ts",
"Printing <cwd>/test/transpile/project/index.ts",
"Constructing emit plan",
"Resolving dependencies for <cwd>/test/transpile/project/otherFile.ts",
"Resolving dependencies for <cwd>/test/transpile/project/index.ts",
"Resolving \\"./otherFile\\" from <cwd>/test/transpile/project",
"Resolved ./otherFile to <cwd>/test/transpile/project/otherFile.ts",
"Emitting output",
"Emitting <cwd>/test/transpile/project/otherFile.lua",
"Emitting <cwd>/test/transpile/project/index.lua",
"Emit finished!",
]
`;

exports[`should transpile 1`] = `
Array [
Object {
Expand Down
19 changes: 0 additions & 19 deletions test/transpile/module-resolution.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,25 +230,6 @@ describe("module resolution in library mode", () => {
expect(file.lua).not.toContain('require("lua_modules');
}
});

test("bundle works in library mode because no external dependencies", () => {
const projectPath = path.resolve(__dirname, "module-resolution", "project-with-lua-sources");
const mainFile = path.join(projectPath, "main.ts");

const { transpiledFiles } = util
.testProject(path.join(projectPath, "tsconfig.json"))
.setMainFileName(path.join(projectPath, "main.ts"))
.setOptions({ buildMode: tstl.BuildMode.Library, luaBundle: "bundle.lua", luaBundleEntry: mainFile })
.expectToEqual({
funcFromLuaFile: "lua file in subdir",
funcFromSubDirLuaFile: "lua file in subdir",
})
.getLuaResult();

for (const file of transpiledFiles) {
expect(file.lua).not.toContain('require("lua_modules');
}
});
});

describe("module resolution project with dependencies built by tstl library mode", () => {
Expand Down
20 changes: 20 additions & 0 deletions test/transpile/project.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as path from "path";
import { normalizeSlashes } from "../../src/utils";
import * as util from "../util";

test("should transpile", () => {
Expand All @@ -13,3 +14,22 @@ test("should transpile", () => {
transpiledFiles.map(f => ({ filePath: path.relative(projectDir, f.outPath), lua: f.lua }))
).toMatchSnapshot();
});

test("should give verbose output", () => {
// Capture console logs
const consoleLogs: string[] = [];
const originalLog = console.log;
console.log = (...args: any[]) => {
consoleLogs.push(args.map(a => a.toString().replace(normalizeSlashes(process.cwd()), "<cwd>")).join(","));
};

const projectDir = path.join(__dirname, "project");
util.testProject(path.join(projectDir, "tsconfig.json"))
.setMainFileName(path.join(projectDir, "index.ts"))
.setOptions({ tstlVerbose: true })
.expectToHaveNoDiagnostics();

console.log = originalLog;

expect(consoleLogs).toMatchSnapshot();
});
Loading