From 91d3729b3735f7645e1fab7e55e1c4ab9a567a98 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Sat, 6 Oct 2018 09:43:25 +0200
Subject: [PATCH] feat: hashicorp semver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Hashicorp’s semver is same as npm’s except for handling of “~> 1.2”. For Hashicorp it means ^1.2 whereas for Hashicorp is means ~1.2.
---
 lib/versioning/index.js                  |  2 +
 lib/versioning/semver-hashicorp/index.js | 45 +++++++++++++++++++++
 test/versioning/semver-hashicorp.spec.js | 50 ++++++++++++++++++++++++
 3 files changed, 97 insertions(+)
 create mode 100644 lib/versioning/semver-hashicorp/index.js
 create mode 100644 test/versioning/semver-hashicorp.spec.js

diff --git a/lib/versioning/index.js b/lib/versioning/index.js
index cab16eeefa..d23484d1c1 100644
--- a/lib/versioning/index.js
+++ b/lib/versioning/index.js
@@ -1,12 +1,14 @@
 const docker = require('./docker');
 const semver = require('./semver');
 const semverComposer = require('./semver-composer');
+const semverHashicorp = require('./semver-hashicorp');
 const pep440 = require('./pep440');
 
 const schemes = {
   docker,
   semver,
   semverComposer,
+  semverHashicorp,
   pep440,
 };
 
diff --git a/lib/versioning/semver-hashicorp/index.js b/lib/versioning/semver-hashicorp/index.js
new file mode 100644
index 0000000000..66012a6f95
--- /dev/null
+++ b/lib/versioning/semver-hashicorp/index.js
@@ -0,0 +1,45 @@
+const semver = require('../semver');
+
+function hashicorp2npm(input) {
+  // The only case incompatible with semver is a "short" ~>, e.g. ~> 1.2
+  return input.replace(/~>(\s*\d+\.\d+$)/, '^$1');
+}
+
+const matches = (version, range) =>
+  semver.matches(hashicorp2npm(version), hashicorp2npm(range));
+
+const maxSatisfyingVersion = (versions, range) =>
+  semver.maxSatisfyingVersion(
+    versions.map(hashicorp2npm),
+    hashicorp2npm(range)
+  );
+
+const minSatisfyingVersion = (versions, range) =>
+  semver.minSatisfyingVersion(
+    versions.map(hashicorp2npm),
+    hashicorp2npm(range)
+  );
+
+function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+  // handle specia. ~> 1.2 case
+  if (currentValue.match(/(~>\s*)\d+\.\d+$/)) {
+    return currentValue.replace(
+      /(~>\s*)\d+\.\d+$/,
+      `$1${semver.getMajor(toVersion)}.0`
+    );
+  }
+  return semver.getNewValue(
+    currentValue,
+    rangeStrategy,
+    fromVersion,
+    toVersion
+  );
+}
+
+module.exports = {
+  ...semver,
+  matches,
+  maxSatisfyingVersion,
+  minSatisfyingVersion,
+  getNewValue,
+};
diff --git a/test/versioning/semver-hashicorp.spec.js b/test/versioning/semver-hashicorp.spec.js
new file mode 100644
index 0000000000..9ded6fc12f
--- /dev/null
+++ b/test/versioning/semver-hashicorp.spec.js
@@ -0,0 +1,50 @@
+const semver = require('../../lib/versioning')('semverHashicorp');
+
+describe('semver.matches()', () => {
+  it('handles tilde greater than', () => {
+    expect(semver.matches('4.2.0', '~> 4.0')).toBe(true);
+    expect(semver.matches('4.2.0', '~> 4.0.0')).toBe(false);
+  });
+});
+describe('semver.maxSatisfyingVersion()', () => {
+  it('handles tilde greater than', () => {
+    expect(
+      semver.maxSatisfyingVersion(
+        ['0.4.0', '0.5.0', '4.0.0', '4.2.0', '5.0.0'],
+        '~> 4.0'
+      )
+    ).toBe('4.2.0');
+    expect(
+      semver.maxSatisfyingVersion(
+        ['0.4.0', '0.5.0', '4.0.0', '4.2.0', '5.0.0'],
+        '~> 4.0.0'
+      )
+    ).toBe('4.0.0');
+  });
+});
+describe('semver.minSatisfyingVersion()', () => {
+  it('handles tilde greater than', () => {
+    expect(
+      semver.minSatisfyingVersion(
+        ['0.4.0', '0.5.0', '4.2.0', '5.0.0'],
+        '~> 4.0'
+      )
+    ).toBe('4.2.0');
+    expect(
+      semver.minSatisfyingVersion(
+        ['0.4.0', '0.5.0', '4.2.0', '5.0.0'],
+        '~> 4.0.0'
+      )
+    ).toBe(null);
+  });
+});
+describe('semver.getNewValue()', () => {
+  it('handles tilde greater than', () => {
+    expect(semver.getNewValue('~> 1.2', 'replace', '1.2.3', '2.0.7')).toEqual(
+      '~> 2.0'
+    );
+    expect(semver.getNewValue('~> 1.2.0', 'replace', '1.2.3', '2.0.7')).toEqual(
+      '~> 2.0.0'
+    );
+  });
+});
-- 
GitLab