123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- var assert = require("assert");
- var path = require("path");
- var Q = require("q");
- var util = require("./util");
- var spawn = require("child_process").spawn;
- var ReadFileCache = require("./cache").ReadFileCache;
- var grepP = require("./grep");
- var glob = require("glob");
- var env = process.env;
- function BuildContext(options, readFileCache) {
- var self = this;
- assert.ok(self instanceof BuildContext);
- assert.ok(readFileCache instanceof ReadFileCache);
- if (options) {
- assert.strictEqual(typeof options, "object");
- } else {
- options = {};
- }
- Object.freeze(options);
- Object.defineProperties(self, {
- readFileCache: { value: readFileCache },
- config: { value: options.config },
- options: { value: options },
- optionsHash: { value: util.deepHash(options) }
- });
- }
- var BCp = BuildContext.prototype;
- BCp.makePromise = function(callback, context) {
- return util.makePromise(callback, context);
- };
- BCp.spawnP = function(command, args, kwargs) {
- args = args || [];
- kwargs = kwargs || {};
- var deferred = Q.defer();
- var outs = [];
- var errs = [];
- var options = {
- stdio: "pipe",
- env: env
- };
- if (kwargs.cwd) {
- options.cwd = kwargs.cwd;
- }
- var child = spawn(command, args, options);
- child.stdout.on("data", function(data) {
- outs.push(data);
- });
- child.stderr.on("data", function(data) {
- errs.push(data);
- });
- child.on("close", function(code) {
- if (errs.length > 0 || code !== 0) {
- var err = {
- code: code,
- text: errs.join("")
- };
- }
- deferred.resolve([err, outs.join("")]);
- });
- var stdin = kwargs && kwargs.stdin;
- if (stdin) {
- child.stdin.end(stdin);
- }
- return deferred.promise;
- };
- BCp.setIgnoreDependencies = function(value) {
- Object.defineProperty(this, "ignoreDependencies", {
- value: !!value
- });
- };
- // This default can be overridden by individual BuildContext instances.
- BCp.setIgnoreDependencies(false);
- BCp.setRelativize = function(value) {
- Object.defineProperty(this, "relativize", {
- value: !!value
- });
- };
- // This default can be overridden by individual BuildContext instances.
- BCp.setRelativize(false);
- BCp.setUseProvidesModule = function(value) {
- Object.defineProperty(this, "useProvidesModule", {
- value: !!value
- });
- };
- // This default can be overridden by individual BuildContext instances.
- BCp.setUseProvidesModule(false);
- BCp.setCacheDirectory = function(dir) {
- if (!dir) {
- // Disable the cache directory.
- } else {
- assert.strictEqual(typeof dir, "string");
- }
- Object.defineProperty(this, "cacheDir", {
- value: dir || null
- });
- };
- // This default can be overridden by individual BuildContext instances.
- BCp.setCacheDirectory(null);
- function PreferredFileExtension(ext) {
- assert.strictEqual(typeof ext, "string");
- assert.ok(this instanceof PreferredFileExtension);
- Object.defineProperty(this, "extension", {
- value: ext.toLowerCase()
- });
- }
- var PFEp = PreferredFileExtension.prototype;
- PFEp.check = function(file) {
- return file.split(".").pop().toLowerCase() === this.extension;
- };
- PFEp.trim = function(file) {
- if (this.check(file)) {
- var len = file.length;
- var extLen = 1 + this.extension.length;
- file = file.slice(0, len - extLen);
- }
- return file;
- };
- PFEp.glob = function() {
- return "**/*." + this.extension;
- };
- exports.PreferredFileExtension = PreferredFileExtension;
- BCp.setPreferredFileExtension = function(pfe) {
- assert.ok(pfe instanceof PreferredFileExtension);
- Object.defineProperty(this, "preferredFileExtension", { value: pfe });
- };
- BCp.setPreferredFileExtension(new PreferredFileExtension("js"));
- BCp.expandIdsOrGlobsP = function(idsOrGlobs) {
- var context = this;
- return Q.all(
- idsOrGlobs.map(this.expandSingleIdOrGlobP, this)
- ).then(function(listOfListsOfIDs) {
- var result = [];
- var seen = {};
- util.flatten(listOfListsOfIDs).forEach(function(id) {
- if (!seen.hasOwnProperty(id)) {
- seen[id] = true;
- if (util.isValidModuleId(id))
- result.push(id);
- }
- });
- return result;
- });
- };
- BCp.expandSingleIdOrGlobP = function(idOrGlob) {
- var context = this;
- return util.makePromise(function(callback) {
- // If idOrGlob already looks like an acceptable identifier, don't
- // try to expand it.
- if (util.isValidModuleId(idOrGlob)) {
- callback(null, [idOrGlob]);
- return;
- }
- glob(idOrGlob, {
- cwd: context.readFileCache.sourceDir
- }, function(err, files) {
- if (err) {
- callback(err);
- } else {
- callback(null, files.filter(function(file) {
- return !context.isHiddenFile(file);
- }).map(function(file) {
- return context.preferredFileExtension.trim(file);
- }));
- }
- });
- });
- };
- BCp.readModuleP = function(id) {
- return this.readFileCache.readFileP(
- id + "." + this.preferredFileExtension.extension
- );
- };
- BCp.readFileP = function(file) {
- return this.readFileCache.readFileP(file);
- };
- // Text editors such as VIM and Emacs often create temporary swap files
- // that should be ignored.
- var hiddenExp = /^\.|~$/;
- BCp.isHiddenFile = function(file) {
- return hiddenExp.test(path.basename(file));
- };
- BCp.getProvidedP = util.cachedMethod(function() {
- var context = this;
- var pattern = "@providesModule\\s+\\S+";
- return grepP(
- pattern,
- context.readFileCache.sourceDir
- ).then(function(pathToMatch) {
- var idToPath = {};
- Object.keys(pathToMatch).sort().forEach(function(path) {
- if (context.isHiddenFile(path))
- return;
- var id = pathToMatch[path].split(/\s+/).pop();
- // If we're about to overwrite an existing module identifier,
- // make sure the corresponding path ends with the preferred
- // file extension. This allows @providesModule directives in
- // .coffee files, for example, but prevents .js~ temporary
- // files from taking precedence over actual .js files.
- if (!idToPath.hasOwnProperty(id) ||
- context.preferredFileExtension.check(path))
- idToPath[id] = path;
- });
- return idToPath;
- });
- });
- var providesExp = /@providesModule[ ]+(\S+)/;
- BCp.getProvidedId = function(source) {
- var match = providesExp.exec(source);
- return match && match[1];
- };
- exports.BuildContext = BuildContext;
|