Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(checker): add ability to check multiple files at once #127

Merged
merged 1 commit into from
Apr 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 1 addition & 11 deletions bin/check.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,2 @@
#!/usr/bin/env node

try {
require("../lib/checker").check(process.argv[2]);
} catch (e) {
if (e.name === "ConflictRules") {
console.log(e.message);
process.exitCode = 1;
} else {
throw e;
}
}
require("../lib/checker").check(process.argv.slice(2));
84 changes: 56 additions & 28 deletions tools/__snapshots__/checker.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,35 +1,63 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should show success message for conflict rules that is disabled 1`] = `"No conflict rule detected in <cwd>/fixtures/tslint.false.json"`;
exports[`should be able to check multiple config files 1`] = `
"[error] Conflict rule(s) detected in <cwd>/fixtures/tslint.all.json:
[error] align
[error] arrow-parens
[error] eofline
[error] import-spacing
[error] indent
[error] linebreak-style
[error] max-line-length
[error] new-parens
[error] newline-per-chained-call
[error] no-consecutive-blank-lines
[error] no-irregular-whitespace
[error] no-trailing-whitespace
[error] number-literal-format
[error] object-literal-key-quotes
[error] one-line
[error] quotemark
[error] semicolon
[error] space-before-function-paren
[error] space-within-parens
[error] trailing-comma
[error] typedef-whitespace
[error] whitespace
[log] No conflict rule detected in <cwd>/fixtures/tslint.empty.json
[error] Unexpected number in JSON at position 1 in <cwd>/fixtures/tslint.error.json"
`;

exports[`should show success message for conflict rules that is disabled 1`] = `"[log] No conflict rule detected in <cwd>/fixtures/tslint.false.json"`;

exports[`should show success message for non-conflict rules 1`] = `"No conflict rule detected in <cwd>/fixtures/tslint.empty.json"`;
exports[`should show success message for non-conflict rules 1`] = `"[log] No conflict rule detected in <cwd>/fixtures/tslint.empty.json"`;

exports[`should show usage if there is no filePath 1`] = `"[log] Usage: tslint-config-prettier-check <pathToConfigFile> ..."`;

exports[`should throw conflict rules 1`] = `
"Conflict rule(s) detected in <cwd>/fixtures/tslint.all.json:
align
arrow-parens
eofline
import-spacing
indent
linebreak-style
max-line-length
new-parens
newline-per-chained-call
no-consecutive-blank-lines
no-irregular-whitespace
no-trailing-whitespace
number-literal-format
object-literal-key-quotes
one-line
quotemark
semicolon
space-before-function-paren
space-within-parens
trailing-comma
typedef-whitespace
whitespace"
"[error] Conflict rule(s) detected in <cwd>/fixtures/tslint.all.json:
[error] align
[error] arrow-parens
[error] eofline
[error] import-spacing
[error] indent
[error] linebreak-style
[error] max-line-length
[error] new-parens
[error] newline-per-chained-call
[error] no-consecutive-blank-lines
[error] no-irregular-whitespace
[error] no-trailing-whitespace
[error] number-literal-format
[error] object-literal-key-quotes
[error] one-line
[error] quotemark
[error] semicolon
[error] space-before-function-paren
[error] space-within-parens
[error] trailing-comma
[error] typedef-whitespace
[error] whitespace"
`;

exports[`should throw error if input is not a string 1`] = `"Usage: tslint-config-prettier-check <pathToConfigFile>"`;

exports[`should throw parsing error for invalid config 1`] = `"Unexpected number in JSON at position 1 in <cwd>/fixtures/tslint.error.json"`;
exports[`should throw parsing error for invalid config 1`] = `"[error] Unexpected number in JSON at position 1 in <cwd>/fixtures/tslint.error.json"`;
69 changes: 56 additions & 13 deletions tools/checker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,82 @@ import * as path from "path";
import { check } from "./checker";

expect.addSnapshotSerializer({
print: (value: string, serializer) => serializer(value.replace(process.cwd(), "<cwd>")),
test: (value) => typeof value === "string" && value.indexOf(process.cwd()) !== -1,
print: (value: string, serializer) =>
serializer(value.replace(process.cwd(), "<cwd>")),
test: (value) =>
typeof value === "string" && value.indexOf(process.cwd()) !== -1,
});

const mockedConsoleLog = jest.spyOn(console, "log");
const messages: string[] = [];

mockConsole("log");
mockConsole("error");

beforeEach(() => {
mockedConsoleLog.mockReset();
messages.splice(0, messages.length);
process.exitCode = 0;
});

afterAll(() => {
process.exitCode = 0;
});

it("should throw conflict rules", () => {
expect(() => checkFixture("all")).toThrowErrorMatchingSnapshot();
checkFixture("all");
expect(getMessage()).toMatchSnapshot();
expect(process.exitCode).toBe(1);
});

it("should throw parsing error for invalid config", () => {
expect(() => checkFixture("error")).toThrowErrorMatchingSnapshot();
checkFixture("error");
expect(getMessage()).toMatchSnapshot();
expect(process.exitCode).toBe(1);
});

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

it("should show success message for conflict rules that is disabled", () => {
checkFixture("false");
expect(mockedConsoleLog.mock.calls[0][0]).toMatchSnapshot();
expect(getMessage()).toMatchSnapshot();
expect(process.exitCode).toBe(0);
});

it("should show usage if there is no filePath", () => {
checkFixture();
expect(getMessage()).toMatchSnapshot();
expect(process.exitCode).toBe(0);
});

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

function checkFixture(id: string) {
const filePath = path.resolve(__dirname, `../fixtures/tslint.${id}.json`);
return check(filePath);
function mockConsole(id: keyof typeof console) {
const mockedConsoleLog = jest
.spyOn(console, id)
.mockImplementation((message: string) =>
messages.push(
message
.split("\n")
.map((x) => `[${id}] ${x}`)
.join("\n"),
),
);
}

function getMessage() {
return messages.join("\n");
}

function checkFixture(...ids: string[]) {
const filePaths = ids.map((id) =>
path.resolve(__dirname, `../fixtures/tslint.${id}.json`),
);
return check(filePaths);
}
57 changes: 37 additions & 20 deletions tools/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,49 @@ import { Configuration, Linter } from "tslint";
// tslint:disable-next-line:no-var-requires
const tslintConfigPrettier = require("..") as Configuration.RawConfigFile;

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

const { rules, jsRules } = Linter.loadConfigurationFromPath(configFilePath);

const conflictRules: string[] = [];

Object.keys(tslintConfigPrettier.rules!).forEach((conflictRuleName) => {
if (isConflict(conflictRuleName, rules) || isConflict(conflictRuleName, jsRules)) {
conflictRules.push(conflictRuleName);
configFilePaths.forEach((configFilePath) => {
try {
const conflictRules = getConflictRules(configFilePath);
if (conflictRules.length === 0) {
// tslint:disable-next-line:no-console
console.log(`No conflict rule detected in ${configFilePath}`);
} else {
// tslint:disable-next-line:no-console
console.error(
`Conflict rule(s) detected in ${configFilePath}:\n${conflictRules
.map((conflictRule) => ` ${conflictRule}`)
.join("\n")}`,
);
process.exitCode = 1;
}
} catch (error) {
// tslint:disable-next-line:no-console
console.error(error.message);
process.exitCode = 1;
}
});

if (conflictRules.length !== 0) {
const error = new Error(`Conflict rule(s) detected in ${configFilePath}:\n${conflictRules.join("\n")}`);
error.name = "ConflictRules";
throw error;
}

// tslint:disable-next-line:no-console
console.log(`No conflict rule detected in ${configFilePath}`);
};

function isConflict(conflictRuleName: string, rules: Configuration.IConfigurationFile["rules"]) {
function getConflictRules(configFilePath: string) {
const { rules, jsRules } = Linter.loadConfigurationFromPath(configFilePath);
return Object.keys(tslintConfigPrettier.rules!).filter(
(conflictRuleName) =>
isConflict(conflictRuleName, rules) ||
isConflict(conflictRuleName, jsRules),
);
}

function isConflict(
conflictRuleName: string,
rules: Configuration.IConfigurationFile["rules"],
) {
return (
rules.has(conflictRuleName) &&
rules.get(conflictRuleName)!.ruleSeverity !== "off"
Expand Down