Compare commits

...

19 Commits

Author SHA1 Message Date
2344adc3b2 v1.1.4: tighten matching that was too relaxed in v1.1.3 2018-10-08 19:23:40 -06:00
daab053561 correctly parse '~> 2.0.0' 2018-10-08 19:11:40 -06:00
55d71d3929 add LICENSE 2018-10-08 19:04:03 -06:00
AJ ONeal
3e4e0a65f4 v1.1.2 2018-03-28 00:10:59 -06:00
AJ ONeal
540c7430df v1.1.2 2018-03-28 00:10:32 -06:00
AJ ONeal
361e1dd788 Merge pull request #2 from metaraine/master
Add mocha tests. Add support for caret (^).
2015-10-21 10:05:38 -07:00
metaraine
86ea225075 Fix reSemverRange to parse pre-release versions that contain hyphens. 2015-08-03 11:12:58 -06:00
metaraine
ff978dc8ad Remove unnecessary deep-equal dependency. 2015-06-06 15:39:50 -06:00
metaraine
74cc0b238e Add support for caret (^) 2015-06-06 15:27:43 -06:00
metaraine
d9e4e7b776 prune results of .parse, not just .parseRange 2015-06-06 15:22:32 -06:00
metaraine
787f71566c Add mocha unit tests. 2015-06-06 15:22:04 -06:00
484199f855 Update README.md 2014-02-24 16:35:47 -06:00
f587dbbc80 Update README.md 2014-02-24 16:35:21 -06:00
a0878abeb4 added Install / Usage and API TOC 2014-02-24 16:34:54 -06:00
3f553abd40 Merge branch 'master' of github.com:coolaj86/semver-utils 2013-05-22 15:57:47 -05:00
c80b378a8b created SemVer class such that ver.toString() calls stringify(ver) 2013-05-22 15:57:39 -05:00
c430bd2682 typo fix rangeString -> rangeArray 2013-05-17 16:14:15 -03:00
fa2a82ef75 updated README with stringifyRange 2013-05-17 15:04:10 -04:00
d1a4afb909 allow 'v' prefix, implemented missing 'stringifyRange' 2013-05-17 15:01:32 -04:00
8 changed files with 439 additions and 161 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

41
LICENSE Normal file
View File

