postcss-custom-values
Version:
[![NPM Version][npm-img]][npm-url] [![Build Status][cli-img]][cli-url] [![Support Chat][git-img]][git-url]
113 lines (90 loc) • 3.45 kB
JavaScript
import postcss from 'postcss';
var tokens = [{
name: "number",
regex: /[+-]?\d*\.?\d+/
}, {
name: "integer",
regex: /[+-]?[1-9]\d*|0/
}, {
name: "side",
regex: /top|right|bottom|left/
}];
var genericToken = /<(\w+)>/;
function tokenRegex(string) {
// Takes string where token is referenced as ident eg. layout_<direction>
let regex;
if (string.match(genericToken)) {
// Create array with regex for standard token and capture name
let ident = [string.match(genericToken)[0], string.match(genericToken)[1]]; // For each token definition
for (let i = 0; i < tokens.length; i++) {
// If defined token matches ident
if (tokens[i].name === ident[1]) {
string = string.replace(genericToken, "(" + tokens[i].regex.source + ")"); // Create a regex which can be used to find matching things and capture value
regex = new RegExp(string);
}
}
} else {
regex = new RegExp("\\b" + string + "\\b", 'gi');
} // Outputs regex that looks for exact match of string plus token eg. /layout_(left|right)/
return regex;
} // export function tokenMatches(string, regex) {
// return string.match(regex)[1];
// }
function getKeyword(root) {
let keywords = []; // Look for every keyword definition
root.walkAtRules("value", rule => {
// Create object so can look for keywords in CSS
let keyword = {};
let propsArray = [];
let propertyThing = /property\((.+)\)/;
rule.each(decl => {
// Grab value
if (decl.prop === "value") {
keyword.value = decl.value;
} // Grab array of properties
if (rule.params.match(propertyThing)) {
let array = rule.params.match(propertyThing)[1].split(",");
for (let i = 0; i < array.length; i++) {
propsArray.push(array[i].trim());
}
}
}); // Create regex to allow matching of properties
keyword.props = new RegExp(propsArray.join("|"), 'i'); // Create regex to replace instances of word in declaration value
let nameString = rule.params.toString();
let name = nameString.replace(propertyThing, "").trim();
keyword.name = tokenRegex(name);
keywords.push(keyword);
}); // Reverse array so that keyword definitions that are declared later in document overide earlier rules
keywords.reverse();
return keywords;
}
var index = postcss.plugin("postcss-custom-value", () => {
return root => {
// console.log("root, result", root, result);
const keywords = getKeyword(root); // For each keyword definition
for (let i = 0; i < keywords.length; i++) {
let keyword = keywords[i]; // For each declration with matching properties
root.walkDecls(keyword.props, decl => {
// If value
if (decl.value.match(keyword.name)) {
// Replace instances of keyword name with correct value
var array1 = postcss.list.space(decl.value);
for (let b = 0; b < array1.length; b++) {
if (array1[b].match(keyword.name)) {
if (keyword.value.match(/\$0/gi)) {
array1[b] = keyword.value.replace(/\$0/gi, array1[b].match(keyword.name)[1]);
} else {
array1[b] = array1[b].replace(keyword.name, keyword.value);
}
}
}
decl.value = array1.join(" ");
}
});
}
root.walkAtRules("value", rule => {
rule.remove();
});
};
});
export default index;