Skip to content

Commit c99198b

Browse files
authored
feat: add required child type entries to manifest (#446)
* feat: add required child type entries to manifest * test: update test comment
1 parent e51977e commit c99198b

File tree

7 files changed

+84
-16
lines changed

7 files changed

+84
-16
lines changed

src/collections/componentSet.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
import { LazyCollection } from './lazyCollection';
3131
import { j2xParser } from 'fast-xml-parser';
3232
import { Logger } from '@salesforce/core';
33-
import { RegistryAccess } from '../registry';
33+
import { MetadataType, RegistryAccess } from '../registry';
3434

3535
export type DeploySetOptions = Omit<MetadataApiDeployOptions, 'components'>;
3636
export type RetrieveSetOptions = Omit<MetadataApiRetrieveOptions, 'components'>;
@@ -269,11 +269,21 @@ export class ComponentSet extends LazyCollection<MetadataComponent> {
269269

270270
const typeMap = new Map<string, string[]>();
271271

272-
const addToTypeMap = (typeName: string, fullName: string): void => {
273-
if (!typeMap.has(typeName)) {
274-
typeMap.set(typeName, []);
272+
const addToTypeMap = (type: MetadataType, fullName: string): void => {
273+
if (type.isAddressable !== false) {
274+
const typeName = type.name;
275+
if (!typeMap.has(typeName)) {
276+
typeMap.set(typeName, []);
277+
}
278+
const typeEntry = typeMap.get(typeName);
279+
if (fullName === ComponentSet.WILDCARD) {
280+
typeMap.set(typeName, [fullName]);
281+
} else {
282+
if (!typeEntry.includes(fullName) && !typeEntry.includes(ComponentSet.WILDCARD)) {
283+
typeMap.get(typeName).push(fullName);
284+
}
285+
}
275286
}
276-
typeMap.get(typeName).push(fullName);
277287
};
278288

279289
for (const key of components.keys()) {
@@ -283,17 +293,13 @@ export class ComponentSet extends LazyCollection<MetadataComponent> {
283293
if (type.folderContentType) {
284294
type = this.registry.getTypeByName(type.folderContentType);
285295
}
286-
if (type.isAddressable !== false) {
287-
addToTypeMap(type.name, fullName);
288-
}
296+
addToTypeMap(type, fullName);
289297

290298
// Add children
291299
const componentMap = components.get(key);
292300
for (const comp of componentMap.values()) {
293301
for (const child of comp.getChildren()) {
294-
if (child.isAddressable) {
295-
addToTypeMap(child.type.name, child.fullName);
296-
}
302+
addToTypeMap(child.type, child.fullName);
297303
}
298304
}
299305
}

src/registry/registry.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"customlabel": {
2222
"id": "customlabel",
2323
"name": "CustomLabel",
24+
"xmlElementName": "labels",
2425
"ignoreParentName": true,
2526
"uniqueIdElement": "fullName",
2627
"directoryName": "labels",
@@ -599,42 +600,56 @@
599600
"workflowfieldupdate": {
600601
"id": "workflowfieldupdate",
601602
"name": "WorkflowFieldUpdate",
603+
"xmlElementName": "fieldUpdates",
604+
"uniqueIdElement": "fullName",
602605
"directoryName": "workflowFieldUpdates",
603606
"suffix": "workflowFieldUpdate"
604607
},
605608
"workflowknowledgepublish": {
606609
"id": "workflowknowledgepublish",
607610
"name": "WorkflowKnowledgePublish",
611+
"xmlElementName": "knowledgePublishes",
612+
"uniqueIdElement": "fullName",
608613
"directoryName": "workflowKnowledgePublishs",
609614
"suffix": "workflowKnowledgePublish"
610615
},
611616
"workflowtask": {
612617
"id": "workflowtask",
613618
"name": "WorkflowTask",
619+
"xmlElementName": "tasks",
620+
"uniqueIdElement": "fullName",
614621
"directoryName": "workflowTasks",
615622
"suffix": "workflowTask"
616623
},
617624
"workflowalert": {
618625
"id": "workflowalert",
619626
"name": "WorkflowAlert",
627+
"xmlElementName": "alerts",
628+
"uniqueIdElement": "fullName",
620629
"directoryName": "workflowAlerts",
621630
"suffix": "workflowAlert"
622631
},
623632
"workflowsend": {
624633
"id": "workflowsend",
625634
"name": "WorkflowSend",
635+
"xmlElementName": "sends",
636+
"uniqueIdElement": "fullName",
626637
"directoryName": "workflowSends",
627638
"suffix": "workflowSend"
628639
},
629640
"workflowoutboundmessage": {
630641
"id": "workflowoutboundmessage",
631642
"name": "WorkflowOutboundMessage",
643+
"xmlElementName": "outboundMessages",
644+
"uniqueIdElement": "fullName",
632645
"directoryName": "workflowOutboundMessages",
633646
"suffix": "workflowOutboundMessage"
634647
},
635648
"workflowrule": {
636649
"id": "workflowrule",
637650
"name": "WorkflowRule",
651+
"xmlElementName": "rules",
652+
"uniqueIdElement": "fullName",
638653
"directoryName": "workflowRules",
639654
"suffix": "workflowRule"
640655
}
@@ -670,6 +685,8 @@
670685
"assignmentrule": {
671686
"id": "assignmentrule",
672687
"name": "AssignmentRule",
688+
"xmlElementName": "assignmentRule",
689+
"uniqueIdElement": "fullName",
673690
"directoryName": "assignmentRules",
674691
"suffix": "assignmentRule"
675692
}
@@ -694,6 +711,8 @@
694711
"autoresponserule": {
695712
"id": "autoresponserule",
696713
"name": "AutoResponseRule",
714+
"xmlElementName": "autoResponseRule",
715+
"uniqueIdElement": "fullName",
697716
"directoryName": "autoResponseRules",
698717
"suffix": "autoResponseRule"
699718
}
@@ -718,6 +737,8 @@
718737
"escalationrule": {
719738
"id": "escalationrule",
720739
"name": "EscalationRule",
740+
"xmlElementName": "escalationRule",
741+
"uniqueIdElement": "fullName",
721742
"directoryName": "escalationRules",
722743
"suffix": "escalationRule"
723744
}
@@ -929,6 +950,8 @@
929950
"matchingrule": {
930951
"id": "matchingrule",
931952
"name": "MatchingRule",
953+
"xmlElementName": "matchingRules",
954+
"uniqueIdElement": "fullName",
932955
"directoryName": "matchingRules",
933956
"suffix": "matchingRule"
934957
}
@@ -1134,24 +1157,32 @@
11341157
"sharingownerrule": {
11351158
"id": "sharingownerrule",
11361159
"name": "SharingOwnerRule",
1160+
"xmlElementName": "sharingOwnerRules",
1161+
"uniqueIdElement": "fullName",
11371162
"directoryName": "sharingOwnerRules",
11381163
"suffix": "sharingOwnerRule"
11391164
},
11401165
"sharingcriteriarule": {
11411166
"id": "sharingcriteriarule",
11421167
"name": "SharingCriteriaRule",
1168+
"xmlElementName": "sharingCriteriaRules",
1169+
"uniqueIdElement": "fullName",
11431170
"directoryName": "sharingCriteriaRules",
11441171
"suffix": "sharingCriteriaRule"
11451172
},
11461173
"sharingguestrule": {
11471174
"id": "sharingguestrule",
11481175
"name": "SharingGuestRule",
1176+
"xmlElementName": "sharingGuestRules",
1177+
"uniqueIdElement": "fullName",
11491178
"directoryName": "sharingGuestRules",
11501179
"suffix": "sharingGuestRule"
11511180
},
11521181
"sharingterritoryrule": {
11531182
"id": "sharingterritoryrule",
11541183
"name": "SharingTerritoryRule",
1184+
"xmlElementName": "sharingTerritoryRules",
1185+
"uniqueIdElement": "fullName",
11551186
"directoryName": "sharingTerritoryRules",
11561187
"suffix": "sharingTerritoryRule"
11571188
}
@@ -1350,6 +1381,8 @@
13501381
"managedtopic": {
13511382
"id": "managedtopic",
13521383
"name": "ManagedTopic",
1384+
"xmlElementName": "managedTopic",
1385+
"uniqueIdElement": "fullName",
13531386
"directoryName": "managedTopics",
13541387
"suffix": "managedTopic"
13551388
}

src/registry/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ export interface MetadataType {
7474
* If the parent name should be ignored when constructing the type's fullName
7575
*/
7676
ignoreParentName?: boolean;
77+
/**
78+
* The XML element name for the type in the xml file used for constructing child components.
79+
*/
80+
xmlElementName?: string;
7781
/**
7882
* When converting deploying source, this will update the suffix in the output or temporary directory (metadata format)
7983
* Use this, along with additional suffix keys in the registry, to support incorrect suffixes from existing code

src/resolve/sourceComponent.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,15 +201,17 @@ export class SourceComponent implements MetadataComponent {
201201
return children;
202202
}
203203

204+
// Get the children for non-decomposed types that have an xmlElementName
205+
// and uniqueIdElement defined in the registry.
206+
// E.g., CustomLabels, Workflows, SharingRules, AssignmentRules.
204207
private getNonDecomposedChildren(): SourceComponent[] {
205-
// this method only applies to customlabels type
206208
const parsed = this.parseXmlSync();
207-
const xmlPathToChildren = `${this.type.name}.${this.type.directoryName}`;
208209
const children: SourceComponent[] = [];
209210
for (const childTypeId of Object.keys(this.type.children.types)) {
210211
const childType = this.type.children.types[childTypeId];
211212
const uniqueIdElement = childType.uniqueIdElement;
212213
if (uniqueIdElement) {
214+
const xmlPathToChildren = `${this.type.name}.${childType.xmlElementName}`;
213215
const elements = normalizeToArray(get(parsed, xmlPathToChildren, []));
214216
const childComponents = elements.map((element) => {
215217
return new SourceComponent(

test/collections/componentSet.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
decomposedtoplevel,
3030
matchingContentFile,
3131
} from '../mock/registry';
32+
import { MATCHING_RULES_COMPONENT } from '../mock/registry/type-constants/nonDecomposedConstants';
3233
import * as manifestFiles from '../mock/registry/manifestConstants';
3334

3435
const env = createSandbox();
@@ -419,6 +420,14 @@ describe('ComponentSet', () => {
419420
]);
420421
});
421422

423+
it('should include required child types as defined in the registry', () => {
424+
const set = new ComponentSet([MATCHING_RULES_COMPONENT]);
425+
expect(set.getObject().Package.types).to.deep.equal([
426+
{ name: MATCHING_RULES_COMPONENT.type.name, members: [MATCHING_RULES_COMPONENT.name] },
427+
{ name: 'MatchingRule', members: ['MatchingRules.My_Account_Matching_Rule'] },
428+
]);
429+
});
430+
422431
it('should exclude components that are not addressable as defined in the registry', () => {
423432
const type: MetadataType = {
424433
id: 'customfieldtranslation',

test/mock/registry/mockRegistry.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export const mockRegistryData = {
124124
nondecomposedchild: {
125125
id: 'nondecomposedchild',
126126
name: 'nondecomposedchild',
127+
xmlElementName: 'nondecomposed',
127128
ignoreParentName: true,
128129
uniqueIdElement: 'id',
129130
directoryName: 'nondecomposed',

test/resolve/sourceComponent.test.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@ import {
2323
VIRTUAL_DIR,
2424
COMPONENT_1_XML_PATH,
2525
CHILD_2_NAME,
26-
MATCHING_RULES_COMPONENT,
26+
MATCHING_RULES_TYPE,
27+
MATCHING_RULES_COMPONENT_XML_PATH,
28+
TREE,
2729
} from '../mock/registry/type-constants/nonDecomposedConstants';
2830
import { createSandbox } from 'sinon';
29-
import { MetadataType } from '../../src';
3031
import { join } from 'path';
3132
import { DecomposedSourceAdapter } from '../../src/resolve/adapters';
3233
import { TypeInferenceError } from '../../src/errors';
3334
import { nls } from '../../src/i18n';
35+
import { MetadataType } from '../../src';
3436

3537
const env = createSandbox();
3638

@@ -312,7 +314,18 @@ describe('SourceComponent', () => {
312314

313315
// https://github.com/forcedotcom/salesforcedx-vscode/issues/3210
314316
it('should return empty children for types that do not have uniqueIdElement but xmlPathToChildren returns elements', () => {
315-
expect(MATCHING_RULES_COMPONENT.getChildren()).to.deep.equal([]);
317+
const noUniqueIdElementType: MetadataType = JSON.parse(JSON.stringify(MATCHING_RULES_TYPE));
318+
// remove the uniqueElementType for this test
319+
delete noUniqueIdElementType.children.types.matchingrule.uniqueIdElement;
320+
const noUniqueIdElement_Component = new SourceComponent(
321+
{
322+
name: noUniqueIdElementType.name,
323+
type: noUniqueIdElementType,
324+
xml: MATCHING_RULES_COMPONENT_XML_PATH,
325+
},
326+
TREE
327+
);
328+
expect(noUniqueIdElement_Component.getChildren()).to.deep.equal([]);
316329
});
317330
});
318331
});

0 commit comments

Comments
 (0)