UNPKG

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

546 lines (421 loc) 14.9 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = cabinet; function _typescript() { const data = _interopRequireDefault(require("typescript")); _typescript = function () { return data; }; return data; } function _path() { const data = _interopRequireDefault(require("path")); _path = function () { return data; }; return data; } function _moduleDefinition() { const data = _interopRequireDefault(require("module-definition")); _moduleDefinition = function () { return data; }; return data; } function _resolve() { const data = _interopRequireDefault(require("resolve")); _resolve = function () { return data; }; return data; } function _moduleLookupAmd() { const data = _interopRequireDefault(require("module-lookup-amd")); _moduleLookupAmd = function () { return data; }; return data; } function _stylusLookup() { const data = _interopRequireDefault(require("stylus-lookup")); _stylusLookup = function () { return data; }; return data; } function _sassLookup() { const data = _interopRequireDefault(require("sass-lookup")); _sassLookup = function () { return data; }; return data; } function _resolveDependencyPath() { const data = _interopRequireDefault(require("resolve-dependency-path")); _resolveDependencyPath = function () { return data; }; return data; } function _appModulePath() { const data = _interopRequireDefault(require("app-module-path")); _appModulePath = function () { return data; }; return data; } function _enhancedResolve() { const data = _interopRequireDefault(require("enhanced-resolve")); _enhancedResolve = function () { return data; }; return data; } function _isRelativePath() { const data = _interopRequireDefault(require("is-relative-path")); _isRelativePath = function () { return data; }; return data; } function _objectAssign() { const data = _interopRequireDefault(require("object-assign")); _objectAssign = function () { return data; }; return data; } function _vueLookup() { const data = _interopRequireDefault(require("../lookups/vue-lookup")); _vueLookup = function () { return data; }; return data; } function _utils() { const data = require("../../../../../utils"); _utils = function () { return data; }; return data; } // @flow /** * this file had been forked from https://github.com/dependents/node-filing-cabinet */ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const debug = require('debug')('cabinet'); const defaultLookups = { '.js': jsLookup, '.jsx': jsLookup, '.ts': tsLookup, '.tsx': tsLookup, '.scss': cssPreprocessorLookup, '.sass': cssPreprocessorLookup, '.styl': _stylusLookup().default, '.less': cssPreprocessorLookup, '.vue': _vueLookup().default }; // for some reason, .ts is not sufficient, .d.ts is needed as well // these extensions are used with commonJs and nonRelative lookups. When a dependency doesn't have an // extension it will look for files with these extensions in order. // for example, `const a = require('.a')`, it'll look for a.js, a.jsx, a.ts and so on. const resolveExtensions = Object.keys(defaultLookups).concat(['.d.ts', '.json', '.css']); // when webpack resolves dependencies from a style file, such as .scss file, look for style extensions only const styleExtensions = ['.scss', '.sass', '.less', '.css']; function cabinet(options) { const { dependency, filename } = options; const ext = options.ext || _path().default.extname(filename); debug(`working on a dependency "${dependency}" of a file "${filename}"`); let resolver = defaultLookups[ext]; if (!resolver) { debug('using generic resolver'); resolver = _resolveDependencyPath().default; } if (ext === '.css' && dependency.startsWith('~')) resolver = cssPreprocessorLookup; debug(`found a resolver ${resolver.name} for ${ext}`); let result = resolver(options); const dependencyExt = _path().default.extname(dependency); if (!result && dependencyExt && dependencyExt !== ext) { resolver = defaultLookups[dependencyExt]; if (resolver) { // todo: this strategy probably fails often. if, for example, a dependency A.js inside B.ts // was not found using the ts resolve, it tries the js resolver, however, parsing the ts file // with js parser, won't work most of the time. A better approach would be to fix the // original resolver. debug(`dependency has a different extension (${dependencyExt}) than the original file (${ext}), trying to use its resolver instead`); try { result = resolver(options); } catch (err) { debug(`unable to use the resolver of ${dependencyExt} for ${filename}. got an error ${err.message}`); } } } debug(`resolved path for ${dependency}: ${result}`); return result; } module.exports.supportedFileExtensions = Object.keys(defaultLookups); /** * Register a custom lookup resolver for a file extension * * @param {String} extension - The file extension that should use the resolver * @param {Function} lookupStrategy - A resolver of dependency paths */ module.exports.register = function (extension, lookupStrategy) { defaultLookups[extension] = lookupStrategy; if (this.supportedFileExtensions.indexOf(extension) === -1) { this.supportedFileExtensions.push(extension); } }; /** * Exposed for testing * * @param {Object} options * @param {String} options.config * @param {String} options.webpackConfig * @param {String} options.filename * @param {Object} options.ast * @return {String} */ function _getJSType(options) { options = options || {}; if (options.config) { return 'amd'; } if (options.webpackConfig) { return 'webpack'; } const ast = options.ast || options.content; if (ast) { debug('reusing the given ast or content'); return _moduleDefinition().default.fromSource(ast); } debug('using the filename to find the module type'); return _moduleDefinition().default.sync(options.filename); } /** * @private * @param {String} dependency * @param {String} filename * @param {String} directory * @param {String} [config] * @param {String} [webpackConfig] * @param {String} [configPath] * @param {Object} [ast] * @return {String} */ function jsLookup(options) { const { configPath, dependency, directory, config, webpackConfig, filename, ast, isScript, content } = options; const type = _getJSType({ config, webpackConfig, filename, ast, isScript, content }); switch (type) { case 'amd': debug('using amd resolver'); return (0, _moduleLookupAmd().default)({ config, // Optional in case a pre-parsed config is being passed in configPath, partial: dependency, directory, filename }); case 'webpack': debug('using webpack resolver for es6'); return resolveWebpackPath(dependency, filename, directory, webpackConfig); case 'commonjs': case 'es6': default: debug(`using commonjs resolver ${type}`); return commonJSLookup(options); } } /** * from https://github.com/webpack-contrib/sass-loader webpack provides an [advanced mechanism to resolve files](https://webpack.js.org/concepts/module-resolution/). The sass-loader uses node-sass' custom importer feature to pass all queries to the webpack resolving engine. Thus you can import your Sass modules from `node_modules`. Just prepend them with a `~` to tell webpack that this is not a relative import: ```css @import "~bootstrap/dist/css/bootstrap"; ``` It's important to only prepend it with `~`, because `~/` resolves to the home directory. webpack needs to distinguish between `bootstrap` and `~bootstrap` because CSS and Sass files have no special syntax for importing relative files. Writing `@import "file"` is the same as `@import "./file"; */ function cssPreprocessorLookup(options) { const { filename, dependency, directory, resolveConfig } = options; if (resolveConfig && !(0, _utils().isRelativeImport)(dependency)) { const result = resolveNonRelativePath(dependency, filename, directory, resolveConfig); if (result) { options.wasCustomResolveUsed = true; return result; } } if (dependency.startsWith('~') && !dependency.startsWith('~/')) { // webpack syntax for resolving a module from node_modules debug('changing the resolver of css preprocessor to resolveWebpackPath as it has a ~ prefix'); const dependencyWithNoTilda = dependency.replace('~', ''); return resolveWebpack(dependencyWithNoTilda, filename, directory, { extensions: styleExtensions, symlinks: false }); } // Less and Sass imports are very similar return (0, _sassLookup().default)({ dependency, filename, directory }); } function tsLookup(options) { const { dependency, filename } = options; if (dependency[0] !== '.') { // when a path is not relative, use the standard commonJS lookup return commonJSLookup(options); } debug('performing a typescript lookup'); const tsOptions = { module: _typescript().default.ModuleKind.CommonJS }; const host = _typescript().default.createCompilerHost({}); debug('with options: ', tsOptions); let resolvedModule = _typescript().default.resolveModuleName(dependency, filename, tsOptions, host).resolvedModule; if (!resolvedModule) { // for some reason, on Windows, ts.resolveModuleName method tries to find the module in the // root directory. For example, it searches for module './bar', in 'c:\bar.ts'. const fallbackModule = _path().default.resolve(_path().default.dirname(filename), dependency); resolvedModule = _typescript().default.resolveModuleName(fallbackModule, filename, tsOptions, host).resolvedModule; } if (!resolvedModule) { // ts.resolveModuleName doesn't always work, fallback to commonJSLookup debug('failed resolving with tsLookup, trying commonJSLookup'); return commonJSLookup(options); } debug('ts resolved module: ', resolvedModule); const result = resolvedModule ? resolvedModule.resolvedFileName : ''; debug(`result: ${result}`); return result ? _path().default.resolve(result) : ''; } function resolveNonRelativePath(dependency, filename, directory, resolveConfig) { const webpackResolveConfig = {}; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! if (resolveConfig.modulesDirectories) webpackResolveConfig.modules = resolveConfig.modulesDirectories; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! if (resolveConfig.aliases) webpackResolveConfig.alias = resolveConfig.aliases; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! webpackResolveConfig.extensions = resolveExtensions; // a resolve module might point to an imported component via the package name, in which case // the package name is a symlink to the imported component. we want it to be resolved as a pkg // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! webpackResolveConfig.symlinks = false; return resolveWebpack(dependency, filename, directory, webpackResolveConfig); } function commonJSLookup(options) { const { filename, resolveConfig } = options; const directory = _path().default.dirname(filename); // node_modules should be propagated from the file location backwards // Need to resolve dependencies within the directory of the module, not filing-cabinet const moduleLookupDir = _path().default.join(directory, 'node_modules'); debug(`adding ${moduleLookupDir} to the require resolution paths`); _appModulePath().default.addPath(moduleLookupDir); let dependency = options.dependency; let result = ''; if (!(0, _utils().isRelativeImport)(dependency) && resolveConfig) { debug(`trying to resolve using resolveConfig ${JSON.stringify(resolveConfig)}`); result = resolveNonRelativePath(dependency, filename, directory, resolveConfig); if (result) { debug('successfully resolved using resolveConfig'); options.wasCustomResolveUsed = true; return result; } debug('failed resolved using resolveConfig, fall back to the standard resolver'); } // Make sure the dependency is being resolved to the filename's context // 3rd party modules will not be relative if (dependency[0] === '.') { dependency = _path().default.resolve(_path().default.dirname(filename), dependency); } try { result = _resolve().default.sync(dependency, { extensions: resolveExtensions, basedir: directory, moduleDirectory: ['node_modules'] }); debug(`resolved path: ${result}`); } catch (e) { debug(`could not resolve ${dependency}`); } return result; } function resolveWebpackPath(dependency, filename, directory, webpackConfig) { webpackConfig = _path().default.resolve(webpackConfig); let loadedConfig; try { // eslint-disable-next-line import/no-dynamic-require, global-require loadedConfig = require(webpackConfig); if (typeof loadedConfig === 'function') { loadedConfig = loadedConfig(); } } catch (e) { debug(`error loading the webpack config at ${webpackConfig}`); debug(e.message); debug(e.stack); return ''; } const resolveConfig = (0, _objectAssign().default)({}, loadedConfig.resolve); if (!resolveConfig.modules && (resolveConfig.root || resolveConfig.modulesDirectories)) { resolveConfig.modules = []; if (resolveConfig.root) { resolveConfig.modules = resolveConfig.modules.concat(resolveConfig.root); } if (resolveConfig.modulesDirectories) { resolveConfig.modules = resolveConfig.modules.concat(resolveConfig.modulesDirectories); } } return resolveWebpack(dependency, filename, directory, resolveConfig); } function resolveWebpack(dependency, filename, directory, resolveConfig) { try { const resolver = _enhancedResolve().default.create.sync(resolveConfig); // We don't care about what the loader resolves the dependency to // we only want the path of the resolved file dependency = stripLoader(dependency); const lookupPath = (0, _isRelativePath().default)(dependency) ? _path().default.dirname(filename) : directory; return resolver(lookupPath, dependency); } catch (e) { debug(`error when resolving ${dependency}`); debug(e.message); debug(e.stack); return ''; } } function stripLoader(dependency) { const exclamationLocation = dependency.indexOf('!'); if (exclamationLocation === -1) { return dependency; } return dependency.slice(exclamationLocation + 1); }