@sequencemedia/css-purge
Version:
A CSS tool written in Node JS as a command line app or library for the purging, burning, reducing, shortening, compressing, cleaning, trimming and formatting of duplicate, extra, excess or bloated CSS.
259 lines (204 loc) • 6.83 kB
JavaScript
import debug from 'debug'
import colors from '#default-options/colors' with { type: 'json' }
import extendedColors from '#default-options/extended-colors' with { type: 'json' }
import hslToRgb from '#utils/hsl-to-rgb'
import componentFromString from '#utils/component-from-string'
const log = debug('@sequencemedia/css-purge/process-color')
const info = debug('@sequencemedia/css-purge:info')
function getReduceColor (declaration, rule, OPTIONS, SUMMARY) {
const {
value: VALUE
} = declaration
const {
shorten_hexcolor_uppercase: SHORTEN_HEXCOLOR_UPPERCASE,
shorten_hexcolor_lowercase: SHORTEN_HEXCOLOR_LOWERCASE
} = OPTIONS
const {
stats: {
summary: collector
}
} = SUMMARY
return function reduceColor ({ value, hasChanged }, [key, colorValue]) {
let colorIndex = value.toLowerCase().indexOf(key)
while (colorIndex > -1) {
// global for multiple colors e.g. gradient
const regExp = new RegExp(key + "(?![\"\'.a-zA-Z0-9_-])", 'g') // eslint-disable-line no-useless-escape
const was = value
const now = was.replace(regExp, (capture) => {
capture = capture.trim()
return (
(capture.startsWith('(') ? '(' : '') +
(SHORTEN_HEXCOLOR_UPPERCASE ? colorValue.toUpperCase() : SHORTEN_HEXCOLOR_LOWERCASE ? colorValue.toLowerCase() : colorValue) +
(capture.endsWith(',') ? ',' : capture.endsWith(')') ? ')' : '')
)
}).trim()
value = now
colorIndex = value.toLowerCase().indexOf(regExp, colorIndex)
if (was !== now) {
collector.noNamedColorsShortened += 1
const {
selectors = []
} = rule
log(selectors) // .join(', ').trim())
}
}
return {
hasChanged: hasChanged || value !== VALUE,
value
}
}
}
function processRgbColor (value, declaration, rule, OPTIONS, SUMMARY) {
// rgb to hex
const rgb = /(rgb)[(]\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*(?:,\s*([\d.]+)\s*)?[)]/g.exec(value)
if (rgb) {
const {
shorten_hexcolor_uppercase: SHORTEN_HEXCOLOR_UPPERCASE,
shorten_hexcolor_lowercase: SHORTEN_HEXCOLOR_LOWERCASE
} = OPTIONS
const {
stats: {
summary: collector = {}
}
} = SUMMARY
const cr = componentFromString(rgb[2], 255)
const cg = componentFromString(rgb[3], 255)
const cb = componentFromString(rgb[4], 255)
value = '#' + ((1 << 24) + (cr << 16) + (cg << 8) + cb).toString(16).slice(1)
value = SHORTEN_HEXCOLOR_UPPERCASE ? value.toUpperCase() : SHORTEN_HEXCOLOR_LOWERCASE ? value.toLowerCase() : value
collector.noRGBColorsShortened += 1
const {
selectors = []
} = rule
log(selectors) // .join(', ').trim())
}
return value
}
function processHslColor (value, declaration, rule, OPTIONS, SUMMARY) {
// hsl to hex
const hsl = /(hsl)[(]\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*(?:,\s*([\d.]+)\s*)?[)]$/.exec(value)
if (hsl) {
const {
shorten_hexcolor_uppercase: SHORTEN_HEXCOLOR_UPPERCASE,
shorten_hexcolor_lowercase: SHORTEN_HEXCOLOR_LOWERCASE
} = OPTIONS
const {
stats: {
summary: collector = {}
}
} = SUMMARY
const ch = componentFromString(hsl[2], 360)
const cs = componentFromString(hsl[3], 100)
const cl = componentFromString(hsl[4], 100)
const [
cr,
cg,
cb
] = hslToRgb(ch / 360, cs / 100, cl / 100)
value = '#' + ((1 << 24) + (cr << 16) + (cg << 8) + cb).toString(16).slice(1)
value = SHORTEN_HEXCOLOR_UPPERCASE ? value.toUpperCase() : SHORTEN_HEXCOLOR_LOWERCASE ? value.toLowerCase() : value
collector.noHSLColorsShortened += 1
const {
selectors = []
} = rule
log(selectors) // .join(', ').trim())
}
return value
}
function processHexColor (value, declaration, rule, OPTIONS, SUMMARY) {
// hex
const hex = /#(.)\1\1\1\1\1/.exec(value)
if (hex) { // #aaaaaa
const {
shorten_hexcolor_uppercase: SHORTEN_HEXCOLOR_UPPERCASE,
shorten_hexcolor_lowercase: SHORTEN_HEXCOLOR_LOWERCASE
} = OPTIONS
const {
stats: {
summary: collector = {}
}
} = SUMMARY
value = value.replace(hex[0], hex[0].substring(0, 4)) // #aaa
value = SHORTEN_HEXCOLOR_UPPERCASE ? value.toUpperCase() : SHORTEN_HEXCOLOR_LOWERCASE ? value.toLowerCase() : value
collector.noHexColorsShortened += 1
const {
selectors = []
} = rule
log(selectors) // .join(', ').trim())
}
return value
}
function processHexColorPairs (value, declaration, rule, OPTIONS, SUMMARY) {
// hex pairs
const hexPairs = /(#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2}))/.exec(value)
if (hexPairs) {
if (
hexPairs[2][0] === hexPairs[2][1] &&
hexPairs[3][0] === hexPairs[3][1] &&
hexPairs[4][0] === hexPairs[4][1]
) {
const {
shorten_hexcolor_uppercase: SHORTEN_HEXCOLOR_UPPERCASE,
shorten_hexcolor_lowercase: SHORTEN_HEXCOLOR_LOWERCASE
} = OPTIONS
const {
stats: {
summary: collector = {}
}
} = SUMMARY
value = value.replace(hexPairs[0], '#' + hexPairs[2][0] + hexPairs[3][0] + hexPairs[4][0]) // #aaa
value = SHORTEN_HEXCOLOR_UPPERCASE ? value.toUpperCase() : SHORTEN_HEXCOLOR_LOWERCASE ? value.toLowerCase() : value
collector.noHexColorsShortened += 1
const {
selectors = []
} = rule
log(selectors) // .join(', ').trim())
}
}
return value
}
log('`css-purge` is awake')
export default function processColor (value, declaration, rule, OPTIONS, SUMMARY) {
info('Process color')
const {
shorten: SHORTEN,
shorten_hexcolor_extended: SHORTEN_HEXCOLOR_EXTENDED,
shorten_hexcolor: SHORTEN_HEXCOLOR
} = OPTIONS
if (value) {
let hasChanged = false
if (SHORTEN || SHORTEN_HEXCOLOR_EXTENDED) {
({
hasChanged,
value
} = Object
.entries(extendedColors)
.reduce(getReduceColor(declaration, rule, OPTIONS, SUMMARY), {
hasChanged,
value
}))
}
if (SHORTEN || SHORTEN_HEXCOLOR) {
({
hasChanged,
value
} = Object
.entries(colors)
.reduce(getReduceColor(declaration, rule, OPTIONS, SUMMARY), {
value,
hasChanged
}))
}
if (!hasChanged) {
value = processRgbColor(value, declaration, rule, OPTIONS, SUMMARY)
value = processHslColor(value, declaration, rule, OPTIONS, SUMMARY)
value = processHexColor(value, declaration, rule, OPTIONS, SUMMARY)
value = processHexColorPairs(value, declaration, rule, OPTIONS, SUMMARY)
const {
selectors = []
} = rule
log(selectors) // .join(', ').trim())
}
}
return value
}