diff --git a/integration/src/tsc.test.mts b/integration/src/tsc.test.mts index 94a1428..d235ee1 100644 --- a/integration/src/tsc.test.mts +++ b/integration/src/tsc.test.mts @@ -214,7 +214,10 @@ describe("tsc", (suiteCtx) => { test("tsconfig", async (testCtx) => { const dir = getTestDir(suiteCtx, testCtx); const script = "script.mts"; - writeFileSync(join(dir, script), "console.log('Hello World!');\n"); + writeFileSync( + join(dir, script), + "function greet(msg): void { console.log(msg); }\ngreet('Hello World!');\n", + ); const tsConfig = join(dir, "tsconfig.json"); writeFileSync( @@ -223,10 +226,8 @@ describe("tsc", (suiteCtx) => { { files: [script], compilerOptions: { + noImplicitAny: false, outDir: "myOutput", - declaration: true, - strict: true, - alwaysStrict: true, skipLibCheck: true, }, }, @@ -239,7 +240,10 @@ describe("tsc", (suiteCtx) => { const tsc = makeTSCRule(ninja); const typecheck = makeTypeCheckRule(ninja); - const out = await tsc({ tsConfig: "tsconfig.json" }); + const out = await tsc({ + tsConfig: "tsconfig.json", + compilerOptions: { declaration: true }, + }); assert.deepEqual(out, ["myOutput/script.mjs", "myOutput/script.d.mts"]); const typechecked = await typecheck({ @@ -250,6 +254,19 @@ describe("tsc", (suiteCtx) => { { file: "script.mts", [validations]: "typechecked.stamp" }, ]); + const failed = await typecheck({ + tsConfig: "tsconfig.json", + out: "failed.stamp", + compilerOptions: { + noImplicitAny: true, + }, + }); + assert.deepEqual(failed, [ + { file: "script.mts", [validations]: "failed.stamp" }, + ]); + + const err = ninja.phony({ out: "err", in: failed[0][validations] }); + ninja.default(...out, typechecked[0][validations]); writeFileSync(join(dir, "build.ninja"), ninja.output); { @@ -269,6 +286,14 @@ describe("tsc", (suiteCtx) => { } assert.strictEqual(callNinja(dir).trimEnd(), "ninja: no work to do."); + + { + const { stdout } = callNinjaWithFailure(dir, err); + assert.match( + stdout, + /error TS7006: Parameter 'msg' implicitly has an 'any' type/, + ); + } }); // TODO: Check the `incremental` flag works correctly diff --git a/packages/tsc/package.json b/packages/tsc/package.json index 08b62ad..f630e20 100644 --- a/packages/tsc/package.json +++ b/packages/tsc/package.json @@ -1,6 +1,6 @@ { "name": "@ninjutsu-build/tsc", - "version": "0.12.4", + "version": "0.12.5", "description": "Create a ninjutsu-build rule for running the TypeScript compiler (tsc)", "author": "Elliot Goodrich", "scripts": { diff --git a/packages/tsc/src/tsc.ts b/packages/tsc/src/tsc.ts index f30dc5d..7d218fa 100644 --- a/packages/tsc/src/tsc.ts +++ b/packages/tsc/src/tsc.ts @@ -157,6 +157,7 @@ export type TypeCheckRuleFn = { (a: { tsConfig: string; + compilerOptions?: CompilerOptions; out: O2; [implicitDeps]?: string | readonly string[]; [orderOnlyDeps]?: Input | readonly Input[]; @@ -167,12 +168,12 @@ export type TypeCheckRuleFn = { a: ( | { in: readonly Input[]; - compilerOptions?: CompilerOptions; } | { tsConfig: Input; } ) & { + compilerOptions?: CompilerOptions; out: O3; [implicitDeps]?: string | readonly string[]; [orderOnlyDeps]?: Input | readonly Input[]; @@ -241,12 +242,12 @@ export function makeTypeCheckRule( a: ( | { in: readonly Input[]; - compilerOptions?: CompilerOptions; } | { tsConfig: Input; } ) & { + compilerOptions?: CompilerOptions; out: O; [implicitDeps]?: string | readonly string[]; [orderOnlyDeps]?: Input | readonly Input[]; @@ -270,7 +271,7 @@ export function makeTypeCheckRule( const typechecked = typecheck({ in: [a.tsConfig], out: a.out, - args: "-p", + args: compilerOptionsToString(a.compilerOptions ?? {}) + " -p", }); return getFileNames(ninja, a.tsConfig).then(({ files }) => files.map((file) => ({ @@ -293,6 +294,7 @@ export type TSCRuleFn = { }): string[]; (a: { tsConfig: Input; + compilerOptions?: CompilerOptions; [implicitDeps]?: string | readonly string[]; [orderOnlyDeps]?: Input | readonly Input[]; [implicitOut]?: string | readonly string[]; @@ -302,12 +304,12 @@ export type TSCRuleFn = { a: ( | { in: readonly Input[]; - compilerOptions?: CompilerOptions; } | { tsConfig: Input; } ) & { + compilerOptions?: CompilerOptions; [implicitDeps]?: string | readonly string[]; [orderOnlyDeps]?: Input | readonly Input[]; [implicitOut]?: string | readonly string[]; @@ -399,12 +401,12 @@ export function makeTSCRule(ninja: NinjaBuilder, name = "tsc"): TSCRuleFn { a: ( | { in: readonly Input[]; - compilerOptions?: CompilerOptions; } | { tsConfig: Input; } ) & { + compilerOptions?: CompilerOptions; [implicitDeps]?: string | readonly string[]; [orderOnlyDeps]?: Input | readonly Input[]; [implicitOut]?: string | readonly string[]; @@ -441,14 +443,21 @@ export function makeTSCRule(ninja: NinjaBuilder, name = "tsc"): TSCRuleFn { } else { const { tsConfig, + compilerOptions: overrideOptions = {}, [implicitOut]: _implicitOut = [], [validations]: _validations, ...rest } = a; return getFileNames(ninja, tsConfig).then( ({ files, compilerOptions }) => { + const finalCompilerOptions = { + ...compilerOptions, + ...overrideOptions, + }; const commandLine = ts.parseCommandLine( - files.concat(compilerOptionsToArrayBestEffort(compilerOptions)), + files.concat( + compilerOptionsToArrayBestEffort(finalCompilerOptions), + ), ); // We need to set this to something, else we get a debug exception @@ -462,7 +471,7 @@ export function makeTSCRule(ninja: NinjaBuilder, name = "tsc"): TSCRuleFn { ...rest, in: [tsConfig], out: out[0], - args: "-p", + args: compilerOptionsToString(finalCompilerOptions) + " -p", [implicitOut]: out.slice(1).concat(_implicitOut), [validations]: _validations === undefined ? undefined : () => _validations(out),