Created
March 15, 2020 18:15
-
-
Save jmakeig/1801a0de3abc1b5ef55d9d750afff60c to your computer and use it in GitHub Desktop.
Recursive descent transformation with visitor
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
#!/usr/bin/env node | |
/** | |
* Depth-first copy with selective transformation. | |
* For each of the `Iterable` selected by the selector function, it | |
* applies the `visitor` function and continues recursively. | |
* | |
* | |
* @param {object} node the tree structure | |
* @param {function} [visitor] the function to apply to selected children | |
* @param {function} [childrenSelector] selects an `Iterable` of children | |
* @return {object} the new tree | |
*/ | |
function transform(object, visitor = v => v, childrenSelector = p => true) { | |
const copy = Object.create(Object.getPrototypeOf(object)); | |
for (let p in object) { | |
if (!childrenSelector(p)) { | |
copy[p] = object[p]; | |
} else { | |
copy[p] = object[p].map(prop => | |
visitor(transform(prop, visitor, childrenSelector)) | |
); | |
} | |
} | |
return copy; | |
} | |
/* Usage: */ | |
const Cardinality = Object.freeze({ | |
one: 1, | |
many: Infinity | |
}); | |
const entity = { | |
label: 'Customer', | |
name: 'customer', | |
properties: [ | |
{ | |
label: 'Given Name', | |
name: 'givenName', | |
type: 'string', | |
cardinality: Cardinality.one | |
}, | |
{ | |
label: 'Family Name', | |
name: 'familyName', | |
type: 'string', | |
cardinality: Cardinality.one | |
}, | |
{ | |
label: 'Shipping Address', | |
name: 'shippingAddress', | |
type: 'object', | |
cardinality: Cardinality.one, | |
properties: [ | |
{ | |
label: 'Street Address', | |
name: 'address', | |
type: 'string', | |
cardinality: Cardinality.one | |
}, | |
{ | |
label: 'City', | |
name: 'city', | |
type: 'string', | |
cardinality: Cardinality.one | |
}, | |
{ | |
label: 'State', | |
name: 'state', | |
type: 'string', | |
cardinality: Cardinality.one | |
}, | |
{ | |
label: 'ZIP Code', | |
name: 'zip', | |
type: 'string', | |
cardinality: Cardinality.one | |
} | |
] | |
} | |
] | |
}; | |
let counter = 0; | |
function spawn(property) { | |
return { | |
ref: `${++counter}`, | |
context: Object.assign(Object.create(null), property) | |
}; | |
} | |
console.log( | |
JSON.stringify( | |
transform(entity, spawn, p => 'properties' === p), | |
null, | |
2 | |
) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment