audit-resolve-core
Advanced tools
Comparing version 1.1.8 to 3.0.0-2
{ | ||
"standard.enable": false | ||
"standard.enable": true | ||
} |
@@ -1,8 +0,8 @@ | ||
var argv = require('yargs-parser')(process.argv.slice(2)); | ||
var argv = require('yargs-parser')(process.argv.slice(2)) | ||
module.exports = { | ||
get: () => argv, | ||
set: a => { | ||
if (a) { argv = a } | ||
} | ||
} | ||
get: () => argv, | ||
set: a => { | ||
if (a) { argv = a } | ||
} | ||
} |
module.exports = { | ||
FILENAME: 'audit-resolve.json', | ||
FILENAME_DEPRECATED: 'audit-resolv.json' | ||
} | ||
FILENAME: 'audit-resolve.json', | ||
FILENAME_DEPRECATED: 'audit-resolv.json' | ||
} |
const debug = require('debug')('audit-resolve-core') | ||
const argv = require('../arguments') | ||
const djv = require('djv') | ||
const Djv = require('djv') | ||
const path = require('path') | ||
@@ -9,68 +9,71 @@ const fs = require('fs') | ||
const versions = { | ||
0: require('./versions/v0'), | ||
1: require('./versions/v1') | ||
0: require('./versions/v0'), | ||
1: require('./versions/v1') | ||
} | ||
function defaultFilePath(pathOverride) { | ||
return pathOverride || path.resolve(argv.get().prefix || '.', FILE.FILENAME) | ||
function defaultFilePath (pathOverride) { | ||
return pathOverride || path.resolve(argv.get().prefix || '.', FILE.FILENAME) | ||
} | ||
function resolutionFilePath(pathOverride) { | ||
const filePath1 = defaultFilePath(pathOverride) | ||
function resolutionFilePath (pathOverride) { | ||
const filePath1 = defaultFilePath(pathOverride) | ||
if (fs.existsSync(filePath1)) { | ||
return filePath1 | ||
} | ||
if (fs.existsSync(filePath1)) { | ||
return filePath1 | ||
} | ||
const filePath2 = path.resolve(argv.get().prefix || '.', FILE.FILENAME_DEPRECATED) | ||
if (fs.existsSync(filePath2)) { | ||
printV1MigrationNotes() | ||
return filePath2 | ||
} | ||
const filePath2 = path.resolve(argv.get().prefix || '.', FILE.FILENAME_DEPRECATED) | ||
if (fs.existsSync(filePath2)) { | ||
printV1MigrationNotes() | ||
return filePath2 | ||
} | ||
throw Error(`Could not find the resolutions file. Expected ${filePath1}`) | ||
throw Error(`Could not find the resolutions file. Expected ${filePath1}`) | ||
} | ||
function validate(JSONSchema, data) { | ||
const env = new djv(); | ||
env.addSchema('resolve', JSONSchema); | ||
const result = env.validate('resolve', data); | ||
if (result) { | ||
throw Error(`Invalid audit-resolve file. ${JSON.stringify(result, null, 2)}`) | ||
} | ||
function validate (JSONSchema, data) { | ||
const env = new Djv() | ||
env.addSchema('resolve', JSONSchema) | ||
const result = env.validate('resolve', data) | ||
if (result) { | ||
throw Error(`Invalid audit-resolve file. ${JSON.stringify(result, null, 2)}`) | ||
} | ||
} | ||
function parseResolutionsData(rawdata) { | ||
const data = JSON.parse(rawdata); | ||
let version = 0; | ||
if (data.version) { | ||
version = +data.version | ||
} | ||
if (!versions[version]) { | ||
throw Error(`Unrecognized ${FILE.FILENAME} content version ${version}`) | ||
} | ||
validate(versions[version].schema, data) | ||
return versions[version].extract(data) | ||
function readAndValidate (pathOverride) { | ||
const filePath = resolutionFilePath(pathOverride) | ||
debug('loading from ', filePath) | ||
const rawdata = fs.readFileSync(filePath) | ||
const data = JSON.parse(rawdata) | ||
let version = 0 | ||
if (data.version) { | ||
version = +data.version | ||
} | ||
if (!versions[version]) { | ||
throw Error(`Unrecognized ${FILE.FILENAME} content version ${version}`) | ||
} | ||
validate(versions[version].schema, data) | ||
return data | ||
} | ||
function parseResolutionsData (data) { | ||
const version = +data.version | ||
return versions[version].extract(data) | ||
} | ||
module.exports = { | ||
load(pathOverride) { | ||
const filePath = resolutionFilePath(pathOverride) | ||
debug('loading from ', filePath) | ||
const rawdata = fs.readFileSync(filePath) | ||
return parseResolutionsData(rawdata) | ||
}, | ||
save({ decisions, rules }, pathOverride) { | ||
const wrappedData = { | ||
decisions, | ||
rules, | ||
version: 1 | ||
} | ||
validate(versions[1].schema, wrappedData) | ||
fs.writeFileSync(defaultFilePath(pathOverride), JSON.stringify(wrappedData, null, 2)) | ||
load (pathOverride) { | ||
const data = readAndValidate(pathOverride) | ||
return parseResolutionsData(data) | ||
}, | ||
save ({ decisions, rules }, pathOverride) { | ||
const wrappedData = { | ||
decisions, | ||
rules, | ||
version: 1 | ||
} | ||
} | ||
validate(versions[1].schema, wrappedData) | ||
fs.writeFileSync(defaultFilePath(pathOverride), JSON.stringify(wrappedData, null, 2)) | ||
}, | ||
validateResolveFile (pathOverride) { | ||
return readAndValidate(pathOverride) | ||
} | ||
} |
const debug = require('debug')('audit-resolve-core') | ||
const auditFile = require('./fileHandle') | ||
const RESOLUTIONS = require('../resolutions/RESOLUTIONS') | ||
const decision2resolution = require('../resolutions/decision2resolution') | ||
let decisionsData = null; | ||
let rules = {}; | ||
const { buildKey } = require('./identifier') | ||
let decisionsData = null | ||
let rules = {} | ||
const buildKey = ({ id, path }) => `${id}|${path}`; | ||
function load(pathOverride) { | ||
debug('load') | ||
if (decisionsData) { | ||
return | ||
} | ||
decisionsData = {} //in case loading fails, have something valid to extend and save | ||
try { | ||
const file = auditFile.load(pathOverride) | ||
debug('resolve file loaded', file) | ||
rules = file.rules | ||
decisionsData = file.decisions | ||
} catch (e) { | ||
debug('error loading resolve file', e) | ||
} | ||
function load (pathOverride) { | ||
debug('load') | ||
if (decisionsData) { | ||
return | ||
} | ||
decisionsData = {} // in case loading fails, have something valid to extend and save | ||
try { | ||
const file = auditFile.load(pathOverride) | ||
debug('resolve file loaded', file) | ||
rules = file.rules | ||
decisionsData = file.decisions | ||
} catch (e) { | ||
debug('error loading resolve file', e) | ||
} | ||
} | ||
const longRandomRegex = /^[a-z0-9]{64}$/ | ||
// I'm still hoping this can be removed if audit results get it fixed for git packages | ||
function pathCorruptionWorkaround(depPath) { | ||
const chunks = depPath.split('>') | ||
return chunks.map(c => { | ||
if (c.match(longRandomRegex)) { | ||
return '00unidentified' | ||
} else { | ||
return c | ||
} | ||
}).join('>') | ||
} | ||
module.exports = { | ||
load, | ||
getRules() { | ||
// naive clone is enough to make you, dear contributor, treat this as readonly | ||
return Object.assign({}, rules) | ||
}, | ||
flush() { | ||
auditFile.save({ | ||
decisions: decisionsData, | ||
rules | ||
}) | ||
}, | ||
set({ id, path }, { resolution, reason, expiresAt }) { | ||
if (!RESOLUTIONS.reverseLookup[resolution]) { | ||
throw Error(`invalid resolution ${resolution}`) | ||
} | ||
load() | ||
path = pathCorruptionWorkaround(path) | ||
const payload = { | ||
decision: resolution, | ||
madeAt: Date.now() | ||
} | ||
if (reason) { | ||
payload.reason = reason | ||
} | ||
if (expiresAt) { | ||
payload.expiresAt = expiresAt | ||
} | ||
return (decisionsData[buildKey({ id, path })] = payload); | ||
}, | ||
get({ id, path }) { | ||
load() | ||
path = pathCorruptionWorkaround(path) | ||
return decision2resolution(decisionsData[buildKey({ id, path })]); | ||
load, | ||
getRules () { | ||
// naive clone is enough to make you, dear contributor, treat this as readonly | ||
return Object.assign({}, rules) | ||
}, | ||
flush () { | ||
auditFile.save({ | ||
decisions: decisionsData, | ||
rules | ||
}) | ||
}, | ||
set ({ id, path }, { resolution, reason, expiresAt }) { | ||
if (!RESOLUTIONS.reverseLookup[resolution]) { | ||
throw Error(`invalid resolution ${resolution}`) | ||
} | ||
}; | ||
const key = buildKey({ id, path }) | ||
load() | ||
const payload = { | ||
decision: resolution, | ||
madeAt: Date.now() | ||
} | ||
if (reason) { | ||
payload.reason = reason | ||
} | ||
if (expiresAt) { | ||
payload.expiresAt = expiresAt | ||
} | ||
return (decisionsData[key] = payload) | ||
}, | ||
get ({ id, path }) { | ||
const key = buildKey({ id, path }) | ||
load() | ||
return decisionsData[key] | ||
} | ||
} |
@@ -5,31 +5,31 @@ const RESOLUTIONS = require('../../resolutions/RESOLUTIONS') | ||
module.exports = { | ||
schema: { | ||
type: "object", | ||
"additionalProperties": { | ||
"type": "object" | ||
schema: { | ||
type: 'object', | ||
additionalProperties: { | ||
type: 'object' | ||
} | ||
}, | ||
extract (data) { | ||
return { | ||
rules: {}, | ||
decisions: Object.keys(data).reduce((acc, key) => { | ||
acc[key] = { madeAt: 0 } | ||
if (data[key].postpone) { | ||
acc[key].decision = RESOLUTIONS.POSTPONE | ||
acc[key].madeAt = data[key].postpone - MILIS24H | ||
} | ||
}, | ||
extract(data) { | ||
return { | ||
rules: {}, | ||
decisions: Object.keys(data).reduce((acc, key) => { | ||
acc[key] = { madeAt: 0 } | ||
if (data[key].postpone) { | ||
acc[key].decision = RESOLUTIONS.POSTPONE | ||
acc[key].madeAt = data[key].postpone - MILIS24H | ||
} | ||
if (data[key].remind) { | ||
acc[key].decision = RESOLUTIONS.POSTPONE | ||
acc[key].madeAt = data[key].remind - MILIS24H | ||
} | ||
if (data[key].ignore) { | ||
acc[key].decision = RESOLUTIONS.IGNORE | ||
} | ||
if (data[key].fix) { | ||
acc[key].decision = RESOLUTIONS.FIX | ||
} | ||
return acc | ||
}, {}) | ||
if (data[key].remind) { | ||
acc[key].decision = RESOLUTIONS.POSTPONE | ||
acc[key].madeAt = data[key].remind - MILIS24H | ||
} | ||
if (data[key].ignore) { | ||
acc[key].decision = RESOLUTIONS.IGNORE | ||
} | ||
if (data[key].fix) { | ||
acc[key].decision = RESOLUTIONS.FIX | ||
} | ||
return acc | ||
}, {}) | ||
} | ||
} | ||
} | ||
} |
const RESOLUTIONS = require('../../resolutions/RESOLUTIONS') | ||
module.exports = { | ||
schema: { | ||
schema: { | ||
properties: { | ||
version: { | ||
type: 'number', | ||
minimum: 1 | ||
}, | ||
decisions: { | ||
type: 'object', | ||
additionalProperties: { | ||
type: 'object', | ||
required: ['decision'], | ||
properties: { | ||
decision: { | ||
type: 'string', | ||
enum: Object.keys(RESOLUTIONS.reverseLookup) | ||
}, | ||
reason: { type: 'string' }, | ||
madeAt: { type: 'number' }, | ||
expiresAt: { type: 'number' } | ||
} | ||
} | ||
}, | ||
rules: { | ||
type: 'object', | ||
properties: { | ||
version: { | ||
'type': 'number', | ||
'minimum': 1 | ||
}, | ||
decisions: { | ||
type: 'object', | ||
additionalProperties: { | ||
type: 'object', | ||
required: ['decision'], | ||
properties: { | ||
decision: { | ||
type: 'string', | ||
enum: Object.keys(RESOLUTIONS.reverseLookup) | ||
}, | ||
reason: { type: 'string' }, | ||
madeAt: { type: 'number' }, | ||
expiresAt: { type: 'number' } | ||
} | ||
} | ||
}, | ||
rules: { | ||
type: 'object', | ||
properties:{ | ||
ignoreExpiresInDays: { type: 'number' }, //should it be days or should I pull in a dependency to resolve nice text? | ||
ignoreLowSeverity: {type: 'boolean' } | ||
} | ||
ignoreConfig: { | ||
type: 'object', | ||
properties: { | ||
ignoreExpiresInDays: { type: 'number' }, // should it be days or should I pull in a dependency to resolve nice text? | ||
ignoreLowSeverity: { type: 'boolean' } | ||
} | ||
}, | ||
required: [ | ||
'version', | ||
'decisions' | ||
] | ||
} | ||
} | ||
} | ||
}, | ||
extract(data) { | ||
return { | ||
decisions: data.decisions, | ||
rules: data.rules | ||
} | ||
required: [ | ||
'version', | ||
'decisions' | ||
] | ||
}, | ||
extract (data) { | ||
return { | ||
decisions: data.decisions, | ||
rules: data.rules | ||
} | ||
} | ||
} | ||
} |
const statusManager = require('./statusManager') | ||
const RESOLUTIONS = require('./resolutions/RESOLUTIONS') | ||
const fileHandle = require('./auditFile/fileHandle') | ||
const identifier = require('./auditFile/identifier') | ||
module.exports = Object.assign({}, statusManager, { RESOLUTIONS }) | ||
module.exports = Object.assign({}, statusManager, { | ||
RESOLUTIONS, | ||
validateResolveFile: fileHandle.validateResolveFile, | ||
identify: identifier.identify | ||
}) |
{ | ||
"name": "audit-resolve-core", | ||
"version": "1.1.8", | ||
"version": "3.0.0-2", | ||
"description": "Core modules for audit-resolve.json file and logic of its processing", | ||
"scripts": { | ||
"test": "mv audit-resolve.json ~ar.json || true && node test/index.js", | ||
"debug": "DEBUG=audit-resolve-core npm test" | ||
"debug": "DEBUG=audit-resolve-core npm test", | ||
"lint": "npx standard --fix" | ||
}, | ||
@@ -14,4 +15,2 @@ "keywords": [ | ||
"dependencies", | ||
"nsp", | ||
"check", | ||
"resolve" | ||
@@ -30,6 +29,4 @@ ], | ||
"dependencies": { | ||
"concat-stream": "^1.6.2", | ||
"debug": "^4.1.1", | ||
"djv": "^2.1.2", | ||
"spawn-shell": "^2.1.0", | ||
"debug": "^4.3.1", | ||
"djv": "^2.1.4", | ||
"yargs-parser": "^18.1.3" | ||
@@ -36,0 +33,0 @@ }, |
const RESOLUTIONS = require('./RESOLUTIONS') | ||
const MILIS24H = 1000 * 60 * 60 * 24 | ||
module.exports = function decision2resolution(item) { | ||
if (!item) { | ||
return RESOLUTIONS.NONE | ||
} | ||
if (item.expiresAt < Date.now()) { | ||
return RESOLUTIONS.EXPIRED | ||
} | ||
if (item.decision === RESOLUTIONS.POSTPONE && Date.now() > item.madeAt + MILIS24H) { | ||
return RESOLUTIONS.EXPIRED | ||
} | ||
return RESOLUTIONS[RESOLUTIONS.reverseLookup[item.decision]] || RESOLUTIONS.NONE | ||
} | ||
module.exports = function decision2resolution (item) { | ||
if (!item) { | ||
return RESOLUTIONS.NONE | ||
} | ||
if (item.expiresAt < Date.now()) { | ||
return RESOLUTIONS.EXPIRED | ||
} | ||
if (item.decision === RESOLUTIONS.POSTPONE && Date.now() > item.madeAt + MILIS24H) { | ||
return RESOLUTIONS.EXPIRED | ||
} | ||
return RESOLUTIONS[RESOLUTIONS.reverseLookup[item.decision]] || RESOLUTIONS.NONE | ||
} |
const RESOLUTIONS = { | ||
NONE: 'none', | ||
FIX: 'fix', | ||
IGNORE: 'ignore', | ||
POSTPONE: 'postpone', | ||
EXPIRED: 'expired' | ||
NONE: 'none', | ||
FIX: 'fix', | ||
IGNORE: 'ignore', | ||
POSTPONE: 'postpone', | ||
EXPIRED: 'expired' | ||
} | ||
RESOLUTIONS.reverseLookup = Object.keys(RESOLUTIONS).reduce((acc, key) => { | ||
acc[RESOLUTIONS[key]] = key | ||
return acc; | ||
acc[RESOLUTIONS[key]] = key | ||
return acc | ||
}, {}) | ||
module.exports = RESOLUTIONS | ||
module.exports = RESOLUTIONS |
@@ -1,64 +0,66 @@ | ||
const auditFile = require('./auditFile'); | ||
const RESOLUTIONS = require('./resolutions/RESOLUTIONS'); | ||
const auditFile = require('./auditFile') | ||
const RESOLUTIONS = require('./resolutions/RESOLUTIONS') | ||
const { printSkipping } = require('./views/main') | ||
const decision2resolution = require('./resolutions/decision2resolution') | ||
/** | ||
* | ||
* | ||
* @param {Array<{id: string, path:string}>} items | ||
* @param { resolution: string, reason?:string, expiresAt:number } | ||
* @returns void | ||
*/ | ||
function saveResolution (items, { resolution, reason, expiresAt }) { | ||
// default expiry rules | ||
if (!expiresAt && resolution === RESOLUTIONS.IGNORE && auditFile.getRules().ignoreConfig.ignoreExpiresInDays) { | ||
expiresAt = auditFile.getRules().ignoreConfig.ignoreExpiresInDays * 24 * 60 * 60 * 1000 | ||
} | ||
items.map(item => auditFile.set( | ||
{ id: item.id, path: item.path }, | ||
{ resolution, reason, expiresAt } | ||
)) | ||
function addStatusToAction(action) { | ||
let unresolved = false; | ||
action.resolves.map(re => { | ||
let status = auditFile.get({ id: re.id, path: re.path }); | ||
if (status) { | ||
re.decision = status | ||
if (status === RESOLUTIONS.FIX) { | ||
// should have been fixed! | ||
unresolved = true | ||
} | ||
if (status === RESOLUTIONS.EXPIRED) { | ||
unresolved = true | ||
} | ||
if (status === RESOLUTIONS.NONE) { | ||
unresolved = true | ||
} | ||
} else { | ||
unresolved = true | ||
} | ||
return re; | ||
}); | ||
action.isMarkedResolved = !unresolved | ||
return action | ||
return auditFile.flush() | ||
} | ||
/** | ||
* | ||
* @param {string} identifierOrItem.id | ||
* @param {string} identifierOrItem.path | ||
* @returns { resolution: string, reason?:string, expiresAt:number } | ||
*/ | ||
function get (identifierOrItem) { | ||
return auditFile.get(identifierOrItem) | ||
} | ||
function saveResolution(action, { resolution, reason, expiresAt }) { | ||
// default expiry rules | ||
if (!expiresAt && resolution === RESOLUTIONS.IGNORE && auditFile.getRules().ignoreExpiresInDays) { | ||
expiresAt = auditFile.getRules().ignoreExpiresInDays * 24 * 60 * 60 * 1000 | ||
} | ||
action.resolves.map(re => auditFile.set( | ||
{ id: re.id, path: re.path }, | ||
{ resolution, reason, expiresAt } | ||
)) | ||
return auditFile.flush() | ||
/** | ||
* | ||
* @param {string} identifierOrItem.id | ||
* @param {string} identifierOrItem.path | ||
* @returns {string} resolution | ||
*/ | ||
function getResolution ({ id, path }) { | ||
const data = auditFile.get({ id, path }) | ||
return decision2resolution(data) | ||
} | ||
function dropResolvedActions(actions) { | ||
if (!actions) { | ||
return actions; | ||
} | ||
return actions | ||
.map(addStatusToAction) | ||
.filter(action => { | ||
if (action.isMarkedResolved) { | ||
printSkipping(action) | ||
} | ||
return !action.isMarkedResolved; | ||
}) | ||
/** | ||
* | ||
* | ||
* @param {string} identifierOrItem.id | ||
* @param {string} identifierOrItem.path | ||
* @param {string} resolution.resolution | ||
* @param [string] resolution.reason | ||
* @param [number] resolution.expiresAt | ||
* @returns | ||
*/ | ||
function set (identifierOrItem, resolution) { | ||
return auditFile.set(identifierOrItem, resolution) | ||
} | ||
module.exports = { | ||
dropResolvedActions, | ||
addStatusToAction, | ||
saveResolution | ||
}; | ||
saveResolution, | ||
getResolution, | ||
get, | ||
set | ||
} |
const assert = require('assert') | ||
const api = require('../../index') | ||
assert(api.RESOLUTIONS) | ||
const exampleItem = { id: 123, path: 'aa>bb>cc' } | ||
assert(api.RESOLUTIONS) | ||
assert(api.validateResolveFile) | ||
assert(api.identify) | ||
assert(api.getResolution) | ||
assert.doesNotThrow(() => { | ||
api.getResolution(api.identify(exampleItem)) | ||
}) | ||
assert(api.saveResolution) | ||
assert(api.get) | ||
assert(api.set) | ||
console.log('embedder passed') |
@@ -1,7 +0,7 @@ | ||
const path = require("path"); | ||
const auditFile = require("../../auditFile/index") | ||
const path = require('path') | ||
const auditFile = require('../../auditFile/index') | ||
auditFile.load(path.resolve(__dirname,"./v0.json")) | ||
auditFile.load(path.resolve(__dirname, './v0.json')) | ||
auditFile.flush() | ||
console.log("migration passed") | ||
console.log('migration passed') |
@@ -1,11 +0,11 @@ | ||
const path = require("path"); | ||
const assert = require("assert"); | ||
const auditFile = require("../../auditFile/fileHandle") | ||
const path = require('path') | ||
const assert = require('assert') | ||
const auditFile = require('../../auditFile/fileHandle') | ||
auditFile.load(path.resolve(__dirname,"./v1ok.json")) | ||
auditFile.load(path.resolve(__dirname, './v1ok.json')) | ||
assert.throws(()=>{ | ||
auditFile.load(path.resolve(__dirname,"./v1wrong.json")) | ||
assert.throws(() => { | ||
auditFile.load(path.resolve(__dirname, './v1wrong.json')) | ||
}) | ||
console.log("schemas passed") | ||
console.log('schemas passed') |
@@ -0,4 +1,5 @@ | ||
require('./api/embedder-usecase') | ||
require('./auditFile/schemas') | ||
require('./auditFile/migration') | ||
console.log('finished') | ||
console.log('finished') |
const FILE = require('../auditFile/FILE') | ||
module.exports = { | ||
printV1MigrationNotes(){ | ||
console.error(`You are using a deprecated file name. ${FILE.FILENAME_DEPRECATED} was renamed to ${FILE.FILENAME}. Any changes will be written to the new file and format.`) | ||
}, | ||
printSkipping(action) { | ||
console.error( | ||
printV1MigrationNotes () { | ||
console.error(`You are using a deprecated file name. ${FILE.FILENAME_DEPRECATED} was renamed to ${FILE.FILENAME}. Any changes will be written to the new file and format.`) | ||
}, | ||
printSkipping (action) { | ||
console.error( | ||
`skipping issues in ${action.module} based on decisions: "${Array.from(new Set(action.resolves.map(re => re.decision))).join()}" from ${FILE.FILENAME}` | ||
) | ||
} | ||
} | ||
) | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
3
1
13665
22
429
1
- Removedconcat-stream@^1.6.2
- Removedspawn-shell@^2.1.0
- Removedbuffer-from@1.1.2(transitive)
- Removedconcat-stream@1.6.2(transitive)
- Removedcore-util-is@1.0.3(transitive)
- Removeddefault-shell@1.0.1(transitive)
- Removedinherits@2.0.4(transitive)
- Removedis-plain-obj@1.1.0(transitive)
- Removedisarray@1.0.0(transitive)
- Removedmerge-options@1.0.1(transitive)
- Removednpm-run-path@2.0.2(transitive)
- Removedpath-key@2.0.1(transitive)
- Removedprocess-nextick-args@2.0.1(transitive)
- Removedreadable-stream@2.3.8(transitive)
- Removedsafe-buffer@5.1.2(transitive)
- Removedspawn-shell@2.1.0(transitive)
- Removedstring_decoder@1.1.1(transitive)
- Removedtypedarray@0.0.6(transitive)
- Removedutil-deprecate@1.0.2(transitive)
Updateddebug@^4.3.1
Updateddjv@^2.1.4