Last active
August 9, 2018 18:46
-
-
Save gabejohnson/89817a96346a5e770ec17c7415620d66 to your computer and use it in GitHub Desktop.
Simple DSL for accessing/updating deeply nested data
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
/* | |
Calling _.foo.bar with a value returns the value at the end of that path (if it exists), `undefined` otherwise. | |
Constructing _.foo.bar with a function returns a function that immutably updates a value if the path matches, returns the original otherwise. | |
Usage: | |
> [{foo: {bar: 1}}, {foo: {bar: 2}}, {foo: {bar: 3}}, {foo: {bur: 4}}].map(_.foo.bar) | |
[1, 2, 3, undefined] | |
> [{foo: {bar: 1}}, {foo: {bar: 2}}, {foo: {bar: 3}}, {foo: {bur: 4}}].map(new _.foo.bar(x => x + 1)) | |
[{foo: {bar: 2}}, {foo: {bar: 3}}, {foo: {bar: 4}}, {foo: {bur: 4}}] | |
*/ | |
const _ = new Proxy(Object.create(null), { | |
get: (obj, prop) => { | |
const paths = [prop]; | |
const getter = new Proxy(function(){}, { | |
get: (obj, prop) => { | |
paths.push(prop); | |
return getter; | |
}, | |
apply: (target, thisArg, [result]) => { | |
for (let i = 0; i < paths.length; i++) { | |
if (result.hasOwnProperty(paths[i])) result = result[paths[i]]; | |
else return; | |
} | |
return result; | |
}, | |
construct: (target, [fn], newTarget) => result => { | |
const ogObj = result; | |
let newObj = objRef = {...result}, i; | |
for (i = 0; i < paths.length; i++) { | |
if (result.hasOwnProperty(paths[i])) { | |
result = result[paths[i]]; | |
if (i < paths.length - 1 && Object.getOwnPropertyNames(result).length > 0) { | |
objRef = objRef[paths[i]] = {...result}; | |
} | |
} else { | |
return ogObj; | |
} | |
} | |
objRef[paths[i-1]] = fn(result); | |
return newObj; | |
} | |
}); | |
return getter; | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment