-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
removeUnusedvars.ts
85 lines (69 loc) · 1.99 KB
/
removeUnusedvars.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import postcss from "postcss";
interface UseRecord {
declarations: Set<postcss.Declaration>;
dependencies: Set<string>;
uses: number;
}
const varRegex = /var\(\s*(?<name>--[^ ,);]+)/g;
/**
* Adapted from https://github.com/tomasklaen/postcss-prune-var/blob/57ad5041806b73479d0c558e0b1a918803cb7cbc/index.js
*/
export function removeUnusedCssVars(css: string) {
const root = postcss.parse(css);
const records = new Map<string, UseRecord>();
const getRecord = (variable: string): UseRecord => {
let record = records.get(variable);
if (!record) {
record = { declarations: new Set(), dependencies: new Set(), uses: 0 };
records.set(variable, record);
}
return record;
};
const registerUse = (variable: string, ignoreList = new Set<string>()) => {
const record = getRecord(variable);
record.uses++;
ignoreList.add(variable);
for (const dependency of record.dependencies) {
if (!ignoreList.has(dependency))
registerUse(dependency, ignoreList);
}
};
const registerDependency = (variable: string, dependency: string) => {
const record = getRecord(variable);
record.dependencies.add(dependency);
};
// Detect variable uses
root.walkDecls((decl) => {
const parent = decl.parent;
if (!parent)
return;
if (parent.type === "rule" && (parent as postcss.Rule).selector === ":root")
return;
const isVar = decl.prop.startsWith("--");
// Initiate record
if (isVar)
getRecord(decl.prop).declarations.add(decl);
if (!decl.value.includes("var("))
return;
for (const match of decl.value.matchAll(varRegex)) {
const variable = match.groups?.name.trim();
if (!variable)
continue;
if (isVar)
registerDependency(decl.prop, variable);
else
registerUse(variable);
}
});
// Remove unused variables
for (const { declarations, uses } of records.values()) {
if (uses === 0) {
for (const decl of declarations) {
if (decl.parent?.nodes.length === 1)
decl.parent?.remove();
else decl.remove();
}
}
}
return root.toString();
}