From aa73819e166af11fd4ac59e361fe42bbd1bd1296 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Sat, 14 Jul 2018 10:12:59 +0200
Subject: [PATCH] fix(semver): handle unstable range replacements better

---
 lib/versioning/semver/range.js                | 26 ++++++++++++++++---
 test/versioning/semver.spec.js                | 20 ++++++++++++++
 .../lookup/__snapshots__/index.spec.js.snap   |  2 +-
 3 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/lib/versioning/semver/range.js b/lib/versioning/semver/range.js
index 018615f077..ff86c0fcab 100644
--- a/lib/versioning/semver/range.js
+++ b/lib/versioning/semver/range.js
@@ -1,4 +1,11 @@
-const { inc: increment, major, minor, valid: isVersion } = require('semver');
+const {
+  inc: increment,
+  major,
+  minor,
+  patch,
+  prerelease,
+  valid: isVersion,
+} = require('semver');
 const { parseRange } = require('semver-utils');
 
 module.exports = {
@@ -40,11 +47,16 @@ function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
   }
   const toVersionMajor = major(toVersion);
   const toVersionMinor = minor(toVersion);
+  const toVersionPatch = patch(toVersion);
+  const suffix = prerelease(toVersion) ? '-' + prerelease(toVersion)[0] : '';
   // Simple range
   if (rangeStrategy === 'bump') {
     if (parsedRange.length === 1) {
       if (element.operator === '^') {
         const split = currentValue.split('.');
+        if (suffix.length) {
+          return `^${toVersionMajor}.${toVersionMinor}.${toVersionPatch}${suffix}`;
+        }
         if (split.length === 1) {
           // ^4
           return '^' + toVersionMajor;
@@ -57,6 +69,9 @@ function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
       }
       if (element.operator === '~') {
         const split = currentValue.split('.');
+        if (suffix.length) {
+          return `~${toVersionMajor}.${toVersionMinor}.${toVersionPatch}${suffix}`;
+        }
         if (split.length === 1) {
           // ~4
           return '~' + toVersionMajor;
@@ -82,8 +97,8 @@ function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
     return null;
   }
   if (element.operator === '^') {
-    if (!fromVersion) {
-      return `^${toVersion}`;
+    if (suffix.length || !fromVersion) {
+      return `^${toVersionMajor}.${toVersionMinor}.${toVersionPatch}${suffix}`;
     }
     if (toVersionMajor === major(fromVersion)) {
       if (toVersionMajor === 0) {
@@ -100,11 +115,14 @@ function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
     return `=${toVersion}`;
   }
   if (element.operator === '~') {
+    if (suffix.length) {
+      return `~${toVersionMajor}.${toVersionMinor}.${toVersionPatch}${suffix}`;
+    }
     return `~${toVersionMajor}.${toVersionMinor}.0`;
   }
   if (element.operator === '<=') {
     let res;
-    if (element.patch) {
+    if (element.patch || suffix.length) {
       res = `<=${toVersion}`;
     } else if (element.minor) {
       res = `<=${toVersionMajor}.${toVersionMinor}`;
diff --git a/test/versioning/semver.spec.js b/test/versioning/semver.spec.js
index 4a88b6bf9c..dc256e65aa 100644
--- a/test/versioning/semver.spec.js
+++ b/test/versioning/semver.spec.js
@@ -50,6 +50,16 @@ describe('semver.getNewValue()', () => {
       '^1.0'
     );
   });
+  it('bumps caret to prerelease', () => {
+    expect(
+      semver.getNewValue('^1', 'bump', '1.0.0', '1.0.7-prerelease.1')
+    ).toEqual('^1.0.7-prerelease');
+  });
+  it('replaces with newer', () => {
+    expect(semver.getNewValue('^1.0.0', 'replace', '1.0.0', '1.0.7')).toEqual(
+      '^1.0.7'
+    );
+  });
   it('bumps short caret to new', () => {
     expect(semver.getNewValue('^1.0', 'bump', '1.0.0', '1.1.7')).toEqual(
       '^1.1'
@@ -60,6 +70,11 @@ describe('semver.getNewValue()', () => {
       '~1.1'
     );
   });
+  it('bumps tilde to prerelease', () => {
+    expect(
+      semver.getNewValue('~1.0', 'bump', '1.0.0', '1.0.7-prerelease.1')
+    ).toEqual('~1.0.7-prerelease');
+  });
   it('updates naked caret', () => {
     expect(semver.getNewValue('^1', 'bump', '1.0.0', '2.1.7')).toEqual('^2');
   });
@@ -81,4 +96,9 @@ describe('semver.getNewValue()', () => {
       '2.*'
     );
   });
+  it('handles updating from stable to unstable', () => {
+    expect(
+      semver.getNewValue('~0.6.1', 'replace', '0.6.8', '0.7.0-rc.2')
+    ).toEqual('~0.7.0-rc');
+  });
 });
diff --git a/test/workers/repository/process/lookup/__snapshots__/index.spec.js.snap b/test/workers/repository/process/lookup/__snapshots__/index.spec.js.snap
index f5b8bcf6fc..a1b40de861 100644
--- a/test/workers/repository/process/lookup/__snapshots__/index.spec.js.snap
+++ b/test/workers/repository/process/lookup/__snapshots__/index.spec.js.snap
@@ -103,7 +103,7 @@ Array [
     "isSingleVersion": false,
     "newMajor": 2,
     "newMinor": 9,
-    "newValue": "^2.9.1-insiders.20180516",
+    "newValue": "^2.9.1-insiders",
     "releaseTimestamp": "2018-05-16T23:16:36.911Z",
     "toVersion": "2.9.1-insiders.20180516",
     "updateType": "minor",
-- 
GitLab