From afb625e6592374b2f9ef648195a709a96a28dd12 Mon Sep 17 00:00:00 2001 From: Mike Donnalley Date: Mon, 26 Aug 2024 09:47:57 -0600 Subject: [PATCH] fix: revert MSO changes (#1147) * Revert "fix: prevent NaN in stage output (#1139)" This reverts commit e426bf5aa43b6e07142ea6612c5dfa1865372810. * Revert "Merge pull request #1123 from salesforcecli/mdonnalley/ink" This reverts commit c4f1cff365c219714aaede6548d228f7090f1a55, reversing changes made to 2098219b4882dd153aef7ac65a9fc8a3c000d07c. --- messages/retrieve.start.md | 12 + package.json | 1 - src/commands/project/delete/source.ts | 12 +- src/commands/project/deploy/report.ts | 9 +- src/commands/project/deploy/resume.ts | 10 +- src/commands/project/deploy/start.ts | 63 ++---- src/commands/project/deploy/validate.ts | 9 +- src/commands/project/retrieve/start.ts | 83 ++----- src/utils/deployStages.ts | 183 --------------- src/utils/progressBar.ts | 98 ++++++++ yarn.lock | 284 +----------------------- 11 files changed, 173 insertions(+), 591 deletions(-) delete mode 100644 src/utils/deployStages.ts create mode 100644 src/utils/progressBar.ts diff --git a/messages/retrieve.start.md b/messages/retrieve.start.md index 12fa5e27..c1484904 100644 --- a/messages/retrieve.start.md +++ b/messages/retrieve.start.md @@ -145,6 +145,18 @@ 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 1fd1802f..6e38d655 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,6 @@ "bugs": "https://github.com/forcedotcom/cli/issues", "dependencies": { "@oclif/core": "^4.0.18", - "@oclif/multi-stage-output": "^0.3.1", "@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 dfdcd5d3..166de79f 100644 --- a/src/commands/project/delete/source.ts +++ b/src/commands/project/delete/source.ts @@ -33,7 +33,6 @@ 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'; @@ -42,6 +41,7 @@ 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,14 +244,8 @@ 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']; - stages.update({ message: `Deleting with ${isRest ? 'REST' : 'SOAP'} API` }); + this.log(`*** Deleting with ${isRest ? 'REST' : 'SOAP'} API ***`); const deploy = await this.componentSet.deploy({ usernameOrConnection: this.org.getUsername() as string, @@ -263,7 +257,7 @@ export class Source extends SfCommand { }, }); - stages.start({ deploy, username: this.org.getUsername() }); + new DeployProgress(deploy, this.jsonEnabled()).start(); 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 64f3c36b..283205fc 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; + const wait = flags['wait']; const org = deployOpts?.['target-org'] ? await Org.create({ aliasOrUsername: deployOpts['target-org'] }) : flags['target-org']; @@ -124,10 +124,7 @@ export default class DeployMetadataReport extends SfCommand { if (wait) { // poll for deploy results try { - new DeployStages({ - title: 'Deploying Metadata', - jsonEnabled: this.jsonEnabled(), - }).start({ deploy: mdapiDeploy, username: org.getUsername() }); + new DeployProgress(mdapiDeploy, this.jsonEnabled()).start(); 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 95d25aea..3dbfe7c0 100644 --- a/src/commands/project/deploy/resume.ts +++ b/src/commands/project/deploy/resume.ts @@ -5,12 +5,13 @@ * 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'; @@ -123,11 +124,8 @@ export default class DeployMetadataResume extends SfCommand { jobId ); - new DeployStages({ - title: 'Resuming Deploy', - jsonEnabled: this.jsonEnabled(), - }).start({ deploy, username: deployOpts['target-org'] }); - + this.log(`Deploy ID: ${ansis.bold(jobId)}`); + new DeployProgress(deploy, this.jsonEnabled()).start(); 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 b798d254..a9467978 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 { MultiStageOutput } from '@oclif/multi-stage-output'; +import ansis from 'ansis'; import { EnvironmentVariable, Lifecycle, Messages, OrgConfigProperties, SfError } from '@salesforce/core'; -import { DeployVersionData, MetadataApiDeployStatus } from '@salesforce/source-deploy-retrieve'; +import { DeployVersionData } from '@salesforce/source-deploy-retrieve'; import { Duration } from '@salesforce/kit'; import { SfCommand, toHelpSection, Flags } from '@salesforce/sf-plugins-core'; -import { SourceConflictError, SourceMemberPollingEvent } from '@salesforce/source-tracking'; -import { DeployStages } from '../../../utils/deployStages.js'; +import { SourceConflictError } from '@salesforce/source-tracking'; 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,16 +176,6 @@ 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(); @@ -207,30 +197,23 @@ export default class DeployMetadata extends SfCommand { const api = await resolveApi(this.configAggregator); const username = flags['target-org'].getUsername(); - const title = flags['dry-run'] ? 'Deploying Metadata (dry-run)' : 'Deploying Metadata'; + const action = flags['dry-run'] ? 'Deploying (dry-run)' : 'Deploying'; - this.stages = new DeployStages({ - title, - jsonEnabled: this.jsonEnabled(), + // 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, + ]) + ); }); - 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, @@ -241,7 +224,6 @@ export default class DeployMetadata extends SfCommand { ); if (!deploy) { - this.stages.stop(); this.log('No changes to deploy'); return { status: 'Nothing to deploy', files: [] }; } @@ -249,12 +231,9 @@ export default class DeployMetadata extends SfCommand { if (!deploy.id) { throw new SfError('The deploy id is not available.'); } - - this.stages.start({ username, deploy }); + this.log(`Deploy ID: ${ansis.bold(deploy.id)}`); if (flags.async) { - this.stages.done({ status: 'Queued', username }); - this.stages.stop(); if (flags['coverage-formatters']) { this.warn(messages.getMessage('asyncCoverageJunitWarning')); } @@ -263,6 +242,8 @@ 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); @@ -280,8 +261,6 @@ 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 a66bde0c..2b6d7ad3 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,18 +195,15 @@ 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 DeployStages({ - title: 'Validating Deployment', - jsonEnabled: this.jsonEnabled(), - }).start({ deploy, username }); + new DeployProgress(deploy, this.jsonEnabled()).start(); 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 47018a1d..9fb7df8b 100644 --- a/src/commands/project/retrieve/start.ts +++ b/src/commands/project/retrieve/start.ts @@ -9,7 +9,6 @@ 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, @@ -148,10 +147,6 @@ 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 { @@ -166,6 +161,8 @@ 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 @@ -180,76 +177,42 @@ 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.ms.goto('Sending request to org'); + this.spinner.status = messages.getMessage('spinner.sending'); this.retrieveResult = new RetrieveResult({} as MetadataApiRetrieveStatus, componentSetFromNonDeletes); if (componentSetFromNonDeletes.size !== 0 || retrieveOpts.packageOptions?.length) { - Lifecycle.getInstance().on('apiVersionRetrieve', async (apiData: RetrieveVersionData) => - Promise.resolve(this.ms.updateData({ apiData })) - ); + // 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, + ]) + ); + }); const retrieve = await componentSetFromNonDeletes.retrieve(retrieveOpts); - this.ms.goto('Waiting for the org to respond', { status: 'Pending' }); + this.spinner.status = messages.getMessage('spinner.polling'); retrieve.onUpdate((data) => { - 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')); + this.spinner.status = mdTransferMessages.getMessage(data.status); }); + // 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) => { - if (error.message.includes('client has timed out')) { - this.ms.updateData({ status: 'Client Timeout' }); - } - - this.ms.stop(error); + this.spinner.stop(error.name); throw error; }); this.retrieveResult = await retrieve.pollStatus(500, flags.wait.seconds); } - this.ms.stop(); + this.spinner.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) { @@ -300,8 +263,6 @@ 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({ @@ -309,8 +270,6 @@ 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 deleted file mode 100644 index 1fd6f71e..00000000 --- a/src/utils/deployStages.ts +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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 { - if (total === 0) { - return '0/0 (0%)'; - } - - 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?.original - ? formatProgress( - data.sourceMemberPolling.original - data.sourceMemberPolling.remaining, - data.sourceMemberPolling.original - ) - : undefined, - 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 new file mode 100644 index 00000000..b39a732d --- /dev/null +++ b/src/utils/progressBar.ts @@ -0,0 +1,98 @@ +/* + * 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 a54ddb23..74271a1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,14 +2,6 @@ # 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" @@ -1528,19 +1520,6 @@ wordwrap "^1.0.0" wrap-ansi "^7.0.0" -"@oclif/multi-stage-output@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@oclif/multi-stage-output/-/multi-stage-output-0.3.1.tgz#13222bef5fbc7e7dd3395536e7bc9d23dfabc8fa" - integrity sha512-CBE8Cesd3Pxd0n+9GUqaml1yHKi93dNGvP5ksS0SnUfkfFVI6AMPWDzFLmMiqNxl1k78+IklKoMygw0rqaZCvA== - 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.13": version "5.2.13" resolved "https://registry.yarnpkg.com/@oclif/plugin-command-snapshot/-/plugin-command-snapshot-5.2.13.tgz#d0025844865c20e38d4198c43fd6a515fedfde06" @@ -2576,19 +2555,6 @@ 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" @@ -2858,13 +2824,6 @@ 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" @@ -2889,7 +2848,7 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -ansi-styles@^6.0.0, ansi-styles@^6.1.0, ansi-styles@^6.2.1: +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== @@ -3076,11 +3035,6 @@ 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" @@ -3377,11 +3331,6 @@ 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" @@ -3438,18 +3387,6 @@ 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" @@ -3457,7 +3394,7 @@ cli-progress@^3.12.0: dependencies: string-width "^4.2.3" -cli-spinners@^2, cli-spinners@^2.9.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== @@ -3471,14 +3408,6 @@ 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" @@ -3518,13 +3447,6 @@ 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" @@ -3637,11 +3559,6 @@ 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" @@ -3702,11 +3619,6 @@ 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" @@ -4019,11 +3931,6 @@ 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" @@ -4152,11 +4059,6 @@ 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" @@ -4548,13 +4450,6 @@ 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" @@ -5220,11 +5115,6 @@ 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" @@ -5243,36 +5133,6 @@ 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" @@ -5383,11 +5243,6 @@ 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" @@ -5402,11 +5257,6 @@ 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" @@ -5519,11 +5369,6 @@ 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" @@ -5672,7 +5517,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@^3.0.0 || ^4.0.0", js-tokens@^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== @@ -6066,13 +5911,6 @@ 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" @@ -6820,11 +6658,6 @@ 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" @@ -7108,21 +6941,6 @@ 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" @@ -7303,14 +7121,6 @@ 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" @@ -7389,13 +7199,6 @@ 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" @@ -7528,7 +7331,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.7: +signal-exit@^3.0.2, signal-exit@^3.0.3: 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== @@ -7616,14 +7419,6 @@ 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" @@ -7774,13 +7569,6 @@ 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" @@ -7788,16 +7576,7 @@ static-eval@2.0.2: dependencies: escodegen "^1.8.1" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7815,7 +7594,7 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string-width@^7.0.0, string-width@^7.2.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== @@ -7866,14 +7645,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -8159,11 +7931,6 @@ 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" @@ -8434,13 +8201,6 @@ 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" @@ -8467,7 +8227,7 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -8485,15 +8245,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" @@ -8503,15 +8254,6 @@ 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" @@ -8527,11 +8269,6 @@ 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" @@ -8660,8 +8397,3 @@ 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==