object-scan
Advanced tools
Comparing version 16.0.3 to 16.1.0
@@ -18,2 +18,3 @@ "use strict"; | ||
const COUNTER = Symbol('counter'); | ||
const LEAF = Symbol('leaf'); | ||
@@ -82,2 +83,9 @@ | ||
module.exports.getIndex = getIndex; | ||
const ORDER = Symbol('order'); | ||
const setOrder = (input, order) => defineProperty(input, ORDER, order); | ||
const getOrder = input => input[ORDER]; | ||
module.exports.getOrder = getOrder; | ||
const WILDCARD = Symbol('wildcard'); | ||
@@ -98,6 +106,6 @@ | ||
module.exports.matchedBy = searches => Array.from(new Set([].concat(...searches.map(e => getLeafNeedlesMatch(e))))); | ||
module.exports.excludedBy = searches => Array.from(new Set([].concat(...searches.map(e => getLeafNeedlesExclude(e))))); | ||
module.exports.matchedBy = searches => Array.from(new Set([].concat(...searches.map(e => getLeafNeedlesMatch(e))))); | ||
module.exports.traversedBy = searches => Array.from(new Set([].concat(...searches.map(e => getNeedles(e))))); | ||
@@ -157,3 +165,3 @@ | ||
const applyNeedle = (tower, needle, tree, strict, ctx) => { | ||
const applyNeedle = (tower, needle, tree, ctx) => { | ||
iterate(tower, needle, tree, { | ||
@@ -164,3 +172,3 @@ onAdd: (cur, wc, wcParent, next) => { | ||
if (redundantRecursion && strict) { | ||
if (redundantRecursion && ctx.strict) { | ||
throw new Error(`Redundant Recursion: "${needle}"`); | ||
@@ -170,6 +178,11 @@ } | ||
if (!redundantRecursion) { | ||
if (cur[wc.value] === undefined) { | ||
if (!(wc.value in cur)) { | ||
const child = {}; // eslint-disable-next-line no-param-reassign | ||
cur[wc.value] = child; | ||
if (ctx.orderByNeedles) { | ||
setOrder(child, ctx[COUNTER]); | ||
} | ||
setWildcard(child, wc); | ||
@@ -186,3 +199,3 @@ } | ||
onFin: (cur, wc, parent, excluded) => { | ||
if (strict) { | ||
if (ctx.strict) { | ||
if (wc.isSimpleStarRec) { | ||
@@ -199,7 +212,7 @@ const unnecessary = Object.keys(parent).filter(k => !['**', ''].includes(k)); | ||
if (strict && LEAF_NEEDLES in cur) { | ||
if (ctx.strict && LEAF_NEEDLES in cur) { | ||
throw new Error(`Redundant Needle Target: "${cur[LEAF_NEEDLES][0]}" vs "${needle}"`); | ||
} | ||
addLeafNeedle(cur, needle, strict); | ||
addLeafNeedle(cur, needle, ctx.strict); | ||
@@ -212,5 +225,5 @@ if (excluded) { | ||
markLeaf(cur, !excluded, strict); | ||
setIndex(cur, ctx.index, strict); | ||
ctx.index += 1; | ||
markLeaf(cur, !excluded, ctx.strict); | ||
setIndex(cur, ctx[COUNTER], ctx.strict); | ||
ctx[COUNTER] += 1; | ||
} | ||
@@ -242,12 +255,10 @@ }); | ||
module.exports.compile = (needles, strict = true, useArraySelector = true) => { | ||
module.exports.compile = (needles, ctx) => { | ||
const tower = {}; | ||
const ctx = { | ||
index: 0 | ||
}; | ||
ctx[COUNTER] = 0; | ||
for (let idx = 0; idx < needles.length; idx += 1) { | ||
const needle = needles[idx]; | ||
const tree = [parser.parse(needle, useArraySelector)]; | ||
applyNeedle(tower, needle, tree, strict, ctx); | ||
const tree = [parser.parse(needle, ctx)]; | ||
applyNeedle(tower, needle, tree, ctx); | ||
} | ||
@@ -254,0 +265,0 @@ |
@@ -13,2 +13,6 @@ "use strict"; | ||
const { | ||
getOrder | ||
} = require('./compiler'); | ||
const formatPath = (input, ctx) => ctx.joined ? toPath(input) : [...input]; | ||
@@ -236,3 +240,14 @@ | ||
stack.push(false, searchesOut, isArray ? Number(key) : key, depth + 1); | ||
if (ctx.orderByNeedles) { | ||
searchesOut.index = Buffer.from(searchesOut.map(e => getOrder(e)).sort()); | ||
let insertIdx = stack.length - kIdx * 4; | ||
while (insertIdx < stack.length && Buffer.compare(searchesOut.index, stack[insertIdx + 1].index) !== 1) { | ||
insertIdx += 4; | ||
} | ||
stack.splice(insertIdx, 0, false, searchesOut, isArray ? Number(key) : key, depth + 1); | ||
} else { | ||
stack.push(false, searchesOut, isArray ? Number(key) : key, depth + 1); | ||
} | ||
} | ||
@@ -239,0 +254,0 @@ } |
@@ -13,3 +13,3 @@ "use strict"; | ||
module.exports.parse = (input, useArraySelector = true) => { | ||
module.exports.parse = (input, ctx) => { | ||
if (input === '') { | ||
@@ -37,3 +37,3 @@ return new Wildcard('', false); | ||
case '[': | ||
if (useArraySelector === false) { | ||
if (!ctx.useArraySelector) { | ||
throwError('Forbidden Array Selector', input, { | ||
@@ -40,0 +40,0 @@ char: idx |
@@ -9,2 +9,4 @@ "use strict"; | ||
const Context = require('./core/context'); | ||
module.exports = (needles, opts = {}) => { | ||
@@ -18,29 +20,4 @@ assert(Array.isArray(needles)); | ||
const ctx = { | ||
filterFn: undefined, | ||
breakFn: undefined, | ||
beforeFn: undefined, | ||
afterFn: undefined, | ||
compareFn: undefined, | ||
reverse: true, | ||
abort: false, | ||
rtn: undefined, | ||
joined: false, | ||
useArraySelector: true, | ||
strict: true, | ||
...opts | ||
}; | ||
assert(Object.keys(ctx).length === 11, 'Unexpected Option provided!'); | ||
assert(['function', 'undefined'].includes(typeof ctx.filterFn)); | ||
assert(['function', 'undefined'].includes(typeof ctx.breakFn)); | ||
assert(['function', 'undefined'].includes(typeof ctx.beforeFn)); | ||
assert(['function', 'undefined'].includes(typeof ctx.afterFn)); | ||
assert(['function', 'undefined'].includes(typeof ctx.compareFn)); | ||
assert(typeof ctx.reverse === 'boolean'); | ||
assert(typeof ctx.abort === 'boolean'); | ||
assert([undefined, 'context', 'key', 'value', 'entry', 'property', 'gproperty', 'parent', 'gparent', 'parents', 'isMatch', 'matchedBy', 'excludedBy', 'traversedBy', 'isCircular', 'isLeaf', 'depth', 'bool', 'count'].includes(opts.rtn) || Array.isArray(opts.rtn) && opts.rtn.every(e => ['key', 'value', 'entry', 'property', 'gproperty', 'parent', 'gparent', 'parents', 'isMatch', 'matchedBy', 'excludedBy', 'traversedBy', 'isCircular', 'isLeaf', 'depth'].includes(e))); | ||
assert(typeof ctx.joined === 'boolean'); | ||
assert(typeof ctx.useArraySelector === 'boolean'); | ||
assert(typeof ctx.strict === 'boolean'); | ||
const search = compiler.compile(needles, ctx.strict, ctx.useArraySelector); // keep separate for performance | ||
const ctx = Context(opts); | ||
const search = compiler.compile(needles, ctx); // keep separate for performance | ||
@@ -47,0 +24,0 @@ return (haystack, context) => find(haystack, [search], { |
{ | ||
"name": "object-scan", | ||
"version": "16.0.3", | ||
"version": "16.1.0", | ||
"description": "Traverse object hierarchies using matching and callbacks.", | ||
@@ -50,7 +50,7 @@ "main": "lib/index.js", | ||
"devDependencies": { | ||
"@babel/cli": "7.14.5", | ||
"@babel/core": "7.14.6", | ||
"@babel/cli": "7.14.8", | ||
"@babel/core": "7.14.8", | ||
"@babel/register": "7.14.5", | ||
"@blackflux/eslint-plugin-rules": "2.0.3", | ||
"@blackflux/robo-config-plugin": "5.2.4", | ||
"@blackflux/robo-config-plugin": "5.2.5", | ||
"babel-eslint": "10.1.0", | ||
@@ -61,4 +61,4 @@ "babel-preset-latest-node": "5.5.1", | ||
"diff": "5.0.0", | ||
"diff2html": "3.4.7", | ||
"eslint": "7.30.0", | ||
"diff2html": "3.4.8", | ||
"eslint": "7.32.0", | ||
"eslint-config-airbnb-base": "14.2.1", | ||
@@ -65,0 +65,0 @@ "eslint-plugin-import": "2.23.4", |
@@ -544,2 +544,80 @@ # Object-Scan | ||
#### orderByNeedles | ||
Type: `boolean`<br> | ||
Default: `false` | ||
When set to `false`, all targeted keys are traversed and matched | ||
in the order determined by the `compareFn` and `reverse` option. | ||
When set to `true`, all targeted keys are traversed and matched | ||
in the order determined by the corresponding needles, | ||
falling back to the above ordering. | ||
Note that this option is constraint by the depth-first search approach. | ||
_Examples_: | ||
<details><summary> <code>['c', 'a', 'b']</code> <em>(order by needle)</em> </summary> | ||
<!-- eslint-disable no-undef --> | ||
```js | ||
const haystack = { a: 0, b: 1, c: 1 }; | ||
objectScan(['c', 'a', 'b'], { | ||
joined: true, | ||
orderByNeedles: true | ||
})(haystack); | ||
// => [ 'c', 'a', 'b' ] | ||
``` | ||
</details> | ||
<details><summary> <code>['b', '*']</code> <em>(fallback reverse)</em> </summary> | ||
<!-- eslint-disable no-undef --> | ||
```js | ||
const haystack = { a: 0, b: 1, c: 1 }; | ||
objectScan(['b', '*'], { | ||
joined: true, | ||
reverse: true, | ||
orderByNeedles: true | ||
})(haystack); | ||
// => [ 'b', 'c', 'a' ] | ||
``` | ||
</details> | ||
<details><summary> <code>['b', '*']</code> <em>(fallback not reverse)</em> </summary> | ||
<!-- eslint-disable no-undef --> | ||
```js | ||
const haystack = { a: 0, b: 1, c: 1 }; | ||
objectScan(['b', '*'], { | ||
joined: true, | ||
reverse: false, | ||
orderByNeedles: true | ||
})(haystack); | ||
// => [ 'b', 'a', 'c' ] | ||
``` | ||
</details> | ||
<details><summary> <code>['a', 'b.c', 'd']</code> <em>(nested match)</em> </summary> | ||
<!-- eslint-disable no-undef --> | ||
```js | ||
const haystack = { a: 0, b: { c: 1 }, d: 2 }; | ||
objectScan(['a', 'b.c', 'd'], { | ||
joined: true, | ||
orderByNeedles: true | ||
})(haystack); | ||
// => [ 'a', 'b.c', 'd' ] | ||
``` | ||
</details> | ||
<details><summary> <code>['b', 'a', 'b.c', 'd']</code> <em>(matches traverse first)</em> </summary> | ||
<!-- eslint-disable no-undef --> | ||
```js | ||
const haystack = { a: 0, b: { c: 1 }, d: 2 }; | ||
objectScan(['b', 'a', 'b.c', 'd'], { | ||
joined: true, | ||
orderByNeedles: true | ||
})(haystack); | ||
// => [ 'b.c', 'b', 'a', 'd' ] | ||
``` | ||
</details> | ||
#### abort | ||
@@ -546,0 +624,0 @@ |
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
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
63602
14
886
1078