packages/postcss-move-props-to-bg-image-query/index.js (54 lines of code) (raw):
/* eslint-disable no-param-reassign */
const postcss = require('postcss');
const merge = require('merge-options');
const {
createMatcher,
postcss: postcssUtils
} = require('svg-mixer-utils');
const { name: packageName } = require('./package.json');
const {
declsToObject,
computeCustomProps
} = require('./utils');
/**
* @typedef {Object} PluginConfig
* @property {RegExp|string|Array<RegExp|string>} match Which props (declarations) should be processed. Glob wildcard can be used, e.g. 'stroke-*'.
* @property {Function<(postcss.Declaration): { name: string, value: string }>} transform How prop name & value should be transformed to become a query string parameter.
* @property {boolean|postcss.Processor} computeCustomProps=false
*/
const defaultConfig = {
match: '-svg-mixer-*',
computeCustomProps: false,
transform: ({ name, value }) => ({
name: name.replace(/^-svg-mixer-/, ''),
value
})
};
module.exports = postcss.plugin(packageName, config => {
const cfg = merge(defaultConfig, config);
const declNameMatcher = createMatcher(cfg.match);
return async (root, result) => {
const promisees = [];
root.walkRules(rule => {
const promise = Promise.resolve().then(async () => {
const bgDecls = postcssUtils.findBgDecls(rule);
const declsToMove = [];
rule.walkDecls(decl => {
if (declNameMatcher(decl.prop)) {
declsToMove.push(decl);
}
});
if (!bgDecls.length || !declsToMove.length) {
return;
}
if (cfg.computeCustomProps) {
await computeCustomProps(declsToMove, result, cfg.computeCustomProps);
}
const query = declsToObject(declsToMove, cfg.transform);
bgDecls.forEach(({ decl, helper }) => {
helper.URIS.forEach(url => {
url.setSearch(query);
// TODO use humane URL parsing lib
url._parts.query = url._parts.query.replace(/\+/g, '%20');
});
decl.value = helper.getModifiedRule();
});
declsToMove.forEach(d => d.remove());
});
promisees.push(promise);
});
return Promise.all(promisees);
};
});