Skip to content

Instantly share code, notes, and snippets.

@fernandocamargo
Last active September 29, 2021 22:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fernandocamargo/26dd36641743088d6b8889ac8e03b57c to your computer and use it in GitHub Desktop.
Save fernandocamargo/26dd36641743088d6b8889ac8e03b57c to your computer and use it in GitHub Desktop.
export const fail = (reason) => Promise.resolve({ status: 'failed', reason });
export const skip = (unresolvedDependencies) =>
Promise.resolve({ status: 'skipped', unresolvedDependencies });
export const succeed = (value) =>
Promise.resolve({ status: 'resolved', value });
export const categorize = (stack, [id, { status, value }]) => {
const type = status === 'resolved' ? status : 'unresolved';
const { [type]: next } = { resolved: value, unresolved: id };
const { [type]: current } = stack;
return Object.assign(stack, { [type]: current.concat(next) });
};
export const runTasks = (tasks) => {
const extract = function (stack, [id, { dependencies, task }]) {
const { origin = [id] } = this || globalThis;
const validate = (dependency) => !origin.includes(dependency);
const format = (details) => [id, details];
const load = (dependency) => {
const get = ({ indexes: { [dependency]: value } }) => value;
const resolve = () => {
const cached = stack.indexes.hasOwnProperty(dependency);
const flush = () =>
extract.call({ origin: origin.concat(dependency) }, stack, [
dependency,
tasks[dependency],
]);
return get(cached ? stack : flush());
};
const reject = () => [dependency, { status: 'circular' }];
return validate(dependency) ? resolve() : reject();
};
const execute = (params) => {
const { resolved, unresolved } = params.reduce(categorize, {
resolved: [],
unresolved: [],
});
const attempt = () => {
try {
return Promise.resolve(task(...resolved))
.then(succeed)
.catch(fail);
} catch (reason) {
return fail(reason);
}
};
const process = () =>
!!unresolved.length ? skip(unresolved) : attempt();
return process().then(format);
};
const reconcile = () =>
stack.indexes.hasOwnProperty(id) && stack.indexes[id];
const fulfill = () => Promise.all(dependencies.map(load)).then(execute);
const promise = reconcile() || fulfill();
return {
indexes: Object.assign(stack.indexes, { [id]: promise }),
promises: stack.promises.concat(promise),
};
};
const { promises } = Object.entries(tasks).reduce(extract, {
indexes: {},
promises: [],
});
return Promise.all(promises).then(Object.fromEntries);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment