This repository has been archived by the owner on Mar 13, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve CLI engine detection mechanism
Largely taken from StandardJS: https://github.com/standard/standard/blob/cb456f51718a93e5e2dce298ad9aee06ee1678d7/bin/cmd.js
- Loading branch information
Showing
3 changed files
with
185 additions
and
179 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
/* eslint-disable no-console, unicorn/no-process-exit */ | ||
|
||
'use strict' | ||
|
||
const debug = require('debug')('dependency-check') | ||
|
||
const { check, extra, missing } = require('.') | ||
|
||
const args = require('minimist')(process.argv.slice(2), { | ||
'default': { | ||
missing: false, | ||
unused: false, | ||
dev: true, | ||
'default-entries': true, | ||
verbose: false, | ||
json: false, | ||
}, | ||
'boolean': ['missing', 'unused', 'dev', 'version', 'ignore', 'default-entries', 'verbose', 'json'], | ||
alias: { | ||
'ignore-module': 'i', | ||
extensions: 'e', | ||
json: 'j', | ||
} | ||
}) | ||
|
||
if (args['version']) { | ||
console.log(require('./package.json').version) | ||
process.exit(1) | ||
} | ||
|
||
if (args['help'] || args._.length === 0) { | ||
console.log('\nUsage: dependency-check <path to entry file, package.json or module folder> <additional entry paths to add> <options>') | ||
console.log('\nEntry paths supports globbing for easy adding of eg. entire folders.') | ||
console.log('\nOptions:') | ||
console.log('--missing Only check to make sure that all modules in your code are listed in your package.json') | ||
console.log('--unused Only check which modules listed in your package.json *are not* used in your code') | ||
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("--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'") | ||
console.log('--version Show current version') | ||
console.log('--ignore To always exit with code 0 pass --ignore') | ||
console.log('--json -j Format the output as json object') | ||
console.log('--verbose Enable logging of eg. success message') | ||
console.log('') | ||
|
||
process.exit(1) | ||
} | ||
|
||
// windows leaves leading/trailing quotes on strings needed on unix to | ||
// stop shells from doing path expansion, so strip them if present | ||
args._ = args._.map((string) => { | ||
if (string.startsWith("'") || string.startsWith('"')) { | ||
string = string.slice(1) | ||
} | ||
|
||
if (string.endsWith("'") || string.endsWith('"')) { | ||
string = string.slice(0, -1) | ||
} | ||
|
||
return string | ||
}) | ||
|
||
/** | ||
* @param {*} arg | ||
* @returns {import('.').Extensions} | ||
*/ | ||
const extensions = function (arg) { | ||
if (!arg) return {} | ||
|
||
/** @type {import('.').Extensions} */ | ||
const extensions = {} | ||
|
||
if (typeof arg === 'string') { | ||
arg = [arg] | ||
} | ||
|
||
for (const value of arg) { | ||
const parts = value.trim().split(':', 2) | ||
|
||
for (const ext of parts[0].split(',')) { | ||
extensions[ext.charAt(0) === '.' ? ext : '.' + ext] = parts[1] | ||
} | ||
} | ||
|
||
return extensions | ||
} | ||
|
||
const path = args._.shift() | ||
|
||
if (!path) { | ||
console.error('Requires a path') | ||
process.exit(1) | ||
} | ||
|
||
check({ | ||
path, | ||
entries: args._, | ||
noDefaultEntries: !args['default-entries'], | ||
extensions: extensions(args['e']), | ||
detective: args['detective'] | ||
}) | ||
.catch(err => { | ||
console.error('An unexpected error in initial stage:', err.message) | ||
debug(err.stack) | ||
process.exit(1) | ||
}) | ||
.then(data => { | ||
const pkg = data.package | ||
const deps = data.used | ||
let failed = 0 | ||
const options = { | ||
excludeDev: args['dev'] === false, | ||
excludePeer: args['peer'] === false, | ||
ignore: [args['i'] || []].flat() | ||
} | ||
|
||
const runAllTests = !args['extra'] && !args['missing'] | ||
|
||
/** @type {string[]|undefined} */ | ||
let extras | ||
/** @type {string[]|undefined} */ | ||
let result | ||
|
||
if (runAllTests || args['unused']) { | ||
extras = extra(pkg, deps, options) | ||
failed += extras.length | ||
} | ||
if (runAllTests || args['missing']) { | ||
const optionsForMissingCheck = runAllTests | ||
? Object.assign({}, options, { | ||
excludeDev: false, | ||
excludePeer: false | ||
}) | ||
: options | ||
|
||
result = missing(pkg, deps, optionsForMissingCheck) | ||
|
||
failed += result.length | ||
} | ||
|
||
if (args['json']) { | ||
console.log(JSON.stringify({ missing: result, unused: extras })) | ||
// eslint-disable-next-line promise/always-return | ||
process.exit(args['ignore'] || !failed ? 0 : 1) | ||
} | ||
|
||
if (extras) { | ||
if (extras.length) { | ||
console.error('Fail! Modules in package.json not used in code: ' + extras.join(', ')) | ||
} else if (args['verbose']) { | ||
console.log('Success! All dependencies in package.json are used in the code') | ||
} | ||
} | ||
if (result) { | ||
if (result.length) { | ||
console.error('Fail! Dependencies not listed in package.json: ' + result.join(', ')) | ||
} else if (args['verbose']) { | ||
console.log('Success! All dependencies used in the code are listed in package.json') | ||
} | ||
} | ||
|
||
// eslint-disable-next-line promise/always-return | ||
process.exit(args['ignore'] || !failed ? 0 : 1) | ||
}) | ||
.catch(err => { | ||
console.error('An unexpected error happened:', err.message) | ||
debug(err.stack) | ||
process.exit(1) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,185 +1,20 @@ | ||
#!/usr/bin/env node | ||
/* eslint-disable no-console */ | ||
/* eslint-disable no-var, no-console, unicorn/prefer-number-properties */ | ||
|
||
'use strict' | ||
|
||
const debug = require('debug')('dependency-check') | ||
|
||
// Check that we're at a supported version | ||
const requiredNodeEngineMinimum = require('./package.json').engines.node.match(/^>=(\d+)\./) | ||
const currentNodeEngine = process.version.match(/^v(\d+)\./) | ||
if ( | ||
!currentNodeEngine || | ||
!requiredNodeEngineMinimum || | ||
Number.parseInt(currentNodeEngine[1] || '', 10) < Number.parseInt(requiredNodeEngineMinimum[1] || '', 10) | ||
) { | ||
console.error('dependency-check: Node ' + requiredNodeEngineMinimum + ' or greater is required. `dependency-check` did not run.') | ||
process.exit(0) | ||
} | ||
|
||
const { check, extra, missing } = require('.') | ||
|
||
const args = require('minimist')(process.argv.slice(2), { | ||
'default': { | ||
missing: false, | ||
unused: false, | ||
dev: true, | ||
'default-entries': true, | ||
verbose: false, | ||
json: false, | ||
}, | ||
'boolean': ['missing', 'unused', 'dev', 'version', 'ignore', 'default-entries', 'verbose', 'json'], | ||
alias: { | ||
'ignore-module': 'i', | ||
extensions: 'e', | ||
json: 'j', | ||
} | ||
}) | ||
|
||
if (args['version']) { | ||
console.log(require('./package.json').version) | ||
process.exit(1) | ||
} | ||
|
||
if (args['help'] || args._.length === 0) { | ||
console.log('\nUsage: dependency-check <path to entry file, package.json or module folder> <additional entry paths to add> <options>') | ||
console.log('\nEntry paths supports globbing for easy adding of eg. entire folders.') | ||
console.log('\nOptions:') | ||
console.log('--missing Only check to make sure that all modules in your code are listed in your package.json') | ||
console.log('--unused Only check which modules listed in your package.json *are not* used in your code') | ||
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("--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'") | ||
console.log('--version Show current version') | ||
console.log('--ignore To always exit with code 0 pass --ignore') | ||
console.log('--json -j Format the output as json object') | ||
console.log('--verbose Enable logging of eg. success message') | ||
console.log('') | ||
|
||
if (require('./package.json').engines.node !== '^12.20.0 || ^14.13.1 || >=16.0.0') { | ||
console.error('dependency-check: Mismatch between package.json node engine and cli engine check') | ||
process.exit(1) | ||
} | ||
|
||
// windows leaves leading/trailing quotes on strings needed on unix to | ||
// stop shells from doing path expansion, so strip them if present | ||
args._ = args._.map((string) => { | ||
if (string.startsWith("'") || string.startsWith('"')) { | ||
string = string.slice(1) | ||
} | ||
|
||
if (string.endsWith("'") || string.endsWith('"')) { | ||
string = string.slice(0, -1) | ||
} | ||
|
||
return string | ||
}) | ||
|
||
/** | ||
* @param {*} arg | ||
* @returns {import('.').Extensions} | ||
*/ | ||
const extensions = function (arg) { | ||
if (!arg) return {} | ||
|
||
/** @type {import('.').Extensions} */ | ||
const extensions = {} | ||
|
||
if (typeof arg === 'string') { | ||
arg = [arg] | ||
} | ||
|
||
for (const value of arg) { | ||
const parts = value.trim().split(':', 2) | ||
var match = process.version.match(/v(\d+)\.(\d+)/) || [] | ||
var major = parseInt(match[1] || '', 10) | ||
var minor = parseInt(match[2] || '', 10) | ||
|
||
for (const ext of parts[0].split(',')) { | ||
extensions[ext.charAt(0) === '.' ? ext : '.' + ext] = parts[1] | ||
} | ||
} | ||
|
||
return extensions | ||
} | ||
|
||
const path = args._.shift() | ||
|
||
if (!path) { | ||
console.error('Requires a path') | ||
process.exit(1) | ||
if (major >= 12 || (major === 12 && minor >= 20)) { | ||
require('./cli-engine') | ||
} else { | ||
console.error('dependency-check: Node 12.20.0 or greater is required. `dependency-check` did not run.') | ||
process.exit(0) | ||
} | ||
|
||
check({ | ||
path, | ||
entries: args._, | ||
noDefaultEntries: !args['default-entries'], | ||
extensions: extensions(args['e']), | ||
detective: args['detective'] | ||
}) | ||
.catch(err => { | ||
console.error('An unexpected error in initial stage:', err.message) | ||
debug(err.stack) | ||
process.exit(1) | ||
}) | ||
.then(data => { | ||
const pkg = data.package | ||
const deps = data.used | ||
let failed = 0 | ||
const options = { | ||
excludeDev: args['dev'] === false, | ||
excludePeer: args['peer'] === false, | ||
ignore: [args['i'] || []].flat() | ||
} | ||
|
||
const runAllTests = !args['extra'] && !args['missing'] | ||
|
||
/** @type {string[]|undefined} */ | ||
let extras | ||
/** @type {string[]|undefined} */ | ||
let result | ||
|
||
if (runAllTests || args['unused']) { | ||
extras = extra(pkg, deps, options) | ||
failed += extras.length | ||
} | ||
if (runAllTests || args['missing']) { | ||
const optionsForMissingCheck = runAllTests | ||
? Object.assign({}, options, { | ||
excludeDev: false, | ||
excludePeer: false | ||
}) | ||
: options | ||
|
||
result = missing(pkg, deps, optionsForMissingCheck) | ||
|
||
failed += result.length | ||
} | ||
|
||
if (args['json']) { | ||
console.log(JSON.stringify({ missing: result, unused: extras })) | ||
// eslint-disable-next-line promise/always-return | ||
process.exit(args['ignore'] || !failed ? 0 : 1) | ||
} | ||
|
||
if (extras) { | ||
if (extras.length) { | ||
console.error('Fail! Modules in package.json not used in code: ' + extras.join(', ')) | ||
} else if (args['verbose']) { | ||
console.log('Success! All dependencies in package.json are used in the code') | ||
} | ||
} | ||
if (result) { | ||
if (result.length) { | ||
console.error('Fail! Dependencies not listed in package.json: ' + result.join(', ')) | ||
} else if (args['verbose']) { | ||
console.log('Success! All dependencies used in the code are listed in package.json') | ||
} | ||
} | ||
|
||
// eslint-disable-next-line promise/always-return | ||
process.exit(args['ignore'] || !failed ? 0 : 1) | ||
}) | ||
.catch(err => { | ||
console.error('An unexpected error happened:', err.message) | ||
debug(err.stack) | ||
process.exit(1) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters