@sentry/wizard 3.11.0 → 3.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.
Files changed (91) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/lib/Steps/ChooseIntegration.js +1 -0
  3. package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
  4. package/dist/package.json +1 -1
  5. package/dist/src/android/android-wizard.js +14 -4
  6. package/dist/src/android/android-wizard.js.map +1 -1
  7. package/dist/src/android/code-tools.d.ts +8 -0
  8. package/dist/src/android/code-tools.js +20 -8
  9. package/dist/src/android/code-tools.js.map +1 -1
  10. package/dist/src/android/gradle.js +6 -1
  11. package/dist/src/android/gradle.js.map +1 -1
  12. package/dist/src/nextjs/nextjs-wizard.js +5 -2
  13. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  14. package/dist/src/nextjs/templates.d.ts +1 -1
  15. package/dist/src/nextjs/templates.js +2 -2
  16. package/dist/src/nextjs/templates.js.map +1 -1
  17. package/dist/src/remix/remix-wizard.js +8 -4
  18. package/dist/src/remix/remix-wizard.js.map +1 -1
  19. package/dist/src/remix/sdk-setup.d.ts +5 -1
  20. package/dist/src/remix/sdk-setup.js +3 -2
  21. package/dist/src/remix/sdk-setup.js.map +1 -1
  22. package/dist/src/sourcemaps/tools/sentry-cli.d.ts +9 -0
  23. package/dist/src/sourcemaps/tools/sentry-cli.js +26 -22
  24. package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
  25. package/dist/src/sourcemaps/tools/tsc.d.ts +6 -0
  26. package/dist/src/sourcemaps/tools/tsc.js +98 -17
  27. package/dist/src/sourcemaps/tools/tsc.js.map +1 -1
  28. package/dist/src/sourcemaps/tools/vite.js +39 -124
  29. package/dist/src/sourcemaps/tools/vite.js.map +1 -1
  30. package/dist/src/sourcemaps/tools/webpack.d.ts +6 -1
  31. package/dist/src/sourcemaps/tools/webpack.js +280 -25
  32. package/dist/src/sourcemaps/tools/webpack.js.map +1 -1
  33. package/dist/src/sveltekit/sdk-setup.js +123 -49
  34. package/dist/src/sveltekit/sdk-setup.js.map +1 -1
  35. package/dist/src/sveltekit/sveltekit-wizard.d.ts +1 -0
  36. package/dist/src/sveltekit/sveltekit-wizard.js +119 -44
  37. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  38. package/dist/src/sveltekit/utils.d.ts +2 -0
  39. package/dist/src/sveltekit/utils.js +48 -0
  40. package/dist/src/sveltekit/utils.js.map +1 -0
  41. package/dist/src/utils/ast-utils.d.ts +77 -3
  42. package/dist/src/utils/ast-utils.js +172 -6
  43. package/dist/src/utils/ast-utils.js.map +1 -1
  44. package/dist/src/utils/clack-utils.d.ts +85 -1
  45. package/dist/src/utils/clack-utils.js +214 -51
  46. package/dist/src/utils/clack-utils.js.map +1 -1
  47. package/dist/src/utils/package-manager.d.ts +5 -0
  48. package/dist/src/utils/package-manager.js +11 -7
  49. package/dist/src/utils/package-manager.js.map +1 -1
  50. package/dist/test/android/code-tools.test.d.ts +1 -0
  51. package/dist/test/android/code-tools.test.js +34 -0
  52. package/dist/test/android/code-tools.test.js.map +1 -0
  53. package/dist/test/sourcemaps/tools/sentry-cli.test.d.ts +1 -0
  54. package/dist/test/sourcemaps/tools/sentry-cli.test.js +112 -0
  55. package/dist/test/sourcemaps/tools/sentry-cli.test.js.map +1 -0
  56. package/dist/test/sourcemaps/tools/tsc.test.d.ts +1 -0
  57. package/dist/test/sourcemaps/tools/tsc.test.js +121 -0
  58. package/dist/test/sourcemaps/tools/tsc.test.js.map +1 -0
  59. package/dist/test/sourcemaps/tools/webpack.test.d.ts +1 -0
  60. package/dist/test/sourcemaps/tools/webpack.test.js +179 -0
  61. package/dist/test/sourcemaps/tools/webpack.test.js.map +1 -0
  62. package/dist/test/utils/ast-utils.test.js +181 -15
  63. package/dist/test/utils/ast-utils.test.js.map +1 -1
  64. package/dist/test/utils/clack-utils.test.d.ts +1 -0
  65. package/dist/test/utils/clack-utils.test.js +200 -0
  66. package/dist/test/utils/clack-utils.test.js.map +1 -0
  67. package/lib/Steps/ChooseIntegration.ts +1 -0
  68. package/package.json +1 -1
  69. package/src/android/android-wizard.ts +16 -5
  70. package/src/android/code-tools.ts +21 -7
  71. package/src/android/gradle.ts +6 -1
  72. package/src/nextjs/nextjs-wizard.ts +15 -3
  73. package/src/nextjs/templates.ts +3 -2
  74. package/src/remix/remix-wizard.ts +8 -11
  75. package/src/remix/sdk-setup.ts +8 -2
  76. package/src/sourcemaps/tools/sentry-cli.ts +16 -9
  77. package/src/sourcemaps/tools/tsc.ts +133 -28
  78. package/src/sourcemaps/tools/vite.ts +37 -127
  79. package/src/sourcemaps/tools/webpack.ts +343 -27
  80. package/src/sveltekit/sdk-setup.ts +115 -39
  81. package/src/sveltekit/sveltekit-wizard.ts +93 -25
  82. package/src/sveltekit/utils.ts +50 -0
  83. package/src/utils/ast-utils.ts +203 -7
  84. package/src/utils/clack-utils.ts +211 -44
  85. package/src/utils/package-manager.ts +12 -6
  86. package/test/android/code-tools.test.ts +49 -0
  87. package/test/sourcemaps/tools/sentry-cli.test.ts +51 -0
  88. package/test/sourcemaps/tools/tsc.test.ts +181 -0
  89. package/test/sourcemaps/tools/webpack.test.ts +303 -0
  90. package/test/utils/ast-utils.test.ts +240 -20
  91. package/test/utils/clack-utils.test.ts +142 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ast-utils.js","sourceRoot":"","sources":["../../../src/utils/ast-utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAyB;AAIzB;;;GAGG;AACH,SAAgB,QAAQ,CACtB,QAAgB,EAChB,SAA4C;IAA5C,0BAAA,EAAA,aAAuB,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC;IAE5C,OAAO,SAAS;SACb,GAAG,CAAC,UAAC,IAAI,IAAK,OAAA,UAAG,QAAQ,SAAG,IAAI,CAAE,EAApB,CAAoB,CAAC;SACnC,IAAI,CAAC,UAAC,IAAI,IAAK,OAAA,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAnB,CAAmB,CAAC,CAAC;AACzC,CAAC;AAPD,4BAOC;AAED,kEAAkE;AAClE,SAAgB,gBAAgB,CAAC,GAA4B;IAC3D,IAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,CAAC,IAAI,EAAN,CAAM,CAAC,CAAC;IACtD,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAxB,CAAwB,CAAC,CAAC;AACzD,CAAC;AAHD,4CAGC","sourcesContent":["import * as fs from 'fs';\n// @ts-ignore - magicast is ESM and TS complains about that. It works though\nimport { ProxifiedModule } from 'magicast';\n\n/**\n * Checks if a file where we don't know its concrete file type yet exists\n * and returns the full path to the file with the correct file type.\n */\nexport function findFile(\n filePath: string,\n fileTypes: string[] = ['.js', '.ts', '.mjs'],\n): string | undefined {\n return fileTypes\n .map((type) => `${filePath}${type}`)\n .find((file) => fs.existsSync(file));\n}\n\n/** Checks if a Sentry package is already mentioned in the file */\nexport function hasSentryContent(mod: ProxifiedModule<object>): boolean {\n const imports = mod.imports.$items.map((i) => i.from);\n return !!imports.find((i) => i.startsWith('@sentry/'));\n}\n"]}
