@sentry/wizard
Version:
Sentry wizard helping you to configure your project
169 lines • 7.26 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;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.instrumentViteConfig = exports.addReactRouterPluginToViteConfig = void 0;
const recast = __importStar(require("recast"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
const magicast_1 = require("magicast");
// @ts-expect-error - clack is ESM and TS complains about that. It works though
const prompts_1 = __importDefault(require("@clack/prompts"));
const chalk_1 = __importDefault(require("chalk"));
const ast_utils_1 = require("../../utils/ast-utils");
/**
* Extracts ObjectExpression from function body.
* Handles both arrow functions with object returns and block statements with explicit returns.
*
* - Arrow with object-return: (config) => ({ ... })
* - Arrow with block: (config) => { return { ... }; }
* - Function with block: function(config) { return { ... }; }
*
* @param body - The function body to extract from
* @returns The ObjectExpression if found, undefined otherwise
*/
function extractFromFunctionBody(body) {
if (body.type === 'ObjectExpression') {
return body;
}
if (body.type === 'BlockStatement') {
const blockBody = body;
const returnStatement = blockBody.body.find((stmt) => stmt.type === 'ReturnStatement');
return returnStatement?.argument?.type === 'ObjectExpression'
? returnStatement.argument
: undefined;
}
return undefined;
}
/**
* Creates the sentryReactRouter Vite plugin call expression.
*
* Generates AST for:
* sentryReactRouter({
* org: "...",
* project: "...",
* authToken: process.env.SENTRY_AUTH_TOKEN
* }, config)
*
* @param orgSlug - Sentry organization slug
* @param projectSlug - Sentry project slug
* @returns CallExpression node for the Sentry Vite plugin
*/
function createSentryPluginCall(orgSlug, projectSlug) {
const b = recast.types.builders;
return b.callExpression(b.identifier('sentryReactRouter'), [
b.objectExpression([
b.objectProperty(b.identifier('org'), b.stringLiteral(orgSlug)),
b.objectProperty(b.identifier('project'), b.stringLiteral(projectSlug)),
b.objectProperty(b.identifier('authToken'), b.memberExpression(b.memberExpression(b.identifier('process'), b.identifier('env')), b.identifier('SENTRY_AUTH_TOKEN'))),
]),
b.identifier('config'),
]);
}
function addReactRouterPluginToViteConfig(program, orgSlug, projectSlug) {
const b = recast.types.builders;
let wasConverted = false;
const defaultExport = program.body.find((node) => node.type === 'ExportDefaultDeclaration');
if (!defaultExport) {
return { success: false, wasConverted: false };
}
let configObj;
let defineConfigCall;
if (defaultExport.declaration.type === 'CallExpression' &&
defaultExport.declaration.callee.type === 'Identifier' &&
defaultExport.declaration.callee.name === 'defineConfig') {
defineConfigCall = defaultExport.declaration;
// Early exit if not single argument
if (defineConfigCall.arguments.length !== 1) {
return { success: false, wasConverted: false };
}
const arg = defineConfigCall.arguments[0];
if (arg.type === 'ObjectExpression') {
configObj = arg;
// Convert to function form
const arrowFunction = b.arrowFunctionExpression([b.identifier('config')], configObj);
defineConfigCall.arguments[0] = arrowFunction;
wasConverted = true;
}
else if (arg.type === 'ArrowFunctionExpression' ||
arg.type === 'FunctionExpression') {
configObj = extractFromFunctionBody(arg.body);
}
}
if (!configObj) {
return { success: false, wasConverted };
}
const pluginsProp = (0, ast_utils_1.findProperty)(configObj, 'plugins');
const sentryPluginCall = createSentryPluginCall(orgSlug, projectSlug);
if (!pluginsProp) {
configObj.properties.push(b.objectProperty(b.identifier('plugins'), b.arrayExpression([sentryPluginCall])));
}
else if (pluginsProp.value.type === 'ArrayExpression' &&
pluginsProp.type === 'ObjectProperty') {
const arrayExpr = pluginsProp.value;
// Defensive: ensure elements array exists
if (!arrayExpr.elements) {
arrayExpr.elements = [];
}
arrayExpr.elements.push(sentryPluginCall);
}
else {
return { success: false, wasConverted };
}
return { success: true, wasConverted };
}
exports.addReactRouterPluginToViteConfig = addReactRouterPluginToViteConfig;
async function instrumentViteConfig(orgSlug, projectSlug) {
const configPath = fs.existsSync(path.join(process.cwd(), 'vite.config.ts'))
? path.join(process.cwd(), 'vite.config.ts')
: path.join(process.cwd(), 'vite.config.js');
if (!fs.existsSync(configPath)) {
throw new Error('Could not find vite.config.ts or vite.config.js');
}
const configContent = await fs.promises.readFile(configPath, 'utf-8');
const filename = chalk_1.default.cyan(path.basename(configPath));
const mod = (0, magicast_1.parseModule)(configContent);
if ((0, ast_utils_1.hasSentryContent)(mod.$ast)) {
prompts_1.default.log.info(`${filename} already contains sentryReactRouter plugin.`);
return { wasConverted: false };
}
mod.imports.$add({
from: '@sentry/react-router',
imported: 'sentryReactRouter',
local: 'sentryReactRouter',
});
const { success, wasConverted } = addReactRouterPluginToViteConfig(mod.$ast, orgSlug, projectSlug);
if (!success) {
throw new Error('Failed to modify Vite config structure');
}
const code = (0, magicast_1.generateCode)(mod.$ast).code;
await fs.promises.writeFile(configPath, code);
return { wasConverted };
}
exports.instrumentViteConfig = instrumentViteConfig;
//# sourceMappingURL=vite.js.map