@shopify/cli-kit 3.91.1 → 3.92.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/dist/private/node/analytics/bounded-collections.d.ts +1 -3
- package/dist/private/node/analytics/bounded-collections.js.map +1 -1
- package/dist/private/node/analytics/error-categorizer.js.map +1 -1
- package/dist/private/node/analytics.js.map +1 -1
- package/dist/private/node/api/graphql.d.ts +1 -3
- package/dist/private/node/api/graphql.js.map +1 -1
- package/dist/private/node/api/headers.d.ts +2 -6
- package/dist/private/node/api/headers.js +0 -1
- package/dist/private/node/api/headers.js.map +1 -1
- package/dist/private/node/api/rest.d.ts +2 -6
- package/dist/private/node/api/rest.js.map +1 -1
- package/dist/private/node/api.js.map +1 -1
- package/dist/private/node/conf-store.d.ts +6 -6
- package/dist/private/node/conf-store.js +13 -6
- package/dist/private/node/conf-store.js.map +1 -1
- package/dist/private/node/session/device-authorization.js.map +1 -1
- package/dist/private/node/session/exchange.d.ts +1 -19
- package/dist/private/node/session/exchange.js +13 -30
- package/dist/private/node/session/exchange.js.map +1 -1
- package/dist/private/node/session/schema.d.ts +62 -62
- package/dist/private/node/session/store.js +1 -1
- package/dist/private/node/session/store.js.map +1 -1
- package/dist/private/node/session/validate.d.ts +4 -5
- package/dist/private/node/session/validate.js +7 -35
- package/dist/private/node/session/validate.js.map +1 -1
- package/dist/private/node/session.js +18 -65
- package/dist/private/node/session.js.map +1 -1
- package/dist/private/node/testing/ui.d.ts +2 -1
- package/dist/private/node/testing/ui.js +22 -24
- package/dist/private/node/testing/ui.js.map +1 -1
- package/dist/private/node/themes/generate-theme-name.js +0 -1
- package/dist/private/node/themes/generate-theme-name.js.map +1 -1
- package/dist/private/node/ui/alert.js.map +1 -1
- package/dist/private/node/ui/components/Alert.test.js +2 -4
- package/dist/private/node/ui/components/Alert.test.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.js +6 -1
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.test.js +2 -3
- package/dist/private/node/ui/components/AutocompletePrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/Banner.js +0 -1
- package/dist/private/node/ui/components/Banner.js.map +1 -1
- package/dist/private/node/ui/components/Banner.test.js +2 -2
- package/dist/private/node/ui/components/Banner.test.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.js +4 -2
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +9 -3
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -1
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/FatalError.js +0 -1
- package/dist/private/node/ui/components/FatalError.js.map +1 -1
- package/dist/private/node/ui/components/FatalError.test.js.map +1 -1
- package/dist/private/node/ui/components/List.test.js.map +1 -1
- package/dist/private/node/ui/components/LoadingBar.js.map +1 -1
- package/dist/private/node/ui/components/LoadingBar.test.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/InfoTable.d.ts +1 -3
- package/dist/private/node/ui/components/Prompts/InfoTable.js +0 -1
- package/dist/private/node/ui/components/Prompts/InfoTable.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/InfoTable.test.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.d.ts +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.js +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.test.js +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.d.ts +4 -5
- package/dist/private/node/ui/components/SelectInput.js +5 -7
- package/dist/private/node/ui/components/SelectInput.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.js +0 -1
- package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js +0 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/SingleTask.js.map +1 -1
- package/dist/private/node/ui/components/SingleTask.test.js.map +1 -1
- package/dist/private/node/ui/components/Table/ScalarDict.d.ts +2 -4
- package/dist/private/node/ui/components/Table/ScalarDict.js.map +1 -1
- package/dist/private/node/ui/components/Table/Table.js +0 -1
- package/dist/private/node/ui/components/Table/Table.js.map +1 -1
- package/dist/private/node/ui/components/Table/Table.test.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.js +0 -2
- package/dist/private/node/ui/components/Tasks.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.test.js +2 -6
- package/dist/private/node/ui/components/Tasks.test.js.map +1 -1
- package/dist/private/node/ui/components/TextAnimation.test.js +1 -1
- package/dist/private/node/ui/components/TextAnimation.test.js.map +1 -1
- package/dist/private/node/ui/components/TextInput.js +19 -19
- package/dist/private/node/ui/components/TextInput.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.js +1 -1
- package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.test.js +0 -1
- package/dist/private/node/ui/components/TextPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/TokenizedText.js +1 -2
- package/dist/private/node/ui/components/TokenizedText.js.map +1 -1
- package/dist/private/node/ui/components/TokenizedText.test.js.map +1 -1
- package/dist/private/node/ui/contexts/LinksContext.d.ts +1 -3
- package/dist/private/node/ui/contexts/LinksContext.js.map +1 -1
- package/dist/private/node/ui/hooks/use-abort-signal.js +9 -1
- package/dist/private/node/ui/hooks/use-abort-signal.js.map +1 -1
- package/dist/private/node/ui.js +8 -1
- package/dist/private/node/ui.js.map +1 -1
- package/dist/public/common/array.js +0 -1
- package/dist/public/common/array.js.map +1 -1
- package/dist/public/common/collection.d.ts +1 -3
- package/dist/public/common/collection.js.map +1 -1
- package/dist/public/common/string.js +1 -4
- package/dist/public/common/string.js.map +1 -1
- package/dist/public/common/ts/json-narrowing.d.ts +1 -3
- package/dist/public/common/ts/json-narrowing.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/analytics.js +1 -1
- package/dist/public/node/analytics.js.map +1 -1
- package/dist/public/node/api/admin.d.ts +2 -6
- package/dist/public/node/api/admin.js +1 -2
- package/dist/public/node/api/admin.js.map +1 -1
- package/dist/public/node/api/app-dev.d.ts +1 -1
- package/dist/public/node/api/app-dev.js +1 -1
- package/dist/public/node/api/app-dev.js.map +1 -1
- package/dist/public/node/api/app-management.d.ts +1 -3
- package/dist/public/node/api/app-management.js +1 -1
- package/dist/public/node/api/app-management.js.map +1 -1
- package/dist/public/node/api/business-platform.js.map +1 -1
- package/dist/public/node/api/functions.js +1 -1
- package/dist/public/node/api/functions.js.map +1 -1
- package/dist/public/node/api/graphql.d.ts +4 -12
- package/dist/public/node/api/graphql.js.map +1 -1
- package/dist/public/node/api/partners.js +1 -1
- package/dist/public/node/api/partners.js.map +1 -1
- package/dist/public/node/api/rest-api-throttler.js +0 -1
- package/dist/public/node/api/rest-api-throttler.js.map +1 -1
- package/dist/public/node/archiver.js +2 -2
- package/dist/public/node/archiver.js.map +1 -1
- package/dist/public/node/base-command.js +0 -2
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/cli.js.map +1 -1
- package/dist/public/node/context/local.js.map +1 -1
- package/dist/public/node/custom-oclif-loader.js +0 -1
- package/dist/public/node/custom-oclif-loader.js.map +1 -1
- package/dist/public/node/doctor/framework.d.ts +14 -9
- package/dist/public/node/doctor/framework.js +10 -3
- package/dist/public/node/doctor/framework.js.map +1 -1
- package/dist/public/node/doctor/reporter.d.ts +23 -0
- package/dist/public/node/doctor/reporter.js +33 -1
- package/dist/public/node/doctor/reporter.js.map +1 -1
- package/dist/public/node/dot-env.d.ts +2 -6
- package/dist/public/node/dot-env.js +1 -2
- package/dist/public/node/dot-env.js.map +1 -1
- package/dist/public/node/environments.d.ts +1 -3
- package/dist/public/node/environments.js.map +1 -1
- package/dist/public/node/error-handler.js +3 -3
- package/dist/public/node/error-handler.js.map +1 -1
- package/dist/public/node/error.d.ts +1 -1
- package/dist/public/node/error.js +2 -2
- package/dist/public/node/error.js.map +1 -1
- package/dist/public/node/framework.js +0 -1
- package/dist/public/node/framework.js.map +1 -1
- package/dist/public/node/fs.d.ts +1 -1
- package/dist/public/node/fs.js +1 -1
- package/dist/public/node/fs.js.map +1 -1
- package/dist/public/node/git.d.ts +1 -3
- package/dist/public/node/git.js +1 -3
- package/dist/public/node/git.js.map +1 -1
- package/dist/public/node/github.js +14 -8
- package/dist/public/node/github.js.map +1 -1
- package/dist/public/node/hooks/postrun.js +2 -2
- package/dist/public/node/hooks/postrun.js.map +1 -1
- package/dist/public/node/hooks/prerun.js +2 -2
- package/dist/public/node/hooks/prerun.js.map +1 -1
- package/dist/public/node/http.js +2 -3
- package/dist/public/node/http.js.map +1 -1
- package/dist/public/node/json-schema.d.ts +1 -3
- package/dist/public/node/json-schema.js +0 -1
- package/dist/public/node/json-schema.js.map +1 -1
- package/dist/public/node/liquid.js +1 -1
- package/dist/public/node/liquid.js.map +1 -1
- package/dist/public/node/local-storage.d.ts +1 -3
- package/dist/public/node/local-storage.js.map +1 -1
- package/dist/public/node/metadata.d.ts +1 -3
- package/dist/public/node/metadata.js +0 -1
- package/dist/public/node/metadata.js.map +1 -1
- package/dist/public/node/mimes.d.ts +1 -3
- package/dist/public/node/mimes.js.map +1 -1
- package/dist/public/node/monorail.js +1 -1
- package/dist/public/node/monorail.js.map +1 -1
- package/dist/public/node/multiple-installation-warning.d.ts +1 -3
- package/dist/public/node/multiple-installation-warning.js.map +1 -1
- package/dist/public/node/node-package-manager.d.ts +9 -27
- package/dist/public/node/node-package-manager.js +1 -1
- package/dist/public/node/node-package-manager.js.map +1 -1
- package/dist/public/node/os.js +1 -1
- package/dist/public/node/os.js.map +1 -1
- package/dist/public/node/output.d.ts +1 -3
- package/dist/public/node/output.js +1 -2
- package/dist/public/node/output.js.map +1 -1
- package/dist/public/node/path.d.ts +13 -0
- package/dist/public/node/path.js +10 -1
- package/dist/public/node/path.js.map +1 -1
- package/dist/public/node/plugins/tunnel.d.ts +5 -11
- package/dist/public/node/plugins/tunnel.js.map +1 -1
- package/dist/public/node/plugins.d.ts +4 -12
- package/dist/public/node/plugins.js.map +1 -1
- package/dist/public/node/result.js +1 -1
- package/dist/public/node/result.js.map +1 -1
- package/dist/public/node/session.js +15 -7
- package/dist/public/node/session.js.map +1 -1
- package/dist/public/node/system.d.ts +1 -3
- package/dist/public/node/system.js +1 -1
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/tcp.js +1 -1
- package/dist/public/node/tcp.js.map +1 -1
- package/dist/public/node/testing/output.js +1 -1
- package/dist/public/node/testing/output.js.map +1 -1
- package/dist/public/node/themes/api.js +2 -2
- package/dist/public/node/themes/api.js.map +1 -1
- package/dist/public/node/themes/conf.d.ts +1 -3
- package/dist/public/node/themes/conf.js.map +1 -1
- package/dist/public/node/tree-kill.js +0 -1
- package/dist/public/node/tree-kill.js.map +1 -1
- package/dist/public/node/ui.js +0 -12
- package/dist/public/node/ui.js.map +1 -1
- package/dist/public/node/vendor/dev_server/dev-server-2016.d.ts +8 -0
- package/dist/public/node/vendor/dev_server/dev-server-2016.js +10 -2
- package/dist/public/node/vendor/dev_server/dev-server-2016.js.map +1 -1
- package/dist/public/node/vendor/dev_server/dev-server-2024.d.ts +8 -0
- package/dist/public/node/vendor/dev_server/dev-server-2024.js +10 -2
- package/dist/public/node/vendor/dev_server/dev-server-2024.js.map +1 -1
- package/dist/public/node/vendor/dev_server/dev-server.js +1 -1
- package/dist/public/node/vendor/dev_server/dev-server.js.map +1 -1
- package/dist/public/node/vendor/dev_server/env.d.ts +3 -0
- package/dist/public/node/vendor/dev_server/env.js +3 -0
- package/dist/public/node/vendor/dev_server/env.js.map +1 -1
- package/dist/public/node/vendor/dev_server/network/host.d.ts +7 -0
- package/dist/public/node/vendor/dev_server/network/host.js +7 -1
- package/dist/public/node/vendor/dev_server/network/host.js.map +1 -1
- package/dist/public/node/vendor/dev_server/network/index.d.ts +7 -0
- package/dist/public/node/vendor/dev_server/network/index.js +7 -2
- package/dist/public/node/vendor/dev_server/network/index.js.map +1 -1
- package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.d.ts +1 -1
- package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js +2 -4
- package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js.map +1 -1
- package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.d.ts +7 -0
- package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js +9 -1
- package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js.map +1 -1
- package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.d.ts +12 -1
- package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.js +11 -0
- package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.js.map +1 -1
- package/dist/public/node/vendor/otel-js/service/types.d.ts +6 -10
- package/dist/public/node/vendor/otel-js/service/types.js.map +1 -1
- package/dist/public/node/vendor/otel-js/utils/throttle.d.ts +10 -2
- package/dist/public/node/vendor/otel-js/utils/throttle.js +9 -0
- package/dist/public/node/vendor/otel-js/utils/throttle.js.map +1 -1
- package/dist/public/node/vendor/otel-js/utils/validators.d.ts +4 -0
- package/dist/public/node/vendor/otel-js/utils/validators.js +4 -0
- package/dist/public/node/vendor/otel-js/utils/validators.js.map +1 -1
- package/dist/public/node/version.js +1 -1
- package/dist/public/node/version.js.map +1 -1
- package/dist/public/node/vscode.js +1 -1
- package/dist/public/node/vscode.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
|
@@ -3,23 +3,23 @@ import type { DoctorContext, TestResult } from './types.js';
|
|
|
3
3
|
* Result from running a CLI command.
|
|
4
4
|
*/
|
|
5
5
|
interface CommandResult {
|
|
6
|
-
/** The full command that was run */
|
|
6
|
+
/** The full command that was run. */
|
|
7
7
|
command: string;
|
|
8
|
-
/** Exit code (0 = success) */
|
|
8
|
+
/** Exit code (0 = success). */
|
|
9
9
|
exitCode: number;
|
|
10
|
-
/** Standard output */
|
|
10
|
+
/** Standard output. */
|
|
11
11
|
stdout: string;
|
|
12
|
-
/** Standard error */
|
|
12
|
+
/** Standard error. */
|
|
13
13
|
stderr: string;
|
|
14
|
-
/** Combined output (stdout + stderr) */
|
|
14
|
+
/** Combined output (stdout + stderr). */
|
|
15
15
|
output: string;
|
|
16
|
-
/** Whether the command succeeded (exitCode === 0) */
|
|
16
|
+
/** Whether the command succeeded (exitCode === 0). */
|
|
17
17
|
success: boolean;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Base class for doctor test suites.
|
|
21
21
|
*
|
|
22
|
-
* Write tests using the test() method
|
|
22
|
+
* Write tests using the test() method.
|
|
23
23
|
*
|
|
24
24
|
* ```typescript
|
|
25
25
|
* export default class MyTests extends DoctorSuite {
|
|
@@ -48,6 +48,7 @@ export declare abstract class DoctorSuite<TContext extends DoctorContext = Docto
|
|
|
48
48
|
* Run the entire test suite.
|
|
49
49
|
*
|
|
50
50
|
* @param context - The doctor context for this suite run.
|
|
51
|
+
* @returns The list of test results.
|
|
51
52
|
*/
|
|
52
53
|
runSuite(context: TContext): Promise<TestResult[]>;
|
|
53
54
|
/**
|
|
@@ -65,7 +66,9 @@ export declare abstract class DoctorSuite<TContext extends DoctorContext = Docto
|
|
|
65
66
|
* Run a CLI command and return the result.
|
|
66
67
|
*
|
|
67
68
|
* @param command - The CLI command to run.
|
|
68
|
-
* @param options - Optional
|
|
69
|
+
* @param options - Optional overrides.
|
|
70
|
+
* @param options.cwd - Working directory for the command.
|
|
71
|
+
* @param options.env - Environment variables for the command.
|
|
69
72
|
* @example
|
|
70
73
|
* const result = await this.run('shopify theme init my-theme')
|
|
71
74
|
* const result = await this.run('shopify theme push --json')
|
|
@@ -81,7 +84,9 @@ export declare abstract class DoctorSuite<TContext extends DoctorContext = Docto
|
|
|
81
84
|
* Returns only success/failure.
|
|
82
85
|
*
|
|
83
86
|
* @param command - The CLI command to run.
|
|
84
|
-
* @param options - Optional
|
|
87
|
+
* @param options - Optional overrides.
|
|
88
|
+
* @param options.cwd - Working directory for the command.
|
|
89
|
+
* @param options.env - Environment variables for the command.
|
|
85
90
|
*/
|
|
86
91
|
protected runInteractive(command: string, options?: {
|
|
87
92
|
cwd?: string;
|
|
@@ -4,7 +4,7 @@ import { execCommand, captureCommandWithExitCode } from '../system.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* Base class for doctor test suites.
|
|
6
6
|
*
|
|
7
|
-
* Write tests using the test() method
|
|
7
|
+
* Write tests using the test() method.
|
|
8
8
|
*
|
|
9
9
|
* ```typescript
|
|
10
10
|
* export default class MyTests extends DoctorSuite {
|
|
@@ -33,6 +33,7 @@ export class DoctorSuite {
|
|
|
33
33
|
* Run the entire test suite.
|
|
34
34
|
*
|
|
35
35
|
* @param context - The doctor context for this suite run.
|
|
36
|
+
* @returns The list of test results.
|
|
36
37
|
*/
|
|
37
38
|
async runSuite(context) {
|
|
38
39
|
this.context = context;
|
|
@@ -85,11 +86,14 @@ export class DoctorSuite {
|
|
|
85
86
|
// ============================================
|
|
86
87
|
// Command execution
|
|
87
88
|
// ============================================
|
|
89
|
+
/* eslint-disable tsdoc/syntax -- jsdoc/require-param expects dotted names for destructured options; tsdoc disallows dots */
|
|
88
90
|
/**
|
|
89
91
|
* Run a CLI command and return the result.
|
|
90
92
|
*
|
|
91
93
|
* @param command - The CLI command to run.
|
|
92
|
-
* @param options - Optional
|
|
94
|
+
* @param options - Optional overrides.
|
|
95
|
+
* @param options.cwd - Working directory for the command.
|
|
96
|
+
* @param options.env - Environment variables for the command.
|
|
93
97
|
* @example
|
|
94
98
|
* const result = await this.run('shopify theme init my-theme')
|
|
95
99
|
* const result = await this.run('shopify theme push --json')
|
|
@@ -111,7 +115,9 @@ export class DoctorSuite {
|
|
|
111
115
|
* Returns only success/failure.
|
|
112
116
|
*
|
|
113
117
|
* @param command - The CLI command to run.
|
|
114
|
-
* @param options - Optional
|
|
118
|
+
* @param options - Optional overrides.
|
|
119
|
+
* @param options.cwd - Working directory for the command.
|
|
120
|
+
* @param options.env - Environment variables for the command.
|
|
115
121
|
*/
|
|
116
122
|
async runInteractive(command, options) {
|
|
117
123
|
const cwd = options?.cwd ?? this.context.workingDirectory;
|
|
@@ -132,6 +138,7 @@ export class DoctorSuite {
|
|
|
132
138
|
success: exitCode === 0,
|
|
133
139
|
};
|
|
134
140
|
}
|
|
141
|
+
/* eslint-enable tsdoc/syntax */
|
|
135
142
|
// ============================================
|
|
136
143
|
// Assertions
|
|
137
144
|
// ============================================
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework.js","sourceRoot":"","sources":["../../../../src/public/node/doctor/framework.ts"],"names":[],"mappings":"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","sourcesContent":["import {fileExists, readFile} from '../fs.js'\nimport {isAbsolutePath, joinPath, relativePath} from '../path.js'\nimport {execCommand, captureCommandWithExitCode} from '../system.js'\nimport type {DoctorContext, TestResult, AssertionResult} from './types.js'\n\n/**\n * Result from running a CLI command.\n */\ninterface CommandResult {\n /** The full command that was run */\n command: string\n /** Exit code (0 = success) */\n exitCode: number\n /** Standard output */\n stdout: string\n /** Standard error */\n stderr: string\n /** Combined output (stdout + stderr) */\n output: string\n /** Whether the command succeeded (exitCode === 0) */\n success: boolean\n}\n\n/**\n * A registered test with its name and function.\n */\ninterface RegisteredTest {\n name: string\n fn: () => Promise<void>\n}\n\n/**\n * Base class for doctor test suites.\n *\n * Write tests using the test() method:.\n *\n * ```typescript\n * export default class MyTests extends DoctorSuite {\n * static description = 'My test suite'\n *\n * tests() {\n * this.test('basic case', async () => {\n * const result = await this.run('shopify theme init')\n * this.assertSuccess(result)\n * })\n *\n * this.test('error case', async () => {\n * const result = await this.run('shopify theme init --invalid')\n * this.assertError(result, /unknown flag/)\n * })\n * }\n * }\n * ```\n */\nexport abstract class DoctorSuite<TContext extends DoctorContext = DoctorContext> {\n static description = 'Doctor test suite'\n\n protected context!: TContext\n private assertions: AssertionResult[] = []\n private registeredTests: RegisteredTest[] = []\n\n /**\n * Run the entire test suite.\n *\n * @param context - The doctor context for this suite run.\n */\n async runSuite(context: TContext): Promise<TestResult[]> {\n this.context = context\n this.registeredTests = []\n const results: TestResult[] = []\n\n // Call tests() to register tests via this.test()\n this.tests()\n\n // Run all registered tests\n for (const registeredTest of this.registeredTests) {\n this.assertions = []\n const startTime = Date.now()\n\n try {\n // eslint-disable-next-line no-await-in-loop\n await registeredTest.fn()\n\n results.push({\n name: registeredTest.name,\n status: this.hasFailures() ? 'failed' : 'passed',\n duration: Date.now() - startTime,\n assertions: [...this.assertions],\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n results.push({\n name: registeredTest.name,\n status: 'failed',\n duration: Date.now() - startTime,\n assertions: [...this.assertions],\n error: error instanceof Error ? error : new Error(String(error)),\n })\n }\n }\n\n return results\n }\n\n /**\n * Register a test with a name and function.\n *\n * @param name - The test name.\n * @param fn - The async test function.\n */\n protected test(name: string, fn: () => Promise<void>): void {\n this.registeredTests.push({name, fn})\n }\n\n /**\n * Override this method to register tests using this.test().\n */\n protected tests(): void {\n // Subclasses override this to register tests\n }\n\n // ============================================\n // Command execution\n // ============================================\n\n /**\n * Run a CLI command and return the result.\n *\n * @param command - The CLI command to run.\n * @param options - Optional cwd and env overrides.\n * @example\n * const result = await this.run('shopify theme init my-theme')\n * const result = await this.run('shopify theme push --json')\n */\n protected async run(\n command: string,\n options?: {cwd?: string; env?: {[key: string]: string}},\n ): Promise<CommandResult> {\n const cwd = options?.cwd ?? this.context.workingDirectory\n const result = await captureCommandWithExitCode(command, {cwd, env: options?.env})\n\n return {\n command,\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n output: String(result.stdout) + String(result.stderr),\n success: result.exitCode === 0,\n }\n }\n\n /**\n * Run a command without capturing output (for interactive commands).\n * Returns only success/failure.\n *\n * @param command - The CLI command to run.\n * @param options - Optional cwd and env overrides.\n */\n protected async runInteractive(\n command: string,\n options?: {cwd?: string; env?: {[key: string]: string}},\n ): Promise<CommandResult> {\n const cwd = options?.cwd ?? this.context.workingDirectory\n let exitCode = 0\n\n try {\n await execCommand(command, {cwd, env: options?.env, stdin: 'inherit'})\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n exitCode = 1\n }\n\n return {\n command,\n exitCode,\n stdout: '',\n stderr: '',\n output: '',\n success: exitCode === 0,\n }\n }\n\n // ============================================\n // Assertions\n // ============================================\n\n /**\n * Assert that a command succeeded (exit code 0).\n *\n * @param result - The command result to check.\n * @param message - Optional custom assertion message.\n */\n protected assertSuccess(result: CommandResult, message?: string): void {\n this.assertions.push({\n description: message ?? `Command succeeded: ${result.command}`,\n passed: result.success,\n expected: 'exit code 0',\n actual: `exit code ${result.exitCode}`,\n })\n }\n\n /**\n * Assert that a command failed with an error matching the pattern.\n *\n * @param result - The command result to check.\n * @param pattern - Optional regex or string pattern to match against output.\n * @param message - Optional custom assertion message.\n */\n protected assertError(result: CommandResult, pattern?: RegExp | string, message?: string): void {\n const failed = !result.success\n\n if (pattern) {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern\n const matches = regex.test(result.output)\n let actualValue: string\n if (!failed) {\n actualValue = 'command succeeded'\n } else if (matches) {\n actualValue = 'matched'\n } else {\n actualValue = `output: ${result.output.slice(0, 200)}`\n }\n this.assertions.push({\n description: message ?? `Command failed with expected error: ${pattern}`,\n passed: failed && matches,\n expected: `failure with error matching ${pattern}`,\n actual: actualValue,\n })\n } else {\n this.assertions.push({\n description: message ?? `Command failed: ${result.command}`,\n passed: failed,\n expected: 'non-zero exit code',\n actual: `exit code ${result.exitCode}`,\n })\n }\n }\n\n /**\n * Assert that a file exists and optionally matches content.\n *\n * @param path - The file path to check.\n * @param contentPattern - Optional regex or string to match file content.\n * @param message - Optional custom assertion message.\n */\n protected async assertFile(path: string, contentPattern?: RegExp | string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n\n if (!exists) {\n this.assertions.push({\n description: message ?? `File exists: ${displayPath}`,\n passed: false,\n expected: 'file exists',\n actual: 'file not found',\n })\n return\n }\n\n if (contentPattern) {\n const content = await readFile(fullPath)\n const regex = typeof contentPattern === 'string' ? new RegExp(contentPattern) : contentPattern\n const matches = regex.test(content)\n this.assertions.push({\n description: message ?? `File ${displayPath} matches ${contentPattern}`,\n passed: matches,\n expected: `content matching ${contentPattern}`,\n actual: matches ? 'matched' : `content: ${content.slice(0, 200)}...`,\n })\n } else {\n this.assertions.push({\n description: message ?? `File exists: ${displayPath}`,\n passed: true,\n expected: 'file exists',\n actual: 'file exists',\n })\n }\n }\n\n /**\n * Assert that a file does not exist.\n *\n * @param path - The file path to check.\n * @param message - Optional custom assertion message.\n */\n protected async assertNoFile(path: string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n this.assertions.push({\n description: message ?? `File does not exist: ${displayPath}`,\n passed: !exists,\n expected: 'file does not exist',\n actual: exists ? 'file exists' : 'file does not exist',\n })\n }\n\n /**\n * Assert that a directory exists.\n *\n * @param path - The directory path to check.\n * @param message - Optional custom assertion message.\n */\n protected async assertDirectory(path: string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n this.assertions.push({\n description: message ?? `Directory exists: ${displayPath}`,\n passed: exists,\n expected: 'directory exists',\n actual: exists ? 'directory exists' : 'directory not found',\n })\n }\n\n /**\n * Assert that output contains a pattern.\n *\n * @param result - The command result to check.\n * @param pattern - Regex or string pattern to match against output.\n * @param message - Optional custom assertion message.\n */\n protected assertOutput(result: CommandResult, pattern: RegExp | string, message?: string): void {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern\n const matches = regex.test(result.output)\n this.assertions.push({\n description: message ?? `Output matches ${pattern}`,\n passed: matches,\n expected: `output matching ${pattern}`,\n actual: matches ? 'matched' : `output: ${result.output.slice(0, 200)}`,\n })\n }\n\n /**\n * Assert that output contains valid JSON and optionally validate it.\n *\n * @param result - The command result to parse.\n * @param validator - Optional function to validate the parsed JSON.\n * @param message - Optional custom assertion message.\n */\n protected assertJson<T = unknown>(\n result: CommandResult,\n validator?: (json: T) => boolean,\n message?: string,\n ): T | undefined {\n try {\n const json = JSON.parse(result.stdout) as T\n if (validator) {\n const valid = validator(json)\n this.assertions.push({\n description: message ?? 'Output is valid JSON matching validator',\n passed: valid,\n expected: 'valid JSON matching validator',\n actual: valid ? 'matched' : 'validator returned false',\n })\n } else {\n this.assertions.push({\n description: message ?? 'Output is valid JSON',\n passed: true,\n expected: 'valid JSON',\n actual: 'valid JSON',\n })\n }\n return json\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n this.assertions.push({\n description: message ?? 'Output is valid JSON',\n passed: false,\n expected: 'valid JSON',\n actual: `invalid JSON: ${result.stdout.slice(0, 100)}`,\n })\n return undefined\n }\n }\n\n /**\n * Assert a boolean condition.\n *\n * @param condition - The boolean condition to assert.\n * @param message - The assertion description.\n */\n protected assert(condition: boolean, message: string): void {\n this.assertions.push({\n description: message,\n passed: condition,\n expected: 'true',\n actual: String(condition),\n })\n }\n\n /**\n * Assert two values are equal.\n *\n * @param actual - The actual value.\n * @param expected - The expected value.\n * @param message - The assertion description.\n */\n protected assertEqual<T>(actual: T, expected: T, message: string): void {\n this.assertions.push({\n description: message,\n passed: actual === expected,\n expected: String(expected),\n actual: String(actual),\n })\n }\n\n private hasFailures(): boolean {\n return this.assertions.some((assertion) => !assertion.passed)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"framework.js","sourceRoot":"","sources":["../../../../src/public/node/doctor/framework.ts"],"names":[],"mappings":"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","sourcesContent":["import {fileExists, readFile} from '../fs.js'\nimport {isAbsolutePath, joinPath, relativePath} from '../path.js'\nimport {execCommand, captureCommandWithExitCode} from '../system.js'\nimport type {DoctorContext, TestResult, AssertionResult} from './types.js'\n\n/**\n * Result from running a CLI command.\n */\ninterface CommandResult {\n /** The full command that was run. */\n command: string\n /** Exit code (0 = success). */\n exitCode: number\n /** Standard output. */\n stdout: string\n /** Standard error. */\n stderr: string\n /** Combined output (stdout + stderr). */\n output: string\n /** Whether the command succeeded (exitCode === 0). */\n success: boolean\n}\n\n/**\n * A registered test with its name and function.\n */\ninterface RegisteredTest {\n /** The test name. */\n name: string\n /** The async test function. */\n fn: () => Promise<void>\n}\n\n/**\n * Base class for doctor test suites.\n *\n * Write tests using the test() method.\n *\n * ```typescript\n * export default class MyTests extends DoctorSuite {\n * static description = 'My test suite'\n *\n * tests() {\n * this.test('basic case', async () => {\n * const result = await this.run('shopify theme init')\n * this.assertSuccess(result)\n * })\n *\n * this.test('error case', async () => {\n * const result = await this.run('shopify theme init --invalid')\n * this.assertError(result, /unknown flag/)\n * })\n * }\n * }\n * ```\n */\nexport abstract class DoctorSuite<TContext extends DoctorContext = DoctorContext> {\n static description = 'Doctor test suite'\n\n protected context!: TContext\n private assertions: AssertionResult[] = []\n private registeredTests: RegisteredTest[] = []\n\n /**\n * Run the entire test suite.\n *\n * @param context - The doctor context for this suite run.\n * @returns The list of test results.\n */\n async runSuite(context: TContext): Promise<TestResult[]> {\n this.context = context\n this.registeredTests = []\n const results: TestResult[] = []\n\n // Call tests() to register tests via this.test()\n this.tests()\n\n // Run all registered tests\n for (const registeredTest of this.registeredTests) {\n this.assertions = []\n const startTime = Date.now()\n\n try {\n // eslint-disable-next-line no-await-in-loop\n await registeredTest.fn()\n\n results.push({\n name: registeredTest.name,\n status: this.hasFailures() ? 'failed' : 'passed',\n duration: Date.now() - startTime,\n assertions: [...this.assertions],\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n results.push({\n name: registeredTest.name,\n status: 'failed',\n duration: Date.now() - startTime,\n assertions: [...this.assertions],\n error: error instanceof Error ? error : new Error(String(error)),\n })\n }\n }\n\n return results\n }\n\n /**\n * Register a test with a name and function.\n *\n * @param name - The test name.\n * @param fn - The async test function.\n */\n protected test(name: string, fn: () => Promise<void>): void {\n this.registeredTests.push({name, fn})\n }\n\n /**\n * Override this method to register tests using this.test().\n */\n protected tests(): void {\n // Subclasses override this to register tests\n }\n\n // ============================================\n // Command execution\n // ============================================\n\n /* eslint-disable tsdoc/syntax -- jsdoc/require-param expects dotted names for destructured options; tsdoc disallows dots */\n /**\n * Run a CLI command and return the result.\n *\n * @param command - The CLI command to run.\n * @param options - Optional overrides.\n * @param options.cwd - Working directory for the command.\n * @param options.env - Environment variables for the command.\n * @example\n * const result = await this.run('shopify theme init my-theme')\n * const result = await this.run('shopify theme push --json')\n */\n protected async run(\n command: string,\n options?: {cwd?: string; env?: {[key: string]: string}},\n ): Promise<CommandResult> {\n const cwd = options?.cwd ?? this.context.workingDirectory\n const result = await captureCommandWithExitCode(command, {cwd, env: options?.env})\n\n return {\n command,\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n output: String(result.stdout) + String(result.stderr),\n success: result.exitCode === 0,\n }\n }\n\n /**\n * Run a command without capturing output (for interactive commands).\n * Returns only success/failure.\n *\n * @param command - The CLI command to run.\n * @param options - Optional overrides.\n * @param options.cwd - Working directory for the command.\n * @param options.env - Environment variables for the command.\n */\n protected async runInteractive(\n command: string,\n options?: {cwd?: string; env?: {[key: string]: string}},\n ): Promise<CommandResult> {\n const cwd = options?.cwd ?? this.context.workingDirectory\n let exitCode = 0\n\n try {\n await execCommand(command, {cwd, env: options?.env, stdin: 'inherit'})\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n exitCode = 1\n }\n\n return {\n command,\n exitCode,\n stdout: '',\n stderr: '',\n output: '',\n success: exitCode === 0,\n }\n }\n /* eslint-enable tsdoc/syntax */\n\n // ============================================\n // Assertions\n // ============================================\n\n /**\n * Assert that a command succeeded (exit code 0).\n *\n * @param result - The command result to check.\n * @param message - Optional custom assertion message.\n */\n protected assertSuccess(result: CommandResult, message?: string): void {\n this.assertions.push({\n description: message ?? `Command succeeded: ${result.command}`,\n passed: result.success,\n expected: 'exit code 0',\n actual: `exit code ${result.exitCode}`,\n })\n }\n\n /**\n * Assert that a command failed with an error matching the pattern.\n *\n * @param result - The command result to check.\n * @param pattern - Optional regex or string pattern to match against output.\n * @param message - Optional custom assertion message.\n */\n protected assertError(result: CommandResult, pattern?: RegExp | string, message?: string): void {\n const failed = !result.success\n\n if (pattern) {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern\n const matches = regex.test(result.output)\n let actualValue: string\n if (!failed) {\n actualValue = 'command succeeded'\n } else if (matches) {\n actualValue = 'matched'\n } else {\n actualValue = `output: ${result.output.slice(0, 200)}`\n }\n this.assertions.push({\n description: message ?? `Command failed with expected error: ${pattern}`,\n passed: failed && matches,\n expected: `failure with error matching ${pattern}`,\n actual: actualValue,\n })\n } else {\n this.assertions.push({\n description: message ?? `Command failed: ${result.command}`,\n passed: failed,\n expected: 'non-zero exit code',\n actual: `exit code ${result.exitCode}`,\n })\n }\n }\n\n /**\n * Assert that a file exists and optionally matches content.\n *\n * @param path - The file path to check.\n * @param contentPattern - Optional regex or string to match file content.\n * @param message - Optional custom assertion message.\n */\n protected async assertFile(path: string, contentPattern?: RegExp | string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n\n if (!exists) {\n this.assertions.push({\n description: message ?? `File exists: ${displayPath}`,\n passed: false,\n expected: 'file exists',\n actual: 'file not found',\n })\n return\n }\n\n if (contentPattern) {\n const content = await readFile(fullPath)\n const regex = typeof contentPattern === 'string' ? new RegExp(contentPattern) : contentPattern\n const matches = regex.test(content)\n this.assertions.push({\n description: message ?? `File ${displayPath} matches ${contentPattern}`,\n passed: matches,\n expected: `content matching ${contentPattern}`,\n actual: matches ? 'matched' : `content: ${content.slice(0, 200)}...`,\n })\n } else {\n this.assertions.push({\n description: message ?? `File exists: ${displayPath}`,\n passed: true,\n expected: 'file exists',\n actual: 'file exists',\n })\n }\n }\n\n /**\n * Assert that a file does not exist.\n *\n * @param path - The file path to check.\n * @param message - Optional custom assertion message.\n */\n protected async assertNoFile(path: string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n this.assertions.push({\n description: message ?? `File does not exist: ${displayPath}`,\n passed: !exists,\n expected: 'file does not exist',\n actual: exists ? 'file exists' : 'file does not exist',\n })\n }\n\n /**\n * Assert that a directory exists.\n *\n * @param path - The directory path to check.\n * @param message - Optional custom assertion message.\n */\n protected async assertDirectory(path: string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n this.assertions.push({\n description: message ?? `Directory exists: ${displayPath}`,\n passed: exists,\n expected: 'directory exists',\n actual: exists ? 'directory exists' : 'directory not found',\n })\n }\n\n /**\n * Assert that output contains a pattern.\n *\n * @param result - The command result to check.\n * @param pattern - Regex or string pattern to match against output.\n * @param message - Optional custom assertion message.\n */\n protected assertOutput(result: CommandResult, pattern: RegExp | string, message?: string): void {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern\n const matches = regex.test(result.output)\n this.assertions.push({\n description: message ?? `Output matches ${pattern}`,\n passed: matches,\n expected: `output matching ${pattern}`,\n actual: matches ? 'matched' : `output: ${result.output.slice(0, 200)}`,\n })\n }\n\n /**\n * Assert that output contains valid JSON and optionally validate it.\n *\n * @param result - The command result to parse.\n * @param validator - Optional function to validate the parsed JSON.\n * @param message - Optional custom assertion message.\n */\n protected assertJson<T = unknown>(\n result: CommandResult,\n validator?: (json: T) => boolean,\n message?: string,\n ): T | undefined {\n try {\n const json = JSON.parse(result.stdout) as T\n if (validator) {\n const valid = validator(json)\n this.assertions.push({\n description: message ?? 'Output is valid JSON matching validator',\n passed: valid,\n expected: 'valid JSON matching validator',\n actual: valid ? 'matched' : 'validator returned false',\n })\n } else {\n this.assertions.push({\n description: message ?? 'Output is valid JSON',\n passed: true,\n expected: 'valid JSON',\n actual: 'valid JSON',\n })\n }\n return json\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n this.assertions.push({\n description: message ?? 'Output is valid JSON',\n passed: false,\n expected: 'valid JSON',\n actual: `invalid JSON: ${result.stdout.slice(0, 100)}`,\n })\n return undefined\n }\n }\n\n /**\n * Assert a boolean condition.\n *\n * @param condition - The boolean condition to assert.\n * @param message - The assertion description.\n */\n protected assert(condition: boolean, message: string): void {\n this.assertions.push({\n description: message,\n passed: condition,\n expected: 'true',\n actual: String(condition),\n })\n }\n\n /**\n * Assert two values are equal.\n *\n * @param actual - The actual value.\n * @param expected - The expected value.\n * @param message - The assertion description.\n */\n protected assertEqual<T>(actual: T, expected: T, message: string): void {\n this.assertions.push({\n description: message,\n passed: actual === expected,\n expected: String(expected),\n actual: String(actual),\n })\n }\n\n private hasFailures(): boolean {\n return this.assertions.some((assertion) => !assertion.passed)\n }\n}\n"]}
|
|
@@ -2,9 +2,32 @@ import type { TestResult } from './types.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Initialize the reporter with a base path for truncating file paths in output.
|
|
4
4
|
* Call this before running tests to enable path truncation.
|
|
5
|
+
*
|
|
6
|
+
* @param basePath - The base path used to truncate absolute paths in output.
|
|
5
7
|
*/
|
|
6
8
|
export declare function initReporter(basePath: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* Log the start of a test suite.
|
|
11
|
+
*
|
|
12
|
+
* @param suiteName - The name of the suite.
|
|
13
|
+
* @param description - The suite description.
|
|
14
|
+
*/
|
|
7
15
|
export declare function reportSuiteStart(suiteName: string, description: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Log the start of a test.
|
|
18
|
+
*
|
|
19
|
+
* @param testName - The name of the test.
|
|
20
|
+
*/
|
|
8
21
|
export declare function reportTestStart(testName: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Log the result of a single test (passed, failed, or skipped).
|
|
24
|
+
*
|
|
25
|
+
* @param result - The test result to report.
|
|
26
|
+
*/
|
|
9
27
|
export declare function reportTestResult(result: TestResult): void;
|
|
28
|
+
/**
|
|
29
|
+
* Log a summary of all test results.
|
|
30
|
+
*
|
|
31
|
+
* @param results - The list of test results to summarize.
|
|
32
|
+
*/
|
|
10
33
|
export declare function reportSummary(results: TestResult[]): void;
|
|
@@ -7,13 +7,18 @@ let reporterBasePath;
|
|
|
7
7
|
/**
|
|
8
8
|
* Initialize the reporter with a base path for truncating file paths in output.
|
|
9
9
|
* Call this before running tests to enable path truncation.
|
|
10
|
+
*
|
|
11
|
+
* @param basePath - The base path used to truncate absolute paths in output.
|
|
10
12
|
*/
|
|
11
13
|
export function initReporter(basePath) {
|
|
12
14
|
reporterBasePath = basePath;
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
15
17
|
* Truncate absolute paths to be relative to the base path.
|
|
16
|
-
* Looks for paths in common patterns like "File exists: /path/to/file"
|
|
18
|
+
* Looks for paths in common patterns like "File exists: /path/to/file".
|
|
19
|
+
*
|
|
20
|
+
* @param text - The text that may contain absolute paths to truncate.
|
|
21
|
+
* @returns The text with paths relativized when under the reporter base path.
|
|
17
22
|
*/
|
|
18
23
|
function truncatePaths(text) {
|
|
19
24
|
if (!reporterBasePath)
|
|
@@ -26,14 +31,30 @@ function truncatePaths(text) {
|
|
|
26
31
|
return relativizePath(path, reporterBasePath);
|
|
27
32
|
});
|
|
28
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Log the start of a test suite.
|
|
36
|
+
*
|
|
37
|
+
* @param suiteName - The name of the suite.
|
|
38
|
+
* @param description - The suite description.
|
|
39
|
+
*/
|
|
29
40
|
export function reportSuiteStart(suiteName, description) {
|
|
30
41
|
log('');
|
|
31
42
|
log(colors.bold(colors.cyan(`Suite: ${suiteName}`)));
|
|
32
43
|
log(colors.dim(description));
|
|
33
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Log the start of a test.
|
|
47
|
+
*
|
|
48
|
+
* @param testName - The name of the test.
|
|
49
|
+
*/
|
|
34
50
|
export function reportTestStart(testName) {
|
|
35
51
|
log(colors.bold(colors.blue(`Running: ${testName}`)));
|
|
36
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Log the result of a single test (passed, failed, or skipped).
|
|
55
|
+
*
|
|
56
|
+
* @param result - The test result to report.
|
|
57
|
+
*/
|
|
37
58
|
export function reportTestResult(result) {
|
|
38
59
|
const durationStr = `(${(result.duration / 1000).toFixed(2)}s)`;
|
|
39
60
|
if (result.status === 'passed') {
|
|
@@ -55,6 +76,11 @@ export function reportTestResult(result) {
|
|
|
55
76
|
log(colors.yellow(`SKIPPED: ${result.name}`));
|
|
56
77
|
}
|
|
57
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Log a summary of all test results.
|
|
81
|
+
*
|
|
82
|
+
* @param results - The list of test results to summarize.
|
|
83
|
+
*/
|
|
58
84
|
export function reportSummary(results) {
|
|
59
85
|
const passed = results.filter((result) => result.status === 'passed').length;
|
|
60
86
|
const failed = results.filter((result) => result.status === 'failed').length;
|
|
@@ -76,6 +102,12 @@ export function reportSummary(results) {
|
|
|
76
102
|
}
|
|
77
103
|
log(` Total time: ${colors.dim(`${(totalDuration / 1000).toFixed(2)}s`)}`);
|
|
78
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Format assertion results as log lines.
|
|
107
|
+
*
|
|
108
|
+
* @param assertions - The assertion results to format.
|
|
109
|
+
* @returns Array of formatted log lines.
|
|
110
|
+
*/
|
|
79
111
|
function formatAssertions(assertions) {
|
|
80
112
|
return assertions.map((assertion) => {
|
|
81
113
|
if (assertion.passed) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../../../src/public/node/doctor/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,cAAc,CAAA;AACjC,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AACvC,OAAO,EAAC,cAAc,EAAC,MAAM,YAAY,CAAA;AAGzC,MAAM,GAAG,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;AAEpD,4BAA4B;AAC5B,IAAI,gBAAoC,CAAA;AAExC
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../../../src/public/node/doctor/reporter.ts"],"names":[],"mappings":"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","sourcesContent":["import colors from '../colors.js'\nimport {outputInfo} from '../output.js'\nimport {relativizePath} from '../path.js'\nimport type {TestResult, AssertionResult} from './types.js'\n\nconst log = (message: string) => outputInfo(message)\n\n// Reporter context for path\nlet reporterBasePath: string | undefined\n\n/**\n * Initialize the reporter with a base path for truncating file paths in output.\n * Call this before running tests to enable path truncation.\n *\n * @param basePath - The base path used to truncate absolute paths in output.\n */\nexport function initReporter(basePath: string): void {\n reporterBasePath = basePath\n}\n\n/**\n * Truncate absolute paths to be relative to the base path.\n * Looks for paths in common patterns like \"File exists: /path/to/file\".\n *\n * @param text - The text that may contain absolute paths to truncate.\n * @returns The text with paths relativized when under the reporter base path.\n */\nfunction truncatePaths(text: string): string {\n if (!reporterBasePath) return text\n\n // Match absolute paths\n // relativizePath will convert paths under reporterBasePath to relative paths\n // and keep other paths unchanged\n const absolutePathPattern = /\\/[^\\s,)]+/g\n\n return text.replace(absolutePathPattern, (path) => {\n return relativizePath(path, reporterBasePath)\n })\n}\n\n/**\n * Log the start of a test suite.\n *\n * @param suiteName - The name of the suite.\n * @param description - The suite description.\n */\nexport function reportSuiteStart(suiteName: string, description: string): void {\n log('')\n log(colors.bold(colors.cyan(`Suite: ${suiteName}`)))\n log(colors.dim(description))\n}\n\n/**\n * Log the start of a test.\n *\n * @param testName - The name of the test.\n */\nexport function reportTestStart(testName: string): void {\n log(colors.bold(colors.blue(`Running: ${testName}`)))\n}\n\n/**\n * Log the result of a single test (passed, failed, or skipped).\n *\n * @param result - The test result to report.\n */\nexport function reportTestResult(result: TestResult): void {\n const durationStr = `(${(result.duration / 1000).toFixed(2)}s)`\n\n if (result.status === 'passed') {\n log(colors.bold(colors.green(`PASSED: ${result.name} ${colors.dim(durationStr)}`)))\n for (const line of formatAssertions(result.assertions)) {\n log(line)\n }\n } else if (result.status === 'failed') {\n log(colors.red(`FAILED: ${result.name} ${colors.dim(durationStr)}`))\n for (const line of formatAssertions(result.assertions)) {\n log(line)\n }\n if (result.error) {\n log(colors.red(` Error: ${truncatePaths(result.error.message)}`))\n }\n } else {\n log(colors.yellow(`SKIPPED: ${result.name}`))\n }\n}\n\n/**\n * Log a summary of all test results.\n *\n * @param results - The list of test results to summarize.\n */\nexport function reportSummary(results: TestResult[]): void {\n const passed = results.filter((result) => result.status === 'passed').length\n const failed = results.filter((result) => result.status === 'failed').length\n const skipped = results.filter((result) => result.status === 'skipped').length\n const total = results.length\n const totalDuration = results.reduce((sum, result) => sum + result.duration, 0)\n\n log('')\n log(colors.bold('─'.repeat(40)))\n\n if (failed > 0) {\n log(colors.red(colors.bold(`Doctor Complete: ${failed}/${total} tests failed`)))\n } else {\n log(colors.green(colors.bold(`Doctor Complete: ${passed}/${total} tests passed`)))\n }\n\n log(` Passed: ${colors.green(String(passed))}`)\n log(` Failed: ${colors.red(String(failed))}`)\n if (skipped > 0) {\n log(` Skipped: ${colors.yellow(String(skipped))}`)\n }\n log(` Total time: ${colors.dim(`${(totalDuration / 1000).toFixed(2)}s`)}`)\n}\n\n/**\n * Format assertion results as log lines.\n *\n * @param assertions - The assertion results to format.\n * @returns Array of formatted log lines.\n */\nfunction formatAssertions(assertions: AssertionResult[]): string[] {\n return assertions.map((assertion) => {\n if (assertion.passed) {\n return colors.green(` [OK] ${assertion.description}`)\n } else {\n const details = ` (expected: ${assertion.expected}, actual: ${assertion.actual})`\n return colors.red(` [FAIL] ${assertion.description}${details}`)\n }\n })\n}\n"]}
|
|
@@ -9,9 +9,7 @@ export interface DotEnvFile {
|
|
|
9
9
|
/**
|
|
10
10
|
* Variables of the .env file.
|
|
11
11
|
*/
|
|
12
|
-
variables:
|
|
13
|
-
[name: string]: string;
|
|
14
|
-
};
|
|
12
|
+
variables: Record<string, string>;
|
|
15
13
|
}
|
|
16
14
|
/**
|
|
17
15
|
* Reads and parses a .env file.
|
|
@@ -30,7 +28,5 @@ export declare function writeDotEnv(file: DotEnvFile): Promise<void>;
|
|
|
30
28
|
* @param envFileContent - .env file contents.
|
|
31
29
|
* @param updatedValues - object containing new env variables values.
|
|
32
30
|
*/
|
|
33
|
-
export declare function patchEnvFile(envFileContent: string | null, updatedValues:
|
|
34
|
-
[key: string]: string | undefined;
|
|
35
|
-
}): string;
|
|
31
|
+
export declare function patchEnvFile(envFileContent: string | null, updatedValues: Record<string, string | undefined>): string;
|
|
36
32
|
export declare function createDotEnvFileLine(key: string, value?: string, quote?: string): string;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { outputDebug, outputContent, outputToken } from './output.js';
|
|
2
2
|
import { AbortError } from './error.js';
|
|
3
3
|
import { fileExists, readFile, writeFile } from './fs.js';
|
|
4
|
-
import { outputDebug, outputContent, outputToken } from '../../public/node/output.js';
|
|
5
4
|
import { parse } from 'dotenv';
|
|
6
5
|
/**
|
|
7
6
|
* Reads and parses a .env file.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dot-env.js","sourceRoot":"","sources":["../../../src/public/node/dot-env.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"dot-env.js","sourceRoot":"","sources":["../../../src/public/node/dot-env.ts"],"names":[],"mappings":"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","sourcesContent":["import {outputDebug, outputContent, outputToken} from './output.js'\nimport {AbortError} from './error.js'\nimport {fileExists, readFile, writeFile} from './fs.js'\nimport {parse} from 'dotenv'\n\n/**\n * This interface represents a .env file.\n */\nexport interface DotEnvFile {\n /**\n * Path to the .env file.\n */\n path: string\n /**\n * Variables of the .env file.\n */\n variables: Record<string, string>\n}\n\n/**\n * Reads and parses a .env file.\n * @param path - Path to the .env file\n * @returns An in-memory representation of the .env file.\n */\nexport async function readAndParseDotEnv(path: string): Promise<DotEnvFile> {\n outputDebug(outputContent`Reading the .env file at ${outputToken.path(path)}`)\n if (!(await fileExists(path))) {\n throw new AbortError(`The environment file at ${path} does not exist.`)\n }\n const content = await readFile(path)\n return {\n path,\n variables: parse(content),\n }\n}\n\n/**\n * Writes a .env file to disk.\n * @param file - .env file to be written.\n */\nexport async function writeDotEnv(file: DotEnvFile): Promise<void> {\n const fileContent = Object.entries(file.variables)\n .map(([key, value]) => createDotEnvFileLine(key, value))\n .join('\\n')\n\n await writeFile(file.path, fileContent)\n}\n\n/**\n * Given an .env file content, generates a new one with new values\n * without removing already existing lines.\n * @param envFileContent - .env file contents.\n * @param updatedValues - object containing new env variables values.\n */\nexport function patchEnvFile(envFileContent: string | null, updatedValues: Record<string, string | undefined>): string {\n const outputLines: string[] = []\n const envFileLines = envFileContent === null ? [] : envFileContent.split('\\n')\n\n const alreadyPresentKeys: string[] = []\n\n let multilineVariable:\n | {\n key: string\n value: string\n quote: string\n }\n | undefined\n\n for (const line of envFileLines) {\n if (multilineVariable) {\n if (line.endsWith(multilineVariable.quote)) {\n let lineToWrite = createDotEnvFileLine(\n multilineVariable.key,\n multilineVariable.value + line.slice(0, -1),\n multilineVariable.quote,\n )\n const newValue = updatedValues[multilineVariable.key]\n if (newValue) {\n alreadyPresentKeys.push(multilineVariable.key)\n lineToWrite = createDotEnvFileLine(multilineVariable.key, newValue)\n }\n outputLines.push(lineToWrite)\n multilineVariable = undefined\n } else {\n multilineVariable.value += `${line}\\n`\n }\n continue\n }\n\n const match = line.match(/^([^=:#]+?)[=:](.*)/)\n let lineToWrite = line\n\n if (match) {\n const key = match[1]!.trim()\n const value = (match[2] || '').trim()\n\n if (/^[\"'`]/.test(value) && !value.endsWith(value[0]!)) {\n multilineVariable = {\n key,\n value: `${value.slice(1)}\\n`,\n quote: value[0]!,\n }\n continue\n }\n\n const newValue = updatedValues[key]\n if (newValue) {\n alreadyPresentKeys.push(key)\n lineToWrite = createDotEnvFileLine(key, newValue)\n }\n }\n\n outputLines.push(lineToWrite)\n }\n\n if (multilineVariable) {\n throw new AbortError(`Multi-line environment variable '${multilineVariable.key}' is not properly enclosed.`)\n }\n\n for (const [patchKey, updatedValue] of Object.entries(updatedValues)) {\n if (!alreadyPresentKeys.includes(patchKey)) {\n outputLines.push(createDotEnvFileLine(patchKey, updatedValue))\n }\n }\n\n return outputLines.join('\\n')\n}\n\nexport function createDotEnvFileLine(key: string, value?: string, quote?: string): string {\n if (quote) {\n return `${key}=${quote}${value}${quote}`\n }\n if (value?.includes('\\n')) {\n const quoteCharacter = ['\"', \"'\", '`'].find((char) => !value.includes(char))\n\n if (!quoteCharacter) {\n throw new AbortError(`The environment file patch has an env value that can't be surrounded by quotes: ${value}`)\n }\n\n return `${key}=${quoteCharacter}${value}${quoteCharacter}`\n }\n return `${key}=${value}`\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environments.js","sourceRoot":"","sources":["../../../src/public/node/environments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,WAAW,CAAA;AACpC,OAAO,EAAC,UAAU,EAAE,QAAQ,EAAC,MAAM,SAAS,CAAA;AAC5C,OAAO,EAAC,GAAG,EAAC,MAAM,WAAW,CAAA;AAC7B,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"environments.js","sourceRoot":"","sources":["../../../src/public/node/environments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,WAAW,CAAA;AACpC,OAAO,EAAC,UAAU,EAAE,QAAQ,EAAC,MAAM,SAAS,CAAA;AAC5C,OAAO,EAAC,GAAG,EAAC,MAAM,WAAW,CAAA;AAC7B,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,SAAS,CAAA;AAUrC;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,OAA4C,EAAE,MAAgB;IAC3F,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,aAAa,CAAC,OAAO,CAAC,CAAA;IACxB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,eAAuB,EACvB,QAAgB,EAChB,OAAgC;IAEhC,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC7D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,qBAAqB,CAAC,EAAC,IAAI,EAAE,6BAA6B,EAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;QAC7E,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAiB,CAAA;IAC7E,MAAM,YAAY,GAAG,gBAAgB,CAAC,YAAY,CAAA;IAClD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,qBAAqB,CACnB;YACE,IAAI,EAAE,CAAC,0BAA0B,EAAE,EAAC,OAAO,EAAE,QAAQ,EAAC,EAAE,EAAC,IAAI,EAAE,GAAG,EAAC,CAAC;SACrE,EACD,OAAO,EAAE,MAAM,CAChB,CAAA;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,WAAW,GAAG,YAAY,CAAC,eAAe,CAAwB,CAAA;IAExE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,qBAAqB,CACnB;YACE,IAAI,EAAE,CAAC,aAAa,EAAE,EAAC,OAAO,EAAE,eAAe,EAAC,EAAE,YAAY,CAAC;SAChE,EACD,OAAO,EAAE,MAAM,CAChB,CAAA;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,QAAQ,CAAC,oBAAoB,CAAC,GAAG,EAAE,CAAC,CAAC;QACzC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;KAC9C,CAAC,CAAC,CAAA;IAEH,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAgB,EAChB,OAAgC;IAEhC,MAAM,QAAQ,GAAG,OAAO,EAAE,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;IAC7E,OAAO,UAAU,CAAC,QAAQ,EAAE;QAC1B,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,MAAM;KACb,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import {decodeToml} from './toml.js'\nimport {findPathUp, readFile} from './fs.js'\nimport {cwd} from './path.js'\nimport * as metadata from './metadata.js'\nimport {renderWarning} from './ui.js'\nimport {JsonMap} from '../../private/common/json.js'\n\nexport type Environments = Record<string, JsonMap>\n\ninterface LoadEnvironmentOptions {\n from?: string\n silent?: boolean\n}\n\n/**\n * Renders a warning message unless silent mode is enabled.\n * @param message - The warning message to render.\n * @param silent - Whether to suppress the warning.\n */\nfunction renderWarningIfNeeded(message: Parameters<typeof renderWarning>[0], silent?: boolean): void {\n if (!silent) {\n renderWarning(message)\n }\n}\n\n/**\n * Loads environments from a file.\n * @param dir - The file path to load environments from.\n * @returns The loaded environments.\n */\nexport async function loadEnvironment(\n environmentName: string,\n fileName: string,\n options?: LoadEnvironmentOptions,\n): Promise<JsonMap | undefined> {\n const filePath = await environmentFilePath(fileName, options)\n if (!filePath) {\n renderWarningIfNeeded({body: 'Environment file not found.'}, options?.silent)\n return undefined\n }\n const environmentsJson = decodeToml(await readFile(filePath)) as Environments\n const environments = environmentsJson.environments\n if (!environments) {\n renderWarningIfNeeded(\n {\n body: ['No environments found in', {command: filePath}, {char: '.'}],\n },\n options?.silent,\n )\n return undefined\n }\n const environment = environments[environmentName] as JsonMap | undefined\n\n if (!environment) {\n renderWarningIfNeeded(\n {\n body: ['Environment', {command: environmentName}, 'not found.'],\n },\n options?.silent,\n )\n return undefined\n }\n\n await metadata.addSensitiveMetadata(() => ({\n environmentFlags: JSON.stringify(environment),\n }))\n\n return environment\n}\n\nexport async function environmentFilePath(\n fileName: string,\n options?: LoadEnvironmentOptions,\n): Promise<string | undefined> {\n const basePath = options?.from && options.from !== '.' ? options.from : cwd()\n return findPathUp(fileName, {\n cwd: basePath,\n type: 'file',\n })\n}\n"]}
|
|
@@ -3,9 +3,9 @@ import * as path from './path.js';
|
|
|
3
3
|
import { fanoutHooks } from './plugins.js';
|
|
4
4
|
import * as metadata from './metadata.js';
|
|
5
5
|
import { AbortSilentError, CancelExecution, errorMapper, shouldReportErrorAsUnexpected, handler, cleanSingleStackTracePath, } from './error.js';
|
|
6
|
-
import {
|
|
6
|
+
import { outputDebug, outputInfo } from './output.js';
|
|
7
7
|
import { getEnvironmentData } from '../../private/node/analytics.js';
|
|
8
|
-
import {
|
|
8
|
+
import { isLocalEnvironment } from '../../private/node/context/service.js';
|
|
9
9
|
import { bugsnagApiKey, reportingRateLimit } from '../../private/node/constants.js';
|
|
10
10
|
import { CLI_KIT_VERSION } from '../common/version.js';
|
|
11
11
|
import { runWithRateLimit } from '../../private/node/conf-store.js';
|
|
@@ -198,7 +198,7 @@ export async function registerCleanBugsnagErrorsFromWithinPlugins(config) {
|
|
|
198
198
|
}
|
|
199
199
|
});
|
|
200
200
|
}
|
|
201
|
-
// eslint-disable-next-line @typescript-eslint/
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
202
202
|
export async function addBugsnagMetadata(event, config) {
|
|
203
203
|
const publicData = metadata.getAllPublicMetadata();
|
|
204
204
|
const { commandStartOptions } = metadata.getAllSensitiveMetadata();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../../src/public/node/error-handler.ts"],"names":[],"mappings":"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","sourcesContent":["import {CommandExitMode, reportAnalyticsEvent} from './analytics.js'\nimport * as path from './path.js'\nimport {fanoutHooks} from './plugins.js'\nimport * as metadata from './metadata.js'\nimport {\n AbortSilentError,\n CancelExecution,\n errorMapper,\n shouldReportErrorAsUnexpected,\n handler,\n cleanSingleStackTracePath,\n} from './error.js'\nimport {isLocalEnvironment} from '../../private/node/context/service.js'\nimport {getEnvironmentData} from '../../private/node/analytics.js'\nimport {outputDebug, outputInfo} from '../../public/node/output.js'\nimport {bugsnagApiKey, reportingRateLimit} from '../../private/node/constants.js'\nimport {CLI_KIT_VERSION} from '../common/version.js'\nimport {runWithRateLimit} from '../../private/node/conf-store.js'\nimport {getLastSeenUserIdAfterAuth} from '../../private/node/session.js'\nimport {settings, Interfaces} from '@oclif/core'\nimport StackTracey from 'stacktracey'\nimport Bugsnag, {Event} from '@bugsnag/js'\nimport {realpath} from 'fs/promises'\n\n// Allowed slice names for error analytics grouping.\n// Hardcoded list per product slices to keep analytics consistent.\nconst ALLOWED_SLICE_NAMES = new Set<string>(['app', 'theme', 'hydrogen', 'store'])\n\nexport async function errorHandler(\n error: Error & {exitCode?: number | undefined},\n config?: Interfaces.Config,\n): Promise<void> {\n if (error instanceof CancelExecution) {\n if (error.message && error.message !== '') {\n outputInfo(`✨ ${error.message}`)\n }\n } else if (error instanceof AbortSilentError) {\n /* empty */\n } else {\n return errorMapper(error)\n .then((error) => {\n return handler(error)\n })\n .then((mappedError) => {\n return reportError(mappedError, config)\n })\n }\n}\n\nconst reportError = async (error: unknown, config?: Interfaces.Config): Promise<void> => {\n // categorise the error first\n let exitMode: CommandExitMode = 'expected_error'\n if (shouldReportErrorAsUnexpected(error)) exitMode = 'unexpected_error'\n\n if (config !== undefined) {\n // Log an analytics event when there's an error\n await reportAnalyticsEvent({config, errorMessage: error instanceof Error ? error.message : undefined, exitMode})\n }\n await sendErrorToBugsnag(error, exitMode)\n}\n\n/**\n * Sends an error to Bugsnag. This is configured automatically for uncaught errors from CLI commands, but can also be used to manually record an error.\n *\n * @returns the reported error (this may have been tweaked for better reporting), and a bool to indicate if the error was actually submitted or not\n */\nexport async function sendErrorToBugsnag(\n error: unknown,\n exitMode: Omit<CommandExitMode, 'ok'>,\n): Promise<{reported: false; error: unknown; unhandled: unknown} | {error: Error; reported: true; unhandled: boolean}> {\n try {\n if (isLocalEnvironment() || settings.debug) {\n outputDebug(`Skipping Bugsnag report`)\n return {reported: false, error, unhandled: undefined}\n }\n\n // If the error was unexpected, we flag it as \"unhandled\" in Bugsnag. This is a helpful distinction.\n const unhandled = exitMode === 'unexpected_error'\n\n let reportableError: Error\n let stacktrace: string | undefined\n let report = false\n\n if (error instanceof Error) {\n report = true\n reportableError = new Error(error.message)\n stacktrace = error.stack\n\n /**\n * Some errors that reach this point have an empty string. For example:\n * https://app.bugsnag.com/shopify/cli/errors/62cd5d31fd5040000814086c?filters[event.since]=30d&filters[error.status]=new&filters[release.seen_in]=3.1.0\n *\n * Because at this point we have neither the error message nor a stack trace reporting them\n * to Bugsnag is pointless and adds noise.\n */\n } else if (typeof error === 'string' && error.trim().length !== 0) {\n report = true\n reportableError = new Error(error)\n stacktrace = reportableError.stack\n } else {\n report = false\n reportableError = new Error('Unknown error')\n }\n\n const formattedStacktrace = new StackTracey(stacktrace ?? '')\n .clean()\n .items.map((item) => {\n const filePath = cleanSingleStackTracePath(item.file)\n return ` at ${item.callee} (${filePath}:${item.line}:${item.column})`\n })\n .join('\\n')\n reportableError.stack = `Error: ${reportableError.message}\\n${formattedStacktrace}`\n\n let withinRateLimit = false\n await runWithRateLimit({\n key: 'send-error-to-bugsnag',\n ...reportingRateLimit,\n task: async () => {\n withinRateLimit = true\n },\n })\n if (!withinRateLimit) {\n outputDebug(`Skipping Bugsnag report due to rate limiting`)\n report = false\n }\n\n if (report) {\n initializeBugsnag()\n let userId: string | undefined = await getLastSeenUserIdAfterAuth()\n if (userId === 'unknown') {\n // Observe will use the IP when undefined\n userId = undefined\n }\n await new Promise((resolve, reject) => {\n outputDebug(`Reporting ${unhandled ? 'unhandled' : 'handled'} error to Bugsnag: ${reportableError.message}`)\n const eventHandler = (event: Event) => {\n event.severity = 'error'\n event.unhandled = unhandled\n event.setUser(userId)\n // Attach command metadata so we know which CLI command triggered the error\n const {commandStartOptions} = metadata.getAllSensitiveMetadata()\n const {startCommand} = commandStartOptions ?? {}\n if (startCommand) {\n const firstWord = startCommand.trim().split(/\\s+/)[0] ?? 'cli'\n const sliceName = ALLOWED_SLICE_NAMES.has(firstWord) ? firstWord : 'cli'\n event.addMetadata('custom', {slice_name: sliceName})\n }\n }\n const errorHandler = (error: unknown) => {\n if (error) {\n reject(error)\n } else {\n resolve(reportableError)\n }\n }\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n Bugsnag.notify(reportableError, eventHandler, errorHandler)\n })\n }\n return {error: reportableError, reported: report, unhandled}\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (err) {\n outputDebug(`Error reporting to Bugsnag: ${err}`)\n return {error, reported: false, unhandled: undefined}\n }\n}\n\n/**\n * If the given file path is within a node_modules folder, remove prefix up\n * to and including the node_modules folder.\n *\n * This gives us very consistent paths for errors generated by the CLI.\n */\nexport function cleanStackFrameFilePath({\n currentFilePath,\n projectRoot,\n pluginLocations,\n}: {\n currentFilePath: string\n projectRoot: string\n pluginLocations: {name: string; pluginPath: string}[]\n}): string {\n const fullLocation = path.isAbsolutePath(currentFilePath)\n ? currentFilePath\n : path.joinPath(projectRoot, currentFilePath)\n\n const matchingPluginPath = pluginLocations.filter(({pluginPath}) => fullLocation.startsWith(pluginPath))[0]\n\n if (matchingPluginPath !== undefined) {\n // the plugin name (e.g. @shopify/cli-kit), plus the relative path of the error line from within the plugin's code (e.g. dist/something.js )\n return path.joinPath(matchingPluginPath.name, path.relativePath(matchingPluginPath.pluginPath, fullLocation))\n }\n\n // strip prefix up to node_modules folder, so we can normalize error reporting\n return currentFilePath.replace(/.*node_modules\\//, '')\n}\n\n/**\n * Register a Bugsnag error listener to clean up stack traces for errors within plugin code.\n *\n */\nexport async function registerCleanBugsnagErrorsFromWithinPlugins(config: Interfaces.Config): Promise<void> {\n // Bugsnag have their own plug-ins that use this private field\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const bugsnagConfigProjectRoot: string = (Bugsnag as any)?._client?._config?.projectRoot ?? path.cwd()\n const projectRoot = path.normalizePath(bugsnagConfigProjectRoot)\n const pluginLocations = await Promise.all(\n [...config.plugins].map(async ([_, plugin]) => {\n const followSymlinks = await realpath(plugin.root)\n return {name: plugin.name, pluginPath: path.normalizePath(followSymlinks)}\n }),\n )\n initializeBugsnag()\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n Bugsnag.addOnError(async (event) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event.errors.forEach((error: any) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error.stacktrace.forEach((stackFrame: any) => {\n stackFrame.file = cleanStackFrameFilePath({currentFilePath: stackFrame.file, projectRoot, pluginLocations})\n })\n })\n try {\n await addBugsnagMetadata(event, config)\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (metadataError) {\n outputDebug(`There was an error adding metadata to the Bugsnag report; Ignoring and carrying on ${metadataError}`)\n }\n })\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any\nexport async function addBugsnagMetadata(event: any, config: Interfaces.Config): Promise<void> {\n const publicData = metadata.getAllPublicMetadata()\n const {commandStartOptions} = metadata.getAllSensitiveMetadata()\n const {startCommand} = commandStartOptions ?? {}\n\n const {'@shopify/app': appPublic, ...otherPluginsPublic} = await fanoutHooks(config, 'public_command_metadata', {})\n\n const environment = await getEnvironmentData(config)\n\n const allMetadata = {\n command: startCommand,\n ...appPublic,\n ...publicData,\n ...environment,\n pluginData: otherPluginsPublic,\n }\n\n const appData = {} as {[key: string]: unknown}\n const commandData = {} as {[key: string]: unknown}\n const environmentData = {} as {[key: string]: unknown}\n const miscData = {} as {[key: string]: unknown}\n const appKeys = ['api_key', 'business_platform_id', 'partner_id', 'project_type']\n const commandKeys = ['command']\n const environmentKeys = ['cli_version', 'node_version', 'uname']\n\n Object.entries(allMetadata).forEach(([key, value]) => {\n if (key.startsWith('app_') || appKeys.includes(key)) {\n appData[key] = value\n } else if (key.startsWith('cmd_') || commandKeys.includes(key)) {\n commandData[key] = value\n } else if (key.startsWith('env_') || environmentKeys) {\n environmentData[key] = value\n } else {\n miscData[key] = value\n }\n })\n\n // app, command, environment, misc\n const bugsnagMetadata = {\n 'Shopify App': appData,\n Command: commandData,\n Environment: environmentData,\n Misc: miscData,\n }\n Object.entries(bugsnagMetadata).forEach(([section, values]) => {\n event.addMetadata(section, values)\n })\n}\n\nfunction initializeBugsnag() {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n if (Bugsnag.isStarted()) {\n return\n }\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n Bugsnag.start({\n appType: 'node',\n apiKey: bugsnagApiKey,\n logger: null,\n appVersion: CLI_KIT_VERSION,\n autoTrackSessions: false,\n autoDetectErrors: false,\n enabledReleaseStages: ['production'],\n endpoints: {\n notify: 'https://error-analytics-production.shopifysvc.com',\n sessions: 'https://error-analytics-sessions-production.shopifysvc.com',\n },\n // Set the project root to `null` to prevent the default behavior of\n // Bugsnag which is to set it to the cwd. That is unhelpful for us because\n // the cwd can be anywhere in the user's filesystem, not necessarily\n // related to the CLI codebase.\n projectRoot: null,\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../../src/public/node/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,oBAAoB,EAAC,MAAM,gBAAgB,CAAA;AACpE,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAA;AACxC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,6BAA6B,EAC7B,OAAO,EACP,yBAAyB,GAC1B,MAAM,YAAY,CAAA;AACnB,OAAO,EAAC,WAAW,EAAE,UAAU,EAAC,MAAM,aAAa,CAAA;AACnD,OAAO,EAAC,kBAAkB,EAAC,MAAM,iCAAiC,CAAA;AAClE,OAAO,EAAC,kBAAkB,EAAC,MAAM,uCAAuC,CAAA;AACxE,OAAO,EAAC,aAAa,EAAE,kBAAkB,EAAC,MAAM,iCAAiC,CAAA;AACjF,OAAO,EAAC,eAAe,EAAC,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAC,gBAAgB,EAAC,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAC,0BAA0B,EAAC,MAAM,+BAA+B,CAAA;AAExE,OAAO,EAAC,QAAQ,EAAa,MAAM,aAAa,CAAA;AAChD,OAAO,WAAW,MAAM,aAAa,CAAA;AACrC,OAAO,OAAgB,MAAM,aAAa,CAAA;AAE1C,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAA;AAEpC,oDAAoD;AACpD,kEAAkE;AAClE,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAS,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAA;AAElF,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAA8C,EAC9C,MAA0B;IAE1B,IAAI,KAAK,YAAY,eAAe,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,KAAK,EAAE,EAAE,CAAC;YAC1C,UAAU,CAAC,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QACnC,CAAC;IACH,CAAC;SAAM,IAAI,KAAK,YAAY,gBAAgB,EAAE,CAAC;QAC7C,WAAW;IACb,CAAC;SAAM,CAAC;QACN,OAAO,WAAW,CAAC,KAAK,CAAC;aACtB,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;YACd,OAAO,OAAO,CAAC,KAAK,CAAC,CAAA;QACvB,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE;YACpB,OAAO,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QACzC,CAAC,CAAC,CAAA;IACN,CAAC;AACH,CAAC;AAED,MAAM,WAAW,GAAG,KAAK,EAAE,KAAc,EAAE,MAA0B,EAAiB,EAAE;IACtF,6BAA6B;IAC7B,IAAI,QAAQ,GAAoB,gBAAgB,CAAA;IAChD,IAAI,6BAA6B,CAAC,KAAK,CAAC;QAAE,QAAQ,GAAG,kBAAkB,CAAA;IAEvE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,+CAA+C;QAC/C,MAAM,oBAAoB,CAAC,EAAC,MAAM,EAAE,YAAY,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAC,CAAC,CAAA;IAClH,CAAC;IACD,MAAM,kBAAkB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AAC3C,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAc,EACd,QAAqC;IAErC,IAAI,CAAC;QACH,IAAI,kBAAkB,EAAE,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YAC3C,WAAW,CAAC,yBAAyB,CAAC,CAAA;YACtC,OAAO,EAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAC,CAAA;QACvD,CAAC;QAED,oGAAoG;QACpG,MAAM,SAAS,GAAG,QAAQ,KAAK,kBAAkB,CAAA;QAEjD,IAAI,eAAsB,CAAA;QAC1B,IAAI,UAA8B,CAAA;QAClC,IAAI,MAAM,GAAG,KAAK,CAAA;QAElB,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,GAAG,IAAI,CAAA;YACb,eAAe,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YAC1C,UAAU,GAAG,KAAK,CAAC,KAAK,CAAA;YAExB;;;;;;eAMG;QACL,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClE,MAAM,GAAG,IAAI,CAAA;YACb,eAAe,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,CAAA;YAClC,UAAU,GAAG,eAAe,CAAC,KAAK,CAAA;QACpC,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,KAAK,CAAA;YACd,eAAe,GAAG,IAAI,KAAK,CAAC,eAAe,CAAC,CAAA;QAC9C,CAAC;QAED,MAAM,mBAAmB,GAAG,IAAI,WAAW,CAAC,UAAU,IAAI,EAAE,CAAC;aAC1D,KAAK,EAAE;aACP,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAClB,MAAM,QAAQ,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACrD,OAAO,UAAU,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAA;QAC1E,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAA;QACb,eAAe,CAAC,KAAK,GAAG,UAAU,eAAe,CAAC,OAAO,KAAK,mBAAmB,EAAE,CAAA;QAEnF,IAAI,eAAe,GAAG,KAAK,CAAA;QAC3B,MAAM,gBAAgB,CAAC;YACrB,GAAG,EAAE,uBAAuB;YAC5B,GAAG,kBAAkB;YACrB,IAAI,EAAE,KAAK,IAAI,EAAE;gBACf,eAAe,GAAG,IAAI,CAAA;YACxB,CAAC;SACF,CAAC,CAAA;QACF,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,WAAW,CAAC,8CAA8C,CAAC,CAAA;YAC3D,MAAM,GAAG,KAAK,CAAA;QAChB,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACX,iBAAiB,EAAE,CAAA;YACnB,IAAI,MAAM,GAAuB,MAAM,0BAA0B,EAAE,CAAA;YACnE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,yCAAyC;gBACzC,MAAM,GAAG,SAAS,CAAA;YACpB,CAAC;YACD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACpC,WAAW,CAAC,aAAa,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,sBAAsB,eAAe,CAAC,OAAO,EAAE,CAAC,CAAA;gBAC5G,MAAM,YAAY,GAAG,CAAC,KAAY,EAAE,EAAE;oBACpC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAA;oBACxB,KAAK,CAAC,SAAS,GAAG,SAAS,CAAA;oBAC3B,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;oBACrB,2EAA2E;oBAC3E,MAAM,EAAC,mBAAmB,EAAC,GAAG,QAAQ,CAAC,uBAAuB,EAAE,CAAA;oBAChE,MAAM,EAAC,YAAY,EAAC,GAAG,mBAAmB,IAAI,EAAE,CAAA;oBAChD,IAAI,YAAY,EAAE,CAAC;wBACjB,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAA;wBAC9D,MAAM,SAAS,GAAG,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAA;wBACxE,KAAK,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAC,UAAU,EAAE,SAAS,EAAC,CAAC,CAAA;oBACtD,CAAC;gBACH,CAAC,CAAA;gBACD,MAAM,YAAY,GAAG,CAAC,KAAc,EAAE,EAAE;oBACtC,IAAI,KAAK,EAAE,CAAC;wBACV,MAAM,CAAC,KAAK,CAAC,CAAA;oBACf,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,eAAe,CAAC,CAAA;oBAC1B,CAAC;gBACH,CAAC,CAAA;gBACD,6DAA6D;gBAC7D,aAAa;gBACb,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,YAAY,EAAE,YAAY,CAAC,CAAA;YAC7D,CAAC,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,EAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAC,CAAA;QAC5D,qDAAqD;IACvD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,WAAW,CAAC,+BAA+B,GAAG,EAAE,CAAC,CAAA;QACjD,OAAO,EAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAC,CAAA;IACvD,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,EACtC,eAAe,EACf,WAAW,EACX,eAAe,GAKhB;IACC,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC;QACvD,CAAC,CAAC,eAAe;QACjB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC,CAAA;IAE/C,MAAM,kBAAkB,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,EAAC,UAAU,EAAC,EAAE,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAE3G,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;QACrC,4IAA4I;QAC5I,OAAO,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAA;IAC/G,CAAC;IAED,8EAA8E;IAC9E,OAAO,eAAe,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAA;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,2CAA2C,CAAC,MAAyB;IACzF,8DAA8D;IAE9D,8DAA8D;IAC9D,MAAM,wBAAwB,GAAY,OAAe,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAA;IACtG,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAA;IAChE,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,GAAG,CACvC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE;QAC5C,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAClD,OAAO,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,EAAC,CAAA;IAC5E,CAAC,CAAC,CACH,CAAA;IACD,iBAAiB,EAAE,CAAA;IACnB,6DAA6D;IAC7D,aAAa;IACb,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACjC,8DAA8D;QAC9D,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAU,EAAE,EAAE;YAClC,8DAA8D;YAC9D,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,UAAe,EAAE,EAAE;gBAC3C,UAAU,CAAC,IAAI,GAAG,uBAAuB,CAAC,EAAC,eAAe,EAAE,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,eAAe,EAAC,CAAC,CAAA;YAC7G,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QACF,IAAI,CAAC;YACH,MAAM,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;YACvC,qDAAqD;QACvD,CAAC;QAAC,OAAO,aAAa,EAAE,CAAC;YACvB,WAAW,CAAC,sFAAsF,aAAa,EAAE,CAAC,CAAA;QACpH,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,8DAA8D;AAC9D,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAU,EAAE,MAAyB;IAC5E,MAAM,UAAU,GAAG,QAAQ,CAAC,oBAAoB,EAAE,CAAA;IAClD,MAAM,EAAC,mBAAmB,EAAC,GAAG,QAAQ,CAAC,uBAAuB,EAAE,CAAA;IAChE,MAAM,EAAC,YAAY,EAAC,GAAG,mBAAmB,IAAI,EAAE,CAAA;IAEhD,MAAM,EAAC,cAAc,EAAE,SAAS,EAAE,GAAG,kBAAkB,EAAC,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,yBAAyB,EAAE,EAAE,CAAC,CAAA;IAEnH,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAEpD,MAAM,WAAW,GAAG;QAClB,OAAO,EAAE,YAAY;QACrB,GAAG,SAAS;QACZ,GAAG,UAAU;QACb,GAAG,WAAW;QACd,UAAU,EAAE,kBAAkB;KAC/B,CAAA;IAED,MAAM,OAAO,GAAG,EAA6B,CAAA;IAC7C,MAAM,WAAW,GAAG,EAA6B,CAAA;IACjD,MAAM,eAAe,GAAG,EAA6B,CAAA;IACrD,MAAM,QAAQ,GAAG,EAA6B,CAAA;IAC9C,MAAM,OAAO,GAAG,CAAC,SAAS,EAAE,sBAAsB,EAAE,YAAY,EAAE,cAAc,CAAC,CAAA;IACjF,MAAM,WAAW,GAAG,CAAC,SAAS,CAAC,CAAA;IAC/B,MAAM,eAAe,GAAG,CAAC,aAAa,EAAE,cAAc,EAAE,OAAO,CAAC,CAAA;IAEhE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QACnD,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACtB,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/D,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QAC1B,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC;YACrD,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QAC9B,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACvB,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,kCAAkC;IAClC,MAAM,eAAe,GAAG;QACtB,aAAa,EAAE,OAAO;QACtB,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,eAAe;QAC5B,IAAI,EAAE,QAAQ;KACf,CAAA;IACD,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE;QAC5D,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,iBAAiB;IACxB,6DAA6D;IAC7D,aAAa;IACb,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;QACxB,OAAM;IACR,CAAC;IACD,6DAA6D;IAC7D,aAAa;IACb,OAAO,CAAC,KAAK,CAAC;QACZ,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,eAAe;QAC3B,iBAAiB,EAAE,KAAK;QACxB,gBAAgB,EAAE,KAAK;QACvB,oBAAoB,EAAE,CAAC,YAAY,CAAC;QACpC,SAAS,EAAE;YACT,MAAM,EAAE,mDAAmD;YAC3D,QAAQ,EAAE,4DAA4D;SACvE;QACD,oEAAoE;QACpE,0EAA0E;QAC1E,oEAAoE;QACpE,+BAA+B;QAC/B,WAAW,EAAE,IAAI;KAClB,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import {CommandExitMode, reportAnalyticsEvent} from './analytics.js'\nimport * as path from './path.js'\nimport {fanoutHooks} from './plugins.js'\nimport * as metadata from './metadata.js'\nimport {\n AbortSilentError,\n CancelExecution,\n errorMapper,\n shouldReportErrorAsUnexpected,\n handler,\n cleanSingleStackTracePath,\n} from './error.js'\nimport {outputDebug, outputInfo} from './output.js'\nimport {getEnvironmentData} from '../../private/node/analytics.js'\nimport {isLocalEnvironment} from '../../private/node/context/service.js'\nimport {bugsnagApiKey, reportingRateLimit} from '../../private/node/constants.js'\nimport {CLI_KIT_VERSION} from '../common/version.js'\nimport {runWithRateLimit} from '../../private/node/conf-store.js'\nimport {getLastSeenUserIdAfterAuth} from '../../private/node/session.js'\n\nimport {settings, Interfaces} from '@oclif/core'\nimport StackTracey from 'stacktracey'\nimport Bugsnag, {Event} from '@bugsnag/js'\n\nimport {realpath} from 'fs/promises'\n\n// Allowed slice names for error analytics grouping.\n// Hardcoded list per product slices to keep analytics consistent.\nconst ALLOWED_SLICE_NAMES = new Set<string>(['app', 'theme', 'hydrogen', 'store'])\n\nexport async function errorHandler(\n error: Error & {exitCode?: number | undefined},\n config?: Interfaces.Config,\n): Promise<void> {\n if (error instanceof CancelExecution) {\n if (error.message && error.message !== '') {\n outputInfo(`✨ ${error.message}`)\n }\n } else if (error instanceof AbortSilentError) {\n /* empty */\n } else {\n return errorMapper(error)\n .then((error) => {\n return handler(error)\n })\n .then((mappedError) => {\n return reportError(mappedError, config)\n })\n }\n}\n\nconst reportError = async (error: unknown, config?: Interfaces.Config): Promise<void> => {\n // categorise the error first\n let exitMode: CommandExitMode = 'expected_error'\n if (shouldReportErrorAsUnexpected(error)) exitMode = 'unexpected_error'\n\n if (config !== undefined) {\n // Log an analytics event when there's an error\n await reportAnalyticsEvent({config, errorMessage: error instanceof Error ? error.message : undefined, exitMode})\n }\n await sendErrorToBugsnag(error, exitMode)\n}\n\n/**\n * Sends an error to Bugsnag. This is configured automatically for uncaught errors from CLI commands, but can also be used to manually record an error.\n *\n * @returns the reported error (this may have been tweaked for better reporting), and a bool to indicate if the error was actually submitted or not\n */\nexport async function sendErrorToBugsnag(\n error: unknown,\n exitMode: Omit<CommandExitMode, 'ok'>,\n): Promise<{reported: false; error: unknown; unhandled: unknown} | {error: Error; reported: true; unhandled: boolean}> {\n try {\n if (isLocalEnvironment() || settings.debug) {\n outputDebug(`Skipping Bugsnag report`)\n return {reported: false, error, unhandled: undefined}\n }\n\n // If the error was unexpected, we flag it as \"unhandled\" in Bugsnag. This is a helpful distinction.\n const unhandled = exitMode === 'unexpected_error'\n\n let reportableError: Error\n let stacktrace: string | undefined\n let report = false\n\n if (error instanceof Error) {\n report = true\n reportableError = new Error(error.message)\n stacktrace = error.stack\n\n /**\n * Some errors that reach this point have an empty string. For example:\n * https://app.bugsnag.com/shopify/cli/errors/62cd5d31fd5040000814086c?filters[event.since]=30d&filters[error.status]=new&filters[release.seen_in]=3.1.0\n *\n * Because at this point we have neither the error message nor a stack trace reporting them\n * to Bugsnag is pointless and adds noise.\n */\n } else if (typeof error === 'string' && error.trim().length !== 0) {\n report = true\n reportableError = new Error(error)\n stacktrace = reportableError.stack\n } else {\n report = false\n reportableError = new Error('Unknown error')\n }\n\n const formattedStacktrace = new StackTracey(stacktrace ?? '')\n .clean()\n .items.map((item) => {\n const filePath = cleanSingleStackTracePath(item.file)\n return ` at ${item.callee} (${filePath}:${item.line}:${item.column})`\n })\n .join('\\n')\n reportableError.stack = `Error: ${reportableError.message}\\n${formattedStacktrace}`\n\n let withinRateLimit = false\n await runWithRateLimit({\n key: 'send-error-to-bugsnag',\n ...reportingRateLimit,\n task: async () => {\n withinRateLimit = true\n },\n })\n if (!withinRateLimit) {\n outputDebug(`Skipping Bugsnag report due to rate limiting`)\n report = false\n }\n\n if (report) {\n initializeBugsnag()\n let userId: string | undefined = await getLastSeenUserIdAfterAuth()\n if (userId === 'unknown') {\n // Observe will use the IP when undefined\n userId = undefined\n }\n await new Promise((resolve, reject) => {\n outputDebug(`Reporting ${unhandled ? 'unhandled' : 'handled'} error to Bugsnag: ${reportableError.message}`)\n const eventHandler = (event: Event) => {\n event.severity = 'error'\n event.unhandled = unhandled\n event.setUser(userId)\n // Attach command metadata so we know which CLI command triggered the error\n const {commandStartOptions} = metadata.getAllSensitiveMetadata()\n const {startCommand} = commandStartOptions ?? {}\n if (startCommand) {\n const firstWord = startCommand.trim().split(/\\s+/)[0] ?? 'cli'\n const sliceName = ALLOWED_SLICE_NAMES.has(firstWord) ? firstWord : 'cli'\n event.addMetadata('custom', {slice_name: sliceName})\n }\n }\n const errorHandler = (error: unknown) => {\n if (error) {\n reject(error)\n } else {\n resolve(reportableError)\n }\n }\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n Bugsnag.notify(reportableError, eventHandler, errorHandler)\n })\n }\n return {error: reportableError, reported: report, unhandled}\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (err) {\n outputDebug(`Error reporting to Bugsnag: ${err}`)\n return {error, reported: false, unhandled: undefined}\n }\n}\n\n/**\n * If the given file path is within a node_modules folder, remove prefix up\n * to and including the node_modules folder.\n *\n * This gives us very consistent paths for errors generated by the CLI.\n */\nexport function cleanStackFrameFilePath({\n currentFilePath,\n projectRoot,\n pluginLocations,\n}: {\n currentFilePath: string\n projectRoot: string\n pluginLocations: {name: string; pluginPath: string}[]\n}): string {\n const fullLocation = path.isAbsolutePath(currentFilePath)\n ? currentFilePath\n : path.joinPath(projectRoot, currentFilePath)\n\n const matchingPluginPath = pluginLocations.filter(({pluginPath}) => fullLocation.startsWith(pluginPath))[0]\n\n if (matchingPluginPath !== undefined) {\n // the plugin name (e.g. @shopify/cli-kit), plus the relative path of the error line from within the plugin's code (e.g. dist/something.js )\n return path.joinPath(matchingPluginPath.name, path.relativePath(matchingPluginPath.pluginPath, fullLocation))\n }\n\n // strip prefix up to node_modules folder, so we can normalize error reporting\n return currentFilePath.replace(/.*node_modules\\//, '')\n}\n\n/**\n * Register a Bugsnag error listener to clean up stack traces for errors within plugin code.\n *\n */\nexport async function registerCleanBugsnagErrorsFromWithinPlugins(config: Interfaces.Config): Promise<void> {\n // Bugsnag have their own plug-ins that use this private field\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const bugsnagConfigProjectRoot: string = (Bugsnag as any)?._client?._config?.projectRoot ?? path.cwd()\n const projectRoot = path.normalizePath(bugsnagConfigProjectRoot)\n const pluginLocations = await Promise.all(\n [...config.plugins].map(async ([_, plugin]) => {\n const followSymlinks = await realpath(plugin.root)\n return {name: plugin.name, pluginPath: path.normalizePath(followSymlinks)}\n }),\n )\n initializeBugsnag()\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n Bugsnag.addOnError(async (event) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event.errors.forEach((error: any) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error.stacktrace.forEach((stackFrame: any) => {\n stackFrame.file = cleanStackFrameFilePath({currentFilePath: stackFrame.file, projectRoot, pluginLocations})\n })\n })\n try {\n await addBugsnagMetadata(event, config)\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (metadataError) {\n outputDebug(`There was an error adding metadata to the Bugsnag report; Ignoring and carrying on ${metadataError}`)\n }\n })\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function addBugsnagMetadata(event: any, config: Interfaces.Config): Promise<void> {\n const publicData = metadata.getAllPublicMetadata()\n const {commandStartOptions} = metadata.getAllSensitiveMetadata()\n const {startCommand} = commandStartOptions ?? {}\n\n const {'@shopify/app': appPublic, ...otherPluginsPublic} = await fanoutHooks(config, 'public_command_metadata', {})\n\n const environment = await getEnvironmentData(config)\n\n const allMetadata = {\n command: startCommand,\n ...appPublic,\n ...publicData,\n ...environment,\n pluginData: otherPluginsPublic,\n }\n\n const appData = {} as Record<string, unknown>\n const commandData = {} as Record<string, unknown>\n const environmentData = {} as Record<string, unknown>\n const miscData = {} as Record<string, unknown>\n const appKeys = ['api_key', 'business_platform_id', 'partner_id', 'project_type']\n const commandKeys = ['command']\n const environmentKeys = ['cli_version', 'node_version', 'uname']\n\n Object.entries(allMetadata).forEach(([key, value]) => {\n if (key.startsWith('app_') || appKeys.includes(key)) {\n appData[key] = value\n } else if (key.startsWith('cmd_') || commandKeys.includes(key)) {\n commandData[key] = value\n } else if (key.startsWith('env_') || environmentKeys) {\n environmentData[key] = value\n } else {\n miscData[key] = value\n }\n })\n\n // app, command, environment, misc\n const bugsnagMetadata = {\n 'Shopify App': appData,\n Command: commandData,\n Environment: environmentData,\n Misc: miscData,\n }\n Object.entries(bugsnagMetadata).forEach(([section, values]) => {\n event.addMetadata(section, values)\n })\n}\n\nfunction initializeBugsnag() {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n if (Bugsnag.isStarted()) {\n return\n }\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n Bugsnag.start({\n appType: 'node',\n apiKey: bugsnagApiKey,\n logger: null,\n appVersion: CLI_KIT_VERSION,\n autoTrackSessions: false,\n autoDetectErrors: false,\n enabledReleaseStages: ['production'],\n endpoints: {\n notify: 'https://error-analytics-production.shopifysvc.com',\n sessions: 'https://error-analytics-sessions-production.shopifysvc.com',\n },\n // Set the project root to `null` to prevent the default behavior of\n // Bugsnag which is to set it to the cwd. That is unhelpful for us because\n // the cwd can be anywhere in the user's filesystem, not necessarily\n // related to the CLI codebase.\n projectRoot: null,\n })\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AlertCustomSection } from './ui.js';
|
|
2
|
-
import { OutputMessage } from '
|
|
2
|
+
import { OutputMessage } from './output.js';
|
|
3
3
|
import { InlineToken, TokenItem } from '../../private/node/ui/components/TokenizedText.js';
|
|
4
4
|
export { ExtendableError } from 'ts-error';
|
|
5
5
|
export declare enum FatalErrorType {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { renderFatalError } from './ui.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { normalizePath } from './path.js';
|
|
3
|
+
import { stringifyMessage, TokenizedString } from './output.js';
|
|
4
4
|
import { tokenItemToString } from '../../private/node/ui/components/TokenizedText.js';
|
|
5
5
|
import { Errors } from '@oclif/core';
|
|
6
6
|
export { ExtendableError } from 'ts-error';
|