semver-store
Advanced tools
Comparing version 0.1.0 to 0.2.0
59
bench.js
@@ -6,28 +6,51 @@ 'use strict' | ||
const semver = require('semver') | ||
const store = require('./index')() | ||
store.set('1.2.3', null) | ||
const SemVerStore = require('./index') | ||
const store1 = SemVerStore() | ||
const store2 = SemVerStore() | ||
store2 | ||
.set('1.1.1', 1) | ||
.set('1.1.2', 1) | ||
.set('1.1.3', 1) | ||
.set('1.2.1', 1) | ||
.set('1.2.2', 1) | ||
.set('1.2.3', 1) | ||
.set('2.1.1', 1) | ||
.set('2.1.2', 1) | ||
.set('2.1.3', 1) | ||
.set('3.2.1', 1) | ||
.set('3.2.2', 1) | ||
.set('3.2.3', 1) | ||
suite | ||
.add('semver-store - full', function () { | ||
store.get('1.2.3') | ||
.add('set', function () { | ||
store1.set('1.2.3', 1) | ||
}) | ||
.add('semver - full', function () { | ||
semver.satisfies('1.2.3', '1.2.3') | ||
.add('get', function () { | ||
store1.get('1.2.3') | ||
}) | ||
.add('semver-store - wildcard', function () { | ||
store.get('1.x') | ||
.add('get (minor wildcard)', function () { | ||
store1.get('1.x') | ||
}) | ||
.add('semver - wildcard', function () { | ||
semver.satisfies('1.2.3', '1.x') | ||
.add('get (patch wildcard)', function () { | ||
store1.get('1.2.x') | ||
}) | ||
.add('semver-store - no patch', function () { | ||
store.get('1.2') | ||
.add('del + set', function () { | ||
store1.del('1.2.3') | ||
store1.set('1.2.3', 1) | ||
}) | ||
.add('semver - no patch', function () { | ||
semver.satisfies('1.2.3', '1.2') | ||
.add('del (minor wildcard) + set', function () { | ||
store1.del('1.x') | ||
store1.set('1.2.3', 1) | ||
}) | ||
.add('del (patch wildcard) + set', function () { | ||
store1.del('1.2.x') | ||
store1.set('1.2.3', 1) | ||
}) | ||
.add('set with other keys already present', function () { | ||
store2.set('1.2.4', 1) | ||
}) | ||
.add('get with other keys already present', function () { | ||
store2.get('1.2.4') | ||
}) | ||
.on('cycle', function (event) { | ||
@@ -34,0 +57,0 @@ console.log(String(event.target)) |
118
index.js
@@ -10,24 +10,25 @@ 'use strict' | ||
SemVerStore.prototype.set = function (semverString, store) { | ||
SemVerStore.prototype.set = function (version, store) { | ||
var currentNode = this.tree | ||
semverString = semverString.split('.') | ||
while (semverString.length) { | ||
const node = new Node(semverString.shift()) | ||
currentNode = currentNode.addChild(node) | ||
continue | ||
version = version.split('.') | ||
while (version.length) { | ||
currentNode = currentNode.addChild( | ||
new Node(version.shift()) | ||
) | ||
} | ||
currentNode.setStore(store) | ||
return this | ||
} | ||
SemVerStore.prototype.get = function (semverString) { | ||
SemVerStore.prototype.get = function (version) { | ||
var node = this.tree | ||
var firstDot = semverString.indexOf('.') | ||
var secondDot = semverString.indexOf('.', firstDot + 1) | ||
var major = semverString.slice(0, firstDot) | ||
var firstDot = version.indexOf('.') | ||
var secondDot = version.indexOf('.', firstDot + 1) | ||
var major = version.slice(0, firstDot) | ||
var minor = secondDot === -1 | ||
? semverString.slice(firstDot + 1) | ||
: semverString.slice(firstDot + 1, secondDot + 1) | ||
? version.slice(firstDot + 1) | ||
: version.slice(firstDot + 1, secondDot) | ||
var patch = secondDot === -1 | ||
? 'x' | ||
: semverString.slice(secondDot + 1) | ||
: version.slice(secondDot + 1) | ||
@@ -43,2 +44,64 @@ node = node.getChild(major) | ||
SemVerStore.prototype.del = function (version) { | ||
var firstDot = version.indexOf('.') | ||
var secondDot = version.indexOf('.', firstDot + 1) | ||
var major = version.slice(0, firstDot) | ||
var minor = secondDot === -1 | ||
? version.slice(firstDot + 1) | ||
: version.slice(firstDot + 1, secondDot) | ||
var patch = secondDot === -1 | ||
? 'x' | ||
: version.slice(secondDot + 1) | ||
// check existence of major node | ||
var majorNode = this.tree.children[major] | ||
if (majorNode == null) return this | ||
// if minor is the wildcard, then remove the full major node | ||
if (minor === 'x') { | ||
this.tree.removeChild(major) | ||
return this | ||
} | ||
// check existence of minor node | ||
var minorNode = majorNode.children[minor] | ||
if (minorNode == null) return this | ||
// if patch is the wildcard, then remove the full minor node | ||
// and also the major if there are no more children | ||
if (patch === 'x') { | ||
this.tree.children[major].removeChild(minor) | ||
if (this.tree.children[major].length === 0) { | ||
this.tree.removeChild(major) | ||
} | ||
return this | ||
} | ||
// check existence of patch node | ||
var patchNode = minorNode.children[patch] | ||
if (patchNode == null) return this | ||
// Specific delete | ||
this.tree | ||
.children[major] | ||
.children[minor] | ||
.removeChild(patch) | ||
// check if the minor node has no more children, if so removes it | ||
// same for the major node | ||
if (this.tree.children[major].children[minor].length === 0) { | ||
this.tree.children[major].removeChild(minor) | ||
if (this.tree.children[major].length === 0) { | ||
this.tree.removeChild(major) | ||
} | ||
} | ||
return this | ||
} | ||
SemVerStore.prototype.empty = function () { | ||
this.tree = new Node() | ||
return this | ||
} | ||
function Node (prefix, children, store) { | ||
@@ -54,6 +117,6 @@ this.prefix = Number(prefix) || 0 | ||
if (prefix === 'x') { | ||
const max = Math.max.apply(Math, this.childrenPrefixes) | ||
var max = Math.max.apply(Math, this.childrenPrefixes) | ||
return this.children[max] | ||
} | ||
return this.children[Number(prefix)] || null | ||
return this.children[prefix] || null | ||
} | ||
@@ -63,3 +126,3 @@ | ||
this.children = this.children || {} | ||
const child = this.getChild(node.prefix) | ||
var child = this.getChild(node.prefix) | ||
if (child === null) { | ||
@@ -72,6 +135,29 @@ this.children[node.prefix] = node | ||
Node.prototype.removeChild = function (prefix) { | ||
if (prefix === 'x') { | ||
this.children = null | ||
this.childrenPrefixes = [] | ||
return this | ||
} | ||
if (this.children[prefix] !== undefined) { | ||
prefix = Number(prefix) | ||
delete this.children[prefix] | ||
this.childrenPrefixes.splice( | ||
this.childrenPrefixes.indexOf(prefix), 1 | ||
) | ||
} | ||
return this | ||
} | ||
Node.prototype.setStore = function (store) { | ||
this.store = store | ||
return this | ||
} | ||
Object.defineProperty(Node.prototype, 'length', { | ||
get: function () { | ||
return this.childrenPrefixes.length | ||
} | ||
}) | ||
module.exports = SemVerStore |
{ | ||
"name": "semver-store", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "An extremely fast semver based store", | ||
@@ -26,3 +26,2 @@ "main": "index.js", | ||
"benchmark": "^2.1.4", | ||
"semver": "^5.5.0", | ||
"standard": "^11.0.1", | ||
@@ -29,0 +28,0 @@ "tap": "^12.0.1" |
@@ -18,7 +18,25 @@ # semver-store | ||
console.log(store.get('1.2.0')) // { value: 42 } | ||
console.log( | ||
store.get('1.2.0') // { value: 42 } | ||
) | ||
``` | ||
## API | ||
#### `set(version, store)` | ||
Add a document to the store with the specified version.<br/> | ||
The version **must** be conform with the [semver](http://semver.org/) specification. | ||
#### `get(version)` | ||
Get a document from the store with the specified version.<br/> | ||
The version string could be a full version string or specify a range, such as `1.x`, in which case the highest version compatible will be returned. | ||
#### `del(version)` | ||
Deletes a document from the store with the specified version.<br/> | ||
The version string could be a full version string or specify a range, such as `1.x`, in which case all the compatible values will be deleted. | ||
#### `empty()` | ||
Empties the store. | ||
### Why is fast? | ||
Internally uses a prefix tree, which allows the search to be extremely performant. | ||
Internally uses a [prefix tree](https://en.wikipedia.org/wiki/Trie), which allows the search to be extremely performant. | ||
@@ -25,0 +43,0 @@ ## License |
363
test.js
@@ -11,5 +11,6 @@ 'use strict' | ||
store.set('1.2.3', 1) | ||
store.set('1.2.4', 2) | ||
store.set('1.3.0', 3) | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
.set('1.3.0', 3) | ||
@@ -69,5 +70,6 @@ t.deepEqual(store.tree, { | ||
store.set('1.2.3', 1) | ||
store.set('1.2.4', 2) | ||
store.set('1.3.0', 3) | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
.set('1.3.0', 3) | ||
@@ -82,5 +84,6 @@ t.strictEqual(store.get('1.2.4'), 2) | ||
store.set('1.2.3', 1) | ||
store.set('1.2.4', 2) | ||
store.set('1.3.0', 3) | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
.set('1.3.0', 3) | ||
@@ -95,5 +98,6 @@ t.strictEqual(store.get('1.2.x'), 2) | ||
store.set('1.2.3', 1) | ||
store.set('1.2.4', 2) | ||
store.set('1.3.0', 3) | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
.set('1.3.0', 3) | ||
@@ -108,5 +112,6 @@ t.strictEqual(store.get('1.x'), 3) | ||
store.set('1.2.3', 1) | ||
store.set('1.2.4', 2) | ||
store.set('1.3.0', 3) | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
.set('1.3.0', 3) | ||
@@ -121,5 +126,6 @@ t.strictEqual(store.get('2.2.x'), null) | ||
store.set('1.2.3', 1) | ||
store.set('1.2.4', 2) | ||
store.set('1.3.0', 3) | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
.set('1.3.0', 3) | ||
@@ -134,5 +140,6 @@ t.strictEqual(store.get('2.x'), null) | ||
store.set('1.2.3', 1) | ||
store.set('1.2.4', 2) | ||
store.set('1.3.0', 3) | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
.set('1.3.0', 3) | ||
@@ -147,5 +154,6 @@ t.strictEqual(store.get('1.2'), 2) | ||
store.set('1.2.3', 1) | ||
store.set('1.2.4', 2) | ||
store.set('1.3.0', 3) | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
.set('1.3.0', 3) | ||
@@ -160,5 +168,6 @@ t.strictEqual(store.get('1.2.5'), null) | ||
store.set('1.2.3', 1) | ||
store.set('1.2.4', 2) | ||
store.set('1.3.0', 3) | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
.set('1.3.0', 3) | ||
@@ -173,5 +182,6 @@ t.strictEqual(store.get('1.2.a'), null) | ||
store.set('1.2.3', 1) | ||
store.set('1.2.4', 2) | ||
store.set('1.3.0', 3) | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
.set('1.3.0', 3) | ||
@@ -186,12 +196,289 @@ t.strictEqual(store.get('1.a'), null) | ||
store.set('1.22.34', 1) | ||
store.set('2.32.456', 2) | ||
store.set('345.432.34', 3) | ||
store.set('343.432.36', 4) | ||
store.set('343.432.342', 5) | ||
store.set('343.435.367', 6) | ||
store.set('342.435.34', 7) | ||
store.set('341.432.34', 8) | ||
store | ||
.set('1.22.34', 1) | ||
.set('2.32.456', 2) | ||
.set('345.432.34', 3) | ||
.set('343.432.36', 4) | ||
.set('343.432.342', 5) | ||
.set('343.435.367', 6) | ||
.set('342.435.34', 7) | ||
.set('341.432.34', 8) | ||
t.strictEqual(store.get('343.x'), 6) | ||
}) | ||
test('Delete a version / 1', t => { | ||
t.plan(4) | ||
const store = SemVerStore() | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
t.strictEqual(store.get('1.2.3'), 1) | ||
t.strictEqual(store.get('1.2.4'), 2) | ||
store.del('1.2.3') | ||
t.strictEqual(store.get('1.2.3'), null) | ||
t.strictEqual(store.get('1.2.4'), 2) | ||
}) | ||
test('Delete a version / 2', t => { | ||
t.plan(2) | ||
const store = SemVerStore() | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.2.4', 2) | ||
t.deepEqual(store.tree, { | ||
prefix: 0, | ||
store: null, | ||
childrenPrefixes: [1], | ||
children: { | ||
1: { | ||
prefix: 1, | ||
store: null, | ||
childrenPrefixes: [2], | ||
children: { | ||
2: { | ||
prefix: 2, | ||
store: null, | ||
childrenPrefixes: [3, 4], | ||
children: { | ||
3: { | ||
prefix: 3, | ||
store: 1, | ||
childrenPrefixes: [], | ||
children: null | ||
}, | ||
4: { | ||
prefix: 4, | ||
store: 2, | ||
childrenPrefixes: [], | ||
children: null | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
store.del('1.2.3') | ||
t.deepEqual(store.tree, { | ||
prefix: 0, | ||
store: null, | ||
childrenPrefixes: [1], | ||
children: { | ||
1: { | ||
prefix: 1, | ||
store: null, | ||
childrenPrefixes: [2], | ||
children: { | ||
2: { | ||
prefix: 2, | ||
store: null, | ||
childrenPrefixes: [4], | ||
children: { | ||
4: { | ||
prefix: 4, | ||
store: 2, | ||
childrenPrefixes: [], | ||
children: null | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
}) | ||
test('Delete a version / 3', t => { | ||
t.plan(1) | ||
const store = SemVerStore() | ||
store | ||
.set('1.2.3', 1) | ||
.del('1.2.3') | ||
t.deepEqual(store.tree, { | ||
prefix: 0, | ||
store: null, | ||
childrenPrefixes: [], | ||
children: {} | ||
}) | ||
}) | ||
test('Delete a version / 4', t => { | ||
t.plan(1) | ||
const store = SemVerStore() | ||
store | ||
.set('1.2.3', 1) | ||
.set('2.2.3', 2) | ||
.del('1.2.3') | ||
t.deepEqual(store.tree, { | ||
prefix: 0, | ||
store: null, | ||
childrenPrefixes: [2], | ||
children: { | ||
2: { | ||
prefix: 2, | ||
store: null, | ||
childrenPrefixes: [2], | ||
children: { | ||
2: { | ||
prefix: 2, | ||
store: null, | ||
childrenPrefixes: [3], | ||
children: { | ||
3: { | ||
prefix: 3, | ||
store: 2, | ||
childrenPrefixes: [], | ||
children: null | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
}) | ||
test('Delete a version / 5', t => { | ||
t.plan(1) | ||
const store = SemVerStore() | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.3.3', 2) | ||
.set('2.2.3', 3) | ||
.del('1.2.x') | ||
t.deepEqual(store.tree, { | ||
prefix: 0, | ||
store: null, | ||
childrenPrefixes: [1, 2], | ||
children: { | ||
1: { | ||
prefix: 1, | ||
store: null, | ||
childrenPrefixes: [3], | ||
children: { | ||
3: { | ||
prefix: 3, | ||
store: null, | ||
childrenPrefixes: [3], | ||
children: { | ||
3: { | ||
prefix: 3, | ||
store: 2, | ||
childrenPrefixes: [], | ||
children: null | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
2: { | ||
prefix: 2, | ||
store: null, | ||
childrenPrefixes: [2], | ||
children: { | ||
2: { | ||
prefix: 2, | ||
store: null, | ||
childrenPrefixes: [3], | ||
children: { | ||
3: { | ||
prefix: 3, | ||
store: 3, | ||
childrenPrefixes: [], | ||
children: null | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
}) | ||
test('Delete a version / 6', t => { | ||
t.plan(2) | ||
const store = SemVerStore() | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.3.3', 2) | ||
.set('2.2.3', 3) | ||
.del('1.x') | ||
t.deepEqual(store.tree, { | ||
prefix: 0, | ||
store: null, | ||
childrenPrefixes: [2], | ||
children: { | ||
2: { | ||
prefix: 2, | ||
store: null, | ||
childrenPrefixes: [2], | ||
children: { | ||
2: { | ||
prefix: 2, | ||
store: null, | ||
childrenPrefixes: [3], | ||
children: { | ||
3: { | ||
prefix: 3, | ||
store: 3, | ||
childrenPrefixes: [], | ||
children: null | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
store.del('2.x') | ||
t.deepEqual(store.tree, { | ||
prefix: 0, | ||
store: null, | ||
childrenPrefixes: [], | ||
children: {} | ||
}) | ||
}) | ||
test('Empty store', t => { | ||
t.plan(1) | ||
const store = SemVerStore() | ||
store | ||
.set('1.2.3', 1) | ||
.set('1.3.3', 2) | ||
.set('2.2.3', 3) | ||
.empty() | ||
t.deepEqual(store.tree, { | ||
prefix: 0, | ||
store: null, | ||
childrenPrefixes: [], | ||
children: null | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
16954
3
586
45
1