diff --git a/Makefile b/Makefile index ed714fe..d06ea42 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ .PHONY: test test: npx eslint --color --quiet *.js + node --trace-deprecation --throw-deprecation test.js .PHONY: publish publish: diff --git a/package.json b/package.json index 62d2897..d28e481 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "devDependencies": { "eslint": "5.12.1", "eslint-config-silverwind": "2.0.14", + "execa": "^1.0.0", "ver": "3.0.1" } } diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..b17fe43 Binary files /dev/null and b/screenshot.png differ diff --git a/test.js b/test.js new file mode 100644 index 0000000..b17f45b --- /dev/null +++ b/test.js @@ -0,0 +1,50 @@ +"use strict"; + +const assert = require("assert"); +const process = require("process"); +const execa = require("execa"); + +function exit(err) { + if (err) { + console.info(err); + } + process.exit(err ? 1 : 0); +} + +async function run(args) { + return JSON.parse(await execa.stdout("./updates.js", args.split(/\s+/))); +} + +async function main() { + assert.deepStrictEqual(await run("-j -f test.json"), { + results: { + "gulp-sourcemaps": { + old: "2.0.0", + new: "2.6.4", + info: "https://github.com/floridoo/gulp-sourcemaps" + }, + "prismjs": { + old: "1.0.0", + new: "1.15.0", + info: "https://github.com/LeaVerou/prism" + } + } + }); + + assert.deepStrictEqual(await run("-j -g -f test.json"), { + results: { + "gulp-sourcemaps": { + old: "2.0.0", + new: "2.6.4", + info: "https://github.com/floridoo/gulp-sourcemaps" + }, + "prismjs": { + old: "1.0.0", + new: "9000.0.2", + info: "https://github.com/LeaVerou/prism" + } + } + }); +} + +main().then(exit).catch(exit); diff --git a/test.json b/test.json new file mode 100644 index 0000000..f520532 --- /dev/null +++ b/test.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "gulp-sourcemaps": "2.0.0", + "prismjs": "1.0.0" + } +} diff --git a/updates.js b/updates.js index 0a345ef..06eeb1f 100755 --- a/updates.js +++ b/updates.js @@ -324,7 +324,6 @@ function updatePkg() { return newPkgStr; } -// naive regex replace function updateRange(range, version) { return range.replace(/[0-9]+\.[0-9]+\.[0-9]+(-.+)?/g, version); } @@ -338,9 +337,25 @@ function isValidSemverRange(range) { return valid; } -function findNewVersion(data, opts) { - const versions = Object.keys(data.time).filter(version => semver.valid(version)); - let tempVersion = semver.coerce(opts.range) || "0.0.0"; +function isVersionPrerelease(version) { + return semver.parse(version).prerelease.length; +} + +function isRangePrerelease(range) { + // can not use semver.coerce here because it ignores prerelease tags + return /[0-9]+\.[0-9]+\.[0-9]+-.+/.test(range); +} + +function rangeToVersion(range) { + try { + return semver.coerce(range).version; + } catch (err) { + return "0.0.0"; + } +} + +function findVersion(data, versions, opts) { + let tempVersion = rangeToVersion(opts.range); let tempDate = 0; for (const version of versions) { @@ -353,7 +368,7 @@ function findNewVersion(data, opts) { } if (!opts.semvers.includes(diff)) continue; - if (diff === "prerelease" && !opts.usePre) continue; + if (isVersionPrerelease(parsed.version) && !opts.usePre) continue; if (opts.useGreatest) { if (semver.gte(parsed.version, tempVersion)) { @@ -368,17 +383,42 @@ function findNewVersion(data, opts) { } } - // Special case for when pre-releases are tagged as latest. This ignores the - // --prerelease option, but it's how npm and other tools work so we copy - // their behaviour. - const latestTag = data["dist-tags"].latest; - if (!opts.useGreatest && latestTag !== tempVersion && semver.diff(tempVersion, latestTag) === "prerelease") { - tempVersion = latestTag; - } - return tempVersion === "0.0.0" ? null : tempVersion; } +function findNewVersion(data, opts) { + const versions = Object.keys(data.time).filter(version => semver.valid(version)); + const version = findVersion(data, versions, opts); + + if (opts.useGreatest) { + return version; + } else { + const latestTag = data["dist-tags"].latest; + const oldVersion = semver.coerce(opts.range); + const oldIsPre = isRangePrerelease(opts.range); + const newIsPre = isVersionPrerelease(version); + const isGreater = semver.gt(version, oldVersion); + + // update to new prerelease + if (opts.usePre && newIsPre && isGreater) { + return version; + } + + // update from prerelease to release + if (oldIsPre && !newIsPre && isGreater) { + return version; + } + + // do not downgrade from prerelease to release + if (oldIsPre && !newIsPre && !isGreater) { + return oldVersion; + } + + // in all other cases, return latest dist-tag + return latestTag; + } +} + function parseMixedArg(arg) { if (arg === "") { return true;