Skip to content

Commit e3e8012

Browse files
authored
feat(checker): add ability to check multiple files at once (#127)
1 parent b0cea23 commit e3e8012

File tree

4 files changed

+150
-72
lines changed

4 files changed

+150
-72
lines changed

bin/check.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,2 @@
11
#!/usr/bin/env node
2-
3-
try {
4-
require("../lib/checker").check(process.argv[2]);
5-
} catch (e) {
6-
if (e.name === "ConflictRules") {
7-
console.log(e.message);
8-
process.exitCode = 1;
9-
} else {
10-
throw e;
11-
}
12-
}
2+
require("../lib/checker").check(process.argv.slice(2));
Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,63 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`should show success message for conflict rules that is disabled 1`] = `"No conflict rule detected in <cwd>/fixtures/tslint.false.json"`;
3+
exports[`should be able to check multiple config files 1`] = `
4+
"[error] Conflict rule(s) detected in <cwd>/fixtures/tslint.all.json:
5+
[error] align
6+
[error] arrow-parens
7+
[error] eofline
8+
[error] import-spacing
9+
[error] indent
10+
[error] linebreak-style
11+
[error] max-line-length
12+
[error] new-parens
13+
[error] newline-per-chained-call
14+
[error] no-consecutive-blank-lines
15+
[error] no-irregular-whitespace
16+
[error] no-trailing-whitespace
17+
[error] number-literal-format
18+
[error] object-literal-key-quotes
19+
[error] one-line
20+
[error] quotemark
21+
[error] semicolon
22+
[error] space-before-function-paren
23+
[error] space-within-parens
24+
[error] trailing-comma
25+
[error] typedef-whitespace
26+
[error] whitespace
27+
[log] No conflict rule detected in <cwd>/fixtures/tslint.empty.json
28+
[error] Unexpected number in JSON at position 1 in <cwd>/fixtures/tslint.error.json"
29+
`;
30+
31+
exports[`should show success message for conflict rules that is disabled 1`] = `"[log] No conflict rule detected in <cwd>/fixtures/tslint.false.json"`;
432
5-
exports[`should show success message for non-conflict rules 1`] = `"No conflict rule detected in <cwd>/fixtures/tslint.empty.json"`;
33+
exports[`should show success message for non-conflict rules 1`] = `"[log] No conflict rule detected in <cwd>/fixtures/tslint.empty.json"`;
34+
35+
exports[`should show usage if there is no filePath 1`] = `"[log] Usage: tslint-config-prettier-check <pathToConfigFile> ..."`;
636
737
exports[`should throw conflict rules 1`] = `
8-
"Conflict rule(s) detected in <cwd>/fixtures/tslint.all.json:
9-
align
10-
arrow-parens
11-
eofline
12-
import-spacing
13-
indent
14-
linebreak-style
15-
max-line-length
16-
new-parens
17-
newline-per-chained-call
18-
no-consecutive-blank-lines
19-
no-irregular-whitespace
20-
no-trailing-whitespace
21-
number-literal-format
22-
object-literal-key-quotes
23-
one-line
24-
quotemark
25-
semicolon
26-
space-before-function-paren
27-
space-within-parens
28-
trailing-comma
29-
typedef-whitespace
30-
whitespace"
38+
"[error] Conflict rule(s) detected in <cwd>/fixtures/tslint.all.json:
39+
[error] align
40+
[error] arrow-parens
41+
[error] eofline
42+
[error] import-spacing
43+
[error] indent
44+
[error] linebreak-style
45+
[error] max-line-length
46+
[error] new-parens
47+
[error] newline-per-chained-call
48+
[error] no-consecutive-blank-lines
49+
[error] no-irregular-whitespace
50+
[error] no-trailing-whitespace
51+
[error] number-literal-format
52+
[error] object-literal-key-quotes
53+
[error] one-line
54+
[error] quotemark
55+
[error] semicolon
56+
[error] space-before-function-paren
57+
[error] space-within-parens
58+
[error] trailing-comma
59+
[error] typedef-whitespace
60+
[error] whitespace"
3161
`;
3262
33-
exports[`should throw error if input is not a string 1`] = `"Usage: tslint-config-prettier-check <pathToConfigFile>"`;
34-
35-
exports[`should throw parsing error for invalid config 1`] = `"Unexpected number in JSON at position 1 in <cwd>/fixtures/tslint.error.json"`;
63+
exports[`should throw parsing error for invalid config 1`] = `"[error] Unexpected number in JSON at position 1 in <cwd>/fixtures/tslint.error.json"`;

tools/checker.test.ts

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,82 @@ import * as path from "path";
22
import { check } from "./checker";
33

44
expect.addSnapshotSerializer({
5-
print: (value: string, serializer) => serializer(value.replace(process.cwd(), "<cwd>")),
6-
test: (value) => typeof value === "string" && value.indexOf(process.cwd()) !== -1,
5+
print: (value: string, serializer) =>
6+
serializer(value.replace(process.cwd(), "<cwd>")),
7+
test: (value) =>
8+
typeof value === "string" && value.indexOf(process.cwd()) !== -1,
79
});
810

9-
const mockedConsoleLog = jest.spyOn(console, "log");
11+
const messages: string[] = [];
12+
13+
mockConsole("log");
14+
mockConsole("error");
1015

1116
beforeEach(() => {
12-
mockedConsoleLog.mockReset();
17+
messages.splice(0, messages.length);
18+
process.exitCode = 0;
19+
});
20+
21+
afterAll(() => {
22+
process.exitCode = 0;
1323
});
1424

