haste-resolver
Version:
Haste Resolver
265 lines (233 loc) • 9.39 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 _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
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 crypto = require('crypto');
var docblock = require('./DependencyGraph/docblock');
var isAbsolutePath = require('absolute-path');
var jsonStableStringify = require('json-stable-stringify');
var path = require('./fastpath');
var extractRequires = require('./utils/extractRequires');
var Module = (function () {
function Module(_ref) {
var file = _ref.file;
var fastfs = _ref.fastfs;
var moduleCache = _ref.moduleCache;
var cache = _ref.cache;
var _ref$extractor = _ref.extractor;
var extractor = _ref$extractor === undefined ? extractRequires : _ref$extractor;
var transformCode = _ref.transformCode;
var depGraphHelpers = _ref.depGraphHelpers;
_classCallCheck(this, Module);
if (!isAbsolutePath(file)) {
throw new Error('Expected file to be absolute path but got ' + file);
}
this.path = file;
this.type = 'Module';
this._fastfs = fastfs;
this._moduleCache = moduleCache;
this._cache = cache;
this._extractor = extractor;
this._transformCode = transformCode;
this._depGraphHelpers = depGraphHelpers;
}
_createClass(Module, [{
key: 'isHaste',
value: function isHaste() {
var _this = this;
return this._cache.get(this.path, 'isHaste', function () {
return _this._readDocBlock().then(function (_ref2) {
var id = _ref2.id;
return !!id;
});
});
}
}, {
key: 'getCode',
value: function getCode(transformOptions) {
return this.read(transformOptions).then(function (_ref3) {
var code = _ref3.code;
return code;
});
}
}, {
key: 'getMap',
value: function getMap(transformOptions) {
return this.read(transformOptions).then(function (_ref4) {
var map = _ref4.map;
return map;
});
}
}, {
key: 'getName',
value: function getName() {
var _this2 = this;
return this._cache.get(this.path, 'name', function () {
return _this2._readDocBlock().then(function (_ref5) {
var id = _ref5.id;
if (id) {
return id;
}
var p = _this2.getPackage();
if (!p) {
// Name is full path
return _this2.path;
}
return p.getName().then(function (name) {
if (!name) {
return _this2.path;
}
return path.join(name, path.relative(p.root, _this2.path)).replace(/\\/g, '/');
});
});
});
}
}, {
key: 'getPackage',
value: function getPackage() {
return this._moduleCache.getPackageForModule(this);
}
}, {
key: 'getDependencies',
value: function getDependencies(transformOptions) {
return this.read(transformOptions).then(function (data) {
return data.dependencies;
});
}
}, {
key: 'invalidate',
value: function invalidate() {
this._cache.invalidate(this.path);
}
}, {
key: '_parseDocBlock',
value: function _parseDocBlock(docBlock) {
// Extract an id for the module if it's using @providesModule syntax
// and if it's NOT in node_modules (and not a whitelisted node_module).
// This handles the case where a project may have a dep that has @providesModule
// docblock comments, but doesn't want it to conflict with whitelisted @providesModule
// modules, such as react-haste, fbjs-haste, or react-native or with non-dependency,
// project-specific code that is using @providesModule.
var moduleDocBlock = docblock.parseAsObject(docBlock);
var provides = moduleDocBlock.providesModule || moduleDocBlock.provides;
var id = provides && !this._depGraphHelpers.isNodeModulesDir(this.path) ? /^\S+/.exec(provides)[0] : undefined;
return { id: id, moduleDocBlock: moduleDocBlock };
}
}, {
key: '_readDocBlock',
value: function _readDocBlock(contentPromise) {
var _this3 = this;
if (!this._docBlock) {
if (!contentPromise) {
contentPromise = this._fastfs.readWhile(this.path, whileInDocBlock);
}
this._docBlock = contentPromise.then(function (docBlock) {
return _this3._parseDocBlock(docBlock);
});
}
return this._docBlock;
}
}, {
key: 'read',
value: function read(transformOptions) {
var _this4 = this;
return this._cache.get(this.path, cacheKey('moduleData', transformOptions), function () {
var fileContentPromise = _this4._fastfs.readFile(_this4.path);
return Promise.all([fileContentPromise, _this4._readDocBlock(fileContentPromise)]).then(function (_ref6) {
var _ref62 = _slicedToArray(_ref6, 2);
var source = _ref62[0];
var _ref62$1 = _ref62[1];
var id = _ref62$1.id;
var moduleDocBlock = _ref62$1.moduleDocBlock;
// Ignore requires in JSON files or generated code. An example of this
// is prebuilt files like the SourceMap library.
var extern = _this4.isJSON() || 'extern' in moduleDocBlock;
if (extern) {
transformOptions = _extends({}, transformOptions, { extern: extern });
}
var transformCode = _this4._transformCode;
var codePromise = transformCode ? transformCode(_this4, source, transformOptions) : Promise.resolve({ code: source });
return codePromise.then(function (result) {
var code = result.code;
var _result$dependencies = result.dependencies;
var dependencies = _result$dependencies === undefined ? extern ? [] : _this4._extractor(code).deps.sync : _result$dependencies;
return _extends({}, result, { dependencies: dependencies, id: id, source: source });
});
});
});
}
}, {
key: 'hash',
value: function hash() {
return 'Module : ' + this.path;
}
}, {
key: 'isJSON',
value: function isJSON() {
return path.extname(this.path) === '.json';
}
}, {
key: 'isAsset',
value: function isAsset() {
return false;
}
}, {
key: 'isPolyfill',
value: function isPolyfill() {
return false;
}
}, {
key: 'isAsset_DEPRECATED',
value: function isAsset_DEPRECATED() {
return false;
}
}, {
key: 'toJSON',
value: function toJSON() {
return {
hash: this.hash(),
isJSON: this.isJSON(),
isAsset: this.isAsset(),
isAsset_DEPRECATED: this.isAsset_DEPRECATED(),
type: this.type,
path: this.path
};
}
}]);
return Module;
})();
function whileInDocBlock(chunk, i, result) {
// consume leading whitespace
if (!/\S/.test(result)) {
return true;
}
// check for start of doc block
if (!/^\s*\/(\*{2}|\*?$)/.test(result)) {
return false;
}
// check for end of doc block
return !/\*\//.test(result);
}
// use weak map to speed up hash creation of known objects
var knownHashes = new WeakMap();
function stableObjectHash(object) {
var digest = knownHashes.get(object);
if (!digest) {
digest = crypto.createHash('md5').update(jsonStableStringify(object)).digest('base64');
knownHashes.set(object, digest);
}
return digest;
}
function cacheKey(field, transformOptions) {
return transformOptions !== undefined ? stableObjectHash(transformOptions) + '\0' + field : field;
}
module.exports = Module;