@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.
234 lines (202 loc) • 10.6 kB
JavaScript
import debug from 'debug'
import hasPropertyBorderRadius from '#utils/declarations/has-property-border-radius'
import hasPropertyBorderTopLeftRadius from '#utils/declarations/has-property-border-top-left-radius'
import hasPropertyBorderTopRightRadius from '#utils/declarations/has-property-border-top-right-radius'
import hasPropertyBorderBottomLeftRadius from '#utils/declarations/has-property-border-bottom-left-radius'
import hasPropertyBorderBottomRightRadius from '#utils/declarations/has-property-border-bottom-right-radius'
import hasInherit from '#utils/has-inherit'
import hasImportant from '#utils/has-important'
import toProperty from '#utils/to-property'
import toValue from '#utils/to-value'
import getValueOfSquareProp from '#utils/get-value-of-square-prop'
/**
* Preserve order
*/
const DEFAULT_BORDER_RADIUS_PROPERTIES = [
'border-top-left-radius',
'border-top-right-radius',
'border-bottom-left-radius',
'border-bottom-right-radius'
]
function hasBorderRadius (properties) {
return properties.includes('border-radius') || (
properties.includes('border-top-left-radius') &&
properties.includes('border-top-right-radius') &&
properties.includes('border-bottom-left-radius') &&
properties.includes('border-bottom-right-radius')
)
}
const log = debug('@sequencemedia/css-purge/process-border-radius')
export default function processBorderRadius (rule, OPTIONS, SUMMARY) {
const {
declarations = []
} = rule
if (declarations.length) {
const borderRadius = declarations.filter(hasPropertyBorderRadius)
if (!borderRadius.some(hasInherit)) {
let borderRadiusProperties = borderRadius.map(toProperty)
if (hasBorderRadius(borderRadiusProperties)) {
const {
selectors = []
} = rule
log(selectors) // .join(', ').trim())
let borderRadiusValues = borderRadius.map(toValue)
const borderTopLeftRadiusIndex = borderRadiusProperties.indexOf('border-top-left-radius')
const borderTopRightRadiusIndex = borderRadiusProperties.indexOf('border-top-right-radius')
const borderBottomLeftRadiusIndex = borderRadiusProperties.indexOf('border-bottom-left-radius')
const borderBottomRightRadiusIndex = borderRadiusProperties.indexOf('border-bottom-right-radius')
const borderTopLeftRadiusValue = borderRadiusValues[borderTopLeftRadiusIndex] ?? ''
const borderTopRightRadiusValue = borderRadiusValues[borderTopRightRadiusIndex] ?? ''
const borderBottomLeftRadiusValue = borderRadiusValues[borderBottomLeftRadiusIndex] ?? ''
const borderBottomRightRadiusValue = borderRadiusValues[borderBottomRightRadiusIndex] ?? ''
const BORDER_RADIUS_VALUES = [
borderTopLeftRadiusValue,
borderTopRightRadiusValue,
borderBottomLeftRadiusValue,
borderBottomRightRadiusValue
]
// existing border radius check
if (borderRadiusProperties.includes('border-radius')) {
const borderRadiusPropValueIndex = borderRadiusProperties.indexOf('border-radius')
const borderRadiusPropValue = borderRadiusValues[borderRadiusPropValueIndex]
if (borderTopLeftRadiusIndex > borderRadiusPropValueIndex) {
BORDER_RADIUS_VALUES[0] = borderTopLeftRadiusValue
} else {
const propValue = getValueOfSquareProp(borderRadiusPropValue, 'top')
if (propValue) BORDER_RADIUS_VALUES[0] = propValue
}
if (borderRadiusProperties.indexOf('border-top-right-radius') > borderRadiusPropValueIndex) {
BORDER_RADIUS_VALUES[1] = borderTopRightRadiusValue
} else {
const propValue = getValueOfSquareProp(borderRadiusPropValue, 'right')
if (propValue) BORDER_RADIUS_VALUES[1] = propValue
}
if (borderBottomLeftRadiusIndex > borderRadiusPropValueIndex) {
BORDER_RADIUS_VALUES[2] = borderBottomLeftRadiusValue
} else {
const propValue = getValueOfSquareProp(borderRadiusPropValue, 'bottom')
if (propValue) BORDER_RADIUS_VALUES[2] = propValue
}
if (borderBottomRightRadiusIndex > borderRadiusPropValueIndex) {
BORDER_RADIUS_VALUES[3] = borderBottomRightRadiusValue
} else {
const propValue = getValueOfSquareProp(borderRadiusPropValue, 'left')
if (propValue) BORDER_RADIUS_VALUES[3] = propValue
}
}
borderRadiusProperties = [...DEFAULT_BORDER_RADIUS_PROPERTIES]
borderRadiusValues = BORDER_RADIUS_VALUES
// check for requirements
if (
borderRadiusProperties.includes('border-top-left-radius') &&
borderRadiusProperties.includes('border-top-right-radius') &&
borderRadiusProperties.includes('border-bottom-left-radius') &&
borderRadiusProperties.includes('border-bottom-right-radius')
) {
const borderTopLeftRadiusIndex = borderRadiusProperties.indexOf('border-top-left-radius')
const borderTopRightRadiusIndex = borderRadiusProperties.indexOf('border-top-right-radius')
const borderBottomLeftRadiusIndex = borderRadiusProperties.indexOf('border-bottom-left-radius')
const borderBottomRightRadiusIndex = borderRadiusProperties.indexOf('border-bottom-right-radius')
const borderTopLeftRadiusValue = borderRadiusValues[borderTopLeftRadiusIndex] ?? ''
const borderTopRightRadiusValue = borderRadiusValues[borderTopRightRadiusIndex] ?? ''
const borderBottomLeftRadiusValue = borderRadiusValues[borderBottomLeftRadiusIndex] ?? ''
const borderBottomRightRadiusValue = borderRadiusValues[borderBottomRightRadiusIndex] ?? ''
// 1 value
if (
borderTopLeftRadiusValue === borderBottomLeftRadiusValue &&
borderTopLeftRadiusValue === borderTopRightRadiusValue &&
borderTopLeftRadiusValue === borderBottomRightRadiusValue
) {
borderRadiusProperties = ['border-radius']
borderRadiusValues = [borderTopLeftRadiusValue]
} else {
// 2 values
if (
borderTopLeftRadiusValue === borderBottomLeftRadiusValue &&
borderBottomRightRadiusValue === borderTopRightRadiusValue
) {
// remove Top Left + Bottom Left values
borderRadiusValues.splice(borderTopLeftRadiusIndex, 1)
borderRadiusValues.splice(borderBottomLeftRadiusIndex - 1, 1)
// use Top Left as Top Bottom value
borderRadiusValues.splice(0, 0, borderTopLeftRadiusValue)
// remove Top Left + Bottom Left properties
borderRadiusProperties.splice(borderTopLeftRadiusIndex, 1)
borderRadiusProperties.splice(borderBottomLeftRadiusIndex - 1, 1)
// add TopBottom property - for alignment sake
borderRadiusProperties.splice(0, 0, 'border-radius-top-bottom')
// remove Top Right + Bottom Right values
borderRadiusValues.splice(borderTopRightRadiusIndex, 1)
borderRadiusValues.splice(borderBottomRightRadiusIndex - 2, 1)
// use Top Right as Right Left value
borderRadiusValues.splice(1, 0, borderTopRightRadiusValue)
// remove Top Right + Bottom Right properties
borderRadiusProperties.splice(borderTopRightRadiusIndex, 1)
borderRadiusProperties.splice(borderBottomRightRadiusIndex - 2, 1)
// add RightLeft property - for alignment sake
borderRadiusProperties.splice(1, 0, 'border-radius-right-left')
} else {
// 3 values
if (
borderBottomRightRadiusValue === borderTopRightRadiusValue
) {
// remove Top Right + Bottom Right values
borderRadiusValues.splice(borderTopRightRadiusIndex, 1)
borderRadiusValues.splice(borderBottomRightRadiusIndex - 1, 1)
// use TopRight as TopBottom value
borderRadiusValues.splice(1, 0, borderTopRightRadiusValue)
// remove Top Right + Bottom Right properties
borderRadiusProperties.splice(borderTopRightRadiusIndex, 1)
borderRadiusProperties.splice(borderBottomRightRadiusIndex - 1, 1)
// add LeftRight property - for alignment sake
borderRadiusProperties.splice(1, 0, 'border-radius-left-right')
}
}
}
}
// check for !important
if (borderRadiusValues.some(hasImportant)) {
borderRadiusValues = borderRadiusValues.map((borderRadius) => borderRadius.replace(/(!important)/g, ''))
borderRadiusValues[borderRadiusValues.length - 1] += ' !important'
}
// add declaration
if (declarations.some(hasPropertyBorderRadius)) {
const i = declarations.findIndex(hasPropertyBorderRadius)
declarations.splice(i, 0, {
type: 'declaration',
property: 'border-radius',
value: borderRadiusValues.filter(Boolean).join(' ') // remove empty values
})
SUMMARY.stats.summary.noBorderRadiusShortened += 1
}
// remove originals
if (declarations.some(hasPropertyBorderTopLeftRadius)) {
const i = declarations.findIndex(hasPropertyBorderTopLeftRadius)
declarations.splice(i, 1)
}
if (declarations.some(hasPropertyBorderTopRightRadius)) {
const i = declarations.findIndex(hasPropertyBorderTopRightRadius)
declarations.splice(i, 1)
}
if (declarations.some(hasPropertyBorderBottomLeftRadius)) {
const i = declarations.findIndex(hasPropertyBorderBottomLeftRadius)
declarations.splice(i, 1)
}
if (declarations.some(hasPropertyBorderBottomRightRadius)) {
const i = declarations.findIndex(hasPropertyBorderBottomRightRadius)
declarations.splice(i, 1)
}
// remove existing borderRadiuss
const properties = declarations.filter(toProperty).map(toProperty)
const j = properties.filter((property) => property === 'border-radius').length
if (j > 1) {
for (let i = 1; i < j; ++i) {
const was = properties.indexOf('border-radius')
const now = properties.indexOf('border-radius', (was + 1))
declarations.splice(now, 1)
}
}
} // end of inherit check
}
}
}