@pandabox/postcss-plugins
Version:
- `removeUnusedCssVars` - `removeUnusedKeyframes`
78 lines (63 loc) • 2.1 kB
text/typescript
import postcss, { type TransformCallback } from 'postcss'
interface UseRecord {
uses: number
dependencies: Set<string>
declarations: Set<postcss.Declaration>
}
const varRegex = /var\(\s*(?<name>--[^ ,);]+)/g
/**
* Adapted from https://github.com/tomasklaen/postcss-prune-var/blob/57ad5041806b73479d0c558e0b1a918803cb7cbc/index.js
*/
export const removeUnusedCssVars: TransformCallback = (root) => {
const records = new Map<string, UseRecord>()
const getRecord = (variable: string): UseRecord => {
let record = records.get(variable)
if (!record) {
record = { uses: 0, dependencies: new Set(), declarations: new Set() }
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 { uses, declarations } of records.values()) {
if (uses === 0) {
for (const decl of declarations) {
if (decl.parent?.nodes?.length === 1) decl.parent?.remove()
else decl.remove()
}
}
}
}