check-dependencies.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /**
  2. * Copyright (c) 2013-present, Facebook, Inc.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. 'use strict';
  8. var PluginError = require('plugin-error');
  9. var colors = require('ansi-colors');
  10. var fancyLog = require('fancy-log');
  11. var path = require('path');
  12. var semver = require('semver');
  13. var spawn = require('cross-spawn');
  14. var through = require('through2');
  15. var PLUGIN_NAME = 'check-dependencies';
  16. module.exports = function(opts) {
  17. function read(file, enc, cb) {
  18. var cwd = path.dirname(file.path);
  19. var pkgData = JSON.parse(file.contents.toString());
  20. var outdated = spawn(
  21. 'yarn',
  22. ['outdated', '--json'],
  23. { cwd: cwd }
  24. );
  25. var data = '';
  26. outdated.stdout.on('data', function(chunk) {
  27. data += chunk.toString();
  28. });
  29. outdated.on('exit', function(code) {
  30. try {
  31. // Parse the yarn outdated format (http://jsonlines.org/)
  32. var outdatedData = data
  33. .split('\n')
  34. .filter(Boolean)
  35. .map(d => JSON.parse(d))
  36. .filter(j => j.type === 'table')[0].data;
  37. } catch (e) {
  38. console.log('error', e)
  39. cb(new PluginError(PLUGIN_NAME, 'npm broke'));
  40. }
  41. // Convert ["Package", "Current",...] to {"Package": 0, ...}
  42. const name2idx = {};
  43. outdatedData.head.forEach((key, idx) => name2idx[key] = idx);
  44. const {
  45. Package: NAME,
  46. Current: CURRENT,
  47. "Package Type": TYPE
  48. } = name2idx;
  49. var failures = [];
  50. outdatedData.body.forEach(function(row) {
  51. var name = row[NAME];
  52. var current = row[CURRENT];
  53. var type = row[TYPE];
  54. var pkgDeps = pkgData[type];
  55. if (!pkgDeps) {
  56. fancyLog(`Found missing dependency category ${type}.`);
  57. return;
  58. }
  59. var requested = pkgDeps[name];
  60. if (!requested) {
  61. fancyLog('Found extraneous outdated dependency. Consider running `npm prune`');
  62. return;
  63. }
  64. if (!requested.startsWith('file:') && !semver.satisfies(current, requested)) {
  65. // Definitely wrong, so we should error
  66. failures.push({name, current, requested});
  67. }
  68. });
  69. if (failures.length) {
  70. failures.forEach((failure) => {
  71. fancyLog(
  72. `${colors.bold(failure.name)} is outdated ` +
  73. `(${colors.red(failure.current)} does not satisfy ` +
  74. `${colors.yellow(failure.requested)})`
  75. );
  76. });
  77. var msg =
  78. 'Some of your dependencies are outdated. Please run ' +
  79. `${colors.bold('npm update')} to ensure you are up to date.`;
  80. cb(new PluginError(PLUGIN_NAME, msg));
  81. return;
  82. }
  83. cb();
  84. });
  85. }
  86. return through.obj(read);
  87. };