File: /var/www/zaklada/html/node_modules/commoner/lib/commoner.js
var assert = require("assert");
var path = require("path");
var fs = require("fs");
var Q = require("q");
var iconv = require("iconv-lite");
var ReadFileCache = require("./cache").ReadFileCache;
var Watcher = require("./watcher").Watcher;
var contextModule = require("./context");
var BuildContext = contextModule.BuildContext;
var PreferredFileExtension = contextModule.PreferredFileExtension;
var ModuleReader = require("./reader").ModuleReader;
var output = require("./output");
var DirOutput = output.DirOutput;
var StdOutput = output.StdOutput;
var util = require("./util");
var log = util.log;
var Ap = Array.prototype;
var each = Ap.forEach;
// Better stack traces for promises.
Q.longStackSupport = true;
function Commoner() {
var self = this;
assert.ok(self instanceof Commoner);
Object.defineProperties(self, {
customVersion: { value: null, writable: true },
customOptions: { value: [] },
resolvers: { value: [] },
processors: { value: [] }
});
}
var Cp = Commoner.prototype;
Cp.version = function(version) {
this.customVersion = version;
return this; // For chaining.
};
// Add custom command line options
Cp.option = function() {
this.customOptions.push(Ap.slice.call(arguments));
return this; // For chaining.
};
// A resolver is a function that takes a module identifier and returns
// the unmodified source of the corresponding module, either as a string
// or as a promise for a string.
Cp.resolve = function() {
each.call(arguments, function(resolver) {
assert.strictEqual(typeof resolver, "function");
this.resolvers.push(resolver);
}, this);
return this; // For chaining.
};
// A processor is a function that takes a module identifier and a string
// representing the source of the module and returns a modified version of
// the source, either as a string or as a promise for a string.
Cp.process = function(processor) {
each.call(arguments, function(processor) {
assert.strictEqual(typeof processor, "function");
this.processors.push(processor);
}, this);
return this; // For chaining.
};
Cp.buildP = function(options, roots) {
var self = this;
var sourceDir = options.sourceDir;
var outputDir = options.outputDir;
var readFileCache = new ReadFileCache(sourceDir, options.sourceCharset);
var waiting = 0;
var output = outputDir
? new DirOutput(outputDir)
: new StdOutput;
if (self.watch) {
new Watcher(readFileCache).on("changed", function(file) {
log.err(file + " changed; rebuilding...", "yellow");
rebuild();
});
}
function outputModules(modules) {
// Note that output.outputModules comes pre-bound.
modules.forEach(output.outputModule);
return modules;
}
function finish(result) {
rebuild.ing = false;
if (waiting > 0) {
waiting = 0;
process.nextTick(rebuild);
}
return result;
}
function rebuild() {
if (rebuild.ing) {
waiting += 1;
return;
}
rebuild.ing = true;
var context = new BuildContext(options, readFileCache);
if (self.preferredFileExtension)
context.setPreferredFileExtension(
self.preferredFileExtension);
context.setCacheDirectory(self.cacheDir);
context.setIgnoreDependencies(self.ignoreDependencies);
context.setRelativize(self.relativize);
context.setUseProvidesModule(self.useProvidesModule);
return new ModuleReader(
context,
self.resolvers,
self.processors
).readMultiP(context.expandIdsOrGlobsP(roots))
.then(context.ignoreDependencies ? pass : collectDepsP)
.then(outputModules)
.then(outputDir ? printModuleIds : pass)
.then(finish, function(err) {
log.err(err.stack);
if (!self.watch) {
// If we're not building with --watch, throw the error
// so that cliBuildP can call process.exit(-1).
throw err;
}
finish();
});
}
return (
// If outputDir is falsy, we can't (and don't need to) mkdirP it.
outputDir ? util.mkdirP : Q
)(outputDir).then(rebuild);
};
function pass(modules) {
return modules;
}
function collectDepsP(rootModules) {
var modules = [];
var seenIds = {};
function traverse(module) {
if (seenIds.hasOwnProperty(module.id))
return Q(modules);
seenIds[module.id] = true;
return module.getRequiredP().then(function(reqs) {
return Q.all(reqs.map(traverse));
}).then(function() {
modules.push(module);
return modules;
});
}
return Q.all(rootModules.map(traverse)).then(
function() { return modules });
}
function printModuleIds(modules) {
log.out(JSON.stringify(modules.map(function(module) {
return module.id;
})));
return modules;
}
Cp.forceResolve = function(forceId, source) {
this.resolvers.unshift(function(id) {
if (id === forceId)
return source;
});
};
Cp.cliBuildP = function() {
var version = this.customVersion || require("../package.json").version;
return Q.spread([this, version], cliBuildP);
};
function cliBuildP(commoner, version) {
var options = require("commander");
var workingDir = process.cwd();
var sourceDir = workingDir;
var outputDir = null;
var roots;
options.version(version)
.usage("[options] <source directory> <output directory> [<module ID> [<module ID> ...]]")
.option("-c, --config [file]", "JSON configuration file (no file or - means STDIN)")
.option("-w, --watch", "Continually rebuild")
.option("-x, --extension <js | coffee | ...>",
"File extension to assume when resolving module identifiers")
.option("--relativize", "Rewrite all module identifiers to be relative")
.option("--follow-requires", "Scan modules for required dependencies")
.option("--use-provides-module", "Respect @providesModules pragma in files")
.option("--cache-dir <directory>", "Alternate directory to use for disk cache")
.option("--no-cache-dir", "Disable the disk cache")
.option("--source-charset <utf8 | win1252 | ...>",
"Charset of source (default: utf8)")
.option("--output-charset <utf8 | win1252 | ...>",
"Charset of output (default: utf8)");
commoner.customOptions.forEach(function(customOption) {
options.option.apply(options, customOption);
});
options.parse(process.argv.slice(0));
var pfe = new PreferredFileExtension(options.extension || "js");
// TODO Decide whether passing options to buildP via instance
// variables is preferable to passing them as arguments.
commoner.preferredFileExtension = pfe;
commoner.watch = options.watch;
commoner.ignoreDependencies = !options.followRequires;
commoner.relativize = options.relativize;
commoner.useProvidesModule = options.useProvidesModule;
commoner.sourceCharset = normalizeCharset(options.sourceCharset);
commoner.outputCharset = normalizeCharset(options.outputCharset);
function fileToId(file) {
file = absolutePath(workingDir, file);
assert.ok(fs.statSync(file).isFile(), file);
return pfe.trim(path.relative(sourceDir, file));
}
var args = options.args.slice(0);
var argc = args.length;
if (argc === 0) {
if (options.config === true) {
log.err("Cannot read --config from STDIN when reading " +
"source from STDIN");
process.exit(-1);
}
sourceDir = workingDir;
outputDir = null;
roots = ["<stdin>"];
commoner.forceResolve("<stdin>", util.readFromStdinP());
// Ignore dependencies because we wouldn't know how to find them.
commoner.ignoreDependencies = true;
} else {
var first = absolutePath(workingDir, args[0]);
var stats = fs.statSync(first);
if (argc === 1) {
var firstId = fileToId(first);
sourceDir = workingDir;
outputDir = null;
roots = [firstId];
commoner.forceResolve(
firstId,
util.readFileP(first, commoner.sourceCharset)
);
// Ignore dependencies because we wouldn't know how to find them.
commoner.ignoreDependencies = true;
} else if (stats.isDirectory(first)) {
sourceDir = first;
outputDir = absolutePath(workingDir, args[1]);
roots = args.slice(2);
if (roots.length === 0)
roots.push(commoner.preferredFileExtension.glob());
} else {
options.help();
process.exit(-1);
}
}
commoner.cacheDir = null;
if (options.cacheDir === false) {
// Received the --no-cache-dir option, so disable the disk cache.
} else if (typeof options.cacheDir === "string") {
commoner.cacheDir = absolutePath(workingDir, options.cacheDir);
} else if (outputDir) {
// The default cache directory lives inside the output directory.
commoner.cacheDir = path.join(outputDir, ".module-cache");
}
var promise = getConfigP(
workingDir,
options.config
).then(function(config) {
var cleanOptions = {};
options.options.forEach(function(option) {
var name = util.camelize(option.name());
if (options.hasOwnProperty(name)) {
cleanOptions[name] = options[name];
}
});
cleanOptions.version = version;
cleanOptions.config = config;
cleanOptions.sourceDir = sourceDir;
cleanOptions.outputDir = outputDir;
cleanOptions.sourceCharset = commoner.sourceCharset;
cleanOptions.outputCharset = commoner.outputCharset;
return commoner.buildP(cleanOptions, roots);
});
if (!commoner.watch) {
// If we're building from the command line without --watch, any
// build errors should immediately terminate the process with a
// non-zero error code.
promise = promise.catch(function(err) {
log.err(err.stack);
process.exit(-1);
});
}
return promise;
}
function normalizeCharset(charset) {
charset = charset
&& charset.replace(/[- ]/g, "").toLowerCase()
|| "utf8";
assert.ok(
iconv.encodingExists(charset),
"Unrecognized charset: " + charset
);
return charset;
}
function absolutePath(workingDir, pathToJoin) {
if (pathToJoin) {
workingDir = path.normalize(workingDir);
pathToJoin = path.normalize(pathToJoin);
// TODO: use path.isAbsolute when Node < 0.10 is unsupported
if (path.resolve(pathToJoin) !== pathToJoin) {
pathToJoin = path.join(workingDir, pathToJoin);
}
}
return pathToJoin;
}
function getConfigP(workingDir, configFile) {
if (typeof configFile === "undefined")
return Q({}); // Empty config.
if (configFile === true || // --config is present but has no argument
configFile === "<stdin>" ||
configFile === "-" ||
configFile === path.sep + path.join("dev", "stdin")) {
return util.readJsonFromStdinP(
1000, // Time limit in milliseconds before warning displayed.
"Expecting configuration from STDIN (pass --config <file> " +
"if stuck here)...",
"yellow"
);
}
return util.readJsonFileP(absolutePath(workingDir, configFile));
}
exports.Commoner = Commoner;