diff --git a/packages/plugin-typescript/src/lib/runner/runner.ts b/packages/plugin-typescript/src/lib/runner/runner.ts index 8a4a7f141..2e0bb244f 100644 --- a/packages/plugin-typescript/src/lib/runner/runner.ts +++ b/packages/plugin-typescript/src/lib/runner/runner.ts @@ -45,9 +45,9 @@ export function createRunnerFunction(options: RunnerOptions): RunnerFunction { Pick >, ); - return options.expectedAudits.map(audit => { - const { details } = result[audit.slug as CompilerOptionName]; + const { details } = result[audit.slug as CompilerOptionName] || {}; + const issues = details?.issues ?? []; return { ...audit, diff --git a/packages/plugin-typescript/src/lib/runner/ts-runner.ts b/packages/plugin-typescript/src/lib/runner/ts-runner.ts index c8d32a39c..118b0c03b 100644 --- a/packages/plugin-typescript/src/lib/runner/ts-runner.ts +++ b/packages/plugin-typescript/src/lib/runner/ts-runner.ts @@ -17,8 +17,8 @@ export async function getTypeScriptDiagnostics( ): Promise { try { const { fileNames, options } = await loadTargetConfig(tsConfigPath); - const program = createProgram(fileNames, options); + const program = createProgram(fileNames, options); const diagnostics = getPreEmitDiagnostics(program); validateDiagnostics(diagnostics); diff --git a/packages/plugin-typescript/src/lib/runner/utils.ts b/packages/plugin-typescript/src/lib/runner/utils.ts index 781b196f1..abc728966 100644 --- a/packages/plugin-typescript/src/lib/runner/utils.ts +++ b/packages/plugin-typescript/src/lib/runner/utils.ts @@ -1,6 +1,5 @@ import { access } from 'node:fs/promises'; -// eslint-disable-next-line unicorn/import-style -import { dirname } from 'node:path'; +import { dirname, join } from 'node:path'; import { type CompilerOptions, type Diagnostic, @@ -11,6 +10,7 @@ import { parseJsonConfigFileContent, sys, } from 'typescript'; +// eslint-disable-next-line unicorn/import-style import type { Issue } from '@code-pushup/models'; import { executeProcess, @@ -90,31 +90,34 @@ export function getIssueFromDiagnostic(diag: Diagnostic) { } const _TS_CONFIG_MAP = new Map(); + export async function loadTargetConfig(tsConfigPath: string) { - if (_TS_CONFIG_MAP.get(tsConfigPath) === undefined) { - const { config } = parseConfigFileTextToJson( - tsConfigPath, - await readTextFile(tsConfigPath), - ); + if (_TS_CONFIG_MAP.has(tsConfigPath)) { + return _TS_CONFIG_MAP.get(tsConfigPath) as ParsedCommandLine; + } - const parsedConfig = parseJsonConfigFileContent( - config, - sys, - dirname(tsConfigPath), - ); + const { config } = parseConfigFileTextToJson( + tsConfigPath, + await readTextFile(tsConfigPath), + ); - if (parsedConfig.fileNames.length === 0) { - throw new Error( - 'No files matched by the TypeScript configuration. Check your "include", "exclude" or "files" settings.', - ); - } + const parsedConfig = parseJsonConfigFileContent( + config, + sys, + dirname(tsConfigPath), + ); - _TS_CONFIG_MAP.set(tsConfigPath, parsedConfig); + if (parsedConfig.fileNames.length === 0) { + throw new Error( + 'No files matched by the TypeScript configuration. Check your "include", "exclude" or "files" settings.', + ); } + + _TS_CONFIG_MAP.set(tsConfigPath, parsedConfig); return _TS_CONFIG_MAP.get(tsConfigPath) as ParsedCommandLine; } -export async function getCurrentTsVersion(): Promise { +async function _getCurrentTsVersion(): Promise { const { stdout } = await executeProcess({ command: 'npx', args: ['-y', 'tsc', '--version'], @@ -122,10 +125,15 @@ export async function getCurrentTsVersion(): Promise { return stdout.split(' ').slice(-1).join('').trim() as SemVerString; } -export async function loadTsConfigDefaultsByVersion(version: SemVerString) { +export async function loadTsConfigDefaultsByVersion() { + const version = await _getCurrentTsVersion(); const __dirname = new URL('.', import.meta.url).pathname; - const configPath = `${__dirname}default-ts-configs/${version}.ts`; - + const configPath = join( + __dirname, + '..', + 'default-ts-configs', + `${version}.ts`, + ); try { await access(configPath); } catch { diff --git a/packages/plugin-typescript/src/lib/utils.ts b/packages/plugin-typescript/src/lib/utils.ts index 0c91a78f4..74e93863c 100644 --- a/packages/plugin-typescript/src/lib/utils.ts +++ b/packages/plugin-typescript/src/lib/utils.ts @@ -9,7 +9,6 @@ import { } from './constants.js'; import { TS_ERROR_CODES } from './runner/ts-error-codes.js'; import { - getCurrentTsVersion, loadTargetConfig, loadTsConfigDefaultsByVersion, } from './runner/utils.js'; @@ -69,7 +68,7 @@ export function getGroups( refs: group.refs.filter( filterAuditsByCompilerOptions( compilerOptions, - (options ?? {})?.onlyAudits, + (options ?? {}).onlyAudits, ), ), })).filter(group => group.refs.length > 0); @@ -141,7 +140,7 @@ export async function normalizeCompilerOptions( ) { const { tsConfigPath = DEFAULT_TS_CONFIG } = options ?? {}; const { compilerOptions: defaultCompilerOptions } = - await loadTsConfigDefaultsByVersion(await getCurrentTsVersion()); + await loadTsConfigDefaultsByVersion(); const config = await loadTargetConfig(tsConfigPath); return handleCompilerOptionStrict({ ...defaultCompilerOptions, @@ -153,7 +152,6 @@ export function validateAudits(filteredAudits: Audit[]) { const skippedAudits = AUDITS.filter( audit => !filteredAudits.some(filtered => filtered.slug === audit.slug), ).map(audit => kebabCaseToCamelCase(audit.slug)); - if (skippedAudits.length > 0) { console.warn( `Some audits were skipped because the configuration of the compiler options [${skippedAudits.join(', ')}]`, diff --git a/packages/plugin-typescript/src/lib/utils.unit.test.ts b/packages/plugin-typescript/src/lib/utils.unit.test.ts index 98aabab9f..264fd2347 100644 --- a/packages/plugin-typescript/src/lib/utils.unit.test.ts +++ b/packages/plugin-typescript/src/lib/utils.unit.test.ts @@ -1,7 +1,12 @@ import type { CompilerOptions } from 'typescript'; -import { describe, expect, it } from 'vitest'; -import type { Audit, Group } from '@code-pushup/models'; -import { filterAuditsBySlug, handleCompilerOptionStrict } from './utils.js'; +import { describe, expect, it, vi } from 'vitest'; +import type { Audit } from '@code-pushup/models'; +import { AUDITS } from './constants.js'; +import { + filterAuditsBySlug, + handleCompilerOptionStrict, + validateAudits, +} from './utils.js'; describe('filterAuditsBySlug', () => { const mockAudits: Audit[] = [ @@ -121,3 +126,36 @@ describe('handleCompilerOptionStrict', () => { expect(result.noImplicitAny).toBe(true); }); }); + +describe('validateAudits', () => { + beforeEach(() => { + vi.mock('console', () => ({ + warn: vi.fn(), + })); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('should not warn when all audits are included', () => { + const filteredAudits = AUDITS.map(audit => ({ ...audit })); + + validateAudits(filteredAudits); + + expect(console.warn).not.toHaveBeenCalled(); + }); + + it('should warn about skipped audits', () => { + const filteredAudits = AUDITS.slice(1); // Removes an audit + validateAudits(filteredAudits); + + expect(console.warn).toHaveBeenCalled(); + }); + + it('should warn of all audits when filteredAudits are empty', () => { + validateAudits([]); + + expect(console.warn).toHaveBeenCalled(); + }); +});