Skip to content

Commit 083b7c5

Browse files
committed
fix: decompose by any folder name
1 parent 406a43a commit 083b7c5

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

src/convert/transformers/decomposedMetadataTransformer.ts

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
77
import { dirname, join } from 'node:path';
8-
import { JsonMap } from '@salesforce/ts-types';
8+
import { AnyJson, JsonMap, getString, isJsonMap } from '@salesforce/ts-types';
99
import { ensureArray } from '@salesforce/kit';
1010
import { Messages } from '@salesforce/core';
1111
import { MetadataComponent, SourceComponent } from '../../resolve';
@@ -70,9 +70,10 @@ export class DecomposedMetadataTransformer extends BaseMetadataTransformer {
7070
if (!childType) {
7171
throw messages.createError('error_missing_child_type_definition', [type.name, childTypeId]);
7272
}
73-
const tagValues = ensureArray(tagValue);
74-
for (const value of tagValues as [{ fullName: string; name: string }]) {
75-
const entryName = value.fullName || value.name;
73+
const tagValues = ensureArray(tagValue).filter(isJsonMap);
74+
// iterate each array member if it's Object-like (ex: customField of a CustomObject)
75+
for (const value of tagValues) {
76+
const entryName = extractUniqueElementValue(value, childType.uniqueIdElement);
7677
const childComponent: MetadataComponent = {
7778
fullName: `${parentFullName}.${entryName}`,
7879
type: childType,
@@ -196,7 +197,7 @@ export class DecomposedMetadataTransformer extends BaseMetadataTransformer {
196197
forComponent: MetadataComponent,
197198
props: Partial<Omit<DecompositionStateValue, 'origin'>> = {}
198199
): void {
199-
const key = `${forComponent.type.name}#${forComponent.fullName}`;
200+
const key = getKey(forComponent);
200201
const withOrigin = Object.assign({ origin: forComponent.parent ?? forComponent }, props);
201202
this.context.decomposition.transactionState.set(key, {
202203
...(this.context.decomposition.transactionState.get(key) ?? {}),
@@ -205,26 +206,37 @@ export class DecomposedMetadataTransformer extends BaseMetadataTransformer {
205206
}
206207

207208
private getDecomposedState(forComponent: MetadataComponent): DecompositionStateValue | undefined {
208-
const key = `${forComponent.type.name}#${forComponent.fullName}`;
209-
return this.context.decomposition.transactionState.get(key);
209+
return this.context.decomposition.transactionState.get(getKey(forComponent));
210210
}
211211
}
212212

213-
const getComposedMetadataEntries = async (
214-
component: SourceComponent
215-
): Promise<Array<[string, { fullname?: string; name?: string }]>> => {
213+
const getKey = (component: MetadataComponent): string => `${component.type.name}#${component.fullName}`;
214+
215+
const getComposedMetadataEntries = async (component: SourceComponent): Promise<Array<[string, AnyJson]>> => {
216216
const composedMetadata = (await component.parseXml())[component.type.name];
217217
// composedMetadata might be undefined if you call toSourceFormat() from a non-source-backed Component
218218
return composedMetadata ? Object.entries(composedMetadata) : [];
219219
};
220220

221+
/** where the file goes if there's nothing to merge with */
221222
const getDefaultOutput = (component: MetadataComponent): SourcePath => {
222223
const { parent, fullName, type } = component;
223-
const [baseName, childName] = fullName.split('.');
224+
const [baseName, ...tail] = fullName.split('.');
225+
// there could be a '.' inside the child name (ex: PermissionSet.FieldPermissions.field uses Obj__c.Field__c)
226+
// we put folders for each object in (ex) FieldPermissions because of the dot
227+
const childName = tail.length ? join(...tail) : undefined;
224228
const baseComponent = (parent ?? component) as SourceComponent;
225-
let output = `${childName ?? baseName}.${component.type.suffix}${META_XML_SUFFIX}`;
226-
if (parent?.type.strategies?.decomposition === DecompositionStrategy.FolderPerType) {
227-
output = join(type.directoryName, output);
228-
}
229+
const output = join(
230+
parent?.type.strategies?.decomposition === DecompositionStrategy.FolderPerType ? type.directoryName : '',
231+
`${childName ?? baseName}.${component.type.suffix}${META_XML_SUFFIX}`
232+
);
229233
return join(baseComponent.getPackageRelativePath(baseName, 'source'), output);
230234
};
235+
236+
/** handle wide-open reading of values from elements inside any metadata xml file.
237+
* Return the value of the matching element if supplied, or defaults `fullName` then `name` */
238+
const extractUniqueElementValue = (xml: JsonMap, elementName?: string): string | undefined =>
239+
elementName ? getString(xml, elementName) ?? getStandardElements(xml) : getStandardElements(xml);
240+
241+
const getStandardElements = (xml: JsonMap): string | undefined =>
242+
getString(xml, 'fullName') ?? getString(xml, 'name') ?? undefined;

0 commit comments

Comments
 (0)