@sentry/wizard 6.1.2 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/e2e-tests/tests/flutter.test.js +16 -2
  3. package/dist/e2e-tests/tests/flutter.test.js.map +1 -1
  4. package/dist/e2e-tests/tests/remix.test.js +3 -2
  5. package/dist/e2e-tests/tests/remix.test.js.map +1 -1
  6. package/dist/lib/Steps/Integrations/Electron.js +4 -0
  7. package/dist/lib/Steps/Integrations/Electron.js.map +1 -1
  8. package/dist/src/apple/apple-wizard.js +10 -0
  9. package/dist/src/apple/apple-wizard.js.map +1 -1
  10. package/dist/src/apple/code-tools.d.ts +1 -1
  11. package/dist/src/apple/code-tools.js +3 -3
  12. package/dist/src/apple/code-tools.js.map +1 -1
  13. package/dist/src/apple/inject-code-snippet.d.ts +2 -1
  14. package/dist/src/apple/inject-code-snippet.js +2 -2
  15. package/dist/src/apple/inject-code-snippet.js.map +1 -1
  16. package/dist/src/apple/templates.d.ts +2 -2
  17. package/dist/src/apple/templates.js +22 -6
  18. package/dist/src/apple/templates.js.map +1 -1
  19. package/dist/src/flutter/code-tools.d.ts +1 -0
  20. package/dist/src/flutter/code-tools.js +6 -0
  21. package/dist/src/flutter/code-tools.js.map +1 -1
  22. package/dist/src/flutter/templates.d.ts +1 -0
  23. package/dist/src/flutter/templates.js +5 -0
  24. package/dist/src/flutter/templates.js.map +1 -1
  25. package/dist/src/nextjs/nextjs-wizard.js +11 -7
  26. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  27. package/dist/src/nextjs/utils.d.ts +8 -0
  28. package/dist/src/nextjs/utils.js +36 -1
  29. package/dist/src/nextjs/utils.js.map +1 -1
  30. package/dist/src/react-native/expo-metro.d.ts +2 -2
  31. package/dist/src/react-native/expo-metro.js +32 -27
  32. package/dist/src/react-native/expo-metro.js.map +1 -1
  33. package/dist/src/react-native/metro.d.ts +4 -4
  34. package/dist/src/react-native/metro.js +39 -17
  35. package/dist/src/react-native/metro.js.map +1 -1
  36. package/dist/src/remix/codemods/root.d.ts +1 -0
  37. package/dist/src/remix/codemods/root.js +30 -2
  38. package/dist/src/remix/codemods/root.js.map +1 -1
  39. package/dist/src/version.d.ts +1 -1
  40. package/dist/src/version.js +1 -1
  41. package/dist/src/version.js.map +1 -1
  42. package/dist/test/apple/code-tools.test.js +62 -14
  43. package/dist/test/apple/code-tools.test.js.map +1 -1
  44. package/dist/test/apple/templates.test.js +68 -2
  45. package/dist/test/apple/templates.test.js.map +1 -1
  46. package/dist/test/flutter/code-tools.test.js +1 -0
  47. package/dist/test/flutter/code-tools.test.js.map +1 -1
  48. package/dist/test/flutter/templates.test.js +28 -1
  49. package/dist/test/flutter/templates.test.js.map +1 -1
  50. package/dist/test/nextjs/wizard-double-wrap-prevention.test.d.ts +1 -0
  51. package/dist/test/nextjs/wizard-double-wrap-prevention.test.js +266 -0
  52. package/dist/test/nextjs/wizard-double-wrap-prevention.test.js.map +1 -0
  53. package/dist/test/react-native/expo-metro.test.js +3 -3
  54. package/dist/test/react-native/expo-metro.test.js.map +1 -1
  55. package/dist/test/react-native/metro.test.js +73 -15
  56. package/dist/test/react-native/metro.test.js.map +1 -1
  57. package/dist/test/remix/root.test.js +226 -0
  58. package/dist/test/remix/root.test.js.map +1 -1
  59. package/package.json +1 -9
@@ -38,49 +38,54 @@ const metro_1 = require("./metro");
38
38
  const recast = __importStar(require("recast"));
39
39
  const b = recast.types.builders;
40
40
  async function addSentryToExpoMetroConfig() {
41
- if (!fs.existsSync(metro_1.metroConfigPath)) {
42
- const success = await createSentryExpoMetroConfig();
41
+ let metroConfigPath = (0, metro_1.findMetroConfigPath)();
42
+ if (!metroConfigPath) {
43
+ // No existing metro config found, create metro.config.js (Expo default)
44
+ metroConfigPath = 'metro.config.js';
45
+ }
46
+ if (!fs.existsSync(metroConfigPath)) {
47
+ const success = await createSentryExpoMetroConfig(metroConfigPath);
43
48
  if (!success) {
44
49
  Sentry.setTag('expo-metro-config', 'create-new-error');
45
- return await showInstructions();
50
+ return await showInstructions(metroConfigPath);
46
51
  }
47
52
  Sentry.setTag('expo-metro-config', 'created-new');
48
53
  return undefined;
49
54
  }
50
55
  Sentry.setTag('expo-metro-config', 'exists');
51
- clack.log.info(`Updating existing ${metro_1.metroConfigPath}.`);
52
- const mod = await (0, metro_1.parseMetroConfig)();
56
+ clack.log.info(`Updating existing ${metroConfigPath}.`);
57
+ const mod = await (0, metro_1.parseMetroConfig)(metroConfigPath);
53
58
  if (!mod) {
54
- return await showInstructions();
59
+ return await showInstructions(metroConfigPath);
55
60
  }
56
61
  let didPatch = false;
57
62
  try {
58
- didPatch = patchMetroInMemory(mod);
63
+ didPatch = patchMetroInMemory(mod, metroConfigPath);
59
64
  }
60
65
  catch (e) {
61
66
  Sentry.captureException('Unable to patch expo metro config');
62
67
  }
63
68
  if (!didPatch) {
64
69
  Sentry.setTag('expo-metro-config', 'patch-error');
65
- clack.log.error(`Could not patch ${chalk_1.default.cyan(metro_1.metroConfigPath)} with Sentry configuration.`);
66
- return await showInstructions();
70
+ clack.log.error(`Could not patch ${chalk_1.default.cyan(metroConfigPath)} with Sentry configuration.`);
71
+ return await showInstructions(metroConfigPath);
67
72
  }
68
- const saved = await (0, metro_1.writeMetroConfig)(mod);
73
+ const saved = await (0, metro_1.writeMetroConfig)(mod, metroConfigPath);
69
74
  if (saved) {
70
75
  Sentry.setTag('expo-metro-config', 'patch-saved');
71
- clack.log.success(chalk_1.default.green(`${chalk_1.default.cyan(metro_1.metroConfigPath)} changes saved.`));
76
+ clack.log.success(chalk_1.default.green(`${chalk_1.default.cyan(metroConfigPath)} changes saved.`));
72
77
  }
73
78
  else {
74
79
  Sentry.setTag('expo-metro-config', 'patch-save-error');
75
- clack.log.error(`Could not save changes to ${chalk_1.default.cyan(metro_1.metroConfigPath)}, please follow the manual steps.`);
76
- return await showInstructions();
80
+ clack.log.error(`Could not save changes to ${chalk_1.default.cyan(metroConfigPath)}, please follow the manual steps.`);
81
+ return await showInstructions(metroConfigPath);
77
82
  }
78
83
  }
79
84
  exports.addSentryToExpoMetroConfig = addSentryToExpoMetroConfig;
80
- function patchMetroInMemory(mod) {
85
+ function patchMetroInMemory(mod, metroConfigPath) {
81
86
  const ast = mod.$ast;
82
87
  if ((0, ast_utils_1.hasSentryContent)(ast)) {
83
- clack.log.warn(`The ${chalk_1.default.cyan(metro_1.metroConfigPath)} file already has Sentry configuration.`);
88
+ clack.log.warn(`The ${chalk_1.default.cyan(metroConfigPath)} file already has Sentry configuration.`);
84
89
  return false;
85
90
  }
86
91
  let didReplaceDefaultConfigCall = false;
@@ -125,14 +130,14 @@ function patchMetroInMemory(mod) {
125
130
  },
126
131
  });
127
132
  if (!didReplaceDefaultConfigCall) {
128
- clack.log.warn(`Could not find \`getDefaultConfig\` in ${chalk_1.default.cyan(metro_1.metroConfigPath)}.`);
133
+ clack.log.warn(`Could not find \`getDefaultConfig\` in ${chalk_1.default.cyan(metroConfigPath)}.`);
129
134
  return false;
130
135
  }
131
- addSentryExpoConfigRequire(ast);
136
+ addSentryExpoConfigRequire(ast, metroConfigPath);
132
137
  return true;
133
138
  }
134
139
  exports.patchMetroInMemory = patchMetroInMemory;
135
- function addSentryExpoConfigRequire(program) {
140
+ function addSentryExpoConfigRequire(program, metroConfigPath) {
136
141
  try {
137
142
  const lastRequireIndex = (0, ast_utils_1.getLastRequireIndex)(program);
138
143
  const sentryExpoConfigRequire = createSentryExpoConfigRequire();
@@ -140,8 +145,8 @@ function addSentryExpoConfigRequire(program) {
140
145
  program.body.splice(lastRequireIndex + 1, 0, sentryExpoConfigRequire);
141
146
  }
142
147
  catch (error) {
143
- clack.log.error(`Could not add Sentry Expo config require statement to ${chalk_1.default.cyan(metro_1.metroConfigPath)}.`);
144
- Sentry.captureException(`Could not add Sentry Expo config require statement to ${metro_1.metroConfigPath}.`);
148
+ clack.log.error(`Could not add Sentry Expo config require statement to ${chalk_1.default.cyan(metroConfigPath)}.`);
149
+ Sentry.captureException(`Could not add Sentry Expo config require statement to ${metroConfigPath}.`);
145
150
  }
146
151
  }
147
152
  exports.addSentryExpoConfigRequire = addSentryExpoConfigRequire;
@@ -161,7 +166,7 @@ function createSentryExpoConfigRequire() {
161
166
  ])),
162
167
  ]);
163
168
  }
