Skip to content

Commit b781c7f

Browse files
authored
Sm/etf-option-2 (#556)
* fix: emailTempalteFolder => emailFolder * chore: adding types for SDR
1 parent 2e21027 commit b781c7f

File tree

8 files changed

+81
-13
lines changed

8 files changed

+81
-13
lines changed

METADATA_SUPPORT.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This list compares metadata types found in Salesforce v54 with the [metadata reg
44

55
This repository is used by both the Salesforce CLIs and Salesforce's VSCode Extensions.
66

7-
Currently, there are 420/465 supported metadata types.
7+
Currently, there are 421/465 supported metadata types.
88
For status on any existing gaps, please search or file an issue in the [Salesforce CLI issues only repo](https://github.com/forcedotcom/cli/issues).
99
To contribute a new metadata type, please see the [Contributing Metadata Types to the Registry](./contributing/metadata.md)
1010

@@ -178,7 +178,7 @@ To contribute a new metadata type, please see the [Contributing Metadata Types t
178178
|EmailIntegrationSettings|||
179179
|EmailServicesFunction|||
180180
|EmailTemplate|||
181-
|EmailTemplateFolder||Not supported, but support could be added|
181+
|EmailTemplateFolder|||
182182
|EmailTemplateSettings|||
183183
|EmbeddedServiceBranding|||
184184
|EmbeddedServiceConfig|||
@@ -489,6 +489,7 @@ v55 introduces the following new types. Here's their current level of support
489489
|ExternalDataTranObject||Not supported, but support could be added|
490490
|RegisteredExternalService||Not supported, but support could be added|
491491
|StreamingAppDataConnector||Not supported, but support could be added|
492+
|VoiceSettings|||
492493

493494
## Additional Types
494495

src/client/metadataApiDeploy.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ export class DeployResult implements MetadataTransferResult {
197197
// strip document extension from fullName
198198
message.fullName = join(dirname(message.fullName), basename(message.fullName, extname(message.fullName)));
199199
break;
200+
// Treat emailTemplateFolder as EmailFolder
201+
case registry.types.emailtemplatefolder.name:
202+
message.componentType = registry.types.emailfolder.name;
203+
break;
200204
default:
201205
}
202206
return message;

src/registry/metadataRegistry.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,6 +1921,16 @@
19211921
"strictDirectoryName": false,
19221922
"folderContentType": "emailtemplate"
19231923
},
1924+
"emailtemplatefolder": {
1925+
"id": "emailtemplatefolder",
1926+
"name": "EmailTemplateFolder",
1927+
"suffix": "emailTemplateFolder",
1928+
"directoryName": "email",
1929+
"inFolder": false,
1930+
"strictDirectoryName": false,
1931+
"folderContentType": "emailtemplate",
1932+
"aliasFor": "emailfolder"
1933+
},
19241934
"inboundnetworkconnection": {
19251935
"id": "inboundnetworkconnection",
19261936
"name": "InboundNetworkConnection",

src/registry/nonSupportedTypes.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ export const settings = [
3131
'botSettings', // have not successfully deployed this because of licensing errors when deploying settings
3232
];
3333
export const metadataTypes = [
34-
'EmailTemplateFolder', // not a real addressable type (parent of email template)
35-
3634
// things that don't show up in describe so far
3735
'PicklistValue', // only existed in v37, so it's hard to describe!
3836
'AppointmentAssignmentPolicy', // not in describe?

src/registry/registryAccess.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export class RegistryAccess {
1616

1717
private strictFolderTypes: MetadataType[];
1818
private folderContentTypes: MetadataType[];
19+
private aliasTypes: MetadataType[];
1920

2021
public constructor(registry: MetadataRegistry = defaultRegistry) {
2122
this.registry = registry;
@@ -40,7 +41,10 @@ export class RegistryAccess {
4041
if (!this.registry.types[lower]) {
4142
throw new RegistryError('error_missing_type_definition', lower);
4243
}
43-
return this.registry.types[lower];
44+
// redirect via alias
45+
return this.registry.types[lower].aliasFor
46+
? this.registry.types[this.registry.types[lower].aliasFor]
47+
: this.registry.types[lower];
4448
}
4549

4650
/**
@@ -64,7 +68,8 @@ export class RegistryAccess {
6468
* @returns The first metadata type object that fulfills the predicate
6569
*/
6670
public findType(predicate: (type: MetadataType) => boolean): MetadataType {
67-
return Object.values(this.registry.types).find(predicate);
71+
const firstMatch = Object.values(this.registry.types).find(predicate);
72+
return firstMatch.aliasFor ? this.registry.types[firstMatch.aliasFor] : firstMatch;
6873
}
6974

7075
/**
@@ -93,16 +98,28 @@ export class RegistryAccess {
9398
*/
9499
public getFolderContentTypes(): MetadataType[] {
95100
if (!this.folderContentTypes) {
96-
this.folderContentTypes = [];
97-
for (const type of Object.values(this.registry.types)) {
98-
if (type.folderContentType) {
99-
this.folderContentTypes.push(type);
100-
}
101-
}
101+
this.folderContentTypes = Object.values(this.registry.types).filter(
102+
(type) => type.folderContentType && !type.aliasFor
103+
);
102104
}
103105
return this.folderContentTypes;
104106
}
105107

108+
/**
109+
* Query for the types that have the aliasFor property defined.
110+
* E.g., EmailTemplateFolder
111+
*
112+
* @see {@link MetadataType.aliasFor}
113+
*
114+
* @returns An array of metadata type objects that have aliasFor
115+
*/
116+
public getAliasTypes(): MetadataType[] {
117+
if (!this.aliasTypes) {
118+
this.aliasTypes = Object.values(this.registry.types).filter((type) => type.aliasFor);
119+
}
120+
return this.aliasTypes;
121+
}
122+
106123
public get apiVersion(): string {
107124
return this.registry.apiVersion;
108125
}

src/registry/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ export interface MetadataType {
106106
```
107107
*/
108108
supportsWildcardAndName?: boolean;
109+
110+
/**
111+
* Whenever this type is requested, return the aliasFor type instead
112+
*/
113+
aliasFor?: string;
109114
/**
110115
* Type definitions for child types, if the type has any.
111116
*

test/registry/registryAccess.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ describe('RegistryAccess', () => {
1616
});
1717

1818
describe('getTypeByName', () => {
19+
it('should return alias of a type when one exists', () => {
20+
expect(registryAccess.getTypeByName('EmailTemplateFolder')).to.deep.equal(registry.types.emailfolder);
21+
});
22+
1923
it('should fetch type regardless of casing', () => {
2024
expect(registryAccess.getTypeByName('apexclass')).to.deep.equal(registry.types.apexclass);
2125
});
@@ -55,6 +59,10 @@ describe('RegistryAccess', () => {
5559
const foundType = registryAccess.findType((type: MetadataType) => type.suffix === 'objectTranslation');
5660
expect(foundType).to.deep.equal(registry.types.customobjecttranslation);
5761
});
62+
it('should resolve aliases', () => {
63+
const foundType = registryAccess.findType((type: MetadataType) => type.suffix === 'emailTemplateFolder');
64+
expect(foundType).to.deep.equal(registry.types.emailfolder);
65+
});
5866
});
5967

6068
describe('getStrictFolderTypes', () => {
@@ -66,6 +74,14 @@ describe('RegistryAccess', () => {
6674
});
6775
});
6876

77+
describe('aliasTypes', () => {
78+
it('should return 1 aliases type', () => {
79+
const aliasTypes = registryAccess.getAliasTypes();
80+
expect(aliasTypes.length).to.equal(1);
81+
expect(aliasTypes[0].name).to.equal('EmailTemplateFolder');
82+
});
83+
});
84+
6985
describe('getFolderContentTypes', () => {
7086
it('should return all the types with a folderContentType property defined', () => {
7187
const type = registry.types.reportfolder;
@@ -74,5 +90,8 @@ describe('RegistryAccess', () => {
7490
const type4 = registry.types.emailfolder;
7591
expect(registryAccess.getFolderContentTypes()).to.deep.equal([type, type2, type3, type4]);
7692
});
93+
it('should not include EmailTemplateFolder', () => {
94+
expect(registryAccess.getFolderContentTypes()).to.not.deep.include(registry.types.emailtemplatefolder);
95+
});
7796
});
7897
});

test/registry/registryValidation.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,18 @@ describe('Registry Validation', () => {
7171
});
7272
});
7373

74+
describe('aliases', () => {
75+
describe('all aliases point to real types', () => {
76+
Object.values(registry.types)
77+
.filter((type) => type.aliasFor)
78+
.forEach((aliasType) => {
79+
it(`${aliasType.name} is aliased to ${aliasType.aliasFor} and that exists`, () => {
80+
expect(registry.types[aliasType.aliasFor]).to.exist;
81+
});
82+
});
83+
});
84+
});
85+
7486
describe('suffixes', () => {
7587
describe('all properties of suffixes match a real parent or child type', () => {
7688
Object.entries(registry.suffixes).forEach(([suffix, typeId]) => {
@@ -102,7 +114,9 @@ describe('Registry Validation', () => {
102114

103115
const suffixMap = new Map<string, string>();
104116
Object.values(registry.types)
105-
.filter((type) => type.suffix && !type.strictDirectoryName && !knownExceptions.includes(type.name))
117+
.filter(
118+
(type) => type.suffix && !type.aliasFor && !type.strictDirectoryName && !knownExceptions.includes(type.name)
119+
)
106120
.map((type) => {
107121
// mapping for the type's suffix
108122
suffixMap.set(type.suffix, type.id);

0 commit comments

Comments
 (0)