|
export default function collapseDuplicateDeclarations() { |
|
return (root) => { |
|
root.walkRules((node) => { |
|
let seen = new Map() |
|
let droppable = new Set([]) |
|
let byProperty = new Map() |
|
|
|
node.walkDecls((decl) => { |
|
|
|
|
|
|
|
|
|
if (decl.parent !== node) { |
|
return |
|
} |
|
|
|
if (seen.has(decl.prop)) { |
|
|
|
if (seen.get(decl.prop).value === decl.value) { |
|
|
|
droppable.add(seen.get(decl.prop)) |
|
|
|
|
|
|
|
|
|
seen.set(decl.prop, decl) |
|
return |
|
} |
|
|
|
|
|
|
|
if (!byProperty.has(decl.prop)) { |
|
byProperty.set(decl.prop, new Set()) |
|
} |
|
|
|
byProperty.get(decl.prop).add(seen.get(decl.prop)) |
|
byProperty.get(decl.prop).add(decl) |
|
} |
|
|
|
seen.set(decl.prop, decl) |
|
}) |
|
|
|
|
|
|
|
for (let decl of droppable) { |
|
decl.remove() |
|
} |
|
|
|
|
|
|
|
for (let declarations of byProperty.values()) { |
|
let byUnit = new Map() |
|
|
|
for (let decl of declarations) { |
|
let unit = resolveUnit(decl.value) |
|
if (unit === null) { |
|
|
|
|
|
|
|
continue |
|
} |
|
|
|
if (!byUnit.has(unit)) { |
|
byUnit.set(unit, new Set()) |
|
} |
|
|
|
byUnit.get(unit).add(decl) |
|
} |
|
|
|
for (let declarations of byUnit.values()) { |
|
|
|
let removableDeclarations = Array.from(declarations).slice(0, -1) |
|
|
|
for (let decl of removableDeclarations) { |
|
decl.remove() |
|
} |
|
} |
|
} |
|
}) |
|
} |
|
} |
|
|
|
let UNITLESS_NUMBER = Symbol('unitless-number') |
|
|
|
function resolveUnit(input) { |
|
let result = /^-?\d*.?\d+([\w%]+)?$/g.exec(input) |
|
|
|
if (result) { |
|
return result[1] ?? UNITLESS_NUMBER |
|
} |
|
|
|
return null |
|
} |
|
|