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