From 06ed78745ac544f067e377427c8b20ba0b5f06d7 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Mon, 18 Sep 2023 10:41:57 -0500 Subject: [PATCH 1/6] fix: disallow undefined xml --- src/utils/types.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utils/types.ts b/src/utils/types.ts index 4dfec7cce..eab528c24 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -102,7 +102,12 @@ export type Formatter = { /** validates source component with fullname, type, and xml props */ export const isSourceComponent = (sc: unknown): sc is SourceComponent & { xml: string } => - isObject(sc) && 'fullName' in sc && 'type' in sc && 'xml' in sc; + isObject(sc) && + 'fullName' in sc && + 'type' in sc && + 'xml' in sc && + typeof sc.xml === 'string' && + typeof sc.fullName === 'string'; export const isSdrFailure = (fileResponse: FileResponse): fileResponse is FileResponseFailure => fileResponse.state === ComponentStatus.Failed; From fa9f51f417a619d99e0b11281b389948f425f3ea Mon Sep 17 00:00:00 2001 From: mshanemc Date: Mon, 18 Sep 2023 12:31:14 -0500 Subject: [PATCH 2/6] test: add ut and require `type` to be present --- src/utils/types.ts | 5 +++-- test/utils/types.test.ts | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 test/utils/types.test.ts diff --git a/src/utils/types.ts b/src/utils/types.ts index eab528c24..30dc13b9f 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -106,8 +106,9 @@ export const isSourceComponent = (sc: unknown): sc is SourceComponent & { xml: s 'fullName' in sc && 'type' in sc && 'xml' in sc && - typeof sc.xml === 'string' && - typeof sc.fullName === 'string'; + typeof sc.fullName === 'string' && + typeof sc.type === 'string' && + typeof sc.xml === 'string'; export const isSdrFailure = (fileResponse: FileResponse): fileResponse is FileResponseFailure => fileResponse.state === ComponentStatus.Failed; diff --git a/test/utils/types.test.ts b/test/utils/types.test.ts new file mode 100644 index 000000000..a9795629e --- /dev/null +++ b/test/utils/types.test.ts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023, 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 { expect } from 'chai'; +import { SourceComponent } from '@salesforce/source-deploy-retrieve'; +import { RegistryAccess } from '@salesforce/source-deploy-retrieve'; +import { isSourceComponent } from '../../src/utils/types'; + +describe('isSourceComponent (type guard)', () => { + describe('good', () => { + it('full, correct definition', () => { + expect({ fullName: 'foo', type: 'fooType', xml: 'fooXml', content: 'fooContent' }).to.satisfy(isSourceComponent); + }); + it('SC constructed with xml', () => { + const reg = new RegistryAccess(); + const type = reg.getTypeByName('ApexClass'); + expect(new SourceComponent({ name: 'foo', type, xml: 'classes/foo.cls' })).to.not.satisfy(isSourceComponent); + }); + }); + describe('bad', () => { + it('object is undefined', () => { + expect(undefined).to.not.satisfy(isSourceComponent); + }); + it('empty object', () => { + expect({}).to.not.satisfy(isSourceComponent); + }); + it('object.xml is undefined', () => { + expect({ fullName: 'foo', type: 'fooType', content: 'fooContent' }).to.not.satisfy(isSourceComponent); + }); + it('object.type is set to undefined', () => { + expect({ fullName: 'foo', type: undefined, xml: 'fooXml' }).to.not.satisfy(isSourceComponent); + }); + it('SC constructed with no xml', () => { + const reg = new RegistryAccess(); + const type = reg.getTypeByName('ApexClass'); + expect(new SourceComponent({ name: 'foo', type })).to.not.satisfy(isSourceComponent); + }); + }); +}); From 0552fef87cd8fc8735ab6ce22a2b0fa5c9191f40 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Mon, 18 Sep 2023 12:32:19 -0500 Subject: [PATCH 3/6] style: one import from sdr --- test/utils/types.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/utils/types.test.ts b/test/utils/types.test.ts index a9795629e..244ab6e27 100644 --- a/test/utils/types.test.ts +++ b/test/utils/types.test.ts @@ -6,8 +6,7 @@ */ import { expect } from 'chai'; -import { SourceComponent } from '@salesforce/source-deploy-retrieve'; -import { RegistryAccess } from '@salesforce/source-deploy-retrieve'; +import { SourceComponent, RegistryAccess } from '@salesforce/source-deploy-retrieve'; import { isSourceComponent } from '../../src/utils/types'; describe('isSourceComponent (type guard)', () => { From f3fa732cf4005d2d9eab5461b7263764dc002c1e Mon Sep 17 00:00:00 2001 From: mshanemc Date: Mon, 18 Sep 2023 12:34:06 -0500 Subject: [PATCH 4/6] chore: lockfile dedupe --- yarn.lock | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/yarn.lock b/yarn.lock index 29ed13785..8991e2255 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1558,12 +1558,7 @@ dependencies: "@types/node" "*" -"@types/semver@^7.3.12": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" - integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== - -"@types/semver@^7.5.1": +"@types/semver@^7.3.12", "@types/semver@^7.5.1": version "7.5.2" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== @@ -6607,15 +6602,7 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pino-abstract-transport@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz#cc0d6955fffcadb91b7b49ef220a6cc111d48bb3" - integrity sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA== - dependencies: - readable-stream "^4.0.0" - split2 "^4.0.0" - -pino-abstract-transport@v1.1.0: +pino-abstract-transport@^1.0.0, pino-abstract-transport@v1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.1.0.tgz#083d98f966262164504afb989bccd05f665937a8" integrity sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA== From c9288ffcdd6282150afb6ae70a0ea842d70529d3 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Mon, 18 Sep 2023 13:02:45 -0500 Subject: [PATCH 5/6] test: more coverage and cases for typeguard and SC --- src/utils/previewOutput.ts | 4 +-- src/utils/types.ts | 17 ++++++++----- test/utils/types.test.ts | 52 ++++++++++++++++++++++++++++++-------- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/utils/previewOutput.ts b/src/utils/previewOutput.ts index 62e088cc1..158957e06 100644 --- a/src/utils/previewOutput.ts +++ b/src/utils/previewOutput.ts @@ -21,7 +21,7 @@ import { import { filePathsFromMetadataComponent } from '@salesforce/source-deploy-retrieve/lib/src/utils/filePathGenerator'; import { SourceTracking } from '@salesforce/source-tracking'; -import { isSourceComponent } from './types'; +import { isSourceComponentWithXml } from './types'; Messages.importMessagesDirectory(__dirname); const messages = Messages.loadMessages('@salesforce/plugin-deploy-retrieve', 'previewMessages'); @@ -64,7 +64,7 @@ const resolvePaths = (filenames: string[]): Array ({ fullName: sc.fullName, type: sc.type.name, path: ensureAbsolutePath(sc.xml) })); // dedupe by xml path return Array.from(new Map(sourceComponents.map((sc) => [sc.path, sc])).values()); diff --git a/src/utils/types.ts b/src/utils/types.ts index 30dc13b9f..0e316ad6a 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -101,14 +101,19 @@ export type Formatter = { }; /** validates source component with fullname, type, and xml props */ -export const isSourceComponent = (sc: unknown): sc is SourceComponent & { xml: string } => +export const isSourceComponent = (sc: unknown): sc is SourceComponent => isObject(sc) && - 'fullName' in sc && 'type' in sc && - 'xml' in sc && - typeof sc.fullName === 'string' && - typeof sc.type === 'string' && - typeof sc.xml === 'string'; + typeof sc.type === 'object' && + sc.type !== null && + 'name' in sc.type && + typeof sc.type.name === 'string' && + 'fullName' in sc && + // (typeof sc.fullName === 'string' || typeof sc.fullName === 'function'); + typeof sc.fullName === 'string'; + +export const isSourceComponentWithXml = (sc: unknown): sc is SourceComponent & { xml: string } => + isSourceComponent(sc) && 'xml' in sc && typeof sc.xml === 'string'; export const isSdrFailure = (fileResponse: FileResponse): fileResponse is FileResponseFailure => fileResponse.state === ComponentStatus.Failed; diff --git a/test/utils/types.test.ts b/test/utils/types.test.ts index 244ab6e27..19fa572fa 100644 --- a/test/utils/types.test.ts +++ b/test/utils/types.test.ts @@ -5,19 +5,28 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import { expect } from 'chai'; +import { expect, config } from 'chai'; import { SourceComponent, RegistryAccess } from '@salesforce/source-deploy-retrieve'; -import { isSourceComponent } from '../../src/utils/types'; +import { isSourceComponent, isSourceComponentWithXml } from '../../src/utils/types'; + +config.truncateThreshold = 0; + +const reg = new RegistryAccess(); +const type = reg.getTypeByName('ApexClass'); describe('isSourceComponent (type guard)', () => { describe('good', () => { it('full, correct definition', () => { - expect({ fullName: 'foo', type: 'fooType', xml: 'fooXml', content: 'fooContent' }).to.satisfy(isSourceComponent); + expect({ fullName: 'foo', type, xml: 'fooXml', content: 'fooContent' }).to.satisfy(isSourceComponent); }); it('SC constructed with xml', () => { - const reg = new RegistryAccess(); - const type = reg.getTypeByName('ApexClass'); - expect(new SourceComponent({ name: 'foo', type, xml: 'classes/foo.cls' })).to.not.satisfy(isSourceComponent); + expect(new SourceComponent({ name: 'foo', type, xml: 'classes/foo.cls' })).to.satisfy(isSourceComponent); + }); + it('SC constructed with no xml', () => { + const sc = new SourceComponent({ name: 'foo', type }); + // console.log(sc); + // console.log(typeof sc.fullName); + expect(sc).to.satisfy(isSourceComponent); }); }); describe('bad', () => { @@ -27,16 +36,37 @@ describe('isSourceComponent (type guard)', () => { it('empty object', () => { expect({}).to.not.satisfy(isSourceComponent); }); + + it('object.type is set to undefined', () => { + expect({ fullName: 'foo', type: undefined, xml: 'fooXml' }).to.not.satisfy(isSourceComponent); + }); + }); +}); + +describe('isSourceComponentWithXml (type guard)', () => { + describe('good', () => { + it('full, correct definition', () => { + expect({ fullName: 'foo', type, xml: 'fooXml', content: 'fooContent' }).to.satisfy(isSourceComponentWithXml); + }); + it('SC constructed with xml', () => { + expect(new SourceComponent({ name: 'foo', type, xml: 'classes/foo.cls' })).to.satisfy(isSourceComponentWithXml); + }); + }); + describe('bad', () => { + it('object is undefined', () => { + expect(undefined).to.not.satisfy(isSourceComponentWithXml); + }); + it('empty object', () => { + expect({}).to.not.satisfy(isSourceComponentWithXml); + }); it('object.xml is undefined', () => { - expect({ fullName: 'foo', type: 'fooType', content: 'fooContent' }).to.not.satisfy(isSourceComponent); + expect({ fullName: 'foo', type: 'fooType', content: 'fooContent' }).to.not.satisfy(isSourceComponentWithXml); }); it('object.type is set to undefined', () => { - expect({ fullName: 'foo', type: undefined, xml: 'fooXml' }).to.not.satisfy(isSourceComponent); + expect({ fullName: 'foo', type: undefined, xml: 'fooXml' }).to.not.satisfy(isSourceComponentWithXml); }); it('SC constructed with no xml', () => { - const reg = new RegistryAccess(); - const type = reg.getTypeByName('ApexClass'); - expect(new SourceComponent({ name: 'foo', type })).to.not.satisfy(isSourceComponent); + expect(new SourceComponent({ name: 'foo', type })).to.not.satisfy(isSourceComponentWithXml); }); }); }); From 6a73a918bb038c7651036165805da70b74b0a41c Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Mon, 18 Sep 2023 17:04:01 -0300 Subject: [PATCH 6/6] fix: bump SDR --- package.json | 2 +- yarn.lock | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index eedebb8e1..6e176f1bf 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "@salesforce/core": "^5.2.7", "@salesforce/kit": "^3.0.9", "@salesforce/sf-plugins-core": "^3.1.22", - "@salesforce/source-deploy-retrieve": "^9.7.13", + "@salesforce/source-deploy-retrieve": "^9.7.15", "@salesforce/source-tracking": "^4.2.12", "chalk": "^4.1.2", "shelljs": "^0.8.5", diff --git a/yarn.lock b/yarn.lock index 8991e2255..5c10eb1e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -956,15 +956,15 @@ strip-ansi "6.0.1" ts-retry-promise "^0.7.0" -"@salesforce/core@^5.2.0", "@salesforce/core@^5.2.6", "@salesforce/core@^5.2.7": - version "5.2.9" - resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-5.2.9.tgz#812478061d766cdff28f7a0e8abefc9de562465a" - integrity sha512-ZWNxHnCPGT1pcJe1bjeRjd8VAeHELK4fftt/2WO+ZsPFHZnzmdowz2Th407v04et+uIzL0Z6+qOaRY/bZr5tLA== +"@salesforce/core@^5.2.0", "@salesforce/core@^5.2.6", "@salesforce/core@^5.2.7", "@salesforce/core@^5.2.9": + version "5.2.10" + resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-5.2.10.tgz#7f4824ddcef108b6ccec24434260c620de39012e" + integrity sha512-Xj1QRajmHWgl0ahivjKFGKJlGXwe9yFOZ3PwF91qEupGbO74XrCJ8OUM7EVlk53LKy9LlPZQFuy2ATX9MyEDKA== dependencies: "@salesforce/kit" "^3.0.11" "@salesforce/schemas" "^1.6.0" "@salesforce/ts-types" "^2.0.7" - "@types/semver" "^7.5.1" + "@types/semver" "^7.5.2" ajv "^8.12.0" change-case "^4.1.2" faye "^1.4.0" @@ -1121,12 +1121,12 @@ chalk "^4" inquirer "^8.2.5" -"@salesforce/source-deploy-retrieve@^9.7.13", "@salesforce/source-deploy-retrieve@^9.7.2", "@salesforce/source-deploy-retrieve@^9.7.8": - version "9.7.13" - resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-9.7.13.tgz#85777222e157a621eb00fcef0487c682b7e3d5f7" - integrity sha512-QRhdepll3+ED9w4clI/RvcSLtuSbTzFPZenzrvJ2R7Pg5gXRZQIJrphEkAnY7oteVBBUxPVdYgbeuQxeoi98dg== +"@salesforce/source-deploy-retrieve@^9.7.15", "@salesforce/source-deploy-retrieve@^9.7.2", "@salesforce/source-deploy-retrieve@^9.7.8": + version "9.7.15" + resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-9.7.15.tgz#a891e95101816a7e33854bc42ba21fafbdb1728e" + integrity sha512-av9Ojd9B/uegLNJth41aVPvAVPh8N0CllzfiDG5qbtDXW7WV/bqgWjiiiGc1U6RWnJ9OmQZNL/EjaSX0UPhiLA== dependencies: - "@salesforce/core" "^5.2.7" + "@salesforce/core" "^5.2.9" "@salesforce/kit" "^3.0.11" "@salesforce/ts-types" "^2.0.7" fast-levenshtein "^3.0.0" @@ -1558,7 +1558,7 @@ dependencies: "@types/node" "*" -"@types/semver@^7.3.12", "@types/semver@^7.5.1": +"@types/semver@^7.3.12", "@types/semver@^7.5.1", "@types/semver@^7.5.2": version "7.5.2" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==