judocss
Version:
The functional CSS toolkit designed for minimal effort and maximum efficiency.
188 lines (142 loc) • 4.22 kB
JavaScript
;
(function () {
var glob = require('glob-fs')({ gitignore: true });
var htmlparser = require("htmlparser2");
var fs = require('fs');
var dir = require('node-dir');
var ruleset = require('./judo.ruleset.js');
var classRegex = require('./judo.classRegex.js');
var units = "%,cm,em,ex,in,mm,pc,pt,px,vh,vw,vmin".split(",");
var parts = function parts(value, fn) {
var i = units.length;
var index = -1;
var unit = "";
while (i--) {
unit = units[i];
index = value.indexOf(unit);
if (index > -1) {
var 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";
};
var base = function base(baseline) {
return parts(baseline, function (n, unit) {
return function (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) {
var res = {};
var i = void 0;
var key = void 0;
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(function (a, b) {
return a.value.length - b.value.length;
});
}
return res;
}
//=====================
function getStylesGroupedByQuery(classes, classMap) {
var 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;
}
//=====================
var queryBlockOpen = {
"all": function all() {
return "";
},
"small": function small(breakpoint) {
return '@media screen and (min-width: ' + breakpoint.small + ') {';
},
"medium": function medium(breakpoint) {
return '@media screen and (min-width: ' + breakpoint.medium + ') {';
},
"large": function large(breakpoint) {
return '@media screen and (min-width: ' + breakpoint.large + ') {';
}
};
var queryBlockClose = function queryBlockClose(key) {
return key === "all" ? "" : "}";
};
function expandMediaQueries(o, breakpoint) {
var q = void 0;
var res = [];
for (q in o) {
//start query
res.push(queryBlockOpen[q](breakpoint));
var items = o[q];
var i = void 0;
for (i in items) {
res.push(items[i]);
}
//end query
res.push(queryBlockClose(q));
}
return res.join(' ');
}
//=====================
function onComplete(classes, classMap, config, callback) {
var stylesGroupedByQuery = getStylesGroupedByQuery(classes, classMap);
var css = expandMediaQueries(stylesGroupedByQuery, config.breakpoint);
if (config.out) {
fs.writeFile(config.out, css, function (err) {
if (err) throw err;
console.log('Saved.');
callback(css);
});
} else {
callback(css);
}
}
var classes = {};
var parser = new htmlparser.Parser({
onopentag: function onopentag(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
var mapPath = config.map ? process.cwd() + '/' + config.map : "./judo.map.js";
var confMap = require(mapPath);
var baselineFn = base(config.baseline);
var classMap = createMap(confMap(baselineFn));
glob.readdirStream(config.in).on('data', function (file) {
var content = fs.readFileSync(file.path);
parser.write(content);
}).on('error', console.error).on('end', function () {
onComplete(classes, classMap, config, callback);
});
;
};
})();