UNPKG

dependency-cruiser-fork

Version:

Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.

205 lines (183 loc) 5.68 kB
const path = require("path"); const isCore = require("./is-core"); const isRelativeModuleName = require("./is-relative-module-name"); const localNpmHelpers = require("./local-npm-helpers"); const NPM2DEP_TYPE = { dependencies: "npm", devDependencies: "npm-dev", optionalDependencies: "npm-optional", peerDependencies: "npm-peer", }; function determineNpmDependencyTypes(pModuleName, pPackageDependencies) { let lReturnValue = ["npm-unknown"]; if (Boolean(pPackageDependencies)) { lReturnValue = Object.keys(pPackageDependencies) .filter( (pKey) => pKey.includes("ependencies") && Object.prototype.hasOwnProperty.call( pPackageDependencies[pKey], pModuleName ) ) .map((pKey) => NPM2DEP_TYPE[pKey] || "npm-no-pkg"); lReturnValue = lReturnValue.length === 0 ? ["npm-no-pkg"] : lReturnValue; } return lReturnValue; } /* * there's a separate 'isBundled' function because bundle(d)Dependencies is * an array, and not an object, hence needs different treatment */ function dependencyIsBundled(pModule, pPackageDeps) { let lReturnValue = false; if (Boolean(pPackageDeps)) { const lBundledDependencies = pPackageDeps.bundledDependencies || pPackageDeps.bundleDependencies; if (lBundledDependencies) { lReturnValue = lBundledDependencies.includes(pModule); } } return lReturnValue; } function determineNodeModuleDependencyTypes( pModuleName, pPackageDeps, pFileDirectory, pResolveOptions ) { let lReturnValue = determineNpmDependencyTypes( localNpmHelpers.getPackageRoot(pModuleName), pPackageDeps ); if ( localNpmHelpers.dependencyIsDeprecated( pModuleName, pFileDirectory, pResolveOptions ) ) { lReturnValue.push("deprecated"); } if (dependencyIsBundled(pModuleName, pPackageDeps)) { lReturnValue.push("npm-bundled"); } return lReturnValue; } function isNodeModule(pDependency) { return pDependency.resolved.includes("node_modules"); } function determineModuleDependencyTypes( pDependency, pModuleName, pPackageDeps, pFileDirectory, pResolveOptions ) { let lReturnValue = []; if (isNodeModule(pDependency)) { lReturnValue = determineNodeModuleDependencyTypes( pModuleName, pPackageDeps, pFileDirectory, pResolveOptions ); } else { lReturnValue = ["localmodule"]; } return lReturnValue; } function isModule( pDependency, pModules = ["node_modules"], pBaseDirectory = "." ) { return pModules.some( // pModules can contain relative paths, but also absolute ones. // WebPack treats these differently: // - absolute paths only match that exact path // - relative paths get a node lookup treatment so "turtle" matches // "turtle", "../turtle", "../../turtle", "../../../turtle" (.. => // turtles all the way down) // hence we'll have to test for them in different fashion as well. // reference: https://webpack.js.org/configuration/resolve/#resolve-modules (pModule) => { if (path.isAbsolute(pModule)) { return path .resolve(pBaseDirectory, pDependency.resolved) .startsWith(pModule); } return pDependency.resolved.includes(pModule); } ); } function isAliased(pModuleName, pAliasObject) { return Object.keys(pAliasObject || {}).some((pAliasLHS) => pModuleName.startsWith(pAliasLHS) ); } function isLikelyTSAliased(pModuleName, pResolved, pTsConfig) { return ( pTsConfig && !isRelativeModuleName(pModuleName) && pResolved && !pResolved.includes("node_modules") ); } function isAliassy(pModuleName, pDependency, pResolveOptions) { return ( isAliased(pModuleName, pResolveOptions.alias) || isLikelyTSAliased( pModuleName, pDependency.resolved, pResolveOptions.tsConfig ) ); } /* eslint max-params:0, complexity:0 */ /** * * @param {any} pDependency the dependency object with all information found hitherto * @param {string} pModuleName the module name as found in the source * @param {any} pPackageDeps a package.json, in object format * @param {string} pFileDirectory the directory relative to which to resolve (only used for npm deps here) * @param {any} pResolveOptions an enhanced resolve 'resolve' key * @param {string} pBaseDirectory the base directory dependency cruise is run on * * @return {string[]} an array of dependency types for the dependency */ module.exports = function determineDependencyTypes( pDependency, pModuleName, pPackageDeps, pFileDirectory, pResolveOptions, pBaseDirectory ) { let lReturnValue = ["undetermined"]; pResolveOptions = pResolveOptions || {}; if (pDependency.couldNotResolve) { lReturnValue = ["unknown"]; } else if (isCore(pModuleName)) { // this 'isCore' business seems duplicate (it's already in // the passed object as `coreModule`- determined by the resolve-AMD or // resolve-commonJS module). I want to deprecate the `coreModule` // attribute in favor of this one and determining it here will make // live easier in the future lReturnValue = ["core"]; } else if (isRelativeModuleName(pModuleName)) { lReturnValue = ["local"]; } else if (isModule(pDependency, pResolveOptions.modules, pBaseDirectory)) { lReturnValue = determineModuleDependencyTypes( pDependency, pModuleName, pPackageDeps, pFileDirectory, pResolveOptions ); } else if (isAliassy(pModuleName, pDependency, pResolveOptions)) { lReturnValue = ["aliased"]; } return lReturnValue; }; /* eslint security/detect-object-injection: 0*/