diff --git a/src/collections/decodeableMap.ts b/src/collections/decodeableMap.ts index c73701d0b1..8cce0cfe5a 100644 --- a/src/collections/decodeableMap.ts +++ b/src/collections/decodeableMap.ts @@ -4,6 +4,8 @@ * 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 { Logger } from '@salesforce/core'; +import { isString } from '@salesforce/ts-types'; /** * This is an extension of the Map class that can match keys whether they are encoded or decoded. @@ -29,6 +31,8 @@ export class DecodeableMap extends Map { // before `this.set()` is called or `TypeErrors` will be thrown. private internalkeysMap!: Map; + private internalLogger!: Logger; + private get keysMap(): Map { if (!this.internalkeysMap) { this.internalkeysMap = new Map(); @@ -36,6 +40,13 @@ export class DecodeableMap extends Map { return this.internalkeysMap; } + private get logger(): Logger { + if (!this.internalLogger) { + this.internalLogger = Logger.childFromRoot(this.constructor.name); + } + return this.internalLogger; + } + /** * boolean indicating whether an element with the specified key (matching decoded) exists or not. */ @@ -77,21 +88,27 @@ export class DecodeableMap extends Map { if (super.has(key)) { return key; } else { - const decodedKey = decodeURIComponent(key); - if (key !== decodedKey) { - // The key is encoded; If this is part of a set operation, - // set the { decodedKey : encodedKey } in the internal map. - if (setInKeysMap) { - this.keysMap.set(decodedKey, key); - } - if (super.has(decodedKey)) { - return decodedKey; - } - } else { - const encodedKey = this.keysMap.get(decodedKey); - if (encodedKey && super.has(encodedKey)) { - return encodedKey; + try { + const decodedKey = decodeURIComponent(key); + if (key !== decodedKey) { + // The key is encoded; If this is part of a set operation, + // set the { decodedKey : encodedKey } in the internal map. + if (setInKeysMap) { + this.keysMap.set(decodedKey, key); + } + if (super.has(decodedKey)) { + return decodedKey; + } + } else { + const encodedKey = this.keysMap.get(decodedKey); + if (encodedKey && super.has(encodedKey)) { + return encodedKey; + } } + } catch (e: unknown) { + // Log the error and the key + const errMsg = e instanceof Error ? e.message : isString(e) ? e : 'unknown'; + this.logger.debug(`Could not decode metadata key: ${key} due to: ${errMsg}`); } } } diff --git a/test/collections/decodeableMap.test.ts b/test/collections/decodeableMap.test.ts index 94dd1ea5ef..9ad877275b 100644 --- a/test/collections/decodeableMap.test.ts +++ b/test/collections/decodeableMap.test.ts @@ -76,6 +76,12 @@ describe('DecodeableMap', () => { expect(hasMapSpy.calledWith(nonExistent_key_encoded)).to.be.true; expect(hasMapSpy.calledWith(nonExistent_key_decoded)).to.be.true; }); + + it('should not match non-decodeable key', () => { + // trying to decode '%E0%A4%A' throws a URIError so DecodeableMap + // should not throw when a non-decodeable key is encountered. + expect(dMap.has('%E0%A4%A')).to.be.false; + }); }); describe('get()', () => {