bit-bin
Version:
<a href="https://opensource.org/licenses/Apache-2.0"><img alt="apache" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a> <a href="https://github.com/teambit/bit/blob/master/CONTRIBUTING.md"><img alt="prs" src="https://img.shields.io/b
310 lines (245 loc) • 9.46 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
function _Config() {
const data = _interopRequireDefault(require("./Config"));
_Config = function () {
return data;
};
return data;
}
function _filingCabinet() {
const data = _interopRequireDefault(require("../filing-cabinet"));
_filingCabinet = function () {
return data;
};
return data;
}
function _precinct() {
const data = _interopRequireDefault(require("../precinct"));
_precinct = function () {
return data;
};
return data;
}
/**
* this file had been forked from https://github.com/dependents/node-dependency-tree
*/
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const debug = require('debug')('tree'); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const fs = require('fs'); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
/**
* Recursively find all dependencies (avoiding circular) traversing the entire dependency tree
* and returns a flat list of all unique, visited nodes
*
* @param {Object} options
* @param {String} options.filename - The path of the module whose tree to traverse
* @param {String} options.directory - The directory containing all JS files
* @param {String} [options.requireConfig] - The path to a requirejs config
* @param {String} [options.webpackConfig] - The path to a webpack config
* @param {Object} [options.visited] - Cache of visited, absolutely pathed files that should not be reprocessed.
* Format is a filename -> tree as list lookup table
* @param {Array} [options.nonExistent] - List of partials that do not exist
* @return {Object}
*/
function _default(options) {
const config = new (_Config().default)(options);
if (!fs.existsSync(config.filename)) {
debug(`file ${config.filename} does not exist`);
return {};
}
return traverse(config);
}
/**
* Executes a post-order depth first search on the dependency tree and returns a
* list of absolute file paths. The order of files in the list will be the
* proper concatenation order for bundling.
*
* In other words, for any file in the list, all of that file's dependencies (direct or indirect) will appear at
* lower indices in the list. The root (entry point) file will therefore appear last.
*
* The list will not contain duplicates.
*
* Params are those of module.exports
*/
module.exports.toList = function (options) {
options.isListForm = true;
return module.exports(options);
};
/**
* Returns the list of dependencies for the given filename
*
* Protected for testing
*
* @param {Config} config
* @return {Array}
*/
module.exports._getDependencies = function (config) {
let dependenciesRaw; // from some detectives it comes as an array, from some it is an object
const precinctOptions = config.detectiveConfig;
precinctOptions.includeCore = false; // @ts-ignore
delete _precinct().default.ast;
try {
dependenciesRaw = _precinct().default.paperwork(config.filename, precinctOptions);
} catch (e) {
debug(`error getting dependencies: ${e.message}`);
debug(e.stack);
e.code = 'PARSING_ERROR';
config.errors[config.filename] = e;
dependenciesRaw = [];
}
const dependencies = typeof dependenciesRaw === 'object' && !Array.isArray(dependenciesRaw) ? Object.keys(dependenciesRaw) : dependenciesRaw;
const isDependenciesArray = Array.isArray(dependenciesRaw);
debug(`extracted ${dependencies.length} dependencies: `, dependencies);
const resolvedDependencies = [];
const pathMapDependencies = [];
const pathMapFile = {
file: config.filename
};
dependencies.forEach(dependency => processDependency(dependency)); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
pathMapFile.dependencies = pathMapDependencies;
config.pathMap.push(pathMapFile);
return resolvedDependencies;
function processDependency(dependency) {
if (isHttp(dependency)) {
debug(`skipping an http dependency: ${dependency}`);
return;
}
const cabinetParams = {
dependency,
filename: config.filename,
directory: config.directory,
// @ts-ignore
ast: _precinct().default.ast,
config: config.requireConfig,
webpackConfig: config.webpackConfig,
resolveConfig: config.resolveConfig
};
if (!isDependenciesArray && dependenciesRaw[dependency].isScript !== undefined) {
// used for vue
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
cabinetParams.isScript = dependenciesRaw[dependency].isScript;
}
let result;
try {
result = (0, _filingCabinet().default)(cabinetParams);
} catch (err) {
debug(`error resolving dependencies: ${err.message}`);
debug(err.stack);
err.code = 'RESOLVE_ERROR';
throw err;
}
if (!result) {
debug(`skipping an empty filepath resolution for dependency: ${dependency}`);
addToNonExistent(dependency);
return;
}
const exists = fs.existsSync(result);
if (!exists) {
addToNonExistent(dependency);
debug(`skipping non-empty but non-existent resolution: ${result} for dependency: ${dependency}`);
return;
}
const pathMap = {
importSource: dependency,
resolvedDep: result
};
if (!isDependenciesArray && dependenciesRaw[dependency].importSpecifiers) {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
pathMap.importSpecifiers = dependenciesRaw[dependency].importSpecifiers;
} // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (cabinetParams.wasCustomResolveUsed) {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
pathMap.isCustomResolveUsed = true;
} // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
pathMapDependencies.push(pathMap); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
resolvedDependencies.push(result);
}
function addToNonExistent(dependency) {
if (config.nonExistent[config.filename]) {
config.nonExistent[config.filename].push(dependency);
} else {
config.nonExistent[config.filename] = [dependency];
}
}
};
/**
* the traverse is not a recursive function anymore, it has been changed to be iterative to fix
* some performance issues.
* @todo: we have some redundancy here with the `tree` and pathMap`. the `tree` has only the dependencies,
* `pathMap` has the dependencies and some more info, such as importSpecifiers. we should use only
* pathMap and get rid of tree.
*/
function traverse(config) {
const tree = [];
const stack = [config.filename];
while (stack.length) {
const dependency = stack.pop();
debug(`traversing ${dependency}`);
if (config.visited[dependency]) {
populateFromCache(dependency);
} else {
traverseDependency(dependency);
}
}
return tree;
function traverseDependency(dependency) {
const localConfig = config.clone();
localConfig.filename = dependency;
let dependencies = module.exports._getDependencies(localConfig);
if (config.filter) {
debug('using filter function to filter out dependencies');
debug(`number of dependencies before filtering: ${dependencies.length}`);
dependencies = dependencies.filter(function (filePath) {
return localConfig.filter(filePath, localConfig.filename);
});
debug(`number of dependencies after filtering: ${dependencies.length}`);
}
debug('cabinet-resolved all dependencies: ', dependencies); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
tree[dependency] = dependencies;
const filePathMap = config.pathMap.find(pathMapEntry => pathMapEntry.file === dependency);
if (!filePathMap) throw new Error(`file ${dependency} is missing from PathMap`);
config.visited[dependency] = {
pathMap: filePathMap,
missing: config.nonExistent[dependency],
error: config.errors[dependency]
};
stack.push(...dependencies);
}
function populateFromCache(dependency) {
debug(`already visited ${dependency}. Will try to find it and its dependencies in the cache`);
const dependenciesStack = [dependency];
while (dependenciesStack.length) {
findAllDependenciesInCache(dependenciesStack);
}
}
function findAllDependenciesInCache(dependenciesStack) {
const dependency = dependenciesStack.pop();
if (!config.visited[dependency]) {
debug(`unable to find ${dependency} in the cache, it was probably filtered before`);
return;
}
debug(`found ${dependency} in the cache`);
const dependencies = config.visited[dependency].pathMap.dependencies.map(d => d.resolvedDep); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
tree[dependency] = dependencies;
config.pathMap.push(config.visited[dependency].pathMap);
if (config.visited[dependency].missing) {
config.nonExistent[dependency] = config.visited[dependency].missing;
}
if (config.visited[dependency].error) {
config.errors[dependency] = config.visited[dependency].error;
}
dependencies.forEach(d => {
if (!tree[d]) dependenciesStack.push(d);
});
}
}
/**
* whether the dependency is from CDN. (http/https)
*/
function isHttp(dependency) {
return Boolean(dependency.startsWith('http://') || dependency.startsWith('https://'));
}
;