haste-resolver
Version:
Haste Resolver
323 lines (288 loc) • 11.8 kB
JavaScript
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var Fastfs = require('../fastfs');
var ModuleCache = require('../ModuleCache');
var crawl = require('../crawlers');
var getPlatformExtension = require('../utils/getPlatformExtension');
var isAbsolutePath = require('absolute-path');
var path = require('../fastpath');
var util = require('util');
var DependencyGraphHelpers = require('./DependencyGraphHelpers');
var ResolutionRequest = require('./ResolutionRequest');
var ResolutionResponse = require('./ResolutionResponse');
var HasteMap = require('./HasteMap');
var DeprecatedAssetMap = require('./DeprecatedAssetMap');
var ERROR_BUILDING_DEP_GRAPH = 'DependencyGraphError';
var defaultActivity = {
startEvent: function startEvent() {},
endEvent: function endEvent() {}
};
var DependencyGraph = (function () {
function DependencyGraph(_ref) {
var activity = _ref.activity;
var roots = _ref.roots;
var ignoreFilePath = _ref.ignoreFilePath;
var fileWatcher = _ref.fileWatcher;
var assetRoots_DEPRECATED = _ref.assetRoots_DEPRECATED;
var assetExts = _ref.assetExts;
var providesModuleNodeModules = _ref.providesModuleNodeModules;
var platforms = _ref.platforms;
var preferNativePlatform = _ref.preferNativePlatform;
var cache = _ref.cache;
var extensions = _ref.extensions;
var mocksPattern = _ref.mocksPattern;
var extractRequires = _ref.extractRequires;
var transformCode = _ref.transformCode;
var _ref$shouldThrowOnUnresolvedErrors = _ref.shouldThrowOnUnresolvedErrors;
var shouldThrowOnUnresolvedErrors = _ref$shouldThrowOnUnresolvedErrors === undefined ? function () {
return true;
} : _ref$shouldThrowOnUnresolvedErrors;
var enableAssetMap = _ref.enableAssetMap;
_classCallCheck(this, DependencyGraph);
this._opts = {
activity: activity || defaultActivity,
roots: roots,
ignoreFilePath: ignoreFilePath || function () {},
fileWatcher: fileWatcher,
assetRoots_DEPRECATED: assetRoots_DEPRECATED || [],
assetExts: assetExts || [],
providesModuleNodeModules: providesModuleNodeModules,
platforms: platforms || [],
preferNativePlatform: preferNativePlatform || false,
extensions: extensions || ['js', 'json'],
mocksPattern: mocksPattern,
extractRequires: extractRequires,
transformCode: transformCode,
shouldThrowOnUnresolvedErrors: shouldThrowOnUnresolvedErrors,
enableAssetMap: enableAssetMap || true
};
this._cache = cache;
this._helpers = new DependencyGraphHelpers(this._opts);
this.load();
}
_createClass(DependencyGraph, [{
key: 'load',
value: function load() {
var _this = this;
if (this._loading) {
return this._loading;
}
var activity = this._opts.activity;
var depGraphActivity = activity.startEvent('Building Dependency Graph');
var crawlActivity = activity.startEvent('Crawling File System');
var allRoots = this._opts.roots.concat(this._opts.assetRoots_DEPRECATED);
this._crawling = crawl(allRoots, {
ignore: this._opts.ignoreFilePath,
exts: this._opts.extensions.concat(this._opts.assetExts),
fileWatcher: this._opts.fileWatcher
});
this._crawling.then(function (files) {
return activity.endEvent(crawlActivity);
});
this._fastfs = new Fastfs('JavaScript', this._opts.roots, this._opts.fileWatcher, {
ignore: this._opts.ignoreFilePath,
crawling: this._crawling,
activity: activity
});
this._fastfs.on('change', this._processFileChange.bind(this));
this._moduleCache = new ModuleCache({
fastfs: this._fastfs,
cache: this._cache,
extractRequires: this._opts.extractRequires,
transformCode: this._opts.transformCode,
depGraphHelpers: this._helpers
});
this._hasteMap = new HasteMap({
fastfs: this._fastfs,
extensions: this._opts.extensions,
moduleCache: this._moduleCache,
preferNativePlatform: this._opts.preferNativePlatform,
helpers: this._helpers
});
this._deprecatedAssetMap = new DeprecatedAssetMap({
fsCrawl: this._crawling,
roots: this._opts.assetRoots_DEPRECATED,
helpers: this._helpers,
fileWatcher: this._opts.fileWatcher,
ignoreFilePath: this._opts.ignoreFilePath,
assetExts: this._opts.assetExts,
activity: this._opts.activity,
enabled: this._opts.enableAssetMap
});
this._loading = Promise.all([this._fastfs.build().then(function () {
var hasteActivity = activity.startEvent('Building Haste Map');
return _this._hasteMap.build().then(function (map) {
activity.endEvent(hasteActivity);
return map;
});
}), this._deprecatedAssetMap.build()]).then(function (response) {
activity.endEvent(depGraphActivity);
return response[0]; // Return the haste map
}, function (err) {
var error = new Error('Failed to build DependencyGraph: ' + err.message);
error.type = ERROR_BUILDING_DEP_GRAPH;
error.stack = err.stack;
throw error;
});
return this._loading;
}
/**
* Returns a promise with the direct dependencies the module associated to
* the given entryPath has.
*/
}, {
key: 'getShallowDependencies',
value: function getShallowDependencies(entryPath, transformOptions) {
return this._moduleCache.getModule(entryPath).getDependencies(transformOptions);
}
}, {
key: 'getFS',
value: function getFS() {
return this._fastfs;
}
/**
* Returns the module object for the given path.
*/
}, {
key: 'getModuleForPath',
value: function getModuleForPath(entryFile) {
return this._moduleCache.getModule(entryFile);
}
}, {
key: 'getAllModules',
value: function getAllModules() {
var _this2 = this;
return this.load().then(function () {
return _this2._moduleCache.getAllModules();
});
}
}, {
key: 'getDependencies',
value: function getDependencies(_ref2) {
var _this3 = this;
var entryPath = _ref2.entryPath;
var platform = _ref2.platform;
var transformOptions = _ref2.transformOptions;
var onProgress = _ref2.onProgress;
var _ref2$recursive = _ref2.recursive;
var recursive = _ref2$recursive === undefined ? true : _ref2$recursive;
return this.load().then(function () {
platform = _this3._getRequestPlatform(entryPath, platform);
var absPath = path.resolve(entryPath);
var req = new ResolutionRequest({
platform: platform,
preferNativePlatform: _this3._opts.preferNativePlatform,
entryPath: absPath,
deprecatedAssetMap: _this3._deprecatedAssetMap,
hasteMap: _this3._hasteMap,
helpers: _this3._helpers,
moduleCache: _this3._moduleCache,
fastfs: _this3._fastfs,
shouldThrowOnUnresolvedErrors: _this3._opts.shouldThrowOnUnresolvedErrors
});
var response = new ResolutionResponse({ transformOptions: transformOptions });
return req.getOrderedDependencies({
response: response,
mocksPattern: _this3._opts.mocksPattern,
transformOptions: transformOptions,
onProgress: onProgress,
recursive: recursive
}).then(function () {
return response;
});
});
}
}, {
key: 'matchFilesByPattern',
value: function matchFilesByPattern(pattern) {
var _this4 = this;
return this.load().then(function () {
return _this4._fastfs.matchFilesByPattern(pattern);
});
}
}, {
key: '_getRequestPlatform',
value: function _getRequestPlatform(entryPath, platform) {
if (platform == null) {
platform = getPlatformExtension(entryPath);
if (platform == null || this._opts.platforms.indexOf(platform) === -1) {
platform = null;
}
} else if (this._opts.platforms.indexOf(platform) === -1) {
throw new Error('Unrecognized platform: ' + platform);
}
return platform;
}
}, {
key: '_getAbsolutePath',
value: function _getAbsolutePath(filePath) {
if (isAbsolutePath(filePath)) {
return path.resolve(filePath);
}
for (var i = 0; i < this._opts.roots.length; i++) {
var root = this._opts.roots[i];
var potentialAbsPath = path.join(root, filePath);
if (this._fastfs.fileExists(potentialAbsPath)) {
return path.resolve(potentialAbsPath);
}
}
throw new NotFoundError('Cannot find entry file %s in any of the roots: %j', filePath, this._opts.roots);
}
}, {
key: '_processFileChange',
value: function _processFileChange(type, filePath, root, fstat) {
var _this5 = this;
var absPath = path.join(root, filePath);
if (fstat && fstat.isDirectory() || this._opts.ignoreFilePath(absPath) || this._helpers.isNodeModulesDir(absPath)) {
return;
}
// Ok, this is some tricky promise code. Our requirements are:
// * we need to report back failures
// * failures shouldn't block recovery
// * Errors can leave `hasteMap` in an incorrect state, and we need to rebuild
// After we process a file change we record any errors which will also be
// reported via the next request. On the next file change, we'll see that
// we are in an error state and we should decide to do a full rebuild.
var resolve = function resolve() {
if (_this5._hasteMapError) {
console.warn('Rebuilding haste map to recover from error:\n' + _this5._hasteMapError.stack);
_this5._hasteMapError = null;
// Rebuild the entire map if last change resulted in an error.
_this5._loading = _this5._hasteMap.build();
} else {
_this5._loading = _this5._hasteMap.processFileChange(type, absPath);
_this5._loading['catch'](function (e) {
return _this5._hasteMapError = e;
});
}
return _this5._loading;
};
this._loading = this._loading.then(resolve, resolve);
}
}, {
key: 'createPolyfill',
value: function createPolyfill(options) {
return this._moduleCache.createPolyfill(options);
}
}]);
return DependencyGraph;
})();
function NotFoundError() {
Error.call(this);
Error.captureStackTrace(this, this.constructor);
var msg = util.format.apply(util, arguments);
this.message = msg;
this.type = this.name = 'NotFoundError';
this.status = 404;
}
util.inherits(NotFoundError, Error);
module.exports = DependencyGraph;