semver.js
  1  #!/usr/bin/env node
  2  // Standalone semver comparison program.
  3  // Exits successfully and prints matching version(s) if
  4  // any supplied version is valid and passes all tests.
  5  
  6  var argv = process.argv.slice(2)
  7  
  8  var versions = []
  9  
 10  var range = []
 11  
 12  var inc = null
 13  
 14  var version = require('../package.json').version
 15  
 16  var loose = false
 17  
 18  var includePrerelease = false
 19  
 20  var coerce = false
 21  
 22  var rtl = false
 23  
 24  var identifier
 25  
 26  var semver = require('../semver')
 27  
 28  var reverse = false
 29  
 30  var options = {}
 31  
 32  main()
 33  
 34  function main () {
 35    if (!argv.length) return help()
 36    while (argv.length) {
 37      var a = argv.shift()
 38      var indexOfEqualSign = a.indexOf('=')
 39      if (indexOfEqualSign !== -1) {
 40        a = a.slice(0, indexOfEqualSign)
 41        argv.unshift(a.slice(indexOfEqualSign + 1))
 42      }
 43      switch (a) {
 44        case '-rv': case '-rev': case '--rev': case '--reverse':
 45          reverse = true
 46          break
 47        case '-l': case '--loose':
 48          loose = true
 49          break
 50        case '-p': case '--include-prerelease':
 51          includePrerelease = true
 52          break
 53        case '-v': case '--version':
 54          versions.push(argv.shift())
 55          break
 56        case '-i': case '--inc': case '--increment':
 57          switch (argv[0]) {
 58            case 'major': case 'minor': case 'patch': case 'prerelease':
 59            case 'premajor': case 'preminor': case 'prepatch':
 60              inc = argv.shift()
 61              break
 62            default:
 63              inc = 'patch'
 64              break
 65          }
 66          break
 67        case '--preid':
 68          identifier = argv.shift()
 69          break
 70        case '-r': case '--range':
 71          range.push(argv.shift())
 72          break
 73        case '-c': case '--coerce':
 74          coerce = true
 75          break
 76        case '--rtl':
 77          rtl = true
 78          break
 79        case '--ltr':
 80          rtl = false
 81          break
 82        case '-h': case '--help': case '-?':
 83          return help()
 84        default:
 85          versions.push(a)
 86          break
 87      }
 88    }
 89  
 90    var options = { loose: loose, includePrerelease: includePrerelease, rtl: rtl }
 91  
 92    versions = versions.map(function (v) {
 93      return coerce ? (semver.coerce(v, options) || { version: v }).version : v
 94    }).filter(function (v) {
 95      return semver.valid(v)
 96    })
 97    if (!versions.length) return fail()
 98    if (inc && (versions.length !== 1 || range.length)) { return failInc() }
 99  
100    for (var i = 0, l = range.length; i < l; i++) {
101      versions = versions.filter(function (v) {
102        return semver.satisfies(v, range[i], options)
103      })
104      if (!versions.length) return fail()
105    }
106    return success(versions)
107  }
108  
109  function failInc () {
110    console.error('--inc can only be used on a single version with no range')
111    fail()
112  }
113  
114  function fail () { process.exit(1) }
115  
116  function success () {
117    var compare = reverse ? 'rcompare' : 'compare'
118    versions.sort(function (a, b) {
119      return semver[compare](a, b, options)
120    }).map(function (v) {
121      return semver.clean(v, options)
122    }).map(function (v) {
123      return inc ? semver.inc(v, inc, options, identifier) : v
124    }).forEach(function (v, i, _) { console.log(v) })
125  }
126  
127  function help () {
128    console.log(['SemVer ' + version,
129      '',
130      'A JavaScript implementation of the https://semver.org/ specification',
131      'Copyright Isaac Z. Schlueter',
132      '',
133      'Usage: semver [options] <version> [<version> [...]]',
134      'Prints valid versions sorted by SemVer precedence',
135      '',
136      'Options:',
137      '-r --range <range>',
138      '        Print versions that match the specified range.',
139      '',
140      '-i --increment [<level>]',
141      '        Increment a version by the specified level.  Level can',
142      '        be one of: major, minor, patch, premajor, preminor,',
143      "        prepatch, or prerelease.  Default level is 'patch'.",
144      '        Only one version may be specified.',
145      '',
146      '--preid <identifier>',
147      '        Identifier to be used to prefix premajor, preminor,',
148      '        prepatch or prerelease version increments.',
149      '',
150      '-l --loose',
151      '        Interpret versions and ranges loosely',
152      '',
153      '-p --include-prerelease',
154      '        Always include prerelease versions in range matching',
155      '',
156      '-c --coerce',
157      '        Coerce a string into SemVer if possible',
158      '        (does not imply --loose)',
159      '',
160      '--rtl',
161      '        Coerce version strings right to left',
162      '',
163      '--ltr',
164      '        Coerce version strings left to right (default)',
165      '',
166      'Program exits successfully if any valid version satisfies',
167      'all supplied ranges, and prints all satisfying versions.',
168      '',
169      'If no satisfying versions are found, then exits failure.',
170      '',
171      'Versions are printed in ascending order, so supplying',
172      'multiple versions to the utility will just sort them.'
173    ].join('\n'))
174  }