+39
-18
@@ -1,26 +0,47 @@ | ||
| module.exports = function bm (suitename, options) { | ||
| var Benchmark = require('benchmark') | ||
| var suite = new Benchmark.Suite(suitename) | ||
| var assign = require('object-assign') | ||
| for (var key in options) { | ||
| if (!options.hasOwnProperty(key)) continue | ||
| suite = suite.add(key, options[key]) | ||
| var defaults = { | ||
| onStart: function (suitename) { console.log(suitename) }, | ||
| onStep: function (key) { }, | ||
| onStepEnd: function (key, result) { console.log(' x ' + result.rate + ' op/sec - ' + key) }, | ||
| onError: function (err) { console.error(err.stack) } | ||
| } | ||
| function bm (suitename, steps, options) { | ||
| options = assign({}, defaults, options) | ||
| if (!options) options = {} | ||
| options.onStart(suitename, steps, options) | ||
| for (var key in steps) { | ||
| if (!steps.hasOwnProperty(key)) continue | ||
| try { | ||
| options.onStep(key) | ||
| var result = bm.runBenchmark(steps[key]) | ||
| options.onStepEnd(key, result) | ||
| } catch (err) { | ||
| options.onError(err) | ||
| } | ||
| } | ||
| } | ||
| suite.on('start', function (event) { | ||
| console.log(suitename) | ||
| }) | ||
| bm.timeout = 3 | ||
| suite.on('cycle', function (event) { | ||
| console.log(' ' + String(event.target)) | ||
| }) | ||
| bm.runBenchmark = function runBenchmark (fn) { | ||
| var start = +new Date() | ||
| var timeout = bm.timeout | ||
| var elapsed | ||
| var iterations = 0 | ||
| suite.on('error', function (e) { | ||
| console.log(e.target.error.stack) | ||
| }) | ||
| while (true) { | ||
| fn() | ||
| iterations += 1 | ||
| elapsed = (+new Date() - start) / 1000 | ||
| if (elapsed > timeout) break | ||
| } | ||
| suite.on('complete', function () { | ||
| }) | ||
| var time = elapsed | ||
| var rate = iterations / time | ||
| suite.run({ async: true, maxTime: 2 }) | ||
| return { time: time, rate: Math.round(rate), iterations: iterations } | ||
| } | ||
| module.exports = bm |
+31
-0
@@ -46,1 +46,32 @@ # Comparison | ||
| [example]: extensions_example.md | ||
| ## Versus Baobab | ||
| [Baobab] has a similar goal to Scour. Unlike scour, it supports mutable data structures and events. Scour is optimized towards immutable data handling and can take advantage of performance improvements dealing with immutable stores. | ||
| Baobab keeps a single instance (`new Baobab()`) to manage the entire store. Scour instead creates a new root object for every change. This makes Scour suitable for things like Redux. | ||
| Baobab also has good support for Arrays, which Scour doesn't implement yet. | ||
| Baobab has support for computed properties via `Baobab.monkey`. | ||
| | Scour | Baobab | ||
| |---|--- | ||
| | `.go('path')` | `.select('path')` | ||
| | `.go('path').filter(function)` | `.select('path', function)` | ||
| | `.filter(function)` | `.select(function)` | ||
| | *N/A* | `.on('update', fn)` | ||
| | `.value` | `.get()` | ||
| | `.set('key', 'value')` | `.set('key', 'value')` | ||
| | `.del('key')` | `.unset('key')` | ||
| | *N/A* | `.push('item')` | ||
| | *N/A* | `.unshift('item')` | ||
| | *N/A* | `.concat('item')` | ||
| | *N/A* | `.splice('item')` | ||
| | *N/A* | `.apply(args)` | ||
| | `.extend(object)` | `.merge({ object })` | ||
| | *N/A* | `.deepMerge({ object })` | ||
| | `a.root === a` | `a.isRoot()` | ||
| | *N/A* | `Baobab.monkey` | ||
| [Baobab]: https://github.com/Yomguithereal/baobab |
+6
-0
| # Changelog | ||
| ## [v0.12.0] | ||
| > Jan 8, 2016 | ||
| - Implement `scour#index()`. | ||
| ## [v0.11.0] | ||
@@ -105,1 +110,2 @@ > Jan 1, 2016 | ||
| [v0.11.0]: https://github.com/rstacruz/scour/compare/v0.10.0...v0.11.0 | ||
| [v0.12.0]: https://github.com/rstacruz/scour/compare/v0.11.0...v0.12.0 |
+92
-6
| /* eslint-disable new-cap */ | ||
| 'use strict'; | ||
| function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; } | ||
| var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; | ||
| function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
| var Search = require('scour-search'); | ||
@@ -63,2 +65,3 @@ var assign = require('object-assign'); | ||
| this.extensions = options && options.extensions || []; | ||
| this.indices = options && options.indices || undefined; | ||
@@ -178,2 +181,3 @@ // Apply any property extensions | ||
| * index, not by key. This returns a the raw value, unlike [at()]. | ||
| * *(Since v0.5)* | ||
| * | ||
@@ -248,3 +252,6 @@ * users = | ||
| } | ||
| return this.reset(Search(this.value).filter(conditions)); | ||
| var idx = this.indices && this.indices[this.keypath.join('.')] || Search(this.value); | ||
| return this.reset(idx.filter(conditions)); | ||
| }, | ||
@@ -324,3 +331,3 @@ filterByFunction: function filterByFunction(fn) { | ||
| * chaining. Like other chainable methods, this works on arrays as well as | ||
| * objects. | ||
| * objects. *(Since v0.8)* | ||
| * | ||
@@ -513,3 +520,7 @@ * data = | ||
| var result = scour.set(this.value || {}, keypath, value.valueOf()); | ||
| return this.reset(result, { root: null }); | ||
| // Update indices, if any | ||
| var indices = updateIndices(this.indices, result, keypath); | ||
| return this.reset(result, { root: null, indices: indices }); | ||
| }, | ||
@@ -539,3 +550,4 @@ | ||
| var result = scour.del(this.value, keypath); | ||
| return this.reset(result, { root: null }); | ||
| var indices = updateIndices(this.indices, result, keypath); | ||
| return this.reset(result, { root: null, indices: indices }); | ||
| }, | ||
@@ -580,3 +592,5 @@ | ||
| return this.reset(result, { root: false }); | ||
| // TODO | ||
| var indices = updateAllIndices(this.indices, result); | ||
| return this.reset(result, { root: false, indices: indices }); | ||
| }, | ||
@@ -674,2 +688,40 @@ | ||
| /** | ||
| * index : index(keypath, field) | ||
| * Sets up indices to improve [filter()] performance. *(Since v0.12)* | ||
| * | ||
| * - `keypath` *(String | Array)* - the keypath of the collection. | ||
| * - `field` *(String)* - the name of the field to be indexed. | ||
| * | ||
| * data = | ||
| * { users: | ||
| * { 1: { name: 'John Creamer' }, | ||
| * 2: { name: 'Stephane K' } } } | ||
| * | ||
| * db = scour(data).index('users', 'name') | ||
| * db.filter({ name: 'Stephane K' }) | ||
| * | ||
| * Doing this will add an index in the root (acccessible via | ||
| * `scour().indices`) to make searches faster for certain [filter()] queries. | ||
| * Any writing actions ([set()], [extend()], [del()]) will automatically | ||
| * update the index. | ||
| * | ||
| * See [scour-search] for more information on indexing. | ||
| * | ||
| * [scour-search]: https://github.com/rstacruz/scour-search | ||
| */ | ||
| index: function index(keypath, field) { | ||
| keypath = normalizeKeypath(keypath); | ||
| if (this.root !== this) return this.root.index(keypath); | ||
| var oldIndices = this.indices || {}; | ||
| var keypathStr = keypath.join('.'); | ||
| var indices = assign({}, oldIndices, _defineProperty({}, keypathStr, (oldIndices[keypathStr] || Search(this.get(keypath) || {})).index(field))); | ||
| // TODO remove ||{} | ||
| return this.reset(this.value, { indices: indices, root: null }); | ||
| }, | ||
| /** | ||
| * Returns the value for serialization. This allows `JSON.stringify()` to | ||
@@ -843,2 +895,3 @@ * work with `scour`-wrapped objects. The name of this method is a bit | ||
| keypath: typeof op.keypath !== 'undefined' ? op.keypath : this.keypath, | ||
| indices: typeof op.indices !== 'undefined' ? op.indices : this.indices, | ||
| extensions: typeof op.extensions !== 'undefined' ? this.extensions.concat(op.extensions) : this.extensions | ||
@@ -933,2 +986,35 @@ }); | ||
| /** | ||
| * Internal: in the root, given the new data `result`, do an update because | ||
| * `keypath` was changed. | ||
| */ | ||
| function updateIndices(indices, result, keypath) { | ||
| if (!indices) return; | ||
| for (var len = keypath.length, i = len; i >= 0; i--) { | ||
| var newKeypath = keypath.slice(0, i); | ||
| var keypathStr = newKeypath.join('.'); | ||
| if (indices[keypathStr]) { | ||
| var newData = utils.get(result, newKeypath); | ||
| var keys = i === len ? Object.keys(newData) : keypath[i]; | ||
| indices[keypathStr] = indices[keypathStr].reindex(newData, keys); | ||
| } | ||
| } | ||
| return indices; | ||
| } | ||
| function updateAllIndices(indices, result) { | ||
| if (!indices) return; | ||
| var keys = Object.keys(result); | ||
| for (var i = 0, len = keys.length; i < len; i++) { | ||
| indices = updateIndices(indices, result, [keys[i]]); | ||
| } | ||
| return indices; | ||
| } | ||
| module.exports = scour; |
+4
-3
| { | ||
| "name": "scourjs", | ||
| "description": "Traverse objects and arrays", | ||
| "version": "0.11.0", | ||
| "version": "0.12.0", | ||
| "author": "Rico Sta. Cruz <rico@ricostacruz.com>", | ||
@@ -20,5 +20,4 @@ "babel": { | ||
| "devDependencies": { | ||
| "babel-cli": "6.3.17", | ||
| "babel-cli": "6.4.0", | ||
| "babel-preset-es2015": "6.3.13", | ||
| "benchmark": "1.0.0", | ||
| "docpress": "0.6.10", | ||
@@ -29,2 +28,3 @@ "expect": "1.13.4", | ||
| "mdx": "0.3.1", | ||
| "sinon": "1.17.2", | ||
| "standard": "5.4.1", | ||
@@ -39,2 +39,3 @@ "tap-spec": "4.1.1", | ||
| "homepage": "https://github.com/rstacruz/scour#readme", | ||
| "jsnext:main": "src/index.js", | ||
| "keywords": [ | ||
@@ -41,0 +42,0 @@ "array", |
+31
-1
@@ -314,2 +314,3 @@ # scour.js | ||
| index, not by key. This returns a the raw value, unlike [at()]. | ||
| *(Since v0.5)* | ||
@@ -428,3 +429,3 @@ ```js | ||
| chaining. Like other chainable methods, this works on arrays as well as | ||
| objects. | ||
| objects. *(Since v0.8)* | ||
@@ -719,2 +720,30 @@ ```js | ||
| ### index | ||
| > `index(keypath, field)` | ||
| Sets up indices to improve [filter()] performance. *(Since v0.12)* | ||
| - `keypath` *(String | Array)* - the keypath of the collection. | ||
| - `field` *(String)* - the name of the field to be indexed. | ||
| ```js | ||
| data = | ||
| { users: | ||
| { 1: { name: 'John Creamer' }, | ||
| 2: { name: 'Stephane K' } } } | ||
| db = scour(data).index('users', 'name') | ||
| db.filter({ name: 'Stephane K' }) | ||
| ``` | ||
| Doing this will add an index in the root (acccessible via | ||
| `scour().indices`) to make searches faster for certain [filter()] queries. | ||
| Any writing actions ([set()], [extend()], [del()]) will automatically | ||
| update the index. | ||
| See [scour-search] for more information on indexing. | ||
| [scour-search]: https://github.com/rstacruz/scour-search | ||
| ### toJSON | ||
@@ -1134,2 +1163,3 @@ | ||
| [Immutable.js]: http://facebook.github.io/immutable-js/ | ||
| [scour-search]: https://github.com/rstacruz/scour-search | ||
@@ -1136,0 +1166,0 @@ ## Thanks |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
539982
1.08%4434
2%1173
2.62%