"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/npm/lib/outdated.js" (7 Feb 2017, 12389 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2 
    3 npm outdated [pkg]
    4 
    5 Does the following:
    6 
    7 1. check for a new version of pkg
    8 
    9 If no packages are specified, then run for all installed
   10 packages.
   11 
   12 --parseable creates output like this:
   13 <fullpath>:<name@wanted>:<name@installed>:<name@latest>
   14 
   15 */
   16 
   17 module.exports = outdated
   18 
   19 outdated.usage = 'npm outdated [[<@scope>/]<pkg> ...]'
   20 
   21 outdated.completion = require('./utils/completion/installed-deep.js')
   22 
   23 var os = require('os')
   24 var url = require('url')
   25 var path = require('path')
   26 var log = require('npmlog')
   27 var readPackageTree = require('read-package-tree')
   28 var readJson = require('read-package-json')
   29 var asyncMap = require('slide').asyncMap
   30 var color = require('ansicolors')
   31 var styles = require('ansistyles')
   32 var table = require('text-table')
   33 var semver = require('semver')
   34 var npa = require('npm-package-arg')
   35 var mutateIntoLogicalTree = require('./install/mutate-into-logical-tree.js')
   36 var cache = require('./cache.js')
   37 var npm = require('./npm.js')
   38 var long = npm.config.get('long')
   39 var mapToRegistry = require('./utils/map-to-registry.js')
   40 var isExtraneous = require('./install/is-extraneous.js')
   41 var recalculateMetadata = require('./install/deps.js').recalculateMetadata
   42 var moduleName = require('./utils/module-name.js')
   43 var output = require('./utils/output.js')
   44 
   45 function uniqName (item) {
   46   return item[0].path + '|' + item[1] + '|' + item[7]
   47 }
   48 
   49 function uniq (list) {
   50   var uniqed = []
   51   var seen = {}
   52   list.forEach(function (item) {
   53     var name = uniqName(item)
   54     if (seen[name]) return
   55     seen[name] = true
   56     uniqed.push(item)
   57   })
   58   return uniqed
   59 }
   60 
   61 function andRecalculateMetadata (next) {
   62   return function (er, tree) {
   63     if (er) return next(er)
   64     recalculateMetadata(tree, log, next)
   65   }
   66 }
   67 
   68 function outdated (args, silent, cb) {
   69   if (typeof cb !== 'function') {
   70     cb = silent
   71     silent = false
   72   }
   73   var dir = path.resolve(npm.dir, '..')
   74 
   75   // default depth for `outdated` is 0 (cf. `ls`)
   76   if (npm.config.get('depth') === Infinity) npm.config.set('depth', 0)
   77 
   78   readPackageTree(dir, andRecalculateMetadata(function (er, tree) {
   79     if (!tree) return cb(er)
   80     mutateIntoLogicalTree(tree)
   81     outdated_(args, '', tree, {}, 0, function (er, list) {
   82       list = uniq(list || []).sort(function (aa, bb) {
   83         return aa[0].path.localeCompare(bb[0].path) ||
   84           aa[1].localeCompare(bb[1])
   85       })
   86       if (er || silent || list.length === 0) return cb(er, list)
   87       if (npm.config.get('json')) {
   88         output(makeJSON(list))
   89       } else if (npm.config.get('parseable')) {
   90         output(makeParseable(list))
   91       } else {
   92         var outList = list.map(makePretty)
   93         var outHead = [ 'Package',
   94                         'Current',
   95                         'Wanted',
   96                         'Latest',
   97                         'Location'
   98                       ]
   99         if (long) outHead.push('Package Type')
  100         var outTable = [outHead].concat(outList)
  101 
  102         if (npm.color) {
  103           outTable[0] = outTable[0].map(function (heading) {
  104             return styles.underline(heading)
  105           })
  106         }
  107 
  108         var tableOpts = {
  109           align: ['l', 'r', 'r', 'r', 'l'],
  110           stringLength: function (s) { return ansiTrim(s).length }
  111         }
  112         output(table(outTable, tableOpts))
  113       }
  114       cb(null, list.map(function (item) { return [item[0].parent.path].concat(item.slice(1, 7)) }))
  115     })
  116   }))
  117 }
  118 
  119 // [[ dir, dep, has, want, latest, type ]]
  120 function makePretty (p) {
  121   var dep = p[0]
  122   var depname = p[1]
  123   var dir = dep.path
  124   var has = p[2]
  125   var want = p[3]
  126   var latest = p[4]
  127   var type = p[6]
  128   var deppath = p[7]
  129 
  130   if (!npm.config.get('global')) {
  131     dir = path.relative(process.cwd(), dir)
  132   }
  133 
  134   var columns = [ depname,
  135                   has || 'MISSING',
  136                   want,
  137                   latest,
  138                   deppath
  139                 ]
  140   if (long) columns[5] = type
  141 
  142   if (npm.color) {
  143     columns[0] = color[has === want || want === 'linked' ? 'yellow' : 'red'](columns[0]) // dep
  144     columns[2] = color.green(columns[2]) // want
  145     columns[3] = color.magenta(columns[3]) // latest
  146   }
  147 
  148   return columns
  149 }
  150 
  151 function ansiTrim (str) {
  152   var r = new RegExp('\x1b(?:\\[(?:\\d+[ABCDEFGJKSTm]|\\d+;\\d+[Hfm]|' +
  153         '\\d+;\\d+;\\d+m|6n|s|u|\\?25[lh])|\\w)', 'g')
  154   return str.replace(r, '')
  155 }
  156 
  157 function makeParseable (list) {
  158   return list.map(function (p) {
  159     var dep = p[0]
  160     var depname = p[1]
  161     var dir = dep.path
  162     var has = p[2]
  163     var want = p[3]
  164     var latest = p[4]
  165     var type = p[6]
  166 
  167     var out = [
  168       dir,
  169       depname + '@' + want,
  170       (has ? (depname + '@' + has) : 'MISSING'),
  171       depname + '@' + latest
  172     ]
  173     if (long) out.push(type)
  174 
  175     return out.join(':')
  176   }).join(os.EOL)
  177 }
  178 
  179 function makeJSON (list) {
  180   var out = {}
  181   list.forEach(function (p) {
  182     var dep = p[0]
  183     var depname = p[1]
  184     var dir = dep.path
  185     var has = p[2]
  186     var want = p[3]
  187     var latest = p[4]
  188     var type = p[6]
  189     if (!npm.config.get('global')) {
  190       dir = path.relative(process.cwd(), dir)
  191     }
  192     out[depname] = { current: has,
  193                   wanted: want,
  194                   latest: latest,
  195                   location: dir
  196                 }
  197     if (long) out[depname].type = type
  198   })
  199   return JSON.stringify(out, null, 2)
  200 }
  201 
  202 function outdated_ (args, path, tree, parentHas, depth, cb) {
  203   if (!tree.package) tree.package = {}
  204   if (path && tree.package.name) path += ' > ' + tree.package.name
  205   if (!path && tree.package.name) path = tree.package.name
  206   if (depth > npm.config.get('depth')) {
  207     return cb(null, [])
  208   }
  209   var types = {}
  210   var pkg = tree.package
  211 
  212   var deps = tree.children.filter(function (child) { return !isExtraneous(child) }) || []
  213 
  214   deps.forEach(function (dep) {
  215     types[moduleName(dep)] = 'dependencies'
  216   })
  217 
  218   Object.keys(tree.missingDeps).forEach(function (name) {
  219     deps.push({
  220       package: { name: name },
  221       path: tree.path,
  222       parent: tree,
  223       isMissing: true
  224     })
  225     types[name] = 'dependencies'
  226   })
  227 
  228   // If we explicitly asked for dev deps OR we didn't ask for production deps
  229   // AND we asked to save dev-deps OR we didn't ask to save anything that's NOT
  230   // dev deps then…
  231   // (All the save checking here is because this gets called from npm-update currently
  232   // and that requires this logic around dev deps.)
  233   // FIXME: Refactor npm update to not be in terms of outdated.
  234   var dev = npm.config.get('dev') || /^dev(elopment)?$/.test(npm.config.get('also'))
  235   var prod = npm.config.get('production') || /^prod(uction)?$/.test(npm.config.get('only'))
  236   if ((dev || !prod) &&
  237       (npm.config.get('save-dev') || (
  238         !npm.config.get('save') && !npm.config.get('save-optional')))) {
  239     Object.keys(tree.missingDevDeps).forEach(function (name) {
  240       deps.push({
  241         package: { name: name },
  242         path: tree.path,
  243         parent: tree,
  244         isMissing: true
  245       })
  246       if (!types[name]) {
  247         types[name] = 'devDependencies'
  248       }
  249     })
  250   }
  251 
  252   if (npm.config.get('save-dev')) {
  253     deps = deps.filter(function (dep) { return pkg.devDependencies[moduleName(dep)] })
  254     deps.forEach(function (dep) {
  255       types[moduleName(dep)] = 'devDependencies'
  256     })
  257   } else if (npm.config.get('save')) {
  258     // remove optional dependencies from dependencies during --save.
  259     deps = deps.filter(function (dep) { return !pkg.optionalDependencies[moduleName(dep)] })
  260   } else if (npm.config.get('save-optional')) {
  261     deps = deps.filter(function (dep) { return pkg.optionalDependencies[moduleName(dep)] })
  262     deps.forEach(function (dep) {
  263       types[moduleName(dep)] = 'optionalDependencies'
  264     })
  265   }
  266   var doUpdate = dev || (
  267     !prod &&
  268     !Object.keys(parentHas).length &&
  269     !npm.config.get('global')
  270   )
  271   if (doUpdate) {
  272     Object.keys(pkg.devDependencies).forEach(function (k) {
  273       if (!(k in parentHas)) {
  274         deps[k] = pkg.devDependencies[k]
  275         types[k] = 'devDependencies'
  276       }
  277     })
  278   }
  279 
  280   var has = Object.create(parentHas)
  281   tree.children.forEach(function (child) {
  282     if (child.package.name && child.package.private) {
  283       deps = deps.filter(function (dep) { return dep !== child })
  284     }
  285     has[child.package.name] = {
  286       version: child.package.version,
  287       from: child.package._from
  288     }
  289   })
  290 
  291   // now get what we should have, based on the dep.
  292   // if has[dep] !== shouldHave[dep], then cb with the data
  293   // otherwise dive into the folder
  294   asyncMap(deps, function (dep, cb) {
  295     var name = moduleName(dep)
  296     var required = (tree.package.dependencies)[name] ||
  297                    (tree.package.optionalDependencies)[name] ||
  298                    (tree.package.devDependencies)[name] ||
  299                    dep.package._requested && dep.package._requested.spec ||
  300                    '*'
  301     if (!long) return shouldUpdate(args, dep, name, has, required, depth, path, cb)
  302 
  303     shouldUpdate(args, dep, name, has, required, depth, path, cb, types[name])
  304   }, cb)
  305 }
  306 
  307 function shouldUpdate (args, tree, dep, has, req, depth, pkgpath, cb, type) {
  308   // look up the most recent version.
  309   // if that's what we already have, or if it's not on the args list,
  310   // then dive into it.  Otherwise, cb() with the data.
  311 
  312   // { version: , from: }
  313   var curr = has[dep]
  314 
  315   function skip (er) {
  316     // show user that no viable version can be found
  317     if (er) return cb(er)
  318     outdated_(args,
  319               pkgpath,
  320               tree,
  321               has,
  322               depth + 1,
  323               cb)
  324   }
  325 
  326   function doIt (wanted, latest) {
  327     if (!long) {
  328       return cb(null, [[tree, dep, curr && curr.version, wanted, latest, req, null, pkgpath]])
  329     }
  330     cb(null, [[tree, dep, curr && curr.version, wanted, latest, req, type, pkgpath]])
  331   }
  332 
  333   if (args.length && args.indexOf(dep) === -1) return skip()
  334   var parsed = npa(dep + '@' + req)
  335   if (tree.isLink && tree.parent && tree.parent.isTop) {
  336     return doIt('linked', 'linked')
  337   }
  338   if (parsed.type === 'git' || parsed.type === 'hosted') {
  339     return doIt('git', 'git')
  340   }
  341 
  342   // search for the latest package
  343   mapToRegistry(dep, npm.config, function (er, uri, auth) {
  344     if (er) return cb(er)
  345 
  346     npm.registry.get(uri, { auth: auth }, updateDeps)
  347   })
  348 
  349   function updateLocalDeps (latestRegistryVersion) {
  350     readJson(path.resolve(parsed.spec, 'package.json'), function (er, localDependency) {
  351       if (er) return cb()
  352 
  353       var wanted = localDependency.version
  354       var latest = localDependency.version
  355 
  356       if (latestRegistryVersion) {
  357         latest = latestRegistryVersion
  358         if (semver.lt(wanted, latestRegistryVersion)) {
  359           wanted = latestRegistryVersion
  360           req = dep + '@' + latest
  361         }
  362       }
  363 
  364       if (curr.version !== wanted) {
  365         doIt(wanted, latest)
  366       } else {
  367         skip()
  368       }
  369     })
  370   }
  371 
  372   function updateDeps (er, d) {
  373     if (er) {
  374       if (parsed.type !== 'local') return cb(er)
  375       return updateLocalDeps()
  376     }
  377 
  378     if (!d || !d['dist-tags'] || !d.versions) return cb()
  379     var l = d.versions[d['dist-tags'].latest]
  380     if (!l) return cb()
  381 
  382     var r = req
  383     if (d['dist-tags'][req]) {
  384       r = d['dist-tags'][req]
  385     }
  386 
  387     if (semver.validRange(r, true)) {
  388       // some kind of semver range.
  389       // see if it's in the doc.
  390       var vers = Object.keys(d.versions)
  391       var v = semver.maxSatisfying(vers, r, true)
  392       if (v) {
  393         return onCacheAdd(null, d.versions[v])
  394       }
  395     }
  396 
  397     // We didn't find the version in the doc.  See if cache can find it.
  398     cache.add(dep, req, null, false, onCacheAdd)
  399 
  400     function onCacheAdd (er, d) {
  401       // if this fails, then it means we can't update this thing.
  402       // it's probably a thing that isn't published.
  403       if (er) {
  404         if (er.code && er.code === 'ETARGET') {
  405           // no viable version found
  406           return skip(er)
  407         }
  408         return skip()
  409       }
  410 
  411       // check that the url origin hasn't changed (#1727) and that
  412       // there is no newer version available
  413       var dFromUrl = d._from && url.parse(d._from).protocol
  414       var cFromUrl = curr && curr.from && url.parse(curr.from).protocol
  415 
  416       if (!curr ||
  417           dFromUrl && cFromUrl && d._from !== curr.from ||
  418           d.version !== curr.version ||
  419           d.version !== l.version) {
  420         if (parsed.type === 'local') return updateLocalDeps(l.version)
  421 
  422         doIt(d.version, l.version)
  423       } else {
  424         skip()
  425       }
  426     }
  427   }
  428 }