Skip to content

Commit 975f6a7

Browse files
committed
refactor: change type resolution
1 parent 396dcc5 commit 975f6a7

File tree

6 files changed

+83
-14
lines changed

6 files changed

+83
-14
lines changed

src/extract.ts

+26-10
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,38 @@
1+
import type { CSSJSObj, GetParseCaseFunction } from "./type";
2+
import { collectionToObj } from "./util";
3+
4+
const importRe = new RegExp(/^(@import)/);
5+
const keySeparatorRe = new RegExp(/(?=[\s.:[\]><+,()])/g);
6+
17
export const extractClassNameKeys = (
2-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3-
obj: Record<string, any>
8+
obj: CSSJSObj,
9+
toParseCase: GetParseCaseFunction,
10+
parentKey?: string
411
): Map<string, boolean> => {
512
return Object.entries(obj).reduce<Map<string, boolean>>(
613
(curr, [key, value]) => {
7-
const reg = new RegExp(/^(@media)/g);
8-
if (reg.test(key)) return curr;
9-
const splittedKeys = key.split(/(?=[\s.:[\]><+,()])/g);
10-
for (const splittedKey of splittedKeys) {
11-
if (splittedKey.startsWith(".")) {
12-
curr.set(splittedKey.replace(".", "").trim(), true);
14+
if (importRe.test(key)) return curr;
15+
const splitKeys = key.split(keySeparatorRe);
16+
for (const splitKey of splitKeys) {
17+
if (parentKey === ":export" || splitKey.startsWith(".")) {
18+
if (toParseCase) {
19+
curr.set(toParseCase(splitKey.replace(".", "").trim()), true);
20+
} else {
21+
curr.set(splitKey.replace(".", "").trim(), true);
22+
}
1323
}
1424
}
1525

1626
if (typeof value === "object" && Object.keys(value).length > 0) {
17-
const map = extractClassNameKeys(value);
27+
const valueToExtract = Array.isArray(value)
28+
? collectionToObj(value)
29+
: value;
30+
const map = extractClassNameKeys(valueToExtract, toParseCase, key);
31+
1832
for (const key of map.keys()) {
19-
if (key.startsWith(".")) {
33+
if (toParseCase) {
34+
curr.set(toParseCase(key), true);
35+
} else {
2036
curr.set(key, true);
2137
}
2238
}

src/format.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export const formatClassNames = (classNameKeys: Map<string, boolean>) => {
22
let exportTypes = "";
3-
const exportStyle = "export default classNames;";
3+
const exportStyle = "export = classNames;";
44
for (const classNameKey of classNameKeys.keys()) {
55
exportTypes = `${exportTypes}\n${formatExportType(classNameKey)}`;
66
}

src/index.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { getViteConfig } from "./config";
77
import { parseCss } from "./css";
88
import { extractClassNameKeys } from "./extract";
99
import { formatClassNames } from "./format";
10-
import { getPluginOptions } from "./options";
10+
import { getParseCase, getPluginOptions } from "./options";
1111
import { isCSSFile } from "./util";
1212

1313
const factory: ts.server.PluginModuleFactory = (mod: {
@@ -60,8 +60,10 @@ const factory: ts.server.PluginModuleFactory = (mod: {
6060
log(`${e}`);
6161
}
6262
}
63+
const toParseCase = getParseCase(config);
6364
const classNameKeys = extractClassNameKeys(
64-
postcssJs.objectify(postcss.parse(css))
65+
postcssJs.objectify(postcss.parse(css)),
66+
toParseCase
6567
);
6668

6769
for (const classNameKey of classNameKeys) {

src/options.ts

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,37 @@
11
import type { ResolvedConfig } from "vite";
2-
import type { Log, Options } from "./type";
2+
import type { GetParseCaseFunction, Log, Options } from "./type";
3+
import { toCamelCase, toDashCase } from "./util";
34

45
export const getPluginOptions = (log: Log, config: any): Options => {
56
log(`config: ${JSON.stringify(config)}`);
67
return { root: config.root || "./" };
78
};
89

10+
export const getParseCase = (config: ResolvedConfig): GetParseCaseFunction => {
11+
if (
12+
!config.css ||
13+
!config.css.modules ||
14+
!config.css.modules.localsConvention
15+
) {
16+
return;
17+
}
18+
19+
const { localsConvention } = config.css.modules;
20+
21+
if (
22+
localsConvention === "camelCase" ||
23+
localsConvention === "camelCaseOnly"
24+
) {
25+
return toCamelCase;
26+
} else if (
27+
localsConvention === "dashes" ||
28+
localsConvention === "dashesOnly"
29+
) {
30+
return toDashCase;
31+
}
32+
return;
33+
};
34+
935
export const getPreprocessorOptions = (config: ResolvedConfig) => {
1036
let additionalData, includePaths, importer;
1137

src/type.ts

+7
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,10 @@ export type AdditionalData =
77
| ((source: string, filename: string) => string);
88

99
export type Log = (logText: string) => void;
10+
11+
export type CSSJSObj = Record<
12+
string,
13+
string | Record<string, string> | Record<string, Record<string, string>>[]
14+
>;
15+
16+
export type GetParseCaseFunction = ((target: string) => string) | undefined;

src/util.ts

+18
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,21 @@ export const cssLangs = `\\.(css|sass|scss)($|\\?)`;
22
export const cssLangReg = new RegExp(cssLangs);
33

44
export const isCSSFile = (request: string): boolean => cssLangReg.test(request);
5+
6+
export const toDashCase = (target: string) =>
7+
target
8+
.replace(/[-_ /~ . ][A-z0-9]/g, (v) => {
9+
return "-" + v.slice(1);
10+
})
11+
.toLowerCase();
12+
13+
export const toCamelCase = (target: string) =>
14+
target
15+
.replace(/^[A-Z]/, (m) => m.toLowerCase())
16+
.replace(/[-_ ./~ ]+([A-z0-9])/g, (m, $1) => $1.toUpperCase());
17+
18+
export const collectionToObj = <V>(collection: Record<string, V>[]) => {
19+
return collection.reduce((acc, item): Record<string, V> => {
20+
return { ...acc, ...item };
21+
}, {});
22+
};

0 commit comments

Comments
 (0)