|
'use strict' |
|
|
|
const gulp = require('gulp') |
|
const fs = require('fs') |
|
const yaml = require('js-yaml') |
|
const glob = require('glob') |
|
const path = require('path') |
|
|
|
const JSX_CLASS_RX = /className=({?'|{?"|{?`)(-?[_a-zA-Z]+[_a-zA-Z0-9-]*( +)?)+('}?|"}?|`}?)+/g |
|
const PUG_CLASS_RX = /(\.-?[_a-zA-Z]+[_a-zA-Z0-9-]*)+/g |
|
const PARSER_RX = /([a-z]+_)/g |
|
|
|
const getJSXClasses = jsxString => { |
|
let matches = jsxString.match(JSX_CLASS_RX) |
|
if(matches === null){ |
|
return [] |
|
} |
|
let classSplit = [] |
|
for(let match of matches){ |
|
let classString = match.replace(/(className={?'?"?`?|'?"?`?}?)/g, '') |
|
classSplit = classSplit.concat(classString.split(/ +/g)) |
|
} |
|
return classSplit |
|
} |
|
|
|
const getPugClasses = pugString => { |
|
let matches = pugString.match(PUG_CLASS_RX) |
|
if(matches === null){ |
|
return [] |
|
} |
|
let classes = [] |
|
for (let match of matches){ |
|
classes = classes.concat(match.split(/\./g)) |
|
} |
|
return classes |
|
} |
|
|
|
const processClassNames = (classArray, config) => { |
|
let cssString = '' |
|
let seenClassNames = {} |
|
|
|
for(let className of classArray){ |
|
if(typeof seenClassNames[className] !== 'undefined'){ |
|
continue |
|
} |
|
seenClassNames[className] = 1 |
|
|
|
let matches = className.match(PARSER_RX) |
|
if (matches === null) { |
|
continue |
|
} |
|
|
|
let rule = matches[0].replace(/_/, '') |
|
let breakpoint = null, action = null |
|
|
|
if (matches.length > 1){ |
|
for(let match of matches.slice(1)){ |
|
match = match.replace(/_/, '') |
|
if (typeof config.breakpoints[match] !== 'undefined') { |
|
breakpoint = match |
|
} |
|
else if (typeof config.actions[match] !== 'undefined') { |
|
action = match |
|
} |
|
else { |
|
console.warn(`\nModifier not defined: ${match} from ${className}\n`) |
|
} |
|
} |
|
|
|
} |
|
|
|
let value = className.replace(PARSER_RX, '') |
|
// check if value is mapped to something |
|
if (typeof config.values[value] !== 'undefined'){ |
|
value = config.values[value] |
|
} |
|
if (typeof config[rule] === 'undefined'){ |
|
console.warn(`\nRule not defined: ${rule} from ${className}\n`) |
|
} |
|
else { |
|
// if rule is in config, build something like ".p_1px{padding: 1px}" |
|
let cssRuleString = `.${className}` |
|
|
|
if (action !== null) { |
|
let actionValue = config.actions[action] |
|
if(actionValue !== undefined){ |
|
cssRuleString += `:${actionValue}` |
|
} |
|
else { |
|
console.warn(`\nAction not defined: ${action} from ${className}\n`) |
|
} |
|
} |
|
cssRuleString += `{` |
|
|
|
if (Array.isArray(config[rule])) { |
|
for (let r of config[rule]) { |
|
cssRuleString += `${r}: ${value};` |
|
} |
|
} |
|
else { |
|
cssRuleString += `${config[rule]}: ${value}` |
|
} |
|
|
|
cssRuleString += `}` |
|
|
|
if (breakpoint !== null) { |
|
let breakpointValue = config.breakpoints[breakpoint] |
|
if(breakpointValue !== undefined){ |
|
cssString += `@media screen and (min-width: ${breakpointValue}) {\n ${cssRuleString}}\n` |
|
} |
|
else { |
|
console.warn(`\nBreakpoint not defined: ${breakpoint} from ${className}\n`) |
|
} |
|
} |
|
else { |
|
cssString += cssRuleString |
|
} |
|
} |
|
} |
|
return cssString |
|
} |
|
|
|
const getClassesFromFiles = fileNames => { |
|
let classArray = [] |
|
let missingParsers = {} |
|
|
|
for (let fileName of fileNames){ |
|
|
|
let content = fs.readFileSync(`${__dirname}/${fileName}`, 'utf8') |
|
let extension = path.extname(fileName) |
|
switch(extension){ |
|
case '.jsx': |
|
classArray = classArray.concat(getJSXClasses(content)) |
|
break |
|
case '.pug': |
|
classArray = classArray.concat(getPugClasses(content)) |
|
break |
|
default: |
|
missingParsers[extension] = 1 |
|
break; |
|
} |
|
} |
|
|
|
console.log(`\nMissing Atomic CSS Parsers for ${Object.keys(missingParsers).join(', ')}`) |
|
|
|
return classArray |
|
} |
|
|
|
const main = done => { |
|
let config = yaml.safeLoad(fs.readFileSync(process.env.CONFIG_PATH, 'utf8')) |
|
|
|
try { |
|
let allFiles = [] |
|
for (let source of config.sources) { |
|
let files = glob.sync(source, {nodir: true}) |
|
allFiles = allFiles.concat(files) |
|
} |
|
let classArray = getClassesFromFiles(allFiles) |
|
let cssString = processClassNames(classArray, config) |
|
|
|
fs.writeFileSync(`${__dirname}${config.dist}`, cssString, 'utf8') |
|
} |
|
catch(e){ |
|
console.log(e) |
|
} |
|
|
|
|
|
done() |
|
} |
|
|
|
gulp.task('default', main) |