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