Skip to content

Commit 8bd94f6

Browse files
committed
wip
1 parent 7ecb376 commit 8bd94f6

File tree

11 files changed

+172
-103
lines changed

11 files changed

+172
-103
lines changed

code-pushup.preset.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ export const eslintCoreConfigNx = async (
136136
};
137137

138138
export const typescriptPluginConfigNx = async (
139-
options: TypescriptPluginOptions,
139+
options?: TypescriptPluginOptions,
140140
): Promise<CoreConfig> => {
141141
const opt: TypescriptPluginOptions = {
142142
...options,

packages/plugin-typescript/README.md

Lines changed: 74 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -39,53 +39,60 @@ TypeScript compiler diagnostics are mapped to Code PushUp audits in the followin
3939

4040
3. Add this plugin to the `plugins` array in your Code PushUp CLI config file (e.g. `code-pushup.config.ts`).
4141

42-
Pass in the URL you want to measure, along with optional [flags](#flags) and [config](#config) data.
42+
Define the ts config file used to compile your codebase. Based on those compiler options the plugin will generate audits.
4343

44-
```ts
45-
import typescriptPlugin from '@code-pushup/typescript-plugin';
46-
47-
export default {
48-
// ...
49-
plugins: [
50-
// ...
51-
await typescriptPlugin({
52-
tsConfigPath: './tsconfig.json',
53-
}),
54-
],
55-
};
56-
```
44+
```ts
45+
import typescriptPlugin from '@code-pushup/typescript-plugin';
46+
47+
export default {
48+
// ...
49+
plugins: [
50+
// ...
51+
typescriptPlugin({
52+
tsConfigPath: './tsconfig.json',
53+
}),
54+
],
55+
};
56+
```
5757

5858
4. Run the CLI with `npx code-pushup collect` and view or upload the report (refer to [CLI docs](../cli/README.md)).
5959

60-
## About documentation coverage
60+
## About TypeScript checks
6161

62-
The TypeScript plugin analyzes your codebase using the TypeScript compiler to identify potential issues and enforce best practices. It helps ensure type safety and maintainability of your TypeScript code.
62+
The TypeScript plugin analyzes your codebase using the TypeScript compiler to identify potential issues and enforce best practices.
63+
It helps ensure type safety and maintainability of your TypeScript code.
6364

64-
The plugin provides multiple audits grouped into different categories like:
65+
The plugin provides multiple audits grouped into different sets:
6566

66-
- Language and Environment - Checks configuration for TypeScript features like decorators, JSX, target version
67-
- Type Checking - Validates strict null checks, implicit any/this, function types
68-
- Module Resolution - Verifies module imports/exports and resolution settings
69-
- Build/Emit Options - Checks output generation and optimization settings
70-
- Control Flow - Analyzes code flow, unreachable code, switch statements
67+
- Language and Environment - Configuration options for TypeScript language features and runtime environment, including decorators, JSX support, target ECMAScript version, and class field behaviors
68+
- Interop Constraints - Settings that control how TypeScript interoperates with other JavaScript code, including module imports/exports and case sensitivity rules
69+
- Watch Options - Configuration for TypeScript watch mode behavior, including file watching strategies and dependency tracking
70+
- Project References - Options for managing TypeScript project references, composite projects, and build optimization settings
71+
- Module Resolution - Settings that control how TypeScript finds and resolves module imports, including Node.js resolution, package.json exports/imports, and module syntax handling
72+
- Type Checking Behavior - Configuration for TypeScript type checking strictness and error reporting, including property access rules and method override checking
73+
- Control Flow Options - Settings that affect code flow analysis, including handling of unreachable code, unused labels, switch statements, and async/generator functions
74+
- Strict Checks - Strict type checking options that enable additional compile-time verifications, including null checks, implicit any/this, and function type checking
75+
- Build/Emit Options - Configuration options that control TypeScript output generation, including whether to emit files, how to handle comments and declarations, and settings for output optimization and compatibility helpers
7176

7277
Each audit:
7378

7479
- Checks for specific TypeScript compiler errors and warnings
7580
- Provides a score based on the number of issues found
7681
- Includes detailed error messages and locations
7782

78-
The audits are organized into logical groups to give you a comprehensive view of your TypeScript configuration and code quality. You can:
79-
80-
- Use all groups for complete TypeScript analysis
81-
- Focus on specific groups or individual audits based on your needs
83+
Each set is also available as group in the plugin. See more under [Audits and Groups]()
8284

8385
## Plugin architecture
8486

8587
### Plugin configuration specification
8688

8789
The plugin accepts the following parameters:
8890

91+
| Option | Type | Default | Description |
92+
| ------------ | -------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
93+
| tsConfigPath | string | `tsconfig.json` | A string that defines the path to your `tsconfig.json` file |
94+
| onlyAudits | string[] | undefined | An array of audit slugs to specify which documentation types you want to measure. Only the specified audits will be included in the results |
95+
8996
#### TsConfigPath
9097

9198
Required parameter. The `tsConfigPath` option accepts a string that defines the path to your `tsconfig.json` file.
@@ -103,10 +110,8 @@ Optional parameter. The `onlyAudits` option allows you to specify which document
103110
```js
104111
typescriptPlugin({
105112
tsConfigPath: './tsconfig.json',
106-
onlyAudits: [
107-
'no-implicit-any'
108-
] // Only measure documentation for classes and functions
109-
}),
113+
onlyAudits: ['no-implicit-any'], // Only measure documentation for classes and functions
114+
});
110115
```
111116

112117
### Audits and group
@@ -115,55 +120,55 @@ This plugin provides a list of groups to cover different TypeScript configuratio
115120

116121
```ts
117122
// ...
118-
categories: [
119-
{
120-
slug: 'typescript',
121-
title: 'TypeScript',
122-
refs: [
123-
{
124-
slug: 'language-and-environment',
125-
weight: 1,
126-
type: 'group',
127-
plugin: 'typescript'
128-
},
129-
// ...
130-
],
131-
},
132-
// ...
133-
],
123+
categories: [
124+
{
125+
slug: 'typescript',
126+
title: 'TypeScript',
127+
refs: [
128+
{
129+
slug: 'language-and-environment',
130+
weight: 1,
131+
type: 'group',
132+
plugin: 'typescript'
133+
},
134+
// ...
135+
],
136+
},
137+
// ...
138+
],
134139
```
135140

136141
Each TypeScript configuration option still has its own audit. So when you want to include a subset of configuration options or assign different weights to them, you can do so in the following way:
137142

138143
```ts
139144
// ...
140-
categories: [
141-
{
142-
slug: 'typescript',
143-
title: 'TypeScript',
144-
refs: [
145-
{
146-
type: 'audit',
147-
plugin: 'typescript',
148-
slug: 'no-implicit-any',
149-
weight: 2,
150-
},
151-
{
152-
type: 'audit',
153-
plugin: 'typescript',
154-
slug: 'no-explicit-any',
155-
weight: 1,
156-
},
157-
// ...
158-
],
159-
},
160-
// ...
161-
],
145+
categories: [
146+
{
147+
slug: 'typescript',
148+
title: 'TypeScript',
149+
refs: [
150+
{
151+
type: 'audit',
152+
plugin: 'typescript',
153+
slug: 'no-implicit-any',
154+
weight: 2,
155+
},
156+
{
157+
type: 'audit',
158+
plugin: 'typescript',
159+
slug: 'no-explicit-any',
160+
weight: 1,
161+
},
162+
// ...
163+
],
164+
},
165+
// ...
166+
],
162167
```
163168

164169
### Audit output
165170

166-
The plugin outputs a single audit that measures the overall documentation coverage percentage of your codebase.
171+
The plugin outputs multiple audits that track all issues of your codebase.
167172

168173
For instance, this is an example of the plugin output:
169174

packages/plugin-typescript/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"dependencies": {
2626
"@code-pushup/models": "0.57.0",
2727
"typescript": "5.5.4",
28-
"zod": "^3.23.8"
28+
"zod": "^3.23.8",
29+
"@code-pushup/utils": "0.57.0"
2930
}
3031
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
} from './runner/ts-error-codes.js';
77

88
export const TYPESCRIPT_PLUGIN_SLUG = 'typescript';
9+
export const DEFAULT_TS_CONFIG = 'tsconfig.json';
910

1011
export const AUDITS = Object.values(TS_ERROR_CODES)
1112
.flatMap(i => Object.entries(i))
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`getTsConfiguration > should accept valid TS config file 1`] = `
4+
{
5+
"fileNames": [
6+
"ts-2307-module-not-fount.ts",
7+
"ts-2322-strict-null-checks.ts",
8+
"ts-7006-no-implicit-any.ts",
9+
"ts-7027-strict-property-initialization.ts",
10+
],
11+
"options": {
12+
"alwaysStrict": true,
13+
"configFilePath": undefined,
14+
"module": 1,
15+
"noImplicitAny": true,
16+
"rootDir": "src",
17+
"strict": true,
18+
"strictBindCallApply": true,
19+
"strictFunctionTypes": true,
20+
"strictNullChecks": true,
21+
"strictPropertyInitialization": true,
22+
"target": 2,
23+
},
24+
}
25+
`;

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
// eslint-disable-next-line unicorn/import-style
2+
import { basename } from 'node:path';
13
import { describe, expect } from 'vitest';
2-
import { getDiagnostics } from './typescript-runner.js';
4+
import { getDiagnostics, getTsConfiguration } from './typescript-runner.js';
35

46
describe('getDiagnostics', () => {
57
it('should accept valid options', async () => {
@@ -39,3 +41,22 @@ describe('getDiagnostics', () => {
3941
);
4042
});
4143
});
44+
45+
describe('getTsConfiguration', () => {
46+
it('should accept valid TS config file', async () => {
47+
const config = await getTsConfiguration({
48+
tsConfigPath:
49+
'./packages/plugin-typescript/mocks/fixtures/basic-setup/tsconfig.json',
50+
});
51+
52+
expect({
53+
...config,
54+
// omitting path details for better snapshots
55+
fileNames: config.fileNames.map(fileName => basename(fileName)),
56+
options: {
57+
...config.options,
58+
rootDir: basename(config.options?.rootDir ?? ''),
59+
},
60+
}).toMatchSnapshot();
61+
});
62+
});

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
parseJsonConfigFileContent,
1010
sys,
1111
} from 'typescript';
12+
import { DEFAULT_TS_CONFIG } from '../constants.js';
1213

1314
export type DiagnosticsOptions = { tsConfigPath: string };
1415

@@ -23,7 +24,7 @@ export async function getDiagnostics(
2324
}
2425

2526
export async function getTsConfiguration(options: DiagnosticsOptions) {
26-
const { tsConfigPath = 'tsconfig.json' } = options;
27+
const { tsConfigPath = DEFAULT_TS_CONFIG } = options;
2728
const configPath = resolve(process.cwd(), tsConfigPath);
2829
const basePath = dirname(configPath);
2930

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ export function getIssueFromDiagnostic(diag: Diagnostic) {
6767
}
6868

6969
const startLine =
70-
diag.start !== undefined
71-
? diag.file.getLineAndCharacterOfPosition(diag.start).line + 1
72-
: undefined;
70+
diag.start === undefined
71+
? undefined
72+
: diag.file.getLineAndCharacterOfPosition(diag.start).line + 1;
7373

7474
return {
7575
severity: getSeverity(diag.category),

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

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { DiagnosticCategory } from 'typescript';
2-
import { describe, expect } from 'vitest';
1+
import { type Diagnostic, DiagnosticCategory } from 'typescript';
2+
import { beforeEach, describe, expect } from 'vitest';
33
import {
44
getIssueFromDiagnostic,
55
getSeverity,
@@ -35,16 +35,20 @@ describe('getSeverity', () => {
3535
});
3636

3737
describe('getIssueFromDiagnostic', () => {
38-
const diagnosticMock = {
39-
code: 222,
40-
category: DiagnosticCategory.Error,
41-
messageText: "Type 'number' is not assignable to type 'string'.",
42-
file: {
43-
fileName: 'file.ts',
44-
getLineAndCharacterOfPosition: () => ({ line: 99 }),
45-
},
46-
start: 4,
47-
} as any;
38+
let diagnosticMock: Diagnostic;
39+
40+
beforeEach(() => {
41+
diagnosticMock = {
42+
code: 222,
43+
category: DiagnosticCategory.Error,
44+
messageText: "Type 'number' is not assignable to type 'string'.",
45+
file: {
46+
fileName: 'file.ts',
47+
getLineAndCharacterOfPosition: () => ({ line: 99 }),
48+
},
49+
start: 4,
50+
} as any;
51+
});
4852

4953
it('should return valid issue', () => {
5054
expect(getIssueFromDiagnostic(diagnosticMock)).toStrictEqual({
@@ -92,15 +96,16 @@ describe('getIssueFromDiagnostic', () => {
9296
});
9397

9498
it('should throw error if file is undefined', () => {
95-
diagnosticMock.file = undefined;
96-
expect(() => getIssueFromDiagnostic(diagnosticMock)).toThrow(
97-
"Type 'number' is not assignable to type 'string'.",
98-
);
99+
expect(() =>
100+
getIssueFromDiagnostic({ ...diagnosticMock, file: undefined }),
101+
).toThrow("Type 'number' is not assignable to type 'string'.");
99102
});
100103

101104
it('position.startLine should be 1 if start is undefined', () => {
102-
diagnosticMock.start = undefined;
103-
const result = getIssueFromDiagnostic(diagnosticMock);
104-
expect(result.source.position?.startLine).toBe(1);
105+
const result = getIssueFromDiagnostic({
106+
...diagnosticMock,
107+
start: undefined,
108+
});
109+
expect(result.source.position).toBeUndefined();
105110
});
106111
});

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
import { z } from 'zod';
2-
import { AUDITS } from './constants.js';
2+
import { AUDITS, DEFAULT_TS_CONFIG } from './constants.js';
33
import type { AuditSlug } from './types.js';
44

55
const auditSlugs = AUDITS.map(({ slug }) => slug) as [string, ...string[]];
66
export const typescriptPluginConfigSchema = z.object({
7-
tsConfigPath: z.string().describe('Path to the TsConfig'),
7+
tsConfigPath: z
8+
.string({
9+
description: 'Path to the TsConfig',
10+
})
11+
.default(DEFAULT_TS_CONFIG),
812
onlyAudits: z
9-
.array(z.enum(auditSlugs))
10-
.optional()
11-
.describe('Array with specific TsCodes to measure'),
13+
.array(z.enum(auditSlugs), {
14+
description: 'Array with specific TsCodes to measure',
15+
})
16+
.optional(),
1217
});
1318

1419
export type TypescriptPluginOptions = z.infer<

0 commit comments

Comments
 (0)