@sentry/wizard 3.10.0 → 3.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 (150) hide show
  1. package/CHANGELOG.md +54 -7
  2. package/dist/lib/Constants.d.ts +1 -0
  3. package/dist/lib/Constants.js +5 -0
  4. package/dist/lib/Constants.js.map +1 -1
  5. package/dist/lib/Steps/ChooseIntegration.js +8 -4
  6. package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
  7. package/dist/lib/Steps/Integrations/Android.d.ts +9 -0
  8. package/dist/lib/Steps/Integrations/Android.js +86 -0
  9. package/dist/lib/Steps/Integrations/Android.js.map +1 -0
  10. package/dist/lib/Steps/Integrations/ReactNative.js +3 -3
  11. package/dist/lib/Steps/Integrations/ReactNative.js.map +1 -1
  12. package/dist/lib/Steps/PromptForParameters.js +36 -3
  13. package/dist/lib/Steps/PromptForParameters.js.map +1 -1
  14. package/dist/lib/Steps/SentryProjectSelector.js +1 -1
  15. package/dist/lib/Steps/SentryProjectSelector.js.map +1 -1
  16. package/dist/package.json +4 -3
  17. package/dist/src/android/android-wizard.d.ts +2 -0
  18. package/dist/src/android/android-wizard.js +225 -0
  19. package/dist/src/android/android-wizard.js.map +1 -0
  20. package/dist/src/android/code-tools.d.ts +47 -0
  21. package/dist/src/android/code-tools.js +173 -0
  22. package/dist/src/android/code-tools.js.map +1 -0
  23. package/dist/src/android/gradle.d.ts +62 -0
  24. package/dist/src/android/gradle.js +286 -0
  25. package/dist/src/android/gradle.js.map +1 -0
  26. package/dist/src/android/manifest.d.ts +57 -0
  27. package/dist/src/android/manifest.js +183 -0
  28. package/dist/src/android/manifest.js.map +1 -0
  29. package/dist/src/android/templates.d.ts +11 -0
  30. package/dist/src/android/templates.js +34 -0
  31. package/dist/src/android/templates.js.map +1 -0
  32. package/dist/src/apple/apple-wizard.js +123 -64
  33. package/dist/src/apple/apple-wizard.js.map +1 -1
  34. package/dist/src/apple/cocoapod.js +4 -3
  35. package/dist/src/apple/cocoapod.js.map +1 -1
  36. package/dist/src/apple/code-tools.d.ts +1 -1
  37. package/dist/src/apple/code-tools.js +43 -19
  38. package/dist/src/apple/code-tools.js.map +1 -1
  39. package/dist/src/apple/fastlane.d.ts +1 -1
  40. package/dist/src/apple/fastlane.js +12 -6
  41. package/dist/src/apple/fastlane.js.map +1 -1
  42. package/dist/src/apple/templates.d.ts +2 -2
  43. package/dist/src/apple/templates.js +4 -4
  44. package/dist/src/apple/templates.js.map +1 -1
  45. package/dist/src/apple/xcode-manager.d.ts +19 -3
  46. package/dist/src/apple/xcode-manager.js +126 -24
  47. package/dist/src/apple/xcode-manager.js.map +1 -1
  48. package/dist/src/nextjs/nextjs-wizard.js +49 -11
  49. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  50. package/dist/src/nextjs/templates.d.ts +2 -0
  51. package/dist/src/nextjs/templates.js +6 -2
  52. package/dist/src/nextjs/templates.js.map +1 -1
  53. package/dist/src/remix/remix-wizard.js +10 -20
  54. package/dist/src/remix/remix-wizard.js.map +1 -1
  55. package/dist/src/sourcemaps/sourcemaps-wizard.js +26 -13
  56. package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
  57. package/dist/src/sourcemaps/tools/nextjs.js +1 -1
  58. package/dist/src/sourcemaps/tools/nextjs.js.map +1 -1
  59. package/dist/src/sourcemaps/tools/sentry-cli.js +19 -16
  60. package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
  61. package/dist/src/sourcemaps/tools/vite.d.ts +2 -1
  62. package/dist/src/sourcemaps/tools/vite.js +123 -111
  63. package/dist/src/sourcemaps/tools/vite.js.map +1 -1
  64. package/dist/src/sourcemaps/tools/webpack.d.ts +6 -1
  65. package/dist/src/sourcemaps/tools/webpack.js +290 -25
  66. package/dist/src/sourcemaps/tools/webpack.js.map +1 -1
  67. package/dist/src/sourcemaps/utils/detect-tool.d.ts +1 -1
  68. package/dist/src/sourcemaps/utils/detect-tool.js.map +1 -1
  69. package/dist/src/sveltekit/sdk-setup.js +5 -5
  70. package/dist/src/sveltekit/sdk-setup.js.map +1 -1
  71. package/dist/src/sveltekit/sveltekit-wizard.js +34 -44
  72. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  73. package/dist/src/telemetry.js +1 -0
  74. package/dist/src/telemetry.js.map +1 -1
  75. package/dist/src/utils/ast-utils.d.ts +9 -5
  76. package/dist/src/utils/ast-utils.js +26 -11
  77. package/dist/src/utils/ast-utils.js.map +1 -1
  78. package/dist/src/utils/clack-utils.d.ts +74 -28
  79. package/dist/src/utils/clack-utils.js +427 -264
  80. package/dist/src/utils/clack-utils.js.map +1 -1
  81. package/dist/src/utils/package-manager.d.ts +10 -0
  82. package/dist/{lib/Helper/PackageManager.js → src/utils/package-manager.js} +42 -74
  83. package/dist/src/utils/package-manager.js.map +1 -0
  84. package/dist/src/utils/release-registry.d.ts +1 -0
  85. package/dist/src/utils/release-registry.js +68 -0
  86. package/dist/src/utils/release-registry.js.map +1 -0
  87. package/dist/src/utils/sentrycli-utils.d.ts +4 -0
  88. package/dist/src/utils/sentrycli-utils.js +41 -0
  89. package/dist/src/utils/sentrycli-utils.js.map +1 -0
  90. package/dist/test/android/code-tools.test.d.ts +1 -0
  91. package/dist/test/android/code-tools.test.js +34 -0
  92. package/dist/test/android/code-tools.test.js.map +1 -0
  93. package/dist/test/sourcemaps/tools/vite.test.d.ts +1 -0
  94. package/dist/test/sourcemaps/tools/vite.test.js +132 -0
  95. package/dist/test/sourcemaps/tools/vite.test.js.map +1 -0
  96. package/dist/test/sourcemaps/tools/webpack.test.d.ts +1 -0
  97. package/dist/test/sourcemaps/tools/webpack.test.js +179 -0
  98. package/dist/test/sourcemaps/tools/webpack.test.js.map +1 -0
  99. package/dist/test/utils/ast-utils.test.js +42 -7
  100. package/dist/test/utils/ast-utils.test.js.map +1 -1
  101. package/dist/test/utils/clack-utils.test.d.ts +1 -0
  102. package/dist/test/utils/clack-utils.test.js +200 -0
  103. package/dist/test/utils/clack-utils.test.js.map +1 -0
  104. package/lib/Constants.ts +5 -0
  105. package/lib/Steps/ChooseIntegration.ts +7 -3
  106. package/lib/Steps/Integrations/Android.ts +23 -0
  107. package/lib/Steps/Integrations/ReactNative.ts +9 -3
  108. package/lib/Steps/PromptForParameters.ts +48 -3
  109. package/lib/Steps/SentryProjectSelector.ts +3 -1
  110. package/package.json +4 -3
  111. package/src/android/android-wizard.ts +204 -0
  112. package/src/android/code-tools.ts +170 -0
  113. package/src/android/gradle.ts +250 -0
  114. package/src/android/manifest.ts +180 -0
  115. package/src/android/templates.ts +88 -0
  116. package/src/apple/apple-wizard.ts +113 -35
  117. package/src/apple/cocoapod.ts +6 -3
  118. package/src/apple/code-tools.ts +46 -18
  119. package/src/apple/fastlane.ts +6 -12
  120. package/src/apple/templates.ts +2 -8
  121. package/src/apple/xcode-manager.ts +167 -25
  122. package/src/nextjs/nextjs-wizard.ts +72 -8
  123. package/src/nextjs/templates.ts +16 -2
  124. package/src/remix/remix-wizard.ts +10 -15
  125. package/src/sourcemaps/sourcemaps-wizard.ts +19 -5
  126. package/src/sourcemaps/tools/nextjs.ts +2 -2
  127. package/src/sourcemaps/tools/sentry-cli.ts +8 -7
  128. package/src/sourcemaps/tools/vite.ts +143 -79
  129. package/src/sourcemaps/tools/webpack.ts +369 -30
  130. package/src/sourcemaps/utils/detect-tool.ts +2 -1
  131. package/src/sveltekit/sdk-setup.ts +10 -6
  132. package/src/sveltekit/sveltekit-wizard.ts +5 -14
  133. package/src/telemetry.ts +2 -0
  134. package/src/utils/ast-utils.ts +29 -11
  135. package/src/utils/clack-utils.ts +485 -283
  136. package/src/utils/package-manager.ts +61 -0
  137. package/src/utils/release-registry.ts +19 -0
  138. package/src/utils/sentrycli-utils.ts +22 -0
  139. package/test/android/code-tools.test.ts +49 -0
  140. package/test/sourcemaps/tools/vite.test.ts +149 -0
  141. package/test/sourcemaps/tools/webpack.test.ts +303 -0
  142. package/test/utils/ast-utils.test.ts +28 -9
  143. package/test/utils/clack-utils.test.ts +142 -0
  144. package/dist/lib/Helper/PackageManager.d.ts +0 -22
  145. package/dist/lib/Helper/PackageManager.js.map +0 -1
  146. package/dist/src/utils/vendor/clack-custom-select.d.ts +0 -21
  147. package/dist/src/utils/vendor/clack-custom-select.js +0 -137
  148. package/dist/src/utils/vendor/clack-custom-select.js.map +0 -1
  149. package/lib/Helper/PackageManager.ts +0 -59
  150. package/src/utils/vendor/clack-custom-select.ts +0 -160