@ -0,0 +1,41 @@
Copyright 2013 AJ ONeal
This is open source software; you can redistribute it and/or modify it under the
terms of either:
a) the "MIT License"
b) the "Apache-2.0 License"
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Apache-2.0 License Summary
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,15 +1,37 @@
## semver-utils
## semver-utils.js
| Sponsored by [ppl](https://ppl.family)
Some utils that aren't provided by the mainstream `semver` module.
### Usage
```bash
npm install --save semver-utils
```
```javascript
'use strict';
var semverUtils = require('semver-utils');
var version = require('./package.json').version;
var semver = semverUtils.parse(version);
console.log(semver);
```
## API
### parse(semverString)
* `semverUtils.parse(semverString)`
* `semverUtils.stringify(semverObject)`
* `semverUtils.parseRange(rangeString)`
* `semverUtils.stringifyRange(rangeArray)`
### semverUtils.parse(semverString)
Turns a string such as `1.0.6-1+build-623` into the object
{
semver: '1.0.6-1+build-623'
{ semver: '1.0.6-1+build-623'
, version: '1.0.6'
, major: '1'
, minor: '0'
@ -20,25 +42,24 @@ Turns a string such as `1.0.6-1+build-623` into the object
returns `null` on **error**
### stringify(semverObject)
### semverUtils.stringify(semverObject)
Creates a string such as `1.0.6-1+build-623` from the object
{
major: '1'
{ major: '1'
, minor: '0'
, patch: '6'
, release: '1'
, build: 'build-623'
}
### parseRange(rangeString)
### semverUtils.parseRange(rangeString)
A solution to <https://github.com/isaacs/node-semver/issues/10>
Parses a range string into an array of semver objects
`>= 1.1.7 < 2.0.0 || 1.1.3'` becomes
`>= 1.1.7 < 2.0.0 || 1.1.3` becomes
[
{
@ -68,6 +89,35 @@ Parses a range string into an array of semver objects
]
### semverUtils.stringifyRange(rangeArray)
Creates a range string such as `>= 1.1.7 < 2.0.0 || 1.1.3`
from an array of semver objects (and operators) such as
[
{ "semver": ">= v1.1.7"
, "operator": ">="
, "major": 1
, "minor": 1
, "patch": 7
}
, { "semver": "< v2.0.0"
, "operator": "<"
, "major": 2
, "minor": 0
, "patch": 0
}
, { "operator": "||"
}
, { "semver": "v1.1.3"
, "operator": "="
, "major": 1
, "minor": 1
, "patch": 3
}
]
## Obsolete Work
* https://github.com/mojombo/semver/issues/32

View File

@ -1,14 +1,15 @@
{
"name": "semver-utils",
"version": "1.0.2",
"version": "1.1.3",
"description": "Tools for manipulating semver strings and objects",
"homepage": "https://git.coolaj86.com/coolaj86/semver-utils.js",
"main": "semver-utils.js",
"scripts": {
"test": "node semver-utils-test.js"
"test": "mocha"
},
"repository": {
"type": "git",
"url": "git://github.com/coolaj86/semver-utils.git"
"url": "git://git.coolaj86.com/coolaj86/semver-utils.js.git"
},
"keywords": [
"semver",
@ -18,5 +19,9 @@
],
"author": "AJ ONeal",
"license": "APACHEv2",
"readmeFilename": "README.md"
"readmeFilename": "README.md",
"devDependencies": {
"chai": "^3.0.0",
"mocha": "^2.2.5"
}
}

View File

@ -1,109 +0,0 @@
(function () {
var semverutils = require('semver-utils')
;
function testParseRange() {
var str = '~1.0.0 || >= 1.1.7 < 2.0.0+build.1848 || v1.1.3 || 2.0.1-alpha.1227 || 1.0.0 - 1.0.x'
;
console.log(semverutils.parseRange(str));
console.log(semverutils.parseRange('v1.0.0'));
console.log(semverutils.parseRange('< v2.0.0'));
console.log(semverutils.parseRange('~v2.0.0'));
}
function testParse() {
var good
, bad
;
good = [
"1.0.8"
, "1.23.7"
, "2.0.0-alpha.123.abc"
, "2.0.0-alpha.123.abc+build.acebfde1284"
, "1.0.0-alpha"
, "1.0.0-alpha.1"
, "1.0.0-0.3.7"
, "1.0.0-x.7.z.92"
, "1.0.0-alpha"
, "1.0.0-alpha.1"
, "1.0.0-beta.2"
, "1.0.0-beta.11"
, "1.0.0-rc.1"
, "1.0.0-rc.1+build.1"
, "1.0.0-rc.1+build.1-b"
, "1.0.0"
, "1.0.0+0.3.7"
, "1.3.7+build"
, "1.3.7+build.2.b8f12d7"
, "1.3.7+build.11.e0f985a"
, "1.3.7+build.11.e0f9-85a"
, "1.0.0+build-acbe"
, "2.0.0+build.acebfde1284-alpha.123.abc"
];
bad = [
"v1.0.0"
, "a.b.c"
, "1"
, "1.0.0b"
, "1.0"
, "1.0.0+b[\\]^_`uild" // [,\,],^,_,` are between A-z, but not A-Za-z
, "1.0.0+build-acbe." // trailing period
, "1.0.0+build.!@#$%"
];
good.every(function (version) {
var result = semverutils.parse(version)
;
if (!result) {
throw new Error("didn't parse something that should be parseable: " + version);
}
return true;
});
bad.every(function (version) {
var result = semverutils.parse(version)
;
if (result) {
throw new Error("parsed something that should not be parseable: " + version);
}
return true;
});
console.log(semverutils.parse("a.b.c")); // null
console.log(semverutils.parse("1.0.3"));
/*
{
semver: 1.0.3
, major: 1
, minor: 0
, patch: 3
}
*/
console.log(semverutils.parse("1.0.3-rc.1+build.aef312"));
/*
{
semver: v1.0.3-rc.1+build.aef312
, major: 1
, minor: 0
, patch: 3
, build: build.aef312
, release: rc.1
}
*/
console.log(semverutils.parse("1.0.0-rc.1-1"));
console.log(semverutils.parse("1.0.0-rc.1+build.1-b"));
console.log(semverutils.parse("1.0.0-rc.1-1+build.1-b"));
console.log(semverutils.parse("2.0.0+build.acebfde1284-alpha.123.abc"));
}
testParse();
testParseRange();
}());

View File

@ -1,36 +1,31 @@
(function () {
"use strict";
var reSemver = /^((\d+)\.(\d+)\.(\d+))(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?(?:\+([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?$/
, reSemverRange = /\s*((\|\||\-)|(([<>~]?=?)\s*(v)?([0-9]+)(\.(x|[0-9]+))?(\.(x|[0-9]+))?(([\-+])([a-zA-Z0-9\.]+))?))\s*/g
// TODO break these down into escaped strings with meaningful comments and create using new RegExp()
// |optional 'v'
// | | 3 segment version
// | | |optional release prefixed by '-'
// | | | |optional build prefixed by '+'
var reSemver = /^v?((\d+)\.(\d+)\.(\d+))(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?(?:\+([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?$/
//, reSemverRange = /\s*((\|\||\-)|(([<>~]?=?)\s*(v)?([0-9]+)(\.(x|[0-9]+))?(\.(x|[0-9]+))?(([\-+])([a-zA-Z0-9\.]+))?))\s*/g
, reSemverRange = /\s*((\|\||\-)|(((?:(?:~?[<>]?)|\^?)=?)\s*(v)?([0-9]+)(\.(x|\*|[0-9]+))?(\.(x|\*|[0-9]+))?(([\-+])([a-zA-Z0-9\.-]+))?))\s*/g
;
function parseSemver(version) {
// semver, major, minor, patch
// https://github.com/mojombo/semver/issues/32
// https://github.com/isaacs/node-semver/issues/10
// optional v
var m = reSemver.exec(version) || []
, ver = {
semver: m[0]
, version: m[1]
, major: m[2]
, minor: m[3]
, patch: m[4]
, release: m[5]
, build: m[6]
}
;
if (0 === m.length) {
ver = null;
// Returns a new object with all of the undefined properties removed from the given object
function pruned(obj) {
var o = {};
for(var key in obj) {
if ('undefined' !== typeof obj[key]) {
o[key] = obj[key];
}
}
return ver;
return o;
}
function stringifySemver(obj) {
var str = '';
var str = ''
;
str += obj.major || '0';
str += '.';
str += obj.minor || '0';
@ -45,23 +40,89 @@
return str;
}
function stringifySemverRange(arr) {
var str = ''
;
function stringify(ver) {
if (ver.operator) {
str += ver.operator + ' ';
}
if (ver.major) {
str += ver.toString() + ' ';
}
}
arr.forEach(stringify);
return str.trim();
}
function SemVer(obj) {
if (!obj) {
return;
}
var me = this
;
Object.keys(obj).forEach(function (key) {
me[key] = obj[key];
});
}
SemVer.prototype.toString = function () {
return stringifySemver(this);
};
/*
function SemVerRange(obj) {
if (!obj) {
return;
}
var me = this
;
Object.keys(obj).forEach(function (key) {
me[key] = obj[key];
});
}
SemVerRange.prototype = [];
SemVerRange.prototype.toString = stringifySemverRange;
*/
function parseSemver(version) {
// semver, major, minor, patch
// https://github.com/mojombo/semver/issues/32
// https://github.com/isaacs/node-semver/issues/10
// optional v
var m = reSemver.exec(version) || []
, ver = new SemVer(pruned({
semver: m[0]
, version: m[1]
, major: m[2]
, minor: m[3]
, patch: m[4]
, release: m[5]
, build: m[6]
}))
;
if (0 === m.length) {
ver = null;
}
return ver;
}
function parseSemverRange(str) {
var m
, arr = []
, obj
;
function prune(key) {
if ('undefined' === typeof obj[key]) {
delete obj[key];
}
}
while (true) {
m = reSemverRange.exec(str);
if (!m) {
break;
}
while (m = reSemverRange.exec(str)) {
obj = {
semver: m[3]
, operator: m[4] || m[2]
@ -75,15 +136,16 @@
if ('-' === m[12]) {
obj.release = m[13];
}
Object.keys(obj).forEach(prune);
arr.push(obj);
arr.push(new SemVer(pruned(obj)));
//console.log(m);
}
//return new SemVerRange(arr);
return arr;
}
module.exports.parse = parseSemver;
module.exports.stringify = stringifySemver;
module.exports.parseRange = parseSemverRange;
module.exports.stringifyRange = stringifySemverRange;
}());

26
test/deepOwnEqual.js Normal file
View File

@ -0,0 +1,26 @@
var assert = require('chai').assert;
// we need to define our own deepEqual function that ignores properties that are not hasOwnProperty. Not supported in chai.assert.deepEqual as of v3.0.0.
function deepOwnEqual(a, b) {
// if arrays of objects, recurse down to the objects
if(Array.isArray(a) && Array.isArray(b)) {
assert.deepEqual(a.length, b.length, 'Arrays have different lengths')
for(var i=0; i<a.length; i++) {
deepOwnEqual(a[i], b[i])
}
}
// compare all the object properties
else {
var aKeys = Object.keys(a);
var bKeys = Object.keys(b);
assert.deepEqual(aKeys, bKeys, 'Objects have different keys');
aKeys.forEach(function(key) {
assert.deepEqual(a[key], b[key], 'Expected values of "' + key + '" property to be equal in each object')
});
}
}
module.exports = deepOwnEqual

202
test/spec.js Normal file
View File

@ -0,0 +1,202 @@
var assert = require('chai').assert;
var semverutils = require('../semver-utils');
var deepOwnEqual = require('./deepOwnEqual');
describe('parse', function() {
it('should parse a simple 3-part version', function() {
deepOwnEqual(semverutils.parse('1.0.0'), {
semver: '1.0.0',
version: '1.0.0',
major: '1',
minor: '0',
patch: '0'
});
});
it('should parse pre-release versions', function() {
deepOwnEqual(semverutils.parse('1.0.0-alpha1'), {
semver: '1.0.0-alpha1',
version: '1.0.0',
major: '1',
minor: '0',
patch: '0',
release: 'alpha1'
});
});
it('should parse build numbers', function() {
deepOwnEqual(semverutils.parse('1.0.0+build-123'), {
semver: '1.0.0+build-123',
version: '1.0.0',
major: '1',
minor: '0',
patch: '0',
build: 'build-123'
});
});
it('should not parse invalid versions', function() {
assert.equal(semverutils.parse('a.b.c'), null);
assert.equal(semverutils.parse('1'), null);
assert.equal(semverutils.parse('1.0'), null);
assert.equal(semverutils.parse('1.0.0b'), null);
assert.equal(semverutils.parse('1.0.0+build-abc.'), null, 'trailing period');
});
});
describe('parseRange', function() {
it('should parse an exact version as a range', function() {
deepOwnEqual(semverutils.parseRange('1.0.0'), [{
semver: '1.0.0',
major: '1',
minor: '0',
patch: '0'
}]);
});
it('should ignore the v- prefix', function() {
deepOwnEqual(semverutils.parseRange('v1.0.0'), [{
semver: 'v1.0.0',
major: '1',
minor: '0',
patch: '0'
}]);
});
it('should parse a comparison operator', function() {
deepOwnEqual(semverutils.parseRange('< v2.0.0'), [{
semver: '< v2.0.0',
operator: '<',
major: '2',
minor: '0',
patch: '0'
}]);
});
it('should parse tilde', function() {
deepOwnEqual(semverutils.parseRange('~1.0.0'), [{
semver: '~1.0.0',
operator: '~',
major: '1',
minor: '0',
patch: '0'
}]);
});
it('should parse caret', function() {
deepOwnEqual(semverutils.parseRange('^1.0.0'), [{
semver: '^1.0.0',
operator: '^',
major: '1',
minor: '0',
patch: '0'
}]);
});
it('should parse tilde and v- prefix', function() {
deepOwnEqual(semverutils.parseRange('~v1.0.0'), [{
semver: '~v1.0.0',
operator: '~',
major: '1',
minor: '0',
patch: '0'
}]);
});
it('should parse ||', function() {
deepOwnEqual(semverutils.parseRange('~1.0.0 || ~2.0.0'), [{
semver: '~1.0.0',
operator: '~',
major: '1',
minor: '0',
patch: '0'
}, {
operator: '||'
}, {
semver: '~2.0.0',
operator: '~',
major: '2',
minor: '0',
patch: '0'
}]);
});
it('should parse build numbers', function() {
deepOwnEqual(semverutils.parseRange('2.0.0+build.1848'), [{
semver: '2.0.0+build.1848',
major: '2',
minor: '0',
patch: '0',
build: 'build.1848'
}]);
});
it('should parse pre-release versions', function() {
deepOwnEqual(semverutils.parseRange('1.0.0-rc1'), [{
semver: '1.0.0-rc1',
major: '1',
minor: '0',
patch: '0',
release: 'rc1'
}]);
});
it('should parse pre-release versions with hyphens', function() {
deepOwnEqual(semverutils.parseRange('1.0.0-rc-2'), [{
semver: '1.0.0-rc-2',
major: '1',
minor: '0',
patch: '0',
release: 'rc-2'
}]);
});
it('should parse hyphen ranges', function() {
deepOwnEqual(semverutils.parseRange('1.0.0 - 1.0.x'), [{
semver: '1.0.0',
major: '1',
minor: '0',
patch: '0'
}, {
operator: '-'
}, {
semver: '1.0.x',
major: '1',
minor: '0',
patch: 'x'
}]);
});
it('should parse constrained * ranges', function() {
deepOwnEqual(semverutils.parseRange('1.*'), [{
semver: '1.*',
major: '1',
minor: '*',
}]);
});
it('should parse constrained .x', function() {
deepOwnEqual(semverutils.parseRange('1.x'), [{
semver: '1.x',
major: '1',
minor: 'x',
}]);
});
it('should parse ~> ranges', function() {
deepOwnEqual(semverutils.parseRange('~> 2.0.0'), [{
semver: '~> 2.0.0',
operator: '~>',
major: '2',
minor: '0',
patch: '0'
}]);
});
});