forked from angular/angular-cli
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.ts
More file actions
143 lines (121 loc) · 4.14 KB
/
index.ts
File metadata and controls
143 lines (121 loc) · 4.14 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
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {
DirEntry,
Rule,
SchematicContext,
SchematicsException,
Tree,
} from '@angular-devkit/schematics';
import { join, normalize } from 'node:path/posix';
import { ProjectDefinition, getWorkspace } from '../../utility/workspace';
import { Schema } from './schema';
import { transformJasmineToVitest } from './test-file-transformer';
import { RefactorReporter } from './utils/refactor-reporter';
async function getProject(
tree: Tree,
projectName: string | undefined,
): Promise<{ project: ProjectDefinition; name: string }> {
const workspace = await getWorkspace(tree);
if (projectName) {
const project = workspace.projects.get(projectName);
if (!project) {
throw new SchematicsException(`Project "${projectName}" not found.`);
}
return { project, name: projectName };
}
if (workspace.projects.size === 1) {
const [name, project] = Array.from(workspace.projects.entries())[0];
return { project, name };
}
const projectNames = Array.from(workspace.projects.keys());
throw new SchematicsException(
`Multiple projects found: [${projectNames.join(', ')}]. Please specify a project name.`,
);
}
const DIRECTORIES_TO_SKIP = new Set(['node_modules', '.git', 'dist', '.angular']);
function findTestFiles(directory: DirEntry, fileSuffix: string): string[] {
const files: string[] = [];
const stack: DirEntry[] = [directory];
let current: DirEntry | undefined;
while ((current = stack.pop())) {
for (const path of current.subfiles) {
if (path.endsWith(fileSuffix)) {
files.push(current.path + '/' + path);
}
}
for (const path of current.subdirs) {
if (DIRECTORIES_TO_SKIP.has(path)) {
continue;
}
stack.push(current.dir(path));
}
}
return files;
}
export default function (options: Schema): Rule {
return async (tree: Tree, context: SchematicContext) => {
const reporter = new RefactorReporter(context.logger);
const { project, name: projectName } = await getProject(tree, options.project);
const projectRoot = project.root;
const fileSuffix = options.fileSuffix ?? '.spec.ts';
let files: string[];
let searchScope: string;
if (options.include) {
const normalizedInclude = options.include.replace(/\\/g, '/');
const includePath = normalize(join(projectRoot, normalizedInclude));
searchScope = options.include;
let dirEntry: DirEntry | null = null;
try {
dirEntry = tree.getDir(includePath);
} catch {
// Path is not a directory.
}
// Approximation of a directory exists check
if (dirEntry && (dirEntry.subdirs.length > 0 || dirEntry.subfiles.length > 0)) {
// It is a directory
files = findTestFiles(dirEntry, fileSuffix);
} else if (tree.exists(includePath)) {
// It is a file
files = [includePath];
} else {
throw new SchematicsException(
`The specified include path '${options.include}' does not exist.`,
);
}
} else {
searchScope = `project '${projectName}'`;
files = findTestFiles(tree.getDir(projectRoot), fileSuffix);
}
if (files.length === 0) {
throw new SchematicsException(
`No files ending with '${fileSuffix}' found in ${searchScope}.`,
);
}
for (const file of files) {
reporter.incrementScannedFiles();
const content = tree.readText(file);
const newContent = transformJasmineToVitest(file, content, reporter, {
addImports: !!options.addImports,
browserMode: !!options.browerMode,
});
if (content !== newContent) {
tree.overwrite(file, newContent);
reporter.incrementTransformedFiles();
}
}
if (options.report) {
const reportContent = reporter.generateReportContent();
tree.create(
`jasmine-vitest-${new Date().toISOString().replaceAll(/[-:.]/g, '')}.md`,
reportContent,
);
}
reporter.printSummary(options.verbose);
};
}