src/registry.js
function fetchVersions (options, nameVersion) {
    // console.log(nameVersion);
    // TODO use check.schema
  check.verify.object(nameVersion, 'expected name, version object')
  var name = nameVersion.name
  var version = nameVersion.version
  check.verify.string(name, 'missing name string')
  check.verify.string(version, 'missing version string')

  var cleanVersionForName = _.partial(cleanVersionFor, name)
  function isLaterVersion (ver) {
    var later = semver.gt(ver, version)
    return later
  }

    // console.log('fetching versions for', name, 'current version', version);
  var MAX_WAIT_TIMEOUT = options.checkVersionTimeout || 25000
  var deferred = q.defer()

  function rejectOnTimeout () {
    var msg = 'timed out waiting for NPM for package ' + name +
            ' after ' + MAX_WAIT_TIMEOUT + 'ms'
    console.error(msg)
    deferred.reject(msg)
  }

  function escapeName (str) {
    return str.replace('/', '%2F')
  }

  registryUrl().then(function (npmUrl) {
    log('NPM registry url', npmUrl)
    la(check.webUrl(npmUrl), 'need npm registry url, got', npmUrl)

    npmUrl = npmUrl.replace(/^https:/, 'http:').trim()
    var url = (options.registry || npmUrl) + escapeName(name)

        // TODO how to detect if the registry is not responding?

    log('getting url', url)
    request.get(url, onNPMversions)
    var timer = setTimeout(rejectOnTimeout, MAX_WAIT_TIMEOUT)

    function onNPMversions (err, response, body) {
      log('got response for', url)
      clearTimeout(timer)

      if (err) {
        console.error('ERROR when fetching info for package', name)
        deferred.reject(err.message)
        return
      }

      if (is404(response)) {
        log('404 response for', url)
        deferred.resolve({
          name: name,
          versions: []
        })
        return
      }

      try {
        log('parsing response body')
        var info = JSON.parse(body)
        log('parsed response, error?', info.error)
        if (info.error) {
          log('error parsing\n' + body + '\n')
          var str = formNpmErrorMessage(name, info)
          console.error(str)

          if (isNotFound(info.error)) {
            deferred.resolve({
              name: name,
              versions: []
            })
            return
          }

          deferred.reject(str)
          return
        }
        log('extracting versions')
        var versions = extractVersions(info)
        log('%d versions', versions.length)

        if (!Array.isArray(versions)) {
          throw new Error('Could not get versions for ' + name +
                        ' from ' + JSON.stringify(info) +
                        ' response ' + JSON.stringify(response, null, 2))
        }

        var validVersions = versions.filter(cleanVersionForName)
        var newerVersions = validVersions.filter(isLaterVersion)
        log('%d valid versions', validVersions.length)
        if (validVersions.length) {
          log('last version %s', R.last(validVersions))
        }
        if (newerVersions.length) {
          log('%d newer versions', newerVersions.length)
          log('from %s to %s', R.head(newerVersions), R.last(newerVersions))
        }

        deferred.resolve({
          name: name,
          versions: newerVersions
        })
        return
      } catch (err) {
        console.error(err)
        deferred.reject('Could not fetch versions for ' + name)
      }
    }
  })

  return deferred.promise
}
function fetchVersions (options, nameVersion) {
    // console.log(nameVersion);
    // TODO use check.schema
  check.verify.object(nameVersion, 'expected name, version object')
  var name = nameVersion.name
  var version = nameVersion.version
  check.verify.string(name, 'missing name string')
  check.verify.string(version, 'missing version string')

  var cleanVersionForName = _.partial(cleanVersionFor, name)
  function isLaterVersion (ver) {
    var later = semver.gt(ver, version)
    return later
  }

    // console.log('fetching versions for', name, 'current version', version);
  var MAX_WAIT_TIMEOUT = options.checkVersionTimeout || 25000
  var deferred = q.defer()

  function rejectOnTimeout () {
    var msg = 'timed out waiting for NPM for package ' + name +
            ' after ' + MAX_WAIT_TIMEOUT + 'ms'
    console.error(msg)
    deferred.reject(msg)
  }

  function escapeName (str) {
    return str.replace('/', '%2F')
  }

  registryUrl().then(function (npmUrl) {
    log('NPM registry url', npmUrl)
    la(check.webUrl(npmUrl), 'need npm registry url, got', npmUrl)

    npmUrl = npmUrl.replace(/^https:/, 'http:').trim()
    var url = (options.registry || npmUrl) + escapeName(name)

        // TODO how to detect if the registry is not responding?

    log('getting url', url)
    request.get(url, onNPMversions)
    var timer = setTimeout(rejectOnTimeout, MAX_WAIT_TIMEOUT)

    function onNPMversions (err, response, body) {
      log('got response for', url)
      clearTimeout(timer)

      if (err) {
        console.error('ERROR when fetching info for package', name)
        deferred.reject(err.message)
        return
      }

      if (is404(response)) {
        log('404 response for', url)
        deferred.resolve({
          name: name,
          versions: []
        })
        return
      }

      try {
        log('parsing response body')
        var info = JSON.parse(body)
        log('parsed response, error?', info.error)
        if (info.error) {
          log('error parsing\n' + body + '\n')
          var str = formNpmErrorMessage(name, info)
          console.error(str)

          if (isNotFound(info.error)) {
            deferred.resolve({
              name: name,
              versions: []
            })
            return
          }

          deferred.reject(str)
          return
        }
        log('extracting versions')
        var versions = extractVersions(info)
        log('%d versions', versions.length)

        if (!Array.isArray(versions)) {
          throw new Error('Could not get versions for ' + name +
                        ' from ' + JSON.stringify(info) +
                        ' response ' + JSON.stringify(response, null, 2))
        }

        var validVersions = versions.filter(cleanVersionForName)
        var newerVersions = validVersions.filter(isLaterVersion)
        log('%d valid versions', validVersions.length)
        if (validVersions.length) {
          log('last version %s', R.last(validVersions))
        }
        if (newerVersions.length) {
          log('%d newer versions', newerVersions.length)
          log('from %s to %s', R.head(newerVersions), R.last(newerVersions))
        }

        deferred.resolve({
          name: name,
          versions: newerVersions
        })
        return
      } catch (err) {
        console.error(err)
        deferred.reject('Could not fetch versions for ' + name)
      }
    }
  })

  return deferred.promise
}
fetching versions inspired by https://github.com/jprichardson/npm-latest returns a promise