Created
February 25, 2022 09:46
-
-
Save msandrini/34c1453471e53d41e33a57ab6f2ec57a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Taken from: https://github.com/marceloucker/postcss-prefixer | |
* and adapted to receive a third parameter in options | |
* to restrict plugin action by import name match (restrictByName) | |
* Note: it uses the package css-selector-tokenizer | |
* | |
* Specified in postcss.config.cjs | |
*/ | |
const postcss = require('postcss') | |
const Tokenizer = require('css-selector-tokenizer') | |
function itMatchesOne(arr, term) { | |
return arr.some((i) => term.search(i) >= 0) | |
} | |
function parseAttrSelector(node) { | |
const { content } = node | |
const regex = | |
/(^class|^id)([*^?~|$=]*)+(?:("\s*)([^"\\]*?(?:\\.[^"\\]*)*?)(\s*")|('\s*)([^'\\]*?(?:\\.[^'\\]*)*?)(\s*'))/i | |
const [type, operator, head, classes, foot] = content.split(regex).filter((part) => part) | |
return { | |
type, | |
operator, | |
head, | |
classes: classes ? classes.split(' ').map((c) => c.replace(/"|'/g, '')) : [], | |
foot | |
} | |
} | |
function attrStringify({ type, operator, head, classes, foot }) { | |
return `${type}${operator || ''}${head || ''}${classes.join(' ')}${foot || ''}` | |
} | |
const prefixNode = (node, prefix) => { | |
if (['class', 'id'].includes(node.type)) { | |
return Object.assign({}, node, { name: `${prefix}${node.name}` }) | |
} | |
if (['attribute'].includes(node.type) && node.content) { | |
const { type, operator, head, classes, foot } = parseAttrSelector(node) | |
if (!['class', 'id'].includes(type)) return node | |
return Object.assign({}, node, { | |
content: attrStringify({ | |
type, | |
operator, | |
head, | |
classes: classes.map((cls) => `${prefix}${cls}`), | |
foot | |
}) | |
}) | |
} | |
return node | |
} | |
const iterateSelectorNodes = (selector, options) => | |
Object.assign({}, selector, { | |
nodes: selector.nodes.map((node) => { | |
if (['selector', 'nested-pseudo-class'].includes(node.type)) { | |
return iterateSelectorNodes(node, options) | |
} | |
if (itMatchesOne(options.ignore, Tokenizer.stringify(node))) return node | |
return prefixNode(node, options.prefix) | |
}) | |
}) | |
module.exports = (options) => { | |
return { | |
postcssPlugin: 'postcss-prefixer', | |
Once(root, { result }) { | |
const { prefix, ignore } = Object.assign( | |
{}, | |
{ | |
prefix: '', | |
ignore: [] | |
}, | |
options | |
) | |
if (typeof prefix !== 'string') { | |
throw new Error('@postcss-prefix: prefix option should be of type string.') | |
} | |
if (!Array.isArray(ignore)) { | |
throw new Error('@postcss-prefix: ignore options should be an Array.') | |
} | |
if (!prefix.length) return | |
if (root.source.input.file.includes(options.restrictByName)) { | |
root.walkRules(rule => { | |
const parsed = Tokenizer.parse(rule.selector) | |
const selector = iterateSelectorNodes(parsed, { prefix, ignore }) | |
/* eslint no-param-reassign: "off" */ | |
rule.selector = Tokenizer.stringify(selector) | |
}) | |
} | |
} | |
} | |
} | |
module.exports.postcss = true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment