Skip to content

Commit 6f72918

Browse files
committed
feat(list-different): add list-different functionality
1 parent 089bb14 commit 6f72918

15 files changed

+146
-12
lines changed

__tests__/complex.scss.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const someStyles: string;
2+
export const nestedClass: string;
3+
export const nestedAnother: string;

__tests__/core/generate.test.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ describe("generate", () => {
1414

1515
await generate(pattern, {
1616
watch: false,
17-
exportType: "named"
17+
exportType: "named",
18+
listDifferent: false
1819
});
1920

2021
// Three files should match but one is empty
21-
expect(fs.writeFileSync).toBeCalledTimes(2);
22+
expect(fs.writeFileSync).toBeCalledTimes(3);
2223
});
2324
});

__tests__/core/list-different.test.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { listDifferent } from "../../lib/core";
2+
3+
describe("writeFile", () => {
4+
let exit: jest.SpyInstance;
5+
6+
beforeEach(() => {
7+
console.log = jest.fn();
8+
exit = jest.spyOn(process, "exit").mockImplementation();
9+
});
10+
11+
afterEach(() => {
12+
exit.mockRestore();
13+
});
14+
15+
test("logs invalid type definitions and exits with 1", async () => {
16+
const pattern = `${__dirname}/../**/*.scss`;
17+
18+
await listDifferent(pattern, {
19+
watch: false,
20+
exportType: "named",
21+
listDifferent: true
22+
});
23+
24+
expect(exit).toHaveBeenCalledWith(1);
25+
expect(console.log).toBeCalledWith(
26+
expect.stringContaining(`[INVALID TYPES] Check type definitions for`)
27+
);
28+
expect(console.log).toBeCalledWith(expect.stringContaining(`invalid.scss`));
29+
});
30+
31+
test("logs nothing and does not exit if all files are valid", async () => {
32+
const pattern = `${__dirname}/../**/style.scss`;
33+
34+
await listDifferent(pattern, {
35+
watch: false,
36+
exportType: "named",
37+
listDifferent: true
38+
});
39+
40+
expect(exit).not.toHaveBeenCalled();
41+
expect(console.log).not.toHaveBeenCalled();
42+
});
43+
});

