Skip to content

Instantly share code, notes, and snippets.

@jmakeig
Created March 15, 2020 18:15
Show Gist options
  • Save jmakeig/1801a0de3abc1b5ef55d9d750afff60c to your computer and use it in GitHub Desktop.
Save jmakeig/1801a0de3abc1b5ef55d9d750afff60c to your computer and use it in GitHub Desktop.
Recursive descent transformation with visitor
#!/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