validate-tree.js 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. 'use strict'
  2. var path = require('path')
  3. var validate = require('aproba')
  4. var asyncMap = require('slide').asyncMap
  5. var chain = require('slide').chain
  6. var npmInstallChecks = require('npm-install-checks')
  7. var checkGit = npmInstallChecks.checkGit
  8. var clone = require('lodash.clonedeep')
  9. var normalizePackageData = require('normalize-package-data')
  10. var npm = require('../npm.js')
  11. var andFinishTracker = require('./and-finish-tracker.js')
  12. var flattenTree = require('./flatten-tree.js')
  13. var validateAllPeerDeps = require('./deps.js').validateAllPeerDeps
  14. var packageId = require('../utils/package-id.js')
  15. module.exports = function (idealTree, log, next) {
  16. validate('OOF', arguments)
  17. var moduleMap = flattenTree(idealTree)
  18. var modules = Object.keys(moduleMap).map(function (name) { return moduleMap[name] })
  19. chain([
  20. [asyncMap, modules, function (mod, done) {
  21. chain([
  22. mod.parent && !mod.isLink && [checkGit, mod.realpath],
  23. [checkErrors, mod, idealTree]
  24. ], done)
  25. }],
  26. [thenValidateAllPeerDeps, idealTree],
  27. [thenCheckTop, idealTree],
  28. [thenCheckDuplicateDeps, idealTree]
  29. ], andFinishTracker(log, next))
  30. }
  31. function checkErrors (mod, idealTree, next) {
  32. if (mod.error && (mod.parent || path.resolve(npm.globalDir, '..') !== mod.path)) idealTree.warnings.push(mod.error)
  33. next()
  34. }
  35. function thenValidateAllPeerDeps (idealTree, next) {
  36. validate('OF', arguments)
  37. validateAllPeerDeps(idealTree, function (tree, pkgname, version) {
  38. var warn = new Error(packageId(tree) + ' requires a peer of ' + pkgname + '@' +
  39. version + ' but none is installed. You must install peer dependencies yourself.')
  40. warn.code = 'EPEERINVALID'
  41. idealTree.warnings.push(warn)
  42. })
  43. next()
  44. }
  45. function thenCheckTop (idealTree, next) {
  46. validate('OF', arguments)
  47. if (idealTree.package.error) return next()
  48. // FIXME: when we replace read-package-json with something less magic,
  49. // this should done elsewhere.
  50. // As it is, the package has already been normalized and thus some
  51. // errors are suppressed.
  52. var pkg = clone(idealTree.package)
  53. try {
  54. normalizePackageData(pkg, function (warn) {
  55. var warnObj = new Error(packageId(idealTree) + ' ' + warn)
  56. warnObj.code = 'EPACKAGEJSON'
  57. idealTree.warnings.push(warnObj)
  58. }, false)
  59. } catch (er) {
  60. er.code = 'EPACKAGEJSON'
  61. idealTree.warnings.push(er)
  62. }
  63. var nodeVersion = npm.config.get('node-version')
  64. if (/-/.test(nodeVersion)) {
  65. // if this is a prerelease node…
  66. var warnObj = new Error('You are using a pre-release version of node and things may not work as expected')
  67. warnObj.code = 'ENODEPRE'
  68. idealTree.warnings.push(warnObj)
  69. }
  70. next()
  71. }
  72. // check for deps duplciated between devdeps and regular deps
  73. function thenCheckDuplicateDeps (idealTree, next) {
  74. var deps = idealTree.package.dependencies || {}
  75. var devDeps = idealTree.package.devDependencies || {}
  76. for (var pkg in devDeps) {
  77. if (pkg in deps) {
  78. var warnObj = new Error('The package ' + pkg + ' is included as both a dev and production dependency.')
  79. warnObj.code = 'EDUPLICATEDEP'
  80. idealTree.warnings.push(warnObj)
  81. }
  82. }
  83. next()
  84. }