diff --git a/lib/check.js b/lib/check.js index a59677b..c45ade5 100644 --- a/lib/check.js +++ b/lib/check.js @@ -13,6 +13,7 @@ const { * @property {string} path * @property {string[]} [entries] * @property {boolean} [noDefaultEntries] + * @property {boolean} [ignoreUnknownExtensions] * @property {import('./extensions').ExtensionsInput|string[]} [extensions] * @property {import('./extensions').Detective|string} [detective] * @property {boolean} [builtins] @@ -30,6 +31,7 @@ const check = async function (opts) { detective, entries, extensions, + ignoreUnknownExtensions, noDefaultEntries, path: targetPath } = opts @@ -51,6 +53,7 @@ const check = async function (opts) { builtins, entries: [...(targetEntries || []), ...(entries || [])], extensions: getExtensions(extensions, detective), + ignoreUnknownExtensions, noDefaultEntries: noDefaultEntries || (targetEntries && targetEntries.length !== 0), 'package': pkg, path: pkgPath diff --git a/lib/cli-engine.js b/lib/cli-engine.js index 9aee4cd..19435ef 100644 --- a/lib/cli-engine.js +++ b/lib/cli-engine.js @@ -13,12 +13,14 @@ const args = require('minimist')(process.argv.slice(2), { unused: false, dev: true, 'default-entries': true, + 'ignore-unknown-extensions': false, verbose: false, json: false, }, - 'boolean': ['missing', 'unused', 'dev', 'version', 'ignore', 'default-entries', 'verbose', 'json'], + 'boolean': ['missing', 'unused', 'dev', 'version', 'ignore', 'ignore-unknown-extensions', 'default-entries', 'verbose', 'json'], alias: { 'ignore-module': 'i', + 'ignore-unknown-extensions': 'u', extensions: 'e', json: 'j', } @@ -38,6 +40,7 @@ if (args['help'] || args._.length === 0) { console.log("--no-dev Won't tell you about devDependencies that are missing or unused") console.log("--no-peer Won't tell you about peerDependencies that are missing or unused") console.log("--ignore-module, -i Won't tell you about these module names when missing or unused. Supports globbing") + console.log("--ignore-unknown-extension, -u Won't fail on file extensions that are missing detectives") console.log("--no-default-entries Won't parse your main and bin entries from package.json even when a package.json or module folder has been defined") console.log('--detective Requireable path containing an alternative implementation of the detective module that supports alternate syntaxes') console.log("--extensions, -e List of file extensions with detective to use when resolving require paths. Eg. 'js,jsx:detective-es6'") @@ -99,6 +102,7 @@ if (!path) { check({ path, entries: args._, + ignoreUnknownExtensions: args['ignore-unknown-extensions'], noDefaultEntries: !args['default-entries'], extensions: extensions(args['e']), detective: args['detective'] diff --git a/lib/parse.js b/lib/parse.js index 3c7a7b1..435b751 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -10,6 +10,7 @@ const { resolvePaths } = require('./resolve-paths') * @property {import('read-pkg').NormalizedPackageJson} package * @property {import('./extensions').Extensions} extensions * @property {undefined|boolean} builtins + * @property {undefined|boolean} ignoreUnknownExtensions * @property {undefined|boolean} noDefaultEntries * @property {undefined|string[]} entries */ @@ -30,6 +31,7 @@ const parse = async function (opts) { builtins, entries, extensions, + ignoreUnknownExtensions = false, noDefaultEntries, 'package': pkg, path: basePath, @@ -59,7 +61,7 @@ const parse = async function (opts) { const lookups = [] for (const file of paths) { - lookups.push(resolveDep(file, extensions, { deps, seen, core })) + lookups.push(resolveDep(file, extensions, { core, deps, ignoreUnknownExtensions, seen })) } await Promise.all(lookups) diff --git a/lib/resolve-dependency.js b/lib/resolve-dependency.js index 684a70c..2799391 100644 --- a/lib/resolve-dependency.js +++ b/lib/resolve-dependency.js @@ -7,6 +7,14 @@ const isRelative = require('is-relative') const resolveModule = require('resolve') const debug = require('debug')('dependency-check') +/** + * @typedef DependencyContext + * @property {Set} core + * @property {Set} deps + * @property {boolean} ignoreUnknownExtensions + * @property {Set} seen + */ + /** @type {(file: string, options: import('resolve').AsyncOpts) => Promise} */ const promisedResolveModule = (file, options) => new Promise((resolve, reject) => { resolveModule(file, options, (err, path) => { @@ -21,7 +29,6 @@ const promisedResolveModule = (file, options) => new Promise((resolve, reject) = * @returns {boolean} */ const isNotRelative = (file) => isRelative(file) && file[0] !== '.' -/** @typedef {{ deps: Set, seen: Set, core: Set }} DependencyContext */ /** * @param {string} file @@ -29,12 +36,16 @@ const isNotRelative = (file) => isRelative(file) && file[0] !== '.' * @param {DependencyContext} context * @returns {Promise} */ -const getDeps = async function (file, extensions, { core, deps, seen }) { +const getDeps = async function (file, extensions, { core, deps, ignoreUnknownExtensions, seen }) { const ext = path.extname(file) const detective = extensions[ext] if (typeof detective !== 'function') { - throw new TypeError('Detective function missing for "' + file + '"') + if (ignoreUnknownExtensions) { + return + } else { + throw new TypeError('Detective function missing for "' + file + '"') + } } const contents = await readFile(file, 'utf8') @@ -64,7 +75,7 @@ const getDeps = async function (file, extensions, { core, deps, seen }) { } } - await Promise.all(relatives.map(name => resolveDep(name, extensions, { deps, seen, core }))) + await Promise.all(relatives.map(name => resolveDep(name, extensions, { core, deps, ignoreUnknownExtensions, seen }))) } /** @@ -73,7 +84,7 @@ const getDeps = async function (file, extensions, { core, deps, seen }) { * @param {DependencyContext} context * @returns {Promise} */ -const resolveDep = async function (file, extensions, { core, deps, seen }) { +const resolveDep = async function (file, extensions, { core, deps, ignoreUnknownExtensions, seen }) { if (isNotRelative(file)) return const resolvedPath = await promisedResolveModule(file, { @@ -81,7 +92,7 @@ const resolveDep = async function (file, extensions, { core, deps, seen }) { extensions: Object.keys(extensions) }) - return getDeps(resolvedPath, extensions, { deps, seen, core }) + return getDeps(resolvedPath, extensions, { core, deps, ignoreUnknownExtensions, seen }) } module.exports = { diff --git a/readme.md b/readme.md index f0f04e1..83b7677 100644 --- a/readme.md +++ b/readme.md @@ -77,6 +77,10 @@ running `dependency-check ./package.json --unused --no-peer` will not tell you i ignores a module. This works for both `--unused` and `--missing`. You can specify as many separate `--ignore-module` arguments as you want. For example running `dependency-check ./package.json --unused --ignore-module foo` will not tell you if the `foo` module was not used in your code. Supports globbing patterns through the use of [micromatch](https://www.npmjs.com/package/micromatch), so eg. `--ignore-module "@types/*" is possible` +### --ignore-unknown-extensions, -u + +won't fail when finding imported files with file extensions that no detectives has been registered for + ### --no-default-entries running eg. `dependency-check package.json tests.js --no-default-entries` won't add any default entries despite the main path given being one to a package.json or module folder. So only the `tests.js` file will be checked diff --git a/test/parse.spec.js b/test/parse.spec.js index 1c90e6f..bff65b7 100644 --- a/test/parse.spec.js +++ b/test/parse.spec.js @@ -25,6 +25,7 @@ describe('parse()', () => { 'package': mockPkg(), extensions: {}, builtins: undefined, + ignoreUnknownExtensions: undefined, noDefaultEntries: undefined, entries: undefined, })