UNPKG

stylup

Version:

Write utility classes conveniently while optimising your CSS

342 lines (279 loc) 9.45 kB
var phtml = require('phtml'); var _ = require('lodash'); var commonTags = require('common-tags'); var fs = require('fs-extra'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var phtml__default = /*#__PURE__*/_interopDefaultLegacy(phtml); var ___default = /*#__PURE__*/_interopDefaultLegacy(_); var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); function genRegex(opts) { let tokens = {}; if (Object(opts).regex) { tokens = opts.regex; } else { tokens = { property: /[^-\s]+/, number: /[0-9]*\.?[0-9]+|\*/, unit: /px|cm|mm|in|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax/, seperator: /,/, arg: /0*({{number}})({{unit}})?|(\w+)/, args: /(?:({{arg}}){{seperator}}?)+/, decl: /({{property}})(?:-({{args}}))?/ }; } // Define what a token identifier looks like <word> or {{word}} let token = /{{(\w+)}}/gim; // Takes regex like /\d\w[0-9]<word>/ and replaces token identifier with matching token name function replaceTokenIdent(value, tokens) { return value.toString().replace(token, function (match, name) { if (tokens[name]) { if (tokens[name].toString().match(token)) { return replaceTokenIdent(tokens[name], tokens); } return tokens[name].source; } else { return match; } }); } // Go through each token in object and replace tokens identifier with value tokens = ___default['default'].reduce(tokens, function (result, value, key) { return Object.assign({}, result, { [key]: replaceTokenIdent(value, tokens) }); }, {}); // Create new regex for each token return ___default['default'].reduce(tokens, function (result, value, key) { return Object.assign({}, result, { [key]: new RegExp(value.replace(/\//g, ''), 'gmi') }); }, {}); } function getUtilities(str, re) { function findMatches(regex, str, matches = []) { const res = regex.exec(str); res && matches.push(res) && findMatches(regex, str, matches); return matches; } // var declRe = new RegExp(/\b([^-\s]+)(?:-((?:(0*([0-9]*\.?[0-9]+|\*)(px|cm|mm|in|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax)?|(\w+)),?)+))?\b/, 'gi') // let match = str.match(/\b([^-\s]+)(?:-((?:(0*([0-9]*\.?[0-9]+|\*)(px|cm|mm|in|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax)?|(\w+)),?)+))?\b/g); const matches = findMatches(re.decl, str); // console.log(match) let utilities = []; for (let i = 0; i < matches.length; i++) { let match = matches[i]; let utility = {}; if (match !== null) { utility.class = match[1]; // console.log(re.decl) utility.args = []; utility.decl = match[0]; if (match[2]) { /* Temporary fix for multiple arguments */ match[2].replace(new RegExp(re.arg, 'gmi'), function (arg) { if (arg === '*') arg = null; utility.args.push(arg); }); } if (utility.args.length === 0) { utility.args = null; } utilities.push(utility); } } return utilities; } var uniqid = require('uniqid'); const postcss = require('postcss'); const postcssrc = require('postcss-load-config'); const postcssNested = require('postcss-nested'); const autoprefixer = require('autoprefixer'); // Get rules definitions function getConfig(path) { var config; if (fs__default['default'].existsSync(process.cwd() + '/' + path)) { config = require(process.cwd() + '/' + path).classes; } return config; } // var rules; // if (fs.existsSync(process.cwd() + '/' + 'stylup.config.js')) { // rules = require(process.cwd() + '/' + 'stylup.config.js').classes // // console.log(rules) // } // else { // rules = undefined // } function putValuesIntoArray(value) { return Array.isArray(value) ? value : [value]; } function genStyles(utility, acc) { var styles = ''; if (utility.style({ rule: utility, args: utility.args, str: acc }) === undefined) { styles = ''; } else { styles = utility.style({ rule: utility, args: utility.args, str: acc }); } return `${styles}`; } async function processPostCSS(src = '') { const ctx = { parser: true, map: 'inline' }; // FIXME: Can't change this to await because it breaks the function let plugins; try { plugins = postcssrc.sync(ctx).plugins; } catch (error) { plugins = []; } const { css } = await postcss([postcssNested(), autoprefixer(), ...plugins]).process(src, { from: undefined }); return css; // postcssrc(ctx).then((({ plugins, options }) => { // postcss([postcssNested(), autoprefixer(), ...plugins]) // .process(src, { from: undefined }) // .then((css) => { // callback(css) // }) // })) } function processInlineStyles(node, classNameID) { const inlineStyles = node.attrs.get('style'); if (inlineStyles) { styles = ` .${classNameID}.${classNameID} {${inlineStyles}}`; processPostCSS(styles).then(css => { // console.log("css --->", css) // Add new array back to element var styleTag = new phtml.Element({ name: 'style' }, null, css); // Add new array back to element var spanTag = new phtml.Element({ name: 'span' }, null, styleTag); spanTag.attrs.add({ style: 'display: none' }); spanTag.attrs.add({ class: 'stylup-sb' }); node.before(spanTag); node.attrs.remove('style'); var classNames = node.attrs.get('class') ? node.attrs.get('class').split(' ') : []; classNames.push(classNameID); node.attrs.add({ class: classNames.join(' ') }); }).catch(error => { console.log("error", error); }); } } // async function getPostConfig() { var index = new phtml__default['default'].Plugin('phtml-utility-class', opts => { opts = opts || {}; return { Element(node) { if (opts.processBlockStyles === true) { if (node.name === "style") { const target = node.nodes[0]; const source = target.data; processPostCSS(source).then(css => { node.innerHTML = css; }).catch(error => { console.log(error); }); } } var classNameID = uniqid(); if (process.env.NODE_ENV === "test") { classNameID = 'uniqid'; } // Get styles from style attr processInlineStyles(node, classNameID); const hasClass = node.attrs.get('class'); if (hasClass) { const classNames = hasClass ? node.attrs.get('class').split(' ') : null; var re = genRegex(opts); var utilities = getUtilities(hasClass, re); let newClassNames = [...classNames]; let styles = []; let hasUtilities = false; for (let utility of utilities) { // if (utilityClass) { // console.log('utility class') // } // else { // console.log('not utilit class') // } let rules = getConfig('stylup.config.js'); if (rules) { for (let rule of rules) { rule.class = putValuesIntoArray(rule.class); for (let property of rule.class) { var tempRule = Object.assign({}, rule); tempRule.class = property; if (utility.class === tempRule.class) { tempRule = Object.assign(tempRule, utility); hasUtilities = true; var output = ""; function acc(strings, ...values) { if (!strings) { if (typeof output !== "undefined") { return output = output.replace(/\n$/, ''); } else { return str; } } else { let str = ''; strings.forEach((string, a) => { str += string + (values[a] || ''); }); str = commonTags.stripIndent(str); if (typeof output !== "undefined") { output += `${str}\n`; } return str; } } styles.push(genStyles(tempRule, acc)); newClassNames.push(utility.class); } } } } } if (hasUtilities) { styles = ` .${classNameID}.${classNameID} { ${styles.join('')} }`; processPostCSS(styles).then(css => { // Add new array back to element var styleTag = new phtml.Element({ name: 'style' }, null, css); // Add new array back to element var spanTag = new phtml.Element({ name: 'span' }, null, styleTag); spanTag.attrs.add({ style: 'display: none' }); spanTag.attrs.add({ class: 'stylup-sb' }); node.before(spanTag); // Add classNameID newClassNames.push(classNameID); node.attrs.add({ class: newClassNames.join(' ') }); }).catch(error => { console.log(error); }); } } } }; }); module.exports = index; //# sourceMappingURL=index.js.map