@@ -0,0 +1,61 @@
1
+ /* eslint-disable @typescript-eslint/typedef */
2
+ import { exec } from 'child_process';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ import { promisify } from 'util';
6
+
7
+ export interface PackageManager {
8
+ name: string;
9
+ label: string;
10
+ lockFile: string;
11
+ installCommand: string;
12
+ buildCommand: string;
13
+ }
14
+
15
+ const bun: PackageManager = {
16
+ name: 'bun',
17
+ label: 'Bun',
18
+ lockFile: 'bun.lockb',
19
+ installCommand: 'bun add',
20
+ buildCommand: 'bun build',
21
+ };
22
+ const yarn: PackageManager = {
23
+ name: 'yarn',
24
+ label: 'Yarn',
25
+ lockFile: 'yarn.lock',
26
+ installCommand: 'yarn add',
27
+ buildCommand: 'yarn build',
28
+ };
29
+ const pnpm: PackageManager = {
30
+ name: 'pnpm',
31
+ label: 'PNPM',
32
+ lockFile: 'pnpm-lock.yaml',
33
+ installCommand: 'pnpm add',
34
+ buildCommand: 'pnpm build',
35
+ };
36
+ const npm: PackageManager = {
37
+ name: 'npm',
38
+ label: 'NPM',
39
+ lockFile: 'package-lock.json',
40
+ installCommand: 'npm add',
41
+ buildCommand: 'npm run build',
42
+ };
43
+
44
+ export const packageManagers = [bun, yarn, pnpm, npm];
45
+
46
+ export function detectPackageManger(): PackageManager | null {
47
+ for (const packageManager of packageManagers) {
48
+ if (fs.existsSync(path.join(process.cwd(), packageManager.lockFile))) {
49
+ return packageManager;
50
+ }
51
+ }
52
+ // We make the default NPM - it's weird if we don't find any lock file
53
+ return null;
54
+ }
55
+
56
+ export async function installPackageWithPackageManager(
57
+ packageManager: PackageManager,
58
+ packageName: string,
59
+ ): Promise<void> {
60
+ await promisify(exec)(`${packageManager.installCommand} ${packageName}`);
61
+ }
@@ -0,0 +1,19 @@
1
+ import axios from 'axios';
2
+ import { debug } from './debug';
3
+ const registryUrl = 'https://release-registry.services.sentry.io/';
4
+
5
+ export async function fetchSdkVersion(
6
+ sdk: string,
7
+ ): Promise<string | undefined> {
8
+ try {
9
+ const data = (
10
+ await axios.get<Record<string, { version: string }>>(
11
+ `${registryUrl}/sdks`,
12
+ )
13
+ ).data;
14
+ return data[sdk]?.version;
15
+ } catch {
16
+ debug('Failed to fetch latest version from release registry.');
17
+ }
18
+ return undefined;
19
+ }
@@ -0,0 +1,22 @@
1
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+
5
+ export interface SentryCLIConfiguration {
6
+ auth_token: string;
7
+ }
8
+
9
+ export function createSentryCLIRC(
10
+ directory: string,
11
+ params: SentryCLIConfiguration,
12
+ ) {
13
+ const rcPath = path.join(directory, '.sentryclirc');
14
+ fs.writeFileSync(rcPath, '[auth]\ntoken=' + params.auth_token);
15
+
16
+ if (fs.existsSync('.gitignore')) {
17
+ const gitIgnore = fs.readFileSync('.gitignore').toString();
18
+ if (!gitIgnore.includes('.sentryclirc')) {
19
+ fs.appendFileSync('.gitignore', '\n.sentryclirc');
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,49 @@
1
+ //@ts-ignore
2
+ import { getLastImportLineLocation } from '../../src/android/code-tools';
3
+
4
+ describe('code-tools', () => {
5
+ describe('getLastImportLineLocation', () => {
6
+ it('returns proper line index', () => {
7
+ const code = `import a.b.c;\n` + `//<insert-location>\n` + `class X {}`;
8
+ expect(getLastImportLineLocation(code)).toBe(
9
+ code.indexOf('//<insert-location>'),
10
+ );
11
+ });
12
+
13
+ it('returns proper line index when static import is used', () => {
14
+ const code =
15
+ `import static a.b.c;\n` + `//<insert-location>\n` + `class X {}`;
16
+ expect(getLastImportLineLocation(code)).toBe(
17
+ code.indexOf('//<insert-location>'),
18
+ );
19
+ });
20
+
21
+ it('returns proper line index when wildcard import is used', () => {
22
+ const code = `import a.b.*\n` + `//<insert-location>\n` + `class X {}`;
23
+ expect(getLastImportLineLocation(code)).toBe(
24
+ code.indexOf('//<insert-location>'),
25
+ );
26
+ });
27
+
28
+ it('returns proper line index when alias import is used', () => {
29
+ const code =
30
+ `import static a.b.c as d\n` + `//<insert-location>\n` + `class X {}`;
31
+ expect(getLastImportLineLocation(code)).toBe(
32
+ code.indexOf('//<insert-location>'),
33
+ );
34
+ });
35
+
36
+ it('returns proper line index when multiple imports are present', () => {
37
+ const code =
38
+ `import static a.b.c as d\n` +
39
+ `import a.b.*\n` +
40
+ `import static a.b.c;\n` +
41
+ `import a.b.c;\n` +
42
+ `//<insert-location>\n` +
43
+ `class X {}`;
44
+ expect(getLastImportLineLocation(code)).toBe(
45
+ code.indexOf('//<insert-location>'),
46
+ );
47
+ });
48
+ });
49
+ });
@@ -0,0 +1,149 @@
1
+ import * as fs from 'fs';
2
+ import { addVitePluginToConfig } from '../../../src/sourcemaps/tools/vite';
3
+
4
+ function updateFileContent(content: string): void {
5
+ fileContent = content;
6
+ }
7
+
8
+ let fileContent = '';
9
+
10
+ jest.mock('@clack/prompts', () => {
11
+ return {
12
+ log: {
13
+ info: jest.fn(),
14
+ success: jest.fn(),
15
+ },
16
+ };
17
+ });
18
+
19
+ jest
20
+ .spyOn(fs.promises, 'readFile')
21
+ .mockImplementation(() => Promise.resolve(fileContent));
22
+
23
+ const writeFileSpy = jest
24
+ .spyOn(fs.promises, 'writeFile')
25
+ .mockImplementation(() => Promise.resolve(void 0));
26
+
27
+ describe('addVitePluginToConfig', () => {
28
+ afterEach(() => {
29
+ fileContent = '';
30
+ jest.clearAllMocks();
31
+ });
32
+
33
+ it.each([
34
+ [
35
+ 'no build options',
36
+ `
37
+ export default defineConfig({
38
+ plugins: [
39
+ vue(),
40
+ ],
41
+ })
42
+ `,
43
+ `import { sentryVitePlugin } from "@sentry/vite-plugin";
44
+ export default defineConfig({
45
+ plugins: [vue(), sentryVitePlugin({
46
+ org: "my-org",
47
+ project: "my-project"
48
+ })],
49
+
50
+ build: {
51
+ sourcemap: true
52
+ }
53
+ })`,
54
+ ],
55
+ [
56
+ 'no build.sourcemap options',
57
+ `
58
+ export default defineConfig({
59
+ plugins: [
60
+ vue(),
61
+ ],
62
+ build: {
63
+ test: 1,
64
+ }
65
+ })
66
+ `,
67
+ `import { sentryVitePlugin } from "@sentry/vite-plugin";
68
+ export default defineConfig({
69
+ plugins: [vue(), sentryVitePlugin({
70
+ org: "my-org",
71
+ project: "my-project"
72
+ })],
73
+ build: {
74
+ test: 1,
75
+ sourcemap: true
76
+ }
77
+ })`,
78
+ ],
79
+ [
80
+ 'keep sourcemap: "hidden"',
81
+ `
82
+ export default {
83
+ plugins: [
84
+ vue(),
85
+ ],
86
+ build: {
87
+ sourcemap: "hidden",
88
+ }
89
+ }
90
+ `,
91
+ `import { sentryVitePlugin } from "@sentry/vite-plugin";
92
+ export default {
93
+ plugins: [vue(), sentryVitePlugin({
94
+ org: "my-org",
95
+ project: "my-project"
96
+ })],
97
+ build: {
98
+ sourcemap: "hidden",
99
+ }
100
+ }`,
101
+ ],
102
+ [
103
+ 'rewrite sourcemap: false to true',
104
+ `
105
+ const cfg = {
106
+ plugins: [
107
+ vue(),
108
+ ],
109
+ build: {
110
+ sourcemap: false,
111
+ }
112
+ }
113
+
114
+ export default cfg;
115
+ `,
116
+ `import { sentryVitePlugin } from "@sentry/vite-plugin";
117
+ const cfg = {
118
+ plugins: [vue(), sentryVitePlugin({
119
+ org: "my-org",
120
+ project: "my-project"
121
+ })],
122
+
123
+ build: {
124
+ sourcemap: true,
125
+ }
126
+ }
127
+
128
+ export default cfg;`,
129
+ ],
130
+ ])(
131
+ 'adds the plugin and enables source maps generation (%s)',
132
+ async (_, originalCode, expectedCode) => {
133
+ updateFileContent(originalCode);
134
+
135
+ const addedCode = await addVitePluginToConfig('', {
136
+ authToken: '',
137
+ orgSlug: 'my-org',
138
+ projectSlug: 'my-project',
139
+ selfHosted: false,
140
+ url: 'https://sentry.io/',
141
+ });
142
+
143
+ expect(writeFileSpy).toHaveBeenCalledTimes(1);
144
+ const [[, fileContent]] = writeFileSpy.mock.calls;
145
+ expect(fileContent).toBe(expectedCode);
146
+ expect(addedCode).toBe(true);
147
+ },
148
+ );
149
+ });
@@ -0,0 +1,303 @@
1
+ import * as fs from 'fs';
2
+
3
+ import { modifyWebpackConfig } from '../../../src/sourcemaps/tools/webpack';
4
+
5
+ function updateFileContent(content: string): void {
6
+ fileContent = content;
7
+ }
8
+
9
+ let fileContent = '';
10
+
11
+ jest.mock('@clack/prompts', () => {
12
+ return {
13
+ log: {
14
+ info: jest.fn(),
15
+ success: jest.fn(),
16
+ },
17
+ select: jest.fn().mockImplementation(() => Promise.resolve(true)),
18
+ isCancel: jest.fn().mockReturnValue(false),
19
+ };
20
+ });
21
+
22
+ jest
23
+ .spyOn(fs.promises, 'readFile')
24
+ .mockImplementation(() => Promise.resolve(fileContent));
25
+
26
+ const writeFileSpy = jest
27
+ .spyOn(fs.promises, 'writeFile')
28
+ .mockImplementation(() => Promise.resolve(void 0));
29
+
30
+ const noSourcemapNoPluginsPojo = `module.exports = {
31
+ entry: "./src/index.js",
32
+ output: {
33
+ filename: "main.js",
34
+ path: path.resolve(__dirname, "build"),
35
+ },
36
+ };`;
37
+
38
+ const noSourcemapNoPluginsPojoResult = `const {
39
+ sentryWebpackPlugin
40
+ } = require("@sentry/webpack-plugin");
41
+
42
+ module.exports = {
43
+ entry: "./src/index.js",
44
+
45
+ output: {
46
+ filename: "main.js",
47
+ path: path.resolve(__dirname, "build"),
48
+ },
49
+
50
+ devtool: "source-map",
51
+
52
+ plugins: [sentryWebpackPlugin({
53
+ authToken: process.env.SENTRY_AUTH_TOKEN,
54
+ org: "my-org",
55
+ project: "my-project"
56
+ })]
57
+ };`;
58
+
59
+ const noSourcemapsNoPluginsId = `const config = {
60
+ entry: "./src/index.js",
61
+
62
+ output: {
63
+ filename: "main.js",
64
+ path: path.resolve(__dirname, "build"),
65
+ },
66
+ };
67
+
68
+ module.exports = config;`;
69
+
70
+ const noSourcemapsNoPluginsIdResult = `const {
71
+ sentryWebpackPlugin
72
+ } = require("@sentry/webpack-plugin");
73
+
74
+ const config = {
75
+ entry: "./src/index.js",
76
+
77
+ output: {
78
+ filename: "main.js",
79
+ path: path.resolve(__dirname, "build"),
80
+ },
81
+
82
+ devtool: "source-map",
83
+
84
+ plugins: [sentryWebpackPlugin({
85
+ authToken: process.env.SENTRY_AUTH_TOKEN,
86
+ org: "my-org",
87
+ project: "my-project"
88
+ })]
89
+ };
90
+
91
+ module.exports = config;`;
92
+
93
+ const hiddenSourcemapNoPluginsId = `const config = {
94
+ entry: "./src/index.js",
95
+
96
+ output: {
97
+ filename: "main.js",
98
+ path: path.resolve(__dirname, "build"),
99
+ },
100
+
101
+ devtool: "hidden-cheap-source-map",
102
+ };
103
+
104
+ module.exports = config;
105
+ `;
106
+ const hiddenSourcemapNoPluginsIdResult = `const {
107
+ sentryWebpackPlugin
108
+ } = require("@sentry/webpack-plugin");
109
+
110
+ const config = {
111
+ entry: "./src/index.js",
112
+
113
+ output: {
114
+ filename: "main.js",
115
+ path: path.resolve(__dirname, "build"),
116
+ },
117
+
118
+ devtool: "hidden-source-map",
119
+
120
+ plugins: [sentryWebpackPlugin({
121
+ authToken: process.env.SENTRY_AUTH_TOKEN,
122
+ org: "my-org",
123
+ project: "my-project"
124
+ })]
125
+ };
126
+
127
+ module.exports = config;`;
128
+
129
+ const arbitrarySourcemapNoPluginsId = `
130
+ const config = {
131
+ entry: "./src/index.js",
132
+
133
+ output: {
134
+ filename: "main.js",
135
+ path: path.resolve(__dirname, "build"),
136
+ },
137
+
138
+ devtool: getSourcemapSetting(),
139
+ };
140
+
141
+ module.exports = config;
142
+ `;
143
+ const arbitrarySourcemapNoPluginsIdResult = `const {
144
+ sentryWebpackPlugin
145
+ } = require("@sentry/webpack-plugin");
146
+
147
+ const config = {
148
+ entry: "./src/index.js",
149
+
150
+ output: {
151
+ filename: "main.js",
152
+ path: path.resolve(__dirname, "build"),
153
+ },
154
+
155
+ devtool: "source-map",
156
+
157
+ plugins: [sentryWebpackPlugin({
158
+ authToken: process.env.SENTRY_AUTH_TOKEN,
159
+ org: "my-org",
160
+ project: "my-project"
161
+ })]
162
+ };
163
+
164
+ module.exports = config;`;
165
+
166
+ const noSourcemapUndefinedPluginsPojo = `module.exports = {
167
+ entry: "./src/index.js",
168
+ plugins: undefined,
169
+ output: {
170
+ filename: "main.js",
171
+ path: path.resolve(__dirname, "build"),
172
+ },
173
+ };`;
174
+
175
+ const noSourcemapUndefinedPluginsPojoResult = `const {
176
+ sentryWebpackPlugin
177
+ } = require("@sentry/webpack-plugin");
178
+
179
+ module.exports = {
180
+ entry: "./src/index.js",
181
+
182
+ plugins: [sentryWebpackPlugin({
183
+ authToken: process.env.SENTRY_AUTH_TOKEN,
184
+ org: "my-org",
185
+ project: "my-project"
186
+ })],
187
+
188
+ output: {
189
+ filename: "main.js",
190
+ path: path.resolve(__dirname, "build"),
191
+ },
192
+
193
+ devtool: "source-map"
194
+ };`;
195
+
196
+ const noSourcemapPluginsPojo = `module.exports = {
197
+ entry: "./src/index.js",
198
+ plugins: [
199
+ new HtmlWebpackPlugin(),
200
+ new MiniCssExtractPlugin(),
201
+ ],
202
+ output: {
203
+ filename: "main.js",
204
+ path: path.resolve(__dirname, "build"),
205
+ },
206
+ };`;
207
+
208
+ const noSourcemapPluginsPojoResult = `const {
209
+ sentryWebpackPlugin
210
+ } = require("@sentry/webpack-plugin");
211
+
212
+ module.exports = {
213
+ entry: "./src/index.js",
214
+
215
+ plugins: [new HtmlWebpackPlugin(), new MiniCssExtractPlugin(), sentryWebpackPlugin({
216
+ authToken: process.env.SENTRY_AUTH_TOKEN,
217
+ org: "my-org",
218
+ project: "my-project"
219
+ })],
220
+
221
+ output: {
222
+ filename: "main.js",
223
+ path: path.resolve(__dirname, "build"),
224
+ },
225
+
226
+ devtool: "source-map"
227
+ };`;
228
+
229
+ describe('modifyWebpackConfig', () => {
230
+ afterEach(() => {
231
+ fileContent = '';
232
+ jest.clearAllMocks();
233
+ });
234
+
235
+ it.each([
236
+ [
237
+ 'no sourcemap option, no plugins, object',
238
+ noSourcemapNoPluginsPojo,
239
+ noSourcemapNoPluginsPojoResult,
240
+ ],
241
+ [
242
+ 'no sourcemap option, no plugins, identifier',
243
+ noSourcemapsNoPluginsId,
244
+ noSourcemapsNoPluginsIdResult,
245
+ ],
246
+ [
247
+ 'hidden sourcemap option, no plugins, identifier',
248
+ hiddenSourcemapNoPluginsId,
249
+ hiddenSourcemapNoPluginsIdResult,
250
+ ],
251
+ [
252
+ 'arbitrary sourcemap option, no plugins, identifier',
253
+ arbitrarySourcemapNoPluginsId,
254
+ arbitrarySourcemapNoPluginsIdResult,
255
+ ],
256
+ [
257
+ 'no sourcemap option, plugins, object',
258
+ noSourcemapUndefinedPluginsPojo,
259
+ noSourcemapUndefinedPluginsPojoResult,
260
+ ],
261
+ [
262
+ 'no sourcemap option, plugins, object',
263
+ noSourcemapPluginsPojo,
264
+ noSourcemapPluginsPojoResult,
265
+ ],
266
+ ])(
267
+ 'adds plugin and source maps emission to the webpack config (%s)',
268
+ async (_, originalCode, expectedCode) => {
269
+ updateFileContent(originalCode);
270
+
271
+ // updateFileContent(originalCode);
272
+ const addedCode = await modifyWebpackConfig('', {
273
+ authToken: '',
274
+ orgSlug: 'my-org',
275
+ projectSlug: 'my-project',
276
+ selfHosted: false,
277
+ url: 'https://sentry.io/',
278
+ });
279
+
280
+ expect(writeFileSpy).toHaveBeenCalledTimes(1);
281
+ const [[, fileContent]] = writeFileSpy.mock.calls;
282
+ expect(fileContent).toBe(expectedCode);
283
+ expect(addedCode).toBe(true);
284
+ },
285
+ );
286
+
287
+ it('adds the url parameter to the webpack plugin options if self-hosted', async () => {
288
+ updateFileContent(noSourcemapNoPluginsPojo);
289
+
290
+ const addedCode = await modifyWebpackConfig('', {
291
+ authToken: '',
292
+ orgSlug: 'my-org',
293
+ projectSlug: 'my-project',
294
+ selfHosted: true,
295
+ url: 'https://santry.io/',
296
+ });
297
+
298
+ expect(writeFileSpy).toHaveBeenCalledTimes(1);
299
+ const [[, fileContent]] = writeFileSpy.mock.calls;
300
+ expect(fileContent).toContain('url: "https://santry.io/"');
301
+ expect(addedCode).toBe(true);
302
+ });
303
+ });
@@ -1,22 +1,37 @@
1
- //@ts-ignore
2
- import { parseModule } from 'magicast';
3
1
  import { hasSentryContent } from '../../src/utils/ast-utils';
4
2
 
3
+ import * as recast from 'recast';
4
+
5
5
  describe('AST utils', () => {
6
6
  describe('hasSentryContent', () => {
7
- it("returns true if a '@sentry/' import was found in the parsed module", () => {
8
- const code = `
7
+ it.each([
8
+ `
9
+ const { sentryVitePlugin } = require("@sentry/vite-plugin");
10
+ const somethingelse = require('gs');
11
+ `,
12
+ `
9
13
  import { sentryVitePlugin } from "@sentry/vite-plugin";
10
14
  import * as somethingelse from 'gs';
11
15
 
12
16
  export default {
13
17
  plugins: [sentryVitePlugin()]
14
18
  }
15
- `;
19
+ `,
20
+ ])(
21
+ "returns true if a require('@sentry/') call was found in the parsed module",
22
+ (code) => {
23
+ // recast.parse returns a Program node (or fails) but it's badly typed as any
24
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
25
+ const program = recast.parse(code)
26
+ .program as recast.types.namedTypes.Program;
27
+ expect(hasSentryContent(program)).toBe(true);
28
+ },
29
+ );
16
30
 
17
- expect(hasSentryContent(parseModule(code))).toBe(true);
18
- });
19
31
  it.each([
32
+ `const whatever = require('something')`,
33
+ `// const {sentryWebpackPlugin} = require('@sentry/webpack-plugin')`,
34
+ `const {sAntryWebpackPlugin} = require('webpack-plugin-@sentry')`,
20
35
  `
21
36
  import * as somethingelse from 'gs';
22
37
  export default {
@@ -35,9 +50,13 @@ describe('AST utils', () => {
35
50
  }
36
51
  `,
37
52
  ])(
38
- "reutrns false for modules without a valid '@sentry/' import",
53
+ "returns false if the file doesn't contain any require('@sentry/') calls",
39
54
  (code) => {
40
- expect(hasSentryContent(parseModule(code))).toBe(false);
55
+ // recast.parse returns a Program node (or fails) but it's badly typed as any
56
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
57
+ const program = recast.parse(code)
58
+ .program as recast.types.namedTypes.Program;
59
+ expect(hasSentryContent(program)).toBe(false);
41
60
  },
42
61
  );
43
62
  });