From b0790f383aa207e436368a237d3cca8e1a5a944a Mon Sep 17 00:00:00 2001 From: mshanemc Date: Wed, 18 Oct 2023 17:33:11 -0500 Subject: [PATCH] feat!: drop support for lodash-style deep get/set --- src/config/configStore.ts | 36 +++++----------- src/config/lwwMap.ts | 1 - test/unit/config/configStoreTest.ts | 66 +++-------------------------- 3 files changed, 15 insertions(+), 88 deletions(-) diff --git a/src/config/configStore.ts b/src/config/configStore.ts index 51ac8f5990..4de168bb0f 100644 --- a/src/config/configStore.ts +++ b/src/config/configStore.ts @@ -5,9 +5,9 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import { AsyncOptionalCreatable, cloneJson, set } from '@salesforce/kit'; +import { AsyncOptionalCreatable, cloneJson } from '@salesforce/kit'; import { entriesOf, isPlainObject } from '@salesforce/ts-types'; -import { definiteEntriesOf, definiteValuesOf, get, isJsonMap, isString, JsonMap, Optional } from '@salesforce/ts-types'; +import { definiteEntriesOf, definiteValuesOf, isJsonMap, isString, JsonMap, Optional } from '@salesforce/ts-types'; import { Crypto } from '../crypto/crypto'; import { SfError } from '../sfError'; import { LWWMap, stateFromContents } from './lwwMap'; @@ -85,24 +85,23 @@ export abstract class BaseConfigStore< /** * Returns the value associated to the key, or undefined if there is none. * - * @param key The key. Supports query key like `a.b[0]`. + * @param key The key (object property) * @param decrypt If it is an encrypted key, decrypt the value. * If the value is an object, a clone will be returned. */ public get>(key: K, decrypt?: boolean): P[K]; public get(key: string, decrypt?: boolean): V; public get>(key: K | string, decrypt = false): P[K] | ConfigValue { - const k = key as string; - let value = this.getMethod(this.contents.value ?? {}, k); + const rawValue = this.contents.get(key as K); if (this.hasEncryption() && decrypt) { - if (isJsonMap(value)) { - value = this.recursiveDecrypt(cloneJson(value), k); - } else if (this.isCryptoKey(k)) { - value = this.decrypt(value); + if (isJsonMap(rawValue)) { + return this.recursiveDecrypt(cloneJson(rawValue), key); + } else if (this.isCryptoKey(key)) { + return this.decrypt(rawValue) as P[K] | ConfigValue; } } - return value as P[K]; + return rawValue as P[K] | ConfigValue; } /** @@ -302,21 +301,6 @@ export abstract class BaseConfigStore< return this.getEncryptedKeys().length > 0; } - // Allows extended classes the ability to override the set method. i.e. maybe they want - // nested object set from kit. - // eslint-disable-next-line class-methods-use-this - protected setMethod(contents: ConfigContents, key: string, value?: ConfigValue): void { - set(contents, key, value); - } - - // Allows extended classes the ability to override the get method. i.e. maybe they want - // nested object get from ts-types. - // NOTE: Key must stay string to be reliably overwritten. - // eslint-disable-next-line class-methods-use-this - protected getMethod(contents: ConfigContents, key: string): Optional { - return get(contents, key) as ConfigValue; - } - // eslint-disable-next-line class-methods-use-this protected initialContents(): P { return {} as P; @@ -389,7 +373,7 @@ export abstract class BaseConfigStore< return this.crypto.isEncrypted(value) ? value : this.crypto.encrypt(value); } - protected decrypt(value: unknown): Optional { + protected decrypt(value: unknown): string | undefined { if (!value) return; if (!this.crypto) throw new SfError('crypto is not initialized', 'CryptoNotInitializedError'); if (!isString(value)) diff --git a/src/config/lwwMap.ts b/src/config/lwwMap.ts index f37c7bcbb1..2cf99cb096 100644 --- a/src/config/lwwMap.ts +++ b/src/config/lwwMap.ts @@ -86,7 +86,6 @@ export class LWWMap

{ else this.#data.set(key, new LWWRegister(this.id, { peer: this.id, timestamp: process.hrtime.bigint(), value })); } - // TODO: how to handle the deep `get` that is currently allowed ex: get('foo.bar.baz') public get>(key: K): P[K] | undefined { // map loses the typing const value = this.#data.get(key)?.value; diff --git a/test/unit/config/configStoreTest.ts b/test/unit/config/configStoreTest.ts index 4378064be7..96204f7b2c 100644 --- a/test/unit/config/configStoreTest.ts +++ b/test/unit/config/configStoreTest.ts @@ -68,7 +68,6 @@ describe('ConfigStore', () => { config.get('1').a = 'b'; expect(config.get('1').a).to.equal('b'); - expect(config.get('1.a')).to.equal('b'); }); it('updates the object reference', async () => { @@ -146,60 +145,6 @@ describe('ConfigStore', () => { expect(config.get('owner', true).superPassword).to.equal(expected); }); - describe.skip('TODO: set with deep (dots/accessors) keys', () => { - it('encrypts nested query key using dot notation', async () => { - const expected = 'a29djf0kq3dj90d3q'; - const config = await CarConfig.create(); - config.set('owner.creditCardNumber', expected); - // encrypted - expect(config.get('owner.creditCardNumber')).to.not.equal(expected); - // decrypted - expect(config.get('owner.creditCardNumber', true)).to.equal(expected); - }); - - it('encrypts nested query key using accessor with single quotes', async () => { - const expected = 'a29djf0kq3dj90d3q'; - const config = await CarConfig.create(); - config.set('owner["creditCardNumber"]', expected); - // encrypted - expect(config.get("owner['creditCardNumber']")).to.not.equal(expected); - // decrypted - expect(config.get("owner['creditCardNumber']", true)).to.equal(expected); - }); - - it('encrypts nested query key using accessor with double quotes', async () => { - const expected = 'a29djf0kq3dj90d3q'; - const config = await CarConfig.create(); - config.set('owner["creditCardNumber"]', expected); - // encrypted - expect(config.get('owner["creditCardNumber"]')).to.not.equal(expected); - // decrypted - expect(config.get('owner["creditCardNumber"]', true)).to.equal(expected); - }); - - it('encrypts nested query special key using accessor with single quotes', async () => { - const expected = 'a29djf0kq3dj90d3q'; - const config = await CarConfig.create(); - const query = `owner['${specialKey}']`; - config.set(query, expected); - // encrypted - expect(config.get(query)).to.not.equal(expected); - // decrypted - expect(config.get(query, true)).to.equal(expected); - }); - - it('encrypts nested query special key using accessor with double quotes', async () => { - const expected = 'a29djf0kq3dj90d3q'; - const config = await CarConfig.create(); - const query = `owner["${specialKey}"]`; - config.set(query, expected); - // encrypted - expect(config.get(query)).to.not.equal(expected); - // decrypted - expect(config.get(query, true)).to.equal(expected); - }); - }); - it('decrypt returns copies', async () => { const expected = 'a29djf0kq3dj90d3q'; const config = await CarConfig.create(); @@ -213,7 +158,6 @@ describe('ConfigStore', () => { decryptedOwner.creditCardNumber = 'invalid'; expect(config.get('owner').creditCardNumber).to.not.equal('invalid'); expect(config.get('owner', true).creditCardNumber).to.equal(expected); - expect(config.get('owner.creditCardNumber', true)).to.equal(expected); }); // Ensures accessToken and refreshToken are both decrypted upon config.get() @@ -236,12 +180,12 @@ describe('ConfigStore', () => { const config = await CarConfig.create(); const owner = { name: 'Bob', creditCardNumber: expected }; config.set('owner', owner); - const encryptedCreditCardNumber = config.get('owner.creditCardNumber'); + const encryptedCreditCardNumber = config.get('owner').creditCardNumber; const contents = config.getContents(); contents.owner.name = 'Tim'; config.setContents(contents); - expect(config.get('owner.name')).to.equal(contents.owner.name); - expect(config.get('owner.creditCardNumber')).to.equal(encryptedCreditCardNumber); + expect(config.get('owner').name).to.equal(contents.owner.name); + expect(config.get('owner').creditCardNumber).to.equal(encryptedCreditCardNumber); }); it('updates encrypted object', async () => { @@ -252,8 +196,8 @@ describe('ConfigStore', () => { config.update('owner', { creditCardNumber: expected }); - expect(config.get('owner.name')).to.equal(owner.name); - expect(config.get('owner.creditCardNumber', true)).to.equal(expected); + expect(config.get('owner').name).to.equal(owner.name); + expect(config.get('owner', true).creditCardNumber).to.equal(expected); }); }); });