1525
it("should throw conflict rules", () => {
16-
expect(() => checkFixture("all")).toThrowErrorMatchingSnapshot();
26+
checkFixture("all");
27+
expect(getMessage()).toMatchSnapshot();
28+
expect(process.exitCode).toBe(1);
1729
});
1830

1931
it("should throw parsing error for invalid config", () => {
20-
expect(() => checkFixture("error")).toThrowErrorMatchingSnapshot();
32+
checkFixture("error");
33+
expect(getMessage()).toMatchSnapshot();
34+
expect(process.exitCode).toBe(1);
2135
});
2236

2337
it("should show success message for non-conflict rules", () => {
2438
checkFixture("empty");
25-
expect(mockedConsoleLog.mock.calls[0][0]).toMatchSnapshot();
39+
expect(getMessage()).toMatchSnapshot();
40+
expect(process.exitCode).toBe(0);
2641
});
2742

2843
it("should show success message for conflict rules that is disabled", () => {
2944
checkFixture("false");
30-
expect(mockedConsoleLog.mock.calls[0][0]).toMatchSnapshot();
45+
expect(getMessage()).toMatchSnapshot();
46+
expect(process.exitCode).toBe(0);
47+
});
48+
49+
it("should show usage if there is no filePath", () => {
50+
checkFixture();
51+
expect(getMessage()).toMatchSnapshot();
52+
expect(process.exitCode).toBe(0);
3153
});
3254

33-
it("should throw error if input is not a string", () => {
34-
expect(() => check(undefined!)).toThrowErrorMatchingSnapshot();
55+
it("should be able to check multiple config files", () => {
56+
checkFixture("all", "empty", "error");
57+
expect(getMessage()).toMatchSnapshot();
58+
expect(process.exitCode).toBe(1);
3559
});
3660

37-
function checkFixture(id: string) {
38-
const filePath = path.resolve(__dirname, `../fixtures/tslint.${id}.json`);
39-
return check(filePath);
61+
function mockConsole(id: keyof typeof console) {
62+
const mockedConsoleLog = jest
63+
.spyOn(console, id)
64+
.mockImplementation((message: string) =>
65+
messages.push(
66+
message
67+
.split("\n")
68+
.map((x) => `[${id}] ${x}`)
69+
.join("\n"),
70+
),
71+
);
72+
}
73+
74+
function getMessage() {
75+
return messages.join("\n");
76+
}
77+
78+
function checkFixture(...ids: string[]) {
79+
const filePaths = ids.map((id) =>
80+
path.resolve(__dirname, `../fixtures/tslint.${id}.json`),
81+
);
82+
return check(filePaths);
4083
}

tools/checker.ts

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,49 @@ import { Configuration, Linter } from "tslint";
44
// tslint:disable-next-line:no-var-requires
55
const tslintConfigPrettier = require("..") as Configuration.RawConfigFile;
66

7-
export const check = (configFilePath: string) => {
8-
if (typeof configFilePath !== "string") {
9-
throw new Error("Usage: tslint-config-prettier-check <pathToConfigFile>");
7+
export const check = (configFilePaths: string[]) => {
8+
if (configFilePaths.length === 0) {
9+
// tslint:disable-next-line:no-console
10+
console.log("Usage: tslint-config-prettier-check <pathToConfigFile> ...");
11+
return;
1012
}
1113

12-
const { rules, jsRules } = Linter.loadConfigurationFromPath(configFilePath);
13-
14-
const conflictRules: string[] = [];
15-
16-
Object.keys(tslintConfigPrettier.rules!).forEach((conflictRuleName) => {
17-
if (isConflict(conflictRuleName, rules) || isConflict(conflictRuleName, jsRules)) {
18-
conflictRules.push(conflictRuleName);
14+
configFilePaths.forEach((configFilePath) => {
15+
try {
16+
const conflictRules = getConflictRules(configFilePath);
17+
if (conflictRules.length === 0) {
18+
// tslint:disable-next-line:no-console
19+
console.log(`No conflict rule detected in ${configFilePath}`);
20+
} else {
21+
// tslint:disable-next-line:no-console
22+
console.error(
23+
`Conflict rule(s) detected in ${configFilePath}:\n${conflictRules
24+
.map((conflictRule) => ` ${conflictRule}`)
25+
.join("\n")}`,
26+
);
27+
process.exitCode = 1;
28+
}
29+
} catch (error) {
30+
// tslint:disable-next-line:no-console
31+
console.error(error.message);
32+
process.exitCode = 1;
1933
}
2034
});
21-
22-
if (conflictRules.length !== 0) {
23-
const error = new Error(`Conflict rule(s) detected in ${configFilePath}:\n${conflictRules.join("\n")}`);
24-
error.name = "ConflictRules";
25-
throw error;
26-
}
27-
28-
// tslint:disable-next-line:no-console
29-
console.log(`No conflict rule detected in ${configFilePath}`);
3035
};
3136

32-
function isConflict(conflictRuleName: string, rules: Configuration.IConfigurationFile["rules"]) {
37+
function getConflictRules(configFilePath: string) {
38+
const { rules, jsRules } = Linter.loadConfigurationFromPath(configFilePath);
39+
return Object.keys(tslintConfigPrettier.rules!).filter(
40+
(conflictRuleName) =>
41+
isConflict(conflictRuleName, rules) ||
42+
isConflict(conflictRuleName, jsRules),
43+
);
44+
}
45+
46+
function isConflict(
47+
conflictRuleName: string,
48+
rules: Configuration.IConfigurationFile["rules"],
49+
) {
3350
return (
3451
rules.has(conflictRuleName) &&
3552
rules.get(conflictRuleName)!.ruleSeverity !== "off"

0 commit comments

Comments
 (0)