Skip to content

Commit

Permalink
chore: better error logging on prepareRunHook
Browse files Browse the repository at this point in the history
  • Loading branch information
nickreese committed Mar 8, 2022
1 parent babf546 commit aa922f6
Showing 1 changed file with 85 additions and 79 deletions.
164 changes: 85 additions & 79 deletions src/utils/prepareRunHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,104 +3,110 @@ import createReadOnlyProxy from './createReadOnlyProxy';

// TODO: How do we get types to the user when they are writing plugins, etc?
function prepareRunHook({ hooks, allSupportedHooks, settings }) {
// eslint-disable-next-line consistent-return
return async function processHook(hookName, props: any = {}) {
if (props.perf) props.perf.start(`hook.${hookName}`);
try {
if (props.perf) props.perf.start(`hook.${hookName}`);

// do we have a contract for the hook
const hookDefinition = allSupportedHooks.find((h) => h.hook === hookName);
if (!hookDefinition) {
throw new Error(`Hook ${hookName} not defined in hookInterface or via plugins.`);
}
// do we have a contract for the hook
const hookDefinition = allSupportedHooks.find((h) => h.hook === hookName);
if (!hookDefinition) {
throw new Error(`Hook ${hookName} not defined in hookInterface or via plugins.`);
}

const hookProps = hookDefinition.props.reduce((out, cv) => {
if (cv === 'perf') return out; // perf added and prefixed below
const hookProps = hookDefinition.props.reduce((out, cv) => {
if (cv === 'perf') return out; // perf added and prefixed below

if (Object.hasOwnProperty.call(props, cv)) {
if (!hookDefinition.mutable.includes(cv) && cv !== 'perf') {
out[cv] = createReadOnlyProxy(props[cv], cv, hookName);
if (Object.hasOwnProperty.call(props, cv)) {
if (!hookDefinition.mutable.includes(cv)) {
out[cv] = createReadOnlyProxy(props[cv], cv, hookName);
} else {
out[cv] = props[cv];
}
} else {
out[cv] = props[cv];
console.error(
`Hook named '${hookName}' cannot be run because prop ${cv} is not in scope to pass to the hook. Hook contract broken.`,
);
}
} else {
console.error(
`Hook named '${hookName}' cannot be run because prop ${cv} is not in scope to pass to the hook. Hook contract broken.`,
);
}

return out;
}, {});
return out;
}, {});

const theseHooks = hooks.filter((h) => h.hook === hookName);
if (theseHooks && Array.isArray(theseHooks) && theseHooks.length > 0) {
// higher priority is more important.
const hookList = theseHooks.sort((a, b) => b.priority - a.priority);
const theseHooks = hooks.filter((h) => h.hook === hookName);
if (theseHooks && Array.isArray(theseHooks) && theseHooks.length > 0) {
// higher priority is more important.
const hookList = theseHooks.sort((a, b) => b.priority - a.priority);

if (settings && settings.debug && settings.debug.hooks) {
console.log(`Hooks registered on ${hookName}:`, hookList);
}
if (settings && settings.debug && settings.debug.hooks) {
console.log(`Hooks registered on ${hookName}:`, hookList);
}

const hookOutput = {};
const hookOutput = {};

// loop through the hooks, updating the output and the props in order
await hookList.reduce((p, hook) => {
return p.then(async () => {
if (props.perf) props.perf.start(`hook.${hookName}.${hook.name}`);
try {
let hookResponse = await hook.run({
...hookProps,
perf: props.perf.prefix(`hook.${hookName}.${hook.name}`),
});
// loop through the hooks, updating the output and the props in order
await hookList.reduce((p, hook) => {
return p.then(async () => {
if (props.perf) props.perf.start(`hook.${hookName}.${hook.name}`);
try {
let hookResponse = await hook.run({
...hookProps,
perf: props.perf.prefix(`hook.${hookName}.${hook.name}`),
});

if (!hookResponse) hookResponse = {};
if (!hookResponse) hookResponse = {};

if (settings && settings.debug && settings.debug.hooks) {
console.log(`${hook.name} ran on ${hookName} and returned`, hookResponse);
if (settings && settings.debug && settings.debug.hooks) {
console.log(`${hook.name} ran on ${hookName} and returned`, hookResponse);
}

Object.keys(hookResponse).forEach((key) => {
if (hookDefinition.mutable && hookDefinition.mutable.includes(key)) {
hookOutput[key] = hookResponse[key];
hookProps[key] = hookResponse[key];
} else {
console.error(
`Received attempted mutation on "${hookName}" from "${hook.name}" on the object "${key}". ${key} is not mutable on this hook `,
hook.$$meta,
);
}
});
} catch (e) {
console.error(e);
e.message = `Hook: "${hook.name}" threw an error: ${e.message}`;
props.errors.push(e);
if (hookName === 'buildComplete') console.error(e);
}
if (props.perf) props.perf.end(`hook.${hookName}.${hook.name}`);
});
}, Promise.resolve());

// this actually mutates the props.
if (
Object.keys(hookOutput).length > 0 &&
Array.isArray(hookDefinition.mutable) &&
hookDefinition.mutable.length > 0
) {
hookDefinition.mutable.forEach((key) => {
if ({}.hasOwnProperty.call(hookOutput, key)) {
props[key] = hookOutput[key];
}
});
}

Object.keys(hookResponse).forEach((key) => {
if (hookDefinition.mutable && hookDefinition.mutable.includes(key)) {
hookOutput[key] = hookResponse[key];
hookProps[key] = hookResponse[key];
} else {
console.error(
`Received attempted mutation on "${hookName}" from "${hook.name}" on the object "${key}". ${key} is not mutable on this hook `,
hook.$$meta,
);
}
});
} catch (e) {
e.message = `Hook: "${hook.name}" threw an error: ${e.message}`;
props.errors.push(e);
if (hookName === 'buildComplete') console.error(e);
}
if (props.perf) props.perf.end(`hook.${hookName}.${hook.name}`);
});
}, Promise.resolve());

// this actually mutates the props.
if (
Object.keys(hookOutput).length > 0 &&
Array.isArray(hookDefinition.mutable) &&
hookDefinition.mutable.length > 0
) {
hookDefinition.mutable.forEach((key) => {
if ({}.hasOwnProperty.call(hookOutput, key)) {
props[key] = hookOutput[key];
}
});
}
if (settings && settings.debug && settings.debug.hooks) console.log(`${hookName} finished`);

if (settings && settings.debug && settings.debug.hooks) console.log(`${hookName} finished`);
if (props.perf) props.perf.end(`hook.${hookName}`);
return hookOutput;
}
if (settings && settings.debug && settings.debug.hooks) {
console.log(`${hookName} finished without executing any functions`);
}

if (props.perf) props.perf.end(`hook.${hookName}`);
return hookOutput;
return props;
} catch (e) {
console.error(e);
}
if (settings && settings.debug && settings.debug.hooks) {
console.log(`${hookName} finished without executing any functions`);
}

if (props.perf) props.perf.end(`hook.${hookName}`);
return props;
};
}

Expand Down

0 comments on commit aa922f6

Please sign in to comment.