Skip to content

Instantly share code, notes, and snippets.

@IUnknown68
Last active October 28, 2015 14:23
Show Gist options
  • Save IUnknown68/34f9370345bc16b22675 to your computer and use it in GitHub Desktop.
Save IUnknown68/34f9370345bc16b22675 to your computer and use it in GitHub Desktop.
/**************************************************************************//**
* @file
* @brief SemVer.js: Semantic version implementation.
* @author Arne Seib <[email protected]>
* @copyright 2015 Arne Seib (http://www.seiberspace.de).
*****************************************************************************/
SemVer = (function() {
//------------------------------------------------------------------------------
// private function: validate `from[name]` with validator `type`.
// If `from[name]` is undefined, leave `to` unchanged.
// If `from[name]` is invalid, throw.
// Otherwise set `to[name]`.
function _validate(from, to, name, type) {
var val = from[name];
if ('undefined' === typeof val) {
return;
}
if (!SemVer.validators[type].test(val)) {
throw new Error('SemVer: Expected ' + type + ' for ' + val);
}
to[name] = ('number' === type) ? parseInt(val,10) : val;
}
//------------------------------------------------------------------------------
// class SemVer
// Contructor can take:
// - a string: gets parsed
// - an object: copies attributes one by one and validates them
// - nothing: create empty SemVer
// If `val` is invalid, an exception is thrown.
function SemVer(val) {
SemVer.reset(this);
switch(typeof val) {
case 'undefined':
return;
break;
case 'string':
SemVer.parse(val, this);
break;
case 'object':
SemVer.safeCopy(val, this);
break;
default:
throw new TypeError('SemVer::SemVer(): Argument of invalid type: ' + val);
break;
}
}
//------------------------------------------------------------------------------
SemVer.prototype = {
// reset all values to defaults (0.0.0)
reset: function() {SemVer.reset(this);},
// return true if this version number is equal to other
isEqual: function(other) {return 0 === SemVer.compare(this, other);},
// return true if this version number is higher than other
isHigher: function(other) {return SemVer.compare(this, other) > 0;},
// return true if this version number is lower than other
isLower: function(other) {return SemVer.compare(this, other) < 0;},
// return formatted version number
toString: function() {return SemVer.print(this);}
};
//------------------------------------------------------------------------------
// validator regexps
// regex is based on https://github.com/sindresorhus/semver-regex
SemVer.validators = {
// major, minor and patch
number: /^(?:0|[1-9][0-9]*)$/i,
// pre and meta
string: /^[\da-z\-]+(?:\.[\da-z\-]+)*$/i,
version: /^((?:0|[1-9][0-9]*))\.((?:0|[1-9][0-9]*))\.((?:0|[1-9][0-9]*))(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+([\da-z\-]+(?:\.[\da-z\-]+)*))?$/i
};
//------------------------------------------------------------------------------
// static function reset: Clear to 0.0.0
SemVer.reset = function(item) {
item.major = item.minor = item.patch = 0;
item.pre = item.meta = '';
return item;
};
//------------------------------------------------------------------------------
// static function: check if `val` is a valid version string
SemVer.isVersion = function(val) {
return !!SemVer.validators.version.exec(val);
};
//------------------------------------------------------------------------------
// static function: check if `val` is a valid version string
SemVer.print = function(item) {
var s = '' + item.major + '.' + item.minor + '.' + item.patch;
if (item.pre) {
s += '-' + item.pre;
}
if (item.meta) {
s += '+' + item.meta;
}
return s;
};
//------------------------------------------------------------------------------
// static function: copy values from `from` to `to`. Throw on any invalid value.
// returns `to`.
SemVer.safeCopy = function(from, to) {
to = to || {};
to.major = _validate(from, to, 'major', 'number');
to.minor = _validate(from, to, 'minor', 'number');
to.patch = _validate(from, to, 'patch', 'number');
to.pre = _validate(from, to, 'pre', 'string');
to.meta = _validate(from, to, 'meta', 'string');
return to;
};
//------------------------------------------------------------------------------
// static function: parse a string `from` into `to` and return `to`.
SemVer.parse = function(from, to) {
to = to || {};
var m = SemVer.validators.version.exec(from);
if (!m) {
throw new TypeError('SemVer::SemVer(): Argument is not a valid version string: ' + from);
}
to.major = parseInt(m[1],10);
to.minor = parseInt(m[2],10);
to.patch = parseInt(m[3],10);
to.pre = m[4] || '';
to.meta = m[5] || '';
return to;
};
//------------------------------------------------------------------------------
// static function: compare two SemVer objects. Can also be used to sort arrays.
SemVer.compare = function(a, b) {
if (a.major !== b.major) {
return a.major - b.major;
}
if (a.minor !== b.minor) {
return a.minor - b.minor;
}
if (a.patch !== b.patch) {
return a.patch - b.patch;
}
if (a.pre !== b.pre) {
if (a.pre === '') {
return 1;
}
if (b.pre === '') {
return -1;
}
return a.pre.localeCompare(b.pre);
}
return 0;
};
return SemVer;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment