@sentry/wizard 6.11.0 → 6.12.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 (99) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/e2e-tests/tests/cloudflare-worker.test.js +5 -0
  3. package/dist/e2e-tests/tests/cloudflare-worker.test.js.map +1 -1
  4. package/dist/e2e-tests/tests/pnpm-workspace.test.js +2 -1
  5. package/dist/e2e-tests/tests/pnpm-workspace.test.js.map +1 -1
  6. package/dist/e2e-tests/tests/react-router-instrumentation-api.test.d.ts +1 -0
  7. package/dist/e2e-tests/tests/react-router-instrumentation-api.test.js +96 -0
  8. package/dist/e2e-tests/tests/react-router-instrumentation-api.test.js.map +1 -0
  9. package/dist/e2e-tests/tests/react-router.test.js +3 -1
  10. package/dist/e2e-tests/tests/react-router.test.js.map +1 -1
  11. package/dist/e2e-tests/tests/sveltekit-tracing.test.js +2 -1
  12. package/dist/e2e-tests/tests/sveltekit-tracing.test.js.map +1 -1
  13. package/dist/src/apple/code-tools.js +17 -3
  14. package/dist/src/apple/code-tools.js.map +1 -1
  15. package/dist/src/apple/configure-package-manager.js +18 -5
  16. package/dist/src/apple/configure-package-manager.js.map +1 -1
  17. package/dist/src/cloudflare/cloudflare-wizard.js +5 -0
  18. package/dist/src/cloudflare/cloudflare-wizard.js.map +1 -1
  19. package/dist/src/cloudflare/sdk-setup.d.ts +1 -0
  20. package/dist/src/cloudflare/sdk-setup.js.map +1 -1
  21. package/dist/src/cloudflare/templates.d.ts +1 -0
  22. package/dist/src/cloudflare/templates.js +7 -1
  23. package/dist/src/cloudflare/templates.js.map +1 -1
  24. package/dist/src/cloudflare/wrap-worker.d.ts +1 -0
  25. package/dist/src/cloudflare/wrap-worker.js +7 -0
  26. package/dist/src/cloudflare/wrap-worker.js.map +1 -1
  27. package/dist/src/react-native/expo.d.ts +6 -0
  28. package/dist/src/react-native/expo.js +27 -1
  29. package/dist/src/react-native/expo.js.map +1 -1
  30. package/dist/src/react-native/git.d.ts +5 -0
  31. package/dist/src/react-native/git.js +32 -1
  32. package/dist/src/react-native/git.js.map +1 -1
  33. package/dist/src/react-native/javascript.js +3 -1
  34. package/dist/src/react-native/javascript.js.map +1 -1
  35. package/dist/src/react-native/react-native-wizard.js +12 -6
  36. package/dist/src/react-native/react-native-wizard.js.map +1 -1
  37. package/dist/src/react-router/codemods/client.entry.d.ts +1 -1
  38. package/dist/src/react-router/codemods/client.entry.js +69 -12
  39. package/dist/src/react-router/codemods/client.entry.js.map +1 -1
  40. package/dist/src/react-router/codemods/react-router-config.js +1 -1
  41. package/dist/src/react-router/codemods/react-router-config.js.map +1 -1
  42. package/dist/src/react-router/codemods/root.js +1 -2
  43. package/dist/src/react-router/codemods/root.js.map +1 -1
  44. package/dist/src/react-router/codemods/server-entry.d.ts +1 -1
  45. package/dist/src/react-router/codemods/server-entry.js +39 -4
  46. package/dist/src/react-router/codemods/server-entry.js.map +1 -1
  47. package/dist/src/react-router/codemods/vite.js +46 -1
  48. package/dist/src/react-router/codemods/vite.js.map +1 -1
  49. package/dist/src/react-router/react-router-wizard.js +52 -5
  50. package/dist/src/react-router/react-router-wizard.js.map +1 -1
  51. package/dist/src/react-router/sdk-setup.d.ts +4 -2
  52. package/dist/src/react-router/sdk-setup.js +32 -5
  53. package/dist/src/react-router/sdk-setup.js.map +1 -1
  54. package/dist/src/react-router/templates.d.ts +2 -2
  55. package/dist/src/react-router/templates.js +72 -2
  56. package/dist/src/react-router/templates.js.map +1 -1
  57. package/dist/src/sourcemaps/tools/vite.js +1 -1
  58. package/dist/src/sourcemaps/tools/vite.js.map +1 -1
  59. package/dist/src/sveltekit/sdk-setup/vite.js +1 -1
  60. package/dist/src/sveltekit/sdk-setup/vite.js.map +1 -1
  61. package/dist/src/utils/ast-utils.d.ts +10 -0
  62. package/dist/src/utils/ast-utils.js +19 -1
  63. package/dist/src/utils/ast-utils.js.map +1 -1
  64. package/dist/src/version.d.ts +1 -1
  65. package/dist/src/version.js +1 -1
  66. package/dist/src/version.js.map +1 -1
  67. package/dist/test/apple/code-tools.test.js +78 -0
  68. package/dist/test/apple/code-tools.test.js.map +1 -1
  69. package/dist/test/apple/configure-package-manager.test.d.ts +1 -0
  70. package/dist/test/apple/configure-package-manager.test.js +161 -0
  71. package/dist/test/apple/configure-package-manager.test.js.map +1 -0
  72. package/dist/test/cloudflare/sdk-setup.test.js +20 -2
  73. package/dist/test/cloudflare/sdk-setup.test.js.map +1 -1
  74. package/dist/test/cloudflare/templates.test.js +54 -0
  75. package/dist/test/cloudflare/templates.test.js.map +1 -1
  76. package/dist/test/cloudflare/wrap-worker.test.js +74 -11
  77. package/dist/test/cloudflare/wrap-worker.test.js.map +1 -1
  78. package/dist/test/react-native/expo.test.js +140 -0
  79. package/dist/test/react-native/expo.test.js.map +1 -1
  80. package/dist/test/react-native/git.test.d.ts +1 -0
  81. package/dist/test/react-native/git.test.js +160 -0
  82. package/dist/test/react-native/git.test.js.map +1 -0
  83. package/dist/test/react-router/codemods/client-entry.test.js +29 -0
  84. package/dist/test/react-router/codemods/client-entry.test.js.map +1 -1
  85. package/dist/test/react-router/codemods/root.test.js +4 -0
  86. package/dist/test/react-router/codemods/root.test.js.map +1 -1
  87. package/dist/test/react-router/codemods/server-entry.test.js +70 -0
  88. package/dist/test/react-router/codemods/server-entry.test.js.map +1 -1
  89. package/dist/test/react-router/codemods/vite.test.js +89 -0
  90. package/dist/test/react-router/codemods/vite.test.js.map +1 -1
  91. package/dist/test/react-router/sdk-setup.test.js +62 -6
  92. package/dist/test/react-router/sdk-setup.test.js.map +1 -1
  93. package/dist/test/react-router/templates.test.js +50 -0
  94. package/dist/test/react-router/templates.test.js.map +1 -1
  95. package/dist/test/sourcemaps/tools/vite.test.js +12 -8
  96. package/dist/test/sourcemaps/tools/vite.test.js.map +1 -1
  97. package/dist/test/utils/ast-utils.test.js +22 -0
  98. package/dist/test/utils/ast-utils.test.js.map +1 -1
  99. package/package.json +2 -2
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const vitest_1 = require("vitest");
27
+ const fs = __importStar(require("fs"));
28
+ const git_1 = require("../../src/react-native/git");
29
+ // Mock fs module
30
+ vitest_1.vi.mock('fs', () => ({
31
+ promises: {
32
+ readFile: vitest_1.vi.fn(),
33
+ appendFile: vitest_1.vi.fn(),
34
+ },
35
+ }));
36
+ (0, vitest_1.describe)('git', () => {
37
+ (0, vitest_1.beforeEach)(() => {
38
+ vitest_1.vi.clearAllMocks();
39
+ });
40
+ (0, vitest_1.afterEach)(() => {
41
+ vitest_1.vi.restoreAllMocks();
42
+ });
43
+ (0, vitest_1.describe)('isFolderInGitignore', () => {
44
+ (0, vitest_1.test)('returns true when ios is in gitignore', async () => {
45
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios\nandroid\n');
46
+ const result = await (0, git_1.isFolderInGitignore)('ios');
47
+ (0, vitest_1.expect)(result).toBe(true);
48
+ });
49
+ (0, vitest_1.test)('returns true when android is in gitignore', async () => {
50
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios\nandroid\n');
51
+ const result = await (0, git_1.isFolderInGitignore)('android');
52
+ (0, vitest_1.expect)(result).toBe(true);
53
+ });
54
+ (0, vitest_1.test)('returns true when folder has trailing slash pattern', async () => {
55
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios/\nandroid/\n');
56
+ const result = await (0, git_1.isFolderInGitignore)('ios');
57
+ (0, vitest_1.expect)(result).toBe(true);
58
+ });
59
+ (0, vitest_1.test)('returns true when folder has leading slash pattern', async () => {
60
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\n/ios\nandroid\n');
61
+ const result = await (0, git_1.isFolderInGitignore)('ios');
62
+ (0, vitest_1.expect)(result).toBe(true);
63
+ });
64
+ (0, vitest_1.test)('returns true when folder has wildcard pattern', async () => {
65
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios/*\nandroid/*\n');
66
+ const result = await (0, git_1.isFolderInGitignore)('ios');
67
+ (0, vitest_1.expect)(result).toBe(true);
68
+ });
69
+ (0, vitest_1.test)('returns true with leading and trailing slash pattern', async () => {
70
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\n/ios/\nandroid\n');
71
+ const result = await (0, git_1.isFolderInGitignore)('ios');
72
+ (0, vitest_1.expect)(result).toBe(true);
73
+ });
74
+ (0, vitest_1.test)('returns true when folder is in gitignore with additional content', async () => {
75
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('# Dependencies\nnode_modules\n\n# Native folders\nios\nandroid\n\n# Build\nbuild/\ndist/\n');
76
+ const result = await (0, git_1.isFolderInGitignore)('ios');
77
+ (0, vitest_1.expect)(result).toBe(true);
78
+ });
79
+ (0, vitest_1.test)('returns false when specified folder is not in gitignore', async () => {
80
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nandroid\nbuild\n');
81
+ const result = await (0, git_1.isFolderInGitignore)('ios');
82
+ (0, vitest_1.expect)(result).toBe(false);
83
+ });
84
+ (0, vitest_1.test)('returns true when specified folder is in gitignore', async () => {
85
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios\nbuild\n');
86
+ const result = await (0, git_1.isFolderInGitignore)('ios');
87
+ (0, vitest_1.expect)(result).toBe(true);
88
+ });
89
+ (0, vitest_1.test)('returns false when gitignore is empty', async () => {
90
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('');
91
+ const result = await (0, git_1.isFolderInGitignore)('ios');
92
+ (0, vitest_1.expect)(result).toBe(false);
93
+ });
94
+ (0, vitest_1.test)('returns false when gitignore contains folder only in comments', async () => {
95
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('# ios folder\n# android folder\nnode_modules\n');
96
+ const result = await (0, git_1.isFolderInGitignore)('ios');
97
+ (0, vitest_1.expect)(result).toBe(false);
98
+ });
99
+ (0, vitest_1.test)('returns false when gitignore contains similar names as substrings', async () => {
100
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\niosApp\nandroidApp\n');
101
+ const result = await (0, git_1.isFolderInGitignore)('ios');
102
+ (0, vitest_1.expect)(result).toBe(false);
103
+ });
104
+ (0, vitest_1.test)('returns false when gitignore file does not exist', async () => {
105
+ vitest_1.vi.mocked(fs.promises.readFile).mockRejectedValue(new Error('ENOENT: no such file or directory'));
106
+ const result = await (0, git_1.isFolderInGitignore)('ios');
107
+ (0, vitest_1.expect)(result).toBe(false);
108
+ });
109
+ (0, vitest_1.test)('returns false when fs.promises.readFile throws permission error', async () => {
110
+ vitest_1.vi.mocked(fs.promises.readFile).mockRejectedValue(new Error('EACCES: permission denied'));
111
+ const result = await (0, git_1.isFolderInGitignore)('ios');
112
+ (0, vitest_1.expect)(result).toBe(false);
113
+ });
114
+ (0, vitest_1.test)('returns false when fs.promises.readFile throws any error', async () => {
115
+ vitest_1.vi.mocked(fs.promises.readFile).mockRejectedValue(new Error('Unknown error'));
116
+ const result = await (0, git_1.isFolderInGitignore)('ios');
117
+ (0, vitest_1.expect)(result).toBe(false);
118
+ });
119
+ (0, vitest_1.test)('handles gitignore with CRLF line endings', async () => {
120
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\r\nios\r\nandroid\r\n');
121
+ const result = await (0, git_1.isFolderInGitignore)('ios');
122
+ (0, vitest_1.expect)(result).toBe(true);
123
+ });
124
+ (0, vitest_1.test)('handles gitignore with no trailing newline', async () => {
125
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios\nandroid');
126
+ const result = await (0, git_1.isFolderInGitignore)('ios');
127
+ (0, vitest_1.expect)(result).toBe(true);
128
+ });
129
+ (0, vitest_1.test)('ignores folder name in comments', async () => {
130
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\n# ios - native folder\nios\nandroid\n');
131
+ const result = await (0, git_1.isFolderInGitignore)('ios');
132
+ (0, vitest_1.expect)(result).toBe(true);
133
+ });
134
+ (0, vitest_1.test)('returns false when similar folder names exist but not exact match', async () => {
135
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nbiosensor\nhumanoid\n');
136
+ const result = await (0, git_1.isFolderInGitignore)('ios');
137
+ (0, vitest_1.expect)(result).toBe(false);
138
+ });
139
+ (0, vitest_1.test)('returns true when folder is at the start of gitignore file', async () => {
140
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('ios\nandroid\nnode_modules\n');
141
+ const result = await (0, git_1.isFolderInGitignore)('ios');
142
+ (0, vitest_1.expect)(result).toBe(true);
143
+ });
144
+ (0, vitest_1.test)('returns true when folder is at the start with trailing slash', async () => {
145
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('ios/\nandroid/\nnode_modules\n');
146
+ const result = await (0, git_1.isFolderInGitignore)('ios');
147
+ (0, vitest_1.expect)(result).toBe(true);
148
+ });
149
+ (0, vitest_1.test)('works with different folder names', async () => {
150
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nbuild\ndist\n');
151
+ const buildResult = await (0, git_1.isFolderInGitignore)('build');
152
+ const distResult = await (0, git_1.isFolderInGitignore)('dist');
153
+ const srcResult = await (0, git_1.isFolderInGitignore)('src');
154
+ (0, vitest_1.expect)(buildResult).toBe(true);
155
+ (0, vitest_1.expect)(distResult).toBe(true);
156
+ (0, vitest_1.expect)(srcResult).toBe(false);
157
+ });
158
+ });
159
+ });
160
+ //# sourceMappingURL=git.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.test.js","sourceRoot":"","sources":["../../../test/react-native/git.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, test, vi, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport { isFolderInGitignore } from '../../src/react-native/git';\n\n// Mock fs module\nvi.mock('fs', () => ({\n promises: {\n readFile: vi.fn(),\n appendFile: vi.fn(),\n },\n}));\n\ndescribe('git', () => {\n beforeEach(() => {\n vi.clearAllMocks();\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n describe('isFolderInGitignore', () => {\n test('returns true when ios is in gitignore', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios\\nandroid\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true when android is in gitignore', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios\\nandroid\\n',\n );\n\n const result = await isFolderInGitignore('android');\n\n expect(result).toBe(true);\n });\n\n test('returns true when folder has trailing slash pattern', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios/\\nandroid/\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true when folder has leading slash pattern', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\n/ios\\nandroid\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true when folder has wildcard pattern', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios/*\\nandroid/*\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true with leading and trailing slash pattern', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\n/ios/\\nandroid\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true when folder is in gitignore with additional content', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n '# Dependencies\\nnode_modules\\n\\n# Native folders\\nios\\nandroid\\n\\n# Build\\nbuild/\\ndist/\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns false when specified folder is not in gitignore', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nandroid\\nbuild\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns true when specified folder is in gitignore', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios\\nbuild\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns false when gitignore is empty', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue('');\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns false when gitignore contains folder only in comments', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n '# ios folder\\n# android folder\\nnode_modules\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns false when gitignore contains similar names as substrings', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\niosApp\\nandroidApp\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns false when gitignore file does not exist', async () => {\n vi.mocked(fs.promises.readFile).mockRejectedValue(\n new Error('ENOENT: no such file or directory'),\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns false when fs.promises.readFile throws permission error', async () => {\n vi.mocked(fs.promises.readFile).mockRejectedValue(\n new Error('EACCES: permission denied'),\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns false when fs.promises.readFile throws any error', async () => {\n vi.mocked(fs.promises.readFile).mockRejectedValue(\n new Error('Unknown error'),\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('handles gitignore with CRLF line endings', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\r\\nios\\r\\nandroid\\r\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('handles gitignore with no trailing newline', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios\\nandroid',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('ignores folder name in comments', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\n# ios - native folder\\nios\\nandroid\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns false when similar folder names exist but not exact match', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nbiosensor\\nhumanoid\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns true when folder is at the start of gitignore file', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'ios\\nandroid\\nnode_modules\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true when folder is at the start with trailing slash', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'ios/\\nandroid/\\nnode_modules\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('works with different folder names', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nbuild\\ndist\\n',\n );\n\n const buildResult = await isFolderInGitignore('build');\n const distResult = await isFolderInGitignore('dist');\n const srcResult = await isFolderInGitignore('src');\n\n expect(buildResult).toBe(true);\n expect(distResult).toBe(true);\n expect(srcResult).toBe(false);\n });\n });\n});\n"]}
@@ -164,5 +164,34 @@ vitest_1.vi.mock('@clack/prompts', () => {
164
164
  (0, vitest_1.expect)(modifiedContent).toContain('hydrateRoot');
165
165
  (0, vitest_1.expect)(modifiedContent).toContain('<StrictMode>');
166
166
  });
167
+ (0, vitest_1.describe)('Instrumentation API', () => {
168
+ (0, vitest_1.it)('should add instrumentation API setup when enabled', async () => {
169
+ const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
170
+ fs.writeFileSync(tmpFile, basicContent);
171
+ await (0, client_entry_1.instrumentClientEntry)(tmpFile, 'test-dsn', true, false, false, true);
172
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
173
+ (0, vitest_1.expect)(modifiedContent).toContain('const tracing = Sentry.reactRouterTracingIntegration({ useInstrumentationAPI: true });');
174
+ (0, vitest_1.expect)(modifiedContent).toContain('integrations: [tracing]');
175
+ (0, vitest_1.expect)(modifiedContent).toContain('unstable_instrumentations={[tracing.clientInstrumentation]}');
176
+ });
177
+ (0, vitest_1.it)('should combine instrumentation API with replay', async () => {
178
+ const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
179
+ fs.writeFileSync(tmpFile, basicContent);
180
+ await (0, client_entry_1.instrumentClientEntry)(tmpFile, 'test-dsn', true, true, false, true);
181
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
182
+ (0, vitest_1.expect)(modifiedContent).toContain('const tracing = Sentry.reactRouterTracingIntegration({ useInstrumentationAPI: true });');
183
+ (0, vitest_1.expect)(modifiedContent).toContain('integrations: [tracing, Sentry.replayIntegration()]');
184
+ (0, vitest_1.expect)(modifiedContent).toContain('unstable_instrumentations={[tracing.clientInstrumentation]}');
185
+ });
186
+ (0, vitest_1.it)('should not use instrumentation API when useInstrumentationAPI is false', async () => {
187
+ const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
188
+ fs.writeFileSync(tmpFile, basicContent);
189
+ await (0, client_entry_1.instrumentClientEntry)(tmpFile, 'test-dsn', true, false, false, false);
190
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
191
+ (0, vitest_1.expect)(modifiedContent).not.toContain('const tracing = Sentry.reactRouterTracingIntegration({ useInstrumentationAPI: true });');
192
+ (0, vitest_1.expect)(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');
193
+ (0, vitest_1.expect)(modifiedContent).not.toContain('unstable_instrumentations');
194
+ });
195
+ });
167
196
  });
168
197
  //# sourceMappingURL=client-entry.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-entry.test.js","sourceRoot":"","sources":["../../../../test/react-router/codemods/client-entry.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { instrumentClientEntry } from '../../../src/react-router/codemods/client.entry';\n\nvi.mock('@clack/prompts', () => {\n const mock = {\n log: {\n warn: vi.fn(),\n info: vi.fn(),\n success: vi.fn(),\n },\n };\n return {\n default: mock,\n ...mock,\n };\n});\n\ndescribe('instrumentClientEntry', () => {\n const fixturesDir = path.join(__dirname, 'fixtures', 'client-entry');\n let tmpDir: string;\n let tmpFile: string;\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n // Create unique tmp directory for each test\n tmpDir = path.join(\n fixturesDir,\n 'tmp',\n `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n tmpFile = path.join(tmpDir, 'entry.client.tsx');\n\n // Ensure tmp directory exists\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n // Clean up tmp directory\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should add Sentry import and initialization with all features enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n expect(modifiedContent).toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only tracing enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, false, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only replay enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, true, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only logs enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, false, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).toContain('enableLogs: true');\n });\n\n it('should add minimal Sentry initialization when all features are disabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, false, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: []');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should not modify file when Sentry content already exists', async () => {\n const withSentryContent = fs.readFileSync(\n path.join(fixturesDir, 'with-sentry.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, withSentryContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Content should remain unchanged\n expect(modifiedContent).toBe(withSentryContent);\n });\n\n it('should insert Sentry initialization after imports', async () => {\n const withImportsContent = fs.readFileSync(\n path.join(fixturesDir, 'with-imports.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, withImportsContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, false, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n\n // Check that the Sentry import is before the init call\n const sentryImportIndex = modifiedContent.indexOf(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n const sentryInitIndex = modifiedContent.indexOf('Sentry.init({');\n expect(sentryImportIndex).toBeLessThan(sentryInitIndex);\n });\n\n it('should handle files with no imports', async () => {\n const noImportsContent = fs.readFileSync(\n path.join(fixturesDir, 'no-imports.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, noImportsContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, true, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n });\n\n it('should preserve existing code structure', async () => {\n const complexContent = fs.readFileSync(\n path.join(fixturesDir, 'complex.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, complexContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n\n // Original content should still be there\n expect(modifiedContent).toContain('startTransition');\n expect(modifiedContent).toContain('hydrateRoot');\n expect(modifiedContent).toContain('<StrictMode>');\n });\n});\n"]}
1
+ {"version":3,"file":"client-entry.test.js","sourceRoot":"","sources":["../../../../test/react-router/codemods/client-entry.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { instrumentClientEntry } from '../../../src/react-router/codemods/client.entry';\n\nvi.mock('@clack/prompts', () => {\n const mock = {\n log: {\n warn: vi.fn(),\n info: vi.fn(),\n success: vi.fn(),\n },\n };\n return {\n default: mock,\n ...mock,\n };\n});\n\ndescribe('instrumentClientEntry', () => {\n const fixturesDir = path.join(__dirname, 'fixtures', 'client-entry');\n let tmpDir: string;\n let tmpFile: string;\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n // Create unique tmp directory for each test\n tmpDir = path.join(\n fixturesDir,\n 'tmp',\n `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n tmpFile = path.join(tmpDir, 'entry.client.tsx');\n\n // Ensure tmp directory exists\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n // Clean up tmp directory\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should add Sentry import and initialization with all features enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n expect(modifiedContent).toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only tracing enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, false, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only replay enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, true, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only logs enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, false, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).toContain('enableLogs: true');\n });\n\n it('should add minimal Sentry initialization when all features are disabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, false, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: []');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should not modify file when Sentry content already exists', async () => {\n const withSentryContent = fs.readFileSync(\n path.join(fixturesDir, 'with-sentry.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, withSentryContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Content should remain unchanged\n expect(modifiedContent).toBe(withSentryContent);\n });\n\n it('should insert Sentry initialization after imports', async () => {\n const withImportsContent = fs.readFileSync(\n path.join(fixturesDir, 'with-imports.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, withImportsContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, false, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n\n // Check that the Sentry import is before the init call\n const sentryImportIndex = modifiedContent.indexOf(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n const sentryInitIndex = modifiedContent.indexOf('Sentry.init({');\n expect(sentryImportIndex).toBeLessThan(sentryInitIndex);\n });\n\n it('should handle files with no imports', async () => {\n const noImportsContent = fs.readFileSync(\n path.join(fixturesDir, 'no-imports.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, noImportsContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, true, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n });\n\n it('should preserve existing code structure', async () => {\n const complexContent = fs.readFileSync(\n path.join(fixturesDir, 'complex.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, complexContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.init({');\n\n // Original content should still be there\n expect(modifiedContent).toContain('startTransition');\n expect(modifiedContent).toContain('hydrateRoot');\n expect(modifiedContent).toContain('<StrictMode>');\n });\n\n describe('Instrumentation API', () => {\n it('should add instrumentation API setup when enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(\n tmpFile,\n 'test-dsn',\n true,\n false,\n false,\n true,\n );\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'const tracing = Sentry.reactRouterTracingIntegration({ useInstrumentationAPI: true });',\n );\n expect(modifiedContent).toContain('integrations: [tracing]');\n expect(modifiedContent).toContain(\n 'unstable_instrumentations={[tracing.clientInstrumentation]}',\n );\n });\n\n it('should combine instrumentation API with replay', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, false, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'const tracing = Sentry.reactRouterTracingIntegration({ useInstrumentationAPI: true });',\n );\n expect(modifiedContent).toContain(\n 'integrations: [tracing, Sentry.replayIntegration()]',\n );\n expect(modifiedContent).toContain(\n 'unstable_instrumentations={[tracing.clientInstrumentation]}',\n );\n });\n\n it('should not use instrumentation API when useInstrumentationAPI is false', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(\n tmpFile,\n 'test-dsn',\n true,\n false,\n false,\n false,\n );\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).not.toContain(\n 'const tracing = Sentry.reactRouterTracingIntegration({ useInstrumentationAPI: true });',\n );\n expect(modifiedContent).toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).not.toContain('unstable_instrumentations');\n });\n });\n});\n"]}
@@ -86,6 +86,7 @@ vitest_1.vi.mock('../../../src/utils/debug', () => ({
86
86
  const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
87
87
  (0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
88
88
  (0, vitest_1.expect)(modifiedContent).toContain('Sentry.captureException(error);');
89
+ (0, vitest_1.expect)(modifiedContent).toContain('error instanceof Error');
89
90
  });
90
91
  (0, vitest_1.it)('should add Sentry.captureException to existing variable declaration ErrorBoundary', async () => {
91
92
  const srcFile = path.join(fixturesDir, 'with-variable-error-boundary.tsx');
@@ -95,6 +96,7 @@ vitest_1.vi.mock('../../../src/utils/debug', () => ({
95
96
  (0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
96
97
  // Now properly handles variable declaration ErrorBoundary
97
98
  (0, vitest_1.expect)(modifiedContent).toContain('Sentry.captureException(error);');
99
+ (0, vitest_1.expect)(modifiedContent).toContain('error instanceof Error');
98
100
  });
99
101
  (0, vitest_1.it)('should not modify file when ErrorBoundary already has Sentry.captureException', async () => {
100
102
  const srcFile = path.join(fixturesDir, 'with-sentry-error-boundary.tsx');
@@ -138,6 +140,7 @@ vitest_1.vi.mock('../../../src/utils/debug', () => ({
138
140
  const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
139
141
  (0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
140
142
  (0, vitest_1.expect)(modifiedContent).toContain('Sentry.captureException(error);');
143
+ (0, vitest_1.expect)(modifiedContent).toContain('error instanceof Error');
141
144
  });
142
145
  (0, vitest_1.it)('should handle function declaration with separate export', async () => {
143
146
  const srcFile = path.join(fixturesDir, 'function-declaration-separate-export.tsx');
@@ -146,6 +149,7 @@ vitest_1.vi.mock('../../../src/utils/debug', () => ({
146
149
  const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
147
150
  (0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
148
151
  (0, vitest_1.expect)(modifiedContent).toContain('Sentry.captureException(error);');
152
+ (0, vitest_1.expect)(modifiedContent).toContain('error instanceof Error');
149
153
  // Should preserve function declaration syntax
150
154
  (0, vitest_1.expect)(modifiedContent).toMatch(/function ErrorBoundary\(/);
151
155
  (0, vitest_1.expect)(modifiedContent).toContain('export { ErrorBoundary }');
@@ -1 +1 @@
1
- {"version":3,"file":"root.test.js","sourceRoot":"","sources":["../../../../test/react-router/codemods/root.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { instrumentRoot } from '../../../src/react-router/codemods/root';\n\nvi.mock('@clack/prompts', () => {\n const mock = {\n log: {\n warn: vi.fn(),\n info: vi.fn(),\n success: vi.fn(),\n },\n };\n return {\n default: mock,\n ...mock,\n };\n});\n\nvi.mock('../../../src/utils/debug', () => ({\n debug: vi.fn(),\n}));\n\ndescribe('instrumentRoot', () => {\n const fixturesDir = path.join(__dirname, 'fixtures', 'root');\n let tmpDir: string;\n let appDir: string;\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n // Create unique tmp directory for each test\n tmpDir = path.join(\n fixturesDir,\n 'tmp',\n `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n appDir = path.join(tmpDir, 'app');\n\n // Ensure tmp and app directories exist\n fs.mkdirSync(appDir, { recursive: true });\n\n // Mock process.cwd() to return the tmp directory\n vi.spyOn(process, 'cwd').mockReturnValue(tmpDir);\n });\n\n afterEach(() => {\n // Clean up tmp directory\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n vi.restoreAllMocks();\n });\n\n it('should add ErrorBoundary when no ErrorBoundary exists and no Sentry content', async () => {\n // Copy fixture to tmp directory for testing\n const srcFile = path.join(fixturesDir, 'no-error-boundary.tsx');\n\n // Create app directory and copy file\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n // Mock process.cwd() to return tmpDir\n\n await instrumentRoot('root.tsx');\n\n // Check that the file was modified correctly\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain(\n \"import { Outlet, isRouteErrorResponse } from 'react-router';\",\n );\n expect(modifiedContent).toContain(\n 'export function ErrorBoundary({ error })',\n );\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n expect(modifiedContent).toContain('if (isRouteErrorResponse(error))');\n });\n\n it('should add Sentry.captureException to existing function declaration ErrorBoundary', async () => {\n const srcFile = path.join(fixturesDir, 'with-function-error-boundary.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n });\n\n it('should add Sentry.captureException to existing variable declaration ErrorBoundary', async () => {\n const srcFile = path.join(fixturesDir, 'with-variable-error-boundary.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n // Now properly handles variable declaration ErrorBoundary\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n });\n\n it('should not modify file when ErrorBoundary already has Sentry.captureException', async () => {\n const srcFile = path.join(fixturesDir, 'with-sentry-error-boundary.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n // Should not add duplicate Sentry.captureException\n const captureExceptionOccurrences = (\n modifiedContent.match(/Sentry\\.captureException/g) || []\n ).length;\n expect(captureExceptionOccurrences).toBe(1);\n });\n\n it('should not add Sentry import when Sentry content already exists', async () => {\n const srcFile = path.join(fixturesDir, 'with-existing-sentry.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n // Should not duplicate Sentry imports\n const sentryImportOccurrences = (\n modifiedContent.match(/import.*@sentry\\/react-router/g) || []\n ).length;\n expect(sentryImportOccurrences).toBe(1);\n });\n\n it('should add isRouteErrorResponse import when not present and ErrorBoundary is added', async () => {\n const srcFile = path.join(fixturesDir, 'no-isrouteerrorresponse.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n \"import { Outlet, isRouteErrorResponse } from 'react-router';\",\n );\n expect(modifiedContent).toContain(\n 'export function ErrorBoundary({ error })',\n );\n });\n\n it('should not add duplicate isRouteErrorResponse import when already present', async () => {\n const srcFile = path.join(fixturesDir, 'with-isrouteerrorresponse.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n // Should not duplicate isRouteErrorResponse imports\n const isRouteErrorResponseOccurrences = (\n modifiedContent.match(/isRouteErrorResponse/g) || []\n ).length;\n expect(isRouteErrorResponseOccurrences).toBe(2); // One import, one usage in template\n });\n\n it('should handle ErrorBoundary with alternative function declaration syntax', async () => {\n const srcFile = path.join(\n fixturesDir,\n 'function-expression-error-boundary.tsx',\n );\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n });\n\n it('should handle function declaration with separate export', async () => {\n const srcFile = path.join(\n fixturesDir,\n 'function-declaration-separate-export.tsx',\n );\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n\n // Should preserve function declaration syntax\n expect(modifiedContent).toMatch(/function ErrorBoundary\\(/);\n expect(modifiedContent).toContain('export { ErrorBoundary }');\n });\n\n it('should handle ErrorBoundary with captureException imported directly', async () => {\n const srcFile = path.join(fixturesDir, 'with-direct-capture-exception.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n // Should not add duplicate captureException calls\n const captureExceptionOccurrences = (\n modifiedContent.match(/captureException/g) || []\n ).length;\n expect(captureExceptionOccurrences).toBe(2); // One import, one usage\n });\n\n it('should not modify an already properly configured file', async () => {\n const srcFile = path.join(fixturesDir, 'fully-configured.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n // Should not add duplicate imports or modify existing Sentry configuration\n const sentryImportOccurrences = (\n modifiedContent.match(/import.*@sentry\\/react-router/g) || []\n ).length;\n expect(sentryImportOccurrences).toBe(1);\n\n const captureExceptionOccurrences = (\n modifiedContent.match(/Sentry\\.captureException/g) || []\n ).length;\n expect(captureExceptionOccurrences).toBe(1);\n\n const errorBoundaryOccurrences = (\n modifiedContent.match(/export function ErrorBoundary/g) || []\n ).length;\n expect(errorBoundaryOccurrences).toBe(1);\n\n expect(modifiedContent).toContain(\n \"import * as Sentry from '@sentry/react-router';\",\n );\n expect(modifiedContent).toContain(\n \"import { Outlet, isRouteErrorResponse } from 'react-router';\",\n );\n });\n});\n"]}
1
+ {"version":3,"file":"root.test.js","sourceRoot":"","sources":["../../../../test/react-router/codemods/root.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mCAAyE;AACzE,uCAAyB;AACzB,2CAA6B;AAC7B,kEAAyE;AAEzE,WAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC7B,MAAM,IAAI,GAAG;QACX,GAAG,EAAE;YACH,IAAI,EAAE,WAAE,CAAC,EAAE,EAAE;YACb,IAAI,EAAE,WAAE,CAAC,EAAE,EAAE;YACb,OAAO,EAAE,WAAE,CAAC,EAAE,EAAE;SACjB;KACF,CAAC;IACF,OAAO;QACL,OAAO,EAAE,IAAI;QACb,GAAG,IAAI;KACR,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,WAAE,CAAC,IAAI,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,CAAC;IACzC,KAAK,EAAE,WAAE,CAAC,EAAE,EAAE;CACf,CAAC,CAAC,CAAC;AAEJ,IAAA,iBAAQ,EAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IAC7D,IAAI,MAAc,CAAC;IACnB,IAAI,MAAc,CAAC;IAEnB,IAAA,mBAAU,EAAC,GAAG,EAAE;QACd,WAAE,CAAC,aAAa,EAAE,CAAC;QAEnB,4CAA4C;QAC5C,MAAM,GAAG,IAAI,CAAC,IAAI,CAChB,WAAW,EACX,KAAK,EACL,QAAQ,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAChE,CAAC;QACF,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAElC,uCAAuC;QACvC,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1C,iDAAiD;QACjD,WAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,IAAA,kBAAS,EAAC,GAAG,EAAE;QACb,yBAAyB;QACzB,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;YACzB,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;SACxC;QACD,WAAE,CAAC,eAAe,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;QAC3F,4CAA4C;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC;QAEhE,qCAAqC;QACrC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,sCAAsC;QAEtC,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,6CAA6C;QAC7C,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,iDAAiD,CAClD,CAAC;QACF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,8DAA8D,CAC/D,CAAC;QACF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,0CAA0C,CAC3C,CAAC;QACF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAC;QACrE,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,kCAAkC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,mFAAmF,EAAE,KAAK,IAAI,EAAE;QACjG,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,kCAAkC,CAAC,CAAC;QAE3E,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,iDAAiD,CAClD,CAAC;QACF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAC;QACrE,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,mFAAmF,EAAE,KAAK,IAAI,EAAE;QACjG,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,kCAAkC,CAAC,CAAC;QAE3E,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,iDAAiD,CAClD,CAAC;QACF,0DAA0D;QAC1D,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAC;QACrE,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAC7F,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,gCAAgC,CAAC,CAAC;QAEzE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,mDAAmD;QACnD,MAAM,2BAA2B,GAAG,CAClC,eAAe,CAAC,KAAK,CAAC,2BAA2B,CAAC,IAAI,EAAE,CACzD,CAAC,MAAM,CAAC;QACT,IAAA,eAAM,EAAC,2BAA2B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC;QAEnE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,sCAAsC;QACtC,MAAM,uBAAuB,GAAG,CAC9B,eAAe,CAAC,KAAK,CAAC,gCAAgC,CAAC,IAAI,EAAE,CAC9D,CAAC,MAAM,CAAC;QACT,IAAA,eAAM,EAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,oFAAoF,EAAE,KAAK,IAAI,EAAE;QAClG,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,6BAA6B,CAAC,CAAC;QAEtE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,8DAA8D,CAC/D,CAAC;QACF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,0CAA0C,CAC3C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;QACzF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,+BAA+B,CAAC,CAAC;QAExE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,oDAAoD;QACpD,MAAM,+BAA+B,GAAG,CACtC,eAAe,CAAC,KAAK,CAAC,uBAAuB,CAAC,IAAI,EAAE,CACrD,CAAC,MAAM,CAAC;QACT,IAAA,eAAM,EAAC,+BAA+B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,oCAAoC;IACvF,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CACvB,WAAW,EACX,wCAAwC,CACzC,CAAC;QAEF,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,iDAAiD,CAClD,CAAC;QACF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAC;QACrE,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CACvB,WAAW,EACX,0CAA0C,CAC3C,CAAC;QAEF,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,iDAAiD,CAClD,CAAC;QACF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAC;QACrE,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;QAE5D,8CAA8C;QAC9C,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;QAC5D,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,mCAAmC,CAAC,CAAC;QAE5E,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,kDAAkD;QAClD,MAAM,2BAA2B,GAAG,CAClC,eAAe,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,EAAE,CACjD,CAAC,MAAM,CAAC;QACT,IAAA,eAAM,EAAC,2BAA2B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;IACvE,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,sBAAsB,CAAC,CAAC;QAE/D,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAExD,MAAM,IAAA,qBAAc,EAAC,UAAU,CAAC,CAAC;QAEjC,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,MAAM,CACP,CAAC;QAEF,2EAA2E;QAC3E,MAAM,uBAAuB,GAAG,CAC9B,eAAe,CAAC,KAAK,CAAC,gCAAgC,CAAC,IAAI,EAAE,CAC9D,CAAC,MAAM,CAAC;QACT,IAAA,eAAM,EAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAExC,MAAM,2BAA2B,GAAG,CAClC,eAAe,CAAC,KAAK,CAAC,2BAA2B,CAAC,IAAI,EAAE,CACzD,CAAC,MAAM,CAAC;QACT,IAAA,eAAM,EAAC,2BAA2B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE5C,MAAM,wBAAwB,GAAG,CAC/B,eAAe,CAAC,KAAK,CAAC,gCAAgC,CAAC,IAAI,EAAE,CAC9D,CAAC,MAAM,CAAC;QACT,IAAA,eAAM,EAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEzC,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,iDAAiD,CAClD,CAAC;QACF,IAAA,eAAM,EAAC,eAAe,CAAC,CAAC,SAAS,CAC/B,8DAA8D,CAC/D,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { instrumentRoot } from '../../../src/react-router/codemods/root';\n\nvi.mock('@clack/prompts', () => {\n const mock = {\n log: {\n warn: vi.fn(),\n info: vi.fn(),\n success: vi.fn(),\n },\n };\n return {\n default: mock,\n ...mock,\n };\n});\n\nvi.mock('../../../src/utils/debug', () => ({\n debug: vi.fn(),\n}));\n\ndescribe('instrumentRoot', () => {\n const fixturesDir = path.join(__dirname, 'fixtures', 'root');\n let tmpDir: string;\n let appDir: string;\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n // Create unique tmp directory for each test\n tmpDir = path.join(\n fixturesDir,\n 'tmp',\n `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n appDir = path.join(tmpDir, 'app');\n\n // Ensure tmp and app directories exist\n fs.mkdirSync(appDir, { recursive: true });\n\n // Mock process.cwd() to return the tmp directory\n vi.spyOn(process, 'cwd').mockReturnValue(tmpDir);\n });\n\n afterEach(() => {\n // Clean up tmp directory\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n vi.restoreAllMocks();\n });\n\n it('should add ErrorBoundary when no ErrorBoundary exists and no Sentry content', async () => {\n // Copy fixture to tmp directory for testing\n const srcFile = path.join(fixturesDir, 'no-error-boundary.tsx');\n\n // Create app directory and copy file\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n // Mock process.cwd() to return tmpDir\n\n await instrumentRoot('root.tsx');\n\n // Check that the file was modified correctly\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain(\n \"import { Outlet, isRouteErrorResponse } from 'react-router';\",\n );\n expect(modifiedContent).toContain(\n 'export function ErrorBoundary({ error })',\n );\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n expect(modifiedContent).toContain('if (isRouteErrorResponse(error))');\n });\n\n it('should add Sentry.captureException to existing function declaration ErrorBoundary', async () => {\n const srcFile = path.join(fixturesDir, 'with-function-error-boundary.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n expect(modifiedContent).toContain('error instanceof Error');\n });\n\n it('should add Sentry.captureException to existing variable declaration ErrorBoundary', async () => {\n const srcFile = path.join(fixturesDir, 'with-variable-error-boundary.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n // Now properly handles variable declaration ErrorBoundary\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n expect(modifiedContent).toContain('error instanceof Error');\n });\n\n it('should not modify file when ErrorBoundary already has Sentry.captureException', async () => {\n const srcFile = path.join(fixturesDir, 'with-sentry-error-boundary.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n // Should not add duplicate Sentry.captureException\n const captureExceptionOccurrences = (\n modifiedContent.match(/Sentry\\.captureException/g) || []\n ).length;\n expect(captureExceptionOccurrences).toBe(1);\n });\n\n it('should not add Sentry import when Sentry content already exists', async () => {\n const srcFile = path.join(fixturesDir, 'with-existing-sentry.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n // Should not duplicate Sentry imports\n const sentryImportOccurrences = (\n modifiedContent.match(/import.*@sentry\\/react-router/g) || []\n ).length;\n expect(sentryImportOccurrences).toBe(1);\n });\n\n it('should add isRouteErrorResponse import when not present and ErrorBoundary is added', async () => {\n const srcFile = path.join(fixturesDir, 'no-isrouteerrorresponse.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n \"import { Outlet, isRouteErrorResponse } from 'react-router';\",\n );\n expect(modifiedContent).toContain(\n 'export function ErrorBoundary({ error })',\n );\n });\n\n it('should not add duplicate isRouteErrorResponse import when already present', async () => {\n const srcFile = path.join(fixturesDir, 'with-isrouteerrorresponse.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n // Should not duplicate isRouteErrorResponse imports\n const isRouteErrorResponseOccurrences = (\n modifiedContent.match(/isRouteErrorResponse/g) || []\n ).length;\n expect(isRouteErrorResponseOccurrences).toBe(2); // One import, one usage in template\n });\n\n it('should handle ErrorBoundary with alternative function declaration syntax', async () => {\n const srcFile = path.join(\n fixturesDir,\n 'function-expression-error-boundary.tsx',\n );\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n expect(modifiedContent).toContain('error instanceof Error');\n });\n\n it('should handle function declaration with separate export', async () => {\n const srcFile = path.join(\n fixturesDir,\n 'function-declaration-separate-export.tsx',\n );\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n expect(modifiedContent).toContain('error instanceof Error');\n\n // Should preserve function declaration syntax\n expect(modifiedContent).toMatch(/function ErrorBoundary\\(/);\n expect(modifiedContent).toContain('export { ErrorBoundary }');\n });\n\n it('should handle ErrorBoundary with captureException imported directly', async () => {\n const srcFile = path.join(fixturesDir, 'with-direct-capture-exception.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n // Should not add duplicate captureException calls\n const captureExceptionOccurrences = (\n modifiedContent.match(/captureException/g) || []\n ).length;\n expect(captureExceptionOccurrences).toBe(2); // One import, one usage\n });\n\n it('should not modify an already properly configured file', async () => {\n const srcFile = path.join(fixturesDir, 'fully-configured.tsx');\n\n fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));\n\n await instrumentRoot('root.tsx');\n\n const modifiedContent = fs.readFileSync(\n path.join(appDir, 'root.tsx'),\n 'utf8',\n );\n\n // Should not add duplicate imports or modify existing Sentry configuration\n const sentryImportOccurrences = (\n modifiedContent.match(/import.*@sentry\\/react-router/g) || []\n ).length;\n expect(sentryImportOccurrences).toBe(1);\n\n const captureExceptionOccurrences = (\n modifiedContent.match(/Sentry\\.captureException/g) || []\n ).length;\n expect(captureExceptionOccurrences).toBe(1);\n\n const errorBoundaryOccurrences = (\n modifiedContent.match(/export function ErrorBoundary/g) || []\n ).length;\n expect(errorBoundaryOccurrences).toBe(1);\n\n expect(modifiedContent).toContain(\n \"import * as Sentry from '@sentry/react-router';\",\n );\n expect(modifiedContent).toContain(\n \"import { Outlet, isRouteErrorResponse } from 'react-router';\",\n );\n });\n});\n"]}
@@ -80,6 +80,8 @@ vitest_1.vi.mock('../../../src/utils/debug', () => ({
80
80
  const lines = modifiedContent.split('\n');
81
81
  const sentryImportLine = lines.findIndex((line) => line.includes('import * as Sentry from "@sentry/react-router";'));
82
82
  (0, vitest_1.expect)(sentryImportLine).toBeGreaterThanOrEqual(0);
83
+ // Should make handleRequest async
84
+ (0, vitest_1.expect)(modifiedContent).toMatch(/async function handleRequest/);
83
85
  // Should create default handleError since none exists
84
86
  (0, vitest_1.expect)(modifiedContent).toContain('export const handleError = Sentry.createSentryHandleError({');
85
87
  (0, vitest_1.expect)(modifiedContent).toContain('logErrors: false');
@@ -111,6 +113,24 @@ vitest_1.vi.mock('../../../src/utils/debug', () => ({
111
113
  // Should preserve the variable export pattern
112
114
  (0, vitest_1.expect)(modifiedContent).toContain('export const handleError');
113
115
  });
116
+ (0, vitest_1.it)('should not add duplicate async keyword when handleRequest is already async', async () => {
117
+ const asyncContent = `
118
+ import { ServerRouter } from 'react-router';
119
+ import { renderToString } from 'react-dom/server';
120
+
121
+ export default async function handleRequest(request: Request) {
122
+ const html = renderToString(<ServerRouter />);
123
+ return new Response(html);
124
+ }
125
+ `;
126
+ fs.writeFileSync(tmpFile, asyncContent);
127
+ await (0, server_entry_1.instrumentServerEntry)(tmpFile);
128
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
129
+ // Should have async function handleRequest (not async async)
130
+ (0, vitest_1.expect)(modifiedContent).toMatch(/async function handleRequest/);
131
+ (0, vitest_1.expect)(modifiedContent).not.toMatch(/async\s+async/);
132
+ (0, vitest_1.expect)(modifiedContent).toContain('export default Sentry.wrapSentryHandleRequest(handleRequest);');
133
+ });
114
134
  });
115
135
  (0, vitest_1.describe)('instrumentHandleRequest', () => {
116
136
  let tmpDir;
@@ -412,4 +432,54 @@ export function handleError(error: unknown) {
412
432
  (0, vitest_1.expect)(thrownError).toBeNull();
413
433
  });
414
434
  });
435
+ (0, vitest_1.describe)('Instrumentation API', () => {
436
+ const fixturesDir = path.join(__dirname, 'fixtures', 'server-entry');
437
+ let tmpDir;
438
+ let tmpFile;
439
+ (0, vitest_1.beforeEach)(() => {
440
+ vitest_1.vi.clearAllMocks();
441
+ tmpDir = path.join(__dirname, 'fixtures', 'tmp', `test-instrumentation-api-${Date.now()}-${Math.random()
442
+ .toString(36)
443
+ .substring(2, 11)}`);
444
+ tmpFile = path.join(tmpDir, 'entry.server.tsx');
445
+ fs.mkdirSync(tmpDir, { recursive: true });
446
+ });
447
+ (0, vitest_1.afterEach)(() => {
448
+ if (fs.existsSync(tmpDir)) {
449
+ fs.rmSync(tmpDir, { recursive: true });
450
+ }
451
+ });
452
+ (0, vitest_1.it)('should add unstable_instrumentations export when useInstrumentationAPI is true', async () => {
453
+ const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
454
+ fs.writeFileSync(tmpFile, basicContent);
455
+ await (0, server_entry_1.instrumentServerEntry)(tmpFile, true);
456
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
457
+ (0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
458
+ (0, vitest_1.expect)(modifiedContent).toContain('export const unstable_instrumentations = [Sentry.createSentryServerInstrumentation()];');
459
+ });
460
+ (0, vitest_1.it)('should not add unstable_instrumentations export when useInstrumentationAPI is false', async () => {
461
+ const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
462
+ fs.writeFileSync(tmpFile, basicContent);
463
+ await (0, server_entry_1.instrumentServerEntry)(tmpFile, false);
464
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
465
+ (0, vitest_1.expect)(modifiedContent).not.toContain('unstable_instrumentations');
466
+ (0, vitest_1.expect)(modifiedContent).not.toContain('createSentryServerInstrumentation');
467
+ });
468
+ (0, vitest_1.it)('should not duplicate unstable_instrumentations export if already present', async () => {
469
+ const contentWithInstrumentations = `
470
+ import { ServerRouter } from 'react-router';
471
+ import * as Sentry from '@sentry/react-router';
472
+
473
+ export default function handleRequest() {}
474
+ export const handleError = () => {};
475
+ export const unstable_instrumentations = [Sentry.createSentryServerInstrumentation()];
476
+ `;
477
+ fs.writeFileSync(tmpFile, contentWithInstrumentations);
478
+ await (0, server_entry_1.instrumentServerEntry)(tmpFile, true);
479
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
480
+ const count = (modifiedContent.match(/unstable_instrumentations/g) || [])
481
+ .length;
482
+ (0, vitest_1.expect)(count).toBe(1);
483
+ });
484
+ });
415
485
  //# sourceMappingURL=server-entry.test.js.map