UNPKG

aq-web-front

Version:

A compilation framework to allow coding web frontends in a modern style.

183 lines (173 loc) 6.25 kB
var fs = require('fs'); var path = require('path'); var _ = require('underscore'); var NUMBER = 0; var STRING = 1; var OBJECT = 2; exports.pack = function(fpath, kv) { return new Promise(function(callback) { callback = _.once(callback); var outStream = fs.createWriteStream(fpath); outStream.on('error', callback); var markBuffer = new Buffer(5); var index = {}; var pos = 0; var content = _(kv).map(function(v, k) { if (typeof v == 'number') { var buff = new Buffer(8); buff.writeDoubleLE(v); index[k] = [NUMBER, pos, buff.length]; pos += buff.length; return buff; } else { var t = STRING; if (typeof v == 'object') { v = JSON.stringify(v); t = OBJECT; } if (v.length > 0) { var buff = new Buffer(v.toString(), 'utf-8'); index[k] = [t, pos, buff.length]; pos += buff.length; return buff; } else { return null; } } }).filter(function(v) { return v !== null; }); var write = exports.writeStream; var buffer = new Buffer(JSON.stringify(index), 'utf-8'); var lenBuffer = new Buffer(2); lenBuffer.writeUInt16LE(buffer.length); write(outStream, lenBuffer).then(function() { return write(outStream, buffer); }).then(function() { return new Promise(function(done) { (function next() { var buff = content.shift(); if (buff) { write(outStream, buff).then(next); } else { done(); } })(); }); }).then(function() { outStream.once('finish', callback) outStream.end(); }).catch(warn); }); }; exports.unpack = function(fpath, kv) { return new Promise(function(callback) { callback = _.once(callback); fs.open(fpath, 'r', function(err, fd) { if (err) { callback(kv, err); } else { var indexLen; read(0, 2).then(function(buffer) { indexLen = buffer.readUInt16LE(); return read(2, indexLen); }).then(function(buffer) { var index = JSON.parse(buffer); var list = _(Object.keys(index)).filter(function(k) { return k in kv; }).sort(function(a, b) { return index[a].pos - index[b].pos; }); indexLen += 2; return new Promise(function(done) { (function next() { var item = list.shift(); if (item) { var key = item; item = index[key]; read(indexLen + item[1], item[2]).then(function(buffer) { if (item[0] == NUMBER) { kv[key] = buffer.readDoubleLE(); } else { kv[key] = buffer.toString('utf-8'); if (item[0] == OBJECT) { kv[key] = JSON.parse(kv[key]); } } next(); }).catch(warn); } else { done(); } })(); }); }).then(function() { fs.close(fd, function() { callback(kv); }); }).catch(warn); function read(pos, len) { return new Promise(function(accept) { var buffer = new Buffer(len); fs.read(fd, buffer, 0, len, pos, function(err, bytesRead, buffer) { if (err) { fs.close(fd); callback(kv, err); } else { accept(buffer); } }); }); } } }); }); }; exports.writeStream = function(stream, content) { return new Promise(function(next) { if (stream.write(content)) { next(); } else { stream.once('drain', next); } }); }; exports.normalizePath = function(fpath) { return path.normalize(fpath).replace(/\\+/g, '/'); }; exports.isExt = function(fpath, ext) { return (new ExtChecker(ext)).match(fpath); }; exports.ExtChecker = ExtChecker; function ExtChecker(ext) { if (!(ext instanceof Array)) { ext = [ext]; } this.full = {}; this.first = {}; for (var i = 0; i < ext.length; i++) { var item = ext[i]; item = item[0] == '.' ? item.substr(1) : item; this.full[item] = 1; this.first[item.split('.').pop()] = 1; } } ExtChecker.prototype.match = function(fpath) { var fext = path.basename(fpath).split('.'); if (this.first[fext[fext.length - 1]]) { for (var i = 1; i < fext.length; i++) { var find = fext.slice(i).join('.'); if (this.full[find]) { return true; } } } return false; }; function warn(err) { if (err.stack) { console.warn(err.stack); } else { console.warn(err); } }