1
+ {"version":3,"file":"ast-utils.js","sourceRoot":"","sources":["../../../src/utils/ast-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\n\nimport * as recast from 'recast';\nimport x = recast.types;\nimport t = x.namedTypes;\n\nconst b = recast.types.builders;\n\n/**\n * Checks if a file where we don't know its concrete file type yet exists\n * and returns the full path to the file with the correct file type.\n */\nexport function findFile(\n filePath: string,\n fileTypes: string[] = ['.js', '.ts', '.mjs', '.cjs'],\n): string | undefined {\n return fileTypes\n .map((type) => `${filePath}${type}`)\n .find((file) => fs.existsSync(file));\n}\n\n/**\n * checks for require('@sentry/*') syntax\n */\nexport function hasSentryContent(program: t.Program): boolean {\n let foundSentry: boolean | undefined = false;\n recast.visit(program, {\n visitStringLiteral(path) {\n foundSentry = foundSentry || path.node.value.startsWith('@sentry/');\n this.traverse(path);\n },\n visitLiteral(path) {\n foundSentry =\n foundSentry || path.node.value?.toString().startsWith('@sentry/');\n this.traverse(path);\n },\n });\n\n return !!foundSentry;\n}\n\n/**\n * Searches for a property of an ObjectExpression by name\n *\n * @param object the ObjectExpression to search in\n * @param name the name of the property to search for\n *\n * @returns the property if it exists\n */\nexport function getObjectProperty(\n object: t.ObjectExpression,\n name: string,\n): t.Property | undefined {\n return object.properties.find((p): p is t.Property => {\n const isObjectProp = p.type === 'Property' || p.type === 'ObjectProperty';\n\n if (!isObjectProp) {\n return false;\n }\n\n const hasMatchingLiteralKey =\n isObjectProp &&\n (p.key.type === 'Literal' || p.key.type === 'StringLiteral') &&\n p.key.value === name;\n\n if (hasMatchingLiteralKey) {\n return true;\n }\n\n // has matching identifier key\n return isObjectProp && p.key.type === 'Identifier' && p.key.name === name;\n });\n}\n\n/**\n * Attempts to find a property of an ObjectExpression by name. If it doesn't exist,\n * the property will be added to the ObjectExpression with the provided default value.\n *\n * @param object the parent object expression to search in\n * @param name the name of the property to search for\n * @param defaultValue the default value to set if the property doesn't exist\n *\n * @returns the\n */\nexport function getOrSetObjectProperty(\n object: t.ObjectExpression,\n name: string,\n defaultValue:\n | t.Literal\n | t.BooleanLiteral\n | t.StringLiteral\n | t.ObjectExpression,\n): t.Property {\n const existingProperty = getObjectProperty(object, name);\n\n if (existingProperty) {\n return existingProperty;\n }\n\n const newProperty = b.property.from({\n kind: 'init',\n key: b.stringLiteral(name),\n value: defaultValue,\n });\n\n object.properties.push(newProperty);\n\n return newProperty;\n}\n\n/**\n * Sets a property of an ObjectExpression if it exists, otherwise adds it\n * to the ObjectExpression. Optionally, a comment can be added to the\n * property.\n *\n * @param object the ObjectExpression to set the property on\n * @param name the name of the property to set\n * @param value the value of the property to set\n * @param comment (optional) a comment to add to the property\n */\nexport function setOrUpdateObjectProperty(\n object: t.ObjectExpression,\n name: string,\n value: t.Literal | t.BooleanLiteral | t.StringLiteral | t.ObjectExpression,\n comment?: string,\n) {\n const newComments =\n comment &&\n comment.split('\\n').map((c) => b.commentLine(` ${c}`, true, false));\n\n const existingProperty = getObjectProperty(object, name);\n\n if (existingProperty) {\n existingProperty.value = value;\n if (newComments) {\n existingProperty.comments = [\n ...(existingProperty?.comments || []),\n ...newComments,\n ];\n }\n } else {\n object.properties.push(\n b.objectProperty.from({\n key: b.stringLiteral(name),\n value,\n ...(newComments && {\n comments: newComments,\n }),\n }),\n );\n }\n}\n\ntype JsonCParseResult =\n | {\n jsonObject: t.ObjectExpression;\n ast: t.Program;\n }\n | {\n jsonObject: undefined;\n ast: undefined;\n };\n\n/**\n * Parses a JSON string with (potential) comments (JSON-C) and returns the JS AST\n * that can be walked and modified with recast like a normal JS AST.\n *\n * This is done by wrapping the JSON-C string in parentheses, thereby making it\n * a JS `Program` with an `ExpressionStatement` as its body. The expression is then\n * extracted from the AST and returned alongside the AST.\n *\n * To preserve as much original formatting as possible, the returned `ast`\n * property should be passed to {@link `printJsonC`} to get the JSON-C string back.\n *\n * If the input is not valid JSON-C, the result will be undefined.\n *\n * @see {@link JsonCParseResult}\n *\n * @param jsonString a JSON-C string\n *\n * @returns a {@link JsonCParseResult}, containing either the JSON-C object and the AST or undefined in both cases\n */\nexport function parseJsonC(jsonString: string): JsonCParseResult {\n try {\n const jsTsConfig = `(${jsonString})`;\n // no idea why recast returns any here, this is dumb :/\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const ast = recast.parse(jsTsConfig.toString()).program as t.Program;\n\n const jsonObject =\n (ast.body[0].type === 'ExpressionStatement' &&\n ast.body[0].expression.type === 'ObjectExpression' &&\n ast.body[0].expression) ||\n undefined;\n\n if (jsonObject) {\n return { jsonObject, ast };\n }\n } catch {\n /* empty */\n }\n return { jsonObject: undefined, ast: undefined };\n}\n\n/**\n * Takes the AST of a parsed JSON-C \"program\" and returns the JSON-C string without\n * any of the temporary JS wrapper code that was previously applied.\n *\n * Only use this in conjunction with {@link `parseJsonC`}\n *\n * @param ast the `ast` returned from {@link `parseJsonC`}\n *\n * @returns the JSON-C string\n */\nexport function printJsonC(ast: t.Program): string {\n const js = recast.print(ast).code;\n return js.substring(1, js.length - 1);\n}\n"]}
@@ -31,7 +31,7 @@ export declare function installPackage({ packageName, alreadyInstalled, askBefor
31
31
  alreadyInstalled: boolean;
32
32
  askBeforeUpdating?: boolean;
33
33
  }): Promise<void>;
34
- export declare function addSentryCliConfig(authToken: string, setupConfig?: CliSetupConfig, orgSlug?: string, projectSlug?: string): Promise<void>;
34
+ export declare function addSentryCliConfig(authToken: string, setupConfig?: CliSetupConfig): Promise<void>;
35
35
  export declare function addDotEnvSentryBuildPluginFile(authToken: string): Promise<void>;
36
36
  export declare function ensurePackageIsInstalled(packageJson: PackageDotJson, packageId: string, packageName: string): Promise<void>;
37
37
  export declare function getPackageDotJson(): Promise<PackageDotJson>;
@@ -53,3 +53,87 @@ export declare function getOrAskForProjectData(options: WizardOptions, platform?
53
53
  selectedProject: SentryProjectData;
54
54
  authToken: string;
55
55
  }>;
56
+ /**
57
+ * Asks users if they have a config file for @param tool (e.g. Vite).
58
+ * If yes, asks users to specify the path to their config file.
59
+ *
60
+ * Use this helper function as a fallback mechanism if the lookup for
61
+ * a config file with its most usual location/name fails.
62
+ *
63
+ * @param toolName Name of the tool for which we're looking for the config file
64
+ * @param configFileName Name of the most common config file name (e.g. vite.config.js)
65
+ *
66
+ * @returns a user path to the config file or undefined if the user doesn't have a config file
67
+ */
68
+ export declare function askForToolConfigPath(toolName: string, configFileName: string): Promise<string | undefined>;
69
+ /**
70
+ * Prints copy/paste-able instructions to the console.
71
+ * Afterwards asks the user if they added the code snippet to their file.
72
+ *
73
+ * While there's no point in providing a "no" answer here, it gives users time to fulfill the
74
+ * task before the wizard continues with additional steps.
75
+ *
76
+ * Use this function if you want to show users instructions on how to add/modify
77
+ * code in their file. This is helpful if automatic insertion failed or is not possible/feasible.
78
+ *
79
+ * @param filename the name of the file to which the code snippet should be applied.
80
+ * If a path is provided, only the filename will be used.
81
+ *
82
+ * @param codeSnippet the snippet to be printed. Use {@link makeCodeSnippet} to create the
83
+ * diff-like format for visually highlighting unchanged or modified lines of code.
84
+ *
85
+ * @param hint (optional) a hint to be printed after the main instruction to add
86
+ * the code from @param codeSnippet to their @param filename.
87
+ *
88
+ * More guidelines on copy/paste instructions:
89
+ * @see {@link https://develop.sentry.dev/sdk/setup-wizards/#copy--paste-snippets}
90
+ *
91
+ * TODO: refactor copy paste instructions across different wizards to use this function.
92
+ * this might require adding a custom message parameter to the function
93
+ */
94
+ export declare function showCopyPasteInstructions(filename: string, codeSnippet: string, hint?: string): Promise<void>;
95
+ /**
96
+ * Callback that exposes formatting helpers for a code snippet.
97
+ * @param unchanged - Formats text as old code.
98
+ * @param plus - Formats text as new code.
99
+ * @param minus - Formats text as removed code.
100
+ */
101
+ type CodeSnippetFormatter = (unchanged: (txt: string) => string, plus: (txt: string) => string, minus: (txt: string) => string) => string;
102
+ /**
103
+ * Crafts a code snippet that can be used to e.g.
104
+ * - print copy/paste instructions to the console
105
+ * - create a new config file.
106
+ *
107
+ * @param colors set this to true if you want the final snippet to be colored.
108
+ * This is useful for printing the snippet to the console as part of copy/paste instructions.
109
+ *
110
+ * @param callback the callback that returns the formatted code snippet.
111
+ * It exposes takes the helper functions for marking code as unchaned, new or removed.
112
+ * These functions no-op if no special formatting should be applied
113
+ * and otherwise apply the appropriate formatting/coloring.
114
+ * (@see {@link CodeSnippetFormatter})
115
+ *
116
+ * @see {@link showCopyPasteInstructions} for the helper with which to display the snippet in the console.
117
+ *
118
+ * @returns a string containing the final, formatted code snippet.
119
+ */
120
+ export declare function makeCodeSnippet(colors: boolean, callback: CodeSnippetFormatter): string;
121
+ /**
122
+ * Creates a new config file with the given @param filepath and @param codeSnippet.
123
+ *
124
+ * Use this function to create a new config file for users. This is useful
125
+ * when users answered that they don't yet have a config file for a tool.
126
+ *
127
+ * (This doesn't mean that they don't yet have some other way of configuring
128
+ * their tool but we can leave it up to them to figure out how to merge configs
129
+ * here.)
130
+ *
131
+ * @param filepath absolute path to the new config file
132
+ * @param codeSnippet the snippet to be inserted into the file
133
+ * @param moreInformation (optional) the message to be printed after the file was created
134
+ * For example, this can be a link to more information about configuring the tool.
135
+ *
136
+ * @returns true on sucess, false otherwise
137
+ */
138
+ export declare function createNewConfigFile(filepath: string, codeSnippet: string, moreInformation?: string): Promise<boolean>;
139
+ export {};
@@ -58,11 +58,20 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
58
58
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
59
59
  }
60
60
  };
61
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
62
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
63
+ if (ar || !(i in from)) {
64
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
65
+ ar[i] = from[i];
66
+ }
67
+ }
68
+ return to.concat(ar || Array.prototype.slice.call(from));
69
+ };
61
70
  var __importDefault = (this && this.__importDefault) || function (mod) {
62
71
  return (mod && mod.__esModule) ? mod : { "default": mod };
63
72
  };
64
73
  Object.defineProperty(exports, "__esModule", { value: true });
65
- exports.getOrAskForProjectData = exports.isUsingTypeScript = exports.getPackageDotJson = exports.ensurePackageIsInstalled = exports.addDotEnvSentryBuildPluginFile = exports.addSentryCliConfig = exports.installPackage = exports.askForItemSelection = exports.askToInstallSentryCLI = exports.confirmContinueEvenThoughNoGitRepo = exports.printWelcome = exports.abortIfCancelled = exports.abort = exports.sourceMapsCliSetupConfig = exports.SENTRY_PROPERTIES_FILE = exports.SENTRY_CLI_RC_FILE = exports.SENTRY_DOT_ENV_FILE = void 0;
74
+ exports.createNewConfigFile = exports.makeCodeSnippet = exports.showCopyPasteInstructions = exports.askForToolConfigPath = exports.getOrAskForProjectData = exports.isUsingTypeScript = exports.getPackageDotJson = exports.ensurePackageIsInstalled = exports.addDotEnvSentryBuildPluginFile = exports.addSentryCliConfig = exports.installPackage = exports.askForItemSelection = exports.askToInstallSentryCLI = exports.confirmContinueEvenThoughNoGitRepo = exports.printWelcome = exports.abortIfCancelled = exports.abort = exports.sourceMapsCliSetupConfig = exports.SENTRY_PROPERTIES_FILE = exports.SENTRY_CLI_RC_FILE = exports.SENTRY_DOT_ENV_FILE = void 0;
66
75
  // @ts-ignore - clack is ESM and TS complains about that. It works though
