diff --git a/package.json b/package.json index 41454898..b414452c 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "@salesforce/core": "^8.6.1", "@salesforce/kit": "^3.2.3", "@salesforce/plugin-info": "^3.4.9", - "@salesforce/sf-plugins-core": "^11.3.12", + "@salesforce/sf-plugins-core": "^12.0.4", "@salesforce/source-deploy-retrieve": "^12.7.4", "@salesforce/source-tracking": "^7.1.16", "@salesforce/ts-types": "^2.0.12", diff --git a/src/commands/project/convert/source-behavior.ts b/src/commands/project/convert/source-behavior.ts index c53834a3..0efd3f86 100644 --- a/src/commands/project/convert/source-behavior.ts +++ b/src/commands/project/convert/source-behavior.ts @@ -93,15 +93,23 @@ export default class ConvertSourceBehavior extends SfCommand ({ value: f })), - { value: { header: flags['dry-run'] ? 'Files that would have been deleted if not --dry-run' : 'Deleted Files' } } - ); + this.table({ + data: filesToDelete.map((f) => ({ value: f })), + columns: [ + { + key: 'value', + name: flags['dry-run'] ? 'Files that would have been deleted if not --dry-run' : 'Deleted Files', + }, + ], + }); + this.log(); - this.table( - createdFiles.map((f) => ({ value: f })), - { value: { header: 'Created Files' } } - ); + + this.table({ + data: createdFiles.map((f) => ({ value: f })), + columns: [{ key: 'value', name: 'Created Files' }], + }); + if (flags['dry-run']) { // put it back how it was await writeFile(projectJson.getPath(), backupPjsonContents); diff --git a/src/formatters/deleteResultFormatter.ts b/src/formatters/deleteResultFormatter.ts index e70e42a7..664f9dcc 100644 --- a/src/formatters/deleteResultFormatter.ts +++ b/src/formatters/deleteResultFormatter.ts @@ -82,17 +82,17 @@ export class DeleteResultFormatter extends TestResultsFormatter implements Forma }); } - ux.log(''); + ux.log(); ux.styledHeader(tableHeader('Deleted Source')); - ux.table( - successes.map(getFileResponseSuccessProps), - { - fullName: { header: 'FULL NAME' }, - type: { header: 'TYPE' }, - filePath: { header: 'PROJECT PATH' }, - }, - { 'no-truncate': true } - ); + ux.table({ + data: successes.map(getFileResponseSuccessProps), + columns: [ + { key: 'fullName', name: 'FULL NAME' }, + { key: 'type', name: 'TYPE' }, + { key: 'filePath', name: 'PROJECT PATH' }, + ], + overflow: 'wrap', + }); } else { this.displayFailures(); } @@ -105,17 +105,15 @@ export class DeleteResultFormatter extends TestResultsFormatter implements Forma if (!failures.length) return; ux.log(); - ux.table( - failures.map((f) => ({ problemType: f.problemType, fullName: f.fullName, error: f.problem })), - { - problemType: { header: 'Type' }, - fullName: { header: 'Name' }, - error: { header: 'Problem' }, - }, - { - title: StandardColors.error(`Component Failures [${failures.length}]`), - 'no-truncate': true, - } - ); + ux.table({ + data: failures.map((f) => ({ problemType: f.problemType, fullName: f.fullName, error: f.problem })), + columns: [ + { key: 'problemType', name: 'Type' }, + { key: 'fullName', name: 'Name' }, + { key: 'error', name: 'Problem' }, + ], + title: StandardColors.error(`Component Failures [${failures.length}]`), + overflow: 'wrap', + }); } } diff --git a/src/formatters/deployReportResultFormatter.ts b/src/formatters/deployReportResultFormatter.ts index 64d123e8..ad13d7fb 100644 --- a/src/formatters/deployReportResultFormatter.ts +++ b/src/formatters/deployReportResultFormatter.ts @@ -32,7 +32,11 @@ export class DeployReportResultFormatter extends DeployResultFormatter { ); ux.log(); - ux.table(response, { key: {}, value: {} }, { title: tableHeader('Deploy Info'), 'no-truncate': true }); + ux.table({ + data: response, + title: tableHeader('Deploy Info'), + overflow: 'wrap', + }); const opts = Object.entries(this.flags).reduce>((result, [key, value]) => { if (key === 'timestamp') { @@ -48,7 +52,11 @@ export class DeployReportResultFormatter extends DeployResultFormatter { return result.concat({ key, value }); }, []); ux.log(); - ux.table(opts, { key: {}, value: {} }, { title: tableHeader('Deploy Options'), 'no-truncate': true }); + ux.table({ + data: opts, + title: tableHeader('Deploy Options'), + overflow: 'wrap', + }); super.display(); } } diff --git a/src/formatters/deployResultFormatter.ts b/src/formatters/deployResultFormatter.ts index 3b505484..a118c92c 100644 --- a/src/formatters/deployResultFormatter.ts +++ b/src/formatters/deployResultFormatter.ts @@ -274,17 +274,15 @@ export class DeployResultFormatter extends TestResultsFormatter implements Forma replaced, })) ); - ux.table( - replacements, - { - filePath: { header: 'PROJECT PATH' }, - replaced: { header: 'TEXT REPLACED' }, - }, - { - title: tableHeader('Metadata Replacements'), - 'no-truncate': true, - } - ); + ux.table({ + data: replacements, + columns: [ + { key: 'filePath', name: 'PROJECT PATH' }, + { key: 'replaced', name: 'TEXT REPLACED' }, + ], + title: tableHeader('Metadata Replacements'), + overflow: 'wrap', + }); } } @@ -293,17 +291,14 @@ export class DeployResultFormatter extends TestResultsFormatter implements Forma if (!successes.length || this.result.response.status === RequestStatus.Failed) return; - const columns = { - state: { header: 'State' }, - fullName: { header: 'Name' }, - type: { header: 'Type' }, - filePath: { header: 'Path' }, - }; const title = this.result.response.checkOnly ? 'Validated Source' : 'Deployed Source'; - const options = { title: tableHeader(title), 'no-truncate': true }; ux.log(); - - ux.table(successes.map(getFileResponseSuccessProps), columns, options); + ux.table({ + data: successes.map(getFileResponseSuccessProps), + columns: ['state', { key: 'fullName', name: 'Name' }, 'type', { key: 'filePath', name: 'Path' }], + title: tableHeader(title), + overflow: 'wrap', + }); } private displayFailures(): void { @@ -312,24 +307,23 @@ export class DeployResultFormatter extends TestResultsFormatter implements Forma const failures = this.getFileResponseFailures(); if (!failures?.length) return; - const columns = { - problemType: { header: 'Type' }, - fullName: { header: 'Name' }, - error: { header: 'Problem' }, - loc: { header: 'Line:Column' }, - }; - const options = { title: error(`Component Failures [${failures.length}]`), 'no-truncate': true }; ux.log(); - ux.table( - sortBy(failures, ['problemType', 'fullName', 'lineNumber', 'columnNumber', 'error']).map((f) => ({ + ux.table({ + data: sortBy(failures, ['problemType', 'fullName', 'lineNumber', 'columnNumber', 'error']).map((f) => ({ problemType: f.problemType, fullName: f.fullName, error: f.error, loc: f.lineNumber ? `${f.lineNumber}:${f.columnNumber ?? ''}` : '', })), - columns, - options - ); + columns: [ + { key: 'problemType', name: 'Type' }, + { key: 'fullName', name: 'Name' }, + { key: 'error', name: 'Problem' }, + { key: 'loc', name: 'Line:Column' }, + ], + title: error(`Component Failures [${failures.length}]`), + overflow: 'wrap', + }); } } @@ -344,14 +338,12 @@ const displayDeletes = (relativeFiles: FileResponse[], extraDeletes: FileRespons if (!deletions.length) return; - const columns = { - fullName: { header: 'Name' }, - type: { header: 'Type' }, - filePath: { header: 'Path' }, - }; - - const options = { title: tableHeader('Deleted Source'), 'no-truncate': true }; ux.log(); - ux.table(deletions, columns, options); + ux.table({ + data: deletions, + columns: [{ key: 'fullName', name: 'Name' }, 'type', { key: 'filePath', name: 'Path' }], + title: tableHeader('Deleted Source'), + overflow: 'wrap', + }); }; diff --git a/src/formatters/metadataConvertResultFormatter.ts b/src/formatters/metadataConvertResultFormatter.ts index a2a2333f..4ae40dd8 100644 --- a/src/formatters/metadataConvertResultFormatter.ts +++ b/src/formatters/metadataConvertResultFormatter.ts @@ -43,21 +43,21 @@ export class MetadataConvertResultFormatter implements Formatter { const convertData = await this.getJson(); if (convertData?.length) { - ux.table( - convertData.map((entry) => ({ + ux.table({ + data: convertData.map((entry) => ({ state: entry.state, fullName: entry.fullName, type: entry.type, filePath: entry.filePath, })), - { - state: { header: 'STATE' }, - fullName: { header: 'FULL NAME' }, - type: { header: 'TYPE' }, - filePath: { header: 'PROJECT PATH' }, - }, - { 'no-truncate': true } - ); + columns: [ + { key: 'state', name: 'STATE' }, + { key: 'fullName', name: 'FULL NAME' }, + { key: 'type', name: 'TYPE' }, + { key: 'filePath', name: 'PROJECT PATH' }, + ], + overflow: 'wrap', + }); } else { ux.log('No metadata found to convert'); } diff --git a/src/formatters/retrieveResultFormatter.ts b/src/formatters/retrieveResultFormatter.ts index f97e67e5..7af25e8a 100644 --- a/src/formatters/retrieveResultFormatter.ts +++ b/src/formatters/retrieveResultFormatter.ts @@ -50,40 +50,42 @@ export class RetrieveResultFormatter implements Formatter { this.ux.log('Nothing retrieved'); } } else { - const columns = { - state: { header: 'State' }, - fullName: { header: 'Name' }, - type: { header: 'Type' }, - filePath: { header: 'Path' }, - }; - const options = { title: tableHeader('Retrieved Source'), 'no-truncate': true }; this.ux.log(); - this.ux.table(successes, columns, options); + this.ux.table({ + data: successes, + columns: ['state', { key: 'fullName', name: 'Name' }, 'type', { key: 'filePath', name: 'Path' }], + title: tableHeader('Retrieved Source'), + overflow: 'wrap', + }); } const warnings = getWarnings(this.result); if (warnings.length) { this.ux.log(); - this.ux.table( - warnings, - { fileName: { header: 'File' }, problem: { header: 'Problem' } }, - { 'no-truncate': true, title: tableHeader('Warnings') } - ); + this.ux.table({ + data: warnings, + columns: [{ key: 'fileName', name: 'File' }, 'problem'], + title: tableHeader('Warnings'), + overflow: 'wrap', + }); } } private async displayPackages(): Promise { const packages = await this.getPackages(); if (packages?.length) { - const columns = { - name: { header: 'Package Name' }, - fullPath: { header: 'Converted Location' }, - }; - const options = { title: tableHeader('Retrieved Packages'), 'no-truncate': true }; this.ux.log(); this.ux.warn('Metadata from retrieved packages is meant for your reference only, not development.'); - this.ux.table(packages, columns, options); + this.ux.table({ + data: packages, + columns: [ + { key: 'name', name: 'Package Name' }, + { key: 'fullPath', name: 'Converted Location' }, + ], + title: tableHeader('Retrieved Packages'), + overflow: 'wrap', + }); } } diff --git a/src/formatters/testResultsFormatter.ts b/src/formatters/testResultsFormatter.ts index 2e44e3ab..c3ae12fb 100644 --- a/src/formatters/testResultsFormatter.ts +++ b/src/formatters/testResultsFormatter.ts @@ -110,12 +110,14 @@ const displayVerboseTestCoverage = (coverage?: CodeCoverage | CodeCoverage[]): v const codeCoverage = ensureArray(coverage); if (codeCoverage.length) { ux.log(); - ux.log(tableHeader('Apex Code Coverage')); - - ux.table(codeCoverage.sort(coverageSort).map(coverageOutput), { - name: { header: 'Name' }, - coveragePercent: { header: '% Covered' }, - linesNotCovered: { header: 'Uncovered Lines' }, + ux.table({ + data: codeCoverage.sort(coverageSort).map(coverageOutput), + columns: [ + 'name', + { key: 'coveragePercent', name: '% Covered' }, + { key: 'linesNotCovered', name: 'Uncovered Lines' }, + ], + title: tableHeader('Apex Code Coverage'), }); } }; diff --git a/src/utils/conflicts.ts b/src/utils/conflicts.ts index 71bebe82..a0fcc538 100644 --- a/src/utils/conflicts.ts +++ b/src/utils/conflicts.ts @@ -14,16 +14,14 @@ export const writeConflictTable = (conflicts?: ConflictResponse[]): void => { if (!conflicts || conflicts.length === 0) { return; } - ux.table( - // Interfaces cannot be used as Record so we have to make it a concrete type - // See https://github.com/microsoft/TypeScript/issues/15300 - conflicts.map((c) => ({ state: c.state, fullName: c.fullName, type: c.type, filePath: c.filePath })), - { - state: { header: 'STATE' }, - fullName: { header: 'FULL NAME' }, - type: { header: 'TYPE' }, - filePath: { header: 'FILE PATH' }, - }, - { 'no-truncate': true } - ); + ux.table({ + data: conflicts, + columns: [ + { key: 'state', name: 'STATE' }, + { key: 'fullName', name: 'FULL NAME' }, + { key: 'type', name: 'TYPE' }, + { key: 'filePath', name: 'FILE PATH' }, + ], + overflow: 'wrap', + }); }; diff --git a/src/utils/previewOutput.ts b/src/utils/previewOutput.ts index 5c9ec366..798b6edb 100644 --- a/src/utils/previewOutput.ts +++ b/src/utils/previewOutput.ts @@ -101,7 +101,6 @@ const getWillDelete = (files: PreviewFile[]): PreviewFile[] => files.filter(willGo).filter((f) => f.operation && ['deletePre', 'deletePost'].includes(f.operation)); // relative paths are easier on tables -const columns = { type: {}, fullName: {}, projectRelativePath: { header: 'Path' } }; const makeKey = ({ type, fullName }: { type: MetadataType; fullName: string }): string => `${type.name}#${fullName}`; export const compileResults = ({ @@ -212,9 +211,11 @@ const printDeployTable = (files: PreviewFile[]): void => { if (files.length === 0) { ux.log(StandardColors.info(messages.getMessage('deploy.none'))); } else { - // not using table title property to avoid all the ASCII art - ux.log(StandardColors.success(messages.getMessage('deploy.header', [files.length]))); - ux.table(files, columns); + ux.table({ + data: files, + columns: ['type', 'fullName', { key: 'projectRelativePath', name: 'Path' }], + title: StandardColors.success(messages.getMessage('deploy.header', [files.length])), + }); } }; @@ -223,9 +224,11 @@ const printRetrieveTable = (files: PreviewFile[]): void => { if (files.length === 0) { ux.log(StandardColors.info(messages.getMessage('retrieve.none'))); } else { - // not using table title property to avoid all the ASCII art - ux.log(StandardColors.success(messages.getMessage('retrieve.header', [files.length]))); - ux.table(files, columns); + ux.table({ + data: files, + columns: ['type', 'fullName', { key: 'projectRelativePath', name: 'Path' }], + title: StandardColors.success(messages.getMessage('retrieve.header', [files.length])), + }); } }; @@ -234,8 +237,11 @@ const printDeleteTable = (files: PreviewFile[]): void => { if (files.length === 0) { ux.log(StandardColors.info(messages.getMessage('delete.none'))); } else { - ux.log(StandardColors.warning(messages.getMessage('delete.header', [files.length]))); - ux.table(files, columns); + ux.table({ + data: files, + columns: ['type', 'fullName', { key: 'projectRelativePath', name: 'Path' }], + title: StandardColors.warning(messages.getMessage('delete.header', [files.length])), + }); } }; @@ -244,8 +250,14 @@ const printConflictsTable = (files: PreviewFile[]): void => { if (files.length === 0) { ux.log(StandardColors.info(messages.getMessage('conflicts.none'))); } else { - ux.log(StandardColors.error(messages.getMessage('conflicts.header', [files.length]))); - ux.table(files, columns, { sort: 'path' }); + ux.table({ + data: files, + columns: ['type', 'fullName', { key: 'projectRelativePath', name: 'Path' }], + title: StandardColors.error(messages.getMessage('conflicts.header', [files.length])), + sort: { + path: 'asc', + }, + }); } }; @@ -254,8 +266,14 @@ const printIgnoredTable = (files: PreviewFile[], baseOperation: BaseOperation): if (files.length === 0) { ux.log(StandardColors.info(messages.getMessage('ignored.none'))); } else { - ux.log(StandardColors.info(messages.getMessage('ignored.header', [files.length, baseOperation]))); - ux.table(files, columns, { sort: 'path' }); + ux.table({ + data: files, + columns: ['type', 'fullName', { key: 'projectRelativePath', name: 'Path' }], + title: StandardColors.info(messages.getMessage('ignored.header', [files.length, baseOperation])), + sort: { + path: 'asc', + }, + }); } }; diff --git a/test/nuts/tracking/forceIgnore.nut.ts b/test/nuts/tracking/forceIgnore.nut.ts index dae599e4..a9620a54 100644 --- a/test/nuts/tracking/forceIgnore.nut.ts +++ b/test/nuts/tracking/forceIgnore.nut.ts @@ -208,11 +208,13 @@ describe('forceignore changes', () => { const output = execCmd(`project:deploy:preview -d ${classdir} --concise`, { ensureExitCode: 0, + env: { ...process.env, SF_NO_TABLE_STYLE: 'true' }, }).shellOutput.stdout; + expect(output).to.include('Will Deploy [1] files.'); - expect(output).to.include('ApexClass UnIgnoreTest'); + expect(output).to.include('ApexClass UnIgnoreTest'); expect(output).to.not.include("These files won't deploy because they're ignored by your .forceignore file."); - expect(output).to.not.include('ApexClass IgnoreTest'); + expect(output).to.not.include('ApexClass IgnoreTest'); }); }); }); diff --git a/test/utils/output.test.ts b/test/utils/output.test.ts index 0f11bb6f..bb05c24c 100644 --- a/test/utils/output.test.ts +++ b/test/utils/output.test.ts @@ -35,14 +35,24 @@ describe('deployResultFormatter', () => { const formatter = new DeployResultFormatter(deployResultFailure, { verbose: true }); formatter.display(); expect(tableStub.callCount).to.equal(1); - expect(tableStub.firstCall.args[0]).to.deep.equal([ - { - error: 'This component has some problems', - fullName: 'ProductController', - loc: '27:18', - problemType: 'Error', - }, - ]); + expect(tableStub.firstCall.args[0]).to.deep.equal({ + data: [ + { + problemType: 'Error', + fullName: 'ProductController', + error: 'This component has some problems', + loc: '27:18', + }, + ], + columns: [ + { key: 'problemType', name: 'Type' }, + { key: 'fullName', name: 'Name' }, + { key: 'error', name: 'Problem' }, + { key: 'loc', name: 'Line:Column' }, + ], + title: '\x1B[1m\x1B[31mComponent Failures [1]\x1B[39m\x1B[22m', + overflow: 'wrap', + }); }); it('displays errors from the server not in file responses', () => { @@ -93,20 +103,31 @@ describe('deployResultFormatter', () => { const formatter = new DeployResultFormatter(deployFailure, { verbose: true }); formatter.display(); expect(tableStub.callCount).to.equal(1); - expect(tableStub.firstCall.args[0]).to.deep.equal([ - { - error: error2.problem, - fullName: error2.fullName, - loc: '', - problemType: error2.problemType, - }, - { - error: 'This component has some problems', - fullName: 'ProductController', - loc: '27:18', - problemType: 'Error', - }, - ]); + expect(tableStub.firstCall.args[0]).to.deep.equal({ + data: [ + { + problemType: 'Error', + fullName: 'Create_property', + error: + "An object 'Create_property' of type Flow was named in package.xml, but was not found in zipped directory", + loc: '', + }, + { + problemType: 'Error', + fullName: 'ProductController', + error: 'This component has some problems', + loc: '27:18', + }, + ], + columns: [ + { key: 'problemType', name: 'Type' }, + { key: 'fullName', name: 'Name' }, + { key: 'error', name: 'Problem' }, + { key: 'loc', name: 'Line:Column' }, + ], + title: '\x1B[1m\x1B[31mComponent Failures [2]\x1B[39m\x1B[22m', + overflow: 'wrap', + }); }); }); diff --git a/yarn.lock b/yarn.lock index 9c73ec74..f9507df7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1324,6 +1324,22 @@ http-call "^5.2.2" lodash "^4.17.21" +"@oclif/table@^0.1.24": + version "0.1.24" + resolved "https://registry.yarnpkg.com/@oclif/table/-/table-0.1.24.tgz#97cc9fc0e65cf4ceb7628084c73eb6ca30bf19b1" + integrity sha512-HC5lIdy8Q0crW+ImJhzux3lQ2UobcDM//Tw4+HjTcYi9xzgy1hnKQZ7mYSofgRO42bwN7iZulaLvb8dG1giz0g== + dependencies: + "@oclif/core" "^4" + "@types/react" "^18.3.11" + change-case "^5.4.4" + cli-truncate "^4.0.0" + ink "^5.0.1" + natural-orderby "^3.0.2" + object-hash "^3.0.0" + react "^18.3.1" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -1471,7 +1487,7 @@ resolved "https://registry.yarnpkg.com/@salesforce/schemas/-/schemas-1.9.0.tgz#ba477a112653a20b4edcf989c61c57bdff9aa3ca" integrity sha512-LiN37zG5ODT6z70sL1fxF7BQwtCX9JOWofSU8iliSNIM+WDEeinnoFtVqPInRSNt8I0RiJxIKCrqstsmQRBNvA== -"@salesforce/sf-plugins-core@^11.3.10", "@salesforce/sf-plugins-core@^11.3.12", "@salesforce/sf-plugins-core@^11.3.5": +"@salesforce/sf-plugins-core@^11.3.10", "@salesforce/sf-plugins-core@^11.3.5": version "11.3.12" resolved "https://registry.yarnpkg.com/@salesforce/sf-plugins-core/-/sf-plugins-core-11.3.12.tgz#18b3a553688428bcffea9d36abc72847497f06ae" integrity sha512-hi8EcSoRHRxj4sm/V5YDtzq9bPr/cKpM4fC6abo/jRzpXygwizinc2gVQkXfVdhjK7NGMskVRQB1N+0TThG7bA== @@ -1489,6 +1505,25 @@ string-width "^7.2.0" terminal-link "^3.0.0" +"@salesforce/sf-plugins-core@^12.0.4": + version "12.0.4" + resolved "https://registry.yarnpkg.com/@salesforce/sf-plugins-core/-/sf-plugins-core-12.0.4.tgz#b78aa0747ab0b861268bf72b2743217a6b0275c5" + integrity sha512-fIzr6AZbeY5mqFfDHPyN09eVH0qYkkKVf2jB375YaWZZ8WKTqtYQnwaKd3Gi9asggvMKnmI91ov6aFGKCdA1qg== + dependencies: + "@inquirer/confirm" "^3.1.22" + "@inquirer/password" "^2.2.0" + "@oclif/core" "^4.0.27" + "@oclif/table" "^0.1.24" + "@salesforce/core" "^8.5.1" + "@salesforce/kit" "^3.2.3" + "@salesforce/ts-types" "^2.0.12" + ansis "^3.3.2" + cli-progress "^3.12.0" + natural-orderby "^3.0.2" + slice-ansi "^7.1.0" + string-width "^7.2.0" + terminal-link "^3.0.0" + "@salesforce/source-deploy-retrieve@^12.7.1", "@salesforce/source-deploy-retrieve@^12.7.4": version "12.7.4" resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.7.4.tgz#57d3156d1fb5f0ac7021e8e9f871358adaf31b0d" @@ -3127,6 +3162,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" @@ -6294,6 +6334,11 @@ nyc@^17.0.0: test-exclude "^6.0.0" yargs "^15.0.2" +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + object-inspect@^1.13.1: version "1.13.1" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"