UNPKG

judocss

Version:

The functional CSS toolkit designed for minimal effort and maximum efficiency.

177 lines (130 loc) 3.88 kB
(function() { const glob = require('glob-fs')({ gitignore: true }); const htmlparser = require("htmlparser2") const fs = require('fs') const dir = require('node-dir'); const ruleset = require('./judo.ruleset.js') const classRegex = require('./judo.classRegex.js') const units = "%,cm,em,ex,in,mm,pc,pt,px,vh,vw,vmin".split(",") const parts = (value, fn) => { let i = units.length; let index = -1 let unit = "" while(i--) { unit = units[i] index = value.indexOf(unit) if(index > -1) { let n = value.substr(0, value.length - unit.length) if(isNaN(n)) { break } return fn(n, unit) } } throw "Baseline value must consist of a number and a unit. E.g., 7px" } const base = (baseline) => { return parts(baseline, (n, unit) => { return (x) => { return isNaN(x) ? x : (x * n) + unit } }) } function trim(key) { var i = key.indexOf('$') return i === -1 ? key : key.substr(0, i) } function createMap(config) { let res = {} let i let key for(i in config){ key = trim(i) res[key] = res[key] || [] res[key].push({ regex: classRegex(i), value: config[i] }) } for(i in res){ res[i].sort((a, b) => a.value.length - b.value.length) } return res } //===================== function getStylesGroupedByQuery(classes, classMap){ let cache = {} Object.keys(classes).forEach(function(className){ ruleset(classMap, className, function(value, query){ cache[query] = cache[query] || {} cache[query][className] = cache[query][className] || value }) }) return cache } //===================== const queryBlockOpen = { "all": () => "", "small": (breakpoint) => `@media screen and (min-width: ${breakpoint.small}) {`, "medium": (breakpoint) => `@media screen and (min-width: ${breakpoint.medium}) {`, "large": (breakpoint) => `@media screen and (min-width: ${breakpoint.large}) {` } const queryBlockClose = (key) => key === "all" ? "" : "}" function expandMediaQueries(o, breakpoint) { let q let res = [] for(q in o){ //start query res.push(queryBlockOpen[q](breakpoint)) let items = o[q] let i for(i in items){ res.push(items[i]) } //end query res.push(queryBlockClose(q)) } return res.join(' ') } //===================== function onComplete(classes, classMap, config, callback) { const stylesGroupedByQuery = getStylesGroupedByQuery(classes, classMap) const css = expandMediaQueries(stylesGroupedByQuery, config.breakpoint) if(config.out){ fs.writeFile(config.out, css, (err) => { if(err) throw err; console.log('Saved.') callback(css) }) }else { callback(css) } } let classes = {} const parser = new htmlparser.Parser({ onopentag: function(name, attrs){ if(attrs.class){ attrs.class.split(' ').forEach(function(name){ classes[name] = true; }) } } }, {decodeEntities: true}) module.exports = function(config, callback) { classes = {} callback = callback || function(){} //load the path relative to the cwd or use the default const mapPath = config.map ? process.cwd() + '/' + config.map : "./judo.map.js" const confMap = require(mapPath); const baselineFn = base(config.baseline) const classMap = createMap(confMap(baselineFn)) glob.readdirStream(config.in) .on('data', function (file) { const content = fs.readFileSync(file.path) parser.write(content) }) .on('error', console.error) .on('end', () => { onComplete(classes, classMap, config, callback) }); ; } })()