const isPlainObject = require('lodash.isplainobject') | |
const parser = require('postcss-selector-parser') | |
const parseSelector = parser() | |
module.exports = { | |
isUsableColor(color, values) { | |
return isPlainObject(values) && color !== 'gray' && values[600] | |
}, | |
/** | |
* @param {string} selector | |
*/ | |
commonTrailingPseudos(selector) { | |
let ast = parseSelector.astSync(selector) | |
/** @type {import('postcss-selector-parser').Pseudo[][]} */ | |
let matrix = [] | |
// Put the pseudo elements in reverse order in a sparse, column-major 2D array | |
for (let [i, sel] of ast.nodes.entries()) { | |
for (const [j, child] of [...sel.nodes].reverse().entries()) { | |
// We only care about pseudo elements | |
if (child.type !== 'pseudo' || !child.value.startsWith('::')) { | |
break | |
} | |
matrix[j] = matrix[j] || [] | |
matrix[j][i] = child | |
} | |
} | |
let trailingPseudos = parser.selector() | |
// At this point the pseudo elements are in a column-major 2D array | |
// This means each row contains one "column" of pseudo elements from each selector | |
// We can compare all the pseudo elements in a row to see if they are the same | |
for (const pseudos of matrix) { | |
// It's a sparse 2D array so there are going to be holes in the rows | |
// We skip those | |
if (!pseudos) { | |
continue | |
} | |
let values = new Set([...pseudos.map((p) => p.value)]) | |
// The pseudo elements are not the same | |
if (values.size > 1) { | |
break | |
} | |
pseudos.forEach((pseudo) => pseudo.remove()) | |
trailingPseudos.prepend(pseudos[0]) | |
} | |
if (trailingPseudos.nodes.length) { | |
return [trailingPseudos.toString(), ast.toString()] | |
} | |
return [null, selector] | |
}, | |
} | |