UNPKG

dependency-cruiser

Version:

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

135 lines (123 loc) 4.08 kB
import { extname } from "node:path"; export function dependenciesEqual(pLeftDependency) { // As we're using this to compare (typescript) pre-compilation dependencies // with post-compilation dependencies we do not consider the moduleSystem. // // In typescript the module system will typically be es6. Compiled down to // javascript it can be es6, but also cjs (depends on the `module` setting // in your tsconfig). In the latter case, we're still looking at the same // dependency even though the module systems differ. return (pRightDependency) => pLeftDependency.module === pRightDependency.module && pLeftDependency.dynamic === pRightDependency.dynamic && pLeftDependency.exoticRequire === pRightDependency.exoticRequire; } export function detectPreCompilationNess(pTSDependencies, pJSDependencies) { return pTSDependencies.map((pTSDependency) => pJSDependencies.some(dependenciesEqual(pTSDependency)) ? { ...pTSDependency, preCompilationOnly: false } : { ...pTSDependency, preCompilationOnly: true, dependencyTypes: (pTSDependency.dependencyTypes || []).concat( "pre-compilation-only", ), }, ); } const PROTOCOL_ONLY_BUILTINS = new Set([ // module.builtinModules.filter(m=>m.startsWith('node:')) "node:sea", "node:sqlite", "node:test", "node:test/reporters", // module.builtinModules.filter(m=>m.startsWith('bun:')) "bun:ffi", "bun:jsc", "bun:sqlite", "bun:test", "bun:wrap", ]); /** * Given a module name returns the canonical module name. * @param {string} pProtocol * @param {string} pModuleName * @returns {string} */ function getCanonicalModuleName(pModuleName, pProtocol) { const lModuleWithProtocol = pProtocol + pModuleName; const lIsJsIshProtocol = pProtocol === "node:" || pProtocol === "bun:"; const lIsProtocolOnlyModule = PROTOCOL_ONLY_BUILTINS.has(lModuleWithProtocol); if (!lIsJsIshProtocol || lIsProtocolOnlyModule) { return lModuleWithProtocol; } return pModuleName; } /** * Given a module string returns in an object * - the module name * - the protocol (when encoded in the string) * - the mimeType (when encoded in the string) * * See https://nodejs.org/api/esm.html#esm_urls * * would've loved to use url.URL here, but that doesn't extract the mime type * (if there's a default node API that does this I'm all ears) * * @param {string} pString * @returns {{module:string; protocol?:string; mimeType?:string}} */ // eslint-disable-next-line complexity export function extractModuleAttributes(pString) { let lReturnValue = { module: pString }; const lModuleAttributes = pString.match( // eslint-disable-next-line security/detect-unsafe-regex /^(?<protocol>node:|file:|data:|bun:)(?:(?<mimeType>[^,]+),)?(?<module>.+)$/, ); if (lModuleAttributes?.groups) { lReturnValue.module = getCanonicalModuleName( lModuleAttributes?.groups.module, lModuleAttributes?.groups.protocol, ); if (lModuleAttributes?.groups?.protocol) { lReturnValue.protocol = lModuleAttributes.groups.protocol; } if (lModuleAttributes?.groups?.mimeType) { lReturnValue.mimeType = lModuleAttributes.groups.mimeType; } } return lReturnValue; } /** * returns pFilenameString stripped of any 'query parameters' e.g. * * "hello/there?thing=smurf" => "hello/there" * "boink/boink/t.gif?resource" => "boink/boink/t.gif" * "no/thing/after.js" => "no/thing/after.js" * * @param {string} pFilenameString string to strip the query parameters from * @returns {string} the stripped string */ export function stripQueryParameters(pFilenameString) { // url.parse(pFilenameString).pathname did this, but it's // deprecated, hence this funky RE replace. return pFilenameString.replace(/\?.+$/, ""); } const TS_COMPATIBLE_EXTENSIONS = new Set([ ".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".vue", ]); /** * Returns true if the file name has a TypeScript compatible extension * @param {string} pFileName * @returns {boolean} */ export function isTypeScriptCompatible(pFileName) { return TS_COMPATIBLE_EXTENSIONS.has(extname(pFileName)); }