@sentry/wizard
Version:
Sentry wizard helping you to configure your project
119 lines (102 loc) • 4.83 kB
text/typescript
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
import type { ProxifiedModule } from 'magicast';
import type { Program } from '@babel/types';
import * as recast from 'recast';
import { HANDLE_ERROR_TEMPLATE_V2 } from '../templates';
import { getAfterImportsInsertionIndex, hasSentryContent } from '../utils';
// @ts-expect-error - clack is ESM and TS complains about that. It works though
import clack from '@clack/prompts';
import chalk from 'chalk';
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
import { generateCode } from 'magicast';
export function instrumentHandleError(
originalEntryServerMod: ProxifiedModule<any>,
serverEntryFilename: string,
): boolean {
const originalEntryServerModAST = originalEntryServerMod.$ast as Program;
const handleErrorFunctionExport = originalEntryServerModAST.body.find(
(node) => {
return (
node.type === 'ExportNamedDeclaration' &&
node.declaration?.type === 'FunctionDeclaration' &&
node.declaration.id?.name === 'handleError'
);
},
);
const handleErrorFunctionVariableDeclarationExport =
originalEntryServerModAST.body.find(
(node) =>
node.type === 'ExportNamedDeclaration' &&
node.declaration?.type === 'VariableDeclaration' &&
// @ts-expect-error - id should always have a name in this case
node.declaration.declarations[0].id.name === 'handleError',
);
if (
!handleErrorFunctionExport &&
!handleErrorFunctionVariableDeclarationExport
) {
clack.log.warn(
`Could not find function ${chalk.cyan('handleError')} in ${chalk.cyan(
serverEntryFilename,
)}. Creating one for you.`,
);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const implementation = recast.parse(HANDLE_ERROR_TEMPLATE_V2).program
.body[0];
originalEntryServerModAST.body.splice(
getAfterImportsInsertionIndex(originalEntryServerModAST),
0,
// @ts-expect-error - string works here because the AST is proxified by magicast
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
recast.types.builders.exportNamedDeclaration(implementation),
);
} else if (
(handleErrorFunctionExport &&
['wrapHandleErrorWithSentry', 'sentryHandleError'].some((util) =>
hasSentryContent(
generateCode(handleErrorFunctionExport).code,
originalEntryServerMod.$code,
util,
),
)) ||
(handleErrorFunctionVariableDeclarationExport &&
['wrapHandleErrorWithSentry', 'sentryHandleError'].some((util) =>
hasSentryContent(
generateCode(handleErrorFunctionVariableDeclarationExport).code,
originalEntryServerMod.$code,
util,
),
))
) {
return false;
} else if (handleErrorFunctionExport) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const implementation = recast.parse(HANDLE_ERROR_TEMPLATE_V2).program
.body[0];
// If the current handleError function has a body, we need to merge the new implementation with the existing one
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
implementation.declarations[0].init.arguments[0].body.body.unshift(
// @ts-expect-error - declaration works here because the AST is proxified by magicast
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
...handleErrorFunctionExport.declaration.body.body,
);
// @ts-expect-error - declaration works here because the AST is proxified by magicast
handleErrorFunctionExport.declaration = implementation;
} else if (handleErrorFunctionVariableDeclarationExport) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const implementation = recast.parse(HANDLE_ERROR_TEMPLATE_V2).program
.body[0];
// If the current handleError function has a body, we need to merge the new implementation with the existing one
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
implementation.declarations[0].init.arguments[0].body.body.unshift(
// @ts-expect-error - declaration works here because the AST is proxified by magicast
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
...handleErrorFunctionVariableDeclarationExport.declaration
.declarations[0].init.body.body,
);
// @ts-expect-error - declaration works here because the AST is proxified by magicast
handleErrorFunctionVariableDeclarationExport.declaration = implementation;
}
return true;
}