Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Commit

Permalink
Improve CLI engine detection mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
voxpelli committed Sep 25, 2021
1 parent 5c527f1 commit 8f0a129
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 179 deletions.
172 changes: 172 additions & 0 deletions cli-engine.js
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)
})
187 changes: 11 additions & 176 deletions cli.js
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)
})
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
"main": "index.js",
"types": "index.d.ts",
"files": [
"cli-engine.js",
"cli.js",
"cli.d.ts",
"cli.d.ts.map",
"index.js",
"index.d.ts",
"index.d.ts.map"
Expand Down Expand Up @@ -47,7 +46,7 @@
}
},
"engines": {
"node": ">=12.0.0"
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"author": "max ogden",
"dependencies": {
Expand Down

0 comments on commit 8f0a129

Please sign in to comment.