spa
Version:
Single-page applications builder with continuous integration, granular updates and loader.
1,172 lines (1,049 loc) • 34.1 kB
JavaScript
var Builder, CyclicDependenciesError, DB, ExternalDependencyError, HostingUrlOverwritingError, Logger, Loop, ModuleFileOverwritingError, ModuleTypeError, NoCopyingRuleError, UnresolvedDependencyError, amdType, clc, console, crypto, definition, detectiveAMD, detectiveCJS, ejs, encoders, eval_file, fs, get_config_content, globrules, hasBOM, hashers, load_json, load_yaml, mkdirpSync, packagejson, path, resolve, sandbox, vm, walker, yaml, _,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
__slice = [].slice,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
fs = require('fs');
vm = require("vm");
walker = require('fs-walk-glob-rules');
globrules = require('glob-rules');
path = require('path');
clc = require('cli-color');
mkdirpSync = require('mkdirp').sync;
detectiveCJS = require('detective');
detectiveAMD = require('detective-amd');
definition = require('module-definition').fromSource;
amdType = require('get-amd-module-type').fromSource;
yaml = require('js-yaml');
ejs = require("ejs");
_ = require('lodash');
_.string = require('underscore.string');
_.mixin(_.string.exports());
crypto = require("crypto");
resolve = require("resolve");
console = require("./console");
packagejson = (function() {
var packagepath;
packagepath = path.resolve(__dirname, '../package.json');
return JSON.parse(fs.readFileSync(packagepath, 'utf8'));
})();
CyclicDependenciesError = (function(_super) {
__extends(CyclicDependenciesError, _super);
function CyclicDependenciesError(loop) {
this.loop = loop;
this.name = this.constructor.name;
this.message = "Can't sort modules. Loop found: \n" + this.loop;
}
return CyclicDependenciesError;
})(Error);
UnresolvedDependencyError = (function(_super) {
__extends(UnresolvedDependencyError, _super);
function UnresolvedDependencyError(path, alias) {
this.path = path;
this.alias = alias;
this.name = this.constructor.name;
this.message = ("Can't resolve dependency `" + this.alias + "` ") + ("inside module `" + this.path + "`");
}
return UnresolvedDependencyError;
})(Error);
ExternalDependencyError = (function(_super) {
__extends(ExternalDependencyError, _super);
function ExternalDependencyError(path, alias, dep) {
this.path = path;
this.alias = alias;
this.dep = dep;
this.name = this.constructor.name;
this.message = ("Module at path `" + dep + "` is required from `" + path + "` ") + ("as `" + alias + "`, but it cant be found inside building scope.");
}
return ExternalDependencyError;
})(Error);
NoCopyingRuleError = (function(_super) {
__extends(NoCopyingRuleError, _super);
function NoCopyingRuleError(path) {
this.path = path;
this.name = this.constructor.name;
this.message = "No copying rule for module to be crypter at path `" + this.path + "`";
}
return NoCopyingRuleError;
})(Error);
ModuleTypeError = (function(_super) {
__extends(ModuleTypeError, _super);
function ModuleTypeError(path, error) {
var _ref;
this.path = path;
this.error = error;
this.name = this.constructor.name;
this.message = "Can't determine type of module at `" + this.path + "`: " + ((_ref = this.error) != null ? _ref.toString() : void 0);
}
return ModuleTypeError;
})(Error);
ModuleFileOverwritingError = (function(_super) {
__extends(ModuleFileOverwritingError, _super);
function ModuleFileOverwritingError(path) {
this.path = path;
this.name = this.constructor.name;
this.message = "Several modules are about to be wrote into `" + this.path + "`. Please revisit your `copying` rules.";
}
return ModuleFileOverwritingError;
})(Error);
HostingUrlOverwritingError = (function(_super) {
__extends(HostingUrlOverwritingError, _super);
function HostingUrlOverwritingError(url) {
this.url = url;
this.name = this.constructor.name;
this.message = "Several modules are about to be hosted `" + this.url + "`. Please revisit your `hosting` rules.";
}
return HostingUrlOverwritingError;
})(Error);
Loop = (function() {
function Loop() {
this._parts = [];
}
Loop.prototype.prepend = function(path, alias) {
this._parts.unshift([path, alias]);
return this;
};
Loop.prototype.toString = function() {
var i, p;
if (this._parts.length === 0) {
return "";
}
p = this._parts.concat([this._parts[0]]);
return ((function() {
var _i, _ref, _results;
_results = [];
for (i = _i = 0, _ref = this._parts.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
_results.push("" + p[i][0] + " --[" + p[i][1] + "]--> " + p[i + 1][0]);
}
return _results;
}).call(this)).join("\n");
};
return Loop;
})();
Logger = (function() {
function Logger(prefix) {
this.prefix = prefix;
}
Logger.prototype.info = function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return console.info(args.join(" "));
};
Logger.prototype.warn = function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return console.warn(clc.bgYellow.bold(this.prefix), clc.yellow(args.join(" ")));
};
Logger.prototype.error = function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return console.error(clc.bgRed.bold(this.prefix), clc.red.bold(args.join(" ")));
};
return Logger;
})();
DB = (function() {
function DB(filename) {
this.filename = filename;
if ((this.filename != null) && fs.existsSync(this.filename)) {
this._data = JSON.parse(fs.readFileSync(this.filename));
} else {
this._data = {};
}
}
DB.prototype.get = function(key) {
var content;
content = this._data[key];
if (content != null) {
return JSON.parse(content);
}
};
DB.prototype.set = function(key, value) {
return this._data[key] = JSON.stringify(value);
};
DB.prototype.del = function(key) {
return delete this._data[key];
};
DB.prototype.has = function(key) {
return this._data.hasOwnProperty(key);
};
DB.prototype.flush = function() {
return fs.writeFileSync(this.filename, JSON.stringify(this._data));
};
return DB;
})();
sandbox = function() {
var result, window;
window = {};
window.window = window;
result = {
ArrayBuffer: Object.freeze(ArrayBuffer),
Buffer: Object.freeze(Buffer),
Uint8Array: Object.freeze(Uint8Array),
console: Object.freeze(console),
window: Object.freeze(window),
Uint32Array: Object.freeze(Uint32Array)
};
return result;
};
eval_file = function(p, s) {
return vm.runInNewContext(fs.readFileSync(path.resolve(__dirname, p), "utf8"), sandbox());
};
hashers = {
md5: function(data) {
return crypto.createHash("md5").update(data).digest('hex');
},
ripemd160: function(data) {
return crypto.createHash("ripemd160").update(data).digest('hex');
},
sha1: function(data) {
return crypto.createHash("sha1").update(data).digest('hex');
},
sha224: function(data) {
return crypto.createHash("sha224").update(data).digest('hex');
},
sha256: function(data) {
return crypto.createHash("sha256").update(data).digest('hex');
},
sha384: function(data) {
return crypto.createHash("sha384").update(data).digest('hex');
},
sha512: function(data) {
return crypto.createHash("sha512").update(data).digest('hex');
},
sha3: eval_file("./assets/hash/sha3.js")
};
encoders = {
"aes-ccm": eval_file("./assets/encode/aes-ccm.js"),
"aes-gcm": eval_file("./assets/encode/aes-gcm.js"),
"aes-ocb2": eval_file("./assets/encode/aes-ocb2.js")
};
Builder = (function() {
function Builder(options) {
var name, pattern, template, type, value, _base, _ref, _ref1, _ref10, _ref11, _ref12, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9;
this._built_ins = ["loader", "require", "module", "exports"];
this.options = options;
if ((_base = this.options).logger == null) {
_base.logger = "SPA";
}
if (_.isString(options.logger)) {
this.logger = this._create_logger();
} else {
this.logger = options.logger;
}
this.root = path.resolve(process.cwd(), options.root) + "/";
this.extensions = (_ref = options.extensions) != null ? _ref : [".js"];
this.excludes = (_ref1 = options.excludes) != null ? _ref1 : [];
this.paths = (_ref2 = options.paths) != null ? _ref2 : {};
this.hosting = (function() {
var _ref3, _ref4, _results;
_ref4 = (_ref3 = options.hosting) != null ? _ref3 : {};
_results = [];
for (pattern in _ref4) {
template = _ref4[pattern];
_results.push({
test: globrules.tester(pattern),
transform: globrules.transformer(pattern, template)
});
}
return _results;
})();
this.hosting_map = options.hosting_map;
this.copying = (function() {
var _ref3, _ref4, _results;
_ref4 = (_ref3 = options.copying) != null ? _ref3 : {};
_results = [];
for (pattern in _ref4) {
template = _ref4[pattern];
_results.push({
test: globrules.tester(pattern),
transform: globrules.transformer(pattern, template)
});
}
return _results;
})();
this.default_loader = (_ref3 = options.default_loader) != null ? _ref3 : "cjs";
this.loaders = (function() {
var _ref4, _ref5, _results;
_ref5 = (_ref4 = options.loaders) != null ? _ref4 : {};
_results = [];
for (pattern in _ref5) {
type = _ref5[pattern];
_results.push({
test: globrules.tester(pattern),
type: type
});
}
return _results;
})();
this.bundle = options.bundle;
this.manifest = options.manifest;
this.index = options.index;
this.pretty = (_ref4 = options.pretty) != null ? _ref4 : false;
this.grab = (_ref5 = options.grab) != null ? _ref5 : false;
this.print_stats = (_ref6 = options.print_stats) != null ? _ref6 : true;
this.print_roots = (_ref7 = options.print_roots) != null ? _ref7 : true;
this.assets = {
appcache_template: path.join(__dirname, "assets/appcache.tmpl"),
index_template: path.join(__dirname, "assets/index.tmpl")
};
_ref8 = options.assets;
for (name in _ref8) {
if (!__hasProp.call(_ref8, name)) continue;
value = _ref8[name];
this.assets[name] = value;
}
this.appcache = options.appcache;
this.cached = (_ref9 = options.cached) != null ? _ref9 : [];
this.hash_func = (_ref10 = options.hash_func) != null ? _ref10 : "md5";
this.randomize_urls = (_ref11 = options.randomize_urls) != null ? _ref11 : true;
this.coding_func = options.coding_func;
this.cache = this._create_db(path.resolve(this.root, (_ref12 = options.cache_file) != null ? _ref12 : ".spacache"));
}
Builder.prototype._create_db = function(path) {
return new DB(path);
};
Builder.prototype._create_logger = function(name) {
return new Logger(name);
};
Builder.prototype._filter = function(filepath) {
var expected;
expected = path.extname(filepath);
if (!_(this.extensions).any(function(ext) {
return expected === ext;
})) {
return false;
}
return true;
};
Builder.prototype.calc_hash = function(content) {
return hashers[this.hash_func](content);
};
Builder.prototype.encode = function(content, module) {
var encoder;
encoder = encoders[this.coding_func.name];
return encoder(content, module, this);
};
Builder.prototype._relativate = function(filepath) {
return this.walker.normalize(filepath);
};
Builder.prototype._get_copying = function(filepath) {
var rule, _i, _len, _ref;
_ref = this.copying;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
rule = _ref[_i];
if (!rule.test(filepath)) {
continue;
}
return rule.transform(filepath);
}
};
Builder.prototype._host_path = function(relative) {
var rule, _i, _len, _ref;
_ref = this.hosting;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
rule = _ref[_i];
if (!rule.test(relative)) {
continue;
}
return rule.transform(relative);
}
return this.logger.error("No hosting rules for `" + relative + "`");
};
Builder.prototype._resolve_to_file = function(filepath) {
var stats;
if (fs.existsSync(filepath)) {
stats = fs.statSync(filepath);
if (stats.isFile()) {
return filepath;
}
}
};
Builder.prototype._resolve_to_directory = function(dirpath) {
var stats;
if (fs.existsSync(dirpath)) {
stats = fs.statSync(dirpath);
if (stats.isDirectory()) {
return this._resolve_to_file(path.join(dirpath, "index.js"));
}
}
};
Builder.prototype._get_type = function(module, source) {
var error, rule, _i, _len, _ref;
_ref = this.loaders;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
rule = _ref[_i];
if (!rule.test(module.relative)) {
continue;
}
return rule.type;
}
try {
switch (definition(module.source)) {
case "commonjs":
return "cjs";
case "amd":
return "amd";
}
} catch (_error) {
error = _error;
throw new ModuleTypeError(module.path, error);
}
return this.default_loader;
};
Builder.prototype._resolve = function(module, dep) {
var alias, basedir, prefix, _ref, _ref1, _ref2;
_ref = this.paths;
for (alias in _ref) {
prefix = _ref[alias];
if (!_.startsWith(dep, alias)) {
continue;
}
if ((dep[alias.length] || "/") === "/") {
dep = dep.replace(alias, prefix);
break;
}
}
if (_.startsWith(dep, "/")) {
dep = path.join(this.root, dep);
} else if (_.startsWith(dep, "./") || _.startsWith(dep, "../")) {
basedir = path.dirname(module.path);
dep = path.resolve(basedir, dep);
} else {
try {
return resolve.sync(dep, {
basedir: path.dirname(module.path),
extensions: this.extensions
});
} catch (_error) {
return null;
}
}
return (_ref1 = (_ref2 = this._resolve_to_file(dep)) != null ? _ref2 : this._resolve_to_file(dep + ".js")) != null ? _ref1 : this._resolve_to_directory(dep);
};
Builder.prototype._find_loop = function(candidates) {
var candidate, has_loop, walked, _go_deep, _i, _len;
for (_i = 0, _len = candidates.length; _i < _len; _i++) {
candidate = candidates[_i];
walked = [];
_go_deep = (function(_this) {
return function(current) {
var alias, deep, dep, deps, module, relative;
module = _this._by_path[current];
relative = module.relative;
deps = module.deps_paths;
for (alias in deps) {
dep = deps[alias];
if (__indexOf.call(candidates, dep) < 0) {
continue;
}
if (__indexOf.call(walked, dep) >= 0) {
continue;
}
if (dep === candidate) {
return new Loop().prepend(relative, alias);
}
walked.push(dep);
deep = _go_deep(dep);
walked.pop();
if (deep != null) {
return deep.prepend(relative, alias);
}
}
};
})(this);
has_loop = _go_deep(candidate);
if (has_loop != null) {
return has_loop;
}
}
};
Builder.prototype._write_file = function(destination, content) {
var filepath;
filepath = path.resolve(this.root, destination);
this.logger.info("Writing " + filepath + ". " + content.length + " bytes.");
mkdirpSync(path.dirname(filepath));
return fs.writeFileSync(filepath, content);
};
Builder.prototype._stringify_json = function(data) {
return JSON.stringify(data, null, this.pretty ? " " : void 0);
};
Builder.prototype._inject_inline = function(relative) {
var filepath;
filepath = path.resolve(__dirname, "assets", relative);
return fs.readFileSync(filepath, {
encoding: "utf8"
});
};
Builder.prototype._clear = function() {
this._modules = [];
this._by_path = {};
this._by_id = {};
this._manifest_content = void 0;
return this._index_content = void 0;
};
Builder.prototype._enlist = function() {
var data, module, _i, _len, _ref;
this.walker = new walker.SyncWalker({
root: this.root,
excludes: this.excludes
});
_ref = this.walker.walk();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
data = _ref[_i];
if (!this._filter(data.relative)) {
continue;
}
module = {
path: data.path,
relative: data.relative
};
this._by_path[data.path] = module;
this._modules.push(module);
}
};
Builder.prototype._analyze = function() {
var dep, deps, module, modules, resolved, source, submodule, _i, _len;
modules = this._modules.concat();
while (modules.length > 0) {
module = modules.shift();
source = fs.readFileSync(module.path);
module.source = source.toString('utf8');
module.deps_paths = {};
module.type = this._get_type(module);
switch (module.type) {
case "amd":
module.amdtype = amdType(module.source);
}
module.source_hash = this.calc_hash(source);
module.source_length = source.length;
deps = (function() {
switch (module.type) {
case "cjs":
return detectiveCJS(module.source);
case "amd":
return detectiveAMD(module.source);
default:
return [];
}
})();
for (_i = 0, _len = deps.length; _i < _len; _i++) {
dep = deps[_i];
if (__indexOf.call(this._built_ins, dep) >= 0) {
continue;
}
resolved = this._resolve(module, dep);
if (resolved == null) {
throw new UnresolvedDependencyError(module.relative, dep);
}
module.deps_paths[dep] = resolved;
if (this.grab && !this._by_path[resolved]) {
submodule = {
path: resolved,
relative: this._relativate(resolved)
};
this._by_path[resolved] = submodule;
this._modules.push(submodule);
modules.push(submodule);
}
}
}
};
Builder.prototype._host = function() {
var module, url, urls, _i, _len, _ref;
urls = {};
_ref = this._modules;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
module = _ref[_i];
url = this._host_path(module.relative);
if (!url) {
continue;
}
if (url in urls) {
throw new HostingUrlOverwritingError(url);
}
urls[url] = module;
module.url = url;
}
};
Builder.prototype._set_ids = function() {
var ext, id, module, newroot, root, _i, _len, _ref;
_ref = this._modules;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
module = _ref[_i];
ext = path.extname(module.path);
root = path.dirname(module.path);
id = path.basename(module.path, ext);
if (id === "index") {
id = path.basename(root);
root = path.dirname(root);
}
while (id in this._by_id) {
id = path.basename(root) + "/" + id;
newroot = path.dirname(root);
if (newroot === root) {
break;
}
root = newroot;
}
id = id.split(/[^a-zA-Z0-9]/g).join("_");
while (id in this._by_id) {
id = "_" + id;
}
this._by_id[id] = module;
module.id = id;
}
};
Builder.prototype._link = function() {
var dep, module, resolved, _i, _len, _ref, _results;
_ref = this._modules;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
module = _ref[_i];
module.deps_ids = {};
_results.push((function() {
var _ref1, _results1;
_ref1 = module.deps_paths;
_results1 = [];
for (dep in _ref1) {
resolved = _ref1[dep];
if (this._by_path[resolved] != null) {
_results1.push(module.deps_ids[dep] = this._by_path[resolved].id);
} else {
throw new ExternalDependencyError(module.relative, dep, resolved);
}
}
return _results1;
}).call(this));
}
return _results;
};
Builder.prototype._sort = function() {
var deps, left, module, mpath, order, use, _i, _len;
left = (function() {
var _i, _len, _ref, _results;
_ref = this._modules;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
module = _ref[_i];
_results.push(module.path);
}
return _results;
}).call(this);
order = [];
while (left.length > 0) {
use = [];
for (_i = 0, _len = left.length; _i < _len; _i++) {
mpath = left[_i];
deps = this._by_path[mpath].deps_paths;
if (!_(deps).any(function(dep) {
return __indexOf.call(order, dep) < 0;
})) {
use.push(mpath);
}
}
if (use.length === 0) {
throw new CyclicDependenciesError(this._find_loop(left));
}
order.push.apply(order, use);
left = left.filter(function(mpath) {
return __indexOf.call(use, mpath) < 0;
});
}
return this._modules = (function() {
var _j, _len1, _results;
_results = [];
for (_j = 0, _len1 = order.length; _j < _len1; _j++) {
mpath = order[_j];
_results.push(this._by_path[mpath]);
}
return _results;
}).call(this);
};
Builder.prototype._encode = function() {
var destination, module, output, paths, source, _contents, _i, _j, _len, _len1, _ref, _ref1;
_contents = [];
if (this.coding_func != null) {
paths = {};
_ref = this._modules;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
module = _ref[_i];
destination = this._get_copying(module.relative);
if (destination == null) {
throw new NoCopyingRuleError(module.relative);
}
if (destination in paths) {
throw new ModuleFileOverwritingError(destination);
}
paths[destination] = module;
source = fs.readFileSync(module.path);
output = this.encode(source, module);
if (this.bundle) {
_contents.push(output);
}
this._write_file(destination, output);
module.hash = this.calc_hash(output);
module.size = output.length;
}
} else {
_ref1 = this._modules;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
module = _ref1[_j];
module.hash = module.source_hash;
module.size = module.source_length;
if (this.bundle) {
source = fs.readFileSync(module.path);
_contents.push(source);
}
}
}
this._bundle_content = _contents.join("");
};
Builder.prototype._create_manifest = function() {
var bundle, filepath, module, modules, relative, url;
modules = (function() {
var _i, _len, _ref, _results;
_ref = this._modules;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
module = _ref[_i];
_results.push({
id: module.id,
url: module.url,
hash: module.hash,
size: module.size,
type: module.type,
amdtype: module.amdtype,
deps: module.deps_ids,
decoding: module.decoding
});
}
return _results;
}).call(this);
this._manifest_content = {
version: packagejson.version,
hash_func: this.hash_func,
modules: modules
};
if (this.bundle) {
filepath = path.resolve(this.root, this.bundle);
relative = this._relativate(filepath);
url = this._host_path(relative);
bundle = {
hash: this.calc_hash(new Buffer(this._bundle_content, "utf8")),
url: url
};
this._manifest_content.bundle = bundle;
}
if (this.coding_func != null) {
this._manifest_content.decoder_func = this.coding_func.name;
}
return this._manifest_content;
};
Builder.prototype._create_hosting_map = function() {
var filepath, files, map, module, relative, url, _i, _len, _ref;
files = {};
_ref = this._modules;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
module = _ref[_i];
files[module.url] = module.relative;
}
map = {
version: packagejson.version,
files: files
};
if (this.bundle) {
filepath = path.resolve(this.root, this.bundle);
relative = this._relativate(filepath);
url = this._host_path(relative);
if (url != null) {
map.bundle = {
path: relative,
url: url
};
}
}
if (this.manifest) {
filepath = path.resolve(this.root, this.manifest);
relative = this._relativate(filepath);
url = this._host_path(relative);
if (url != null) {
map.manifest = {
path: relative,
url: url
};
}
}
if (this.index) {
filepath = path.resolve(this.root, this.index);
relative = this._relativate(filepath);
url = this._host_path(relative);
if (url != null) {
map.index = {
path: relative,
url: url
};
}
}
if (this.appcache != null) {
filepath = path.resolve(this.root, this.appcache);
relative = this._relativate(filepath);
url = this._host_path(relative);
if (url != null) {
map.appcache = {
path: relative,
url: url
};
}
}
return map;
};
Builder.prototype._create_index = function() {
var assets, compiled, content, filepath, name, namespace, relative, url, value, _ref;
assets = {};
namespace = {
assets: assets
};
_ref = this.assets;
for (name in _ref) {
if (!__hasProp.call(_ref, name)) continue;
value = _ref[name];
content = fs.readFileSync(value, {
encoding: "utf8"
});
namespace[name] = content;
assets[name] = content;
}
namespace["manifest_location"] = "manifest.json";
namespace["randomize_urls"] = this.randomize_urls;
namespace["inline"] = (function(_this) {
return function(relative) {
return _this._inject_inline(relative);
};
})(this);
namespace["version"] = packagejson.version;
namespace["hash_name"] = this.hash_func;
namespace["decoder_name"] = this.coding_func != null ? this.coding_func.name : "identity";
namespace["passcode_required"] = this.coding_func != null;
if (this.manifest != null) {
filepath = path.resolve(this.root, this.manifest);
relative = this._relativate(filepath);
url = this._host_path(relative);
if (url != null) {
namespace["manifest_location"] = url;
} else {
this.logger.warn("Manifest file hosted as `" + relative + "` and will be accesible relatively");
}
}
if (this.appcache != null) {
filepath = path.resolve(this.root, this.appcache);
relative = this._relativate(filepath);
url = this._host_path(relative);
if (url != null) {
namespace["appcache_location"] = url;
} else {
this.logger.warn("AppCache manifest file location can't be automatically calculated for index.html");
}
}
compiled = ejs.compile(assets["index_template"]);
this._index_content = compiled(namespace);
return this._index_content;
};
Builder.prototype._create_appcache = function() {
var assets, compiled, content, filename, filepath, relative, template, url, _i, _len, _ref;
assets = {};
_ref = this.cached;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
filename = _ref[_i];
filepath = path.resolve(this.root, filename);
relative = this._relativate(filepath);
url = this._host_path(relative);
if (url == null) {
continue;
}
content = fs.readFileSync(filepath, {
encoding: "utf8"
});
assets[url] = this.calc_hash(content);
}
if (this.index != null) {
filepath = path.resolve(this.root, this.index);
relative = this._relativate(filepath);
url = this._host_path(relative);
if (url != null) {
filename = path.resolve(this.root, this.index);
assets[url] = this.calc_hash(this._index_content);
}
}
if (Object.keys(assets).length === 0) {
if (this.index != null) {
this.logger.warn("No hosting rule for `" + this.index + "` file. AppCache manifest `" + this.appcache + "` appears to be empty");
} else {
this.logger.warn("There are no assets to be included into AppCache manifest `" + this.appcache + "`");
}
}
template = this.assets["appcache_template"];
compiled = ejs.compile(fs.readFileSync(template, {
encoding: "utf8"
}));
content = compiled({
cached: assets
});
return content;
};
Builder.prototype._print_roots = function() {
var all_deps, dep, dep_path, message, module, num, roots, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3, _results;
all_deps = [];
_ref = this._modules;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
module = _ref[_i];
_ref1 = module.deps_ids;
for (dep_path in _ref1) {
dep = _ref1[dep_path];
all_deps.push(dep);
}
}
roots = [];
_ref2 = this._modules;
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
module = _ref2[_j];
if (_ref3 = module.id, __indexOf.call(all_deps, _ref3) >= 0) {
continue;
}
roots.push(module);
}
if (roots.length === 0) {
return;
}
this.logger.info("Possible roots: ");
_results = [];
for (num in roots) {
module = roots[num];
message = _.sprintf("%(num)3s %(module.relative)s", {
num: parseInt(num) + 1,
module: module
});
_results.push(this.logger.info(message));
}
return _results;
};
Builder.prototype._print_stats = function() {
var message, module, num, total, _ref;
this.logger.info("Statistics: ");
total = 0;
_ref = this._modules;
for (num in _ref) {
module = _ref[num];
total += module.size;
message = _.sprintf("%(num)3s %(module.relative)-40s %(module.size)7s %(type)-11s %(module.hash)s", {
num: parseInt(num) + 1,
module: module,
type: module.type === "amd" ? module.type + "/" + module.amdtype : module.type
});
this.logger.info(message);
}
return this.logger.info("Total " + total + " bytes in " + this._modules.length + " files");
};
Builder.prototype.build = function() {
this._clear();
this._enlist();
this._analyze();
this._host();
this._set_ids();
this._link();
if (this.print_roots) {
this._print_roots();
}
this._sort();
this._encode();
if (this.manifest != null) {
this._write_file(this.manifest, this._stringify_json(this._create_manifest()));
}
if (this.hosting_map != null) {
this._write_file(this.hosting_map, this._stringify_json(this._create_hosting_map()));
}
if (this.index != null) {
this._write_file(this.index, this._create_index());
}
if (this.appcache != null) {
this._write_file(this.appcache, this._create_appcache());
}
if (this.bundle != null) {
this._write_file(this.bundle, this._bundle_content);
}
if (this.print_stats) {
this._print_stats();
}
this.cache.flush();
return this._manifest_content;
};
return Builder;
})();
hasBOM = function(data) {
if (data.length < 3) {
return false;
}
if (data[0] !== 0xef) {
return false;
}
if (data[1] !== 0xbb) {
return false;
}
if (data[2] !== 0xbf) {
return false;
}
return true;
};
load_json = function(filepath) {
var source;
if (filepath == null) {
return;
}
source = fs.readFileSync(filepath);
return JSON.parse(source);
};
load_yaml = function(filepath) {
var data, source;
if (filepath == null) {
return;
}
data = fs.readFileSync(filepath);
source = data.toString("utf8", hasBOM(data) ? 3 : 0);
return yaml.safeLoad(source);
};
get_config_content = function(filepath) {
switch (path.extname(filepath)) {
case ".yaml":
case ".yml":
return load_yaml(filepath);
case ".json":
return load_json(filepath);
}
};
Builder.from_config = function(config_path, options) {
var basedir, config, name, value, _ref;
basedir = path.dirname(config_path);
config = get_config_content(config_path);
_ref = options != null ? options : {};
for (name in _ref) {
if (!__hasProp.call(_ref, name)) continue;
value = _ref[name];
config[name] = value;
}
if (config.root == null) {
config.root = ".";
}
config.root = path.resolve(basedir, config.root);
return new Builder(config);
};
exports.Builder = Builder;
exports.CyclicDependenciesError = CyclicDependenciesError;
exports.UnresolvedDependencyError = UnresolvedDependencyError;
exports.ExternalDependencyError = ExternalDependencyError;
exports.ModuleTypeError = ModuleTypeError;
exports.ModuleFileOverwritingError = ModuleFileOverwritingError;
exports.HostingUrlOverwritingError = HostingUrlOverwritingError;
exports.Loop = Loop;
exports.Logger = Logger;
exports.DB = DB;
exports.hashers = hashers;
exports.encoders = encoders;