lock-verify
Advanced tools
Comparing version 1.0.1 to 1.1.0
124
index.js
@@ -1,9 +0,5 @@ | ||
#!/usr/bin/env node | ||
'use strict' | ||
require('@iarna/cli')(main) | ||
.usage('lock-verify [projectPath]') | ||
.help() | ||
module.exports = lockVerify | ||
const fs = require('fs') | ||
const readFile = promisify(fs.readFile) | ||
const path = require('path') | ||
@@ -13,72 +9,66 @@ const npa = require('npm-package-arg') | ||
async function main (opts, check) { | ||
function lockVerify(check) { | ||
if (!check) check = '.' | ||
const pjson = await readJson(`${check}/package.json`) | ||
let plock | ||
try { | ||
plock = await readJson(`${check}/npm-shrinkwrap.json`) | ||
} catch (ex) { | ||
plock = await readJson(`${check}/package-lock.json`) | ||
} | ||
let errors = false | ||
for (let type of [['dependencies'], ['devDependencies'], ['optionalDependencies', true]]) { | ||
const deps = pjson[type[0]] | ||
if (!deps) continue | ||
const isOptional = type[1] | ||
Object.keys(deps).forEach(name => { | ||
const spec = npa.resolve(name, deps[name]) | ||
const lock = plock.dependencies[name] | ||
if (!lock) { | ||
console.error('Missing:', name + '@' + deps[name]) | ||
if (!isOptional) errors = true | ||
return | ||
} | ||
if (spec.registry) { | ||
// Can't match tags to package-lock w/o network | ||
if (spec.type === 'tag') return | ||
if (!semver.satisfies(lock.version, spec.fetchSpec)) { | ||
console.error("Invalid: lock file's", name + '@' + lock.version, 'does not satisfy', name + '@' + spec.fetchSpec) | ||
errors = true | ||
const pjson = readJson(`${check}/package.json`) | ||
let plock = readJson(`${check}/npm-shrinkwrap.json`) | ||
.catch(() => readJson(`${check}/package-lock.json`)) | ||
return Promise.all([pjson, plock]).then(result => { | ||
const pjson = result[0] | ||
const plock = result[1] | ||
let warnings = [] | ||
let errors = [] | ||
for (let type of [['dependencies'], ['devDependencies'], ['optionalDependencies', true]]) { | ||
const deps = pjson[type[0]] | ||
if (!deps) continue | ||
const isOptional = type[1] | ||
Object.keys(deps).forEach(name => { | ||
const spec = npa.resolve(name, deps[name]) | ||
const lock = plock.dependencies[name] | ||
if (!lock) { | ||
if (isOptional) { | ||
warnings.push('Optional missing: ' + name + '@' + deps[name]) | ||
} else { | ||
errors.push('Missing: ' + name + '@' + deps[name]) | ||
} | ||
return | ||
} | ||
} else if (spec.type === 'git') { | ||
// can't verify git w/o network | ||
return | ||
} else if (spec.type === 'remote') { | ||
if (lock.version !== spec.fetchSpec) { | ||
console.error("Invalid: lock file's", name + '@' + lock.version, 'does not satisfy', name + '@' + spec.fetchSpec) | ||
errors = true | ||
if (spec.registry) { | ||
// Can't match tags to package-lock w/o network | ||
if (spec.type === 'tag') return | ||
if (!semver.satisfies(lock.version, spec.fetchSpec)) { | ||
errors.push("Invalid: lock file's " + name + '@' + lock.version + ' does not satisfy ' + name + '@' + spec.fetchSpec) | ||
return | ||
} | ||
} else if (spec.type === 'git') { | ||
// can't verify git w/o network | ||
return | ||
} else if (spec.type === 'remote') { | ||
if (lock.version !== spec.fetchSpec) { | ||
errors.push("Invalid: lock file's " + name + '@' + lock.version + ' does not satisfy ' + name + '@' + spec.fetchSpec) | ||
return | ||
} | ||
} else if (spec.type === 'file' || spec.type === 'directory') { | ||
const lockSpec = npa.resolve(name, lock.version) | ||
if (spec.fetchSpec !== lockSpec.fetchSpec) { | ||
errors.push("Invalid: lock file's " + name + '@' + lock.version + ' does not satisfy ' + name + '@' + deps[name]) | ||
return | ||
} | ||
} else { | ||
console.log(spec) | ||
} | ||
} else if (spec.type === 'file' || spec.type === 'directory') { | ||
const lockSpec = npa.resolve(name, lock.version) | ||
if (spec.fetchSpec !== lockSpec.fetchSpec) { | ||
console.error("Invalid: lock file's", name + '@' + lock.version, 'does not satisfy', name + '@' + deps[name]) | ||
errors = true | ||
return | ||
} | ||
} else { | ||
console.log(spec) | ||
} | ||
}) | ||
} | ||
if (errors) return Promise.reject('Errors found') | ||
}) | ||
} | ||
return Promise.resolve({status: errors.length === 0, warnings: warnings, errors: errors}) | ||
}) | ||
} | ||
async function readJson (file) { | ||
return JSON.parse(await readFile(file)) | ||
} | ||
function promisify (fn) { | ||
return function asPromised () { | ||
return new Promise((resolve, reject) => { | ||
const args = new Array(arguments.length + 1) | ||
const cbIndex = arguments.length | ||
for (var ii = 0; ii < arguments.length; ++ii) { | ||
args[ii] = arguments[ii] | ||
} | ||
args[cbIndex] = (err, value) => err ? reject(err) : resolve(value) | ||
fn.apply(this, args) | ||
function readJson (file) { | ||
return new Promise((resolve, reject) => { | ||
fs.readFile(file, (err, content) => { | ||
if (err) return reject(err) | ||
return resolve(JSON.parse(content)) | ||
}) | ||
} | ||
}) | ||
} |
{ | ||
"name": "lock-verify", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "Report if your package.json is out of sync with your package-lock.json.", | ||
"bin": "index.js", | ||
"bin": "cli.js", | ||
"main": "index.js", | ||
"scripts": { | ||
@@ -13,5 +14,5 @@ "test": "echo \"Error: no test specified\" && exit 1" | ||
"dependencies": { | ||
"@iarna/cli": "1.1.0", | ||
"@iarna/cli": "^1.2.0", | ||
"npm-package-arg": "^5.1.2", | ||
"semver": "^5.3.0" | ||
"semver": "^5.4.1" | ||
}, | ||
@@ -18,0 +19,0 @@ "devDependencies": {}, |
@@ -26,1 +26,20 @@ # lock-verify | ||
``` | ||
## OR AS A LIBRARY | ||
``` | ||
const lockVerify = require('lock-verify') | ||
lockVerify(moduleDir).then(result => { | ||
result.warnings.forEach(w => console.error('Warning:', w)) | ||
if (!result.status) { | ||
result.errors.forEach(e => console.error(e)) | ||
process.exit(1) | ||
} | ||
}) | ||
``` | ||
As a library it's a function that takes the path to a module and returns a | ||
promise that resolves to an object with `.status`, `.warnings` and `.errors` | ||
properties. The first will be true if everything was ok (though warnings | ||
may exist). If there's no `package.json` or no lockfile in `moduleDir` or they're | ||
unreadable then the promise will be rejected. |
5580
83
45
+ Added@iarna/cli@1.2.0(transitive)
- Removed@iarna/cli@1.1.0(transitive)
Updated@iarna/cli@^1.2.0
Updatedsemver@^5.4.1