Skip to content

Commit

Permalink
feat: add required child type entries to manifest (#446)
Browse files Browse the repository at this point in the history
* feat: add required child type entries to manifest

* test: update test comment
  • Loading branch information
shetzel authored Sep 9, 2021
1 parent e51977e commit c99198b
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 16 deletions.
28 changes: 17 additions & 11 deletions src/collections/componentSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
import { LazyCollection } from './lazyCollection';
import { j2xParser } from 'fast-xml-parser';
import { Logger } from '@salesforce/core';
import { RegistryAccess } from '../registry';
import { MetadataType, RegistryAccess } from '../registry';

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

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

const addToTypeMap = (typeName: string, fullName: string): void => {
if (!typeMap.has(typeName)) {
typeMap.set(typeName, []);
const addToTypeMap = (type: MetadataType, fullName: string): void => {
if (type.isAddressable !== false) {
const typeName = type.name;
if (!typeMap.has(typeName)) {
typeMap.set(typeName, []);
}
const typeEntry = typeMap.get(typeName);
if (fullName === ComponentSet.WILDCARD) {
typeMap.set(typeName, [fullName]);
} else {
if (!typeEntry.includes(fullName) && !typeEntry.includes(ComponentSet.WILDCARD)) {
typeMap.get(typeName).push(fullName);
}
}
}
typeMap.get(typeName).push(fullName);
};

for (const key of components.keys()) {
Expand All @@ -283,17 +293,13 @@ export class ComponentSet extends LazyCollection<MetadataComponent> {
if (type.folderContentType) {
type = this.registry.getTypeByName(type.folderContentType);
}
if (type.isAddressable !== false) {
addToTypeMap(type.name, fullName);
}
addToTypeMap(type, fullName);

// Add children
const componentMap = components.get(key);
for (const comp of componentMap.values()) {
for (const child of comp.getChildren()) {
if (child.isAddressable) {
addToTypeMap(child.type.name, child.fullName);
}
addToTypeMap(child.type, child.fullName);
}
}
}
Expand Down
33 changes: 33 additions & 0 deletions src/registry/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"customlabel": {
"id": "customlabel",
"name": "CustomLabel",
"xmlElementName": "labels",
"ignoreParentName": true,
"uniqueIdElement": "fullName",
"directoryName": "labels",
Expand Down Expand Up @@ -599,42 +600,56 @@
"workflowfieldupdate": {
"id": "workflowfieldupdate",
"name": "WorkflowFieldUpdate",
"xmlElementName": "fieldUpdates",
"uniqueIdElement": "fullName",
"directoryName": "workflowFieldUpdates",
"suffix": "workflowFieldUpdate"
},
"workflowknowledgepublish": {
"id": "workflowknowledgepublish",
"name": "WorkflowKnowledgePublish",
"xmlElementName": "knowledgePublishes",
"uniqueIdElement": "fullName",
"directoryName": "workflowKnowledgePublishs",
"suffix": "workflowKnowledgePublish"
},
"workflowtask": {
"id": "workflowtask",
"name": "WorkflowTask",
"xmlElementName": "tasks",
"uniqueIdElement": "fullName",
"directoryName": "workflowTasks",
"suffix": "workflowTask"
},
"workflowalert": {
"id": "workflowalert",
"name": "WorkflowAlert",
"xmlElementName": "alerts",
"uniqueIdElement": "fullName",
"directoryName": "workflowAlerts",
"suffix": "workflowAlert"
},
"workflowsend": {
"id": "workflowsend",
"name": "WorkflowSend",
"xmlElementName": "sends",
"uniqueIdElement": "fullName",
"directoryName": "workflowSends",
"suffix": "workflowSend"
},
"workflowoutboundmessage": {
"id": "workflowoutboundmessage",
"name": "WorkflowOutboundMessage",
"xmlElementName": "outboundMessages",
"uniqueIdElement": "fullName",
"directoryName": "workflowOutboundMessages",
"suffix": "workflowOutboundMessage"
},
"workflowrule": {
"id": "workflowrule",
"name": "WorkflowRule",
"xmlElementName": "rules",
"uniqueIdElement": "fullName",
"directoryName": "workflowRules",
"suffix": "workflowRule"
}
Expand Down Expand Up @@ -670,6 +685,8 @@
"assignmentrule": {
"id": "assignmentrule",
"name": "AssignmentRule",
"xmlElementName": "assignmentRule",
"uniqueIdElement": "fullName",
"directoryName": "assignmentRules",
"suffix": "assignmentRule"
}
Expand All @@ -694,6 +711,8 @@
"autoresponserule": {
"id": "autoresponserule",
"name": "AutoResponseRule",
"xmlElementName": "autoResponseRule",
"uniqueIdElement": "fullName",
"directoryName": "autoResponseRules",
"suffix": "autoResponseRule"
}
Expand All @@ -718,6 +737,8 @@
"escalationrule": {
"id": "escalationrule",
"name": "EscalationRule",
"xmlElementName": "escalationRule",
"uniqueIdElement": "fullName",
"directoryName": "escalationRules",
"suffix": "escalationRule"
}
Expand Down Expand Up @@ -929,6 +950,8 @@
"matchingrule": {
"id": "matchingrule",
"name": "MatchingRule",
"xmlElementName": "matchingRules",
"uniqueIdElement": "fullName",
"directoryName": "matchingRules",
"suffix": "matchingRule"
}
Expand Down Expand Up @@ -1134,24 +1157,32 @@
"sharingownerrule": {
"id": "sharingownerrule",
"name": "SharingOwnerRule",
"xmlElementName": "sharingOwnerRules",
"uniqueIdElement": "fullName",
"directoryName": "sharingOwnerRules",
"suffix": "sharingOwnerRule"
},
"sharingcriteriarule": {
"id": "sharingcriteriarule",
"name": "SharingCriteriaRule",
"xmlElementName": "sharingCriteriaRules",
"uniqueIdElement": "fullName",
"directoryName": "sharingCriteriaRules",
"suffix": "sharingCriteriaRule"
},
"sharingguestrule": {
"id": "sharingguestrule",
"name": "SharingGuestRule",
"xmlElementName": "sharingGuestRules",
"uniqueIdElement": "fullName",
"directoryName": "sharingGuestRules",
"suffix": "sharingGuestRule"
},
"sharingterritoryrule": {
"id": "sharingterritoryrule",
"name": "SharingTerritoryRule",
"xmlElementName": "sharingTerritoryRules",
"uniqueIdElement": "fullName",
"directoryName": "sharingTerritoryRules",
"suffix": "sharingTerritoryRule"
}
Expand Down Expand Up @@ -1350,6 +1381,8 @@
"managedtopic": {
"id": "managedtopic",
"name": "ManagedTopic",
"xmlElementName": "managedTopic",
"uniqueIdElement": "fullName",
"directoryName": "managedTopics",
"suffix": "managedTopic"
}
Expand Down
4 changes: 4 additions & 0 deletions src/registry/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ export interface MetadataType {
* If the parent name should be ignored when constructing the type's fullName
*/
ignoreParentName?: boolean;
/**
* The XML element name for the type in the xml file used for constructing child components.
*/
xmlElementName?: string;
/**
* When converting deploying source, this will update the suffix in the output or temporary directory (metadata format)
* Use this, along with additional suffix keys in the registry, to support incorrect suffixes from existing code
Expand Down
6 changes: 4 additions & 2 deletions src/resolve/sourceComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,17 @@ export class SourceComponent implements MetadataComponent {
return children;
}

// Get the children for non-decomposed types that have an xmlElementName
// and uniqueIdElement defined in the registry.
// E.g., CustomLabels, Workflows, SharingRules, AssignmentRules.
private getNonDecomposedChildren(): SourceComponent[] {
// this method only applies to customlabels type
const parsed = this.parseXmlSync();
const xmlPathToChildren = `${this.type.name}.${this.type.directoryName}`;
const children: SourceComponent[] = [];
for (const childTypeId of Object.keys(this.type.children.types)) {
const childType = this.type.children.types[childTypeId];
const uniqueIdElement = childType.uniqueIdElement;
if (uniqueIdElement) {
const xmlPathToChildren = `${this.type.name}.${childType.xmlElementName}`;
const elements = normalizeToArray(get(parsed, xmlPathToChildren, []));
const childComponents = elements.map((element) => {
return new SourceComponent(
Expand Down
9 changes: 9 additions & 0 deletions test/collections/componentSet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
decomposedtoplevel,
matchingContentFile,
} from '../mock/registry';
import { MATCHING_RULES_COMPONENT } from '../mock/registry/type-constants/nonDecomposedConstants';
import * as manifestFiles from '../mock/registry/manifestConstants';

const env = createSandbox();
Expand Down Expand Up @@ -419,6 +420,14 @@ describe('ComponentSet', () => {
]);
});

it('should include required child types as defined in the registry', () => {
const set = new ComponentSet([MATCHING_RULES_COMPONENT]);
expect(set.getObject().Package.types).to.deep.equal([
{ name: MATCHING_RULES_COMPONENT.type.name, members: [MATCHING_RULES_COMPONENT.name] },
{ name: 'MatchingRule', members: ['MatchingRules.My_Account_Matching_Rule'] },
]);
});

it('should exclude components that are not addressable as defined in the registry', () => {
const type: MetadataType = {
id: 'customfieldtranslation',
Expand Down
1 change: 1 addition & 0 deletions test/mock/registry/mockRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export const mockRegistryData = {
nondecomposedchild: {
id: 'nondecomposedchild',
name: 'nondecomposedchild',
xmlElementName: 'nondecomposed',
ignoreParentName: true,
uniqueIdElement: 'id',
directoryName: 'nondecomposed',
Expand Down
19 changes: 16 additions & 3 deletions test/resolve/sourceComponent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ import {
VIRTUAL_DIR,
COMPONENT_1_XML_PATH,
CHILD_2_NAME,
MATCHING_RULES_COMPONENT,
MATCHING_RULES_TYPE,
MATCHING_RULES_COMPONENT_XML_PATH,
TREE,
} from '../mock/registry/type-constants/nonDecomposedConstants';
import { createSandbox } from 'sinon';
import { MetadataType } from '../../src';
import { join } from 'path';
import { DecomposedSourceAdapter } from '../../src/resolve/adapters';
import { TypeInferenceError } from '../../src/errors';
import { nls } from '../../src/i18n';
import { MetadataType } from '../../src';

const env = createSandbox();

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

// https://github.com/forcedotcom/salesforcedx-vscode/issues/3210
it('should return empty children for types that do not have uniqueIdElement but xmlPathToChildren returns elements', () => {
expect(MATCHING_RULES_COMPONENT.getChildren()).to.deep.equal([]);
const noUniqueIdElementType: MetadataType = JSON.parse(JSON.stringify(MATCHING_RULES_TYPE));
// remove the uniqueElementType for this test
delete noUniqueIdElementType.children.types.matchingrule.uniqueIdElement;
const noUniqueIdElement_Component = new SourceComponent(
{
name: noUniqueIdElementType.name,
type: noUniqueIdElementType,
xml: MATCHING_RULES_COMPONENT_XML_PATH,
},
TREE
);
expect(noUniqueIdElement_Component.getChildren()).to.deep.equal([]);
});
});
});

0 comments on commit c99198b

Please sign in to comment.