diff --git a/messages/retrieve.start.md b/messages/retrieve.start.md index c1484904..12fa5e27 100644 --- a/messages/retrieve.start.md +++ b/messages/retrieve.start.md @@ -145,18 +145,6 @@ Extract all files from the retrieved zip file. File name to use for the retrieved zip file. -# spinner.start - -Preparing retrieve request - -# spinner.sending - -Sending request to org - -# spinner.polling - -Waiting for the org to respond - # error.Conflicts There are changes in your local files that conflict with the org changes you're trying to retrieve. diff --git a/package.json b/package.json index 99b853ed..65b5f22b 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "bugs": "https://github.com/forcedotcom/cli/issues", "dependencies": { "@oclif/core": "^4.0.17", + "@oclif/multi-stage-output": "^0.3.0", "@salesforce/apex-node": "^8.1.3", "@salesforce/core": "^8.4.0", "@salesforce/kit": "^3.2.1", diff --git a/src/commands/project/delete/source.ts b/src/commands/project/delete/source.ts index 166de79f..dfdcd5d3 100644 --- a/src/commands/project/delete/source.ts +++ b/src/commands/project/delete/source.ts @@ -33,6 +33,7 @@ import { requiredOrgFlagWithDeprecations, SfCommand, } from '@salesforce/sf-plugins-core'; +import { DeployStages } from '../../../utils/deployStages.js'; import { writeConflictTable } from '../../../utils/conflicts.js'; import { isNonDecomposedCustomLabel, isNonDecomposedCustomLabelsOrCustomLabel } from '../../../utils/metadataTypes.js'; import { getFileResponseSuccessProps, tableHeader } from '../../../utils/output.js'; @@ -41,7 +42,6 @@ import { getPackageDirs, getSourceApiVersion } from '../../../utils/project.js'; import { resolveApi, validateTests } from '../../../utils/deploy.js'; import { DeployResultFormatter } from '../../../formatters/deployResultFormatter.js'; import { DeleteResultFormatter } from '../../../formatters/deleteResultFormatter.js'; -import { DeployProgress } from '../../../utils/progressBar.js'; import { DeployCache } from '../../../utils/deployCache.js'; import { testLevelFlag, testsFlag } from '../../../utils/flags.js'; const testFlags = 'Test'; @@ -244,8 +244,14 @@ export class Source extends SfCommand { // fire predeploy event for the delete await Lifecycle.getInstance().emit('predeploy', this.components); + + const stages = new DeployStages({ + title: 'Deleting Metadata', + jsonEnabled: this.jsonEnabled(), + }); + const isRest = (await resolveApi()) === API['REST']; - this.log(`*** Deleting with ${isRest ? 'REST' : 'SOAP'} API ***`); + stages.update({ message: `Deleting with ${isRest ? 'REST' : 'SOAP'} API` }); const deploy = await this.componentSet.deploy({ usernameOrConnection: this.org.getUsername() as string, @@ -257,7 +263,7 @@ export class Source extends SfCommand { }, }); - new DeployProgress(deploy, this.jsonEnabled()).start(); + stages.start({ deploy, username: this.org.getUsername() }); this.deployResult = await deploy.pollStatus({ timeout: this.flags.wait }); if (!deploy.id) { throw new SfError('The deploy id is not available.'); diff --git a/src/commands/project/deploy/report.ts b/src/commands/project/deploy/report.ts index 283205fc..64f3c36b 100644 --- a/src/commands/project/deploy/report.ts +++ b/src/commands/project/deploy/report.ts @@ -8,8 +8,8 @@ import { Messages, Org, SfProject } from '@salesforce/core'; import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; import { ComponentSet, DeployResult, MetadataApiDeploy, RequestStatus } from '@salesforce/source-deploy-retrieve'; +import { DeployStages } from '../../../utils/deployStages.js'; import { buildComponentSet } from '../../../utils/deploy.js'; -import { DeployProgress } from '../../../utils/progressBar.js'; import { DeployCache } from '../../../utils/deployCache.js'; import { DeployReportResultFormatter } from '../../../formatters/deployReportResultFormatter.js'; import { API, DeployResultJson } from '../../../utils/types.js'; @@ -70,7 +70,7 @@ export default class DeployMetadataReport extends SfCommand { const jobId = cache.resolveLatest(flags['use-most-recent'], flags['job-id'], false); const deployOpts = cache.maybeGet(jobId); - const wait = flags['wait']; + const { wait } = flags; const org = deployOpts?.['target-org'] ? await Org.create({ aliasOrUsername: deployOpts['target-org'] }) : flags['target-org']; @@ -124,7 +124,10 @@ export default class DeployMetadataReport extends SfCommand { if (wait) { // poll for deploy results try { - new DeployProgress(mdapiDeploy, this.jsonEnabled()).start(); + new DeployStages({ + title: 'Deploying Metadata', + jsonEnabled: this.jsonEnabled(), + }).start({ deploy: mdapiDeploy, username: org.getUsername() }); result = await mdapiDeploy.pollStatus(500, wait.seconds); } catch (error) { if (error instanceof Error && error.message.includes('The client has timed out')) { diff --git a/src/commands/project/deploy/resume.ts b/src/commands/project/deploy/resume.ts index 3dbfe7c0..95d25aea 100644 --- a/src/commands/project/deploy/resume.ts +++ b/src/commands/project/deploy/resume.ts @@ -5,13 +5,12 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import ansis from 'ansis'; import { EnvironmentVariable, Messages, Org, SfError } from '@salesforce/core'; import { SfCommand, toHelpSection, Flags } from '@salesforce/sf-plugins-core'; import { DeployResult, MetadataApiDeploy } from '@salesforce/source-deploy-retrieve'; import { Duration } from '@salesforce/kit'; +import { DeployStages } from '../../../utils/deployStages.js'; import { DeployResultFormatter } from '../../../formatters/deployResultFormatter.js'; -import { DeployProgress } from '../../../utils/progressBar.js'; import { API, DeployResultJson } from '../../../utils/types.js'; import { buildComponentSet, determineExitCode, executeDeploy, isNotResumable } from '../../../utils/deploy.js'; import { DeployCache } from '../../../utils/deployCache.js'; @@ -124,8 +123,11 @@ export default class DeployMetadataResume extends SfCommand { jobId ); - this.log(`Deploy ID: ${ansis.bold(jobId)}`); - new DeployProgress(deploy, this.jsonEnabled()).start(); + new DeployStages({ + title: 'Resuming Deploy', + jsonEnabled: this.jsonEnabled(), + }).start({ deploy, username: deployOpts['target-org'] }); + result = await deploy.pollStatus(500, wait.seconds); if (!deploy.id) { diff --git a/src/commands/project/deploy/start.ts b/src/commands/project/deploy/start.ts index a9467978..b798d254 100644 --- a/src/commands/project/deploy/start.ts +++ b/src/commands/project/deploy/start.ts @@ -5,15 +5,15 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import ansis from 'ansis'; +import { MultiStageOutput } from '@oclif/multi-stage-output'; import { EnvironmentVariable, Lifecycle, Messages, OrgConfigProperties, SfError } from '@salesforce/core'; -import { DeployVersionData } from '@salesforce/source-deploy-retrieve'; +import { DeployVersionData, MetadataApiDeployStatus } from '@salesforce/source-deploy-retrieve'; import { Duration } from '@salesforce/kit'; import { SfCommand, toHelpSection, Flags } from '@salesforce/sf-plugins-core'; -import { SourceConflictError } from '@salesforce/source-tracking'; +import { SourceConflictError, SourceMemberPollingEvent } from '@salesforce/source-tracking'; +import { DeployStages } from '../../../utils/deployStages.js'; import { AsyncDeployResultFormatter } from '../../../formatters/asyncDeployResultFormatter.js'; import { DeployResultFormatter } from '../../../formatters/deployResultFormatter.js'; -import { DeployProgress } from '../../../utils/progressBar.js'; import { DeployResultJson, TestLevel } from '../../../utils/types.js'; import { executeDeploy, resolveApi, validateTests, determineExitCode } from '../../../utils/deploy.js'; import { DeployCache } from '../../../utils/deployCache.js'; @@ -176,6 +176,16 @@ export default class DeployMetadata extends SfCommand { public static errorCodes = toHelpSection('ERROR CODES', DEPLOY_STATUS_CODES_DESCRIPTIONS); + protected ms!: MultiStageOutput<{ + mdapiDeploy: MetadataApiDeployStatus; + sourceMemberPolling: SourceMemberPollingEvent; + status: string; + apiData: DeployVersionData; + targetOrg: string; + }>; + + protected stages!: DeployStages; + public async run(): Promise { const { flags } = await this.parse(DeployMetadata); const project = await getOptionalProject(); @@ -197,23 +207,30 @@ export default class DeployMetadata extends SfCommand { const api = await resolveApi(this.configAggregator); const username = flags['target-org'].getUsername(); - const action = flags['dry-run'] ? 'Deploying (dry-run)' : 'Deploying'; + const title = flags['dry-run'] ? 'Deploying Metadata (dry-run)' : 'Deploying Metadata'; - // eslint-disable-next-line @typescript-eslint/require-await - Lifecycle.getInstance().on('apiVersionDeploy', async (apiData: DeployVersionData) => { - this.log( - messages.getMessage('apiVersionMsgDetailed', [ - action, - // technically manifestVersion can be undefined, but only on raw mdapi deployments. - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - flags['metadata-dir'] ? '' : `v${apiData.manifestVersion}`, - username, - apiData.apiVersion, - apiData.webService, - ]) - ); + this.stages = new DeployStages({ + title, + jsonEnabled: this.jsonEnabled(), }); + const lifecycle = Lifecycle.getInstance(); + lifecycle.on('apiVersionDeploy', async (apiData: DeployVersionData) => + Promise.resolve( + this.stages.update({ + message: messages.getMessage('apiVersionMsgDetailed', [ + flags['dry-run'] ? 'Deploying (dry-run)' : 'Deploying', + // technically manifestVersion can be undefined, but only on raw mdapi deployments. + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + flags['metadata-dir'] ? '' : `v${apiData.manifestVersion}`, + username, + apiData.apiVersion, + apiData.webService, + ]), + }) + ) + ); + const { deploy } = await executeDeploy( { ...flags, @@ -224,6 +241,7 @@ export default class DeployMetadata extends SfCommand { ); if (!deploy) { + this.stages.stop(); this.log('No changes to deploy'); return { status: 'Nothing to deploy', files: [] }; } @@ -231,9 +249,12 @@ export default class DeployMetadata extends SfCommand { if (!deploy.id) { throw new SfError('The deploy id is not available.'); } - this.log(`Deploy ID: ${ansis.bold(deploy.id)}`); + + this.stages.start({ username, deploy }); if (flags.async) { + this.stages.done({ status: 'Queued', username }); + this.stages.stop(); if (flags['coverage-formatters']) { this.warn(messages.getMessage('asyncCoverageJunitWarning')); } @@ -242,8 +263,6 @@ export default class DeployMetadata extends SfCommand { return asyncFormatter.getJson(); } - new DeployProgress(deploy, this.jsonEnabled()).start(); - const result = await deploy.pollStatus({ timeout: flags.wait }); process.exitCode = determineExitCode(result); const formatter = new DeployResultFormatter(result, flags); @@ -261,6 +280,8 @@ export default class DeployMetadata extends SfCommand { protected catch(error: Error | SfError): Promise { if (error instanceof SourceConflictError && error.data) { if (!this.jsonEnabled()) { + this.stages.update({ status: 'Failed' }); + this.stages.stop(error); writeConflictTable(error.data); // set the message and add plugin-specific actions return super.catch({ diff --git a/src/commands/project/deploy/validate.ts b/src/commands/project/deploy/validate.ts index 2b6d7ad3..a66bde0c 100644 --- a/src/commands/project/deploy/validate.ts +++ b/src/commands/project/deploy/validate.ts @@ -11,9 +11,9 @@ import { EnvironmentVariable, Lifecycle, Messages, OrgConfigProperties, SfError import { CodeCoverageWarnings, DeployVersionData, RequestStatus } from '@salesforce/source-deploy-retrieve'; import { Duration, ensureArray } from '@salesforce/kit'; import { SfCommand, toHelpSection, Flags } from '@salesforce/sf-plugins-core'; +import { DeployStages } from '../../../utils/deployStages.js'; import { AsyncDeployResultFormatter } from '../../../formatters/asyncDeployResultFormatter.js'; import { DeployResultFormatter } from '../../../formatters/deployResultFormatter.js'; -import { DeployProgress } from '../../../utils/progressBar.js'; import { DeployResultJson, TestLevel } from '../../../utils/types.js'; import { executeDeploy, resolveApi, determineExitCode, validateTests } from '../../../utils/deploy.js'; import { DEPLOY_STATUS_CODES_DESCRIPTIONS } from '../../../utils/errorCodes.js'; @@ -195,15 +195,18 @@ export default class DeployMetadataValidate extends SfCommand if (!deploy.id) { throw new SfError('The deploy id is not available.'); } - this.log(`Deploy ID: ${ansis.bold(deploy.id)}`); if (flags.async) { + this.log(`Deploy ID: ${ansis.bold(deploy.id)}`); const asyncFormatter = new AsyncDeployResultFormatter(deploy.id); if (!this.jsonEnabled()) asyncFormatter.display(); return asyncFormatter.getJson(); } - new DeployProgress(deploy, this.jsonEnabled()).start(); + new DeployStages({ + title: 'Validating Deployment', + jsonEnabled: this.jsonEnabled(), + }).start({ deploy, username }); const result = await deploy.pollStatus(500, flags.wait?.seconds); process.exitCode = determineExitCode(result); diff --git a/src/commands/project/retrieve/start.ts b/src/commands/project/retrieve/start.ts index 9fb7df8b..47018a1d 100644 --- a/src/commands/project/retrieve/start.ts +++ b/src/commands/project/retrieve/start.ts @@ -9,6 +9,7 @@ import { rm } from 'node:fs/promises'; import { dirname, join, resolve } from 'node:path'; import * as fs from 'node:fs'; +import { MultiStageOutput } from '@oclif/multi-stage-output'; import { EnvironmentVariable, Lifecycle, Messages, OrgConfigProperties, SfError, SfProject } from '@salesforce/core'; import { RetrieveResult, @@ -147,6 +148,10 @@ export default class RetrieveMetadata extends SfCommand { ); protected retrieveResult!: RetrieveResult; + protected ms!: MultiStageOutput<{ + status: string; + apiData: RetrieveVersionData; + }>; // eslint-disable-next-line complexity public async run(): Promise { @@ -161,8 +166,6 @@ export default class RetrieveMetadata extends SfCommand { const format = flags['target-metadata-dir'] ? 'metadata' : 'source'; const zipFileName = flags['zip-file-name'] ?? DEFAULT_ZIP_FILE_NAME; - this.spinner.start(messages.getMessage('spinner.start')); - const { componentSetFromNonDeletes, fileResponsesFromDelete = [] } = await buildRetrieveAndDeleteTargets( flags, format @@ -177,42 +180,76 @@ export default class RetrieveMetadata extends SfCommand { }); } } + + const stages = ['Preparing retrieve request', 'Sending request to org', 'Waiting for the org to respond', 'Done']; + this.ms = new MultiStageOutput<{ + status: string; + apiData: RetrieveVersionData; + }>({ + stages, + title: 'Retrieving Metadata', + jsonEnabled: this.jsonEnabled(), + preStagesBlock: [ + { + type: 'message', + get: (data) => + data?.apiData && + messages.getMessage('apiVersionMsgDetailed', [ + 'Retrieving', + `v${data.apiData.manifestVersion}`, + flags['target-org'].getUsername(), + data.apiData.apiVersion, + ]), + }, + ], + postStagesBlock: [ + { + label: 'Status', + get: (data) => data?.status, + bold: true, + type: 'dynamic-key-value', + }, + ], + }); + + this.ms.goto('Preparing retrieve request'); + const retrieveOpts = await buildRetrieveOptions(flags, format, zipFileName, resolvedTargetDir); - this.spinner.status = messages.getMessage('spinner.sending'); + this.ms.goto('Sending request to org'); this.retrieveResult = new RetrieveResult({} as MetadataApiRetrieveStatus, componentSetFromNonDeletes); if (componentSetFromNonDeletes.size !== 0 || retrieveOpts.packageOptions?.length) { - // eslint-disable-next-line @typescript-eslint/require-await - Lifecycle.getInstance().on('apiVersionRetrieve', async (apiData: RetrieveVersionData) => { - this.log( - messages.getMessage('apiVersionMsgDetailed', [ - 'Retrieving', - `v${apiData.manifestVersion}`, - flags['target-org'].getUsername(), - apiData.apiVersion, - ]) - ); - }); + Lifecycle.getInstance().on('apiVersionRetrieve', async (apiData: RetrieveVersionData) => + Promise.resolve(this.ms.updateData({ apiData })) + ); const retrieve = await componentSetFromNonDeletes.retrieve(retrieveOpts); - this.spinner.status = messages.getMessage('spinner.polling'); + this.ms.goto('Waiting for the org to respond', { status: 'Pending' }); retrieve.onUpdate((data) => { - this.spinner.status = mdTransferMessages.getMessage(data.status); + this.ms.goto('Waiting for the org to respond', { status: mdTransferMessages.getMessage(data.status) }); + }); + retrieve.onFinish((data) => { + this.ms.goto('Done', { status: mdTransferMessages.getMessage(data.response.status) }); + }); + retrieve.onCancel((data) => { + this.ms.updateData({ status: mdTransferMessages.getMessage(data?.status ?? 'Canceled') }); + this.ms.stop(new Error('Retrieve canceled')); }); - // any thing else should stop the progress bar - retrieve.onFinish((data) => this.spinner.stop(mdTransferMessages.getMessage(data.response.status))); - retrieve.onCancel((data) => this.spinner.stop(mdTransferMessages.getMessage(data?.status ?? 'Canceled'))); retrieve.onError((error: Error) => { - this.spinner.stop(error.name); + if (error.message.includes('client has timed out')) { + this.ms.updateData({ status: 'Client Timeout' }); + } + + this.ms.stop(error); throw error; }); this.retrieveResult = await retrieve.pollStatus(500, flags.wait.seconds); } - this.spinner.stop(); + this.ms.stop(); // flags['output-dir'] will set resolvedTargetDir var, so this check is redundant, but allows for nice typings in the moveResultsForRetrieveTargetDir method if (flags['output-dir'] && resolvedTargetDir) { @@ -263,6 +300,8 @@ export default class RetrieveMetadata extends SfCommand { protected catch(error: Error | SfError): Promise { if (!this.jsonEnabled() && error instanceof SourceConflictError && error.data) { + this.ms.updateData({ status: 'Failed' }); + this.ms.stop(error); writeConflictTable(error.data); // set the message and add plugin-specific actions return super.catch({ @@ -270,6 +309,8 @@ export default class RetrieveMetadata extends SfCommand { message: messages.getMessage('error.Conflicts'), actions: messages.getMessages('error.Conflicts.Actions'), }); + } else { + this.ms.stop(error); } return super.catch(error); diff --git a/src/utils/deployStages.ts b/src/utils/deployStages.ts new file mode 100644 index 00000000..10f21f23 --- /dev/null +++ b/src/utils/deployStages.ts @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2024, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import { MultiStageOutput } from '@oclif/multi-stage-output'; +import { Lifecycle, Messages } from '@salesforce/core'; +import { MetadataApiDeploy, MetadataApiDeployStatus, RequestStatus } from '@salesforce/source-deploy-retrieve'; +import { SourceMemberPollingEvent } from '@salesforce/source-tracking'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const mdTransferMessages = Messages.loadMessages('@salesforce/plugin-deploy-retrieve', 'metadata.transfer'); + +type Options = { + title: string; + jsonEnabled: boolean; +}; + +type Data = { + mdapiDeploy: MetadataApiDeployStatus; + sourceMemberPolling: SourceMemberPollingEvent; + status: string; + message: string; + username: string; + id: string; +}; + +function round(value: number, precision: number): number { + const multiplier = Math.pow(10, precision || 0); + return Math.round(value * multiplier) / multiplier; +} + +function formatProgress(current: number, total: number): string { + return `${current}/${total} (${round((current / total) * 100, 0)}%)`; +} + +export class DeployStages { + private ms: MultiStageOutput; + + public constructor({ title, jsonEnabled }: Options) { + this.ms = new MultiStageOutput({ + title, + stages: [ + 'Preparing', + 'Waiting for the org to respond', + 'Deploying Metadata', + 'Running Tests', + 'Updating Source Tracking', + 'Done', + ], + jsonEnabled, + preStagesBlock: [ + { + type: 'message', + get: (data): string | undefined => data?.message, + }, + ], + postStagesBlock: [ + { + label: 'Status', + get: (data): string | undefined => data?.status, + bold: true, + type: 'dynamic-key-value', + }, + { + label: 'Deploy ID', + get: (data): string | undefined => data?.id, + type: 'static-key-value', + }, + { + label: 'Target Org', + get: (data): string | undefined => data?.username, + type: 'static-key-value', + }, + ], + stageSpecificBlock: [ + { + label: 'Components', + get: (data): string | undefined => + data?.mdapiDeploy?.numberComponentsTotal + ? formatProgress( + data?.mdapiDeploy?.numberComponentsDeployed ?? 0, + data?.mdapiDeploy?.numberComponentsTotal + ) + : undefined, + stage: 'Deploying Metadata', + type: 'dynamic-key-value', + }, + { + label: 'Tests', + get: (data): string | undefined => + data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestsCompleted + ? formatProgress(data?.mdapiDeploy?.numberTestsCompleted, data?.mdapiDeploy?.numberTestsTotal) + : undefined, + stage: 'Running Tests', + type: 'dynamic-key-value', + }, + { + label: 'Members', + get: (data): string | undefined => + data?.sourceMemberPolling && + formatProgress( + data.sourceMemberPolling.original - data.sourceMemberPolling.remaining, + data.sourceMemberPolling.original + ), + stage: 'Updating Source Tracking', + type: 'dynamic-key-value', + }, + ], + }); + } + + public start({ username, deploy }: { username?: string | undefined; deploy: MetadataApiDeploy }): void { + const lifecycle = Lifecycle.getInstance(); + + this.ms.goto('Preparing', { username, id: deploy.id }); + + // for sourceMember polling events + lifecycle.on('sourceMemberPollingEvent', (event: SourceMemberPollingEvent) => + Promise.resolve(this.ms.goto('Updating Source Tracking', { sourceMemberPolling: event })) + ); + + deploy.onUpdate((data) => { + if ( + data.numberComponentsDeployed === data.numberComponentsTotal && + data.numberTestsTotal > 0 && + data.numberComponentsDeployed > 0 + ) { + this.ms.goto('Running Tests', { mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status) }); + } else if (data.status === RequestStatus.Pending) { + this.ms.goto('Waiting for the org to respond', { + mdapiDeploy: data, + status: mdTransferMessages.getMessage(data?.status), + }); + } else { + this.ms.goto('Deploying Metadata', { mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status) }); + } + }); + + deploy.onFinish((data) => { + this.ms.updateData({ mdapiDeploy: data.response, status: mdTransferMessages.getMessage(data.response.status) }); + if (data.response.status === RequestStatus.Failed) { + this.ms.stop(new Error('Failed to deploy metadata')); + } else { + this.ms.goto('Done'); + this.ms.stop(); + } + }); + + deploy.onCancel((data) => { + this.ms.updateData({ mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status ?? 'Canceled') }); + + this.ms.stop(new Error('Deploy canceled')); + }); + + deploy.onError((error: Error) => { + if (error.message.includes('client has timed out')) { + this.ms.updateData({ status: 'Client Timeout' }); + } + + this.ms.stop(error); + throw error; + }); + } + + public update(data: Partial): void { + this.ms.updateData(data); + } + + public stop(error?: Error): void { + this.ms.stop(error); + } + + public done(data?: Partial): void { + this.ms.goto('Done', data); + } +} diff --git a/src/utils/progressBar.ts b/src/utils/progressBar.ts deleted file mode 100644 index b39a732d..00000000 --- a/src/utils/progressBar.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2022, salesforce.com, inc. - * All rights reserved. - * Licensed under the BSD 3-Clause license. - * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause - */ - -import { envVars as env, EnvironmentVariable, Lifecycle, Messages, Logger } from '@salesforce/core'; -import { MetadataApiDeploy, MetadataApiDeployStatus } from '@salesforce/source-deploy-retrieve'; -import { Progress } from '@salesforce/sf-plugins-core'; -import { SourceMemberPollingEvent } from '@salesforce/source-tracking'; - -Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); -const mdTransferMessages = Messages.loadMessages('@salesforce/plugin-deploy-retrieve', 'metadata.transfer'); - -const showBar = Boolean( - process.env.TERM !== 'dumb' && process.stdin.isTTY && env.getBoolean(EnvironmentVariable.SF_USE_PROGRESS_BAR, true) -); - -const logger = await Logger.child('deploy-progress'); - -export class DeployProgress extends Progress { - private static OPTIONS = { - title: 'Status', - format: `%s: {status} ${showBar ? '| {bar} ' : ''}| {value}/{total} Components{errorInfo}{testInfo}{trackingInfo}`, - barCompleteChar: '\u2588', - barIncompleteChar: '\u2591', - linewrap: true, - // people really like to get text output in CI systems - // they won't get the "bar" but will get the remaining template bits this way - noTTYOutput: true, - }; - private lifecycle = Lifecycle.getInstance(); - - public constructor(private deploy: MetadataApiDeploy, jsonEnabled = false) { - super(!jsonEnabled); - } - - public start(): void { - super.start(0, { status: 'Waiting', trackingInfo: '', testInfo: '' }, DeployProgress.OPTIONS); - - // for sourceMember polling events - this.lifecycle.on('sourceMemberPollingEvent', (event: SourceMemberPollingEvent) => - Promise.resolve(this.updateTrackingProgress(event)) - ); - - this.deploy.onUpdate((data) => this.updateProgress(data)); - - // any thing else should make one final update, then stop the progress bar - this.deploy.onFinish((data) => { - this.updateProgress(data.response); - this.finish({ status: mdTransferMessages.getMessage(data.response.status) }); - }); - - this.deploy.onCancel(() => this.stop()); - - this.deploy.onError((error: Error) => { - this.stop(); - throw error; - }); - } - - private updateTrackingProgress(data: SourceMemberPollingEvent): void { - const { remaining, original } = data; - this.update(0, { - status: 'Polling SourceMembers', - trackingInfo: ` | Tracking: ${original - remaining}/${original}`, - }); - } - - private updateProgress(data: MetadataApiDeployStatus): void { - // the numCompTot. isn't computed right away, wait to start until we know how many we have - const testInfo = data.numberTestsTotal - ? ` | ${data.numberTestsCompleted ?? 0}/${data.numberTestsTotal ?? 0} Tests${ - data.numberTestErrors ? `(Errors:${data.numberTestErrors})` : '' - }` - : ''; - const errorInfo = data.numberComponentErrors > 0 ? ` | Errors: ${data.numberComponentErrors}` : ''; - - if (data.numberComponentsTotal) { - this.setTotal(data.numberComponentsTotal); - this.update(data.numberComponentsDeployed, { - errorInfo: data.numberComponentErrors > 0 ? ` | Errors: ${data.numberComponentErrors}` : '', - status: mdTransferMessages.getMessage(data.status), - testInfo, - }); - } else { - let status; - try { - status = mdTransferMessages.getMessage(data.status); - } catch (e) { - logger.debug(`data.status message lookup failed for: ${data.status}`); - status = 'Waiting'; - } - this.update(0, { errorInfo, testInfo, status }); - } - } -} diff --git a/yarn.lock b/yarn.lock index 47cd5b74..bc4ec6bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@alcalzone/ansi-tokenize@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.1.3.tgz#9f89839561325a8e9a0c32360b8d17e48489993f" + integrity sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw== + dependencies: + ansi-styles "^6.2.1" + is-fullwidth-code-point "^4.0.0" + "@ampproject/remapping@^2.2.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" @@ -1520,6 +1528,19 @@ wordwrap "^1.0.0" wrap-ansi "^7.0.0" +"@oclif/multi-stage-output@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@oclif/multi-stage-output/-/multi-stage-output-0.3.0.tgz#2d74763bd2215c61ec1cd53faf3138328d50122d" + integrity sha512-7pMD3CoXfS9/hEWzZ1b8GZb3leSNWENsMJS7uYTX0XqTXlrzh+eYvFHYcJh9bEkIw67LKjFfGGIwXbotdhtZKg== + dependencies: + "@oclif/core" "^4" + "@types/react" "^18.3.3" + change-case "^5.4.4" + cli-spinners "^2" + figures "^6.1.0" + ink "^5.0.1" + react "^18.3.1" + "@oclif/plugin-command-snapshot@^5.2.12": version "5.2.12" resolved "https://registry.yarnpkg.com/@oclif/plugin-command-snapshot/-/plugin-command-snapshot-5.2.12.tgz#f22aaac03ad1e4fbb62c9beb5c44c99522d29e8b" @@ -2555,6 +2576,19 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== +"@types/prop-types@*": + version "15.7.12" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" + integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== + +"@types/react@^18.3.3": + version "18.3.3" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" + integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + "@types/responselike@^1.0.0": version "1.0.3" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" @@ -2824,6 +2858,13 @@ ansi-escapes@^5.0.0: dependencies: type-fest "^1.0.2" +ansi-escapes@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.0.0.tgz#00fc19f491bbb18e1d481b97868204f92109bfe7" + integrity sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw== + dependencies: + environment "^1.0.0" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -2848,7 +2889,7 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -ansi-styles@^6.1.0, ansi-styles@^6.2.1: +ansi-styles@^6.0.0, ansi-styles@^6.1.0, ansi-styles@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== @@ -3035,6 +3076,11 @@ atomic-sleep@^1.0.0: resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== +auto-bind@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-5.0.1.tgz#50d8e63ea5a1dddcb5e5e36451c1a8266ffbb2ae" + integrity sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg== + available-typed-arrays@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" @@ -3331,6 +3377,11 @@ change-case@^4, change-case@^4.1.2: snake-case "^3.0.4" tslib "^2.0.3" +change-case@^5.4.4: + version "5.4.4" + resolved "https://registry.yarnpkg.com/change-case/-/change-case-5.4.4.tgz#0d52b507d8fb8f204343432381d1a6d7bff97a02" + integrity sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w== + check-error@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" @@ -3387,6 +3438,18 @@ clean-stack@^3.0.1: dependencies: escape-string-regexp "4.0.0" +cli-boxes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" + integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== + +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + dependencies: + restore-cursor "^4.0.0" + cli-progress@^3.12.0: version "3.12.0" resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.12.0.tgz#807ee14b66bcc086258e444ad0f19e7d42577942" @@ -3394,7 +3457,7 @@ cli-progress@^3.12.0: dependencies: string-width "^4.2.3" -cli-spinners@^2.9.2: +cli-spinners@^2, cli-spinners@^2.9.2: version "2.9.2" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== @@ -3408,6 +3471,14 @@ cli-table3@^0.6.0: optionalDependencies: "@colors/colors" "1.5.0" +cli-truncate@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-4.0.0.tgz#6cc28a2924fee9e25ce91e973db56c7066e6172a" + integrity sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA== + dependencies: + slice-ansi "^5.0.0" + string-width "^7.0.0" + cli-width@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" @@ -3447,6 +3518,13 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +code-excerpt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/code-excerpt/-/code-excerpt-4.0.0.tgz#2de7d46e98514385cb01f7b3b741320115f4c95e" + integrity sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA== + dependencies: + convert-to-spaces "^2.0.1" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -3559,6 +3637,11 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +convert-to-spaces@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz#61a6c98f8aa626c16b296b862a91412a33bceb6b" + integrity sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ== + core-js-compat@^3.34.0: version "3.37.0" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.37.0.tgz#d9570e544163779bb4dff1031c7972f44918dc73" @@ -3619,6 +3702,11 @@ csprng@*: dependencies: sequin "*" +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + csv-parse@^5.5.2: version "5.5.6" resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-5.5.6.tgz#0d726d58a60416361358eec291a9f93abe0b6b1a" @@ -3931,6 +4019,11 @@ entities@^4.2.0, entities@^4.4.0, entities@^4.5.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -4059,6 +4152,11 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escodegen@^1.8.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" @@ -4450,6 +4548,13 @@ faye@1.4.0, faye@^1.4.0: tough-cookie "*" tunnel-agent "*" +figures@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-6.1.0.tgz#935479f51865fa7479f6fa94fc6fc7ac14e62c4a" + integrity sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg== + dependencies: + is-unicode-supported "^2.0.0" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -5115,6 +5220,11 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== +indent-string@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" + integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -5133,6 +5243,36 @@ ini@^1.3.4: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +ink@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ink/-/ink-5.0.1.tgz#f2ef9796a3911830c3995dedd227ec84ae27de4b" + integrity sha512-ae4AW/t8jlkj/6Ou21H2av0wxTk8vrGzXv+v2v7j4in+bl1M5XRMVbfNghzhBokV++FjF8RBDJvYo+ttR9YVRg== + dependencies: + "@alcalzone/ansi-tokenize" "^0.1.3" + ansi-escapes "^7.0.0" + ansi-styles "^6.2.1" + auto-bind "^5.0.1" + chalk "^5.3.0" + cli-boxes "^3.0.0" + cli-cursor "^4.0.0" + cli-truncate "^4.0.0" + code-excerpt "^4.0.0" + indent-string "^5.0.0" + is-in-ci "^0.1.0" + lodash "^4.17.21" + patch-console "^2.0.0" + react-reconciler "^0.29.0" + scheduler "^0.23.0" + signal-exit "^3.0.7" + slice-ansi "^7.1.0" + stack-utils "^2.0.6" + string-width "^7.0.0" + type-fest "^4.8.3" + widest-line "^5.0.0" + wrap-ansi "^9.0.0" + ws "^8.15.0" + yoga-wasm-web "~0.3.3" + internal-slot@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" @@ -5243,6 +5383,11 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + is-fullwidth-code-point@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz#9609efced7c2f97da7b60145ef481c787c7ba704" @@ -5257,6 +5402,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-in-ci@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-in-ci/-/is-in-ci-0.1.0.tgz#5e07d6a02ec3a8292d3f590973357efa3fceb0d3" + integrity sha512-d9PXLEY0v1iJ64xLiQMJ51J128EYHAaOR4yZqQi8aHGfw6KgifM3/Viw1oZZ1GCVmb3gBuyhLyHj0HgR2DhSXQ== + is-inside-container@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" @@ -5369,6 +5519,11 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +is-unicode-supported@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz#fdf32df9ae98ff6ab2cedc155a5a6e895701c451" + integrity sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q== + is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -5517,7 +5672,7 @@ joycon@^3.1.1: resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== -js-tokens@^4.0.0: +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -5911,6 +6066,13 @@ lolex@^5.0.1: dependencies: "@sinonjs/commons" "^1.7.0" +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + loupe@^2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" @@ -6658,6 +6820,11 @@ pascal-case@^3.1.2: no-case "^3.0.4" tslib "^2.0.3" +patch-console@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/patch-console/-/patch-console-2.0.0.tgz#9023f4665840e66f40e9ce774f904a63167433bb" + integrity sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA== + path-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" @@ -6941,6 +7108,21 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" +react-reconciler@^0.29.0: + version "0.29.2" + resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.29.2.tgz#8ecfafca63549a4f4f3e4c1e049dd5ad9ac3a54f" + integrity sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.2" + +react@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== + dependencies: + loose-envify "^1.1.0" + read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -7121,6 +7303,14 @@ responselike@^3.0.0: dependencies: lowercase-keys "^3.0.0" +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + retry@0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" @@ -7199,6 +7389,13 @@ sax@>=0.6.0: resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== +scheduler@^0.23.0, scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== + dependencies: + loose-envify "^1.1.0" + secure-json-parse@^2.4.0: version "2.7.0" resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" @@ -7331,7 +7528,7 @@ side-channel@^1.0.4: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -7419,6 +7616,14 @@ slash@^5.1.0: resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce" integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg== +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + slice-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.0.tgz#cd6b4655e298a8d1bdeb04250a433094b347b9a9" @@ -7569,6 +7774,13 @@ srcset@^5.0.0: resolved "https://registry.yarnpkg.com/srcset/-/srcset-5.0.1.tgz#e660a728f195419e4afa95121099bc9efb7a1e36" integrity sha512-/P1UYbGfJVlxZag7aABNRrulEXAwCSDo7fklafOQrantuPTDmYgijJMks2zusPCVzgW9+4P69mq7w6pYuZpgxw== +stack-utils@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + static-eval@2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42" @@ -7594,7 +7806,7 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string-width@^7.2.0: +string-width@^7.0.0, string-width@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== @@ -7931,6 +8143,11 @@ type-fest@^1.0.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== +type-fest@^4.8.3: + version "4.22.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.22.0.tgz#da4fc735652e17ef693d2b8dc4f65d93f5fd4ef9" + integrity sha512-hxMO1k4ip1uTVGgPbs1hVpYyhz2P91A6tQyH2H9POx3U6T3MdhIcfY8L2hRu/LRmzPFdfduOS0RIDjFlP2urPw== + typed-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" @@ -8201,6 +8418,13 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" +widest-line@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-5.0.0.tgz#b74826a1e480783345f0cd9061b49753c9da70d0" + integrity sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA== + dependencies: + string-width "^7.0.0" + wireit@^0.14.5: version "0.14.5" resolved "https://registry.yarnpkg.com/wireit/-/wireit-0.14.5.tgz#cd1c4136444c8dbe655f34f60fe2454a9e69d430" @@ -8254,6 +8478,15 @@ wrap-ansi@^8.1.0: string-width "^5.0.1" strip-ansi "^7.0.1" +wrap-ansi@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.0.tgz#1a3dc8b70d85eeb8398ddfb1e4a02cd186e58b3e" + integrity sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q== + dependencies: + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -8269,6 +8502,11 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +ws@^8.15.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + xml2js@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" @@ -8397,3 +8635,8 @@ yoctocolors-cjs@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz#f4b905a840a37506813a7acaa28febe97767a242" integrity sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA== + +yoga-wasm-web@~0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz#eb8e9fcb18e5e651994732f19a220cb885d932ba" + integrity sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==