-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
20 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,32 @@ | ||
// We split the core methods of `wild_wild_path` to keep it small, and provide | ||
// additional utilities built on top of it. | ||
import { list, get, set } from '../wild_wild_path/main.js' | ||
import { iterate, get, set } from '../wild_wild_path/main.js' | ||
|
||
// Map values matching a query. | ||
// Missing entries are mapped too | ||
// - This allows logic such as adding default values | ||
// - However, if the map function does not modify the value, we do not set it | ||
export const map = function (target, queryOrPath, mapFunc) { | ||
const entries = list(target, queryOrPath) | ||
return entries.reduceRight(mapEntry.bind(undefined, mapFunc), target) | ||
// We recurse from children to parents: | ||
// - This allows recursive logic such as cleaning up empty objects | ||
// - This also means newly set values are not recursed over: | ||
// - There are not many use cases for it | ||
// - When needed, this can also be done by the consumer logic | ||
// - This also avoids infinite recursion | ||
export const map = function (target, queryOrPaths, mapFunc) { | ||
// eslint-disable-next-line fp/no-let | ||
let newTarget = target | ||
|
||
// eslint-disable-next-line fp/no-loops | ||
for (const entry of iterate(target, queryOrPaths, { childFirst: true })) { | ||
// eslint-disable-next-line fp/no-mutation | ||
newTarget = mapEntry(mapFunc, newTarget, entry) | ||
} | ||
|
||
return newTarget | ||
} | ||
|
||
const mapEntry = function (mapFunc, target, { path, query, missing }) { | ||
const value = get(target, path) | ||
const value = get(target, [path]) | ||
const mappedValue = mapFunc({ path, query, value, missing }) | ||
return value === mappedValue ? target : set(target, path, mappedValue) | ||
return value === mappedValue ? target : set(target, [path], mappedValue) | ||
} |