Skip to content

Commit feefa0a

Browse files
committed
feat(plugin-doc-coverage): add support for variable statement to be documented, improve test
1 parent 4fb478e commit feefa0a

File tree

8 files changed

+158
-1314
lines changed

8 files changed

+158
-1314
lines changed

code-pushup.config.bundled_oq2x2csd2at.mjs

Lines changed: 0 additions & 1210 deletions
This file was deleted.

packages/plugin-doc-coverage/mocks/component-mock.ts

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,3 @@ export function DUMMY_FUNCTION() {
99
export function DUMMY_FUNCTION_2() {
1010
return 'Hello World 2';
1111
}
12-
13-
// class DummyClass {
14-
// /**
15-
// * Dummy property that returns 'Hello World 3'.
16-
// * @returns {string} - The string 'Hello World 3'.
17-
// */
18-
// dummyProperty = 'Hello World 3';
19-
20-
// /**
21-
// * Dummy method that returns 'Hello World 4'.
22-
// * @returns {string} - The string 'Hello World 4'.
23-
// */
24-
// dummyMethod() {
25-
// return 'Hello World 4';
26-
// }
27-
28-
// constructor() {
29-
// this.dummyProperty = 'Hello World 3';
30-
// }
31-
// }
32-
33-
// export default DummyClass;
34-
35-
// export const variableDummy = 'Hello World 5';
36-
37-
// export const variableDummy2 = 'Hello World 6';
38-
39-
// /** Dummy variable that returns 'Hello World 7'. */
40-
// export const variableDummy3 = 'Hello World 7';
41-
42-
// /** Dummy interface that returns 'Hello World 8'. */
43-
// export interface DummyInterface {
44-
// dummyProperty: string;
45-
// dummyMethod(): string;
46-
// }
47-
48-
// /** Dummy type that returns 'Hello World 9'. */
49-
// export type DummyType = string;

packages/plugin-doc-coverage/mocks/fixtures/angular/map-event.function.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
export const someVariable = 'Hello World 1';
2+
13
export function mapEventToCustomEvent(event: string) {
24
return event;
35
}

packages/plugin-doc-coverage/mocks/source-files.mock.ts

Lines changed: 20 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,70 +6,37 @@ import {
66
SourceFile,
77
SyntaxKind,
88
TypeAliasDeclaration,
9+
VariableStatement,
910
} from 'ts-morph';
10-
import type { CoverageType } from '../src/lib/models';
11+
import type { CoverageType } from '../src/lib/runner/models';
1112

1213
export function sourceFileMock(
1314
file: string,
1415
nodes: Partial<Record<CoverageType, Record<number, boolean>>>,
1516
): SourceFile {
17+
const createNodeGetter = <T>(
18+
coverageType: CoverageType,
19+
nodeData?: Record<number, boolean>,
20+
) => {
21+
if (!nodeData) return [];
22+
return Object.entries(nodeData).map(([line, isCommented]) =>
23+
nodeMock({ coverageType, line: Number(line), file, isCommented }),
24+
) as unknown as T[];
25+
};
26+
1627
return {
1728
getFilePath: () => file as any,
1829
getClasses: () =>
19-
nodes.classes
20-
? (Object.entries(nodes.classes).map(([line, isCommented]) =>
21-
nodeMock({
22-
coverageType: 'classes',
23-
line: Number(line),
24-
file,
25-
isCommented,
26-
}),
27-
) as unknown as ClassDeclaration[])
28-
: [],
30+
createNodeGetter<ClassDeclaration>('classes', nodes.classes),
2931
getFunctions: () =>
30-
nodes.functions
31-
? (Object.entries(nodes.functions).map(([line, isCommented]) =>
32-
nodeMock({
33-
coverageType: 'functions',
34-
line: Number(line),
35-
file,
36-
isCommented,
37-
}),
38-
) as unknown as FunctionDeclaration[])
39-
: [],
40-
getEnums: () =>
41-
nodes.enums
42-
? (Object.entries(nodes.enums).map(([line, isCommented]) =>
43-
nodeMock({
44-
coverageType: 'enums',
45-
line: Number(line),
46-
file,
47-
isCommented,
48-
}),
49-
) as unknown as EnumDeclaration[])
50-
: [],
32+
createNodeGetter<FunctionDeclaration>('functions', nodes.functions),
33+
getEnums: () => createNodeGetter<EnumDeclaration>('enums', nodes.enums),
5134
getTypeAliases: () =>
52-
nodes.types
53-
? (Object.entries(nodes.types).map(([line, isCommented]) =>
54-
nodeMock({
55-
coverageType: 'types',
56-
line: Number(line),
57-
file,
58-
isCommented,
59-
}),
60-
) as unknown as TypeAliasDeclaration[])
61-
: [],
35+
createNodeGetter<TypeAliasDeclaration>('types', nodes.types),
6236
getInterfaces: () =>
63-
nodes.interfaces
64-
? (Object.entries(nodes.interfaces).map(([line, isCommented]) =>
65-
nodeMock({
66-
coverageType: 'interfaces',
67-
line: Number(line),
68-
file,
69-
isCommented,
70-
}),
71-
) as unknown as InterfaceDeclaration[])
72-
: [],
37+
createNodeGetter<InterfaceDeclaration>('interfaces', nodes.interfaces),
38+
getVariableStatements: () =>
39+
createNodeGetter<VariableStatement>('variables', nodes.variables),
7340
} as SourceFile;
7441
}
7542

@@ -84,6 +51,7 @@ export function nodeMock(options: {
8451
getJsDocs: () => (options.isCommented ? ['Comment'] : []),
8552
getName: () => 'test',
8653
getStartLineNumber: () => options.line,
54+
getDeclarations: () => [],
8755
// Only for classes
8856
getMethods: () => [],
8957
getProperties: () => [],

packages/plugin-doc-coverage/src/lib/runner/__snapshots__/doc-processer.integration.test.ts.snap

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ exports[`processDocCoverage > should succesfully get the right number of ts file
2323
},
2424
{
2525
"file": "/home/alejandro/dev/code-pushup-cli/packages/plugin-doc-coverage/mocks/fixtures/angular/map-event.function.ts",
26-
"line": 1,
26+
"line": 3,
2727
"name": "mapEventToCustomEvent",
2828
"type": "functions",
2929
},
@@ -40,7 +40,7 @@ exports[`processDocCoverage > should succesfully get the right number of ts file
4040
"issues": [
4141
{
4242
"file": "/home/alejandro/dev/code-pushup-cli/packages/plugin-doc-coverage/mocks/fixtures/angular/app.component.ts",
43-
"line": 15,
43+
"line": 17,
4444
"name": "sendEvent",
4545
"type": "methods",
4646
},
@@ -52,7 +52,7 @@ exports[`processDocCoverage > should succesfully get the right number of ts file
5252
"issues": [
5353
{
5454
"file": "/home/alejandro/dev/code-pushup-cli/packages/plugin-doc-coverage/mocks/fixtures/angular/app.component.ts",
55-
"line": 5,
55+
"line": 7,
5656
"name": "title",
5757
"type": "properties",
5858
},
@@ -65,9 +65,16 @@ exports[`processDocCoverage > should succesfully get the right number of ts file
6565
"nodesCount": 0,
6666
},
6767
"variables": {
68-
"coverage": 100,
69-
"issues": [],
70-
"nodesCount": 0,
68+
"coverage": 0,
69+
"issues": [
70+
{
71+
"file": "/home/alejandro/dev/code-pushup-cli/packages/plugin-doc-coverage/mocks/fixtures/angular/map-event.function.ts",
72+
"line": 1,
73+
"name": "someVariable",
74+
"type": "variables",
75+
},
76+
],
77+
"nodesCount": 1,
7178
},
7279
}
7380
`;
@@ -89,7 +96,7 @@ exports[`processDocCoverage > should succesfully get the right number of ts file
8996
"issues": [
9097
{
9198
"file": "/home/alejandro/dev/code-pushup-cli/packages/plugin-doc-coverage/mocks/fixtures/angular/map-event.function.ts",
92-
"line": 1,
99+
"line": 3,
93100
"name": "mapEventToCustomEvent",
94101
"type": "functions",
95102
},
@@ -106,7 +113,7 @@ exports[`processDocCoverage > should succesfully get the right number of ts file
106113
"issues": [
107114
{
108115
"file": "/home/alejandro/dev/code-pushup-cli/packages/plugin-doc-coverage/mocks/fixtures/angular/app.component.ts",
109-
"line": 15,
116+
"line": 17,
110117
"name": "sendEvent",
111118
"type": "methods",
112119
},
@@ -118,7 +125,7 @@ exports[`processDocCoverage > should succesfully get the right number of ts file
118125
"issues": [
119126
{
120127
"file": "/home/alejandro/dev/code-pushup-cli/packages/plugin-doc-coverage/mocks/fixtures/angular/app.component.ts",
121-
"line": 5,
128+
"line": 7,
122129
"name": "title",
123130
"type": "properties",
124131
},
@@ -131,9 +138,16 @@ exports[`processDocCoverage > should succesfully get the right number of ts file
131138
"nodesCount": 0,
132139
},
133140
"variables": {
134-
"coverage": 100,
135-
"issues": [],
136-
"nodesCount": 0,
141+
"coverage": 0,
142+
"issues": [
143+
{
144+
"file": "/home/alejandro/dev/code-pushup-cli/packages/plugin-doc-coverage/mocks/fixtures/angular/map-event.function.ts",
145+
"line": 1,
146+
"name": "someVariable",
147+
"type": "variables",
148+
},
149+
],
150+
"nodesCount": 1,
137151
},
138152
}
139153
`;

packages/plugin-doc-coverage/src/lib/runner/doc-processer.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { ClassDeclaration, Project, SourceFile } from 'ts-morph';
1+
import {
2+
ClassDeclaration,
3+
Project,
4+
SourceFile,
5+
VariableStatement,
6+
} from 'ts-morph';
27
import type { DocCoveragePluginConfig } from '../config.js';
38
import type {
49
CoverageResult,
@@ -11,6 +16,30 @@ import {
1116
getCoverageTypeFromKind,
1217
} from './utils.js';
1318

19+
/**
20+
* Gets the variables information from the variable statements
21+
* @param variableStatements - The variable statements to process
22+
* @returns {Node[]} The variables information with the right methods to get the information
23+
*/
24+
export function getVariablesInformation(
25+
variableStatements: VariableStatement[],
26+
) {
27+
return variableStatements.flatMap(variable => {
28+
// Get parent-level information
29+
const parentInfo = {
30+
getKind: () => variable.getKind(),
31+
getJsDocs: () => variable.getJsDocs(),
32+
getStartLineNumber: () => variable.getStartLineNumber(),
33+
};
34+
35+
// Map each declaration to combine parent info with declaration-specific info
36+
return variable.getDeclarations().map(declaration => ({
37+
...parentInfo,
38+
getName: () => declaration.getName(),
39+
}));
40+
});
41+
}
42+
1443
/**
1544
* Processes documentation coverage for TypeScript files in the specified path
1645
* @param toInclude - The file path pattern to include for documentation analysis
@@ -44,6 +73,7 @@ export function getUnprocessedCoverageReport(
4473
...sourceFile.getTypeAliases(),
4574
...sourceFile.getEnums(),
4675
...sourceFile.getInterfaces(),
76+
...getVariablesInformation(sourceFile.getVariableStatements()),
4777
];
4878

4979
const coverageReportOfCurrentFile = allNodesFromFile.reduce(

packages/plugin-doc-coverage/src/lib/runner/doc-processer.unit.test.ts

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import type { ClassDeclaration } from 'ts-morph';
1+
import type { ClassDeclaration, VariableStatement } from 'ts-morph';
22
import { nodeMock, sourceFileMock } from '../../../mocks/source-files.mock';
33
import {
44
getClassNodes,
55
getUnprocessedCoverageReport,
6+
getVariablesInformation,
67
mergeCoverageResults,
78
} from './doc-processer.js';
89
import type { UnprocessedCoverageResult } from './models.js';
@@ -196,3 +197,79 @@ describe('getClassNodes', () => {
196197
expect(propertyNodeSpy).toHaveBeenCalledTimes(1);
197198
});
198199
});
200+
201+
describe('getVariablesInformation', () => {
202+
it('should process variable statements correctly', () => {
203+
const mockDeclaration = {
204+
getName: () => 'testVariable',
205+
};
206+
207+
const mockVariableStatement = {
208+
getKind: () => 'const',
209+
getJsDocs: () => ['some docs'],
210+
getStartLineNumber: () => 42,
211+
getDeclarations: () => [mockDeclaration],
212+
};
213+
214+
const result = getVariablesInformation([
215+
mockVariableStatement as unknown as VariableStatement,
216+
]);
217+
218+
expect(result).toHaveLength(1);
219+
expect(result[0]).toEqual({
220+
getKind: expect.any(Function),
221+
getJsDocs: expect.any(Function),
222+
getStartLineNumber: expect.any(Function),
223+
getName: expect.any(Function),
224+
});
225+
// It must be defined
226+
expect(result[0]!.getName()).toBe('testVariable');
227+
expect(result[0]!.getKind()).toBe('const');
228+
expect(result[0]!.getJsDocs()).toEqual(['some docs']);
229+
expect(result[0]!.getStartLineNumber()).toBe(42);
230+
});
231+
232+
it('should handle multiple declarations in a single variable statement', () => {
233+
const mockDeclarations = [
234+
{ getName: () => 'var1' },
235+
{ getName: () => 'var2' },
236+
];
237+
238+
const mockVariableStatement = {
239+
getKind: () => 'let',
240+
getJsDocs: () => [],
241+
getStartLineNumber: () => 10,
242+
getDeclarations: () => mockDeclarations,
243+
};
244+
245+
const result = getVariablesInformation([
246+
mockVariableStatement as unknown as VariableStatement,
247+
]);
248+
249+
expect(result).toHaveLength(2);
250+
// They must be defined
251+
expect(result[0]!.getName()).toBe('var1');
252+
expect(result[1]!.getName()).toBe('var2');
253+
expect(result[0]!.getKind()).toBe('let');
254+
expect(result[1]!.getKind()).toBe('let');
255+
});
256+
257+
it('should handle empty variable statements array', () => {
258+
const result = getVariablesInformation([]);
259+
expect(result).toHaveLength(0);
260+
});
261+
262+
it('should handle variable statements without declarations', () => {
263+
const mockVariableStatement = {
264+
getKind: () => 'const',
265+
getJsDocs: () => [],
266+
getStartLineNumber: () => 1,
267+
getDeclarations: () => [],
268+
};
269+
270+
const result = getVariablesInformation([
271+
mockVariableStatement as unknown as VariableStatement,
272+
]);
273+
expect(result).toHaveLength(0);
274+
});
275+
});

packages/plugin-doc-coverage/src/lib/runner/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export function getCoverageTypeFromKind(kind: SyntaxKind): CoverageType {
6767
return 'interfaces';
6868
case SyntaxKind.EnumDeclaration:
6969
return 'enums';
70+
case SyntaxKind.VariableStatement:
7071
case SyntaxKind.VariableDeclaration:
7172
return 'variables';
7273
case SyntaxKind.PropertyDeclaration:

0 commit comments

Comments
 (0)