Skip to content

Instantly share code, notes, and snippets.

@zaceno
Created August 29, 2018 11:17
Show Gist options
  • Save zaceno/0d7c62be81a845857e755c1378b7dbff to your computer and use it in GitHub Desktop.
Save zaceno/0d7c62be81a845857e755c1378b7dbff to your computer and use it in GitHub Desktop.
Squirrel -- utility for defining transformations of deeply nested objects
/*
Squirrel helps you work with data held in deeply nested objects
It creates a mapping based on a given `path`. The mapping transforms a unary function `f`
into a function that applies f to the given path of a given object.
The path is given as a string, with each nesting level separated by a '.'
Some examples:
```
const increment = x => x + 1
const fooMap = squirrel('foo')
const incrementFoo = fooMap(increment)
incrementFoo({foo: 1, bar:1}) // returns: {foo: 2, bar:1}
```
Paths are not limited to one level deep:
```
const valueMap = squirrel('foo.bar.value')
const incrementValue = valueMap(x => x + 1)
incrementValue({foo: {bar: {value: 1}, baz: 1}})
// returns: {foo: {bar: {value: 2}, baz: 1}}
```
Your path can build on a previously existing mapping:
```
const data = {
foo: {
doors: {
'front': 'closed',
'back': 'open',
'garage': 'closed',
}
}
}
const doorMap = squirrel('foo.doors')
const setDoorOpen = (doorId, data) => squirrel(doorId, doorMap)(_ => 'open')(data)
setDoorOpen('front', data)
// returns {foo: {doors: {front: 'open', ...}}}
```
Why "Squirrel" ?
– Squirrels run up (data-)trees with acorns (=new data) to put in specific places
...what *you* call it is up to you of course ;)
*/
export default function squirrel (path, map) {
const [key, ...rest] = Array.isArray(path) ? path : path.split('.').reverse()
if (rest.length) map = squirrel(rest, map)
const F = f => x => ({...x, [key]: f(x[key])})
return map ? x => map(F(x)) : F
}
@mshgh
Copy link

mshgh commented Nov 4, 2018

Hi @zaceno,
I have a questions about licensing of this gist? To be more exact can I make it part (copy&paste) of my hyperapp2 modules solution? And make some adjustments to it? If so under what conditions?
Thank you for your answer.

@zaceno
Copy link
Author

zaceno commented Dec 11, 2018

Hi @mshgh thanks for asking and sorry I didn’t notice sooner!

I found the idea too simple to warrant a separate lib, and hence didn’t consider licensing. Of course I’m fine with you using it in whatever way you please, as long as you don’t restrict anyone else from using it in the same way. I e, if you publish it under a license, keep that in mind (use ISC, MIT, BSD3 et c)

You don’t have to credit me, but of course it will make me happy if you do :)

@adriengibrat
Copy link

To support array in your data model, replace line 56 with

const F = f => x => Object.assign(Array.isArray(x) ? [] : {}, x, { [key]: f(x[key]) })

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment