UNPKG

hem

Version:

stitches CommonJS, and ties up other lose ends of web-app development.

630 lines (570 loc) 19.4 kB
// Generated by CoffeeScript 1.12.7 (function() { var Application, CssPackage, Dependency, JsPackage, Package, Stitch, TestPackage, _argv, _hem, create, events, fs, log, path, uglifycss, uglifyjs, utils, versioning, slice = [].slice, extend = 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; }, hasProp = {}.hasOwnProperty; fs = require('fs-extra'); path = require('path'); uglifyjs = require('uglify-js'); uglifycss = require('uglifycss'); Dependency = require('./dependency'); Stitch = require('./stitch'); utils = require('./utils'); events = require('./events'); log = require('./log'); versioning = require('./versioning'); _hem = void 0; _argv = void 0; Application = (function() { function Application(name, config) { var defaults, err, key, loadedDefaults, packager, ref, route, value, verType; if (config == null) { config = {}; } this.name = name; this.route = config.route; this.root = config.root; if (config.defaults) { try { loadedDefaults = utils.loadAsset('defaults/' + config.defaults); defaults = utils.extend({}, loadedDefaults); } catch (error) { err = error; log.error("ERROR: Invalid 'defaults' value provided: " + config.defaults); process.exit(1); } config = utils.extend(defaults, config); } if (!this.root) { if (utils.isDirectory(this.name)) { this.root = this.name; this.route || (this.route = "/" + this.name); } else { this.root = "/"; this.route || (this.route = "/"); } } this["static"] = []; this.packages = []; ref = config["static"]; for (route in ref) { value = ref[route]; this["static"].push({ url: this.applyBaseRoute(route), path: this.applyRootDir(value)[0] }); } for (key in config) { value = config[key]; packager = void 0; if (key === 'js' || utils.endsWith(key, '.js')) { packager = JsPackage; value.name = key; } else if (key === 'css' || utils.endsWith(key, '.css')) { packager = CssPackage; value.name = key; } if (packager) { this.packages.push(new packager(this, value)); } } if (config.test) { config.test.name = "test"; this.packages.push(new TestPackage(this, config.test)); } if (config.version) { verType = versioning[config.version.type]; if (!verType) { log.errorAndExit("Incorrect type value for version configuration: (" + config.version.type + ")"); } this.versioning = new verType(this, config.version); } } Application.prototype.getTestPackage = function() { var i, len, pkg, ref; ref = this.packages; for (i = 0, len = ref.length; i < len; i++) { pkg = ref[i]; if (pkg.constructor.name === "TestPackage") { return pkg; } } }; Application.prototype.isMatchingRoute = function(route) { var i, len, pkg, ref; if (this.versioning) { route = this.versioning.trim(route); } ref = this.packages; for (i = 0, len = ref.length; i < len; i++) { pkg = ref[i]; if (route === pkg.route.toLowerCase()) { return pkg; } } }; Application.prototype.unlink = function() { var i, len, pkg, ref, results1; log("Removing application: <green>" + this.name + "</green>"); ref = this.packages; results1 = []; for (i = 0, len = ref.length; i < len; i++) { pkg = ref[i]; results1.push(pkg.unlink()); } return results1; }; Application.prototype.build = function() { var i, len, pkg, ref, results1; log("Building application: <green>" + this.name + "</green>"); ref = this.packages; results1 = []; for (i = 0, len = ref.length; i < len; i++) { pkg = ref[i]; results1.push(pkg.build()); } return results1; }; Application.prototype.watch = function() { var dirs, pkg; log("Watching application: <green>" + this.name + "</green>"); dirs = (function() { var i, len, ref, results1; ref = this.packages; results1 = []; for (i = 0, len = ref.length; i < len; i++) { pkg = ref[i]; results1.push(pkg.watch()); } return results1; }).call(this); if (dirs.length) { return log.info("- Watching directories: <yellow>" + dirs + "</yellow>"); } else { return log.info("- No directories to watch..."); } }; Application.prototype.version = function() { log("Versioning application: <green>" + this.name + "</green>"); if (this.versioning) { return this.versioning.update(); } else { return log.errorAndExit("ERROR: Versioning not enabled in slug.json"); } }; Application.prototype.applyRootDir = function(value) { var values; values = utils.toArray(value); values = values.map((function(_this) { return function(value) { if (utils.startsWith(value, "." + path.sep)) { return value; } else { return utils.cleanPath(_this.root, value); } }; })(this)); return values; }; Application.prototype.applyBaseRoute = function() { var values; values = 1 <= arguments.length ? slice.call(arguments, 0) : []; if (this.route) { values.unshift(this.route); } return utils.cleanRoute.apply(utils, values); }; return Application; })(); Package = (function() { function Package(app, config) { var i, len, ref, regexp, route, targetFile, targetUrl; this.app = app; this.name = config.name; this.src = this.app.applyRootDir(config.src || ""); this.target = this.app.applyRootDir(config.target || "")[0]; if (utils.isDirectory(this.target)) { if (this.name === this.ext) { targetFile = this.app.name; } else { targetFile = this.name; } this.target = utils.cleanPath(this.target, targetFile); } if (!utils.endsWith(this.target, "." + this.ext)) { this.target = this.target + "." + this.ext; } if (config.route) { if (utils.startsWith(this.target, "/")) { this.route = config.route; } else { this.route = this.app.applyBaseRoute(config.route); } } else { ref = this.app["static"]; for (i = 0, len = ref.length; i < len; i++) { route = ref[i]; if (!this.route) { if (utils.startsWith(this.target, route.path)) { regexp = new RegExp("^" + (route.path.replace(/\\/g, "\\\\")) + "(\\\\|\/)?"); targetUrl = this.target.replace(regexp, ""); this.route = utils.cleanRoute(route.url, targetUrl); } } } } if (_argv.command === "server" && !this.route) { log.errorAndExit("Unable to determine route for <yellow>" + this.target + "</yellow>"); } } Package.prototype.handleCompileError = function(ex) { if (_hem.handleCompileError) { _hem.handleCompileError(ex); return; } log.error(ex.message); if (ex.path) { log.error(ex.path); } switch (_argv.command) { case "server": if (this.ext === "js") { return "alert(\"HEM: " + ex + "\\n\\n" + ex.path + "\");"; } else { return ""; } break; case "watch": return ""; default: return process.exit(1); } }; Package.prototype.unlink = function() { if (fs.existsSync(this.target)) { log.info("- removing <yellow>" + this.target + "</yellow>"); return fs.unlinkSync(this.target); } }; Package.prototype.build = function(file) { var dirname, extra, source, write; if (file) { Stitch.clear(file); } extra = (_argv.compress && " <b>--using compression</b>") || ""; log.info("- Building target: <yellow>" + this.target + "</yellow>" + extra); source = this.compile(); write = _argv.command !== "server"; if (source && write) { dirname = path.dirname(this.target); if (!fs.existsSync(dirname)) { fs.mkdirsSync(dirname); } fs.writeFileSync(this.target, source); } return source; }; Package.prototype.watch = function() { var dir, dirs, fileOrDir, i, j, len, len1, ref, watchOptions; watchOptions = { persistent: true, interval: 1, ignoreDotFiles: true, maxListeners: 128 }; dirs = []; ref = this.getWatchedDirs(); for (i = 0, len = ref.length; i < len; i++) { fileOrDir = ref[i]; if (!fs.existsSync(fileOrDir)) { continue; } if (utils.isDirectory(fileOrDir)) { dirs.push(fileOrDir); } else { dirs.push(path.dirname(fileOrDir)); } } dirs = utils.removeDuplicateValues(dirs); for (j = 0, len1 = dirs.length; j < len1; j++) { dir = dirs[j]; require('watch').watchTree(dir, watchOptions, (function(_this) { return function(f, curr, prev) { if (typeof f === "object" && prev === null && curr === null) { return; } console.log('build', f); _this.build(f); return events.emit("watch", _this.app, _this, f); }; })(this)); } return dirs; }; Package.prototype.getWatchedDirs = function() { return this.src; }; Package.prototype.ext = ""; return Package; })(); JsPackage = (function(superClass) { extend(JsPackage, superClass); function JsPackage(app, config) { JsPackage.__super__.constructor.call(this, app, config); this.commonjs = config.commonjs || 'require'; this.libs = this.app.applyRootDir(config.libs || []); this.modules = utils.toArray(config.modules || []); this.before = utils.arrayToString(config.before || ""); this.after = utils.arrayToString(config.after || ""); } JsPackage.prototype.compile = function() { var ex, result; try { result = [this.before, this.compileLibs(), this.compileModules(), this.after].join("\n"); if (_argv.compress) { result = uglifyjs.minify(result, { fromString: true }).code; } return result; } catch (error) { ex = error; return this.handleCompileError(ex); } }; JsPackage.prototype.compileModules = function() { var _modules; this.depend || (this.depend = new Dependency(this.modules)); this.stitch || (this.stitch = new Stitch(this.src)); _modules = this.depend.resolve().concat(this.stitch.resolve()); if (_modules) { return Stitch.template(this.commonjs, _modules); } else { return ""; } }; JsPackage.prototype.compileLibs = function(files, parentDir) { var dir, file, i, len, ref, results, slash, stats; if (files == null) { files = this.libs; } if (parentDir == null) { parentDir = ""; } results = []; for (i = 0, len = files.length; i < len; i++) { file = files[i]; if (utils.endsWith(file, ";")) { results.join(file); } else { slash = parentDir === "" ? "" : path.sep; if (file.startsWith("_")) { continue; } file = parentDir + slash + file; if (fs.existsSync(file)) { stats = fs.lstatSync(file); if (stats.isDirectory()) { dir = fs.readdirSync(file); results.push(this.compileLibs(dir, file)); } else if (stats.isFile() && ((ref = path.extname(file)) === '.js' || ref === '.coffee')) { results.push(fs.readFileSync(file, 'utf8')); } } } } return results.join("\n"); }; JsPackage.prototype.getWatchedDirs = function() { return this.src.concat(this.libs); }; JsPackage.prototype.ext = "js"; return JsPackage; })(Package); TestPackage = (function(superClass) { extend(TestPackage, superClass); function TestPackage(app, config) { var ref; TestPackage.__super__.constructor.call(this, app, config); this.depends = utils.toArray(config.depends); this.testHome = path.dirname(this.target); this.framework = _hem.options.hem.test.frameworks; if ((ref = this.framework) !== 'jasmine' && ref !== 'mocha') { log.errorAndExit("Test frameworks value is not valid: " + this.framework); } this.after += "// HEM: load in specs from test js file\nvar onlyMatchingModules = \"" + (_argv.grep || "") + "\";\nfor (var key in " + this.commonjs + ".modules) {\n if (onlyMatchingModules && key.indexOf(onlyMatchingModules) == -1) {\n continue;\n }\n " + this.commonjs + "(key);\n}"; } TestPackage.prototype.build = function(file) { this.createTestFiles(); return TestPackage.__super__.build.call(this, file); }; TestPackage.prototype.getAllTestTargets = function(relative) { var dep, depapp, homeRoute, i, j, k, l, len, len1, len2, len3, pkg, pth, ref, ref1, ref2, ref3, relativeFn, targets, url; if (relative == null) { relative = true; } targets = []; homeRoute = path.dirname(this.route); relativeFn = function(home, target, url) { var value; if (url == null) { url = true; } value = ""; if (relative) { value = path.relative(home, target); } else { value = target; } if (url) { return value.replace(/\\/g, "/"); } else { return value; } }; ref = this.depends; for (i = 0, len = ref.length; i < len; i++) { dep = ref[i]; ref1 = _hem.allApps; for (j = 0, len1 = ref1.length; j < len1; j++) { depapp = ref1[j]; if (depapp.name === dep) { ref2 = depapp.packages; for (k = 0, len2 = ref2.length; k < len2; k++) { pkg = ref2[k]; if (pkg.constructor.name !== "JsPackage") { continue; } url = relativeFn(homeRoute, pkg.route); pth = relativeFn(this.testHome, pkg.target); targets.push({ url: url, path: pth }); } } } } ref3 = this.app.packages; for (l = 0, len3 = ref3.length; l < len3; l++) { pkg = ref3[l]; if (pkg.constructor.name !== "JsPackage") { continue; } url = relativeFn(homeRoute, pkg.route); pth = relativeFn(this.testHome, pkg.target); targets.push({ url: url, path: pth }); } url = relativeFn(homeRoute, pkg.route); pth = relativeFn(this.testHome, pkg.target); targets.push({ url: url, path: pth }); return targets; }; TestPackage.prototype.getFrameworkFiles = function() { var file, frameworkPath, i, len, ref, ref1, targets, url; targets = []; frameworkPath = path.resolve(__dirname, "../assets/testing/" + this.framework); ref = fs.readdirSync(frameworkPath); for (i = 0, len = ref.length; i < len; i++) { file = ref[i]; if ((ref1 = path.extname(file)) === ".js" || ref1 === ".css") { url = this.framework + "/" + file; targets.push({ url: url, path: url }); } } return targets; }; TestPackage.prototype.getTestIndexFile = function() { return path.resolve(this.testHome, 'index.html'); }; TestPackage.prototype.createTestFiles = function() { var file, filepath, files, frameworkPath, i, indexFile, len, ref, ref1, results1, template; indexFile = this.getTestIndexFile(); if (!fs.existsSync(indexFile)) { files = []; files.push.apply(files, this.getFrameworkFiles()); files.push.apply(files, this.getAllTestTargets()); template = utils.tmpl("testing/index", { commonjs: this.commonjs, files: files, before: this.before }); fs.outputFileSync(indexFile, template); frameworkPath = path.resolve(__dirname, "../assets/testing/" + this.framework); ref = fs.readdirSync(frameworkPath); results1 = []; for (i = 0, len = ref.length; i < len; i++) { file = ref[i]; if ((ref1 = path.extname(file)) === ".js" || ref1 === ".css") { filepath = path.resolve(this.testHome, this.framework + "/" + file); results1.push(utils.copyFile(path.resolve(frameworkPath, file), filepath)); } else { results1.push(void 0); } } return results1; } }; return TestPackage; })(JsPackage); CssPackage = (function(superClass) { extend(CssPackage, superClass); function CssPackage(app, config) { CssPackage.__super__.constructor.call(this, app, config); } CssPackage.prototype.compile = function() { var ex, file, fileOrDir, i, j, len, len1, output, ref, ref1, requireCss, result; try { output = []; requireCss = function(filepath) { filepath = require.resolve(path.resolve(filepath)); delete require.cache[filepath]; return require(filepath); }; ref = this.src; for (i = 0, len = ref.length; i < len; i++) { fileOrDir = ref[i]; if (utils.isDirectory(fileOrDir)) { ref1 = fs.readdirSync(fileOrDir); for (j = 0, len1 = ref1.length; j < len1; j++) { file = ref1[j]; if (!require.extensions[path.extname(file)]) { continue; } file = path.resolve(fileOrDir, file); output.push(requireCss(file)); } } else { output.push(requireCss(fileOrDir)); } } result = output.join("\n"); if (_argv.compress) { result = uglifycss.processString(result); } return result; } catch (error) { ex = error; return this.handleCompileError(ex); } }; CssPackage.prototype.ext = "css"; return CssPackage; })(Package); create = function(name, config, hem, argv) { _hem || (_hem = hem); _argv || (_argv = argv); return new Application(name, config); }; module.exports.create = create; }).call(this);