diff --git a/src/cli/parse.ts b/src/cli/parse.ts index a49510780..2b9885e59 100644 --- a/src/cli/parse.ts +++ b/src/cli/parse.ts @@ -135,6 +135,8 @@ export function updateParsedConfigFile(parsedConfigFile: ts.ParsedCommandLine): } } + Object.assign(parsedConfigFile.options, { projectReferences: parsedConfigFile.projectReferences }); + return parsedConfigFile; } diff --git a/src/cli/tsconfig.ts b/src/cli/tsconfig.ts index bc6fb5ae9..1e599cd63 100644 --- a/src/cli/tsconfig.ts +++ b/src/cli/tsconfig.ts @@ -41,6 +41,14 @@ export function parseConfigFileWithSystem( commandLineOptions?: CompilerOptions, system = ts.sys ): ParsedCommandLine { + if (!system.fileExists(configFileName)) { + return { + options: {}, + fileNames: [configFileName], + errors: [cliDiagnostics.theSpecifiedPathDoesNotExist(configFileName)], + }; + } + const parsedConfigFile = ts.parseJsonSourceFileConfigFileContent( ts.readJsonConfigFile(configFileName, system.readFile), system, diff --git a/src/transpilation/index.ts b/src/transpilation/index.ts index d4e890719..8d5dcbbe0 100644 --- a/src/transpilation/index.ts +++ b/src/transpilation/index.ts @@ -19,11 +19,10 @@ export function transpileFiles( writeFile?: ts.WriteFileCallback ): EmitResult { const program = ts.createProgram(rootNames, options); - const preEmitDiagnostics = ts.getPreEmitDiagnostics(program); const { diagnostics: transpileDiagnostics, emitSkipped } = new Transpiler().emit({ program, writeFile }); - const diagnostics = ts.sortAndDeduplicateDiagnostics([...preEmitDiagnostics, ...transpileDiagnostics]); + const diagnostics = ts.sortAndDeduplicateDiagnostics(transpileDiagnostics); - return { diagnostics: [...diagnostics], emitSkipped }; + return { diagnostics, emitSkipped }; } export function transpileProject( @@ -96,10 +95,9 @@ export function transpileVirtualProject( options: CompilerOptions = {} ): TranspileVirtualProjectResult { const program = createVirtualProgram(files, options); - const preEmitDiagnostics = ts.getPreEmitDiagnostics(program); const collector = createEmitOutputCollector(); const { diagnostics: transpileDiagnostics } = new Transpiler().emit({ program, writeFile: collector.writeFile }); - const diagnostics = ts.sortAndDeduplicateDiagnostics([...preEmitDiagnostics, ...transpileDiagnostics]); + const diagnostics = ts.sortAndDeduplicateDiagnostics(transpileDiagnostics); return { diagnostics: [...diagnostics], transpiledFiles: collector.files }; } diff --git a/src/transpilation/transpile.ts b/src/transpilation/transpile.ts index 6adfa5fc4..222345bdb 100644 --- a/src/transpilation/transpile.ts +++ b/src/transpilation/transpile.ts @@ -8,6 +8,7 @@ import { Plugin } from "./plugins"; import { getTransformers } from "./transformers"; import { EmitHost, ProcessedFile } from "./utils"; import * as performance from "../measure-performance"; +import { parseConfigFileWithSystem } from "../cli/tsconfig"; export interface TranspileOptions { program: ts.Program; @@ -30,13 +31,38 @@ export function getProgramTranspileResult( const options = program.getCompilerOptions() as CompilerOptions; - if (options.tstlVerbose) { - console.log("Parsing project settings"); - } + if (options.tstlVerbose) console.log("Parsing project settings"); const diagnostics = validateOptions(options); + let transpiledFiles: ProcessedFile[] = []; + if (options.build) { + for (const projectReferences of options.projectReferences ?? []) + { + if (options.tstlVerbose) console.log(`Build mode: Checking reference ${projectReferences.path}`); + + const tsConfigPath = path.join(projectReferences.path, "tsconfig.json"); + // Parse reference path but stay in build mode + const parseResult = parseConfigFileWithSystem(tsConfigPath, { build: true }); + diagnostics.push(...parseResult.errors); + + if (parseResult.errors.length === 0) { + const referenceProgram = ts.createProgram(parseResult.fileNames, parseResult.options); + const referencePreEmitDiagnostics = ts.getPreEmitDiagnostics(referenceProgram); + const { diagnostics: referenceDiagnostics, transpiledFiles: referenceFiles } = getProgramTranspileResult(emitHost, writeFileResult, { program: referenceProgram }); + diagnostics.push(...referencePreEmitDiagnostics, ...referenceDiagnostics); + + if (projectReferences.prepend) + { + transpiledFiles.push(...referenceFiles); + } + } + } + } + + // diagnostics.push(...ts.getPreEmitDiagnostics(program)); + if (options.noEmitOnError) { const preEmitDiagnostics = [ ...diagnostics, diff --git a/src/typescript-internal.d.ts b/src/typescript-internal.d.ts index 8d85b9374..5087d39f5 100644 --- a/src/typescript-internal.d.ts +++ b/src/typescript-internal.d.ts @@ -17,8 +17,10 @@ declare module "typescript" { } interface CompilerOptions { + build?: boolean; configFile?: TsConfigSourceFile; configFilePath?: string; + projectReferences?: ProjectReference[]; } interface TypeChecker { diff --git a/test/transpile/project-references.spec.ts b/test/transpile/project-references.spec.ts new file mode 100644 index 000000000..89cff18b2 --- /dev/null +++ b/test/transpile/project-references.spec.ts @@ -0,0 +1,12 @@ +import * as path from "path"; +import * as tstl from "../../src"; + +test("should transpile all projects with --build", () => { + const solutionDir = path.join(__dirname, "project-references", "project-references"); + const projectDir= path.join(solutionDir, "mainproject"); + + const { diagnostics } = tstl.transpileProject(path.join(projectDir, "tsconfig.json"), {build: true}); + + expect(diagnostics).toHaveLength(0); + // expect(transpiledFiles.some(f => f.outPath === path.join(solutionDir, "dist", "main.lua"))).toBe(true); +}); diff --git a/test/transpile/project-references/project-references/.gitignore b/test/transpile/project-references/project-references/.gitignore new file mode 100644 index 000000000..53c37a166 --- /dev/null +++ b/test/transpile/project-references/project-references/.gitignore @@ -0,0 +1 @@ +dist \ No newline at end of file diff --git a/test/transpile/project-references/project-references/dependency/src/index.ts b/test/transpile/project-references/project-references/dependency/src/index.ts new file mode 100644 index 000000000..997e646a9 --- /dev/null +++ b/test/transpile/project-references/project-references/dependency/src/index.ts @@ -0,0 +1,3 @@ +export function getNumber() { + return 200; +} \ No newline at end of file diff --git a/test/transpile/project-references/project-references/dependency/tsconfig.json b/test/transpile/project-references/project-references/dependency/tsconfig.json new file mode 100644 index 000000000..a3afaa865 --- /dev/null +++ b/test/transpile/project-references/project-references/dependency/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "outDir": "dist" + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/test/transpile/project-references/project-references/mainproject/src/main.ts b/test/transpile/project-references/project-references/mainproject/src/main.ts new file mode 100644 index 000000000..9854ad100 --- /dev/null +++ b/test/transpile/project-references/project-references/mainproject/src/main.ts @@ -0,0 +1,3 @@ +import { getNumber } from "../../dependency/src"; + +export const result = getNumber(); diff --git a/test/transpile/project-references/project-references/mainproject/tsconfig.json b/test/transpile/project-references/project-references/mainproject/tsconfig.json new file mode 100644 index 000000000..5a53351ce --- /dev/null +++ b/test/transpile/project-references/project-references/mainproject/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "rootDir": "src", + "outDir": "../dist", + "strict": true + }, + "references": [ + { + "path": "../dependency" + } + ], + "tstl": { + "luaTarget": "JIT", + "sourceMapTraceback": true, + "luaBundle": "bundle.lua", + "luaBundleEntry": "main.ts" + }, + "include": ["src/**/*.ts"] +} diff --git a/test/util.ts b/test/util.ts index ffc6bac68..ca232d2df 100644 --- a/test/util.ts +++ b/test/util.ts @@ -583,7 +583,9 @@ class ExpressionTestBuilder extends AccessorTestBuilder { class ProjectTestBuilder extends ModuleTestBuilder { constructor(private tsConfig: string) { super(""); - this.setOptions({ configFilePath: this.tsConfig, ...tstl.parseConfigFileWithSystem(this.tsConfig) }); + const options = { configFilePath: this.tsConfig }; + Object.assign(options, tstl.parseConfigFileWithSystem(this.tsConfig)); + this.setOptions(options); } @memoize