__tests__/core/write-file.test.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ describe("writeFile", () => {
1616

1717
await writeFile(testFile, {
1818
watch: false,
19-
exportType: "named"
19+
exportType: "named",
20+
listDifferent: false
2021
});
2122

2223
expect(fs.writeFileSync).toBeCalledWith(
@@ -34,7 +35,8 @@ describe("writeFile", () => {
3435

3536
await writeFile(testFile, {
3637
watch: false,
37-
exportType: "named"
38+
exportType: "named",
39+
listDifferent: false
3840
});
3941

4042
expect(fs.writeFileSync).not.toBeCalled();

__tests__/invalid.scss

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.random-class {
2+
color: pink;
3+
}

__tests__/invalid.scss.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const nope: string;

__tests__/main.test.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ describe("main", () => {
1414

1515
await main(pattern, {
1616
watch: false,
17-
exportType: "named"
17+
exportType: "named",
18+
listDifferent: false
1819
});
1920

2021
// Three files should match but one is empty
21-
expect(fs.writeFileSync).toBeCalledTimes(2);
22+
expect(fs.writeFileSync).toBeCalledTimes(3);
2223

2324
expect(fs.writeFileSync).toBeCalledWith(
2425
`${__dirname}/complex.scss.d.ts`,

__tests__/style.scss.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const someClass: string;

jest.config.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
module.exports = {
22
preset: "ts-jest",
33
testEnvironment: "node",
4-
testPathIgnorePatterns: ["<rootDir>/dist/", "<rootDir>/node_modules/"]
4+
testPathIgnorePatterns: [
5+
"<rootDir>/dist/",
6+
"<rootDir>/node_modules/",
7+
"(.*).d.ts"
8+
]
59
};

lib/cli.ts

+7
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ const { _: patterns, ...rest } = yargs
5555
describe:
5656
"Watch for added or changed files and (re-)generate the type definitions."
5757
})
58+
.option("listDifferent", {
59+
boolean: true,
60+
default: false,
61+
alias: "l",
62+
describe:
63+
"List any type definitions that are different than those that would be generated."
64+
})
5865
.option("includePaths", {
5966
array: true,
6067
string: true,

lib/core/alerts.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import chalk from "chalk";
22

3-
const error = (message: string) => console.log(chalk.red(`[ERROR] ${message}`));
4-
const warn = (message: string) => console.log(chalk.yellowBright(`${message}`));
5-
const notice = (message: string) => console.log(chalk.gray(`${message}`));
6-
const info = (message: string) => console.log(chalk.blueBright(`${message}`));
3+
const error = (message: string) => console.log(chalk.red(message));
4+
const warn = (message: string) => console.log(chalk.yellowBright(message));
5+
const notice = (message: string) => console.log(chalk.gray(message));
6+
const info = (message: string) => console.log(chalk.blueBright(message));
77
const success = (message: string) => console.log(chalk.green(message));
88

99
export const alerts = { error, warn, notice, info, success };

lib/core/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export { alerts } from "./alerts";
22
export { generate } from "./generate";
3+
export { listDifferent } from "./list-different";
34
export { MainOptions } from "./types";
45
export { watch } from "./watch";
56
export { writeFile } from "./write-file";

lib/core/list-different.ts

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import glob from "glob";
2+
import fs from "fs";
3+
4+
import { alerts } from "./alerts";
5+
import { MainOptions } from "./types";
6+
import { fileToClassNames } from "../sass";
7+
import {
8+
classNamesToTypeDefinitions,
9+
getTypeDefinitionPath
10+
} from "../typescript";
11+
12+
export const listDifferent = async (
13+
pattern: string,
14+
options: MainOptions
15+
): Promise<void> => {
16+
// Find all the files that match the provied pattern.
17+
const files = glob.sync(pattern);
18+
19+
if (!files || !files.length) {
20+
alerts.notice("No files found.");
21+
return;
22+
}
23+
24+
// Wait for all the files to be checked.
25+
await Promise.all(files.map(file => checkFile(file, options))).then(
26+
results => {
27+
results.includes(false) && process.exit(1);
28+
}
29+
);
30+
};
31+
32+
export const checkFile = (
33+
file: string,
34+
options: MainOptions
35+
): Promise<boolean> => {
36+
return new Promise(resolve =>
37+
fileToClassNames(file, options).then(classNames => {
38+
const typeDefinition = classNamesToTypeDefinitions(
39+
classNames,
40+
options.exportType
41+
);
42+
43+
if (!typeDefinition) {
44+
// Assume if no type defs are necessary it's fine
45+
resolve(true);
46+
return;
47+
}
48+
49+
const path = getTypeDefinitionPath(file);
50+
51+
const content = fs.readFileSync(path, { encoding: "UTF8" });
52+
53+
if (content === typeDefinition) {
54+
resolve(true);
55+
} else {
56+
alerts.error(`[INVALID TYPES] Check type definitions for ${file}`);
57+
resolve(false);
58+
}
59+
})
60+
);
61+
};

lib/core/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ import { ExportType } from "../typescript";
33

44
export interface MainOptions extends Options {
55
exportType: ExportType;
6+
listDifferent: boolean;
67
watch: boolean;
78
}

lib/main.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from "fs";
22
import path from "path";
33

4-
import { watch, MainOptions, generate } from "./core";
4+
import { watch, MainOptions, generate, listDifferent } from "./core";
55

66
export const main = async (pattern: string, options: MainOptions) => {
77
// When the provided pattern is a directory construct the proper glob to find
@@ -19,6 +19,11 @@ export const main = async (pattern: string, options: MainOptions) => {
1919
pattern = path.resolve(pattern, "**/*.scss");
2020
}
2121

22+
if (options.listDifferent) {
23+
listDifferent(pattern, options);
24+
return;
25+
}
26+
2227
if (options.watch) {
2328
watch(pattern, options);
2429
} else {

0 commit comments

Comments
 (0)