UNPKG

@sentry/wizard

Version:

Sentry wizard helping you to configure your project

231 lines 10.9 kB
"use strict"; 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.getDevDependenciesLocation = exports.getDependenciesLocation = exports.getLastImportLineLocation = exports.patchMainContent = exports.patchMain = exports.addProperties = exports.patchPubspec = exports.findFile = void 0; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const Sentry = __importStar(require("@sentry/node")); // @ts-expect-error - clack is ESM and TS complains about that. It works though const clack = __importStar(require("@clack/prompts")); const chalk_1 = __importDefault(require("chalk")); const templates_1 = require("./templates"); const clack_1 = require("../utils/clack"); /** * Recursively finds a file per name in subfolders. * @param dir - The directory to start searching. * @param name - The name of the file including path extension. * @returns The path to the main.dart file or null if not found. */ function findFile(dir, name) { const files = fs.readdirSync(dir); for (const file of files) { const fullPath = path.join(dir, file); const stats = fs.statSync(fullPath); if (stats.isDirectory()) { const result = findFile(fullPath, name); if (result) { return result; } } else if (file === name) { return fullPath; } } return null; } exports.findFile = findFile; function patchPubspec(pubspecFile, sentryDartFlutterVersion, sentryDartPluginVersion, project, org) { try { if (!pubspecFile) { throw new Error('pubspec.yaml is not provided or invalid.'); } let pubspecContent = fs.readFileSync(pubspecFile, 'utf8'); if (!pubspecContent.includes('sentry_flutter:')) { const dependenciesIndex = getDependenciesLocation(pubspecContent); pubspecContent = pubspecContent.slice(0, dependenciesIndex) + ` sentry_flutter: ${sentryDartFlutterVersion}\n` + pubspecContent.slice(dependenciesIndex); clack.log.success(chalk_1.default.greenBright(`${chalk_1.default.bold('sentry_flutter')} added to pubspec.yaml`)); } else { clack.log.success(chalk_1.default.greenBright(`${chalk_1.default.bold('sentry_flutter')} is already included in pubspec.yaml`)); } if (!pubspecContent.includes('sentry_dart_plugin:')) { const devDependenciesIndex = getDevDependenciesLocation(pubspecContent); pubspecContent = pubspecContent.slice(0, devDependenciesIndex) + ` sentry_dart_plugin: ${sentryDartPluginVersion}\n` + pubspecContent.slice(devDependenciesIndex); clack.log.success(chalk_1.default.greenBright(`${chalk_1.default.bold('sentry_dart_plugin')} added to pubspec.yaml`)); } else { clack.log.success(chalk_1.default.greenBright(`${chalk_1.default.bold('sentry_dart_plugin')} is already included in pubspec.yaml`)); } if (!pubspecContent.includes('sentry:')) { pubspecContent += '\n'; pubspecContent += (0, templates_1.pubspecOptions)(project, org); clack.log.success(chalk_1.default.greenBright(`${chalk_1.default.bold('sentry plugin configuration')} added to pubspec.yaml`)); } else { clack.log.success(chalk_1.default.greenBright(`${chalk_1.default.bold('sentry plugin configuration')} is already included in pubspec.yaml`)); } fs.writeFileSync(pubspecFile, pubspecContent, 'utf8'); return true; } catch (error) { clack.log.warn(`Failed to read/write ${chalk_1.default.cyan('pubspec.yaml')} file.`); Sentry.captureException(error); return false; } } exports.patchPubspec = patchPubspec; function addProperties(pubspecFile, authToken) { try { if (!pubspecFile) { throw new Error('pubspec.yaml is not provided or invalid.'); } const pubspecDir = path.dirname(pubspecFile); const sentryPropertiesFileName = 'sentry.properties'; const sentryPropertiesFile = path.join(pubspecDir, sentryPropertiesFileName); const sentryPropertiesContent = (0, templates_1.sentryProperties)(authToken); fs.writeFileSync(sentryPropertiesFile, sentryPropertiesContent, 'utf8'); const gitignoreFile = path.join(pubspecDir, '.gitignore'); if (fs.existsSync(gitignoreFile)) { fs.appendFileSync(gitignoreFile, `\n${sentryPropertiesFileName}\n`); } else { fs.writeFileSync(gitignoreFile, `${sentryPropertiesFileName}\n`, 'utf8'); } return true; } catch (error) { clack.log.warn(`Failed to read/write ${chalk_1.default.cyan('pubspec.yaml')} file.`); Sentry.captureException(error); return false; } } exports.addProperties = addProperties; async function patchMain(mainFile, dsn, canEnableProfiling) { try { if (!mainFile) { throw new Error('pubspec.yaml is not provided or invalid.'); } let mainContent = fs.readFileSync(mainFile, 'utf8'); if (/import\s+['"]package[:]sentry_flutter\/sentry_flutter\.dart['"];?/i.test(mainContent)) { // sentry is already configured clack.log.success(chalk_1.default.greenBright(`${chalk_1.default.bold('main.dart')} already has Sentry configured.`)); return true; } const features = [ { id: 'tracing', prompt: `Do you want to enable ${chalk_1.default.bold('Tracing')} to track the performance of your application?`, enabledHint: 'recommended', }, ]; if (canEnableProfiling) { features.push({ id: 'profiling', prompt: `Do you want to enable ${chalk_1.default.bold('Profiling')} to analyze CPU usage and optimize performance-critical code on iOS & macOS?`, enabledHint: 'recommended, tracing must be enabled', }); } features.push({ id: 'replay', prompt: `Do you want to enable ${chalk_1.default.bold('Session Replay')} to record user interactions and debug issues?`, enabledHint: 'recommended', }); features.push({ id: 'logs', prompt: `Do you want to enable ${chalk_1.default.bold('Logs')} to send your application logs to Sentry?`, enabledHint: 'optional', }); const selectedFeatures = await (0, clack_1.featureSelectionPrompt)(features); const normalizedSelectedFeatures = { tracing: selectedFeatures.tracing ?? false, profiling: selectedFeatures.profiling ?? false, replay: selectedFeatures.replay ?? false, logs: selectedFeatures.logs ?? false, }; mainContent = patchMainContent(dsn, mainContent, normalizedSelectedFeatures); if (normalizedSelectedFeatures.replay) { clack.log.info(`Session Replay will be enabled with default settings (replaysSessionSampleRate: ${templates_1.sessionReplaySampleRate}, replaysOnErrorSampleRate: ${templates_1.sessionReplayOnErrorSampleRate}).`); clack.log.message('By default, all text content, images, and webviews will be masked for privacy. You can customize this in your code later.'); } fs.writeFileSync(mainFile, mainContent, 'utf8'); clack.log.success(chalk_1.default.greenBright(`Patched ${chalk_1.default.bold('main.dart')} with the Sentry setup and test error snippet.`)); return true; } catch (error) { clack.log.warn(`Failed to read/write ${chalk_1.default.cyan('main.dart')} file.`); Sentry.captureException(error); return false; } } exports.patchMain = patchMain; function patchMainContent(dsn, mainContent, selectedFeatures) { const importIndex = getLastImportLineLocation(mainContent); mainContent = mainContent.slice(0, importIndex) + templates_1.sentryImport + mainContent.slice(importIndex); // Find and replace `runApp(...)` mainContent = mainContent.replace(/runApp\(([\s\S]*?)\);/g, // Match the `runApp(...)` invocation (_, runAppArgs) => (0, templates_1.initSnippet)(dsn, selectedFeatures, runAppArgs)); // Make the `main` function async if it's not already mainContent = mainContent.replace(/void\s+main\(\)\s*\{/g, 'Future<void> main() async {'); return mainContent; } exports.patchMainContent = patchMainContent; function getLastImportLineLocation(sourceCode) { const importRegex = /import\s+['"].*['"].*;/gim; return getLastReqExpLocation(sourceCode, importRegex); } exports.getLastImportLineLocation = getLastImportLineLocation; function getDependenciesLocation(sourceCode) { const dependencyRegex = /^dependencies:\s*$/gim; return getLastReqExpLocation(sourceCode, dependencyRegex); } exports.getDependenciesLocation = getDependenciesLocation; function getDevDependenciesLocation(sourceCode) { const dependencyRegex = /^dev_dependencies:\s*$/gim; return getLastReqExpLocation(sourceCode, dependencyRegex); } exports.getDevDependenciesLocation = getDevDependenciesLocation; // Helper function getLastReqExpLocation(sourceCode, regExp) { let match = regExp.exec(sourceCode); let importIndex = 0; while (match) { importIndex = match.index + match[0].length + 1; match = regExp.exec(sourceCode); } return importIndex; } //# sourceMappingURL=code-tools.js.map