index.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. 'use strict'
  2. module.exports = lockVerify
  3. const fs = require('fs')
  4. const path = require('path')
  5. const npa = require('npm-package-arg')
  6. const semver = require('semver')
  7. function lockVerify(check) {
  8. if (!check) check = '.'
  9. const pjson = readJson(`${check}/package.json`)
  10. let plock = readJson(`${check}/npm-shrinkwrap.json`)
  11. .catch(() => readJson(`${check}/package-lock.json`))
  12. return Promise.all([pjson, plock]).then(result => {
  13. const pjson = result[0]
  14. const plock = result[1]
  15. let warnings = []
  16. let errors = []
  17. for (let type of [['dependencies'], ['devDependencies'], ['optionalDependencies', true]]) {
  18. const deps = pjson[type[0]]
  19. if (!deps) continue
  20. const isOptional = type[1]
  21. Object.keys(deps).forEach(name => {
  22. const spec = npa.resolve(name, deps[name])
  23. const lock = plock.dependencies[name]
  24. if (!lock) {
  25. if (isOptional) {
  26. warnings.push('Optional missing: ' + name + '@' + deps[name])
  27. } else {
  28. errors.push('Missing: ' + name + '@' + deps[name])
  29. }
  30. return
  31. }
  32. if (spec.registry) {
  33. // Can't match tags to package-lock w/o network
  34. if (spec.type === 'tag') return
  35. if (spec.type === 'alias') {
  36. const lockSpec = npa.resolve(name, lock.version)
  37. if (!semver.satisfies(lockSpec.subSpec.fetchSpec, spec.subSpec.fetchSpec)) {
  38. errors.push("Invalid: lock file's " + name + '@' + lock.version + ' does not satisfy ' + name + '@' + spec.rawSpec)
  39. return
  40. }
  41. } else {
  42. if (!semver.satisfies(lock.version, spec.fetchSpec)) {
  43. errors.push("Invalid: lock file's " + name + '@' + lock.version + ' does not satisfy ' + name + '@' + spec.fetchSpec)
  44. return
  45. }
  46. }
  47. } else if (spec.type === 'git') {
  48. // can't verify git w/o network
  49. return
  50. } else if (spec.type === 'remote') {
  51. if (lock.version !== spec.fetchSpec) {
  52. errors.push("Invalid: lock file's " + name + '@' + lock.version + ' does not satisfy ' + name + '@' + spec.fetchSpec)
  53. return
  54. }
  55. } else if (spec.type === 'file' || spec.type === 'directory') {
  56. const lockSpec = npa.resolve(name, lock.version)
  57. if (spec.fetchSpec !== lockSpec.fetchSpec) {
  58. errors.push("Invalid: lock file's " + name + '@' + lock.version + ' does not satisfy ' + name + '@' + deps[name])
  59. return
  60. }
  61. } else {
  62. console.log(spec)
  63. }
  64. })
  65. }
  66. return Promise.resolve({status: errors.length === 0, warnings: warnings, errors: errors})
  67. })
  68. }
  69. function readJson (file) {
  70. return new Promise((resolve, reject) => {
  71. fs.readFile(file, (err, content) => {
  72. if (err) return reject(err)
  73. return resolve(JSON.parse(content))
  74. })
  75. })
  76. }