Skip to content

Instantly share code, notes, and snippets.

@harrishancock
Last active August 29, 2015 14:24
Show Gist options
  • Save harrishancock/d4c59027b0c3aeb4bc26 to your computer and use it in GitHub Desktop.
Save harrishancock/d4c59027b0c3aeb4bc26 to your computer and use it in GitHub Desktop.
Some version parsing, generating, and comparison functions
// If a string begins with 'v' and ends with a dotted sequence of numbers,
// return an array of those numbers. Otherwise, return null.
// Examples:
// 'v1' -> [ 1 ]
// 'v1.2' -> [ 1, 2 ]
// 'v1.2.3' -> [ 1, 2, 3 ]
// '1.2.3' -> null
function parseVersion (v) {
function parseDecInt (a) {
return parseInt(a, 10);
}
var result = /^v(\d+(?:\.\d+)*)$/.exec(v);
return result
? result[1].split('.').map(parseDecInt)
: null;
}
// The inverse operation of parseVersion: given an array of numbers, return a
// string beginning with 'v' and ending with the sequence of numbers in dotted
// format.
function generateVersion (v) {
return 'v' + v.reduce(function (p, v) {
// Force numbers to be integers with |0 so we don't end up with floating
// points in the version string. Perhaps paranoid?
return (p|0).toString() + '.' + (v|0);
});
}
// Compare two arrays of numbers lexicographically. Return less than zero if a
// is ordered before b, greater than zero if b is ordered before a, and zero if
// the two arguments compare equal. If one array is a prefix of the other, the
// shorter of the two arrays is ordered before the longer. Suitable for use
// with Array.sort().
function lexicographicCompare (a, b) {
for (var i = 0; i < Math.max(a.length, b.length); ++i) {
if (a[i] != b[i]) {
return undefined === a[i] || a[i] < b[i]
? -1 : 1;
}
}
return 0;
}
// Choose the maximum version among an array of version arrays and return it.
function maxVersion (versions) {
function chooseGreaterVersion (p, v) {
return lexicographicCompare(p, v) > 0 ? p : v;
}
var versionArrays = versions.map(parseVersion).filter(Boolean);
return versionArrays.length
? generateVersion(versionArrays.reduce(chooseGreaterVersion))
: null;
}
// Split a filename into its stem and extension, if present. The extension's
// dot is retained to distinguish no extension from an empty extension.
// Examples:
// 'a.b.c' -> { stem: 'a.b', extension: '.c' }
// 'a.' -> { stem: 'a', extension: '.' }
// 'a' -> { stem: 'a', extension: null }
function splitFilename (a) {
var i = a.lastIndexOf('.');
return i > 0
? { stem: a.slice(0, i), extension: a.slice(i) }
: { stem: a.slice(0), extension: null };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment