From 9d24d82273ae5bf42ed6ef265dd841537a18c563 Mon Sep 17 00:00:00 2001 From: Steve Hetzel Date: Tue, 15 Aug 2023 17:32:46 -0600 Subject: [PATCH] fix: move DecodeableMap to a new file --- src/collections/componentSet.ts | 77 ++----------------------------- src/collections/decodeableMap.ts | 78 ++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 74 deletions(-) create mode 100644 src/collections/decodeableMap.ts diff --git a/src/collections/componentSet.ts b/src/collections/componentSet.ts index 62fdbf0f49..bea09a5346 100644 --- a/src/collections/componentSet.ts +++ b/src/collections/componentSet.ts @@ -34,6 +34,7 @@ import { PackageTypeMembers, } from './types'; import { LazyCollection } from './lazyCollection'; +import { DecodeableMap } from './decodeableMap'; Messages.importMessagesDirectory(__dirname); const messages = Messages.loadMessages('@salesforce/source-deploy-retrieve', 'sdr'); @@ -43,78 +44,6 @@ export type RetrieveSetOptions = Omit; const KEY_DELIMITER = '#'; -/** - * This is an extension of the Map class that treats keys as the same by matching first normally, - * then decoded. Decoding the key before comparing can solve some edge cases in component fullNames - * such as Layouts. See: https://github.com/forcedotcom/cli/issues/1683 - * - * Examples: - * - * Given a map with entries: - * ```javascript - * 'layout#Layout__Broker__c-v1%2E1 Broker Layout' : {...} - * 'layout#Layout__Broker__c-v9.2 Broker Layout' : {...} - * ``` - * - * `decodeableMap.has('layout#Layout__Broker__c-v1.1 Broker Layout')` --> returns `true` - * `decodeableMap.has('layout#Layout__Broker__c-v9%2E2 Broker Layout')` --> returns `true` - */ -class DecodeableMap extends Map { - /** - * boolean indicating whether an element with the specified key (matching decoded) exists or not. - */ - public has(key: K): boolean { - return super.has(key) || this.hasDecoded(key); - } - - /** - * Returns a specified element from the Map object. If the value that is associated to - * the provided key (matching decoded) is an object, then you will get a reference to - * that object and any change made to that object will effectively modify it inside the Map. - */ - public get(key: K): V | undefined { - return super.get(key) ?? this.getDecoded(key); - } - - /** - * Adds a new element with a specified key and value to the Map. If an element with the - * same key (matching decoded) already exists, the element will be updated. - */ - public set(key: K, value: V): this { - const sKey = this.getExistingKey(key) ?? key; - return super.set(sKey, value); - } - - /** - * true if an element in the Map existed (matching decoded) and has been removed, or false - * if the element does not exist. - */ - public delete(key: K): boolean { - const sKey = this.getExistingKey(key) ?? key; - return super.delete(sKey); - } - - // Returns true if the passed `key` matches an existing key entry when both keys are decoded. - private hasDecoded(key: string): boolean { - return !!this.getExistingKey(key); - } - - // Returns the value of an entry matching on decoded keys. - private getDecoded(key: string): V | undefined { - const existingKey = this.getExistingKey(key); - return existingKey ? super.get(existingKey) : undefined; - } - - // Returns the key as it is in the map, matching on decoded keys. - private getExistingKey(key: string): string | undefined { - for (const compKey of this.keys()) { - if (decodeURIComponent(compKey) === decodeURIComponent(key)) { - return compKey; - } - } - } -} - /** * A collection containing no duplicate metadata members (`fullName` and `type` pairs). `ComponentSets` * are a convenient way of constructing a unique collection of components to perform operations such as @@ -184,11 +113,11 @@ export class ComponentSet extends LazyCollection { return size; } - public get destructiveChangesPre(): Map> { + public get destructiveChangesPre(): DecodeableMap> { return this.destructiveComponents[DestructiveChangesType.PRE]; } - public get destructiveChangesPost(): Map> { + public get destructiveChangesPost(): DecodeableMap> { return this.destructiveComponents[DestructiveChangesType.POST]; } diff --git a/src/collections/decodeableMap.ts b/src/collections/decodeableMap.ts new file mode 100644 index 0000000000..86edacb720 --- /dev/null +++ b/src/collections/decodeableMap.ts @@ -0,0 +1,78 @@ +/* + * 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 + */ + +/** + * This is an extension of the Map class that treats keys as the same by matching first normally, + * then decoded. Decoding the key before comparing can solve some edge cases in component fullNames + * such as Layouts. See: https://github.com/forcedotcom/cli/issues/1683 + * + * Examples: + * + * Given a map with entries: + * ```javascript + * 'layout#Layout__Broker__c-v1%2E1 Broker Layout' : {...} + * 'layout#Layout__Broker__c-v9.2 Broker Layout' : {...} + * ``` + * + * `decodeableMap.has('layout#Layout__Broker__c-v1.1 Broker Layout')` --> returns `true` + * `decodeableMap.has('layout#Layout__Broker__c-v9%2E2 Broker Layout')` --> returns `true` + */ +export class DecodeableMap extends Map { + /** + * boolean indicating whether an element with the specified key (matching decoded) exists or not. + */ + public has(key: K): boolean { + return super.has(key) || this.hasDecoded(key); + } + + /** + * Returns a specified element from the Map object. If the value that is associated to + * the provided key (matching decoded) is an object, then you will get a reference to + * that object and any change made to that object will effectively modify it inside the Map. + */ + public get(key: K): V | undefined { + return super.get(key) ?? this.getDecoded(key); + } + + /** + * Adds a new element with a specified key and value to the Map. If an element with the + * same key (matching decoded) already exists, the element will be updated. + */ + public set(key: K, value: V): this { + const sKey = this.getExistingKey(key) ?? key; + return super.set(sKey, value); + } + + /** + * true if an element in the Map existed (matching decoded) and has been removed, or false + * if the element does not exist. + */ + public delete(key: K): boolean { + const sKey = this.getExistingKey(key) ?? key; + return super.delete(sKey); + } + + // Returns true if the passed `key` matches an existing key entry when both keys are decoded. + private hasDecoded(key: string): boolean { + return !!this.getExistingKey(key); + } + + // Returns the value of an entry matching on decoded keys. + private getDecoded(key: string): V | undefined { + const existingKey = this.getExistingKey(key); + return existingKey ? super.get(existingKey) : undefined; + } + + // Returns the key as it is in the map, matching on decoded keys. + private getExistingKey(key: string): string | undefined { + for (const compKey of this.keys()) { + if (decodeURIComponent(compKey) === decodeURIComponent(key)) { + return compKey; + } + } + } +}