Skip to content

Instantly share code, notes, and snippets.

@Freak613
Last active April 10, 2020 05:23
Show Gist options
  • Save Freak613/543d0ed8a40563ff6347a6c4a7e96dfd to your computer and use it in GitHub Desktop.
Save Freak613/543d0ed8a40563ff6347a6c4a7e96dfd to your computer and use it in GitHub Desktop.
// utils
const curry = (fn, arity = fn.length, ...args) => {
return arity <= args.length
? fn(...args)
: curry.bind(null, fn, arity, ...args);
};
const append = curry((item, array = []) => {
return [...array, item];
}, 2);
const pipe = (...fns) => {
return fns.reduce((f, g) => (...args) => g(f(...args)));
};
const keys = object => {
if (!object) return [];
return Object.keys(object);
};
const forEach = curry((fn, array) => {
return array.forEach(fn);
});
const prop = curry((key, object) => {
if (!object) return undefined;
return object[key];
});
const concat = curry((a = [], b = []) => {
return [...a, ...b];
}, 2);
const reduce = curry((cb, init, array) => {
return array.reduce(cb, init);
});
const uniq = array => {
return reduce(
(acc, value) => {
if (acc.includes(value)) return acc;
return [...acc, value];
},
[],
array
);
};
const mapObjIndexed = curry((cb, object) => {
return pipe(
keys,
reduce((acc, key) => {
acc[key] = cb(object[key], key);
return acc;
}, {})
)(object);
});
// dig - mix of Ramda.evolve and normalizr
const getChildContext = (context, key = null) => {
return {
...context,
path: key ? append(key, context.path) : context.path,
key
};
};
const runTransformation = (transformation, value, context) => {
const transformType = typeof transformation;
if (transformType === "function") {
transformation(value, context);
} else if (transformation && transformType === "object") {
dig(transformation, value, context);
}
};
const dig = (transformations, object, context = {}) => {
if (typeof transformations === "function") {
transformations(object, getChildContext(context));
return;
}
const isArray = transformations instanceof Array;
const target = isArray ? object : transformations;
const getTransformation = isArray
? () => transformations[0]
: key => transformations[key];
pipe(
keys,
forEach(key => {
runTransformation(
getTransformation(key),
prop(key, object),
getChildContext(context, key)
);
})
)(target);
};
dig.Values = (...args) => {
let transformations;
let defaultFields = [];
if (args.length === 1) {
[transformations] = args;
} else if (args.length === 2) {
[defaultFields, transformations] = args;
}
return (object, context) => {
pipe(
keys,
concat(defaultFields),
uniq,
forEach(key => {
dig(
transformations,
prop(key, object),
getChildContext(context, key)
);
})
)(object);
};
};
dig.Optional = (
transformations,
shouldProceed = value => value !== undefined
) => {
if (transformations instanceof Array) {
throw new Error(
"Can't perform optional transformations for Array schema"
);
}
if (typeof transformations === "function") {
return (value, context) => {
if (!shouldProceed(value)) return;
transformations(value, context);
};
}
return mapObjIndexed(
transformation => (value, context) => {
if (!shouldProceed(value)) return;
runTransformation(transformation, value, context);
},
transformations
);
};
dig.Entity = (getChildContext, nestedSchema) => (value, context) => {
const childContext = getChildContext(value, context) || context;
dig(nestedSchema, value, childContext);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment