object-scan
Advanced tools
Comparing version 17.1.0 to 18.0.0
@@ -1,37 +0,19 @@ | ||
"use strict"; | ||
/* compile needles to hierarchical map object */ | ||
const parser = require('./parser'); | ||
import parser from './parser.js'; | ||
import iterator from '../generic/iterator.js'; | ||
import traverser from '../generic/traverser.js'; | ||
import { defineProperty } from '../generic/helper.js'; | ||
import { Wildcard } from './wildcard.js'; | ||
const iterator = require('../generic/iterator'); | ||
const COUNTER = Symbol('counter'); | ||
const traverser = require('../generic/traverser'); | ||
const { | ||
defineProperty | ||
} = require('../generic/helper'); | ||
const { | ||
Wildcard | ||
} = require('./wildcard'); | ||
const COUNTER = Symbol('counter'); | ||
const LEAF = Symbol('leaf'); | ||
const markLeaf = (input, match, readonly) => defineProperty(input, LEAF, match, readonly); | ||
export const isLeaf = (input) => LEAF in input; | ||
export const isMatch = (input) => input !== undefined && input[LEAF] === true; | ||
const isLeaf = input => LEAF in input; | ||
const isMatch = input => input !== undefined && input[LEAF] === true; | ||
module.exports.isLeaf = isLeaf; | ||
module.exports.isMatch = isMatch; | ||
const HAS_MATCHES = Symbol('has-matches'); | ||
const setHasMatches = (input) => defineProperty(input, HAS_MATCHES, true); | ||
export const hasMatches = (input) => input[HAS_MATCHES] === true; | ||
const setHasMatches = input => defineProperty(input, HAS_MATCHES, true); | ||
const hasMatches = input => input[HAS_MATCHES] === true; | ||
module.exports.hasMatches = hasMatches; | ||
const merge = (input, symbol, value) => { | ||
@@ -41,3 +23,2 @@ if (input[symbol] === undefined) { | ||
} | ||
if (!input[symbol].includes(value)) { | ||
@@ -49,72 +30,46 @@ input[symbol].push(value); | ||
const LEAF_NEEDLES = Symbol('leaf-needles'); | ||
const addLeafNeedle = (input, needle) => merge(input, LEAF_NEEDLES, needle); | ||
export const getLeafNeedles = (input) => input[LEAF_NEEDLES] || []; | ||
const getLeafNeedles = input => input[LEAF_NEEDLES] || []; | ||
module.exports.getLeafNeedles = getLeafNeedles; | ||
const LEAF_NEEDLES_EXCLUDE = Symbol('leaf-needles-exclude'); | ||
const addLeafNeedleExclude = (input, needle) => merge(input, LEAF_NEEDLES_EXCLUDE, needle); | ||
export const getLeafNeedlesExclude = (input) => input[LEAF_NEEDLES_EXCLUDE] || []; | ||
const getLeafNeedlesExclude = input => input[LEAF_NEEDLES_EXCLUDE] || []; | ||
module.exports.getLeafNeedlesExclude = getLeafNeedlesExclude; | ||
const LEAF_NEEDLES_MATCH = Symbol('leaf-needles-match'); | ||
const addLeafNeedleMatch = (input, needle) => merge(input, LEAF_NEEDLES_MATCH, needle); | ||
export const getLeafNeedlesMatch = (input) => input[LEAF_NEEDLES_MATCH] || []; | ||
const getLeafNeedlesMatch = input => input[LEAF_NEEDLES_MATCH] || []; | ||
module.exports.getLeafNeedlesMatch = getLeafNeedlesMatch; | ||
const NEEDLES = Symbol('needles'); | ||
const addNeedle = (input, needle) => merge(input, NEEDLES, needle); | ||
export const getNeedles = (input) => input[NEEDLES]; | ||
const getNeedles = input => input[NEEDLES]; | ||
module.exports.getNeedles = getNeedles; | ||
const INDEX = Symbol('index'); | ||
const setIndex = (input, index, readonly) => defineProperty(input, INDEX, index, readonly); | ||
export const getIndex = (input) => input[INDEX]; | ||
const getIndex = input => input[INDEX]; | ||
module.exports.getIndex = getIndex; | ||
const ORDER = Symbol('order'); | ||
const setOrder = (input, order) => defineProperty(input, ORDER, order); | ||
export const getOrder = (input) => input[ORDER]; | ||
const getOrder = input => input[ORDER]; | ||
module.exports.getOrder = getOrder; | ||
const WILDCARD = Symbol('wildcard'); | ||
const setWildcard = (input, wildcard) => defineProperty(input, WILDCARD, wildcard); | ||
export const getWildcard = (input) => input[WILDCARD]; | ||
const getWildcard = input => input[WILDCARD]; | ||
module.exports.getWildcard = getWildcard; | ||
const VALUES = Symbol('values'); | ||
const setValues = (input, entries) => defineProperty(input, VALUES, entries); | ||
export const getValues = (input) => input[VALUES]; | ||
const getValues = input => input[VALUES]; | ||
export const matchedBy = (searches) => Array | ||
.from(new Set([].concat(...searches.map((e) => getLeafNeedlesMatch(e))))); | ||
export const excludedBy = (searches) => Array | ||
.from(new Set([].concat(...searches.map((e) => getLeafNeedlesExclude(e))))); | ||
export const traversedBy = (searches) => Array | ||
.from(new Set([].concat(...searches.map((e) => getNeedles(e))))); | ||
module.exports.getValues = getValues; | ||
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.traversedBy = searches => Array.from(new Set([].concat(...searches.map(e => getNeedles(e))))); | ||
module.exports.isLastLeafMatch = searches => { | ||
export const isLastLeafMatch = (searches) => { | ||
let maxLeafIndex = Number.MIN_SAFE_INTEGER; | ||
let maxLeaf = null; | ||
for (let idx = 0, len = searches.length; idx < len; idx += 1) { | ||
const s = searches[idx]; | ||
const index = getIndex(s); | ||
if (index !== undefined && index > maxLeafIndex) { | ||
@@ -125,13 +80,10 @@ maxLeafIndex = index; | ||
} | ||
return maxLeaf !== null && isMatch(maxLeaf); | ||
}; | ||
const iterate = (tower, needle, tree, { | ||
onAdd, | ||
onFin | ||
}) => { | ||
const iterate = (tower, needle, tree, { onAdd, onFin }) => { | ||
const stack = [[[tower, null]]]; | ||
const wildcards = []; | ||
let excluded = false; | ||
iterator.iterate(tree, (type, wc) => { | ||
@@ -142,3 +94,2 @@ if (type === 'RM') { | ||
} | ||
stack.pop(); | ||
@@ -151,13 +102,14 @@ wildcards.pop(); | ||
} | ||
excluded = true; | ||
} | ||
const toAdd = []; | ||
const wcParent = wildcards[wildcards.length - 1]; | ||
stack[stack.length - 1].forEach(([cur]) => onAdd(cur, wc, wcParent, e => toAdd.push([e, cur]))); | ||
stack[stack.length - 1] | ||
.forEach(([cur]) => onAdd(cur, wc, wcParent, (e) => toAdd.push([e, cur]))); | ||
stack.push(toAdd); | ||
wildcards.push(wc); | ||
} else { | ||
stack[stack.length - 1].filter(([cur]) => cur !== tower).forEach(([cur, parent]) => onFin(cur, wc[wc.length - 1], parent, excluded)); | ||
stack[stack.length - 1] | ||
.filter(([cur]) => cur !== tower) | ||
.forEach(([cur, parent]) => onFin(cur, wc[wc.length - 1], parent, excluded)); | ||
} | ||
@@ -171,24 +123,22 @@ }); | ||
addNeedle(cur, needle); | ||
const redundantRecursion = wcParent !== undefined && wc.isStarRec && wc.value === wcParent.value; | ||
const redundantRecursion = ( | ||
wcParent !== undefined | ||
&& wc.isStarRec | ||
&& wc.value === wcParent.value | ||
); | ||
if (redundantRecursion && ctx.strict) { | ||
throw new Error(`Redundant Recursion: "${needle}"`); | ||
} | ||
if (!redundantRecursion) { | ||
if (!(wc.value in cur)) { | ||
const child = {}; // eslint-disable-next-line no-param-reassign | ||
const child = {}; | ||
// eslint-disable-next-line no-param-reassign | ||
cur[wc.value] = child; | ||
if (ctx.orderByNeedles) { | ||
setOrder(child, ctx[COUNTER]); | ||
} | ||
setWildcard(child, wc); | ||
} | ||
next(cur[wc.value]); | ||
} | ||
if (wc.isStarRec) { | ||
@@ -201,4 +151,3 @@ next(cur); | ||
if (wc.isSimpleStarRec) { | ||
const unnecessary = Object.keys(parent).filter(k => !['**', ''].includes(k)); | ||
const unnecessary = Object.keys(parent).filter((k) => !['**', ''].includes(k)); | ||
if (unnecessary.length !== 0) { | ||
@@ -209,11 +158,7 @@ throw new Error(`Needle Target Invalidated: "${parent[unnecessary[0]][NEEDLES][0]}" by "${needle}"`); | ||
} | ||
addNeedle(cur, needle); | ||
if (ctx.strict && LEAF_NEEDLES in cur) { | ||
throw new Error(`Redundant Needle Target: "${cur[LEAF_NEEDLES][0]}" vs "${needle}"`); | ||
} | ||
addLeafNeedle(cur, needle, ctx.strict); | ||
if (excluded) { | ||
@@ -224,3 +169,2 @@ addLeafNeedleExclude(cur, needle); | ||
} | ||
markLeaf(cur, !excluded, ctx.strict); | ||
@@ -233,18 +177,16 @@ setIndex(cur, ctx[COUNTER], ctx.strict); | ||
const finalizeTower = tower => { | ||
const finalizeTower = (tower) => { | ||
const matches = []; | ||
let lastDepth = -1; | ||
traverser.traverse(tower, (type, obj, depth) => { | ||
if (type === 'EXIT') { | ||
const isUp = lastDepth === depth + 1; | ||
if (isUp && matches[lastDepth] === true || isMatch(obj)) { | ||
if ((isUp && matches[lastDepth] === true) || isMatch(obj)) { | ||
matches[depth] = true; | ||
setHasMatches(obj); | ||
} | ||
if (isUp) { | ||
matches[lastDepth] = false; | ||
} | ||
setValues(obj, Object.values(obj).reverse()); | ||
@@ -256,6 +198,5 @@ lastDepth = depth; | ||
module.exports.compile = (needles, ctx) => { | ||
export const compile = (needles, ctx) => { | ||
const tower = {}; | ||
ctx[COUNTER] = 0; | ||
for (let idx = 0; idx < needles.length; idx += 1) { | ||
@@ -266,6 +207,5 @@ const needle = needles[idx]; | ||
} | ||
setWildcard(tower, new Wildcard('*', false)); | ||
finalizeTower(tower); | ||
return tower; | ||
}; | ||
}; |
@@ -1,6 +0,4 @@ | ||
"use strict"; | ||
import assert from 'assert'; | ||
const assert = require('assert'); | ||
module.exports = opts => { | ||
export default (opts) => { | ||
const ctx = { | ||
@@ -21,2 +19,3 @@ filterFn: undefined, | ||
}; | ||
assert(Object.keys(ctx).length === 12, 'Unexpected Option provided!'); | ||
@@ -31,7 +30,30 @@ assert(['function', 'undefined'].includes(typeof ctx.filterFn)); | ||
assert(typeof ctx.abort === 'boolean'); | ||
assert(typeof ctx.rtn === 'function' && ctx.rtn.length === 1 || [undefined, 'context', 'key', 'value', 'entry', 'property', 'gproperty', 'parent', 'gparent', 'parents', 'isMatch', 'matchedBy', 'excludedBy', 'traversedBy', 'isCircular', 'isLeaf', 'depth', 'bool', 'count'].includes(ctx.rtn) || Array.isArray(ctx.rtn) && ctx.rtn.every(e => ['key', 'value', 'entry', 'property', 'gproperty', 'parent', 'gparent', 'parents', 'isMatch', 'matchedBy', 'excludedBy', 'traversedBy', 'isCircular', 'isLeaf', 'depth'].includes(e))); | ||
assert( | ||
( | ||
typeof ctx.rtn === 'function' | ||
&& ctx.rtn.length === 1 | ||
) | ||
|| [ | ||
undefined, 'context', | ||
'key', 'value', 'entry', | ||
'property', 'gproperty', 'parent', 'gparent', 'parents', | ||
'isMatch', 'matchedBy', 'excludedBy', | ||
'traversedBy', 'isCircular', 'isLeaf', 'depth', | ||
'bool', 'count' | ||
].includes(ctx.rtn) | ||
|| ( | ||
Array.isArray(ctx.rtn) | ||
&& ctx.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'); | ||
return ctx; | ||
}; | ||
}; |
@@ -1,4 +0,2 @@ | ||
"use strict"; | ||
module.exports = (kwargs, ctx) => { | ||
export default (kwargs, ctx) => { | ||
if (ctx.rtn === 'context') { | ||
@@ -10,3 +8,2 @@ return { | ||
} | ||
if (ctx.rtn === 'bool') { | ||
@@ -21,3 +18,2 @@ let result = false; | ||
} | ||
if (ctx.rtn === 'count') { | ||
@@ -39,11 +35,9 @@ let result = 0; | ||
} | ||
if (Array.isArray(ctx.rtn)) { | ||
return () => result.push(ctx.rtn.map(rtn => kwargs[rtn])); | ||
return () => result.push(ctx.rtn.map((rtn) => kwargs[rtn])); | ||
} | ||
return () => result.push(kwargs[ctx.rtn]); | ||
})(), | ||
get: () => ctx.abort ? result[0] : result | ||
get: () => (ctx.abort ? result[0] : result) | ||
}; | ||
}; | ||
}; |
@@ -1,20 +0,13 @@ | ||
"use strict"; | ||
import assert from 'assert'; | ||
import { | ||
getWildcard, excludedBy, traversedBy, | ||
hasMatches, matchedBy, isLastLeafMatch, | ||
getValues, getOrder | ||
} from './compiler.js'; | ||
import Result from './find-result.js'; | ||
import { toPath } from '../generic/helper.js'; | ||
const assert = require('assert'); | ||
const formatPath = (input, ctx) => (ctx.joined ? toPath(input) : [...input]); | ||
const compiler = require('./compiler'); | ||
const Result = require('./find-result'); | ||
const { | ||
toPath | ||
} = require('../generic/helper'); | ||
const { | ||
getOrder | ||
} = require('./compiler'); | ||
const formatPath = (input, ctx) => ctx.joined ? toPath(input) : [...input]; | ||
module.exports = (haystack_, searches_, ctx) => { | ||
export default (haystack_, searches_, ctx) => { | ||
const state = { | ||
@@ -24,3 +17,2 @@ haystack: haystack_, | ||
}; | ||
if (ctx.beforeFn !== undefined) { | ||
@@ -30,6 +22,6 @@ const r = ctx.beforeFn(state); | ||
} | ||
const stack = [false, searches_, null, 0]; | ||
const path = []; | ||
const parents = []; | ||
let depth; | ||
@@ -40,93 +32,64 @@ let segment; | ||
let haystack = state.haystack; | ||
const kwargs = { | ||
getKey: () => formatPath(path, ctx), | ||
get key() { | ||
return kwargs.getKey(); | ||
}, | ||
getValue: () => haystack, | ||
get value() { | ||
return kwargs.getValue(); | ||
}, | ||
getEntry: () => [formatPath(path, ctx), haystack], | ||
get entry() { | ||
return kwargs.getEntry(); | ||
}, | ||
getIsMatch: () => isMatch, | ||
get isMatch() { | ||
return kwargs.getIsMatch(); | ||
}, | ||
getMatchedBy: () => compiler.matchedBy(searches), | ||
getMatchedBy: () => matchedBy(searches), | ||
get matchedBy() { | ||
return kwargs.getMatchedBy(); | ||
}, | ||
getExcludedBy: () => compiler.excludedBy(searches), | ||
getExcludedBy: () => excludedBy(searches), | ||
get excludedBy() { | ||
return kwargs.getExcludedBy(); | ||
}, | ||
getTraversedBy: () => compiler.traversedBy(searches), | ||
getTraversedBy: () => traversedBy(searches), | ||
get traversedBy() { | ||
return kwargs.getTraversedBy(); | ||
}, | ||
getGproperty: () => path[path.length - 2], | ||
get gproperty() { | ||
return kwargs.getGproperty(); | ||
}, | ||
getProperty: () => path[path.length - 1], | ||
get property() { | ||
return kwargs.getProperty(); | ||
}, | ||
getGparent: () => parents[parents.length - 2], | ||
get gparent() { | ||
return kwargs.getGparent(); | ||
}, | ||
getParent: () => parents[parents.length - 1], | ||
get parent() { | ||
return kwargs.getParent(); | ||
}, | ||
getParents: () => [...parents].reverse(), | ||
get parents() { | ||
return kwargs.getParents(); | ||
}, | ||
getIsCircular: () => parents.includes(haystack), | ||
get isCircular() { | ||
return kwargs.getIsCircular(); | ||
}, | ||
getIsLeaf: () => !(haystack instanceof Object), | ||
get isLeaf() { | ||
return kwargs.getIsLeaf(); | ||
}, | ||
getDepth: () => path.length, | ||
get depth() { | ||
return kwargs.getDepth(); | ||
}, | ||
/* getResult: <defined-below> */ | ||
@@ -136,7 +99,6 @@ get result() { | ||
}, | ||
context: state.context | ||
}; | ||
const result = Result(kwargs, ctx); | ||
kwargs.getResult = () => result.get(); | ||
@@ -153,4 +115,4 @@ | ||
isMatch = stack.pop(); | ||
const diff = path.length - depth; | ||
for (let idx = 0; idx < diff; idx += 1) { | ||
@@ -160,3 +122,2 @@ parents.pop(); | ||
} | ||
if (diff === -1) { | ||
@@ -176,13 +137,11 @@ parents.push(haystack); | ||
result.onMatch(); | ||
if (ctx.abort) { | ||
stack.length = 0; | ||
} | ||
} // eslint-disable-next-line no-continue | ||
} | ||
// eslint-disable-next-line no-continue | ||
continue; | ||
} | ||
if (!searches.some(s => compiler.hasMatches(s))) { | ||
if (!searches.some((s) => hasMatches(s))) { | ||
// eslint-disable-next-line no-continue | ||
@@ -194,3 +153,3 @@ continue; | ||
if (!autoTraverseArray && compiler.isLastLeafMatch(searches)) { | ||
if (!autoTraverseArray && isLastLeafMatch(searches)) { | ||
stack.push(true, searches, segment, depth); | ||
@@ -200,21 +159,19 @@ isMatch = true; | ||
if ((ctx.breakFn === undefined || ctx.breakFn(kwargs) !== true) && haystack instanceof Object) { | ||
if ( | ||
(ctx.breakFn === undefined || ctx.breakFn(kwargs) !== true) | ||
&& haystack instanceof Object | ||
) { | ||
const isArray = Array.isArray(haystack); | ||
const keys = Object.keys(haystack); | ||
if (!isArray && ctx.compareFn) { | ||
keys.sort(ctx.compareFn(kwargs)); | ||
} | ||
if (!ctx.reverse) { | ||
keys.reverse(); | ||
} | ||
for (let kIdx = 0, kLen = keys.length; kIdx < kLen; kIdx += 1) { | ||
const key = keys[kIdx]; | ||
const searchesOut = []; | ||
if (autoTraverseArray) { | ||
searchesOut.push(...searches); | ||
if (path.length === 0) { | ||
@@ -224,4 +181,4 @@ if ('' in searches[0]) { | ||
} | ||
searchesOut.push(...compiler.getValues(searches[0]).filter(v => compiler.getWildcard(v).isStarRec)); | ||
searchesOut.push(...getValues(searches[0]) | ||
.filter((v) => getWildcard(v).isStarRec)); | ||
} | ||
@@ -231,14 +188,11 @@ } else { | ||
const search = searches[sIdx]; | ||
if (compiler.getWildcard(search).anyMatch(key)) { | ||
if (getWildcard(search).anyMatch(key)) { | ||
searchesOut.push(search); | ||
} | ||
const values = compiler.getValues(search); | ||
let eIdx = values.length; // eslint-disable-next-line no-plusplus | ||
const values = getValues(search); | ||
let eIdx = values.length; | ||
// eslint-disable-next-line no-plusplus | ||
while (eIdx--) { | ||
const value = values[eIdx]; | ||
if (compiler.getWildcard(value).typeMatch(key, isArray)) { | ||
if (getWildcard(value).typeMatch(key, isArray)) { | ||
searchesOut.push(value); | ||
@@ -249,12 +203,9 @@ } | ||
} | ||
if (ctx.orderByNeedles) { | ||
searchesOut.index = Buffer.from(searchesOut.map(e => getOrder(e)).sort()); | ||
searchesOut.index = Buffer.from(searchesOut.map((e) => getOrder(e)).sort()); | ||
let checkIdx = stack.length - 3; | ||
const checkIdxMin = checkIdx - kIdx * 4; | ||
while (checkIdx !== checkIdxMin && Buffer.compare(searchesOut.index, stack[checkIdx].index) === 1) { | ||
checkIdx -= 4; | ||
} | ||
stack.splice(checkIdx + 3, 0, false, searchesOut, isArray ? Number(key) : key, depth + 1); | ||
@@ -269,3 +220,2 @@ } else { | ||
state.result = result.get(); | ||
if (ctx.afterFn !== undefined) { | ||
@@ -275,4 +225,3 @@ const r = ctx.afterFn(state); | ||
} | ||
return state.result; | ||
}; | ||
}; |
@@ -1,40 +0,30 @@ | ||
"use strict"; | ||
import assert from 'assert'; | ||
import { defineProperty } from '../generic/helper.js'; | ||
import { Wildcard } from './wildcard.js'; | ||
const assert = require('assert'); | ||
const { | ||
defineProperty | ||
} = require('../generic/helper'); | ||
const { | ||
Wildcard | ||
} = require('./wildcard'); | ||
const IS_EXCLUDED = Symbol('is-excluded'); | ||
const markExcluded = (input) => defineProperty(input, IS_EXCLUDED, true); | ||
const isExcluded = (input) => input[IS_EXCLUDED] === true; | ||
const markExcluded = input => defineProperty(input, IS_EXCLUDED, true); | ||
const isExcluded = input => input[IS_EXCLUDED] === true; | ||
const throwError = (msg, input, context = {}) => { | ||
throw new Error(Object.entries(context).reduce((p, [k, v]) => `${p}, ${k} ${v}`, `${msg}: ${input}`)); | ||
throw new Error(Object.entries(context) | ||
.reduce((p, [k, v]) => `${p}, ${k} ${v}`, `${msg}: ${input}`)); | ||
}; | ||
const getSimple = arrOrSet => { | ||
const getSimple = (arrOrSet) => { | ||
if (Array.isArray(arrOrSet)) { | ||
return arrOrSet.length === 1 ? arrOrSet[0] : arrOrSet; | ||
} | ||
return arrOrSet.size === 1 ? arrOrSet.values().next().value : arrOrSet; | ||
}; | ||
module.exports = input => { | ||
export default (input) => { | ||
let cResult = new Set(); | ||
let inArray = false; | ||
let excludeNext = false; | ||
let cursor = 0; // group related | ||
let cursor = 0; | ||
// group related | ||
const parentStack = []; | ||
const newChild = asOr => { | ||
const newChild = (asOr) => { | ||
if (isExcluded(cResult)) { | ||
@@ -44,7 +34,5 @@ assert(excludeNext === false); | ||
} | ||
parentStack.push(cResult); | ||
cResult = asOr ? new Set() : []; | ||
}; | ||
const finishChild = () => { | ||
@@ -54,9 +42,7 @@ const parent = parentStack.pop(); | ||
const child = getSimple(cResult); | ||
if (!parentIsArray && child instanceof Set) { | ||
child.forEach(e => parent.add(e)); | ||
child.forEach((e) => parent.add(e)); | ||
} else { | ||
parent[parentIsArray ? 'push' : 'add'](child); | ||
} | ||
cResult = parent; | ||
@@ -66,53 +52,35 @@ }; | ||
newChild(false); | ||
return { | ||
setInArray: (flag, idx) => { | ||
if (inArray === flag) { | ||
throwError(inArray ? 'Bad Array Start' : 'Bad Array Terminator', input, { | ||
char: idx | ||
}); | ||
throwError(inArray ? 'Bad Array Start' : 'Bad Array Terminator', input, { char: idx }); | ||
} | ||
inArray = flag; | ||
}, | ||
finishElement: (idx, { | ||
err, | ||
fins, | ||
finReq = false | ||
}) => { | ||
finishElement: (idx, { err, fins, finReq = false }) => { | ||
const isFinished = cursor === idx; | ||
if (isFinished && !fins.includes(input[idx - 1] || null)) { | ||
throwError(err, input, { | ||
char: idx | ||
}); | ||
throwError(err, input, { char: idx }); | ||
} | ||
if (!isFinished) { | ||
if (finReq) { | ||
throwError(err, input, { | ||
char: idx | ||
}); | ||
throwError(err, input, { char: idx }); | ||
} | ||
const ele = input.slice(cursor, idx); | ||
if (inArray && !(/^[?*+\d]+$/.test(ele) || ele.startsWith('(') && ele.endsWith(')'))) { | ||
throwError('Bad Array Selector', input, { | ||
selector: ele | ||
}); | ||
if (inArray && !( | ||
/^[?*+\d]+$/.test(ele) | ||
|| (ele.startsWith('(') && ele.endsWith(')')) | ||
)) { | ||
throwError('Bad Array Selector', input, { selector: ele }); | ||
} | ||
cResult.push(new Wildcard(inArray ? `[${ele}]` : ele, excludeNext)); | ||
excludeNext = false; | ||
} | ||
cursor = idx + 1; | ||
}, | ||
startExclusion: idx => { | ||
startExclusion: (idx) => { | ||
if (excludeNext !== false) { | ||
throwError('Redundant Exclusion', input, { | ||
char: idx | ||
}); | ||
throwError('Redundant Exclusion', input, { char: idx }); | ||
} | ||
excludeNext = true; | ||
@@ -122,3 +90,2 @@ }, | ||
newChild(true); | ||
if (excludeNext) { | ||
@@ -128,3 +95,2 @@ markExcluded(cResult); | ||
} | ||
newChild(false); | ||
@@ -136,9 +102,6 @@ }, | ||
}, | ||
finishGroup: idx => { | ||
finishGroup: (idx) => { | ||
if (parentStack.length < 2) { | ||
throwError('Unexpected Group Terminator', input, { | ||
char: idx | ||
}); | ||
throwError('Unexpected Group Terminator', input, { char: idx }); | ||
} | ||
finishChild(); | ||
@@ -150,14 +113,11 @@ finishChild(); | ||
assert(excludeNext === false); | ||
if (parentStack.length !== 0) { | ||
throwError('Non Terminated Group', input); | ||
} | ||
if (inArray) { | ||
throwError('Non Terminated Array', input); | ||
} | ||
return getSimple(cResult); | ||
} | ||
}; | ||
}; | ||
}; |
@@ -1,14 +0,10 @@ | ||
"use strict"; | ||
import { Wildcard } from './wildcard.js'; | ||
import Result from './parser-result.js'; | ||
const { | ||
Wildcard | ||
} = require('./wildcard'); | ||
const Result = require('./parser-result'); | ||
const throwError = (msg, input, context = {}) => { | ||
throw new Error(Object.entries(context).reduce((p, [k, v]) => `${p}, ${k} ${v}`, `${msg}: ${input}`)); | ||
throw new Error(Object.entries(context) | ||
.reduce((p, [k, v]) => `${p}, ${k} ${v}`, `${msg}: ${input}`)); | ||
}; | ||
module.exports.parse = (input, ctx) => { | ||
const parse = (input, ctx) => { | ||
if (input === '') { | ||
@@ -25,68 +21,34 @@ return new Wildcard('', false); | ||
const char = input[idx]; | ||
if (escaped === false && bracketDepth === 0) { | ||
switch (char) { | ||
case '.': | ||
result.finishElement(idx, { | ||
err: 'Bad Path Separator', | ||
fins: [']', '}'] | ||
}); | ||
result.finishElement(idx, { err: 'Bad Path Separator', fins: [']', '}'] }); | ||
break; | ||
case '[': | ||
if (!ctx.useArraySelector) { | ||
throwError('Forbidden Array Selector', input, { | ||
char: idx | ||
}); | ||
throwError('Forbidden Array Selector', input, { char: idx }); | ||
} | ||
result.finishElement(idx, { | ||
err: 'Bad Array Start', | ||
fins: [null, '!', '{', ',', '}', ']'] | ||
}); | ||
result.finishElement(idx, { err: 'Bad Array Start', fins: [null, '!', '{', ',', '}', ']'] }); | ||
result.setInArray(true, idx); | ||
break; | ||
case ']': | ||
result.finishElement(idx, { | ||
err: 'Bad Array Terminator', | ||
fins: ['}'] | ||
}); | ||
result.finishElement(idx, { err: 'Bad Array Terminator', fins: ['}'] }); | ||
result.setInArray(false, idx); | ||
break; | ||
case '{': | ||
result.finishElement(idx, { | ||
err: 'Bad Group Start', | ||
fins: [null, '!', '.', '[', '{', ','], | ||
finReq: true | ||
}); | ||
result.finishElement(idx, { err: 'Bad Group Start', fins: [null, '!', '.', '[', '{', ','], finReq: true }); | ||
result.startGroup(); | ||
break; | ||
case ',': | ||
result.finishElement(idx, { | ||
err: 'Bad Group Separator', | ||
fins: [']', '}'] | ||
}); | ||
result.finishElement(idx, { err: 'Bad Group Separator', fins: [']', '}'] }); | ||
result.newGroupElement(); | ||
break; | ||
case '}': | ||
result.finishElement(idx, { | ||
err: 'Bad Group Terminator', | ||
fins: [']', '}'] | ||
}); | ||
result.finishElement(idx, { err: 'Bad Group Terminator', fins: [']', '}'] }); | ||
result.finishGroup(idx); | ||
break; | ||
case '!': | ||
result.finishElement(idx, { | ||
err: 'Bad Exclusion', | ||
fins: [null, '.', ',', '{', '['], | ||
finReq: true | ||
}); | ||
result.finishElement(idx, { err: 'Bad Exclusion', fins: [null, '.', ',', '{', '['], finReq: true }); | ||
result.startExclusion(idx); | ||
break; | ||
default: | ||
@@ -96,3 +58,2 @@ break; | ||
} | ||
if (escaped === false) { | ||
@@ -103,13 +64,8 @@ switch (char) { | ||
break; | ||
case ')': | ||
if (bracketDepth === 0) { | ||
throwError('Unexpected Parentheses', input, { | ||
char: idx | ||
}); | ||
throwError('Unexpected Parentheses', input, { char: idx }); | ||
} | ||
bracketDepth -= 1; | ||
break; | ||
default: | ||
@@ -119,3 +75,2 @@ break; | ||
} | ||
escaped = char === '\\' ? !escaped : false; | ||
@@ -125,7 +80,4 @@ } | ||
if (escaped !== false) { | ||
throwError('Dangling Escape', input, { | ||
char: inputLength - 1 | ||
}); | ||
throwError('Dangling Escape', input, { char: inputLength - 1 }); | ||
} | ||
if (bracketDepth !== 0) { | ||
@@ -135,7 +87,5 @@ throwError('Unterminated Parentheses', input); | ||
result.finishElement(inputLength, { | ||
err: 'Bad Terminator', | ||
fins: [']', '}'] | ||
}); | ||
result.finishElement(inputLength, { err: 'Bad Terminator', fins: [']', '}'] }); | ||
return result.finalizeResult(); | ||
}; | ||
}; | ||
export default { parse }; |
@@ -1,15 +0,8 @@ | ||
"use strict"; | ||
import { escapeRegex, asRegex } from '../generic/helper.js'; | ||
const { | ||
escapeRegex, | ||
asRegex | ||
} = require('../generic/helper'); | ||
const parseWildcard = str => { | ||
export const parseWildcard = (str) => { | ||
let regex = ''; | ||
let escaped = false; | ||
for (let idx = 0; idx < str.length; idx += 1) { | ||
const char = str[idx]; | ||
if (!escaped && char === '\\') { | ||
@@ -28,33 +21,25 @@ escaped = true; | ||
} | ||
return new RegExp(`^${regex}$`); | ||
}; | ||
module.exports.parseWildcard = parseWildcard; | ||
const compileWildcard = str => { | ||
const compileWildcard = (str) => { | ||
if (['**', '++'].includes(str)) { | ||
return asRegex('.*'); | ||
} | ||
if ((str.startsWith('**(') || str.startsWith('++(')) && str.endsWith(')')) { | ||
return asRegex(str.slice(3, -1)); | ||
} | ||
if (str.startsWith('[(') && str.endsWith(')]')) { | ||
return asRegex(str.slice(2, -2)); | ||
} | ||
if (str.startsWith('(') && str.endsWith(')')) { | ||
return asRegex(str.slice(1, -1)); | ||
} | ||
if (str.startsWith('[') && str.endsWith(']')) { | ||
return parseWildcard(str.slice(1, -1)); | ||
} | ||
return parseWildcard(str); | ||
}; | ||
class Wildcard { | ||
export class Wildcard { | ||
constructor(value, excluded) { | ||
@@ -82,7 +67,5 @@ this.value = value; | ||
} | ||
if (this.isSimpleRec) { | ||
return true; | ||
} | ||
return this.regex.test(key); | ||
@@ -95,20 +78,16 @@ } | ||
} | ||
if (isArray && this.isAnyArrayTarget) { | ||
return true; | ||
} | ||
if (!isArray && this.isAnyObjTarget) { | ||
return true; | ||
} | ||
if (isArray !== this.isArrayTarget && !this.isRec) { | ||
if ( | ||
isArray !== this.isArrayTarget | ||
&& !this.isRec | ||
) { | ||
return false; | ||
} | ||
return this.regex.test(key); | ||
} | ||
} | ||
module.exports.Wildcard = Wildcard; |
@@ -1,17 +0,10 @@ | ||
"use strict"; | ||
export const defineProperty = (target, k, v, readonly = true) => Object | ||
.defineProperty(target, k, { value: v, writable: !readonly }); | ||
module.exports.defineProperty = (target, k, v, readonly = true) => Object.defineProperty(target, k, { | ||
value: v, | ||
writable: !readonly | ||
}); | ||
const specialChars = /[?!,.*+[\](){}\\]/g; | ||
export const escape = (input) => input.replace(specialChars, '\\$&'); | ||
const escape = input => input.replace(specialChars, '\\$&'); | ||
export const escapeRegex = (char) => char.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); | ||
module.exports.escape = escape; | ||
module.exports.escapeRegex = char => char.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); | ||
module.exports.asRegex = regexStr => { | ||
export const asRegex = (regexStr) => { | ||
try { | ||
@@ -24,2 +17,3 @@ return new RegExp(regexStr); | ||
module.exports.toPath = input => input.reduce((p, c) => `${p}${typeof c === 'number' ? `[${c}]` : `${p ? '.' : ''}${escape(c)}`}`, ''); | ||
export const toPath = (input) => input | ||
.reduce((p, c) => `${p}${typeof c === 'number' ? `[${c}]` : `${p ? '.' : ''}${escape(c)}`}`, ''); |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
const iterate = (tree, cb) => { | ||
@@ -14,3 +12,2 @@ const stack = [tree]; | ||
const e = stack[idx]; | ||
if (e instanceof Set) { | ||
@@ -23,3 +20,2 @@ stack[idx] = [...e]; | ||
parent.splice(idx, 1, ...new Array(e.length).fill(parent[idx])); | ||
if (parent[idx] !== null) { | ||
@@ -53,3 +49,2 @@ depth[parent[idx]] += e.length - 1; | ||
cb('ADD', e); | ||
if (idx === stack.length - 1) { | ||
@@ -67,3 +62,2 @@ cb('FIN', path); | ||
}; | ||
module.exports.iterate = iterate; | ||
export default { iterate }; |
@@ -1,7 +0,6 @@ | ||
"use strict"; | ||
module.exports.traverse = (obj, cb) => { | ||
const traverse = (obj, cb) => { | ||
const stack = [obj]; | ||
const counts = [1]; | ||
let depth = 0; | ||
let inc = true; | ||
@@ -13,4 +12,4 @@ | ||
cb('ENTER', cur, depth); | ||
const values = Object.values(cur); | ||
if (values.length !== 0) { | ||
@@ -27,3 +26,2 @@ stack.push(...values); | ||
counts[depth] -= 1; | ||
if (counts[depth] === 0) { | ||
@@ -37,2 +35,3 @@ counts.pop(); | ||
} | ||
}; | ||
}; | ||
export default { traverse }; |
@@ -1,22 +0,15 @@ | ||
"use strict"; | ||
import assert from 'assert'; | ||
import { compile } from './core/compiler.js'; | ||
import find from './core/find.js'; | ||
import Context from './core/context.js'; | ||
const assert = require('assert'); | ||
const compiler = require('./core/compiler'); | ||
const find = require('./core/find'); | ||
const Context = require('./core/context'); | ||
module.exports = (needles, opts = {}) => { | ||
export default (needles, opts = {}) => { | ||
assert(Array.isArray(needles)); | ||
assert(opts instanceof Object && !Array.isArray(opts)); | ||
if (needles.length === 0) { | ||
return (_, ctx) => ctx === undefined ? [] : ctx; | ||
return (_, ctx) => (ctx === undefined ? [] : ctx); | ||
} | ||
const ctx = Context(opts); | ||
const search = compiler.compile(needles, ctx); // keep separate for performance | ||
const search = compile(needles, ctx); // keep separate for performance | ||
return (haystack, context) => find(haystack, [search], { | ||
@@ -27,2 +20,2 @@ context, | ||
}); | ||
}; | ||
}; |
{ | ||
"name": "object-scan", | ||
"version": "17.1.0", | ||
"type": "module", | ||
"version": "18.0.0", | ||
"description": "Traverse object hierarchies using matching and callbacks.", | ||
@@ -8,9 +9,9 @@ "main": "lib/index.js", | ||
"clean": "rm -rf lib", | ||
"build": "npx babel src --out-dir lib --copy-files --include-dotfiles --config-file ./.babelrc", | ||
"build": "cp -rf ./src ./lib", | ||
"build-clean": "yarn run clean && yarn run build", | ||
"test-simple": "nyc mocha \"./test/**/*.spec.js\"", | ||
"test-simple": "c8 mocha \"./test/**/*.spec.js\"", | ||
"test": "yarn run clean && yarn run gardener && yarn run test-simple", | ||
"coveralls": "node ./node_modules/coveralls/bin/coveralls.js < ./coverage/lcov.info", | ||
"semantic-release": "yarn run build-clean && npx semantic-release", | ||
"gardener": "node gardener", | ||
"gardener": "node gardener.js", | ||
"docker": "docker run --net host -u`id -u`:`id -g` -v $(pwd):/user/project -v ~/.aws:/user/.aws -v ~/.npmrc:/user/.npmrc -w /user/project -it --entrypoint /bin/bash", | ||
@@ -51,64 +52,29 @@ "t": "yarn test", | ||
"devDependencies": { | ||
"@babel/cli": "7.14.8", | ||
"@babel/core": "7.15.0", | ||
"@babel/register": "7.15.3", | ||
"@blackflux/eslint-plugin-rules": "2.0.3", | ||
"@blackflux/robo-config-plugin": "5.3.0", | ||
"babel-eslint": "10.1.0", | ||
"babel-preset-latest-node": "5.5.1", | ||
"@babel/core": "7.17.2", | ||
"@babel/eslint-parser": "7.17.0", | ||
"@babel/register": "7.17.0", | ||
"@blackflux/eslint-plugin-rules": "2.1.0", | ||
"@blackflux/robo-config-plugin": "7.0.2", | ||
"c8": "7.11.0", | ||
"chai": "4.3.4", | ||
"coveralls": "3.1.1", | ||
"diff": "5.0.0", | ||
"diff2html": "3.4.10", | ||
"eslint": "7.32.0", | ||
"eslint-config-airbnb-base": "14.2.1", | ||
"eslint-plugin-import": "2.24.2", | ||
"diff2html": "3.4.14", | ||
"eslint": "8.7.0", | ||
"eslint-config-airbnb-base": "15.0.0", | ||
"eslint-plugin-import": "2.25.4", | ||
"eslint-plugin-json": "3.1.0", | ||
"eslint-plugin-markdown": "2.2.0", | ||
"eslint-plugin-mocha": "9.0.0", | ||
"joi-strict": "2.0.0", | ||
"js-gardener": "3.0.3", | ||
"eslint-plugin-markdown": "2.2.1", | ||
"eslint-plugin-mocha": "10.0.3", | ||
"joi-strict": "2.0.1", | ||
"js-gardener": "3.0.5", | ||
"json-stringify-pretty-compact": "3.0.0", | ||
"lodash.isequal": "4.5.0", | ||
"mustache": "4.2.0", | ||
"node-tdd": "3.0.4", | ||
"nyc": "15.1.0", | ||
"object-scan": "17.0.0", | ||
"semantic-release": "17.4.7", | ||
"smart-fs": "2.0.2", | ||
"node-tdd": "3.3.1", | ||
"object-scan": "17.1.0", | ||
"smart-fs": "2.0.3", | ||
"stringify-object": "3.3.0", | ||
"uuid": "8.3.2" | ||
}, | ||
"nyc": { | ||
"tempDir": "./coverage/.nyc_output", | ||
"report-dir": "./coverage", | ||
"check-coverage": true, | ||
"per-file": false, | ||
"lines": 100, | ||
"statements": 100, | ||
"functions": 100, | ||
"branches": 100, | ||
"include": [ | ||
"**/*.js" | ||
], | ||
"reporter": [ | ||
"lcov", | ||
"text-summary" | ||
], | ||
"require": [ | ||
"@babel/register" | ||
], | ||
"extension": [], | ||
"cache": true, | ||
"all": true, | ||
"babel": true, | ||
"exclude": [ | ||
"gardener.js", | ||
"node_modules/*", | ||
"coverage/*", | ||
"lib/*", | ||
"test/regression-test.js", | ||
"test/worker.js" | ||
] | ||
}, | ||
"licenses": [ | ||
@@ -121,3 +87,3 @@ { | ||
"engines": { | ||
"node": ">= 12" | ||
"node": ">= 14" | ||
}, | ||
@@ -124,0 +90,0 @@ "files": [ |
@@ -24,3 +24,3 @@ # Object-Scan | ||
```js | ||
const objectScan = require('object-scan'); | ||
import objectScan from 'object-scan'; | ||
@@ -27,0 +27,0 @@ const haystack = { a: { b: { c: 'd' }, e: { f: 'g' } } }; |
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
26
Yes
62737
864