@sentry/wizard 6.12.0 → 6.13.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.
- package/CHANGELOG.md +15 -0
- package/dist/bin.js +16 -1
- package/dist/bin.js.map +1 -1
- package/dist/e2e-tests/tests/angular-17.test.js +3 -4
- package/dist/e2e-tests/tests/angular-17.test.js.map +1 -1
- package/dist/e2e-tests/tests/angular-19.test.js +3 -4
- package/dist/e2e-tests/tests/angular-19.test.js.map +1 -1
- package/dist/e2e-tests/tests/flutter.test.js +60 -0
- package/dist/e2e-tests/tests/flutter.test.js.map +1 -1
- package/dist/e2e-tests/tests/help-message.test.js +8 -3
- package/dist/e2e-tests/tests/help-message.test.js.map +1 -1
- package/dist/e2e-tests/tests/nuxt-3.test.js +12 -6
- package/dist/e2e-tests/tests/nuxt-3.test.js.map +1 -1
- package/dist/e2e-tests/tests/nuxt-4.test.js +12 -6
- package/dist/e2e-tests/tests/nuxt-4.test.js.map +1 -1
- package/dist/e2e-tests/tests/pnpm-workspace.test.js +6 -3
- package/dist/e2e-tests/tests/pnpm-workspace.test.js.map +1 -1
- package/dist/e2e-tests/tests/react-router-instrumentation-api.test.js +4 -4
- package/dist/e2e-tests/tests/react-router-instrumentation-api.test.js.map +1 -1
- package/dist/e2e-tests/tests/react-router.test.js +3 -6
- package/dist/e2e-tests/tests/react-router.test.js.map +1 -1
- package/dist/e2e-tests/tests/remix.test.js +2 -4
- package/dist/e2e-tests/tests/remix.test.js.map +1 -1
- package/dist/e2e-tests/tests/sveltekit-hooks.test.js +24 -8
- package/dist/e2e-tests/tests/sveltekit-hooks.test.js.map +1 -1
- package/dist/e2e-tests/tests/sveltekit-tracing.test.js +6 -3
- package/dist/e2e-tests/tests/sveltekit-tracing.test.js.map +1 -1
- package/dist/lib/Constants.d.ts +1 -0
- package/dist/lib/Constants.js +5 -0
- package/dist/lib/Constants.js.map +1 -1
- package/dist/lib/Steps/Integrations/Electron.js +2 -2
- package/dist/lib/Steps/Integrations/Electron.js.map +1 -1
- package/dist/src/android/android-wizard.js +3 -0
- package/dist/src/android/android-wizard.js.map +1 -1
- package/dist/src/angular/codemods/main.d.ts +1 -1
- package/dist/src/angular/codemods/main.js +0 -1
- package/dist/src/angular/codemods/main.js.map +1 -1
- package/dist/src/apple/apple-wizard.js +2 -3
- package/dist/src/apple/apple-wizard.js.map +1 -1
- package/dist/src/apple/check-installed-cli.d.ts +1 -1
- package/dist/src/apple/check-installed-cli.js +13 -7
- package/dist/src/apple/check-installed-cli.js.map +1 -1
- package/dist/src/apple/configure-xcode-project.js +8 -1
- package/dist/src/apple/configure-xcode-project.js.map +1 -1
- package/dist/src/apple/lookup-xcode-project.d.ts +8 -5
- package/dist/src/apple/lookup-xcode-project.js +22 -17
- package/dist/src/apple/lookup-xcode-project.js.map +1 -1
- package/dist/src/apple/options.d.ts +5 -0
- package/dist/src/apple/options.js.map +1 -1
- package/dist/src/apple/sentry-swift-package.d.ts +4 -0
- package/dist/src/apple/sentry-swift-package.js +17 -0
- package/dist/src/apple/sentry-swift-package.js.map +1 -0
- package/dist/src/apple/snapshots/apple-snapshots-wizard.d.ts +2 -0
- package/dist/src/apple/snapshots/apple-snapshots-wizard.js +251 -0
- package/dist/src/apple/snapshots/apple-snapshots-wizard.js.map +1 -0
- package/dist/src/apple/snapshots/configure-snapshotpreviews-xcode-project.d.ts +13 -0
- package/dist/src/apple/snapshots/configure-snapshotpreviews-xcode-project.js +48 -0
- package/dist/src/apple/snapshots/configure-snapshotpreviews-xcode-project.js.map +1 -0
- package/dist/src/apple/snapshots/snapshot-test-file.d.ts +18 -0
- package/dist/src/apple/snapshots/snapshot-test-file.js +122 -0
- package/dist/src/apple/snapshots/snapshot-test-file.js.map +1 -0
- package/dist/src/apple/snapshots/snapshot-verification-scheme.d.ts +6 -0
- package/dist/src/apple/snapshots/snapshot-verification-scheme.js +147 -0
- package/dist/src/apple/snapshots/snapshot-verification-scheme.js.map +1 -0
- package/dist/src/apple/snapshots/snapshotpreviews-package.d.ts +4 -0
- package/dist/src/apple/snapshots/snapshotpreviews-package.js +8 -0
- package/dist/src/apple/snapshots/snapshotpreviews-package.js.map +1 -0
- package/dist/src/apple/snapshots/snapshots-cli-preflight.d.ts +23 -0
- package/dist/src/apple/snapshots/snapshots-cli-preflight.js +136 -0
- package/dist/src/apple/snapshots/snapshots-cli-preflight.js.map +1 -0
- package/dist/src/apple/xcode-manager.d.ts +59 -1
- package/dist/src/apple/xcode-manager.js +507 -106
- package/dist/src/apple/xcode-manager.js.map +1 -1
- package/dist/src/flutter/flutter-wizard.js +3 -0
- package/dist/src/flutter/flutter-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.js +12 -6
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/nuxt/templates.js +12 -6
- package/dist/src/nuxt/templates.js.map +1 -1
- package/dist/src/react-router/codemods/client.entry.d.ts +1 -1
- package/dist/src/react-router/codemods/client.entry.js +93 -52
- package/dist/src/react-router/codemods/client.entry.js.map +1 -1
- package/dist/src/react-router/codemods/server-entry.js +8 -7
- package/dist/src/react-router/codemods/server-entry.js.map +1 -1
- package/dist/src/react-router/react-router-wizard.js +13 -19
- package/dist/src/react-router/react-router-wizard.js.map +1 -1
- package/dist/src/react-router/sdk-setup.d.ts +2 -2
- package/dist/src/react-router/sdk-setup.js +16 -15
- package/dist/src/react-router/sdk-setup.js.map +1 -1
- package/dist/src/react-router/templates.d.ts +1 -3
- package/dist/src/react-router/templates.js +24 -92
- package/dist/src/react-router/templates.js.map +1 -1
- package/dist/src/remix/sdk-setup.js +1 -2
- package/dist/src/remix/sdk-setup.js.map +1 -1
- package/dist/src/run.d.ts +4 -1
- package/dist/src/run.js +13 -0
- package/dist/src/run.js.map +1 -1
- package/dist/src/sourcemaps/tools/remix.js +4 -4
- package/dist/src/sourcemaps/tools/remix.js.map +1 -1
- package/dist/src/sveltekit/sdk-setup/setup.js +17 -4
- package/dist/src/sveltekit/sdk-setup/setup.js.map +1 -1
- package/dist/src/sveltekit/templates.js +12 -6
- package/dist/src/sveltekit/templates.js.map +1 -1
- package/dist/src/utils/clack/index.d.ts +2 -1
- package/dist/src/utils/clack/index.js +17 -6
- package/dist/src/utils/clack/index.js.map +1 -1
- package/dist/src/utils/files.d.ts +2 -0
- package/dist/src/utils/files.js +58 -0
- package/dist/src/utils/files.js.map +1 -0
- package/dist/src/utils/git.d.ts +3 -1
- package/dist/src/utils/git.js +2 -1
- package/dist/src/utils/git.js.map +1 -1
- package/dist/src/utils/line-endings.d.ts +1 -0
- package/dist/src/utils/line-endings.js +76 -0
- package/dist/src/utils/line-endings.js.map +1 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/test/angular/angular-wizard.test.js +0 -5
- package/dist/test/angular/angular-wizard.test.js.map +1 -1
- package/dist/test/apple/lookup-xcode-project.test.js +167 -0
- package/dist/test/apple/lookup-xcode-project.test.js.map +1 -0
- package/dist/test/apple/snapshots/apple-snapshots-wizard.test.d.ts +1 -0
- package/dist/test/apple/snapshots/apple-snapshots-wizard.test.js +487 -0
- package/dist/test/apple/snapshots/apple-snapshots-wizard.test.js.map +1 -0
- package/dist/test/apple/snapshots/hosted-test-target-fixture.d.ts +24 -0
- package/dist/test/apple/snapshots/hosted-test-target-fixture.js +191 -0
- package/dist/test/apple/snapshots/hosted-test-target-fixture.js.map +1 -0
- package/dist/test/apple/snapshots/snapshot-test-file.test.d.ts +1 -0
- package/dist/test/apple/snapshots/snapshot-test-file.test.js +110 -0
- package/dist/test/apple/snapshots/snapshot-test-file.test.js.map +1 -0
- package/dist/test/apple/snapshots/snapshot-verification-scheme.test.d.ts +1 -0
- package/dist/test/apple/snapshots/snapshot-verification-scheme.test.js +146 -0
- package/dist/test/apple/snapshots/snapshot-verification-scheme.test.js.map +1 -0
- package/dist/test/apple/snapshots/snapshotpreviews-xcode-smoke.test.d.ts +1 -0
- package/dist/test/apple/snapshots/snapshotpreviews-xcode-smoke.test.js +186 -0
- package/dist/test/apple/snapshots/snapshotpreviews-xcode-smoke.test.js.map +1 -0
- package/dist/test/apple/snapshots/snapshots-cli-preflight.test.d.ts +1 -0
- package/dist/test/apple/snapshots/snapshots-cli-preflight.test.js +192 -0
- package/dist/test/apple/snapshots/snapshots-cli-preflight.test.js.map +1 -0
- package/dist/test/apple/snapshots/source-file-insertion.test.d.ts +1 -0
- package/dist/test/apple/snapshots/source-file-insertion.test.js +77 -0
- package/dist/test/apple/snapshots/source-file-insertion.test.js.map +1 -0
- package/dist/test/apple/xcode-manager.test.js +452 -43
- package/dist/test/apple/xcode-manager.test.js.map +1 -1
- package/dist/test/constants.test.d.ts +1 -0
- package/dist/test/constants.test.js +12 -0
- package/dist/test/constants.test.js.map +1 -0
- package/dist/test/nextjs/templates.test.js +66 -33
- package/dist/test/nextjs/templates.test.js.map +1 -1
- package/dist/test/nuxt/templates.test.js +66 -36
- package/dist/test/nuxt/templates.test.js.map +1 -1
- package/dist/test/react-router/codemods/client-entry.test.js +15 -11
- package/dist/test/react-router/codemods/client-entry.test.js.map +1 -1
- package/dist/test/react-router/codemods/server-entry.test.js +21 -8
- package/dist/test/react-router/codemods/server-entry.test.js.map +1 -1
- package/dist/test/react-router/sdk-setup.test.js +46 -10
- package/dist/test/react-router/sdk-setup.test.js.map +1 -1
- package/dist/test/react-router/templates.test.js +26 -64
- package/dist/test/react-router/templates.test.js.map +1 -1
- package/dist/test/remix/build-script.test.d.ts +1 -0
- package/dist/test/remix/build-script.test.js +124 -0
- package/dist/test/remix/build-script.test.js.map +1 -0
- package/dist/test/remix/client-entry.test.js +4 -10
- package/dist/test/remix/client-entry.test.js.map +1 -1
- package/dist/test/run.test.d.ts +1 -0
- package/dist/test/run.test.js +137 -0
- package/dist/test/run.test.js.map +1 -0
- package/dist/test/sveltekit/templates.test.js +78 -27
- package/dist/test/sveltekit/templates.test.js.map +1 -1
- package/dist/test/utils/clack/index.test.js +101 -0
- package/dist/test/utils/clack/index.test.js.map +1 -1
- package/dist/test/utils/git.test.js +10 -0
- package/dist/test/utils/git.test.js.map +1 -1
- package/dist/test/utils/line-endings.test.d.ts +1 -0
- package/dist/test/utils/line-endings.test.js +103 -0
- package/dist/test/utils/line-endings.test.js.map +1 -0
- package/package.json +2 -2
- package/dist/src/react-router/codemods/root.d.ts +0 -1
- package/dist/src/react-router/codemods/root.js +0 -170
- package/dist/src/react-router/codemods/root.js.map +0 -1
- package/dist/test/react-router/codemods/root.test.js +0 -182
- package/dist/test/react-router/codemods/root.test.js.map +0 -1
- /package/dist/test/{react-router/codemods/root.test.d.ts → apple/lookup-xcode-project.test.d.ts} +0 -0
|
@@ -1,170 +0,0 @@
|
|
|
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
|
-
exports.instrumentRoot = void 0;
|
|
27
|
-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
28
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
29
|
-
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
30
|
-
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
31
|
-
const recast = __importStar(require("recast"));
|
|
32
|
-
const path = __importStar(require("path"));
|
|
33
|
-
const magicast_1 = require("magicast");
|
|
34
|
-
const templates_1 = require("../templates");
|
|
35
|
-
const ast_utils_1 = require("../../utils/ast-utils");
|
|
36
|
-
const debug_1 = require("../../utils/debug");
|
|
37
|
-
function hasCaptureExceptionCall(node) {
|
|
38
|
-
let found = false;
|
|
39
|
-
recast.visit(node, {
|
|
40
|
-
visitCallExpression(path) {
|
|
41
|
-
const callee = path.value.callee;
|
|
42
|
-
if ((callee.type === 'MemberExpression' &&
|
|
43
|
-
callee.object?.name === 'Sentry' &&
|
|
44
|
-
callee.property?.name === 'captureException') ||
|
|
45
|
-
(callee.type === 'Identifier' && callee.name === 'captureException')) {
|
|
46
|
-
found = true;
|
|
47
|
-
}
|
|
48
|
-
this.traverse(path);
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
return found;
|
|
52
|
-
}
|
|
53
|
-
function addCaptureExceptionCall(functionNode) {
|
|
54
|
-
const captureExceptionCall = recast.parse(`if (error && error instanceof Error) {\n Sentry.captureException(error);\n}`).program.body[0];
|
|
55
|
-
const functionBody = (0, ast_utils_1.safeGetFunctionBody)(functionNode);
|
|
56
|
-
if (functionBody) {
|
|
57
|
-
if (!(0, ast_utils_1.safeInsertBeforeReturn)(functionBody, captureExceptionCall)) {
|
|
58
|
-
functionBody.push(captureExceptionCall);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
(0, debug_1.debug)('Could not safely access ErrorBoundary function body');
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
function findErrorBoundaryInExports(namedExports) {
|
|
66
|
-
return namedExports.some((namedExport) => {
|
|
67
|
-
const declaration = namedExport.declaration;
|
|
68
|
-
if (!declaration) {
|
|
69
|
-
return namedExport.specifiers?.some((spec) => spec.type === 'ExportSpecifier' &&
|
|
70
|
-
spec.exported?.type === 'Identifier' &&
|
|
71
|
-
spec.exported.name === 'ErrorBoundary');
|
|
72
|
-
}
|
|
73
|
-
if (declaration.type === 'FunctionDeclaration') {
|
|
74
|
-
return declaration.id?.name === 'ErrorBoundary';
|
|
75
|
-
}
|
|
76
|
-
if (declaration.type === 'VariableDeclaration') {
|
|
77
|
-
return declaration.declarations.some((decl) => {
|
|
78
|
-
// @ts-expect-error - id should always have a name in this case
|
|
79
|
-
return decl.id?.name === 'ErrorBoundary';
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
return false;
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
async function instrumentRoot(rootFileName) {
|
|
86
|
-
const filePath = path.join(process.cwd(), 'app', rootFileName);
|
|
87
|
-
const rootRouteAst = await (0, magicast_1.loadFile)(filePath);
|
|
88
|
-
const exportsAst = rootRouteAst.exports.$ast;
|
|
89
|
-
const namedExports = exportsAst.body.filter((node) => node.type === 'ExportNamedDeclaration');
|
|
90
|
-
const foundErrorBoundary = findErrorBoundaryInExports(namedExports);
|
|
91
|
-
const alreadyHasSentry = (0, ast_utils_1.hasSentryContent)(rootRouteAst.$ast);
|
|
92
|
-
if (!alreadyHasSentry) {
|
|
93
|
-
rootRouteAst.imports.$add({
|
|
94
|
-
from: '@sentry/react-router',
|
|
95
|
-
imported: '*',
|
|
96
|
-
local: 'Sentry',
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
if (!foundErrorBoundary) {
|
|
100
|
-
const hasIsRouteErrorResponseImport = rootRouteAst.imports.$items.some((item) => item.imported === 'isRouteErrorResponse' &&
|
|
101
|
-
item.from === 'react-router');
|
|
102
|
-
if (!hasIsRouteErrorResponseImport) {
|
|
103
|
-
rootRouteAst.imports.$add({
|
|
104
|
-
from: 'react-router',
|
|
105
|
-
imported: 'isRouteErrorResponse',
|
|
106
|
-
local: 'isRouteErrorResponse',
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
recast.visit(rootRouteAst.$ast, {
|
|
110
|
-
visitExportDefaultDeclaration(path) {
|
|
111
|
-
const implementation = recast.parse(templates_1.ERROR_BOUNDARY_TEMPLATE).program
|
|
112
|
-
.body[0];
|
|
113
|
-
path.insertBefore(recast.types.builders.exportDeclaration(false, implementation));
|
|
114
|
-
this.traverse(path);
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
recast.visit(rootRouteAst.$ast, {
|
|
120
|
-
visitExportNamedDeclaration(path) {
|
|
121
|
-
const declaration = path.value.declaration;
|
|
122
|
-
if (!declaration) {
|
|
123
|
-
this.traverse(path);
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
let functionToInstrument = null;
|
|
127
|
-
if (declaration.type === 'FunctionDeclaration' &&
|
|
128
|
-
declaration.id?.name === 'ErrorBoundary') {
|
|
129
|
-
functionToInstrument = declaration;
|
|
130
|
-
}
|
|
131
|
-
else if (declaration.type === 'VariableDeclaration' &&
|
|
132
|
-
declaration.declarations?.[0]?.id?.name === 'ErrorBoundary') {
|
|
133
|
-
const init = declaration.declarations[0].init;
|
|
134
|
-
if (init &&
|
|
135
|
-
(init.type === 'FunctionExpression' ||
|
|
136
|
-
init.type === 'ArrowFunctionExpression')) {
|
|
137
|
-
functionToInstrument = init;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (functionToInstrument &&
|
|
141
|
-
!hasCaptureExceptionCall(functionToInstrument)) {
|
|
142
|
-
addCaptureExceptionCall(functionToInstrument);
|
|
143
|
-
}
|
|
144
|
-
this.traverse(path);
|
|
145
|
-
},
|
|
146
|
-
visitVariableDeclaration(path) {
|
|
147
|
-
if (path.value.declarations?.[0]?.id?.name === 'ErrorBoundary') {
|
|
148
|
-
const init = path.value.declarations[0].init;
|
|
149
|
-
if (init &&
|
|
150
|
-
(init.type === 'FunctionExpression' ||
|
|
151
|
-
init.type === 'ArrowFunctionExpression') &&
|
|
152
|
-
!hasCaptureExceptionCall(init)) {
|
|
153
|
-
addCaptureExceptionCall(init);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
this.traverse(path);
|
|
157
|
-
},
|
|
158
|
-
visitFunctionDeclaration(path) {
|
|
159
|
-
if (path.value.id?.name === 'ErrorBoundary' &&
|
|
160
|
-
!hasCaptureExceptionCall(path.value)) {
|
|
161
|
-
addCaptureExceptionCall(path.value);
|
|
162
|
-
}
|
|
163
|
-
this.traverse(path);
|
|
164
|
-
},
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
await (0, magicast_1.writeFile)(rootRouteAst.$ast, filePath);
|
|
168
|
-
}
|
|
169
|
-
exports.instrumentRoot = instrumentRoot;
|
|
170
|
-
//# sourceMappingURL=root.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"root.js","sourceRoot":"","sources":["../../../../src/react-router/codemods/root.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+DAA+D;AAC/D,4DAA4D;AAC5D,sDAAsD;AACtD,0DAA0D;AAC1D,+CAAiC;AACjC,2CAA6B;AAK7B,uCAIkB;AAElB,4CAAuD;AACvD,qDAI+B;AAC/B,6CAA0C;AAE1C,SAAS,uBAAuB,CAAC,IAAY;IAC3C,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;QACjB,mBAAmB,CAAC,IAAI;YACtB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YACjC,IACE,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;gBACjC,MAAM,CAAC,MAAM,EAAE,IAAI,KAAK,QAAQ;gBAChC,MAAM,CAAC,QAAQ,EAAE,IAAI,KAAK,kBAAkB,CAAC;gBAC/C,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB,CAAC,EACpE;gBACA,KAAK,GAAG,IAAI,CAAC;aACd;YACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;KACF,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,uBAAuB,CAAC,YAAoB;IACnD,MAAM,oBAAoB,GAAG,MAAM,CAAC,KAAK,CACvC,8EAA8E,CAC/E,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAElB,MAAM,YAAY,GAAG,IAAA,+BAAmB,EAAC,YAAY,CAAC,CAAC;IACvD,IAAI,YAAY,EAAE;QAChB,IAAI,CAAC,IAAA,kCAAsB,EAAC,YAAY,EAAE,oBAAoB,CAAC,EAAE;YAC/D,YAAY,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;SACzC;KACF;SAAM;QACL,IAAA,aAAK,EAAC,qDAAqD,CAAC,CAAC;KAC9D;AACH,CAAC;AAED,SAAS,0BAA0B,CACjC,YAAsC;IAEtC,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE;QACvC,MAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC;QAE5C,IAAI,CAAC,WAAW,EAAE;YAChB,OAAO,WAAW,CAAC,UAAU,EAAE,IAAI,CACjC,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,IAAI,KAAK,iBAAiB;gBAC/B,IAAI,CAAC,QAAQ,EAAE,IAAI,KAAK,YAAY;gBACpC,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,eAAe,CACzC,CAAC;SACH;QAED,IAAI,WAAW,CAAC,IAAI,KAAK,qBAAqB,EAAE;YAC9C,OAAO,WAAW,CAAC,EAAE,EAAE,IAAI,KAAK,eAAe,CAAC;SACjD;QAED,IAAI,WAAW,CAAC,IAAI,KAAK,qBAAqB,EAAE;YAC9C,OAAO,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;gBAC5C,+DAA+D;gBAC/D,OAAO,IAAI,CAAC,EAAE,EAAE,IAAI,KAAK,eAAe,CAAC;YAC3C,CAAC,CAAC,CAAC;SACJ;QAED,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,YAAoB;IACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAC/D,MAAM,YAAY,GAAG,MAAM,IAAA,mBAAQ,EAAC,QAAQ,CAAC,CAAC;IAE9C,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,IAAiB,CAAC;IAC1D,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CACzC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,wBAAwB,CACrB,CAAC;IAE9B,MAAM,kBAAkB,GAAG,0BAA0B,CAAC,YAAY,CAAC,CAAC;IACpE,MAAM,gBAAgB,GAAG,IAAA,4BAAgB,EAAC,YAAY,CAAC,IAAiB,CAAC,CAAC;IAE1E,IAAI,CAAC,gBAAgB,EAAE;QACrB,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC;YACxB,IAAI,EAAE,sBAAsB;YAC5B,QAAQ,EAAE,GAAG;YACb,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;KACJ;IAED,IAAI,CAAC,kBAAkB,EAAE;QACvB,MAAM,6BAA6B,GAAG,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CACpE,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,QAAQ,KAAK,sBAAsB;YACxC,IAAI,CAAC,IAAI,KAAK,cAAc,CAC/B,CAAC;QAEF,IAAI,CAAC,6BAA6B,EAAE;YAClC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC;gBACxB,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,sBAAsB;gBAChC,KAAK,EAAE,sBAAsB;aAC9B,CAAC,CAAC;SACJ;QAED,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE;YAC9B,6BAA6B,CAAC,IAAI;gBAChC,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,mCAAuB,CAAC,CAAC,OAAO;qBACjE,IAAI,CAAC,CAAC,CAAC,CAAC;gBAEX,IAAI,CAAC,YAAY,CACf,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC,KAAK,EAAE,cAAc,CAAC,CAC/D,CAAC;gBAEF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;SACF,CAAC,CAAC;KACJ;SAAM;QACL,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE;YAC9B,2BAA2B,CAAC,IAAI;gBAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;gBAC3C,IAAI,CAAC,WAAW,EAAE;oBAChB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;oBACpB,OAAO;iBACR;gBAED,IAAI,oBAAoB,GAAG,IAAI,CAAC;gBAEhC,IACE,WAAW,CAAC,IAAI,KAAK,qBAAqB;oBAC1C,WAAW,CAAC,EAAE,EAAE,IAAI,KAAK,eAAe,EACxC;oBACA,oBAAoB,GAAG,WAAW,CAAC;iBACpC;qBAAM,IACL,WAAW,CAAC,IAAI,KAAK,qBAAqB;oBAC1C,WAAW,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,KAAK,eAAe,EAC3D;oBACA,MAAM,IAAI,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC9C,IACE,IAAI;wBACJ,CAAC,IAAI,CAAC,IAAI,KAAK,oBAAoB;4BACjC,IAAI,CAAC,IAAI,KAAK,yBAAyB,CAAC,EAC1C;wBACA,oBAAoB,GAAG,IAAI,CAAC;qBAC7B;iBACF;gBAED,IACE,oBAAoB;oBACpB,CAAC,uBAAuB,CAAC,oBAAoB,CAAC,EAC9C;oBACA,uBAAuB,CAAC,oBAAoB,CAAC,CAAC;iBAC/C;gBAED,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;YAED,wBAAwB,CAAC,IAAI;gBAC3B,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,KAAK,eAAe,EAAE;oBAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC7C,IACE,IAAI;wBACJ,CAAC,IAAI,CAAC,IAAI,KAAK,oBAAoB;4BACjC,IAAI,CAAC,IAAI,KAAK,yBAAyB,CAAC;wBAC1C,CAAC,uBAAuB,CAAC,IAAI,CAAC,EAC9B;wBACA,uBAAuB,CAAC,IAAI,CAAC,CAAC;qBAC/B;iBACF;gBACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;YAED,wBAAwB,CAAC,IAAI;gBAC3B,IACE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,KAAK,eAAe;oBACvC,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,EACpC;oBACA,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;iBACrC;gBACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;SACF,CAAC,CAAC;KACJ;IAED,MAAM,IAAA,oBAAS,EAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC/C,CAAC;AAnHD,wCAmHC","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 } from '@babel/types';\nimport type { namedTypes as t } from 'ast-types';\n\nimport {\n loadFile,\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 {\n hasSentryContent,\n safeGetFunctionBody,\n safeInsertBeforeReturn,\n} from '../../utils/ast-utils';\nimport { debug } from '../../utils/debug';\n\nfunction hasCaptureExceptionCall(node: t.Node): boolean {\n let found = false;\n recast.visit(node, {\n visitCallExpression(path) {\n const callee = path.value.callee;\n if (\n (callee.type === 'MemberExpression' &&\n callee.object?.name === 'Sentry' &&\n callee.property?.name === 'captureException') ||\n (callee.type === 'Identifier' && callee.name === 'captureException')\n ) {\n found = true;\n }\n this.traverse(path);\n },\n });\n return found;\n}\n\nfunction addCaptureExceptionCall(functionNode: t.Node): void {\n const captureExceptionCall = recast.parse(\n `if (error && error instanceof Error) {\\n Sentry.captureException(error);\\n}`,\n ).program.body[0];\n\n const functionBody = safeGetFunctionBody(functionNode);\n if (functionBody) {\n if (!safeInsertBeforeReturn(functionBody, captureExceptionCall)) {\n functionBody.push(captureExceptionCall);\n }\n } else {\n debug('Could not safely access ErrorBoundary function body');\n }\n}\n\nfunction findErrorBoundaryInExports(\n namedExports: ExportNamedDeclaration[],\n): boolean {\n return namedExports.some((namedExport) => {\n const declaration = namedExport.declaration;\n\n if (!declaration) {\n return namedExport.specifiers?.some(\n (spec) =>\n spec.type === 'ExportSpecifier' &&\n spec.exported?.type === 'Identifier' &&\n spec.exported.name === 'ErrorBoundary',\n );\n }\n\n if (declaration.type === 'FunctionDeclaration') {\n return declaration.id?.name === 'ErrorBoundary';\n }\n\n if (declaration.type === 'VariableDeclaration') {\n return declaration.declarations.some((decl) => {\n // @ts-expect-error - id should always have a name in this case\n return decl.id?.name === 'ErrorBoundary';\n });\n }\n\n return false;\n });\n}\n\nexport async function instrumentRoot(rootFileName: string): Promise<void> {\n const filePath = path.join(process.cwd(), 'app', rootFileName);\n const rootRouteAst = await loadFile(filePath);\n\n const exportsAst = rootRouteAst.exports.$ast as t.Program;\n const namedExports = exportsAst.body.filter(\n (node) => node.type === 'ExportNamedDeclaration',\n ) as ExportNamedDeclaration[];\n\n const foundErrorBoundary = findErrorBoundaryInExports(namedExports);\n const alreadyHasSentry = hasSentryContent(rootRouteAst.$ast as t.Program);\n\n if (!alreadyHasSentry) {\n rootRouteAst.imports.$add({\n from: '@sentry/react-router',\n imported: '*',\n local: 'Sentry',\n });\n }\n\n if (!foundErrorBoundary) {\n const hasIsRouteErrorResponseImport = rootRouteAst.imports.$items.some(\n (item) =>\n item.imported === 'isRouteErrorResponse' &&\n item.from === 'react-router',\n );\n\n if (!hasIsRouteErrorResponseImport) {\n rootRouteAst.imports.$add({\n from: 'react-router',\n imported: 'isRouteErrorResponse',\n local: 'isRouteErrorResponse',\n });\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 } else {\n recast.visit(rootRouteAst.$ast, {\n visitExportNamedDeclaration(path) {\n const declaration = path.value.declaration;\n if (!declaration) {\n this.traverse(path);\n return;\n }\n\n let functionToInstrument = null;\n\n if (\n declaration.type === 'FunctionDeclaration' &&\n declaration.id?.name === 'ErrorBoundary'\n ) {\n functionToInstrument = declaration;\n } else if (\n declaration.type === 'VariableDeclaration' &&\n declaration.declarations?.[0]?.id?.name === 'ErrorBoundary'\n ) {\n const init = declaration.declarations[0].init;\n if (\n init &&\n (init.type === 'FunctionExpression' ||\n init.type === 'ArrowFunctionExpression')\n ) {\n functionToInstrument = init;\n }\n }\n\n if (\n functionToInstrument &&\n !hasCaptureExceptionCall(functionToInstrument)\n ) {\n addCaptureExceptionCall(functionToInstrument);\n }\n\n this.traverse(path);\n },\n\n visitVariableDeclaration(path) {\n if (path.value.declarations?.[0]?.id?.name === 'ErrorBoundary') {\n const init = path.value.declarations[0].init;\n if (\n init &&\n (init.type === 'FunctionExpression' ||\n init.type === 'ArrowFunctionExpression') &&\n !hasCaptureExceptionCall(init)\n ) {\n addCaptureExceptionCall(init);\n }\n }\n this.traverse(path);\n },\n\n visitFunctionDeclaration(path) {\n if (\n path.value.id?.name === 'ErrorBoundary' &&\n !hasCaptureExceptionCall(path.value)\n ) {\n addCaptureExceptionCall(path.value);\n }\n this.traverse(path);\n },\n });\n }\n\n await writeFile(rootRouteAst.$ast, filePath);\n}\n"]}
|
|
@@ -1,182 +0,0 @@
|
|
|
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 path = __importStar(require("path"));
|
|
29
|
-
const root_1 = require("../../../src/react-router/codemods/root");
|
|
30
|
-
vitest_1.vi.mock('@clack/prompts', () => {
|
|
31
|
-
const mock = {
|
|
32
|
-
log: {
|
|
33
|
-
warn: vitest_1.vi.fn(),
|
|
34
|
-
info: vitest_1.vi.fn(),
|
|
35
|
-
success: vitest_1.vi.fn(),
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
return {
|
|
39
|
-
default: mock,
|
|
40
|
-
...mock,
|
|
41
|
-
};
|
|
42
|
-
});
|
|
43
|
-
vitest_1.vi.mock('../../../src/utils/debug', () => ({
|
|
44
|
-
debug: vitest_1.vi.fn(),
|
|
45
|
-
}));
|
|
46
|
-
(0, vitest_1.describe)('instrumentRoot', () => {
|
|
47
|
-
const fixturesDir = path.join(__dirname, 'fixtures', 'root');
|
|
48
|
-
let tmpDir;
|
|
49
|
-
let appDir;
|
|
50
|
-
(0, vitest_1.beforeEach)(() => {
|
|
51
|
-
vitest_1.vi.clearAllMocks();
|
|
52
|
-
// Create unique tmp directory for each test
|
|
53
|
-
tmpDir = path.join(fixturesDir, 'tmp', `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`);
|
|
54
|
-
appDir = path.join(tmpDir, 'app');
|
|
55
|
-
// Ensure tmp and app directories exist
|
|
56
|
-
fs.mkdirSync(appDir, { recursive: true });
|
|
57
|
-
// Mock process.cwd() to return the tmp directory
|
|
58
|
-
vitest_1.vi.spyOn(process, 'cwd').mockReturnValue(tmpDir);
|
|
59
|
-
});
|
|
60
|
-
(0, vitest_1.afterEach)(() => {
|
|
61
|
-
// Clean up tmp directory
|
|
62
|
-
if (fs.existsSync(tmpDir)) {
|
|
63
|
-
fs.rmSync(tmpDir, { recursive: true });
|
|
64
|
-
}
|
|
65
|
-
vitest_1.vi.restoreAllMocks();
|
|
66
|
-
});
|
|
67
|
-
(0, vitest_1.it)('should add ErrorBoundary when no ErrorBoundary exists and no Sentry content', async () => {
|
|
68
|
-
// Copy fixture to tmp directory for testing
|
|
69
|
-
const srcFile = path.join(fixturesDir, 'no-error-boundary.tsx');
|
|
70
|
-
// Create app directory and copy file
|
|
71
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
72
|
-
// Mock process.cwd() to return tmpDir
|
|
73
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
74
|
-
// Check that the file was modified correctly
|
|
75
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
76
|
-
(0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
|
|
77
|
-
(0, vitest_1.expect)(modifiedContent).toContain("import { Outlet, isRouteErrorResponse } from 'react-router';");
|
|
78
|
-
(0, vitest_1.expect)(modifiedContent).toContain('export function ErrorBoundary({ error })');
|
|
79
|
-
(0, vitest_1.expect)(modifiedContent).toContain('Sentry.captureException(error);');
|
|
80
|
-
(0, vitest_1.expect)(modifiedContent).toContain('if (isRouteErrorResponse(error))');
|
|
81
|
-
});
|
|
82
|
-
(0, vitest_1.it)('should add Sentry.captureException to existing function declaration ErrorBoundary', async () => {
|
|
83
|
-
const srcFile = path.join(fixturesDir, 'with-function-error-boundary.tsx');
|
|
84
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
85
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
86
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
87
|
-
(0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
|
|
88
|
-
(0, vitest_1.expect)(modifiedContent).toContain('Sentry.captureException(error);');
|
|
89
|
-
(0, vitest_1.expect)(modifiedContent).toContain('error instanceof Error');
|
|
90
|
-
});
|
|
91
|
-
(0, vitest_1.it)('should add Sentry.captureException to existing variable declaration ErrorBoundary', async () => {
|
|
92
|
-
const srcFile = path.join(fixturesDir, 'with-variable-error-boundary.tsx');
|
|
93
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
94
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
95
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
96
|
-
(0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
|
|
97
|
-
// Now properly handles variable declaration ErrorBoundary
|
|
98
|
-
(0, vitest_1.expect)(modifiedContent).toContain('Sentry.captureException(error);');
|
|
99
|
-
(0, vitest_1.expect)(modifiedContent).toContain('error instanceof Error');
|
|
100
|
-
});
|
|
101
|
-
(0, vitest_1.it)('should not modify file when ErrorBoundary already has Sentry.captureException', async () => {
|
|
102
|
-
const srcFile = path.join(fixturesDir, 'with-sentry-error-boundary.tsx');
|
|
103
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
104
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
105
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
106
|
-
// Should not add duplicate Sentry.captureException
|
|
107
|
-
const captureExceptionOccurrences = (modifiedContent.match(/Sentry\.captureException/g) || []).length;
|
|
108
|
-
(0, vitest_1.expect)(captureExceptionOccurrences).toBe(1);
|
|
109
|
-
});
|
|
110
|
-
(0, vitest_1.it)('should not add Sentry import when Sentry content already exists', async () => {
|
|
111
|
-
const srcFile = path.join(fixturesDir, 'with-existing-sentry.tsx');
|
|
112
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
113
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
114
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
115
|
-
// Should not duplicate Sentry imports
|
|
116
|
-
const sentryImportOccurrences = (modifiedContent.match(/import.*@sentry\/react-router/g) || []).length;
|
|
117
|
-
(0, vitest_1.expect)(sentryImportOccurrences).toBe(1);
|
|
118
|
-
});
|
|
119
|
-
(0, vitest_1.it)('should add isRouteErrorResponse import when not present and ErrorBoundary is added', async () => {
|
|
120
|
-
const srcFile = path.join(fixturesDir, 'no-isrouteerrorresponse.tsx');
|
|
121
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
122
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
123
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
124
|
-
(0, vitest_1.expect)(modifiedContent).toContain("import { Outlet, isRouteErrorResponse } from 'react-router';");
|
|
125
|
-
(0, vitest_1.expect)(modifiedContent).toContain('export function ErrorBoundary({ error })');
|
|
126
|
-
});
|
|
127
|
-
(0, vitest_1.it)('should not add duplicate isRouteErrorResponse import when already present', async () => {
|
|
128
|
-
const srcFile = path.join(fixturesDir, 'with-isrouteerrorresponse.tsx');
|
|
129
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
130
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
131
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
132
|
-
// Should not duplicate isRouteErrorResponse imports
|
|
133
|
-
const isRouteErrorResponseOccurrences = (modifiedContent.match(/isRouteErrorResponse/g) || []).length;
|
|
134
|
-
(0, vitest_1.expect)(isRouteErrorResponseOccurrences).toBe(2); // One import, one usage in template
|
|
135
|
-
});
|
|
136
|
-
(0, vitest_1.it)('should handle ErrorBoundary with alternative function declaration syntax', async () => {
|
|
137
|
-
const srcFile = path.join(fixturesDir, 'function-expression-error-boundary.tsx');
|
|
138
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
139
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
140
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
141
|
-
(0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
|
|
142
|
-
(0, vitest_1.expect)(modifiedContent).toContain('Sentry.captureException(error);');
|
|
143
|
-
(0, vitest_1.expect)(modifiedContent).toContain('error instanceof Error');
|
|
144
|
-
});
|
|
145
|
-
(0, vitest_1.it)('should handle function declaration with separate export', async () => {
|
|
146
|
-
const srcFile = path.join(fixturesDir, 'function-declaration-separate-export.tsx');
|
|
147
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
148
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
149
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
150
|
-
(0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
|
|
151
|
-
(0, vitest_1.expect)(modifiedContent).toContain('Sentry.captureException(error);');
|
|
152
|
-
(0, vitest_1.expect)(modifiedContent).toContain('error instanceof Error');
|
|
153
|
-
// Should preserve function declaration syntax
|
|
154
|
-
(0, vitest_1.expect)(modifiedContent).toMatch(/function ErrorBoundary\(/);
|
|
155
|
-
(0, vitest_1.expect)(modifiedContent).toContain('export { ErrorBoundary }');
|
|
156
|
-
});
|
|
157
|
-
(0, vitest_1.it)('should handle ErrorBoundary with captureException imported directly', async () => {
|
|
158
|
-
const srcFile = path.join(fixturesDir, 'with-direct-capture-exception.tsx');
|
|
159
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
160
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
161
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
162
|
-
// Should not add duplicate captureException calls
|
|
163
|
-
const captureExceptionOccurrences = (modifiedContent.match(/captureException/g) || []).length;
|
|
164
|
-
(0, vitest_1.expect)(captureExceptionOccurrences).toBe(2); // One import, one usage
|
|
165
|
-
});
|
|
166
|
-
(0, vitest_1.it)('should not modify an already properly configured file', async () => {
|
|
167
|
-
const srcFile = path.join(fixturesDir, 'fully-configured.tsx');
|
|
168
|
-
fs.copyFileSync(srcFile, path.join(appDir, 'root.tsx'));
|
|
169
|
-
await (0, root_1.instrumentRoot)('root.tsx');
|
|
170
|
-
const modifiedContent = fs.readFileSync(path.join(appDir, 'root.tsx'), 'utf8');
|
|
171
|
-
// Should not add duplicate imports or modify existing Sentry configuration
|
|
172
|
-
const sentryImportOccurrences = (modifiedContent.match(/import.*@sentry\/react-router/g) || []).length;
|
|
173
|
-
(0, vitest_1.expect)(sentryImportOccurrences).toBe(1);
|
|
174
|
-
const captureExceptionOccurrences = (modifiedContent.match(/Sentry\.captureException/g) || []).length;
|
|
175
|
-
(0, vitest_1.expect)(captureExceptionOccurrences).toBe(1);
|
|
176
|
-
const errorBoundaryOccurrences = (modifiedContent.match(/export function ErrorBoundary/g) || []).length;
|
|
177
|
-
(0, vitest_1.expect)(errorBoundaryOccurrences).toBe(1);
|
|
178
|
-
(0, vitest_1.expect)(modifiedContent).toContain("import * as Sentry from '@sentry/react-router';");
|
|
179
|
-
(0, vitest_1.expect)(modifiedContent).toContain("import { Outlet, isRouteErrorResponse } from 'react-router';");
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
//# sourceMappingURL=root.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
/package/dist/test/{react-router/codemods/root.test.d.ts → apple/lookup-xcode-project.test.d.ts}
RENAMED
|
File without changes
|