67
76
  var clack = __importStar(require("@clack/prompts"));
68
77
  var axios_1 = __importDefault(require("axios"));
@@ -76,6 +85,7 @@ var Sentry = __importStar(require("@sentry/node"));
76
85
  var package_json_1 = require("./package-json");
77
86
  var telemetry_1 = require("../telemetry");
78
87
  var package_manager_1 = require("./package-manager");
88
+ var debug_1 = require("./debug");
79
89
  var opn = require('opn');
80
90
  exports.SENTRY_DOT_ENV_FILE = '.env.sentry-build-plugin';
81
91
  exports.SENTRY_CLI_RC_FILE = '.sentryclirc';
@@ -165,15 +175,15 @@ function printWelcome(options) {
165
175
  console.log('');
166
176
  clack.intro(chalk_1.default.inverse(" ".concat(options.wizardName, " ")));
167
177
  var welcomeText = options.message ||
168
- 'This Wizard will help you set up Sentry for your application.\nThank you for using Sentry :)';
178
+ "The ".concat(options.wizardName, " will help you set up Sentry for your application.\nThank you for using Sentry :)");
169
179
  if (options.promoCode) {
170
- welcomeText += "\n\nUsing promo-code: ".concat(options.promoCode);
180
+ welcomeText = "".concat(welcomeText, "\n\nUsing promo-code: ").concat(options.promoCode);
171
181
  }
172
182
  if (wizardPackage.version) {
173
- welcomeText += "\n\nVersion: ".concat(wizardPackage.version);
183
+ welcomeText = "".concat(welcomeText, "\n\nVersion: ").concat(wizardPackage.version);
174
184
  }
175
185
  if (options.telemetryEnabled) {
176
- welcomeText += "\n\nYou are using the Sentry Wizard with telemetry enabled. This helps us improve the Wizard.\nYou can disable it at any time by running `sentry-wizard --disable-telemetry`.";
186
+ welcomeText = "".concat(welcomeText, "\n\nThis wizard sends telemetry data and crash reports to Sentry. This helps us improve the Wizard.\nYou can turn this off at any time by running ").concat(chalk_1.default.cyanBright('sentry-wizard --disable-telemetry'), ".");
177
187
  }
178
188
  clack.note(welcomeText);
179
189
  }
