Skip to content

Commit 824b795

Browse files
Spruced up convertComments
1 parent bd5adde commit 824b795

File tree

7 files changed

+169
-102
lines changed

7 files changed

+169
-102
lines changed

docs/Development.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ Compile with `npm run tsc` and run tests with `npm run test`.
2121

2222
## Further Reading
2323

24-
- [Architecture](./Architecture.md): How the general app structure operates
24+
- [Architecture](./Architecture/README.md): How the general app structure operates
2525
- [Dependencies](./Dependencies.md): How functions pass and receive static dependencies
2626
- [Testing](./Testing.md): Unit tests

src/converters/comments/convertComments.test.ts

Lines changed: 10 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ const createStubDependencies = (
99
include: ["a.ts"],
1010
}),
1111
convertFileComments: jest.fn(),
12-
globAsync: jest.fn().mockResolvedValue(["a.ts", "b.ts"]),
12+
extractGlobPaths: jest.fn().mockResolvedValue({
13+
data: ["a.ts", "b.ts"],
14+
status: ResultStatus.Succeeded,
15+
}),
1316
reportCommentResults: jest.fn(),
1417
...overrides,
1518
});
@@ -56,77 +59,27 @@ describe("convertComments", () => {
5659
});
5760
});
5861

59-
it("returns the failure result when a file path glob fails", async () => {
62+
it("returns the failure result when a globbing file paths fails", async () => {
6063
// Arrange
6164
const globAsyncError = new Error();
6265
const dependencies = createStubDependencies({
63-
globAsync: jest.fn().mockResolvedValueOnce(globAsyncError),
64-
});
65-
66-
// Act
67-
const result = await convertComments(
68-
dependencies,
69-
{ comments: true },
70-
createStubOriginalConfigurationsData({
71-
typescript: {
72-
include: ["src/*.ts"],
73-
},
66+
extractGlobPaths: jest.fn().mockResolvedValueOnce({
67+
errors: [globAsyncError],
68+
status: ResultStatus.Failed,
7469
}),
75-
new Map(),
76-
);
77-
78-
// Assert
79-
expect(result).toEqual({
80-
errors: [globAsyncError],
81-
status: ResultStatus.Failed,
82-
});
83-
});
84-
85-
it("returns an error when there are no resultant file paths", async () => {
86-
// Arrange
87-
const dependencies = createStubDependencies({
88-
collectCommentFileNames: async () => ({
89-
include: [],
90-
}),
91-
globAsync: jest.fn().mockResolvedValueOnce([]),
9270
});
9371

9472
// Act
9573
const result = await convertComments(
9674
dependencies,
97-
{ comments: [] },
98-
createStubOriginalConfigurationsData(),
99-
new Map(),
100-
);
101-
102-
// Assert
103-
expect(result).toEqual({
104-
errors: expect.arrayContaining([expect.any(Error)]),
105-
status: ResultStatus.Failed,
106-
});
107-
});
108-
109-
it("returns an error when all globbed file paths are excluded", async () => {
110-
// Arrange
111-
const dependencies = createStubDependencies({
112-
collectCommentFileNames: async () => ({
113-
exclude: ["*.ts"],
114-
include: ["a.ts"],
115-
}),
116-
globAsync: jest.fn().mockResolvedValueOnce(["a.ts"]),
117-
});
118-
119-
// Act
120-
const result = await convertComments(
121-
dependencies,
122-
{ comments: ["*.ts"] },
75+
{ comments: true },
12376
createStubOriginalConfigurationsData(),
12477
new Map(),
12578
);
12679

12780
// Assert
12881
expect(result).toEqual({
129-
errors: expect.arrayContaining([expect.any(Error)]),
82+
errors: [globAsyncError],
13083
status: ResultStatus.Failed,
13184
});
13285
});

src/converters/comments/convertComments.ts

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
1-
import minimatch from "minimatch";
2-
3-
import { GlobAsync } from "../../adapters/globAsync";
41
import { SansDependencies } from "../../binding";
52
import { collectCommentFileNames } from "../../comments/collectCommentFileNames";
63
import { AllOriginalConfigurations } from "../../input/findOriginalConfigurations";
74
import { ResultWithDataStatus, ResultStatus, TSLintToESLintSettings } from "../../types";
8-
import { uniqueFromSources, separateErrors, isError } from "../../utils";
5+
import { isError } from "../../utils";
96
import { convertFileComments } from "./convertFileComments";
7+
import { extractGlobPaths } from "./extractGlobPaths";
108
import { reportCommentResults } from "./reporting/reportCommentResults";
119

1210
export type ConvertCommentsDependencies = {
1311
collectCommentFileNames: SansDependencies<typeof collectCommentFileNames>;
1412
convertFileComments: SansDependencies<typeof convertFileComments>;
15-
globAsync: GlobAsync;
13+
extractGlobPaths: SansDependencies<typeof extractGlobPaths>;
1614
reportCommentResults: SansDependencies<typeof reportCommentResults>;
1715
};
1816

17+
/**
18+
* Root-level driver to convert a tslint:disable comments to eslint-disables.
19+
* @see `/docs/Architecture/Comments.md` for documentation.
20+
*/
1921
export const convertComments = async (
2022
dependencies: ConvertCommentsDependencies,
2123
{ comments }: Pick<TSLintToESLintSettings, "comments">,
2224
{ typescript }: Pick<AllOriginalConfigurations, "typescript">,
2325
ruleEquivalents: Map<string, string[]>,
2426
): Promise<ResultWithDataStatus<string[] | undefined>> => {
27+
// 1. If no comments are requested to be converted, immediately report it out and mark this as passed.
2528
if (comments === undefined) {
2629
dependencies.reportCommentResults();
2730
return {
@@ -30,57 +33,27 @@ export const convertComments = async (
3033
};
3134
}
3235

36+
// 2. Create the list of include and possibly exclude globs to search on.
3337
const commentFileNames = await dependencies.collectCommentFileNames(comments, typescript);
34-
3538
if (commentFileNames instanceof Error) {
3639
return {
3740
errors: [commentFileNames],
3841
status: ResultStatus.Failed,
3942
};
4043
}
4144

42-
const { exclude, include } = commentFileNames;
43-
const [fileGlobErrors, globbedFilePaths] = separateErrors(
44-
await Promise.all(include.map(dependencies.globAsync)),
45-
);
46-
47-
if (fileGlobErrors.length !== 0) {
48-
return {
49-
errors: fileGlobErrors,
50-
status: ResultStatus.Failed,
51-
};
52-
}
53-
54-
if (globbedFilePaths.join("") === "") {
55-
return {
56-
errors: [
57-
new Error(
58-
"--comments found no files. Consider passing no globs to it, to default to all TypeScript files.",
59-
),
60-
],
61-
status: ResultStatus.Failed,
62-
};
63-
}
64-
65-
const uniqueGlobbedFilePaths = uniqueFromSources(...globbedFilePaths).filter(
66-
(filePathGlob) => !exclude?.some((exclusion) => minimatch(filePathGlob, exclusion)),
67-
);
68-
69-
if (uniqueGlobbedFilePaths.join("") === "") {
70-
return {
71-
errors: [
72-
new Error(
73-
`All files passed to --comments were excluded. Consider removing 'exclude' from your TypeScript configuration.`,
74-
),
75-
],
76-
status: ResultStatus.Failed,
77-
};
45+
// 3. Search for files matching those globs to have their comments converted.
46+
const globbedFilePaths = await dependencies.extractGlobPaths(commentFileNames);
47+
if (globbedFilePaths.status !== ResultStatus.Succeeded) {
48+
return globbedFilePaths;
7849
}
7950

51+
// 4. Convert comments in the contents of each file, storing equivalents in a cache.
52+
const uniqueGlobbedFilePaths = globbedFilePaths.data;
8053
const ruleCommentsCache = new Map<string, string[]>();
8154
const fileFailures = (
8255
await Promise.all(
83-
uniqueGlobbedFilePaths.map(async (filePath) =>
56+
globbedFilePaths.data.map(async (filePath) =>
8457
dependencies.convertFileComments(filePath, ruleCommentsCache, ruleEquivalents),
8558
),
8659
)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { ResultStatus } from "../../types";
2+
import { extractGlobPaths, ExtractGlobPathsDependencies } from "./extractGlobPaths";
3+
4+
const createStubDependencies = (
5+
overrides: Partial<ExtractGlobPathsDependencies> = {},
6+
): ExtractGlobPathsDependencies => ({
7+
globAsync: jest.fn().mockResolvedValue(["a.ts", "b.ts"]),
8+
...overrides,
9+
});
10+
11+
describe("extractGlobPaths", () => {
12+
it("returns the failure result when a file path glob fails", async () => {
13+
// Arrange
14+
const globAsyncError = new Error();
15+
const dependencies = createStubDependencies({
16+
globAsync: jest.fn().mockResolvedValueOnce(globAsyncError),
17+
});
18+
19+
// Act
20+
const result = await extractGlobPaths(dependencies, {
21+
include: ["src/*.ts"],
22+
});
23+
24+
// Assert
25+
expect(result).toEqual({
26+
errors: [globAsyncError],
27+
status: ResultStatus.Failed,
28+
});
29+
});
30+
31+
it("returns an error when there are no resultant file paths", async () => {
32+
// Arrange
33+
const dependencies = createStubDependencies({
34+
globAsync: jest.fn().mockResolvedValueOnce([]),
35+
});
36+
37+
// Act
38+
const result = await extractGlobPaths(dependencies, {
39+
include: ["src/*.ts"],
40+
});
41+
42+
// Assert
43+
expect(result).toEqual({
44+
errors: expect.arrayContaining([expect.any(Error)]),
45+
status: ResultStatus.Failed,
46+
});
47+
});
48+
49+
it("returns an error when all globbed file paths are excluded", async () => {
50+
// Arrange
51+
const dependencies = createStubDependencies({
52+
globAsync: jest.fn().mockResolvedValueOnce(["a.ts"]),
53+
});
54+
55+
// Act
56+
const result = await extractGlobPaths(dependencies, {
57+
exclude: ["a.ts"],
58+
include: ["*.ts"],
59+
});
60+
61+
// Assert
62+
expect(result).toEqual({
63+
errors: expect.arrayContaining([expect.any(Error)]),
64+
status: ResultStatus.Failed,
65+
});
66+
});
67+
68+
it("returns the paths when unique file paths are not excluded", async () => {
69+
// Arrange
70+
const dependencies = createStubDependencies({
71+
globAsync: jest.fn().mockResolvedValueOnce(["a.ts"]),
72+
});
73+
74+
// Act
75+
const result = await extractGlobPaths(dependencies, { include: ["*.ts"] });
76+
77+
// Assert
78+
expect(result).toEqual({
79+
data: ["a.ts"],
80+
status: ResultStatus.Succeeded,
81+
});
82+
});
83+
});
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import minimatch from "minimatch";
2+
3+
import { GlobAsync } from "../../adapters/globAsync";
4+
import { CommentFileNames } from "../../comments/collectCommentFileNames";
5+
import { ResultStatus, ResultWithDataStatus } from "../../types";
6+
import { separateErrors, uniqueFromSources } from "../../utils";
7+
8+
export type ExtractGlobPathsDependencies = {
9+
globAsync: GlobAsync;
10+
};
11+
12+
export const extractGlobPaths = async (
13+
dependencies: ExtractGlobPathsDependencies,
14+
{ exclude, include }: CommentFileNames,
15+
): Promise<ResultWithDataStatus<string[]>> => {
16+
const [fileGlobErrors, globbedFilePaths] = separateErrors(
17+
await Promise.all(include.map(dependencies.globAsync)),
18+
);
19+
20+
if (fileGlobErrors.length !== 0) {
21+
return {
22+
errors: fileGlobErrors,
23+
status: ResultStatus.Failed,
24+
};
25+
}
26+
27+
if (globbedFilePaths.join("") === "") {
28+
return {
29+
errors: [
30+
new Error(
31+
"--comments found no files. Consider passing no globs to it, to default to all TypeScript files.",
32+
),
33+
],
34+
status: ResultStatus.Failed,
35+
};
36+
}
37+
38+
const uniqueGlobbedFilePaths = uniqueFromSources(...globbedFilePaths).filter(
39+
(filePathGlob) => !exclude?.some((exclusion) => minimatch(filePathGlob, exclusion)),
40+
);
41+
42+
if (uniqueGlobbedFilePaths.join("") === "") {
43+
return {
44+
errors: [
45+
new Error(
46+
`All files passed to --comments were excluded. Consider removing 'exclude' from your TypeScript configuration.`,
47+
),
48+
],
49+
status: ResultStatus.Failed,
50+
};
51+
}
52+
53+
return {
54+
data: uniqueGlobbedFilePaths,
55+
status: ResultStatus.Succeeded,
56+
};
57+
};

src/converters/editorConfigs/convertEditorConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export type ConvertEditorConfigDependencies = {
1616

1717
/**
1818
* Root-level driver to convert an editor configuration.
19+
* @see `/docs/Architecture/Editors.md` for documentation.
1920
*/
2021
export const convertEditorConfig = async (
2122
dependencies: ConvertEditorConfigDependencies,

src/converters/lintConfigs/convertLintConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export type ConvertLintConfigDependencies = {
1717

1818
/**
1919
* Root-level driver to convert a TSLint configuration to ESLint.
20-
* @see `Architecture.md` for documentation.
20+
* @see `/docs/Architecture/Linting.md` for documentation.
2121
*/
2222
export const convertLintConfig = async (
2323
dependencies: ConvertLintConfigDependencies,

0 commit comments

Comments
 (0)