@sentry/wizard
Version:
Sentry wizard helping you to configure your project
171 lines • 7.36 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.instrumentRoot = void 0;
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
const recast = __importStar(require("recast"));
const path = __importStar(require("path"));
const magicast_1 = require("magicast");
const templates_1 = require("../templates");
const ast_utils_1 = require("../../utils/ast-utils");
const debug_1 = require("../../utils/debug");
function hasCaptureExceptionCall(node) {
let found = false;
recast.visit(node, {
visitCallExpression(path) {
const callee = path.value.callee;
if ((callee.type === 'MemberExpression' &&
callee.object?.name === 'Sentry' &&
callee.property?.name === 'captureException') ||
(callee.type === 'Identifier' && callee.name === 'captureException')) {
found = true;
}
this.traverse(path);
},
});
return found;
}
function addCaptureExceptionCall(functionNode) {
const captureExceptionCall = recast.parse(`Sentry.captureException(error);`)
.program.body[0];
const functionBody = (0, ast_utils_1.safeGetFunctionBody)(functionNode);
if (functionBody) {
if (!(0, ast_utils_1.safeInsertBeforeReturn)(functionBody, captureExceptionCall)) {
functionBody.push(captureExceptionCall);
}
}
else {
(0, debug_1.debug)('Could not safely access ErrorBoundary function body');
}
}
function findErrorBoundaryInExports(namedExports) {
return namedExports.some((namedExport) => {
const declaration = namedExport.declaration;
if (!declaration) {
return namedExport.specifiers?.some((spec) => spec.type === 'ExportSpecifier' &&
spec.exported?.type === 'Identifier' &&
spec.exported.name === 'ErrorBoundary');
}
if (declaration.type === 'FunctionDeclaration') {
return declaration.id?.name === 'ErrorBoundary';
}
if (declaration.type === 'VariableDeclaration') {
return declaration.declarations.some((decl) => {
// @ts-expect-error - id should always have a name in this case
return decl.id?.name === 'ErrorBoundary';
});
}
return false;
});
}
async function instrumentRoot(rootFileName) {
const filePath = path.join(process.cwd(), 'app', rootFileName);
const rootRouteAst = await (0, magicast_1.loadFile)(filePath);
const exportsAst = rootRouteAst.exports.$ast;
const namedExports = exportsAst.body.filter((node) => node.type === 'ExportNamedDeclaration');
const foundErrorBoundary = findErrorBoundaryInExports(namedExports);
const alreadyHasSentry = (0, ast_utils_1.hasSentryContent)(rootRouteAst.$ast);
if (!alreadyHasSentry) {
rootRouteAst.imports.$add({
from: '@sentry/react-router',
imported: '*',
local: 'Sentry',
});
}
if (!foundErrorBoundary) {
const hasIsRouteErrorResponseImport = rootRouteAst.imports.$items.some((item) => item.imported === 'isRouteErrorResponse' &&
item.from === 'react-router');
if (!hasIsRouteErrorResponseImport) {
rootRouteAst.imports.$add({
from: 'react-router',
imported: 'isRouteErrorResponse',
local: 'isRouteErrorResponse',
});
}
recast.visit(rootRouteAst.$ast, {
visitExportDefaultDeclaration(path) {
const implementation = recast.parse(templates_1.ERROR_BOUNDARY_TEMPLATE).program
.body[0];
path.insertBefore(recast.types.builders.exportDeclaration(false, implementation));
this.traverse(path);
},
});
}
else {
recast.visit(rootRouteAst.$ast, {
visitExportNamedDeclaration(path) {
const declaration = path.value.declaration;
if (!declaration) {
this.traverse(path);
return;
}
let functionToInstrument = null;
if (declaration.type === 'FunctionDeclaration' &&
declaration.id?.name === 'ErrorBoundary') {
functionToInstrument = declaration;
}
else if (declaration.type === 'VariableDeclaration' &&
declaration.declarations?.[0]?.id?.name === 'ErrorBoundary') {
const init = declaration.declarations[0].init;
if (init &&
(init.type === 'FunctionExpression' ||
init.type === 'ArrowFunctionExpression')) {
functionToInstrument = init;
}
}
if (functionToInstrument &&
!hasCaptureExceptionCall(functionToInstrument)) {
addCaptureExceptionCall(functionToInstrument);
}
this.traverse(path);
},
visitVariableDeclaration(path) {
if (path.value.declarations?.[0]?.id?.name === 'ErrorBoundary') {
const init = path.value.declarations[0].init;
if (init &&
(init.type === 'FunctionExpression' ||
init.type === 'ArrowFunctionExpression') &&
!hasCaptureExceptionCall(init)) {
addCaptureExceptionCall(init);
}
}
this.traverse(path);
},
visitFunctionDeclaration(path) {
if (path.value.id?.name === 'ErrorBoundary' &&
!hasCaptureExceptionCall(path.value)) {
addCaptureExceptionCall(path.value);
}
this.traverse(path);
},
});
}
await (0, magicast_1.writeFile)(rootRouteAst.$ast, filePath);
}
exports.instrumentRoot = instrumentRoot;
//# sourceMappingURL=root.js.map