164
- async function createSentryExpoMetroConfig() {
169
+ async function createSentryExpoMetroConfig(metroConfigPath) {
165
170
  const snippet = `const { getSentryExpoConfig } = require("@sentry/react-native/metro");
166
171
 
167
172
  const config = getSentryExpoConfig(__dirname);
@@ -169,19 +174,19 @@ const config = getSentryExpoConfig(__dirname);
169
174
  module.exports = config;
170
175
  `;
171
176
  try {
172
- await fs.promises.writeFile(metro_1.metroConfigPath, snippet);
177
+ await fs.promises.writeFile(metroConfigPath, snippet);
173
178
  }
174
179
  catch (e) {
175
- clack.log.error(`Could not create ${chalk_1.default.cyan(metro_1.metroConfigPath)} with Sentry configuration.`);
176
- Sentry.captureException(`Could not create ${metro_1.metroConfigPath} with Sentry configuration.`);
180
+ clack.log.error(`Could not create ${chalk_1.default.cyan(metroConfigPath)} with Sentry configuration.`);
181
+ Sentry.captureException(`Could not create ${metroConfigPath} with Sentry configuration.`);
177
182
  return false;
178
183
  }
179
- clack.log.success(`Created ${chalk_1.default.cyan(metro_1.metroConfigPath)} with Sentry configuration.`);
184
+ clack.log.success(`Created ${chalk_1.default.cyan(metroConfigPath)} with Sentry configuration.`);
180
185
  return true;
181
186
  }
182
- function showInstructions() {
187
+ function showInstructions(metroConfigPath) {
183
188
  return (0, clack_1.showCopyPasteInstructions)({
184
- filename: metro_1.metroConfigPath,
189
+ filename: metroConfigPath,
185
190
  codeSnippet: getMetroWithSentryExpoConfigSnippet(true),
186
191
  });
187
192
  }
@@ -1 +1 @@
1
- {"version":3,"file":"expo-metro.js","sourceRoot":"","sources":["../../../src/react-native/expo-metro.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\n// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport * as clack from '@clack/prompts';\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport type { ProxifiedModule } from 'magicast';\nimport chalk from 'chalk';\nimport * as Sentry from '@sentry/node';\n\nimport { getLastRequireIndex, hasSentryContent } from '../utils/ast-utils';\nimport { makeCodeSnippet, showCopyPasteInstructions } from '../utils/clack';\n\nimport { metroConfigPath, parseMetroConfig, writeMetroConfig } from './metro';\n\nimport * as recast from 'recast';\nimport x = recast.types;\nimport t = x.namedTypes;\n\nconst b = recast.types.builders;\n\nexport async function addSentryToExpoMetroConfig() {\n if (!fs.existsSync(metroConfigPath)) {\n const success = await createSentryExpoMetroConfig();\n if (!success) {\n Sentry.setTag('expo-metro-config', 'create-new-error');\n return await showInstructions();\n }\n Sentry.setTag('expo-metro-config', 'created-new');\n return undefined;\n }\n\n Sentry.setTag('expo-metro-config', 'exists');\n clack.log.info(`Updating existing ${metroConfigPath}.`);\n\n const mod = await parseMetroConfig();\n if (!mod) {\n return await showInstructions();\n }\n\n let didPatch = false;\n try {\n didPatch = patchMetroInMemory(mod);\n } catch (e) {\n Sentry.captureException('Unable to patch expo metro config');\n }\n if (!didPatch) {\n Sentry.setTag('expo-metro-config', 'patch-error');\n clack.log.error(\n `Could not patch ${chalk.cyan(\n metroConfigPath,\n )} with Sentry configuration.`,\n );\n return await showInstructions();\n }\n\n const saved = await writeMetroConfig(mod);\n if (saved) {\n Sentry.setTag('expo-metro-config', 'patch-saved');\n clack.log.success(\n chalk.green(`${chalk.cyan(metroConfigPath)} changes saved.`),\n );\n } else {\n Sentry.setTag('expo-metro-config', 'patch-save-error');\n clack.log.error(\n `Could not save changes to ${chalk.cyan(\n metroConfigPath,\n )}, please follow the manual steps.`,\n );\n return await showInstructions();\n }\n}\n\nexport function patchMetroInMemory(mod: ProxifiedModule): boolean {\n const ast = mod.$ast as t.Program;\n\n if (hasSentryContent(ast)) {\n clack.log.warn(\n `The ${chalk.cyan(\n metroConfigPath,\n )} file already has Sentry configuration.`,\n );\n return false;\n }\n\n let didReplaceDefaultConfigCall = false;\n\n recast.visit(ast, {\n visitVariableDeclaration(path) {\n const { node } = path;\n\n if (\n // path is require(\"expo/metro-config\")\n // and only getDefaultConfig is being destructured\n // then remove the entire declaration\n node.declarations.length > 0 &&\n node.declarations[0].type === 'VariableDeclarator' &&\n node.declarations[0].init &&\n node.declarations[0].init.type === 'CallExpression' &&\n node.declarations[0].init.callee &&\n node.declarations[0].init.callee.type === 'Identifier' &&\n node.declarations[0].init.callee.name === 'require' &&\n node.declarations[0].init.arguments[0].type === 'StringLiteral' &&\n node.declarations[0].init.arguments[0].value === 'expo/metro-config' &&\n node.declarations[0].id.type === 'ObjectPattern' &&\n node.declarations[0].id.properties.length === 1 &&\n node.declarations[0].id.properties[0].type === 'ObjectProperty' &&\n node.declarations[0].id.properties[0].key.type === 'Identifier' &&\n node.declarations[0].id.properties[0].key.name === 'getDefaultConfig'\n ) {\n path.prune();\n return false;\n }\n\n this.traverse(path);\n },\n\n visitCallExpression(path) {\n const { node } = path;\n if (\n // path is getDefaultConfig\n // then rename it to getSentryExpoConfig\n node.callee.type === 'Identifier' &&\n node.callee.name === 'getDefaultConfig'\n ) {\n node.callee.name = 'getSentryExpoConfig';\n didReplaceDefaultConfigCall = true;\n return false;\n }\n\n this.traverse(path);\n },\n });\n\n if (!didReplaceDefaultConfigCall) {\n clack.log.warn(\n `Could not find \\`getDefaultConfig\\` in ${chalk.cyan(metroConfigPath)}.`,\n );\n return false;\n }\n\n addSentryExpoConfigRequire(ast);\n\n return true;\n}\n\nexport function addSentryExpoConfigRequire(program: t.Program) {\n try {\n const lastRequireIndex = getLastRequireIndex(program);\n const sentryExpoConfigRequire = createSentryExpoConfigRequire();\n\n // Add the require statement after the last require or at the beginning\n program.body.splice(lastRequireIndex + 1, 0, sentryExpoConfigRequire);\n } catch (error) {\n clack.log.error(\n `Could not add Sentry Expo config require statement to ${chalk.cyan(\n metroConfigPath,\n )}.`,\n );\n Sentry.captureException(\n `Could not add Sentry Expo config require statement to ${metroConfigPath}.`,\n );\n }\n}\n\n/**\n * Creates const { getSentryExpoConfig } = require(\"@sentry/react-native/metro\");\n */\nfunction createSentryExpoConfigRequire() {\n return b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern([\n b.objectProperty.from({\n key: b.identifier('getSentryExpoConfig'),\n value: b.identifier('getSentryExpoConfig'),\n shorthand: true,\n }),\n ]),\n b.callExpression(b.identifier('require'), [\n b.literal('@sentry/react-native/metro'),\n ]),\n ),\n ]);\n}\n\nasync function createSentryExpoMetroConfig(): Promise<boolean> {\n const snippet = `const { getSentryExpoConfig } = require(\"@sentry/react-native/metro\");\n\nconst config = getSentryExpoConfig(__dirname);\n\nmodule.exports = config;\n`;\n try {\n await fs.promises.writeFile(metroConfigPath, snippet);\n } catch (e) {\n clack.log.error(\n `Could not create ${chalk.cyan(\n metroConfigPath,\n )} with Sentry configuration.`,\n );\n Sentry.captureException(\n `Could not create ${metroConfigPath} with Sentry configuration.`,\n );\n return false;\n }\n clack.log.success(\n `Created ${chalk.cyan(metroConfigPath)} with Sentry configuration.`,\n );\n return true;\n}\n\nfunction showInstructions() {\n return showCopyPasteInstructions({\n filename: metroConfigPath,\n codeSnippet: getMetroWithSentryExpoConfigSnippet(true),\n });\n}\n\nfunction getMetroWithSentryExpoConfigSnippet(colors: boolean): string {\n return makeCodeSnippet(colors, (unchanged, plus, minus) =>\n unchanged(`${minus(\n `// const { getDefaultConfig } = require(\"expo/metro-config\");`,\n )}\n${plus(\n `const { getSentryExpoConfig } = require(\"@sentry/react-native/metro\");`,\n)}\n\n${minus(`// const config = getDefaultConfig(__dirname);`)}\n${plus(`const config = getSentryExpoConfig(__dirname);`)}\n\nmodule.exports = config;`),\n );\n}\n"]}
1
+ {"version":3,"file":"expo-metro.js","sourceRoot":"","sources":["../../../src/react-native/expo-metro.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\n// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport * as clack from '@clack/prompts';\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport type { ProxifiedModule } from 'magicast';\nimport chalk from 'chalk';\nimport * as Sentry from '@sentry/node';\n\nimport { getLastRequireIndex, hasSentryContent } from '../utils/ast-utils';\nimport { makeCodeSnippet, showCopyPasteInstructions } from '../utils/clack';\n\nimport {\n findMetroConfigPath,\n parseMetroConfig,\n writeMetroConfig,\n} from './metro';\n\nimport * as recast from 'recast';\nimport x = recast.types;\nimport t = x.namedTypes;\n\nconst b = recast.types.builders;\n\nexport async function addSentryToExpoMetroConfig() {\n let metroConfigPath = findMetroConfigPath();\n\n if (!metroConfigPath) {\n // No existing metro config found, create metro.config.js (Expo default)\n metroConfigPath = 'metro.config.js';\n }\n\n if (!fs.existsSync(metroConfigPath)) {\n const success = await createSentryExpoMetroConfig(metroConfigPath);\n if (!success) {\n Sentry.setTag('expo-metro-config', 'create-new-error');\n return await showInstructions(metroConfigPath);\n }\n Sentry.setTag('expo-metro-config', 'created-new');\n return undefined;\n }\n\n Sentry.setTag('expo-metro-config', 'exists');\n clack.log.info(`Updating existing ${metroConfigPath}.`);\n\n const mod = await parseMetroConfig(metroConfigPath);\n if (!mod) {\n return await showInstructions(metroConfigPath);\n }\n\n let didPatch = false;\n try {\n didPatch = patchMetroInMemory(mod, metroConfigPath);\n } catch (e) {\n Sentry.captureException('Unable to patch expo metro config');\n }\n if (!didPatch) {\n Sentry.setTag('expo-metro-config', 'patch-error');\n clack.log.error(\n `Could not patch ${chalk.cyan(\n metroConfigPath,\n )} with Sentry configuration.`,\n );\n return await showInstructions(metroConfigPath);\n }\n\n const saved = await writeMetroConfig(mod, metroConfigPath);\n if (saved) {\n Sentry.setTag('expo-metro-config', 'patch-saved');\n clack.log.success(\n chalk.green(`${chalk.cyan(metroConfigPath)} changes saved.`),\n );\n } else {\n Sentry.setTag('expo-metro-config', 'patch-save-error');\n clack.log.error(\n `Could not save changes to ${chalk.cyan(\n metroConfigPath,\n )}, please follow the manual steps.`,\n );\n return await showInstructions(metroConfigPath);\n }\n}\n\nexport function patchMetroInMemory(\n mod: ProxifiedModule,\n metroConfigPath: string,\n): boolean {\n const ast = mod.$ast as t.Program;\n\n if (hasSentryContent(ast)) {\n clack.log.warn(\n `The ${chalk.cyan(\n metroConfigPath,\n )} file already has Sentry configuration.`,\n );\n return false;\n }\n\n let didReplaceDefaultConfigCall = false;\n\n recast.visit(ast, {\n visitVariableDeclaration(path) {\n const { node } = path;\n\n if (\n // path is require(\"expo/metro-config\")\n // and only getDefaultConfig is being destructured\n // then remove the entire declaration\n node.declarations.length > 0 &&\n node.declarations[0].type === 'VariableDeclarator' &&\n node.declarations[0].init &&\n node.declarations[0].init.type === 'CallExpression' &&\n node.declarations[0].init.callee &&\n node.declarations[0].init.callee.type === 'Identifier' &&\n node.declarations[0].init.callee.name === 'require' &&\n node.declarations[0].init.arguments[0].type === 'StringLiteral' &&\n node.declarations[0].init.arguments[0].value === 'expo/metro-config' &&\n node.declarations[0].id.type === 'ObjectPattern' &&\n node.declarations[0].id.properties.length === 1 &&\n node.declarations[0].id.properties[0].type === 'ObjectProperty' &&\n node.declarations[0].id.properties[0].key.type === 'Identifier' &&\n node.declarations[0].id.properties[0].key.name === 'getDefaultConfig'\n ) {\n path.prune();\n return false;\n }\n\n this.traverse(path);\n },\n\n visitCallExpression(path) {\n const { node } = path;\n if (\n // path is getDefaultConfig\n // then rename it to getSentryExpoConfig\n node.callee.type === 'Identifier' &&\n node.callee.name === 'getDefaultConfig'\n ) {\n node.callee.name = 'getSentryExpoConfig';\n didReplaceDefaultConfigCall = true;\n return false;\n }\n\n this.traverse(path);\n },\n });\n\n if (!didReplaceDefaultConfigCall) {\n clack.log.warn(\n `Could not find \\`getDefaultConfig\\` in ${chalk.cyan(metroConfigPath)}.`,\n );\n return false;\n }\n\n addSentryExpoConfigRequire(ast, metroConfigPath);\n\n return true;\n}\n\nexport function addSentryExpoConfigRequire(\n program: t.Program,\n metroConfigPath: string,\n) {\n try {\n const lastRequireIndex = getLastRequireIndex(program);\n const sentryExpoConfigRequire = createSentryExpoConfigRequire();\n\n // Add the require statement after the last require or at the beginning\n program.body.splice(lastRequireIndex + 1, 0, sentryExpoConfigRequire);\n } catch (error) {\n clack.log.error(\n `Could not add Sentry Expo config require statement to ${chalk.cyan(\n metroConfigPath,\n )}.`,\n );\n Sentry.captureException(\n `Could not add Sentry Expo config require statement to ${metroConfigPath}.`,\n );\n }\n}\n\n/**\n * Creates const { getSentryExpoConfig } = require(\"@sentry/react-native/metro\");\n */\nfunction createSentryExpoConfigRequire() {\n return b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern([\n b.objectProperty.from({\n key: b.identifier('getSentryExpoConfig'),\n value: b.identifier('getSentryExpoConfig'),\n shorthand: true,\n }),\n ]),\n b.callExpression(b.identifier('require'), [\n b.literal('@sentry/react-native/metro'),\n ]),\n ),\n ]);\n}\n\nasync function createSentryExpoMetroConfig(\n metroConfigPath: string,\n): Promise<boolean> {\n const snippet = `const { getSentryExpoConfig } = require(\"@sentry/react-native/metro\");\n\nconst config = getSentryExpoConfig(__dirname);\n\nmodule.exports = config;\n`;\n try {\n await fs.promises.writeFile(metroConfigPath, snippet);\n } catch (e) {\n clack.log.error(\n `Could not create ${chalk.cyan(\n metroConfigPath,\n )} with Sentry configuration.`,\n );\n Sentry.captureException(\n `Could not create ${metroConfigPath} with Sentry configuration.`,\n );\n return false;\n }\n clack.log.success(\n `Created ${chalk.cyan(metroConfigPath)} with Sentry configuration.`,\n );\n return true;\n}\n\nfunction showInstructions(metroConfigPath: string) {\n return showCopyPasteInstructions({\n filename: metroConfigPath,\n codeSnippet: getMetroWithSentryExpoConfigSnippet(true),\n });\n}\n\nfunction getMetroWithSentryExpoConfigSnippet(colors: boolean): string {\n return makeCodeSnippet(colors, (unchanged, plus, minus) =>\n unchanged(`${minus(\n `// const { getDefaultConfig } = require(\"expo/metro-config\");`,\n )}\n${plus(\n `const { getSentryExpoConfig } = require(\"@sentry/react-native/metro\");`,\n)}\n\n${minus(`// const config = getDefaultConfig(__dirname);`)}\n${plus(`const config = getSentryExpoConfig(__dirname);`)}\n\nmodule.exports = config;`),\n );\n}\n"]}
@@ -2,11 +2,11 @@ import { ProxifiedModule } from 'magicast';
2
2
  import * as recast from 'recast';
3
3
  import x = recast.types;
4
4
  import t = x.namedTypes;
5
- export declare const metroConfigPath = "metro.config.js";
5
+ export declare function findMetroConfigPath(): string | undefined;
6
6
  export declare function patchMetroWithSentryConfig(): Promise<void>;
7
- export declare function patchMetroWithSentryConfigInMemory(mod: ProxifiedModule, showInstructions: () => Promise<void>): Promise<boolean>;
8
- export declare function parseMetroConfig(): Promise<ProxifiedModule | undefined>;
9
- export declare function writeMetroConfig(mod: ProxifiedModule): Promise<boolean>;
7
+ export declare function patchMetroWithSentryConfigInMemory(mod: ProxifiedModule, metroConfigPath: string, skipInstructions?: boolean): Promise<boolean>;
8
+ export declare function parseMetroConfig(configPath: string): Promise<ProxifiedModule | undefined>;
9
+ export declare function writeMetroConfig(mod: ProxifiedModule, configPath: string): Promise<boolean>;
10
10
  export declare function addSentrySerializerToMetroConfig(configObj: t.ObjectExpression): boolean;
11
11
  export declare function addSentrySerializerRequireToMetroConfig(program: t.Program): boolean;
12
12
  export declare function addSentryMetroRequireToMetroConfig(program: t.Program): boolean;
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.getModuleExportsAssignmentRight = exports.getMetroConfigObject = exports.addSentryMetroRequireToMetroConfig = exports.addSentrySerializerRequireToMetroConfig = exports.addSentrySerializerToMetroConfig = exports.writeMetroConfig = exports.parseMetroConfig = exports.patchMetroWithSentryConfigInMemory = exports.patchMetroWithSentryConfig = exports.metroConfigPath = void 0;
29
+ exports.getModuleExportsAssignmentRight = exports.getMetroConfigObject = exports.addSentryMetroRequireToMetroConfig = exports.addSentrySerializerRequireToMetroConfig = exports.addSentrySerializerToMetroConfig = exports.writeMetroConfig = exports.parseMetroConfig = exports.patchMetroWithSentryConfigInMemory = exports.patchMetroWithSentryConfig = exports.findMetroConfigPath = void 0;
30
30
  // @ts-expect-error - clack is ESM and TS complains about that. It works though
31
31
  const clack = __importStar(require("@clack/prompts"));
32
32
  // @ts-expect-error - magicast is ESM and TS complains about that. It works though
@@ -38,32 +38,54 @@ const clack_1 = require("../utils/clack");
38
38
  const recast = __importStar(require("recast"));
39
39
  const chalk_1 = __importDefault(require("chalk"));
40
40
  const b = recast.types.builders;
41
- exports.metroConfigPath = 'metro.config.js';
41
+ const METRO_CONFIG_FILENAMES = ['metro.config.js', 'metro.config.cjs'];
42
+ function findMetroConfigPath() {
43
+ return METRO_CONFIG_FILENAMES.find((filename) => fs.existsSync(filename));
44
+ }
45
+ exports.findMetroConfigPath = findMetroConfigPath;
42
46
  async function patchMetroWithSentryConfig() {
47
+ const metroConfigPath = findMetroConfigPath();
48
+ if (!metroConfigPath) {
49
+ clack.log.error(`No Metro config file found. Expected: ${METRO_CONFIG_FILENAMES.join(' or ')}`);
50
+ // Fallback to .js for manual instructions
51
+ return await (0, clack_1.showCopyPasteInstructions)({
52
+ filename: 'metro.config.js',
53
+ codeSnippet: getMetroWithSentryConfigSnippet(true),
54
+ });
55
+ }
43
56
  const showInstructions = () => (0, clack_1.showCopyPasteInstructions)({
44
- filename: exports.metroConfigPath,
57
+ filename: metroConfigPath,
45
58
  codeSnippet: getMetroWithSentryConfigSnippet(true),
46
59
  });
47
- const mod = await parseMetroConfig();
60
+ const mod = await parseMetroConfig(metroConfigPath);
48
61
  if (!mod) {
49
- clack.log.error(`Could read from file ${chalk_1.default.cyan(exports.metroConfigPath)}, please follow the manual steps.`);
62
+ clack.log.error(`Could not read from file ${chalk_1.default.cyan(metroConfigPath)}, please follow the manual steps.`);
50
63
  return await showInstructions();
51
64
  }
52
- const success = await patchMetroWithSentryConfigInMemory(mod, showInstructions);
65
+ const success = await patchMetroWithSentryConfigInMemory(mod, metroConfigPath);
53
66
  if (!success) {
54
67
  return;
55
68
  }
56
- const saved = await writeMetroConfig(mod);
69
+ const saved = await writeMetroConfig(mod, metroConfigPath);
57
70
  if (saved) {
58
- clack.log.success(chalk_1.default.green(`${chalk_1.default.cyan(exports.metroConfigPath)} changes saved.`));
71
+ clack.log.success(chalk_1.default.green(`${chalk_1.default.cyan(metroConfigPath)} changes saved.`));
59
72
  }
60
73
  else {
61
- clack.log.warn(`Could not save changes to ${chalk_1.default.cyan(exports.metroConfigPath)}, please follow the manual steps.`);
74
+ clack.log.warn(`Could not save changes to ${chalk_1.default.cyan(metroConfigPath)}, please follow the manual steps.`);
62
75
  return await showInstructions();
63
76
  }
64
77
  }
65
78
  exports.patchMetroWithSentryConfig = patchMetroWithSentryConfig;
66
- async function patchMetroWithSentryConfigInMemory(mod, showInstructions) {
79
+ async function patchMetroWithSentryConfigInMemory(mod, metroConfigPath, skipInstructions = false) {
80
+ const showInstructions = () => {
81
+ if (skipInstructions) {
82
+ return Promise.resolve();
83
+ }
84
+ return (0, clack_1.showCopyPasteInstructions)({
85
+ filename: metroConfigPath,
86
+ codeSnippet: getMetroWithSentryConfigSnippet(true),
87
+ });
88
+ };
67
89
  if ((0, ast_utils_1.hasSentryContent)(mod.$ast)) {
68
90
  const shouldContinue = await confirmPathMetroConfig();
69
91
  if (!shouldContinue) {
@@ -93,28 +115,28 @@ async function patchMetroWithSentryConfigInMemory(mod, showInstructions) {
93
115
  await showInstructions();
94
116
  return false;
95
117
  }
96
- clack.log.success(`Added Sentry Metro plugin to ${chalk_1.default.cyan(exports.metroConfigPath)}.`);
118
+ clack.log.success(`Added Sentry Metro plugin to ${chalk_1.default.cyan(metroConfigPath)}.`);
97
119
  return true;
98
120
  }
99
121
  exports.patchMetroWithSentryConfigInMemory = patchMetroWithSentryConfigInMemory;
100
- async function parseMetroConfig() {
122
+ async function parseMetroConfig(configPath) {
101
123
  try {
102
- const metroConfigContent = (await fs.promises.readFile(exports.metroConfigPath)).toString();
124
+ const metroConfigContent = (await fs.promises.readFile(configPath)).toString();
103
125
  return (0, magicast_1.parseModule)(metroConfigContent);
104
126
  }
105
127
  catch (error) {
106
- clack.log.error(`Could not read Metro config file ${chalk_1.default.cyan(exports.metroConfigPath)}`);
128
+ clack.log.error(`Could not read Metro config file ${chalk_1.default.cyan(configPath)}`);
107
129
  Sentry.captureException('Could not read Metro config file');
108
130
  return undefined;
109
131
  }
110
132
  }
111
133
  exports.parseMetroConfig = parseMetroConfig;
112
- async function writeMetroConfig(mod) {
134
+ async function writeMetroConfig(mod, configPath) {
113
135
  try {
114
- await (0, magicast_1.writeFile)(mod.$ast, exports.metroConfigPath);
136
+ await (0, magicast_1.writeFile)(mod.$ast, configPath);
115
137
  }
116
138
  catch (e) {
117
- clack.log.error(`Failed to write to ${chalk_1.default.cyan(exports.metroConfigPath)}: ${JSON.stringify(e)}`);
139
+ clack.log.error(`Failed to write to ${chalk_1.default.cyan(configPath)}: ${JSON.stringify(e)}`);
118
140
  Sentry.captureException('Failed to write to Metro config file');
119
141
  return false;
120
142
  }
@@ -1 +1 @@
1
- {"version":3,"file":"metro.js","sourceRoot":"","sources":["../../../src/react-native/metro.ts"],"names":[],"mappings":"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","sourcesContent":["// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport * as clack from '@clack/prompts';\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport { ProxifiedModule, parseModule, writeFile } from 'magicast';\nimport * as fs from 'fs';\nimport * as Sentry from '@sentry/node';\n\nimport { getLastRequireIndex, hasSentryContent } from '../utils/ast-utils';\nimport {\n abortIfCancelled,\n makeCodeSnippet,\n showCopyPasteInstructions,\n} from '../utils/clack';\n\nimport * as recast from 'recast';\nimport x = recast.types;\nimport t = x.namedTypes;\nimport chalk from 'chalk';\n\nconst b = recast.types.builders;\n\nexport const metroConfigPath = 'metro.config.js';\n\nexport async function patchMetroWithSentryConfig() {\n const showInstructions = () =>\n showCopyPasteInstructions({\n filename: metroConfigPath,\n codeSnippet: getMetroWithSentryConfigSnippet(true),\n });\n\n const mod = await parseMetroConfig();\n if (!mod) {\n clack.log.error(\n `Could read from file ${chalk.cyan(\n metroConfigPath,\n )}, please follow the manual steps.`,\n );\n return await showInstructions();\n }\n\n const success = await patchMetroWithSentryConfigInMemory(\n mod,\n showInstructions,\n );\n if (!success) {\n return;\n }\n\n const saved = await writeMetroConfig(mod);\n if (saved) {\n clack.log.success(\n chalk.green(`${chalk.cyan(metroConfigPath)} changes saved.`),\n );\n } else {\n clack.log.warn(\n `Could not save changes to ${chalk.cyan(\n metroConfigPath,\n )}, please follow the manual steps.`,\n );\n return await showInstructions();\n }\n}\n\nexport async function patchMetroWithSentryConfigInMemory(\n mod: ProxifiedModule,\n showInstructions: () => Promise<void>,\n): Promise<boolean> {\n if (hasSentryContent(mod.$ast as t.Program)) {\n const shouldContinue = await confirmPathMetroConfig();\n if (!shouldContinue) {\n await showInstructions();\n return false;\n }\n }\n\n const configExpression = getModuleExportsAssignmentRight(\n mod.$ast as t.Program,\n );\n if (!configExpression) {\n clack.log.warn(\n 'Could not find Metro config, please follow the manual steps.',\n );\n Sentry.captureException('Could not find Metro config.');\n await showInstructions();\n return false;\n }\n\n const wrappedConfig = wrapWithSentryConfig(configExpression);\n\n const replacedModuleExportsRight = replaceModuleExportsRight(\n mod.$ast as t.Program,\n wrappedConfig,\n );\n if (!replacedModuleExportsRight) {\n clack.log.warn(\n 'Could not automatically wrap the config export, please follow the manual steps.',\n );\n Sentry.captureException('Could not automatically wrap the config export.');\n await showInstructions();\n return false;\n }\n\n const addedSentryMetroImport = addSentryMetroRequireToMetroConfig(\n mod.$ast as t.Program,\n );\n if (!addedSentryMetroImport) {\n clack.log.warn(\n 'Could not add `@sentry/react-native/metro` import to Metro config, please follow the manual steps.',\n );\n Sentry.captureException(\n 'Could not add `@sentry/react-native/metro` import to Metro config.',\n );\n await showInstructions();\n return false;\n }\n\n clack.log.success(\n `Added Sentry Metro plugin to ${chalk.cyan(metroConfigPath)}.`,\n );\n return true;\n}\n\nexport async function parseMetroConfig(): Promise<ProxifiedModule | undefined> {\n try {\n const metroConfigContent = (\n await fs.promises.readFile(metroConfigPath)\n ).toString();\n\n return parseModule(metroConfigContent);\n } catch (error) {\n clack.log.error(\n `Could not read Metro config file ${chalk.cyan(metroConfigPath)}`,\n );\n Sentry.captureException('Could not read Metro config file');\n return undefined;\n }\n}\n\nexport async function writeMetroConfig(mod: ProxifiedModule): Promise<boolean> {\n try {\n await writeFile(mod.$ast, metroConfigPath);\n } catch (e) {\n clack.log.error(\n `Failed to write to ${chalk.cyan(metroConfigPath)}: ${JSON.stringify(e)}`,\n );\n Sentry.captureException('Failed to write to Metro config file');\n return false;\n }\n return true;\n}\n\nexport function addSentrySerializerToMetroConfig(\n configObj: t.ObjectExpression,\n): boolean {\n const serializerProp = getSerializerProp(configObj);\n if ('invalid' === serializerProp) {\n return false;\n }\n\n // case 1: serializer property doesn't exist yet, so we can just add it\n if ('undefined' === serializerProp) {\n configObj.properties.push(\n b.objectProperty(\n b.identifier('serializer'),\n b.objectExpression([\n b.objectProperty(\n b.identifier('customSerializer'),\n b.callExpression(b.identifier('createSentryMetroSerializer'), []),\n ),\n ]),\n ),\n );\n return true;\n }\n\n const customSerializerProp = getCustomSerializerProp(serializerProp);\n // case 2: serializer.customSerializer property doesn't exist yet, so we just add it\n if (\n 'undefined' === customSerializerProp &&\n serializerProp.value.type === 'ObjectExpression'\n ) {\n serializerProp.value.properties.push(\n b.objectProperty(\n b.identifier('customSerializer'),\n b.callExpression(b.identifier('createSentryMetroSerializer'), []),\n ),\n );\n return true;\n }\n\n return false;\n}\n\nfunction getCustomSerializerProp(\n prop: t.ObjectProperty,\n): t.ObjectProperty | 'undefined' | 'invalid' {\n const customSerializerProp =\n prop.value.type === 'ObjectExpression' &&\n prop.value.properties.find(\n (p: t.ObjectProperty) =>\n p.key.type === 'Identifier' && p.key.name === 'customSerializer',\n );\n\n if (!customSerializerProp) {\n return 'undefined';\n }\n\n if (customSerializerProp.type === 'ObjectProperty') {\n return customSerializerProp;\n }\n\n return 'invalid';\n}\n\nfunction getSerializerProp(\n obj: t.ObjectExpression,\n): t.ObjectProperty | 'undefined' | 'invalid' {\n const serializerProp = obj.properties.find(\n (p: t.ObjectProperty) =>\n p.key.type === 'Identifier' && p.key.name === 'serializer',\n );\n\n if (!serializerProp) {\n return 'undefined';\n }\n\n if (serializerProp.type === 'ObjectProperty') {\n return serializerProp;\n }\n\n return 'invalid';\n}\n\nexport function addSentrySerializerRequireToMetroConfig(\n program: t.Program,\n): boolean {\n const lastRequireIndex = getLastRequireIndex(program);\n const sentrySerializerRequire = createSentrySerializerRequire();\n const sentryImportIndex = lastRequireIndex + 1;\n if (sentryImportIndex < program.body.length) {\n // insert after last require\n program.body.splice(lastRequireIndex + 1, 0, sentrySerializerRequire);\n } else {\n // insert at the beginning\n program.body.unshift(sentrySerializerRequire);\n }\n return true;\n}\n\nexport function addSentryMetroRequireToMetroConfig(\n program: t.Program,\n): boolean {\n const lastRequireIndex = getLastRequireIndex(program);\n const sentryMetroRequire = createSentryMetroRequire();\n const sentryImportIndex = lastRequireIndex + 1;\n if (sentryImportIndex < program.body.length) {\n // insert after last require\n program.body.splice(lastRequireIndex + 1, 0, sentryMetroRequire);\n } else {\n // insert at the beginning\n program.body.unshift(sentryMetroRequire);\n }\n return true;\n}\n\nfunction wrapWithSentryConfig(\n configObj: t.Identifier | t.CallExpression | t.ObjectExpression,\n): t.CallExpression {\n return b.callExpression(b.identifier('withSentryConfig'), [configObj]);\n}\n\nfunction replaceModuleExportsRight(\n program: t.Program,\n wrappedConfig: t.CallExpression,\n): boolean {\n const moduleExports = getModuleExports(program);\n if (!moduleExports) {\n return false;\n }\n\n if (moduleExports.expression.type === 'AssignmentExpression') {\n moduleExports.expression.right = wrappedConfig;\n return true;\n }\n\n return false;\n}\n\n/**\n * Creates const {createSentryMetroSerializer} = require('@sentry/react-native/dist/js/tools/sentryMetroSerializer');\n */\nfunction createSentrySerializerRequire() {\n return b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern([\n b.objectProperty.from({\n key: b.identifier('createSentryMetroSerializer'),\n value: b.identifier('createSentryMetroSerializer'),\n shorthand: true,\n }),\n ]),\n b.callExpression(b.identifier('require'), [\n b.literal('@sentry/react-native/dist/js/tools/sentryMetroSerializer'),\n ]),\n ),\n ]);\n}\n\n/**\n * Creates const {withSentryConfig} = require('@sentry/react-native/metro');\n */\nfunction createSentryMetroRequire() {\n return b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern([\n b.objectProperty.from({\n key: b.identifier('withSentryConfig'),\n value: b.identifier('withSentryConfig'),\n shorthand: true,\n }),\n ]),\n b.callExpression(b.identifier('require'), [\n b.literal('@sentry/react-native/metro'),\n ]),\n ),\n ]);\n}\n\nasync function confirmPathMetroConfig() {\n const shouldContinue = await abortIfCancelled(\n clack.select({\n message: `Metro Config already contains Sentry-related code. Should the wizard modify it anyway?`,\n options: [\n {\n label: 'Yes, add the Sentry Metro plugin',\n value: true,\n },\n {\n label: 'No, show me instructions to manually add the plugin',\n value: false,\n },\n ],\n initialValue: true,\n }),\n );\n\n if (!shouldContinue) {\n Sentry.setTag('ast-mod-fail-reason', 'has-sentry-content');\n }\n\n return shouldContinue;\n}\n\n/**\n * Returns value from `module.exports = value` or `const config = value`\n */\nexport function getMetroConfigObject(\n program: t.Program,\n): t.ObjectExpression | undefined {\n // check config variable\n const configVariable = program.body.find((s) => {\n if (\n s.type === 'VariableDeclaration' &&\n s.declarations.length === 1 &&\n s.declarations[0].type === 'VariableDeclarator' &&\n s.declarations[0].id.type === 'Identifier' &&\n s.declarations[0].id.name === 'config'\n ) {\n return true;\n }\n return false;\n }) as t.VariableDeclaration | undefined;\n\n if (\n configVariable?.declarations[0].type === 'VariableDeclarator' &&\n configVariable?.declarations[0].init?.type === 'ObjectExpression'\n ) {\n Sentry.setTag('metro-config', 'config-variable');\n return configVariable.declarations[0].init;\n }\n\n return getModuleExportsObject(program);\n}\n\nfunction getModuleExportsObject(\n program: t.Program,\n): t.ObjectExpression | undefined {\n // check module.exports\n const moduleExports = getModuleExportsAssignmentRight(program);\n\n if (moduleExports?.type === 'ObjectExpression') {\n return moduleExports;\n }\n\n Sentry.setTag('metro-config', 'not-found');\n return undefined;\n}\n\nexport function getModuleExportsAssignmentRight(\n program: t.Program,\n): t.Identifier | t.CallExpression | t.ObjectExpression | undefined {\n // check module.exports\n const moduleExports = getModuleExports(program);\n\n if (\n moduleExports?.expression.type === 'AssignmentExpression' &&\n (moduleExports.expression.right.type === 'ObjectExpression' ||\n moduleExports.expression.right.type === 'CallExpression' ||\n moduleExports.expression.right.type === 'Identifier')\n ) {\n Sentry.setTag('metro-config', 'module-exports');\n return moduleExports?.expression.right;\n }\n\n Sentry.setTag('metro-config', 'not-found');\n return undefined;\n}\n\nfunction getModuleExports(\n program: t.Program,\n): t.ExpressionStatement | undefined {\n // find module.exports\n return program.body.find((s) => {\n if (\n s.type === 'ExpressionStatement' &&\n s.expression.type === 'AssignmentExpression' &&\n s.expression.left.type === 'MemberExpression' &&\n s.expression.left.object.type === 'Identifier' &&\n s.expression.left.object.name === 'module' &&\n s.expression.left.property.type === 'Identifier' &&\n s.expression.left.property.name === 'exports'\n ) {\n return true;\n }\n return false;\n }) as t.ExpressionStatement | undefined;\n}\n\nfunction getMetroWithSentryConfigSnippet(colors: boolean) {\n return makeCodeSnippet(colors, (unchanged, plus, _) =>\n unchanged(`const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');\";\n${plus(\"const {withSentryConfig} = require('@sentry/react-native/metro');\")}\n\nconst config = {};\n\nmodule.exports = ${plus(\n 'withSentryConfig(',\n )}mergeConfig(getDefaultConfig(__dirname), config)${plus(')')};\n`),\n );\n}\n"]}
1
+ {"version":3,"file":"metro.js","sourceRoot":"","sources":["../../../src/react-native/metro.ts"],"names":[],"mappings":"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","sourcesContent":["// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport * as clack from '@clack/prompts';\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport { ProxifiedModule, parseModule, writeFile } from 'magicast';\nimport * as fs from 'fs';\nimport * as Sentry from '@sentry/node';\n\nimport { getLastRequireIndex, hasSentryContent } from '../utils/ast-utils';\nimport {\n abortIfCancelled,\n makeCodeSnippet,\n showCopyPasteInstructions,\n} from '../utils/clack';\n\nimport * as recast from 'recast';\nimport x = recast.types;\nimport t = x.namedTypes;\nimport chalk from 'chalk';\n\nconst b = recast.types.builders;\n\nconst METRO_CONFIG_FILENAMES = ['metro.config.js', 'metro.config.cjs'];\n\nexport function findMetroConfigPath(): string | undefined {\n return METRO_CONFIG_FILENAMES.find((filename) => fs.existsSync(filename));\n}\n\nexport async function patchMetroWithSentryConfig() {\n const metroConfigPath = findMetroConfigPath();\n\n if (!metroConfigPath) {\n clack.log.error(\n `No Metro config file found. Expected: ${METRO_CONFIG_FILENAMES.join(\n ' or ',\n )}`,\n );\n // Fallback to .js for manual instructions\n return await showCopyPasteInstructions({\n filename: 'metro.config.js',\n codeSnippet: getMetroWithSentryConfigSnippet(true),\n });\n }\n\n const showInstructions = () =>\n showCopyPasteInstructions({\n filename: metroConfigPath,\n codeSnippet: getMetroWithSentryConfigSnippet(true),\n });\n\n const mod = await parseMetroConfig(metroConfigPath);\n if (!mod) {\n clack.log.error(\n `Could not read from file ${chalk.cyan(\n metroConfigPath,\n )}, please follow the manual steps.`,\n );\n return await showInstructions();\n }\n\n const success = await patchMetroWithSentryConfigInMemory(\n mod,\n metroConfigPath,\n );\n if (!success) {\n return;\n }\n\n const saved = await writeMetroConfig(mod, metroConfigPath);\n if (saved) {\n clack.log.success(\n chalk.green(`${chalk.cyan(metroConfigPath)} changes saved.`),\n );\n } else {\n clack.log.warn(\n `Could not save changes to ${chalk.cyan(\n metroConfigPath,\n )}, please follow the manual steps.`,\n );\n return await showInstructions();\n }\n}\n\nexport async function patchMetroWithSentryConfigInMemory(\n mod: ProxifiedModule,\n metroConfigPath: string,\n skipInstructions = false,\n): Promise<boolean> {\n const showInstructions = () => {\n if (skipInstructions) {\n return Promise.resolve();\n }\n return showCopyPasteInstructions({\n filename: metroConfigPath,\n codeSnippet: getMetroWithSentryConfigSnippet(true),\n });\n };\n\n if (hasSentryContent(mod.$ast as t.Program)) {\n const shouldContinue = await confirmPathMetroConfig();\n if (!shouldContinue) {\n await showInstructions();\n return false;\n }\n }\n\n const configExpression = getModuleExportsAssignmentRight(\n mod.$ast as t.Program,\n );\n if (!configExpression) {\n clack.log.warn(\n 'Could not find Metro config, please follow the manual steps.',\n );\n Sentry.captureException('Could not find Metro config.');\n await showInstructions();\n return false;\n }\n\n const wrappedConfig = wrapWithSentryConfig(configExpression);\n\n const replacedModuleExportsRight = replaceModuleExportsRight(\n mod.$ast as t.Program,\n wrappedConfig,\n );\n if (!replacedModuleExportsRight) {\n clack.log.warn(\n 'Could not automatically wrap the config export, please follow the manual steps.',\n );\n Sentry.captureException('Could not automatically wrap the config export.');\n await showInstructions();\n return false;\n }\n\n const addedSentryMetroImport = addSentryMetroRequireToMetroConfig(\n mod.$ast as t.Program,\n );\n if (!addedSentryMetroImport) {\n clack.log.warn(\n 'Could not add `@sentry/react-native/metro` import to Metro config, please follow the manual steps.',\n );\n Sentry.captureException(\n 'Could not add `@sentry/react-native/metro` import to Metro config.',\n );\n await showInstructions();\n return false;\n }\n\n clack.log.success(\n `Added Sentry Metro plugin to ${chalk.cyan(metroConfigPath)}.`,\n );\n return true;\n}\n\nexport async function parseMetroConfig(\n configPath: string,\n): Promise<ProxifiedModule | undefined> {\n try {\n const metroConfigContent = (\n await fs.promises.readFile(configPath)\n ).toString();\n\n return parseModule(metroConfigContent);\n } catch (error) {\n clack.log.error(\n `Could not read Metro config file ${chalk.cyan(configPath)}`,\n );\n Sentry.captureException('Could not read Metro config file');\n return undefined;\n }\n}\n\nexport async function writeMetroConfig(\n mod: ProxifiedModule,\n configPath: string,\n): Promise<boolean> {\n try {\n await writeFile(mod.$ast, configPath);\n } catch (e) {\n clack.log.error(\n `Failed to write to ${chalk.cyan(configPath)}: ${JSON.stringify(e)}`,\n );\n Sentry.captureException('Failed to write to Metro config file');\n return false;\n }\n return true;\n}\n\nexport function addSentrySerializerToMetroConfig(\n configObj: t.ObjectExpression,\n): boolean {\n const serializerProp = getSerializerProp(configObj);\n if ('invalid' === serializerProp) {\n return false;\n }\n\n // case 1: serializer property doesn't exist yet, so we can just add it\n if ('undefined' === serializerProp) {\n configObj.properties.push(\n b.objectProperty(\n b.identifier('serializer'),\n b.objectExpression([\n b.objectProperty(\n b.identifier('customSerializer'),\n b.callExpression(b.identifier('createSentryMetroSerializer'), []),\n ),\n ]),\n ),\n );\n return true;\n }\n\n const customSerializerProp = getCustomSerializerProp(serializerProp);\n // case 2: serializer.customSerializer property doesn't exist yet, so we just add it\n if (\n 'undefined' === customSerializerProp &&\n serializerProp.value.type === 'ObjectExpression'\n ) {\n serializerProp.value.properties.push(\n b.objectProperty(\n b.identifier('customSerializer'),\n b.callExpression(b.identifier('createSentryMetroSerializer'), []),\n ),\n );\n return true;\n }\n\n return false;\n}\n\nfunction getCustomSerializerProp(\n prop: t.ObjectProperty,\n): t.ObjectProperty | 'undefined' | 'invalid' {\n const customSerializerProp =\n prop.value.type === 'ObjectExpression' &&\n prop.value.properties.find(\n (p: t.ObjectProperty) =>\n p.key.type === 'Identifier' && p.key.name === 'customSerializer',\n );\n\n if (!customSerializerProp) {\n return 'undefined';\n }\n\n if (customSerializerProp.type === 'ObjectProperty') {\n return customSerializerProp;\n }\n\n return 'invalid';\n}\n\nfunction getSerializerProp(\n obj: t.ObjectExpression,\n): t.ObjectProperty | 'undefined' | 'invalid' {\n const serializerProp = obj.properties.find(\n (p: t.ObjectProperty) =>\n p.key.type === 'Identifier' && p.key.name === 'serializer',\n );\n\n if (!serializerProp) {\n return 'undefined';\n }\n\n if (serializerProp.type === 'ObjectProperty') {\n return serializerProp;\n }\n\n return 'invalid';\n}\n\nexport function addSentrySerializerRequireToMetroConfig(\n program: t.Program,\n): boolean {\n const lastRequireIndex = getLastRequireIndex(program);\n const sentrySerializerRequire = createSentrySerializerRequire();\n const sentryImportIndex = lastRequireIndex + 1;\n if (sentryImportIndex < program.body.length) {\n // insert after last require\n program.body.splice(lastRequireIndex + 1, 0, sentrySerializerRequire);\n } else {\n // insert at the beginning\n program.body.unshift(sentrySerializerRequire);\n }\n return true;\n}\n\nexport function addSentryMetroRequireToMetroConfig(\n program: t.Program,\n): boolean {\n const lastRequireIndex = getLastRequireIndex(program);\n const sentryMetroRequire = createSentryMetroRequire();\n const sentryImportIndex = lastRequireIndex + 1;\n if (sentryImportIndex < program.body.length) {\n // insert after last require\n program.body.splice(lastRequireIndex + 1, 0, sentryMetroRequire);\n } else {\n // insert at the beginning\n program.body.unshift(sentryMetroRequire);\n }\n return true;\n}\n\nfunction wrapWithSentryConfig(\n configObj: t.Identifier | t.CallExpression | t.ObjectExpression,\n): t.CallExpression {\n return b.callExpression(b.identifier('withSentryConfig'), [configObj]);\n}\n\nfunction replaceModuleExportsRight(\n program: t.Program,\n wrappedConfig: t.CallExpression,\n): boolean {\n const moduleExports = getModuleExports(program);\n if (!moduleExports) {\n return false;\n }\n\n if (moduleExports.expression.type === 'AssignmentExpression') {\n moduleExports.expression.right = wrappedConfig;\n return true;\n }\n\n return false;\n}\n\n/**\n * Creates const {createSentryMetroSerializer} = require('@sentry/react-native/dist/js/tools/sentryMetroSerializer');\n */\nfunction createSentrySerializerRequire() {\n return b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern([\n b.objectProperty.from({\n key: b.identifier('createSentryMetroSerializer'),\n value: b.identifier('createSentryMetroSerializer'),\n shorthand: true,\n }),\n ]),\n b.callExpression(b.identifier('require'), [\n b.literal('@sentry/react-native/dist/js/tools/sentryMetroSerializer'),\n ]),\n ),\n ]);\n}\n\n/**\n * Creates const {withSentryConfig} = require('@sentry/react-native/metro');\n */\nfunction createSentryMetroRequire() {\n return b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern([\n b.objectProperty.from({\n key: b.identifier('withSentryConfig'),\n value: b.identifier('withSentryConfig'),\n shorthand: true,\n }),\n ]),\n b.callExpression(b.identifier('require'), [\n b.literal('@sentry/react-native/metro'),\n ]),\n ),\n ]);\n}\n\nasync function confirmPathMetroConfig() {\n const shouldContinue = await abortIfCancelled(\n clack.select({\n message: `Metro Config already contains Sentry-related code. Should the wizard modify it anyway?`,\n options: [\n {\n label: 'Yes, add the Sentry Metro plugin',\n value: true,\n },\n {\n label: 'No, show me instructions to manually add the plugin',\n value: false,\n },\n ],\n initialValue: true,\n }),\n );\n\n if (!shouldContinue) {\n Sentry.setTag('ast-mod-fail-reason', 'has-sentry-content');\n }\n\n return shouldContinue;\n}\n\n/**\n * Returns value from `module.exports = value` or `const config = value`\n */\nexport function getMetroConfigObject(\n program: t.Program,\n): t.ObjectExpression | undefined {\n // check config variable\n const configVariable = program.body.find((s) => {\n if (\n s.type === 'VariableDeclaration' &&\n s.declarations.length === 1 &&\n s.declarations[0].type === 'VariableDeclarator' &&\n s.declarations[0].id.type === 'Identifier' &&\n s.declarations[0].id.name === 'config'\n ) {\n return true;\n }\n return false;\n }) as t.VariableDeclaration | undefined;\n\n if (\n configVariable?.declarations[0].type === 'VariableDeclarator' &&\n configVariable?.declarations[0].init?.type === 'ObjectExpression'\n ) {\n Sentry.setTag('metro-config', 'config-variable');\n return configVariable.declarations[0].init;\n }\n\n return getModuleExportsObject(program);\n}\n\nfunction getModuleExportsObject(\n program: t.Program,\n): t.ObjectExpression | undefined {\n // check module.exports\n const moduleExports = getModuleExportsAssignmentRight(program);\n\n if (moduleExports?.type === 'ObjectExpression') {\n return moduleExports;\n }\n\n Sentry.setTag('metro-config', 'not-found');\n return undefined;\n}\n\nexport function getModuleExportsAssignmentRight(\n program: t.Program,\n): t.Identifier | t.CallExpression | t.ObjectExpression | undefined {\n // check module.exports\n const moduleExports = getModuleExports(program);\n\n if (\n moduleExports?.expression.type === 'AssignmentExpression' &&\n (moduleExports.expression.right.type === 'ObjectExpression' ||\n moduleExports.expression.right.type === 'CallExpression' ||\n moduleExports.expression.right.type === 'Identifier')\n ) {\n Sentry.setTag('metro-config', 'module-exports');\n return moduleExports?.expression.right;\n }\n\n Sentry.setTag('metro-config', 'not-found');\n return undefined;\n}\n\nfunction getModuleExports(\n program: t.Program,\n): t.ExpressionStatement | undefined {\n // find module.exports\n return program.body.find((s) => {\n if (\n s.type === 'ExpressionStatement' &&\n s.expression.type === 'AssignmentExpression' &&\n s.expression.left.type === 'MemberExpression' &&\n s.expression.left.object.type === 'Identifier' &&\n s.expression.left.object.name === 'module' &&\n s.expression.left.property.type === 'Identifier' &&\n s.expression.left.property.name === 'exports'\n ) {\n return true;\n }\n return false;\n }) as t.ExpressionStatement | undefined;\n}\n\nfunction getMetroWithSentryConfigSnippet(colors: boolean) {\n return makeCodeSnippet(colors, (unchanged, plus, _) =>\n unchanged(`const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');\";\n${plus(\"const {withSentryConfig} = require('@sentry/react-native/metro');\")}\n\nconst config = {};\n\nmodule.exports = ${plus(\n 'withSentryConfig(',\n )}mergeConfig(getDefaultConfig(__dirname), config)${plus(')')};\n`),\n );\n}\n"]}
@@ -1,3 +1,4 @@
1
1
  import { ProxifiedModule } from 'magicast';
2
2
  export declare function wrapAppWithSentry(rootRouteAst: ProxifiedModule, rootFileName: string): void;
3
+ export declare function isWithSentryAlreadyUsed(rootRouteAst: ProxifiedModule): boolean;
3
4
  export declare function instrumentRoot(rootFileName: string): Promise<void>;
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.instrumentRoot = exports.wrapAppWithSentry = void 0;
29
+ exports.instrumentRoot = exports.isWithSentryAlreadyUsed = exports.wrapAppWithSentry = void 0;
30
30
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
31
31
  /* eslint-disable @typescript-eslint/no-unsafe-assignment */
32
32
  /* eslint-disable @typescript-eslint/no-unsafe-call */
@@ -70,11 +70,28 @@ function wrapAppWithSentry(rootRouteAst, rootFileName) {
70
70
  });
71
71
  }
72
72
  exports.wrapAppWithSentry = wrapAppWithSentry;
73
+ function isWithSentryAlreadyUsed(rootRouteAst) {
74
+ // Check if withSentry is called anywhere in the code
75
+ let isUsed = false;
76
+ recast.visit(rootRouteAst.$ast, {
77
+ visitCallExpression(path) {
78
+ if (path.value.callee.type === 'Identifier' &&
79
+ path.value.callee.name === 'withSentry') {
80
+ isUsed = true;
81
+ return false; // Stop traversal
82
+ }
83
+ this.traverse(path);
84
+ },
85
+ });
86
+ return isUsed;
87
+ }
88
+ exports.isWithSentryAlreadyUsed = isWithSentryAlreadyUsed;
73
89
  async function instrumentRoot(rootFileName) {
74
90
  const rootRouteAst = await (0, magicast_1.loadFile)(path.join(process.cwd(), 'app', rootFileName));
75
91
  const exportsAst = rootRouteAst.exports.$ast;
76
92
  const namedExports = exportsAst.body.filter((node) => node.type === 'ExportNamedDeclaration');
77
93
  let foundErrorBoundary = false;
94
+ const withSentryAlreadyUsed = isWithSentryAlreadyUsed(rootRouteAst);
78
95
  namedExports.forEach((namedExport) => {
79
96
  const declaration = namedExport.declaration;
80
97
  if (!declaration) {
@@ -106,6 +123,10 @@ async function instrumentRoot(rootFileName) {
106
123
  imported: 'useRouteError',
107
124
  local: 'useRouteError',
108
125
  });
126
+ // Call wrapAppWithSentry if withSentry is not already used
127
+ if (!withSentryAlreadyUsed) {
128
+ wrapAppWithSentry(rootRouteAst, rootFileName);
129
+ }
109
130
  recast.visit(rootRouteAst.$ast, {
110
131
  visitExportDefaultDeclaration(path) {
111
132
  const implementation = recast.parse(templates_1.ERROR_BOUNDARY_TEMPLATE).program
@@ -122,7 +143,10 @@ async function instrumentRoot(rootFileName) {
122
143
  imported: 'captureRemixErrorBoundaryError',
123
144
  local: 'captureRemixErrorBoundaryError',
124
145
  });
125
- wrapAppWithSentry(rootRouteAst, rootFileName);
146
+ // Call wrapAppWithSentry if withSentry is not already used
147
+ if (!withSentryAlreadyUsed) {
148
+ wrapAppWithSentry(rootRouteAst, rootFileName);
149
+ }
126
150
  recast.visit(rootRouteAst.$ast, {
127
151
  visitExportNamedDeclaration(path) {
128
152
  // Find ErrorBoundary export
@@ -161,6 +185,10 @@ async function instrumentRoot(rootFileName) {
161
185
  },
162
186
  });
163
187
  }
188
+ else if (!withSentryAlreadyUsed) {
189
+ // Even if we have Sentry content but withSentry is not used, we should still wrap the app
190
+ wrapAppWithSentry(rootRouteAst, rootFileName);
191
+ }
164
192
  await (0, magicast_1.writeFile)(rootRouteAst.$ast, path.join(process.cwd(), 'app', rootFileName));
165
193
  }
166
194
  exports.instrumentRoot = instrumentRoot;
@@ -1 +1 @@
1
- {"version":3,"file":"root.js","sourceRoot":"","sources":["../../../../src/remix/codemods/root.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\nimport * as recast from 'recast';\nimport * as path from 'path';\n\nimport type { ExportNamedDeclaration, Program } from '@babel/types';\n\nimport {\n builders,\n generateCode,\n loadFile,\n ProxifiedModule,\n writeFile,\n // @ts-expect-error - magicast is ESM and TS complains about that. It works though\n} from 'magicast';\n\nimport { ERROR_BOUNDARY_TEMPLATE } from '../templates';\nimport { hasSentryContent } from '../utils';\nimport chalk from 'chalk';\n\n// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport * as clack from '@clack/prompts';\n\nexport function wrapAppWithSentry(\n rootRouteAst: ProxifiedModule,\n rootFileName: string,\n) {\n rootRouteAst.imports.$add({\n from: '@sentry/remix',\n imported: 'withSentry',\n local: 'withSentry',\n });\n\n recast.visit(rootRouteAst.$ast, {\n visitExportDefaultDeclaration(path) {\n if (path.value.declaration.type === 'FunctionDeclaration') {\n // Move the function declaration just before the default export\n path.insertBefore(path.value.declaration);\n\n // Get the name of the function to be wrapped\n const functionName: string = path.value.declaration.id.name as string;\n\n // Create the wrapped function call\n const functionCall = recast.types.builders.callExpression(\n recast.types.builders.identifier('withSentry'),\n [recast.types.builders.identifier(functionName)],\n );\n\n // Replace the default export with the wrapped function call\n path.value.declaration = functionCall;\n } else if (path.value.declaration.type === 'Identifier') {\n const rootRouteExport = rootRouteAst.exports.default;\n\n const expressionToWrap = generateCode(rootRouteExport.$ast).code;\n\n rootRouteAst.exports.default = builders.raw(\n `withSentry(${expressionToWrap})`,\n );\n } else {\n clack.log.warn(\n chalk.yellow(\n `Couldn't instrument ${chalk.bold(\n rootFileName,\n )} automatically. Wrap your default export with: ${chalk.dim(\n 'withSentry()',\n )}\\n`,\n ),\n );\n }\n\n this.traverse(path);\n },\n });\n}\n\nexport async function instrumentRoot(rootFileName: string): Promise<void> {\n const rootRouteAst = await loadFile(\n path.join(process.cwd(), 'app', rootFileName),\n );\n\n const exportsAst = rootRouteAst.exports.$ast as Program;\n\n const namedExports = exportsAst.body.filter(\n (node) => node.type === 'ExportNamedDeclaration',\n ) as ExportNamedDeclaration[];\n\n let foundErrorBoundary = false;\n\n namedExports.forEach((namedExport) => {\n const declaration = namedExport.declaration;\n\n if (!declaration) {\n return;\n }\n\n if (declaration.type === 'FunctionDeclaration') {\n if (declaration.id?.name === 'ErrorBoundary') {\n foundErrorBoundary = true;\n }\n } else if (declaration.type === 'VariableDeclaration') {\n const declarations = declaration.declarations;\n\n declarations.forEach((declaration) => {\n // @ts-expect-error - id should always have a name in this case\n if (declaration.id?.name === 'ErrorBoundary') {\n foundErrorBoundary = true;\n }\n });\n }\n });\n\n if (!foundErrorBoundary) {\n rootRouteAst.imports.$add({\n from: '@sentry/remix',\n imported: 'captureRemixErrorBoundaryError',\n local: 'captureRemixErrorBoundaryError',\n });\n\n rootRouteAst.imports.$add({\n from: '@remix-run/react',\n imported: 'useRouteError',\n local: 'useRouteError',\n });\n\n recast.visit(rootRouteAst.$ast, {\n visitExportDefaultDeclaration(path) {\n const implementation = recast.parse(ERROR_BOUNDARY_TEMPLATE).program\n .body[0];\n\n path.insertBefore(\n recast.types.builders.exportDeclaration(false, implementation),\n );\n\n this.traverse(path);\n },\n });\n // If there is already a ErrorBoundary export, and it doesn't have Sentry content\n } else if (!hasSentryContent(rootFileName, rootRouteAst.$code)) {\n rootRouteAst.imports.$add({\n from: '@sentry/remix',\n imported: 'captureRemixErrorBoundaryError',\n local: 'captureRemixErrorBoundaryError',\n });\n\n wrapAppWithSentry(rootRouteAst, rootFileName);\n\n recast.visit(rootRouteAst.$ast, {\n visitExportNamedDeclaration(path) {\n // Find ErrorBoundary export\n if (path.value.declaration?.id?.name === 'ErrorBoundary') {\n const errorBoundaryExport = path.value.declaration;\n\n let errorIdentifier;\n\n // check if useRouteError is called\n recast.visit(errorBoundaryExport, {\n visitVariableDeclaration(path) {\n const variableDeclaration = path.value.declarations[0];\n const initializer = variableDeclaration.init;\n\n if (\n initializer.type === 'CallExpression' &&\n initializer.callee.name === 'useRouteError'\n ) {\n errorIdentifier = variableDeclaration.id.name;\n }\n\n this.traverse(path);\n },\n });\n\n // We don't have an errorIdentifier, which means useRouteError is not called / imported\n // We need to add it and capture the error\n if (!errorIdentifier) {\n rootRouteAst.imports.$add({\n from: '@remix-run/react',\n imported: 'useRouteError',\n local: 'useRouteError',\n });\n\n const useRouteErrorCall = recast.parse(\n `const error = useRouteError();`,\n ).program.body[0];\n\n // Insert at the top of ErrorBoundary body\n errorBoundaryExport.body.body.splice(0, 0, useRouteErrorCall);\n }\n\n const captureErrorCall = recast.parse(\n `captureRemixErrorBoundaryError(error);`,\n ).program.body[0];\n\n // Insert just before the the fallback page is returned\n errorBoundaryExport.body.body.splice(\n errorBoundaryExport.body.body.length - 1,\n 0,\n captureErrorCall,\n );\n }\n this.traverse(path);\n },\n });\n }\n\n await writeFile(\n rootRouteAst.$ast,\n path.join(process.cwd(), 'app', rootFileName),\n );\n}\n"]}
1
+ {"version":3,"file":"root.js","sourceRoot":"","sources":["../../../../src/remix/codemods/root.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\nimport * as recast from 'recast';\nimport * as path from 'path';\n\nimport type { ExportNamedDeclaration, Program } from '@babel/types';\n\nimport {\n builders,\n generateCode,\n loadFile,\n ProxifiedModule,\n writeFile,\n // @ts-expect-error - magicast is ESM and TS complains about that. It works though\n} from 'magicast';\n\nimport { ERROR_BOUNDARY_TEMPLATE } from '../templates';\nimport { hasSentryContent } from '../utils';\nimport chalk from 'chalk';\n\n// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport * as clack from '@clack/prompts';\n\nexport function wrapAppWithSentry(\n rootRouteAst: ProxifiedModule,\n rootFileName: string,\n) {\n rootRouteAst.imports.$add({\n from: '@sentry/remix',\n imported: 'withSentry',\n local: 'withSentry',\n });\n\n recast.visit(rootRouteAst.$ast, {\n visitExportDefaultDeclaration(path) {\n if (path.value.declaration.type === 'FunctionDeclaration') {\n // Move the function declaration just before the default export\n path.insertBefore(path.value.declaration);\n\n // Get the name of the function to be wrapped\n const functionName: string = path.value.declaration.id.name as string;\n\n // Create the wrapped function call\n const functionCall = recast.types.builders.callExpression(\n recast.types.builders.identifier('withSentry'),\n [recast.types.builders.identifier(functionName)],\n );\n\n // Replace the default export with the wrapped function call\n path.value.declaration = functionCall;\n } else if (path.value.declaration.type === 'Identifier') {\n const rootRouteExport = rootRouteAst.exports.default;\n\n const expressionToWrap = generateCode(rootRouteExport.$ast).code;\n\n rootRouteAst.exports.default = builders.raw(\n `withSentry(${expressionToWrap})`,\n );\n } else {\n clack.log.warn(\n chalk.yellow(\n `Couldn't instrument ${chalk.bold(\n rootFileName,\n )} automatically. Wrap your default export with: ${chalk.dim(\n 'withSentry()',\n )}\\n`,\n ),\n );\n }\n\n this.traverse(path);\n },\n });\n}\n\nexport function isWithSentryAlreadyUsed(\n rootRouteAst: ProxifiedModule,\n): boolean {\n // Check if withSentry is called anywhere in the code\n let isUsed = false;\n recast.visit(rootRouteAst.$ast, {\n visitCallExpression(path) {\n if (\n path.value.callee.type === 'Identifier' &&\n path.value.callee.name === 'withSentry'\n ) {\n isUsed = true;\n return false; // Stop traversal\n }\n this.traverse(path);\n },\n });\n return isUsed;\n}\n\nexport async function instrumentRoot(rootFileName: string): Promise<void> {\n const rootRouteAst = await loadFile(\n path.join(process.cwd(), 'app', rootFileName),\n );\n\n const exportsAst = rootRouteAst.exports.$ast as Program;\n\n const namedExports = exportsAst.body.filter(\n (node) => node.type === 'ExportNamedDeclaration',\n ) as ExportNamedDeclaration[];\n\n let foundErrorBoundary = false;\n const withSentryAlreadyUsed = isWithSentryAlreadyUsed(rootRouteAst);\n\n namedExports.forEach((namedExport) => {\n const declaration = namedExport.declaration;\n\n if (!declaration) {\n return;\n }\n\n if (declaration.type === 'FunctionDeclaration') {\n if (declaration.id?.name === 'ErrorBoundary') {\n foundErrorBoundary = true;\n }\n } else if (declaration.type === 'VariableDeclaration') {\n const declarations = declaration.declarations;\n\n declarations.forEach((declaration) => {\n // @ts-expect-error - id should always have a name in this case\n if (declaration.id?.name === 'ErrorBoundary') {\n foundErrorBoundary = true;\n }\n });\n }\n });\n\n if (!foundErrorBoundary) {\n rootRouteAst.imports.$add({\n from: '@sentry/remix',\n imported: 'captureRemixErrorBoundaryError',\n local: 'captureRemixErrorBoundaryError',\n });\n\n rootRouteAst.imports.$add({\n from: '@remix-run/react',\n imported: 'useRouteError',\n local: 'useRouteError',\n });\n\n // Call wrapAppWithSentry if withSentry is not already used\n if (!withSentryAlreadyUsed) {\n wrapAppWithSentry(rootRouteAst, rootFileName);\n }\n\n recast.visit(rootRouteAst.$ast, {\n visitExportDefaultDeclaration(path) {\n const implementation = recast.parse(ERROR_BOUNDARY_TEMPLATE).program\n .body[0];\n\n path.insertBefore(\n recast.types.builders.exportDeclaration(false, implementation),\n );\n\n this.traverse(path);\n },\n });\n // If there is already a ErrorBoundary export, and it doesn't have Sentry content\n } else if (!hasSentryContent(rootFileName, rootRouteAst.$code)) {\n rootRouteAst.imports.$add({\n from: '@sentry/remix',\n imported: 'captureRemixErrorBoundaryError',\n local: 'captureRemixErrorBoundaryError',\n });\n\n // Call wrapAppWithSentry if withSentry is not already used\n if (!withSentryAlreadyUsed) {\n wrapAppWithSentry(rootRouteAst, rootFileName);\n }\n\n recast.visit(rootRouteAst.$ast, {\n visitExportNamedDeclaration(path) {\n // Find ErrorBoundary export\n if (path.value.declaration?.id?.name === 'ErrorBoundary') {\n const errorBoundaryExport = path.value.declaration;\n\n let errorIdentifier;\n\n // check if useRouteError is called\n recast.visit(errorBoundaryExport, {\n visitVariableDeclaration(path) {\n const variableDeclaration = path.value.declarations[0];\n const initializer = variableDeclaration.init;\n\n if (\n initializer.type === 'CallExpression' &&\n initializer.callee.name === 'useRouteError'\n ) {\n errorIdentifier = variableDeclaration.id.name;\n }\n\n this.traverse(path);\n },\n });\n\n // We don't have an errorIdentifier, which means useRouteError is not called / imported\n // We need to add it and capture the error\n if (!errorIdentifier) {\n rootRouteAst.imports.$add({\n from: '@remix-run/react',\n imported: 'useRouteError',\n local: 'useRouteError',\n });\n\n const useRouteErrorCall = recast.parse(\n `const error = useRouteError();`,\n ).program.body[0];\n\n // Insert at the top of ErrorBoundary body\n errorBoundaryExport.body.body.splice(0, 0, useRouteErrorCall);\n }\n\n const captureErrorCall = recast.parse(\n `captureRemixErrorBoundaryError(error);`,\n ).program.body[0];\n\n // Insert just before the the fallback page is returned\n errorBoundaryExport.body.body.splice(\n errorBoundaryExport.body.body.length - 1,\n 0,\n captureErrorCall,\n );\n }\n this.traverse(path);\n },\n });\n } else if (!withSentryAlreadyUsed) {\n // Even if we have Sentry content but withSentry is not used, we should still wrap the app\n wrapAppWithSentry(rootRouteAst, rootFileName);\n }\n\n await writeFile(\n rootRouteAst.$ast,\n path.join(process.cwd(), 'app', rootFileName),\n );\n}\n"]}
@@ -1 +1 @@
1
- export declare const WIZARD_VERSION = "6.1.2";
1
+ export declare const WIZARD_VERSION = "6.2.0";
@@ -3,5 +3,5 @@
3
3
  // This is file is updated at release time.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.WIZARD_VERSION = void 0;
6
- exports.WIZARD_VERSION = '6.1.2';
6
+ exports.WIZARD_VERSION = '6.2.0';
7
7
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":";AAAA,oCAAoC;AACpC,2CAA2C;;;AAE9B,QAAA,cAAc,GAAG,OAAO,CAAC","sourcesContent":["// DO NOT modify this file manually!\n// This is file is updated at release time.\n\nexport const WIZARD_VERSION = '6.1.2';\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":";AAAA,oCAAoC;AACpC,2CAA2C;;;AAE9B,QAAA,cAAc,GAAG,OAAO,CAAC","sourcesContent":["// DO NOT modify this file manually!\n// This is file is updated at release time.\n\nexport const WIZARD_VERSION = '6.2.0';\n"]}