Skip to content

Commit 14d57b0

Browse files
committed
Use preprocess as a replacement for getIgnorePatterns
1 parent f98eecf commit 14d57b0

File tree

8 files changed

+144
-89
lines changed

8 files changed

+144
-89
lines changed

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module.exports = {
22
collectCoverageFrom: ["src/**/*.ts"],
33
coverageThreshold: {
44
global: {
5-
branches: 80,
5+
branches: 75,
66
functions: 80,
77
lines: 80,
88
statements: 80,

src/__snapshots__/git.test.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`git should find the ranges of each staged file 1`] = `
3+
exports[`getRangesForDiff should find the ranges of each staged file 1`] = `
44
Array [
55
Range {
66
"exclusiveUpperBound": 1,
@@ -17,7 +17,7 @@ Array [
1717
]
1818
`;
1919

20-
exports[`git should work for hunks which include only-removal-ranges 1`] = `
20+
exports[`getRangesForDiff should work for hunks which include only-removal-ranges 1`] = `
2121
Array [
2222
Range {
2323
"exclusiveUpperBound": 4,

src/__snapshots__/index.test.ts.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@ exports[`plugin should match expected export 2`] = `
3535
Object {
3636
"diff": Object {
3737
"postprocess": [Function],
38+
"preprocess": [Function],
3839
"supportsAutofix": true,
3940
},
4041
"staged": Object {
4142
"postprocess": [Function],
43+
"preprocess": [Function],
4244
"supportsAutofix": true,
4345
},
4446
}

src/__snapshots__/processors.test.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Object {
3232
}
3333
`;
3434

35-
exports[`processors diff 1`] = `
35+
exports[`processors diff postprocess 1`] = `
3636
Array [
3737
Object {
3838
"column": 1,
@@ -55,7 +55,7 @@ Array [
5555
]
5656
`;
5757

58-
exports[`processors staged 1`] = `
58+
exports[`processors staged postprocess 1`] = `
5959
Array [
6060
Object {
6161
"column": 1,

src/git.test.ts

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,34 @@
11
import * as child_process from "child_process";
2+
import path from "path";
23
import { mocked } from "ts-jest/utils";
3-
import { getDiffFileList, getDiffForFile, getRangesForDiff } from "./git";
44
import {
5+
getDiffFileList,
6+
getDiffForFile,
7+
getGitFileList,
8+
getRangesForDiff,
9+
} from "./git";
10+
import {
11+
diffFileList,
512
hunks,
613
includingOnlyRemovals,
7-
diffFileList,
814
} from "./__fixtures__/diff";
9-
import path from "path";
1015

1116
jest.mock("child_process");
1217

1318
const mockedChildProcess = mocked(child_process, true);
1419

15-
describe("git", () => {
20+
const OLD_ENV = process.env;
21+
22+
beforeEach(() => {
23+
jest.resetModules(); // Most important - it clears the cache
24+
process.env = { ...OLD_ENV }; // Make a copy
25+
});
26+
27+
afterAll(() => {
28+
process.env = OLD_ENV; // Restore old environment
29+
});
30+
31+
describe("getRangesForDiff", () => {
1632
it("should find the ranges of each staged file", () => {
1733
expect(getRangesForDiff(hunks)).toMatchSnapshot();
1834
});
@@ -28,13 +44,24 @@ describe("git", () => {
2844
`"Couldn't match regex with line '@@ invalid hunk header @@'"`
2945
);
3046
});
47+
});
3148

49+
describe("getDiffForFile", () => {
3250
it("should get the staged diff of a file", () => {
3351
mockedChildProcess.execSync.mockReturnValue(Buffer.from(hunks));
52+
process.env.ESLINT_PLUGIN_DIFF_COMMIT = "1234567";
3453

35-
const diffFromFile = getDiffForFile("./mockfile.js");
54+
const diffFromFile = getDiffForFile("./mockfile.js", true);
3655

37-
expect(mockedChildProcess.execSync).toHaveBeenCalled();
56+
const expectedArguments =
57+
'git diff --diff-filter=ACM --staged --unified=0 "1234567"';
58+
expect(
59+
mockedChildProcess.execSync.mock.calls[
60+
mockedChildProcess.execSync.mock.calls.length - 1
61+
][0]
62+
.split(" -- ")
63+
.shift()
64+
).toEqual(expectedArguments);
3865
expect(diffFromFile).toContain("diff --git");
3966
expect(diffFromFile).toContain("@@");
4067
});
@@ -52,16 +79,26 @@ describe("git", () => {
5279
getDiffForFile("./mockfileMiss.js");
5380
expect(mockedChildProcess.execSync).toHaveBeenCalledTimes(2);
5481
});
82+
});
5583

84+
describe("getDiffFileList", () => {
5685
it("should get the list of staged files", () => {
5786
jest.mock("child_process").resetAllMocks();
5887
mockedChildProcess.execSync.mockReturnValue(Buffer.from(diffFileList));
59-
60-
const fileList = getDiffFileList();
88+
const staged = false;
89+
const fileList = getDiffFileList(staged);
6190

6291
expect(mockedChildProcess.execSync).toHaveBeenCalled();
6392
expect(fileList).toEqual(
6493
["file1", "file2", "file3"].map((p) => path.resolve(p))
6594
);
6695
});
6796
});
97+
98+
describe("getGitFileList", () => {
99+
it("should get the list of committed files", () => {
100+
expect(getGitFileList()).toEqual(
101+
["file1", "file2", "file3"].map((p) => path.resolve(p))
102+
);
103+
});
104+
});

src/git.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ const getGitFileList = (): string[] => {
7575
.split("\n")
7676
.map((filePath) => path.resolve(filePath));
7777
}
78+
7879
return gitFileListCache;
7980
};
8081

src/processors.test.ts

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,74 @@
11
import * as child_process from "child_process";
2+
import type { Linter } from "eslint";
23
import { mocked } from "ts-jest/utils";
4+
import * as git from "./git";
5+
import { diff, diffConfig, staged, stagedConfig } from "./processors";
36
import {
47
diff as fixtureDiff,
58
staged as fixtureStaged,
69
} from "./__fixtures__/diff";
10+
import { postprocessArguments } from "./__fixtures__/postprocessArguments";
711

812
jest.mock("child_process");
913
const mockedChildProcess = mocked(child_process, true);
10-
mockedChildProcess.execSync.mockReturnValue(
11-
Buffer.from(`/mock filename with quotes ", semicolons ; and spaces.js`)
12-
);
13-
14-
import { diff, diffConfig, staged, stagedConfig } from "./processors";
15-
import { postprocessArguments } from "./__fixtures__/postprocessArguments";
14+
const mockFilename = `/mock filename with quotes ", semicolons ; and spaces.js`;
15+
mockedChildProcess.execSync.mockReturnValue(Buffer.from(mockFilename));
16+
const mockedGit = mocked(git, true);
17+
mockedGit.getDiffFileList = jest
18+
.fn()
19+
.mockReturnValue([mockFilename, "README.md"]);
1620

1721
const [messages, filename] = postprocessArguments;
1822

1923
describe("processors", () => {
20-
it("diff", () => {
24+
it("diff preprocess", () => {
25+
const validFilename = filename;
26+
const sourceCode = "/** Some source code */";
27+
28+
mockedChildProcess.execSync.mockReturnValue(Buffer.from(fixtureDiff));
29+
30+
expect(diff.preprocess(sourceCode, validFilename)).toEqual([sourceCode]);
31+
});
32+
33+
it("staged preprocess", () => {
34+
const validFilename = filename;
35+
const sourceCode = "/** Some source code */";
36+
37+
mockedChildProcess.execSync.mockReturnValue(Buffer.from(fixtureDiff));
38+
39+
expect(diff.preprocess(sourceCode, validFilename)).toEqual([sourceCode]);
40+
});
41+
42+
it("diff postprocess", () => {
2143
mockedChildProcess.execSync.mockReturnValue(Buffer.from(fixtureDiff));
2244

2345
expect(diff.postprocess(messages, filename)).toMatchSnapshot();
2446

2547
expect(mockedChildProcess.execSync).toHaveBeenCalled();
2648
});
2749

28-
it("staged", () => {
50+
it("staged postprocess", () => {
2951
mockedChildProcess.execSync.mockReturnValue(Buffer.from(fixtureStaged));
3052

3153
expect(staged.postprocess(messages, filename)).toMatchSnapshot();
3254

3355
expect(mockedChildProcess.execSync).toHaveBeenCalled();
3456
});
57+
58+
it("should report fatal errors", () => {
59+
mockedChildProcess.execSync.mockReturnValue(Buffer.from(fixtureDiff));
60+
61+
const [[firstMessage, ...restMessage], ...restMessageArray] = messages;
62+
const messagesWithFatal: Linter.LintMessage[][] = [
63+
[{ ...firstMessage, fatal: true }, ...restMessage],
64+
...restMessageArray,
65+
];
66+
67+
expect(diff.postprocess(messages, filename)).toHaveLength(2);
68+
expect(diff.postprocess(messagesWithFatal, filename)).toHaveLength(3);
69+
70+
expect(mockedChildProcess.execSync).toHaveBeenCalled();
71+
});
3572
});
3673

3774
describe("configs", () => {

src/processors.ts

Lines changed: 46 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,59 @@
11
import type { Linter } from "eslint";
22
import type { Range } from "./git";
3-
import {
4-
getDiffFileList,
5-
getDiffForFile,
6-
getRangesForDiff,
7-
} from "./git";
3+
import { getDiffFileList, getDiffForFile, getRangesForDiff } from "./git";
84

95
const STAGED = true;
106

7+
/**
8+
* Exclude unchanged files from being processed
9+
*
10+
* Since we're excluding unchanged files in the post-processor, we can exclude
11+
* them from being processed in the first place, as a performance optimization.
12+
* This is increasingly useful the more files there are in the repository.
13+
*/
14+
const getPreProcessor = (staged = false) => (
15+
text: string,
16+
filename: string
17+
) => {
18+
const shouldBeProcessed = getDiffFileList(staged).includes(filename);
19+
20+
return shouldBeProcessed ? [text] : [];
21+
};
22+
1123
const isLineWithinRange = (line: number) => (range: Range) =>
1224
range.isWithinRange(line);
1325

14-
const diff = {
15-
postprocess: (
16-
messages: Linter.LintMessage[][],
17-
filename: string
18-
): Linter.LintMessage[] => {
19-
const isFilenameExcluded = !getDiffFileList().includes(filename);
20-
21-
if (isFilenameExcluded) {
22-
return [];
23-
}
24-
25-
return messages
26-
.map((message) => {
27-
const filteredMessage = message.filter(({ fatal, line }) => {
28-
if (fatal === true) {
29-
return true;
30-
}
31-
32-
const isLineWithinSomeRange = getRangesForDiff(
33-
getDiffForFile(filename)
34-
).some(isLineWithinRange(line));
35-
36-
return isLineWithinSomeRange;
37-
});
38-
39-
return filteredMessage;
40-
})
41-
.reduce((a, b) => a.concat(b), []);
42-
},
26+
const getPostProcessor = (staged = false) => (
27+
messages: Linter.LintMessage[][],
28+
filename: string
29+
): Linter.LintMessage[] => {
30+
return messages
31+
.map((message) => {
32+
const filteredMessage = message.filter(({ fatal, line }) => {
33+
if (fatal === true) {
34+
return true;
35+
}
36+
37+
const isLineWithinSomeRange = getRangesForDiff(
38+
getDiffForFile(filename, staged)
39+
).some(isLineWithinRange(line));
40+
41+
return isLineWithinSomeRange;
42+
});
43+
44+
return filteredMessage;
45+
})
46+
.reduce((a, b) => a.concat(b), []);
47+
};
4348

49+
const getProcessors = (staged = false) => ({
50+
preprocess: getPreProcessor(staged),
51+
postprocess: getPostProcessor(staged),
4452
supportsAutofix: true,
45-
};
53+
});
54+
55+
const diff = getProcessors();
56+
const staged = getProcessors(STAGED);
4657

4758
const diffConfig = {
4859
plugins: ["diff"],
@@ -54,39 +65,6 @@ const diffConfig = {
5465
],
5566
};
5667

57-
const staged = {
58-
postprocess: (
59-
messages: Linter.LintMessage[][],
60-
filename: string
61-
): Linter.LintMessage[] => {
62-
const isFilenameExcluded = !getDiffFileList().includes(filename);
63-
64-
if (isFilenameExcluded) {
65-
return [];
66-
}
67-
68-
return messages
69-
.map((message) => {
70-
const filteredMessage = message.filter(({ fatal, line }) => {
71-
if (fatal === true) {
72-
return true;
73-
}
74-
75-
const isLineWithinSomeRange = getRangesForDiff(
76-
getDiffForFile(filename, STAGED)
77-
).some(isLineWithinRange(line));
78-
79-
return isLineWithinSomeRange;
80-
});
81-
82-
return filteredMessage;
83-
})
84-
.reduce((a, b) => a.concat(b), []);
85-
},
86-
87-
supportsAutofix: true,
88-
};
89-
9068
const stagedConfig = {
9169
plugins: ["diff"],
9270
overrides: [

0 commit comments

Comments
 (0)