New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

breadth-filter

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

breadth-filter - npm Package Compare versions

Comparing version 1.2.0 to 2.0.0

.travis.yml

37

index.js
const entries = require('object.entries')
function targetFor (source, destructive) {
function defaultOnArray () { return [] }
function defaultOnObject () { return {} }
function targetFor (source, key, fieldPath, isNew, {
onArray = defaultOnArray,
onObject = defaultOnObject
} = {}) {
if (Array.isArray(source)) {
return destructive ? source : []
} else if (typeof source === 'object') {
return destructive ? source : {}
return onArray(source, key, fieldPath, isNew)
} else if (source !== null && typeof source === 'object') {
return onObject(source, key, fieldPath, isNew)
}
}
module.exports = function breadthFilter (root, fn, destructive) {
const target = targetFor(root, destructive)
module.exports = function breadthFilter (root, opts = {}) {
const { onValue } = opts
const target = targetFor(root, null, [], true, opts)
if (!target) return root
const queue = [[ root, target, [] ]]
const seen = new Set()
const seen = new Set([ root ])
let item

@@ -23,13 +30,13 @@

const fieldPath = path.concat(key)
const newTarget = targetFor(value, destructive)
const isNew = !seen.has(value)
if (isNew) seen.add(value)
const newTarget = targetFor(value, key, fieldPath, isNew, opts)
if (newTarget) {
if (!seen.has(value)) {
seen.add(value)
} else {
continue
target[key] = newTarget
if (isNew) {
queue.push([ value, target[key], fieldPath ])
}
target[key] = newTarget
queue.push([ value, target[key], fieldPath ])
} else {
target[key] = fn(value, key, fieldPath)
target[key] = onValue(value, key, fieldPath)
}

@@ -36,0 +43,0 @@ }

{
"name": "breadth-filter",
"version": "1.2.0",
"version": "2.0.0",
"description": "Breadth-first deep object filter",

@@ -5,0 +5,0 @@ "author": "Stephen Belanger <admin@stephenbelanger.com> (https://github.com/qard)",

# breadth-filter
Apply a deep object filter via breadth traversal.
[![Greenkeeper badge](https://badges.greenkeeper.io/Qard/breadth-filter.svg)](https://greenkeeper.io/)
Apply a deep object filter via breadth traversal. It allows replacing values, including retargeting objects and arrays and even detecting circular references to allow the user to decide how to handle the circle. Note that the filter will _not_ descend _into_ circular objects but will only _reach_ them.
## Install

@@ -16,3 +18,3 @@

const filtered = breadthFilter({
const data = {
user: {

@@ -22,3 +24,5 @@ name: 'someone',

}
}, (value, key, path) => {
}
function onValue (value, key, path) {
if (key === 'password') {

@@ -29,8 +33,71 @@ console.log('redacted field at', path.join('.'))

return value
}
// build a new filtered object...
const filtered = breadthFilter(data, {
onValue
})
// or, mutate in-place and break cycles...
breadthFilter(data, {
onValue,
onObject (value, key, path, isNew) {
return isNew ? value : '[Circular]'
},
onArray (value, key, path, isNew) {
return isNew ? value : '[Circular]'
}
})
```
## Options
### onValue(value, key, path)
This function handles primitive value types such as numbers or strings. It can be used to filter things like sensitive data such as passwords or credit card numbers.
Arguments:
* `value` - any
The encountered value to filter.
* `key` - string | number
The property key of the encountered value, at the current depth level. Will be `null` when encountering the root object.
* `path` - array<string>
Any array of all property keys leading from the root to this encountered value.
### onObject(value, key, path, isNew)
This handles encountered objects. It can be used to filter entire objects out of the result, by returning `undefined`, it can enable in-place mutation by return the value directly, and the `isNew` property can be used to identify and break out of circular references, replacing them with something else such as `'[Circular]'`.
Arguments:
* `value` - any
The encountered value to filter.
* `key` - string | number
The property key of the encountered value, at the current depth level. Will be `null` when encountering the root object.
* `path` - array<string>
Any array of all property keys leading from the root to this encountered value.
* `isNew` - boolean
Indicates if this is the first time encountering this value, a false value indicates a circular reference.
### onArray(value, key, path, isNew)
This handles encountered arrays. It can be used to filter entire arrays out of the result, by returning `undefined`, it can enable in-place mutation by return the value directly, and the `isNew` property can be used to identify and break out of circular references, replacing them with something else such as `'[Circular]'`.
Arguments:
* `value` - any
The encountered value to filter.
* `key` - string | number
The property key of the encountered value, at the current depth level. Will be `null` when encountering the root object.
* `path` - array<string>
Any array of all property keys leading from the root to this encountered value.
* `isNew` - boolean
Indicates if this is the first time encountering this value, a false value indicates a circular reference.
---
### Copyright (c) 2018 Stephen Belanger
### Copyright (c) 2019 Stephen Belanger
#### Licensed under MIT License

@@ -37,0 +104,0 @@

@@ -9,2 +9,6 @@ const tap = require('tap')

function identity (input) {
return input
}
function whenKeyMatches (expected, fn) {

@@ -22,2 +26,10 @@ return (value, key) => {

// Mutation handlers
function onObject (source) {
return source
}
function onArray (source) {
return source
}
tap.test('basic value mapping', (t) => {

@@ -33,3 +45,5 @@ const input = {

const output = breadthFilter(input, reverse)
const output = breadthFilter(input, {
onValue: reverse
})

@@ -62,3 +76,5 @@ const expected = {

const output = breadthFilter(input, whenKeyMatches('bar', reverse))
const output = breadthFilter(input, {
onValue: whenKeyMatches('bar', reverse)
})

@@ -91,3 +107,5 @@ const expected = {

const output = breadthFilter(input, whenPathMatches('foo.bar.baz', reverse))
const output = breadthFilter(input, {
onValue: whenPathMatches('foo.bar.baz', reverse)
})

@@ -115,3 +133,5 @@ const expected = {

const output = breadthFilter(input, whenPathMatches('foo.0.bar', reverse))
const output = breadthFilter(input, {
onValue: whenPathMatches('foo.0.bar', reverse)
})

@@ -139,3 +159,5 @@ const expected = {

breadthFilter(input, reverse)
breadthFilter(input, {
onValue: reverse
})

@@ -161,7 +183,11 @@ const expected = {

},
bux: 'bax'
bux: ['bax']
}
}
breadthFilter(input, reverse, true)
breadthFilter(input, {
onValue: reverse,
onObject,
onArray
})

@@ -173,3 +199,3 @@ const expected = {

},
bux: 'xab'
bux: ['xab']
}

@@ -193,5 +219,12 @@ }

// Form a circular reference
input.foo.input = input
input.foo.foo = input.foo
input.foo.bar.root = input
breadthFilter(input, reverse, true)
const output = breadthFilter(input, {
onValue: reverse,
onArray,
onObject(source, key, path, isNew) {
return isNew ? {} : '[Circular]'
}
})

@@ -201,13 +234,42 @@ const expected = {

bar: {
baz: 'zub'
baz: 'zub',
root: '[Circular]'
},
bux: 'xab'
bux: 'xab',
foo: '[Circular]'
}
}
// The expectation also needs a circular reference
expected.foo.input = expected
t.deepEqual(output, expected, 'matches expected output')
t.end()
})
tap.test('supports null and undefined values', (t) => {
const input = {
foo: {
bar: {
baz: null
},
bux: undefined
}
}
breadthFilter(input, {
onValue: identity,
onObject,
onArray
})
const expected = {
foo: {
bar: {
baz: null
},
bux: undefined
}
}
t.deepEqual(input, expected, 'matches expected output')
t.end()
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc