UNPKG

postcss-merge-longhand

Version:

Merge longhand properties into shorthand with PostCSS.

82 lines (77 loc) • 2.37 kB
import cssnanoUtils from 'cssnano-utils'; import stylehacks from 'stylehacks'; import { normalizeValue } from './minifyShorthandValues.js'; const { asciiLowerCase } = cssnanoUtils; /** * Shorthand properties whose redundant axes, sides, or default components can be * algebraically folded in-place without inter-declaration data dependencies. */ export const foldableShorthands = new Set([ 'aspect-ratio', 'border-spacing', 'gap', 'inset', 'overflow', 'overscroll-behavior', 'place-content', 'place-items', 'place-self', 'scroll-margin', 'scroll-padding', 'transition', '-webkit-transition', ]); /** * In-place peephole rewrite: folds identity components of a shorthand declaration * using a memoization table to cache pure value transformations across the AST. * * @param {import('postcss').Declaration} decl * @param {Map<string, string | null>} [memoTable] * @param {string} [property] - the lowercased property name, when known * @return {void} */ export function foldShorthandDeclaration( decl, memoTable, property = asciiLowerCase(decl.prop) ) { if (!foldableShorthands.has(property) || stylehacks.detect(decl)) return; const sourceValue = decl.raws.value?.value === decl.value ? (decl.raws.value.raw ?? decl.value) : decl.value; const memoKey = `${property}\0${sourceValue}`; let canonicalValue; if (memoTable) { canonicalValue = memoTable.get(memoKey); if (canonicalValue === undefined && !memoTable.has(memoKey)) { canonicalValue = normalizeValue(property, sourceValue); memoTable.set(memoKey, canonicalValue); } } else { canonicalValue = normalizeValue(property, sourceValue); } if ( canonicalValue === undefined || canonicalValue === null || canonicalValue === decl.value ) { return; } const oldValue = decl.value; decl.value = canonicalValue; if (decl.raws.value?.value === oldValue) { decl.raws.value = { raw: canonicalValue, value: canonicalValue }; } } /** * Full AST traversal fallback for standalone shorthand identity canonicalization. * * @param {import('postcss').Root} root * @return {void} */ export default function minifyShorthandIdentities(root) { /** @type {Map<string, string | null>} */ const memoTable = new Map(); root.walkDecls((decl) => foldShorthandDeclaration(decl, memoTable)); }