@@ -291,32 +301,7 @@ function installPackage(_a) {
291
301
  });
292
302
  }
293
303
  exports.installPackage = installPackage;
294
- function addOrgAndProjectToSentryCliRc(org, project, setupConfig) {
295
- return __awaiter(this, void 0, void 0, function () {
296
- var configContents, e_2;
297
- return __generator(this, function (_a) {
298
- switch (_a.label) {
299
- case 0:
300
- configContents = fs.readFileSync(path.join(process.cwd(), setupConfig.filename), 'utf8');
301
- if (!setupConfig.likelyAlreadyHasOrgAndProject(configContents)) return [3 /*break*/, 1];
302
- clack.log.warn("".concat(chalk_1.default.bold(setupConfig.filename), " already has org and project. Will not add them."));
303
- return [3 /*break*/, 4];
304
- case 1:
305
- _a.trys.push([1, 3, , 4]);
306
- return [4 /*yield*/, fs.promises.appendFile(path.join(process.cwd(), setupConfig.filename), "\n".concat(setupConfig.orgAndProjContent(org, project), "\n"))];
307
- case 2:
308
- _a.sent();
309
- return [3 /*break*/, 4];
310
- case 3:
311
- e_2 = _a.sent();
312
- clack.log.warn("".concat(chalk_1.default.bold(setupConfig.filename), " could not be updated with org and project."));
313
- return [3 /*break*/, 4];
314
- case 4: return [2 /*return*/];
315
- }
316
- });
317
- });
318
- }
319
- function addSentryCliConfig(authToken, setupConfig, orgSlug, projectSlug) {
304
+ function addSentryCliConfig(authToken, setupConfig) {
320
305
  if (setupConfig === void 0) { setupConfig = exports.sourceMapsCliSetupConfig; }
321
306
  return __awaiter(this, void 0, void 0, function () {
322
307
  var configExists, configContents, _a, _b;
@@ -352,14 +337,8 @@ function addSentryCliConfig(authToken, setupConfig, orgSlug, projectSlug) {
352
337
  _b = _c.sent();
353
338
  clack.log.warning("Failed to create ".concat(chalk_1.default.bold(setupConfig.filename), " with auth token. Uploading ").concat(setupConfig.name, " during build will likely not work locally."));
354
339
  return [3 /*break*/, 8];
355
- case 8:
356
- if (!(orgSlug && projectSlug)) return [3 /*break*/, 10];
357
- return [4 /*yield*/, addOrgAndProjectToSentryCliRc(orgSlug, projectSlug, setupConfig)];
340
+ case 8: return [4 /*yield*/, addAuthTokenFileToGitIgnore(setupConfig.filename)];
358
341
  case 9:
359
- _c.sent();
360
- _c.label = 10;
361
- case 10: return [4 /*yield*/, addAuthTokenFileToGitIgnore(setupConfig.filename)];
362
- case 11:
363
342
  _c.sent();
364
343
  return [2 /*return*/];
365
344
  }
@@ -447,7 +426,8 @@ function ensurePackageIsInstalled(packageJson, packageId, packageName) {
447
426
  return __generator(this, function (_a) {
448
427
  switch (_a.label) {
449
428
  case 0:
450
- if (!!(0, package_json_1.hasPackageInstalled)(packageId, packageJson)) return [3 /*break*/, 3];
429
+ if (!!(0, package_json_1.hasPackageInstalled)(packageId, packageJson)) return [3 /*break*/, 4];
430
+ Sentry.setTag('package-installed', false);
451
431
  return [4 /*yield*/, abortIfCancelled(clack.confirm({
452
432
  message: "".concat(packageName, " does not seem to be installed. Do you still want to continue?"),
453
433
  initialValue: false,
@@ -459,7 +439,11 @@ function ensurePackageIsInstalled(packageJson, packageId, packageName) {
459
439
  case 2:
460
440
  _a.sent();
461
441
  _a.label = 3;
462
- case 3: return [2 /*return*/];
442
+ case 3: return [3 /*break*/, 5];
443
+ case 4:
444
+ Sentry.setTag('package-installed', true);
445
+ _a.label = 5;
446
+ case 5: return [2 /*return*/];
463
447
  }
464
448
  });
465
449
  });
@@ -756,19 +740,27 @@ function askForWizardLogin(options) {
756
740
  }
757
741
  function askForProjectSelection(projects) {
758
742
  return __awaiter(this, void 0, void 0, function () {
759
- var selection;
743
+ var label, sortedProjects, selection;
760
744
  return __generator(this, function (_a) {
761
745
  switch (_a.label) {
762
- case 0: return [4 /*yield*/, abortIfCancelled(clack.select({
763
- maxItems: 12,
764
- message: 'Select your Sentry project.',
765
- options: projects.map(function (project) {
766
- return {
767
- value: project,
768
- label: "".concat(project.organization.slug, "/").concat(project.slug),
769
- };
770
- }),
771
- }))];
746
+ case 0:
747
+ label = function (project) {
748
+ return "".concat(project.organization.slug, "/").concat(project.slug);
749
+ };
750
+ sortedProjects = __spreadArray([], projects, true);
751
+ sortedProjects.sort(function (a, b) {
752
+ return label(a).localeCompare(label(b));
753
+ });
754
+ return [4 /*yield*/, abortIfCancelled(clack.select({
755
+ maxItems: 12,
756
+ message: 'Select your Sentry project.',
757
+ options: sortedProjects.map(function (project) {
758
+ return {
759
+ value: project,
760
+ label: label(project),
761
+ };
762
+ }),
763
+ }))];
772
764
  case 1:
773
765
  selection = _a.sent();
774
766
  Sentry.setTag('project', selection.slug);
@@ -779,4 +771,175 @@ function askForProjectSelection(projects) {
779
771
  });
780
772
  });
781
773
  }
774
+ /**
775
+ * Asks users if they have a config file for @param tool (e.g. Vite).
776
+ * If yes, asks users to specify the path to their config file.
777
+ *
778
+ * Use this helper function as a fallback mechanism if the lookup for
779
+ * a config file with its most usual location/name fails.
780
+ *
781
+ * @param toolName Name of the tool for which we're looking for the config file
782
+ * @param configFileName Name of the most common config file name (e.g. vite.config.js)
783
+ *
784
+ * @returns a user path to the config file or undefined if the user doesn't have a config file
785
+ */
786
+ function askForToolConfigPath(toolName, configFileName) {
787
+ return __awaiter(this, void 0, void 0, function () {
788
+ var hasConfig;
789
+ return __generator(this, function (_a) {
790
+ switch (_a.label) {
791
+ case 0: return [4 /*yield*/, abortIfCancelled(clack.confirm({
792
+ message: "Do you have a ".concat(toolName, " config file (e.g. ").concat(chalk_1.default.cyan(configFileName), ")?"),
793
+ initialValue: true,
794
+ }))];
795
+ case 1:
796
+ hasConfig = _a.sent();
797
+ if (!hasConfig) {
798
+ return [2 /*return*/, undefined];
799
+ }
800
+ return [4 /*yield*/, abortIfCancelled(clack.text({
801
+ message: "Please enter the path to your ".concat(toolName, " config file:"),
802
+ placeholder: path.join('.', configFileName),
803
+ validate: function (value) {
804
+ if (!value) {
805
+ return 'Please enter a path.';
806
+ }
807
+ try {
808
+ fs.accessSync(value);
809
+ }
810
+ catch (_a) {
811
+ return 'Could not access the file at this path.';
812
+ }
813
+ },
814
+ }))];
815
+ case 2: return [2 /*return*/, _a.sent()];
816
+ }
817
+ });
818
+ });
819
+ }
820
+ exports.askForToolConfigPath = askForToolConfigPath;
821
+ /**
822
+ * Prints copy/paste-able instructions to the console.
823
+ * Afterwards asks the user if they added the code snippet to their file.
824
+ *
825
+ * While there's no point in providing a "no" answer here, it gives users time to fulfill the
826
+ * task before the wizard continues with additional steps.
827
+ *
828
+ * Use this function if you want to show users instructions on how to add/modify
829
+ * code in their file. This is helpful if automatic insertion failed or is not possible/feasible.
830
+ *
831
+ * @param filename the name of the file to which the code snippet should be applied.
832
+ * If a path is provided, only the filename will be used.
833
+ *
834
+ * @param codeSnippet the snippet to be printed. Use {@link makeCodeSnippet} to create the
835
+ * diff-like format for visually highlighting unchanged or modified lines of code.
836
+ *
837
+ * @param hint (optional) a hint to be printed after the main instruction to add
838
+ * the code from @param codeSnippet to their @param filename.
839
+ *
840
+ * More guidelines on copy/paste instructions:
841
+ * @see {@link https://develop.sentry.dev/sdk/setup-wizards/#copy--paste-snippets}
842
+ *
843
+ * TODO: refactor copy paste instructions across different wizards to use this function.
844
+ * this might require adding a custom message parameter to the function
845
+ */
846
+ function showCopyPasteInstructions(filename, codeSnippet, hint) {
847
+ return __awaiter(this, void 0, void 0, function () {
848
+ return __generator(this, function (_a) {
849
+ switch (_a.label) {
850
+ case 0:
851
+ clack.log.step("Add the following code to your ".concat(chalk_1.default.cyan(path.basename(filename)), " file:").concat(hint ? chalk_1.default.dim(" (".concat(chalk_1.default.dim(hint), ")")) : ''));
852
+ // Padding the code snippet to be printed with a \n at the beginning and end
853
+ // This makes it easier to distinguish the snippet from the rest of the output
854
+ // Intentionally logging directly to console here so that the code can be copied/pasted directly
855
+ // eslint-disable-next-line no-console
856
+ console.log("\n".concat(codeSnippet, "\n"));
857
+ return [4 /*yield*/, abortIfCancelled(clack.select({
858
+ message: 'Did you apply the snippet above?',
859
+ options: [{ label: 'Yes, continue!', value: true }],
860
+ initialValue: true,
861
+ }))];
862
+ case 1:
863
+ _a.sent();
864
+ return [2 /*return*/];
865
+ }
866
+ });
867
+ });
868
+ }
869
+ exports.showCopyPasteInstructions = showCopyPasteInstructions;
870
+ /**
871
+ * Crafts a code snippet that can be used to e.g.
872
+ * - print copy/paste instructions to the console
873
+ * - create a new config file.
874
+ *
875
+ * @param colors set this to true if you want the final snippet to be colored.
876
+ * This is useful for printing the snippet to the console as part of copy/paste instructions.
877
+ *
878
+ * @param callback the callback that returns the formatted code snippet.
879
+ * It exposes takes the helper functions for marking code as unchaned, new or removed.
880
+ * These functions no-op if no special formatting should be applied
881
+ * and otherwise apply the appropriate formatting/coloring.
882
+ * (@see {@link CodeSnippetFormatter})
883
+ *
884
+ * @see {@link showCopyPasteInstructions} for the helper with which to display the snippet in the console.
885
+ *
886
+ * @returns a string containing the final, formatted code snippet.
887
+ */
888
+ function makeCodeSnippet(colors, callback) {
889
+ var unchanged = function (txt) { return (colors ? chalk_1.default.grey(txt) : txt); };
890
+ var plus = function (txt) { return (colors ? chalk_1.default.greenBright(txt) : txt); };
891
+ var minus = function (txt) { return (colors ? chalk_1.default.redBright(txt) : txt); };
892
+ return callback(unchanged, plus, minus);
893
+ }
894
+ exports.makeCodeSnippet = makeCodeSnippet;
895
+ /**
896
+ * Creates a new config file with the given @param filepath and @param codeSnippet.
897
+ *
898
+ * Use this function to create a new config file for users. This is useful
899
+ * when users answered that they don't yet have a config file for a tool.
900
+ *
901
+ * (This doesn't mean that they don't yet have some other way of configuring
902
+ * their tool but we can leave it up to them to figure out how to merge configs
903
+ * here.)
904
+ *
905
+ * @param filepath absolute path to the new config file
906
+ * @param codeSnippet the snippet to be inserted into the file
907
+ * @param moreInformation (optional) the message to be printed after the file was created
908
+ * For example, this can be a link to more information about configuring the tool.
909
+ *
910
+ * @returns true on sucess, false otherwise
911
+ */
912
+ function createNewConfigFile(filepath, codeSnippet, moreInformation) {
913
+ return __awaiter(this, void 0, void 0, function () {
914
+ var prettyFilename, e_2;
915
+ return __generator(this, function (_a) {
916
+ switch (_a.label) {
917
+ case 0:
918
+ if (!path.isAbsolute(filepath)) {
919
+ (0, debug_1.debug)("createNewConfigFile: filepath is not absolute: ".concat(filepath));
920
+ return [2 /*return*/, false];
921
+ }
922
+ prettyFilename = chalk_1.default.cyan(path.relative(process.cwd(), filepath));
923
+ _a.label = 1;
924
+ case 1:
925
+ _a.trys.push([1, 3, , 4]);
926
+ return [4 /*yield*/, fs.promises.writeFile(filepath, codeSnippet)];
927
+ case 2:
928
+ _a.sent();
929
+ clack.log.success("Added new ".concat(prettyFilename, " file."));
930
+ if (moreInformation) {
931
+ clack.log.info(chalk_1.default.gray(moreInformation));
932
+ }
933
+ return [2 /*return*/, true];
934
+ case 3:
935
+ e_2 = _a.sent();
936
+ (0, debug_1.debug)(e_2);
937
+ clack.log.warn("Could not create a new ".concat(prettyFilename, " file. Please create one manually and follow the instructions below."));
938
+ return [3 /*break*/, 4];
939
+ case 4: return [2 /*return*/, false];
940
+ }
941
+ });
942
+ });
943
+ }
944
+ exports.createNewConfigFile = createNewConfigFile;
782
945
  //# sourceMappingURL=clack-utils.js.map