-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathdoc-processor.ts
More file actions
166 lines (153 loc) · 4.72 KB
/
Copy pathdoc-processor.ts
File metadata and controls
166 lines (153 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import {
ClassDeclaration,
JSDoc,
Project,
SourceFile,
SyntaxKind,
VariableStatement,
} from 'ts-morph';
import {
type FileCoverage,
objectFromEntries,
objectToEntries,
} from '@code-pushup/utils';
import type { JsDocsPluginTransformedConfig } from '../config.js';
import type { CoverageType } from './models.js';
import {
createInitialCoverageTypesRecord,
getCoverageTypeFromKind,
logReport,
logSourceFiles,
singularCoverageType,
} from './utils.js';
type Node = {
getKind: () => SyntaxKind;
getName: () => string | undefined;
getStartLineNumber: () => number;
getEndLineNumber: () => number;
getJsDocs: () => JSDoc[];
};
/**
* Gets the variables information from the variable statements
* @param variableStatements The variable statements to process
* @returns The variables information with the right methods to get the information
*/
export function getVariablesInformation(
variableStatements: VariableStatement[],
): Node[] {
return variableStatements.flatMap(variable => {
// Get parent-level information
const parentInfo = {
getKind: () => variable.getKind(),
getJsDocs: () => variable.getJsDocs(),
getStartLineNumber: () => variable.getStartLineNumber(),
getEndLineNumber: () => variable.getEndLineNumber(),
};
// Map each declaration to combine parent info with declaration-specific info
return variable.getDeclarations().map(declaration => ({
...parentInfo,
getName: () => declaration.getName(),
}));
});
}
/**
* Processes documentation coverage for TypeScript files in the specified path
* @param config The configuration object containing patterns to include for documentation analysis
* @returns Object containing coverage statistics and undocumented items
*/
export function processJsDocs(
config: JsDocsPluginTransformedConfig,
): Record<CoverageType, FileCoverage[]> {
const project = new Project();
project.addSourceFilesAtPaths(config.patterns);
const sourceFiles = project.getSourceFiles();
logSourceFiles(sourceFiles, config);
const report = getDocumentationReport(sourceFiles);
logReport(report);
return report;
}
export function getAllNodesFromASourceFile(sourceFile: SourceFile) {
const classes = sourceFile.getClasses();
return [
...sourceFile.getFunctions(),
...classes,
...getClassNodes(classes),
...sourceFile.getTypeAliases(),
...sourceFile.getEnums(),
...sourceFile.getInterfaces(),
...getVariablesInformation(sourceFile.getVariableStatements()),
];
}
/**
* Gets the documentation coverage report from the source files
* @param sourceFiles The source files to process
* @returns The documentation coverage report
*/
export function getDocumentationReport(
sourceFiles: SourceFile[],
): Record<CoverageType, FileCoverage[]> {
return sourceFiles.reduce((acc, sourceFile) => {
const filePath = sourceFile.getFilePath();
const nodes = getAllNodesFromASourceFile(sourceFile);
const coverageTypes = getCoverageFromAllNodesOfFile(nodes, filePath);
return objectFromEntries(
objectToEntries(coverageTypes).map(([type, file]) => [
type,
[...acc[type], file],
]),
);
}, createInitialCoverageTypesRecord<FileCoverage[]>([]));
}
/**
* Gets the coverage from all nodes of a file
* @param nodes The nodes to process
* @param filePath The file path where the nodes are located
* @returns The coverage report for the nodes
*/
function getCoverageFromAllNodesOfFile(nodes: Node[], filePath: string) {
return nodes.reduce(
(acc: Record<CoverageType, FileCoverage>, node: Node) => {
const nodeType = getCoverageTypeFromKind(node.getKind());
const isCovered = node.getJsDocs().length > 0;
return {
...acc,
[nodeType]: {
...acc[nodeType],
total: acc[nodeType].total + 1,
...(isCovered
? {
covered: acc[nodeType].covered + 1,
}
: {
missing: [
...acc[nodeType].missing,
{
kind: singularCoverageType(nodeType),
name: node.getName(),
startLine: node.getStartLineNumber(),
endLine: node.getEndLineNumber(),
},
],
}),
},
};
},
createInitialCoverageTypesRecord<FileCoverage>({
path: filePath,
covered: 0,
total: 0,
missing: [],
}),
);
}
/**
* Gets the nodes from a class
* @param classNodes The class nodes to process
* @returns The nodes from the class
*/
export function getClassNodes(classNodes: ClassDeclaration[]) {
return classNodes.flatMap(classNode => [
...classNode.getMethods(),
...classNode.getProperties(),
]);
}