UNPKG

postcss-merge-longhand

Version:

Merge longhand properties into shorthand with PostCSS.

78 lines (60 loc) 2.06 kB
import { list } from 'postcss'; import { sides } from './spec.js'; import { isUnresolved } from './unresolved.js'; /* CSS user agents ignore margin and padding declarations that violate the * property's grammar: margin rejects negative values and auto, * padding rejects both and bounds values at zero. */ /* Parse CSS dimension format: a number with optional exponent and unit * (percentage or keyword). Only zero can omit a unit. */ const dimensionRegex = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)(%|[a-z]+)?$/i; /* Padding forbids auto and negative values; margin allows both. */ const grammars = new Map([ ['margin', { auto: true, negative: true }], ['padding', { auto: false, negative: false }], ]); /** * @param {string} token * @param {{auto: boolean, negative: boolean}} grammar * @return {boolean} */ function specifiesSide(token, grammar) { if (isUnresolved(token)) { return true; } const lowered = token.toLowerCase(); if (lowered === 'auto') { return grammar.auto; } const match = dimensionRegex.exec(lowered); if (!match) { return false; } const [, number, unit] = match; /* Only zero may go without a unit; `margin: 5` is no length. */ if (unit === undefined && Number(number) !== 0) { return false; } return grammar.negative || !number.startsWith('-'); } /** * @param {string} prop lower-cased, a property of one of the two families * @param {string} value * @return {boolean} whether the browser keeps the declaration */ function browserKeeps(prop, value) { const [family] = prop.split('-'); const grammar = grammars.get(family); if (grammar === undefined) { return false; } const tokens = list.space(value); /* The shorthand spreads one to four values across the sides; a property * naming a side takes exactly the one. */ const most = prop === family ? sides.length : 1; if (tokens.length === 0 || tokens.length > most) { return false; } return tokens.every((token) => specifiesSide(token, grammar)); } export { browserKeeps };