Skip to content

Commit eda1681

Browse files
authored
chore(plugin-typescript): wip (#906)
1 parent d7d797c commit eda1681

File tree

5 files changed

+76
-32
lines changed

5 files changed

+76
-32
lines changed

packages/plugin-typescript/src/lib/runner/runner.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ export function createRunnerFunction(options: RunnerOptions): RunnerFunction {
4545
Pick<AuditReport, 'slug' | 'details'>
4646
>,
4747
);
48-
4948
return options.expectedAudits.map(audit => {
50-
const { details } = result[audit.slug as CompilerOptionName];
49+
const { details } = result[audit.slug as CompilerOptionName] || {};
50+
5151
const issues = details?.issues ?? [];
5252
return {
5353
...audit,

packages/plugin-typescript/src/lib/runner/ts-runner.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ export async function getTypeScriptDiagnostics(
1717
): Promise<readonly Diagnostic[]> {
1818
try {
1919
const { fileNames, options } = await loadTargetConfig(tsConfigPath);
20-
const program = createProgram(fileNames, options);
2120

21+
const program = createProgram(fileNames, options);
2222
const diagnostics = getPreEmitDiagnostics(program);
2323
validateDiagnostics(diagnostics);
2424

packages/plugin-typescript/src/lib/runner/utils.ts

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { access } from 'node:fs/promises';
2-
// eslint-disable-next-line unicorn/import-style
3-
import { dirname } from 'node:path';
2+
import { dirname, join } from 'node:path';
43
import {
54
type CompilerOptions,
65
type Diagnostic,
@@ -11,6 +10,7 @@ import {
1110
parseJsonConfigFileContent,
1211
sys,
1312
} from 'typescript';
13+
// eslint-disable-next-line unicorn/import-style
1414
import type { Issue } from '@code-pushup/models';
1515
import {
1616
executeProcess,
@@ -90,42 +90,50 @@ export function getIssueFromDiagnostic(diag: Diagnostic) {
9090
}
9191

9292
const _TS_CONFIG_MAP = new Map<string, ParsedCommandLine>();
93+
9394
export async function loadTargetConfig(tsConfigPath: string) {
94-
if (_TS_CONFIG_MAP.get(tsConfigPath) === undefined) {
95-
const { config } = parseConfigFileTextToJson(
96-
tsConfigPath,
97-
await readTextFile(tsConfigPath),
98-
);
95+
if (_TS_CONFIG_MAP.has(tsConfigPath)) {
96+
return _TS_CONFIG_MAP.get(tsConfigPath) as ParsedCommandLine;
97+
}
9998

100-
const parsedConfig = parseJsonConfigFileContent(
101-
config,
102-
sys,
103-
dirname(tsConfigPath),
104-
);
99+
const { config } = parseConfigFileTextToJson(
100+
tsConfigPath,
101+
await readTextFile(tsConfigPath),
102+
);
105103

106-
if (parsedConfig.fileNames.length === 0) {
107-
throw new Error(
108-
'No files matched by the TypeScript configuration. Check your "include", "exclude" or "files" settings.',
109-
);
110-
}
104+
const parsedConfig = parseJsonConfigFileContent(
105+
config,
106+
sys,
107+
dirname(tsConfigPath),
108+
);
111109

112-
_TS_CONFIG_MAP.set(tsConfigPath, parsedConfig);
110+
if (parsedConfig.fileNames.length === 0) {
111+
throw new Error(
112+
'No files matched by the TypeScript configuration. Check your "include", "exclude" or "files" settings.',
113+
);
113114
}
115+
116+
_TS_CONFIG_MAP.set(tsConfigPath, parsedConfig);
114117
return _TS_CONFIG_MAP.get(tsConfigPath) as ParsedCommandLine;
115118
}
116119

117-
export async function getCurrentTsVersion(): Promise<SemVerString> {
120+
async function _getCurrentTsVersion(): Promise<SemVerString> {
118121
const { stdout } = await executeProcess({
119122
command: 'npx',
120123
args: ['-y', 'tsc', '--version'],
121124
});
122125
return stdout.split(' ').slice(-1).join('').trim() as SemVerString;
123126
}
124127

125-
export async function loadTsConfigDefaultsByVersion(version: SemVerString) {
128+
export async function loadTsConfigDefaultsByVersion() {
129+
const version = await _getCurrentTsVersion();
126130
const __dirname = new URL('.', import.meta.url).pathname;
127-
const configPath = `${__dirname}default-ts-configs/${version}.ts`;
128-
131+
const configPath = join(
132+
__dirname,
133+
'..',
134+
'default-ts-configs',
135+
`${version}.ts`,
136+
);
129137
try {
130138
await access(configPath);
131139
} catch {

packages/plugin-typescript/src/lib/utils.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
} from './constants.js';
1010
import { TS_ERROR_CODES } from './runner/ts-error-codes.js';
1111
import {
12-
getCurrentTsVersion,
1312
loadTargetConfig,
1413
loadTsConfigDefaultsByVersion,
1514
} from './runner/utils.js';
@@ -69,7 +68,7 @@ export function getGroups(
6968
refs: group.refs.filter(
7069
filterAuditsByCompilerOptions(
7170
compilerOptions,
72-
(options ?? {})?.onlyAudits,
71+
(options ?? {}).onlyAudits,
7372
),
7473
),
7574
})).filter(group => group.refs.length > 0);
@@ -141,7 +140,7 @@ export async function normalizeCompilerOptions(
141140
) {
142141
const { tsConfigPath = DEFAULT_TS_CONFIG } = options ?? {};
143142
const { compilerOptions: defaultCompilerOptions } =
144-
await loadTsConfigDefaultsByVersion(await getCurrentTsVersion());
143+
await loadTsConfigDefaultsByVersion();
145144
const config = await loadTargetConfig(tsConfigPath);
146145
return handleCompilerOptionStrict({
147146
...defaultCompilerOptions,
@@ -153,7 +152,6 @@ export function validateAudits(filteredAudits: Audit[]) {
153152
const skippedAudits = AUDITS.filter(
154153
audit => !filteredAudits.some(filtered => filtered.slug === audit.slug),
155154
).map(audit => kebabCaseToCamelCase(audit.slug));
156-
157155
if (skippedAudits.length > 0) {
158156
console.warn(
159157
`Some audits were skipped because the configuration of the compiler options [${skippedAudits.join(', ')}]`,

packages/plugin-typescript/src/lib/utils.unit.test.ts

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import type { CompilerOptions } from 'typescript';
2-
import { describe, expect, it } from 'vitest';
3-
import type { Audit, Group } from '@code-pushup/models';
4-
import { filterAuditsBySlug, handleCompilerOptionStrict } from './utils.js';
2+
import { describe, expect, it, vi } from 'vitest';
3+
import type { Audit } from '@code-pushup/models';
4+
import { AUDITS } from './constants.js';
5+
import {
6+
filterAuditsBySlug,
7+
handleCompilerOptionStrict,
8+
validateAudits,
9+
} from './utils.js';
510

611
describe('filterAuditsBySlug', () => {
712
const mockAudits: Audit[] = [
@@ -121,3 +126,36 @@ describe('handleCompilerOptionStrict', () => {
121126
expect(result.noImplicitAny).toBe(true);
122127
});
123128
});
129+
130+
describe('validateAudits', () => {
131+
beforeEach(() => {
132+
vi.mock('console', () => ({
133+
warn: vi.fn(),
134+
}));
135+
});
136+
137+
afterEach(() => {
138+
vi.restoreAllMocks();
139+
});
140+
141+
it('should not warn when all audits are included', () => {
142+
const filteredAudits = AUDITS.map(audit => ({ ...audit }));
143+
144+
validateAudits(filteredAudits);
145+
146+
expect(console.warn).not.toHaveBeenCalled();
147+
});
148+
149+
it('should warn about skipped audits', () => {
150+
const filteredAudits = AUDITS.slice(1); // Removes an audit
151+
validateAudits(filteredAudits);
152+
153+
expect(console.warn).toHaveBeenCalled();
154+
});
155+
156+
it('should warn of all audits when filteredAudits are empty', () => {
157+
validateAudits([]);
158+
159+
expect(console.warn).toHaveBeenCalled();
160+
});
161+
});

0 commit comments

Comments
 (0)