### Install object-scan Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/README.md Install the object-scan package using npm. ```bash npm install object-scan ``` -------------------------------- ### beforeFn: Pre-process Haystack Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md This beforeFn example demonstrates pre-processing the haystack by extracting its keys. ```javascript haystack: { a: 0, b: 1 } needles: ['**'] comment: pre-processing haystack beforeFn: ({ haystack: h }) => Object.keys(h) rtn: ['key', 'value'] ``` -------------------------------- ### Basic Object-Scan Usage Example Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md A simple example demonstrating how to use object-scan with a haystack, needles, and spoiler option. ```javascript haystack: { a: { b: { c: 'd' }, e: { f: 'g' } } } needles: ['a.*.f'] spoiler: false ``` -------------------------------- ### Scanner Function Usage Examples Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/api-reference/objectscan.md Examples demonstrating how to use the scanner function returned by `objectScan`. ```APIDOC ### Basic matching ```javascript import objectScan from 'object-scan'; const haystack = { a: { b: { c: 'd' }, e: { f: 'g' } } }; const scanner = objectScan(['a.*.f'], { joined: true }); scanner(haystack); // => [ 'a.e.f' ] ``` ### Array needles Array needles match object properties and array indices without requiring escaping: ```javascript const haystack = { 'a.b': [0], a: { b: [1] } }; const scanner = objectScan([['a.b', 0]], { joined: true, rtn: 'value' }); scanner(haystack); // => [ 0 ] // matches 'a.b'[0], not a.b[0] ``` ### With context ```javascript const haystack = { a: { b: { c: 2, d: 11 }, e: 7 } }; const scanner = objectScan(['**.{c,d,e}'], { joined: true, filterFn: ({ value, context }) => { context.sum += value; } }); const result = scanner(haystack, { sum: 0 }); // => { sum: 20 } ``` ### Return value types ```javascript const haystack = { a: 0, b: 1, c: 2 }; const scanner = objectScan(['**'], { rtn: 'value' }); scanner(haystack); // => [ 2, 1, 0 ] // values instead of keys ``` ### Custom function return ```javascript const haystack = { a: 0, b: 1, c: 2 }; const scanner = objectScan(['**'], { rtn: ({ key, value }) => `${key}=${value}` }); scanner(haystack); // => [ 'c=2', 'b=1', 'a=0' ] ``` ``` -------------------------------- ### Joined Option Example Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Demonstrates the 'joined' option set to true, returning keys as strings. This can impact performance. ```javascript haystack: [0, 1, { foo: 'bar' }] needles: ['[*]', '[*].foo'] joined: true comment: joined ``` -------------------------------- ### Wildcard Matching Examples Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Illustrates wildcard usage for matching strings in paths. Supports '*', '+', and '?' for various matching patterns. ```javascript haystack: { foo: 0, foobar: 1, bar: 2 } needles: ['foo*'] comment: starting with `foo` ``` ```javascript haystack: { a: { b: 0, c: 1 }, d: 2 } needles: ['*'] comment: top level ``` ```javascript haystack: [...Array(30).keys()] needles: ['[?5]'] comment: two digit ending in five ``` ```javascript haystack: { a: { b: { c: 0 }, d: { f: 0 } } } needles: ['a.+.c'] comment: nested ``` ```javascript haystack: { a: { b: { c: 0 }, '+': { c: 0 } } } needles: ['a.\+.c'] comment: escaped ``` -------------------------------- ### Nested Path Recursion (Zero or More) Source: https://github.com/blackflux/object-scan/blob/master/README.md Use '**.{...}' to recursively match paths within an Or Clause zero or more times. This example selects nested 'b.c' paths starting from 'a'. ```javascript const haystack = { a: { b: { c: { b: { c: 0 } } } } }; objectScan(['a.**{b.c}'], { joined: true })(haystack); // => [ 'a.b.c.b.c', 'a.b.c', 'a' ] ``` -------------------------------- ### Not Joined Option Example Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Demonstrates the 'joined' option set to false, returning keys as lists. This is the default behavior. ```javascript haystack: [0, 1, { foo: 'bar' }] needles: ['[*]', '[*].foo'] joined: false comment: not joined ``` -------------------------------- ### afterFn: Pass Data from beforeFn to afterFn Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md This example shows how to pass data from beforeFn to afterFn by modifying the state object. ```javascript haystack: {} needles: ['**'] comment: pass data from beforeFn to afterFn beforeFn: (state) => { /* eslint-disable no-param-reassign */ state.custom = 7; } afterFn: (state) => state.custom joined: false ``` -------------------------------- ### Regex Matching Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Apply regular expressions within parentheses to match keys based on a pattern. This example finds keys whose names start with 'b' or 'c'. ```json needles: ['**.(^[bc]$)'] comment: regex matching ``` -------------------------------- ### Leaf Detection Example Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/traversal-order.md Illustrates how object-scan identifies leaf nodes (primitives and null) using the `isLeaf` flag in `filterFn`. The example logs the key and value of each leaf node found. ```javascript const haystack = { a: 1, b: { c: 2 } }; objectScan(['**'], { filterFn: ({ key, isLeaf, value, context }) => { if (isLeaf) context.push(`${key}=${value}`); } })(haystack, []); // Output: [ 'a=1', 'b.c=2' ] // Only primitives marked as leaves ``` -------------------------------- ### Example JSON with Metadata Source: https://github.com/blackflux/object-scan/blob/master/test/helper.spec/create-html-diff.spec.js__fixtures/example-with-meta.html A sample JSON object containing boolean and nested data structures. ```json { "bool": true, "data": { "value": 1 } } ``` -------------------------------- ### Examples of Arbitrary Depth Matching Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/needle-syntax.md Demonstrates practical applications of '**' and '++' wildcards for finding keys at any depth, specific named properties, and nested objects. ```javascript // Find all keys at any depth objectScan(['**'])(haystack) ``` ```javascript // Find all properties named 'id' at any depth objectScan(['**.id'])(haystack) ``` ```javascript // Find all nested objects (at least 1 level deep) objectScan(['a.++'])(haystack) ``` -------------------------------- ### Example of Escaping Special Characters Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/needle-syntax.md Provides a practical example demonstrating how to match object keys that contain special characters by escaping them within the needle patterns. ```javascript const haystack = { 'a.b': { value: 1 }, // key contains dot '[0]': { value: 2 }, // key contains brackets 'foo?bar': { value: 3 } // key contains question mark }; objectScan(['a\.b', '\[0\]', 'foo\?bar'])(haystack); // Matches all three literal keys ``` -------------------------------- ### Nested Path Recursion (One or More) Source: https://github.com/blackflux/object-scan/blob/master/README.md Use '++.{...}' to recursively match paths within an Or Clause one or more times. This example selects nested 'b.c' paths starting from 'a', excluding 'a' itself. ```javascript const haystack = { a: { b: { c: { b: { c: 0 } } } } }; objectScan(['a.++{b.c}'], { joined: true })(haystack); // => [ 'a.b.c.b.c', 'a.b.c' ] ``` -------------------------------- ### Search Context Example Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Demonstrates how to use a search context object to accumulate state across callbacks. The context is passed to the filterFn and can be modified within it. ```javascript haystack: { a: { b: { c: 2, d: 11 }, e: 7 } } needles: ['**.{c,d,e}'] context: { sum: 0 } filterFn: ({ value, context }) => { context.sum += value; } ``` -------------------------------- ### Arbitrary Depth Matching (Any Level) Source: https://github.com/blackflux/object-scan/blob/master/README.md Use '**' to match any key or index at any level of nesting. This example finds all paths containing the number '1'. ```javascript const haystack = { 1: { 1: ['c', 'd'] }, 510: 'e', foo: { 1: 'f' } }; objectScan(['**(1)'], { joined: true })(haystack); // => [ '510', '1.1[1]', '1.1', '1' ] ``` -------------------------------- ### Or Clause Matching Examples Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Shows how to use curly braces for 'OR' conditions in path matching, allowing multiple specific array indices or object properties. ```javascript haystack: ['a', 'b', 'c', 'd'] needles: ['[{0,1}]'] comment: `[0]` and `[1]` ``` ```javascript haystack: { a: { b: 0, c: 1 }, d: { e: 2, f: 3 } } needles: ['{a,d}.{b,f}'] comment: `a.b`, `a.f`, `d.b` and `d.f` ``` -------------------------------- ### Validation Error Examples Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/types.md Shows examples of validation error messages for invalid options passed to object-scan. ```text Option "filterFn" not one of [function, undefined] ``` ```text Option "rtn" is malformed ``` ```text Redundant Needle Target: "a" vs "a" ``` ```text Redundant Recursion: "a.**" ``` ```text Needle Target Invalidated: "a" by "a.**" ``` ```text Unexpected Option provided ``` -------------------------------- ### Wildcard Matching 'foo*' in objectScan Source: https://github.com/blackflux/object-scan/blob/master/README.md Use the '*' wildcard to match zero or more characters. This example matches properties starting with 'foo'. ```javascript const haystack = { foo: 0, foobar: 1, bar: 2 }; objectScan(['foo*'], { joined: true })(haystack); // => [ 'foobar', 'foo' ] ``` -------------------------------- ### Arbitrary Depth Matching (One or More) Source: https://github.com/blackflux/object-scan/blob/master/README.md Use '++' to match one or more levels of nesting under a specified path. This example selects all properties under 'a', excluding 'a' itself. ```javascript const haystack = { a: { b: 0, c: 0 } }; objectScan(['a.++'], { joined: true })(haystack); // => [ 'a.c', 'a.b' ] ``` -------------------------------- ### Syntax Error Examples Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/types.md Illustrates various syntax error messages that can be thrown when parsing invalid needle syntax. ```text Bad Path Separator: ... ``` ```text Bad Array Start: ... ``` ```text Bad Array Terminator: ... ``` ```text Bad Group Start: ... ``` ```text Bad Group Separator: ... ``` ```text Bad Group Terminator: ... ``` ```text Bad Exclusion: ... ``` ```text Unexpected Parentheses: ... ``` ```text Unterminated Parentheses: ... ``` ```text Dangling Escape: ... ``` ```text Bad Terminator: ... ``` ```text Invalid Regex: "(malformed)" ``` ```text Forbidden Array Selector: ... ``` -------------------------------- ### Break Function Example Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Shows how to use a breakFn to skip traversal of nested keys. If the breakFn returns true for a key, all its children are ignored. ```javascript haystack: { a: { b: { c: 0 } } } needles: ['**'] breakFn: ({ key }) => key === 'a.b' ``` -------------------------------- ### Object Scan: Joined Option Example Source: https://github.com/blackflux/object-scan/blob/master/README.md Demonstrates the 'joined' option, which returns keys as strings instead of lists. Setting this to true can impact performance and can be overwritten by getKey() or getEntry(). ```javascript const haystack = [0, 1, { foo: 'bar' }]; objectScan(['[*]', '[*].foo'], { joined: true })(haystack); // => [ '[2].foo', '[2]', '[1]', '[0]' ] ``` ```javascript const haystack = [0, 1, { foo: 'bar' }]; objectScan(['[*]', '[*].foo'])(haystack); // => [ [ 2, 'foo' ], [ 2 ], [ 1 ], [ 0 ] ] ``` -------------------------------- ### String Needle Syntax Example Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/types.md Illustrates the syntax for string needles, which use a specific pattern matching language for object properties, array indices, wildcards, regex, and more. ```string path.segment[0].(regex).*wildcard ``` -------------------------------- ### Redundant Needle Error Example Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/errors.md This example demonstrates a 'Redundant Needle Target' error, indicating that two needles are matching the exact same path, which is unnecessary. ```text Redundant Needle Target: "a.b.c" vs "a.b.c" ``` -------------------------------- ### afterFn: Post-process Result Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md This afterFn example demonstrates post-processing the result by filtering values greater than 3. ```javascript haystack: { a: 0, b: 3, c: 4 } needles: ['**'] comment: post-processing result afterFn: ({ result }) => result.filter((v) => v > 3) rtn: 'value' joined: false ``` -------------------------------- ### Examples of Nested Path Recursion Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/needle-syntax.md Illustrates matching nested structures like JSON trees, repeating path patterns, and recursively traversing objects or arrays. ```javascript // Match nested structure like JSON trees objectScan(['**{[0]}'])(haystack) // Matches [0], [0][0], [0][0][0], etc. ``` ```javascript // Match repeating path patterns const haystack = { a: { b: { c: { b: { c: 0 } } } } }; objectScan(['a.++{b.c}'])(haystack) // => [ 'a.b.c.b.c', 'a.b.c' ] ``` ```javascript // Match all keys at any depth (objects only) objectScan(['**{*}'])(haystack) // Traverses object properties recursively ``` ```javascript // Match all indices at any depth (arrays only) objectScan(['**{[*]}'])(haystack) // Traverses array elements recursively ``` -------------------------------- ### afterFn: Pass Data from beforeFn Source: https://github.com/blackflux/object-scan/blob/master/README.md Data added to the state in beforeFn is available in afterFn. This example adds a custom property in beforeFn and accesses it in afterFn. ```javascript const haystack = {}; objectScan(['**'], { beforeFn: (state) => { /* eslint-disable no-param-reassign */ state.custom = 7; }, afterFn: (state) => state.custom })(haystack); // => 7 ``` -------------------------------- ### Order by Needle Source: https://github.com/blackflux/object-scan/blob/master/README.md When orderByNeedles is true, keys are traversed and matched in the order determined by the needles. This example shows basic ordering. ```javascript const haystack = { a: 0, b: 1, c: 1 }; objectScan(['c', 'a', 'b'], { joined: true, orderByNeedles: true })(haystack); // => [ 'c', 'a', 'b' ] ``` -------------------------------- ### objectScan with Array Needles Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/api-reference/objectscan.md Illustrates using array needles with objectScan to match specific object properties and array indices. The example shows how array needles differentiate between object keys and array indices. ```javascript const haystack = { 'a.b': [0], a: { b: [1] } }; const scanner = objectScan([['a.b', 0]], { joined: true, rtn: 'value' }); scanner(haystack); // => [ 0 ] // matches 'a.b'[0], not a.b[0] ``` -------------------------------- ### Skip empty entries in sparse arrays using wildcard Source: https://github.com/blackflux/object-scan/blob/master/README.md For sparse arrays, only set keys are traversed. This example using `['**']` demonstrates that empty entries in the array are skipped during traversal. ```javascript const haystack = (() => { const r = []; r[1] = 'a'; return r; })(); objectScan(['**'], { joined: true, rtn: 'entry' })(haystack); // => [ [ '[1]', 'a' ] ] ``` -------------------------------- ### Object Property Matching in objectScan Source: https://github.com/blackflux/object-scan/blob/master/README.md Use property names directly to match exact properties in an object. This example shows a successful match. ```javascript const haystack = { foo: 0, bar: 1 }; objectScan(['foo'], { joined: true })(haystack); // => [ 'foo' ] ``` -------------------------------- ### Exclusion with Arbitrary Depth Source: https://github.com/blackflux/object-scan/blob/master/README.md Use '!,!**.a' to exclude all paths that end with '.a' at any nesting level. This example selects all paths except those ending in 'a'. ```javascript const haystack = { a: 0, b: { a: 1, c: 2 } }; objectScan(['**,!**.a'], { joined: true })(haystack); // => [ 'b.c', 'b' ] ``` -------------------------------- ### Array Needle Example Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/types.md Demonstrates the structure of an array needle, where segments represent object properties or array indices. This format is generally faster to parse than string needles. ```javascript ['a', 0, 'b'] // matches a[0].b ['a.b', 0] // matches 'a.b'[0] with implicit escape ``` -------------------------------- ### Array Needle vs String Needle Example Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/needle-syntax.md Demonstrates the difference between string needles (requiring escaping) and array needles (no escaping) for accessing nested properties and array elements. ```javascript const haystack = { user: [{ name: 'Alice' }, { name: 'Bob' }] }; // Using string needle (requires escaping) objectScan(['user[*].name'])(haystack); ``` ```javascript // Using array needle (no escaping) objectScan([['user', 0, 'name'], ['user', 1, 'name']])(haystack); ``` ```javascript // Mixing array and string needles objectScan([['user', 0, 'name'], 'user[1].name'])(haystack); ``` -------------------------------- ### Object-Scan Key vs Non-Key Traversal Example Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/traversal-order.md Illustrates how object-scan traverses intermediate nodes and actual matches. Intermediate nodes have 'isMatch' as false and 'matchedBy' as an empty array. ```javascript const haystack = { a: { b: { c: 1, d: 2 } } }; objectScan(['a.b.c'], { filterFn: ({ key, isMatch, matchedBy }) => { console.log(`${key}: isMatch=${isMatch}, matchedBy=${matchedBy.length}`); } })(haystack); // Output: // a: isMatch=false, matchedBy=0 // intermediate node // a.b: isMatch=false, matchedBy=0 // intermediate node // a.b.c: isMatch=true, matchedBy=1 // actual match ``` -------------------------------- ### Nested Path Recursion (One or More) Source: https://github.com/blackflux/object-scan/blob/master/README.md Use '++{...}' to recursively match paths within an Or Clause one or more times. This example demonstrates matching a cyclic path. ```javascript const haystack = [[[[0, 1], [1, 2]], [[3, 4], [5, 6]]], [[[7, 8], [9, 10]], [[11, 12], [13, 14]]]]; objectScan(['++{[0][1]}'], { joined: true })(haystack); // => [ '[0][1][0][1]', '[0][1]' ] ``` -------------------------------- ### Regex Matching '(^foo)' in objectScan Source: https://github.com/blackflux/object-scan/blob/master/README.md Use parentheses to define a regex pattern. This example matches properties starting with 'foo'. ```javascript const haystack = { foo: 0, foobar: 1, bar: 2 }; objectScan(['(^foo)'], { joined: true })(haystack); // => [ 'foobar', 'foo' ] ``` -------------------------------- ### Navigate deeply nested JSON Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/needle-syntax.md This example demonstrates how to navigate through deeply nested JSON structures to extract specific fields like 'id' and 'name' from nested 'attributes'. ```javascript objectScan(['**.data[*].attributes.{id,name}'])(apiResponse) ``` -------------------------------- ### Object Scan with Correct Syntax Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/errors.md Provides an example of valid needle syntax for objectScan, including array indexing, group selection, and regular expressions. This demonstrates proper usage after correcting syntax errors. ```javascript objectScan(['a[0].b', '{x,y,z}', '(^[0-9]+$)']); // Success ``` -------------------------------- ### Create Object Scanner with Options Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/configuration.md Initialize an object scanner by passing configuration options as the second parameter. These options control how the scanner traverses and what it returns. ```javascript const scanner = objectScan(needles, options); ``` -------------------------------- ### Transform with Context Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/README.md Transforms an object while maintaining context across traversal using `beforeFn`, `filterFn`, and `afterFn`. This example collects all keys seen during traversal into a sorted array. ```javascript const result = objectScan(['**'], { beforeFn: ({ context }) => { context.seen = new Set(); }, filterFn: ({ key, context }) => { context.seen.add(key); }, afterFn: ({ context }) => { return Array.from(context.seen).sort(); } })(obj, {}); ``` -------------------------------- ### Get Value by Path Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/usage-patterns.md Retrieves a single value from an object using a specified path. Note: This example has a potential issue where 'result' is not assigned within the scope of the function. ```javascript const getValue = (obj, path) => { let result; objectScan([path], { rtn: 'value' })(obj); return result; }; ``` -------------------------------- ### Joined Option with getKey Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Illustrates the 'joined' option with the getKey method, showing how keys are retrieved with and without the joined setting. ```javascript haystack: { a: { b: { c: 0 } } } needles: ['**.c'] joined: true rtn: ({ getKey }) => [getKey(true), getKey(false), getKey()] comment: joined, getKey ``` -------------------------------- ### Array Needle Examples Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/needle-syntax.md Array needles provide an efficient way to specify simple paths without complex escaping. Numbers target array indices, and strings target object properties. ```javascript objectScan([['a', 0, 'b']])(haystack) // matches a[0].b ``` ```javascript objectScan([['a.b', 0]])(haystack) // matches 'a.b'[0] (literal key 'a.b') ``` ```javascript objectScan([['foo', 'bar', 'baz']])(haystack) // matches foo.bar.baz ``` -------------------------------- ### Strict Mode - Identical Paths Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Illustrates the 'strict' option behavior when identical paths are provided, which throws an error. ```javascript haystack: [] needles: ['a.b', 'a.b'] comment: identical ``` -------------------------------- ### Forward Traversal with breakFn Source: https://github.com/blackflux/object-scan/blob/master/README.md Demonstrates forward traversal using breakFn. When reverse is false, breakFn is executed in pre-order. ```javascript const haystack = { f: { b: { a: {}, d: { c: {}, e: {} } }, g: { i: { h: {} } } } }; objectScan(['**'], { breakFn: ({ isMatch, property, context }) => { if (isMatch) { context.push(property); } }, reverse: false })(haystack, []); // => [ 'f', 'b', 'a', 'd', 'c', 'e', 'g', 'i', 'h' ] ``` -------------------------------- ### Using the Scanner Function Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/types.md Demonstrates how to use the scanner function obtained from objectScan with an object and context. ```javascript const scanner = objectScan(['a.b', 'c.d']); const result = scanner(myObject, myContext); ``` -------------------------------- ### Build Path List in Custom Order Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/traversal-order.md Demonstrates building a custom list of paths during traversal, in this case, from leaves to the root using `reverse: true`. The `filterFn` pushes each `key` into a provided `context` array. Ensure the `context` array is initialized before the scan. ```javascript objectScan(['**'], { reverse: true, filterFn: ({ key, context }) => { context.push(key); } })(haystack, []); // Paths from leaves to root ``` -------------------------------- ### Early Termination with abort Option Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/traversal-order.md Shows how to use the `abort: true` option for immediate termination after the first match is found. This is useful for quickly retrieving a single value. ```javascript objectScan(['specific.path'], { abort: true, rtn: 'value' })(data); // Returns immediately after first match ``` -------------------------------- ### Exclusion with Or Clause Source: https://github.com/blackflux/object-scan/blob/master/README.md Use an exclamation mark '!' to exclude specific paths defined within an Or Clause. This example selects 'a' and 'b' but excludes 'a'. ```javascript const haystack = { a: 0, b: 1 }; objectScan(['{a,b},!a'], { joined: true, strict: false })(haystack); // => [ 'b' ] ``` -------------------------------- ### Regex Matching '[(^[01]$)]' in objectScan Source: https://github.com/blackflux/object-scan/blob/master/README.md Use regex to match specific array indices. This example matches indices '[0]' and '[1]'. ```javascript const haystack = ['a', 'b', 'c', 'd']; objectScan(['[(^[01]$)]'], { joined: true })(haystack); // => [ '[1]', '[0]' ] ``` -------------------------------- ### Using Search Context with filterFn Source: https://github.com/blackflux/object-scan/blob/master/README.md Demonstrates how to use a search context to accumulate a sum based on matched values. The context is initialized with a sum property and updated within the filterFn. ```javascript const haystack = { a: { b: { c: 2, d: 11 }, e: 7 } }; objectScan(['**.{c,d,e}'], { joined: true, filterFn: ({ value, context }) => { context.sum += value; } })(haystack, { sum: 0 }); // => { sum: 20 } ``` -------------------------------- ### Basic objectScan Usage Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/api-reference/objectscan.md Demonstrates basic usage of objectScan with a string needle pattern. Imports the library and creates a scanner to find a nested property. ```javascript import objectScan from 'object-scan'; const haystack = { a: { b: { c: 'd' }, e: { f: 'g' } } }; const scanner = objectScan(['a.*.f'], { joined: true }); scanner(haystack); // => [ 'a.e.f' ] ``` -------------------------------- ### compareFn: Simple Sort Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md The compareFn is used to determine the traversal order of object keys. This example provides a simple locale-based sort. ```javascript haystack: { a: 0, c: 1, b: 2 } needles: ['**'] compareFn: () => (k1, k2) => k1.localeCompare(k2) comment: simple sort reverse: false ``` -------------------------------- ### Array Index Matching in objectScan Source: https://github.com/blackflux/object-scan/blob/master/README.md Use bracket notation with an index to match an exact element in an array. This example shows a successful match. ```javascript const haystack = [0, 1, 2, 3, 4]; objectScan(['[2]'], { joined: true })(haystack); // => [ '[2]' ] ``` -------------------------------- ### UseArraySelector False Example Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Shows 'useArraySelector' set to false, enabling automatic array traversal without including array selectors in the results. ```javascript haystack: [{ a: 0 }, { b: [{ c: 1 }, { d: 2 }] }] needles: ['a', 'b.d'] useArraySelector: false comment: automatic array traversal ``` -------------------------------- ### Object Scan: Joined Option with getKey Source: https://github.com/blackflux/object-scan/blob/master/README.md Illustrates the 'joined' option combined with the getKey() method. getKey(true) returns a joined string path, getKey(false) returns a list path, and getKey() returns a joined string path. ```javascript const haystack = { a: { b: { c: 0 } } }; objectScan(['**.c'], { joined: true, rtn: ({ getKey }) => [getKey(true), getKey(false), getKey()] })(haystack); // => [ [ 'a.b.c', [ 'a', 'b', 'c' ], 'a.b.c' ] ] ``` -------------------------------- ### afterFn: Return Count Plus Context Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md The afterFn is called after traversal. This example shows returning the count of results plus the provided context. ```javascript haystack: { a: 0 } context: 5 needles: ['**'] comment: returning count plus context afterFn: ({ result, context }) => result + context rtn: 'count' joined: false ``` -------------------------------- ### Forward Traversal with filterFn Source: https://github.com/blackflux/object-scan/blob/master/README.md Demonstrates forward traversal using filterFn. When reverse is false, filterFn is executed in post-order. ```javascript const haystack = { f: { b: { a: {}, d: { c: {}, e: {} } }, g: { i: { h: {} } } } }; objectScan(['**'], { filterFn: ({ property, context }) => { context.push(property); }, reverse: false })(haystack, []); // => [ 'a', 'c', 'e', 'd', 'b', 'h', 'i', 'g', 'f' ] ``` -------------------------------- ### Pre-order Traversal Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Demonstrates pre-order traversal with `reverse: false` and a break function. The context array collects properties in pre-order. ```javascript haystack: { F: { B: { A: 0, D: { C: 1, E: 2 } }, G: { I: { H: 3 } } } } joined: false needles: ['**'] context: [] reverse: false breakFn: ({ context, property }) => { context.push(property); } comment: Pre-order ``` -------------------------------- ### Exclusion with Regex Source: https://github.com/blackflux/object-scan/blob/master/README.md Use '!' combined with a regex to exclude paths that match the pattern. This example selects all array elements except those at indices '0' or '1'. ```javascript const haystack = ['a', 'b', 'c', 'd']; objectScan(['[*]', '[!(^[01]$)]'], { joined: true })(haystack); // => [ '[3]', '[2]' ] ``` -------------------------------- ### Using Getter Methods in Callback Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/configuration.md Demonstrates how to use getter methods within a callback function to optimize performance by computing values only when needed. This is useful for accessing parent information or checking match status. ```javascript filterFn: ({ isMatch, getParents }) => { if (isMatch) { getParents(); // only computed if needed } } ``` -------------------------------- ### Nested Path Recursion (Traverse Objects) Source: https://github.com/blackflux/object-scan/blob/master/README.md Use '**{*'}' to recursively traverse only object properties. This example selects all object properties and their nested object paths. ```javascript const haystack = { a: [0, { b: 1 }], c: { d: 2 } }; objectScan(['**{*}'], { joined: true })(haystack); // => [ 'c.d', 'c', 'a' ] ``` -------------------------------- ### Nested Path Recursion (Traverse Arrays) Source: https://github.com/blackflux/object-scan/blob/master/README.md Use '**{[*]}' to recursively traverse only array elements. This example selects all array elements and their nested array paths. ```javascript const haystack = [[[{ a: [1] }], [2]]]; objectScan(['**{[*]}'], { joined: true })(haystack); // => [ '[0][1][0]', '[0][1]', '[0][0][0]', '[0][0]', '[0]' ] ``` -------------------------------- ### Regex Path Matching Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Demonstrates using regular expressions within parentheses for flexible path matching in arrays and objects. ```javascript haystack: { foo: 0, foobar: 1, bar: 2 } needles: ['(^foo)'] comment: starting with `foo` ``` ```javascript haystack: [...Array(20).keys()] needles: ['[(5)]'] comment: containing `5` ``` ```javascript haystack: ['a', 'b', 'c', 'd'] needles: ['[(^[01]$)]'] comment: `[0]` and `[1]` ``` ```javascript haystack: ['a', 'b', 'c', 'd'] needles: ['[(^[^01]$)]'] comment: other than `[0]` and `[1]` ``` -------------------------------- ### Or Clause with Array Indices Source: https://github.com/blackflux/object-scan/blob/master/README.md Use curly braces to define an 'or' condition for array indices. This example selects elements at index 0 or 1. ```javascript const haystack = ['a', 'b', 'c', 'd']; objectScan(['[{0,1}]'], { joined: true })(haystack); // => [ '[1]', '[0]' ] ``` -------------------------------- ### Use Joined Keys for Human-Readable Output Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/usage-patterns.md Enable `joined: true` and set `rtn: 'key'` to obtain human-readable, dot-notation string keys instead of arrays of path segments. This is useful for presenting results in a more understandable format. ```javascript objectScan(['**'], { joined: true, // Returns 'a.b[0].c' instead of ['a', 'b', 0, 'c'] rtn: 'key' })(obj) ``` -------------------------------- ### Escaped Wildcard Matching 'a.\+.c' in objectScan Source: https://github.com/blackflux/object-scan/blob/master/README.md Use a backslash to escape special wildcard characters like '+'. This example matches a literal '+'. ```javascript const haystack = { a: { b: { c: 0 }, '+': { c: 0 } } }; objectScan(['a.\+.c'], { joined: true })(haystack); // => [ 'a.\+.c' ] ``` -------------------------------- ### Not Joined Option with getEntry Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Demonstrates the 'joined' option with the getEntry method, showing how entries are retrieved with and without the joined setting. ```javascript haystack: { a: { b: { c: 0 } } } needles: ['**.c'] joined: false rtn: ({ getEntry }) => [getEntry(true), getEntry(false), getEntry()] comment: not joined, getEntry ``` -------------------------------- ### List Filter Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Filter elements within arrays using wildcard and bracket notation. This example targets any array element within any nested structure. ```json needles: ['*.*[*]'] comment: list filter ``` -------------------------------- ### Build Nested Configuration with objectScan Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/usage-patterns.md Loads a nested configuration object and provides a method to retrieve values by dot-separated paths. Ideal for managing application settings. ```javascript const Config = { load: (configObj) => { const config = {}; objectScan(['**'], { filterFn: ({ key, value, context }) => { if (typeof value !== 'object') { context[key] = value; } } })(configObj, config); return { get: (path) => { const pathArray = path.split('.'); return objectScan([pathArray], { rtn: 'value' })(config)[0]; } }; } }; const cfg = Config.load({ db: { host: 'localhost', port: 5432 }, cache: { ttl: 3600 } }); cfg.get('db.host'); // => 'localhost' ``` -------------------------------- ### Array Path Matching Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Demonstrates exact matching within an array using bracket notation. Note that this syntax does not match object keys. ```javascript haystack: [0, 1, 2, 3, 4] needles: ['[2]'] comment: exact in array ``` ```javascript haystack: { 0: 'a', 1: 'b', 2: 'c' } needles: ['[1]'] comment: no match in object ``` -------------------------------- ### Wildcard Matching '[?5]' in objectScan Source: https://github.com/blackflux/object-scan/blob/master/README.md Use the '?' wildcard within array brackets to match a single character. This example matches array indices ending in '5'. ```javascript const haystack = [...Array(30).keys()]; objectScan(['[?5]'], { joined: true })(haystack); // => [ '[25]', '[15]' ] ``` -------------------------------- ### beforeFn: Combine Haystack and Context Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md The beforeFn is called before traversal. If it returns a value other than undefined, that value is written to state.haystack. This example shows combining haystack and context. ```javascript haystack: { a: 0 } context: { b: 0 } needles: ['**'] comment: combining haystack and context beforeFn: ({ haystack: h, context: c }) => [h, c] rtn: 'key' ``` -------------------------------- ### Reverse Traversal with filterFn Source: https://github.com/blackflux/object-scan/blob/master/README.md Demonstrates reverse traversal using filterFn. When reverse is true, filterFn is executed in reverse pre-order. ```javascript const haystack = { f: { b: { a: {}, d: { c: {}, e: {} } }, g: { i: { h: {} } } } }; objectScan(['**'], { filterFn: ({ property, context }) => { context.push(property); }, reverse: true })(haystack, []); // => [ 'h', 'i', 'g', 'e', 'c', 'd', 'a', 'b', 'f' ] ``` -------------------------------- ### Filter Function Example Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Illustrates the use of a filterFn to conditionally include or exclude values from the scan results. If the filterFn returns false, the current key is excluded. ```javascript haystack: { a: 0, b: 'bar' } needles: ['**'] filterFn: ({ value }) => typeof value === 'string' ``` -------------------------------- ### Get Value by Array Path Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/usage-patterns.md Retrieves the first value found matching an exact path specified as an array of keys. Returns undefined if no match is found. ```javascript const getByArrayPath = (obj, path) => { const result = []; objectScan([path], { rtn: 'value' })(obj); return result[0]; }; const user = { profile: { name: 'Alice', age: 30 } }; getByArrayPath(user, ['profile', 'name']); // => 'Alice' ``` -------------------------------- ### Process Data with Before/After Hooks Source: https://github.com/blackflux/object-scan/blob/master/_autodocs/usage-patterns.md Implement pre-processing and post-processing logic using `beforeFn` and `afterFn` hooks within object-scan. These hooks allow custom operations on the data before scanning and on the results after scanning. ```javascript const processWithHooks = (obj, pattern, options = {}) => { return objectScan([pattern], { beforeFn: ({ haystack, context }) => { // Pre-processing if (options.beforeFn) { options.beforeFn(haystack, context); } }, filterFn: options.filterFn, afterFn: ({ result, context }) => { // Post-processing if (options.afterFn) { return options.afterFn(result, context); } } })(obj); }; ``` -------------------------------- ### Return Sum of Matches with objectScan Source: https://github.com/blackflux/object-scan/blob/master/README.md Use 'rtn: "sum"' to return the sum of all matched values that satisfy the filter function. This example sums all numbers. ```javascript const haystack = { a: { b: { c: -2, d: 1 }, e: [3, 7] } }; objectScan(['**'], { filterFn: ({ value }) => typeof value === 'number', rtn: 'sum' })(haystack); // => 9 ``` -------------------------------- ### beforeFn: Combine Haystack and Context Source: https://github.com/blackflux/object-scan/blob/master/README.md The beforeFn is called before traversal. If it returns a value other than undefined, that value is used as the new haystack. This example combines the original haystack and context. ```javascript const haystack = { a: 0 }; objectScan(['**'], { joined: true, beforeFn: ({ haystack: h, context: c }) => [h, c], rtn: 'key' })(haystack, { b: 0 }); // => [ '[1].b', '[1]', '[0].a', '[0]' ] ``` -------------------------------- ### Object Scan Pre-order Traversal Source: https://github.com/blackflux/object-scan/blob/master/README.md Demonstrates pre-order traversal using `['**']` and `reverse: false`. The `breakFn` collects properties in this order. ```javascript const haystack = { F: { B: { A: 0, D: { C: 1, E: 2 } }, G: { I: { H: 3 } } } }; objectScan(['**'], { breakFn: ({ context, property }) => { context.push(property); }, reverse: false })(haystack, []); // => [ undefined, 'F', 'B', 'A', 'D', 'C', 'E', 'G', 'I', 'H' ] ``` -------------------------------- ### Match Empty String Keys Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Demonstrates matching keys that are empty strings using the `(^$)` pattern within a needle. ```javascript haystack: { '': 0, a: { '': 1 } } needles: ['**.(^$)'] joined: false comment: match empty string keys ``` -------------------------------- ### Or Clause with Object Keys Source: https://github.com/blackflux/object-scan/blob/master/README.md Use curly braces to define an 'or' condition for object keys. This example selects properties 'a' or 'd', and then their nested properties 'b' or 'f'. ```javascript const haystack = { a: { b: 0, c: 1 }, d: { e: 2, f: 3 } }; objectScan(['{a,d}.{b,f}'], { joined: true })(haystack); // => [ 'd.f', 'a.b' ] ``` -------------------------------- ### Regex Matching '[(^[^01]$)]' in objectScan Source: https://github.com/blackflux/object-scan/blob/master/README.md Use negated regex within array brackets to exclude specific array indices. This example matches indices other than '[0]' and '[1]'. ```javascript const haystack = ['a', 'b', 'c', 'd']; objectScan(['[(^[^01]$)]'], { joined: true })(haystack); // => [ '[3]', '[2]' ] ``` -------------------------------- ### Arbitrary Depth Matching (Zero or More Nestings) Source: https://github.com/blackflux/object-scan/blob/master/test/readme/README.template.md Use '**' to match zero or more nestings in a path. This is useful for searching properties at any level within an object. ```javascript haystack: { a: { b: 0, c: 0 } } needles: ['a.**'] comment: zero or more nestings under `a` ```