Skip to content

Commit 585aa1d

Browse files
shetzelKaaviyanSF-CLI-BOT
authored
feat: support digitalExperienceBundle md types
* feat: support deb and dec md types * chore: auto-update metadata coverage in METADATA_SUPPORT.md * fix: explicitly declare undefined in getParentType return type * fix: remove strict dir name req for DEC * chore: auto-update metadata coverage in METADATA_SUPPORT.md * fix: remove changes to settings.json * test: record perf Co-authored-by: Kaaviyan Kanagasabapathi <[email protected]> Co-authored-by: Kaaviyan Kanagasabapathi <[email protected]> Co-authored-by: SF-CLI-BOT <[email protected]>
1 parent 6fe0063 commit 585aa1d

28 files changed

+1058
-553
lines changed

METADATA_SUPPORT.md

Lines changed: 525 additions & 526 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,4 @@
123123
"path": "./node_modules/cz-conventional-changelog"
124124
}
125125
}
126-
}
126+
}

src/collections/componentSet.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,14 @@ export class ComponentSet extends LazyCollection<MetadataComponent> {
523523
if (parentInWildcard) {
524524
return true;
525525
}
526+
const partialWildcardKey = this.simpleKey({
527+
fullName: `${parent.fullName}.${ComponentSet.WILDCARD}`,
528+
type: component.type,
529+
});
530+
const parentInPartialWildcard = this.components.has(partialWildcardKey);
531+
if (parentInPartialWildcard) {
532+
return true;
533+
}
526534
}
527535
}
528536

src/convert/transformers/defaultMetadataTransformer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,11 @@ export class DefaultMetadataTransformer extends BaseMetadataTransformer {
8888
let xmlDestination = component.getPackageRelativePath(component.xml, targetFormat);
8989

9090
// quirks:
91-
// - append or strip the -meta.xml suffix to the path if there's no content
91+
// - append or strip the -meta.xml suffix to the path if there's no content and if it's not DigitalExperienceBundle
9292
// for folder components:
9393
// - remove file extension but preserve -meta.xml suffix if folder type and to 'metadata format'
9494
// - insert file extension behind the -meta.xml suffix if folder type and to 'source format'
95-
if (!component.content) {
95+
if (!component.content && !['digitalexperiencebundle'].includes(component.type.id)) {
9696
if (targetFormat === 'metadata') {
9797
xmlDestination = folderContentType
9898
? xmlDestination.replace(`.${suffix}`, '')

src/registry/metadataRegistry.json

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3043,6 +3043,44 @@
30433043
"inFolder": false,
30443044
"strictDirectoryName": false
30453045
},
3046+
"digitalexperiencebundle": {
3047+
"id": "digitalexperiencebundle",
3048+
"name": "DigitalExperienceBundle",
3049+
"directoryName": "digitalExperiences",
3050+
"inFolder": false,
3051+
"supportsWildcardAndName": true,
3052+
"suffix": "digitalExperience",
3053+
"children": {
3054+
"types": {
3055+
"digitalexperience": {
3056+
"id": "digitalexperience",
3057+
"name": "DigitalExperience",
3058+
"directoryName": "digitalExperiences",
3059+
"suffix": "digitalExperience",
3060+
"strategies": {
3061+
"adapter": "digitalExperience"
3062+
}
3063+
}
3064+
},
3065+
"suffixes": {
3066+
"digitalExperience": "digitalexperience"
3067+
},
3068+
"directories": {
3069+
"digitalExperiences": "digitalexperience"
3070+
}
3071+
},
3072+
"strategies": {
3073+
"adapter": "digitalExperience"
3074+
}
3075+
},
3076+
"digitalexperienceconfig": {
3077+
"id": "digitalexperienceconfig",
3078+
"name": "DigitalExperienceConfig",
3079+
"suffix": "digitalExperienceConfig",
3080+
"directoryName": "digitalExperienceConfigs",
3081+
"inFolder": false,
3082+
"strictDirectoryName": false
3083+
},
30463084
"forecastingfilter": {
30473085
"id": "forecastingfilter",
30483086
"name": "ForecastingFilter",
@@ -3404,6 +3442,8 @@
34043442
"aq": "assessmentquestion",
34053443
"aqs": "assessmentquestionset",
34063444
"identityverificationprocdef": "identityverificationprocdef",
3445+
"digitalExperience": "digitalexperiencebundle",
3446+
"digitalExperienceConfig": "digitalexperienceconfig",
34073447
"forecastingFilter": "forecastingfilter",
34083448
"forecastingFilterCondition": "forecastingfiltercondition",
34093449
"schedulingObjective": "schedulingobjective"
@@ -3464,6 +3504,7 @@
34643504
"sharingcriteriarule": "sharingrules",
34653505
"botversion": "bot",
34663506
"customfieldtranslation": "customobjecttranslation",
3467-
"mktdatatranfield": "mktdatatranobject"
3507+
"mktdatatranfield": "mktdatatranobject",
3508+
"digitalexperience": "digitalexperiencebundle"
34683509
}
34693510
}

src/registry/nonSupportedTypes.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ export const features = [
2424
'MANAGETIMELINE', // is not a valid Features value
2525
'HEALTHCLOUDBETA', // is not a valid Features value
2626
'PARDOTADVANCED', // org:create throws a C-9999 when this is not excluded
27-
'MCONTENTMETADATA',
2827
'EMBEDDEDSERVICEMESSAGING',
2928
'ARCGRAPHCOMMUNITY',
3029
'UNIFIEDHEALTHSCORING',

src/registry/registryAccess.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,18 @@ export class RegistryAccess {
129129
}
130130
return this.aliasTypes;
131131
}
132+
133+
/**
134+
* Return the parent metadata type from the registry for the given child type
135+
*
136+
* @param childName - Child metadata type name
137+
* @returns Parent metadata type object or undefined if no parent exists
138+
*/
139+
public getParentType(childName: string): MetadataType | undefined {
140+
const lower = childName.toLowerCase().trim();
141+
if (this.registry.childTypes[lower]) {
142+
const parentTypeId = this.registry.childTypes[lower];
143+
return this.registry.types[parentTypeId];
144+
}
145+
}
132146
}

src/resolve/adapters/baseSourceAdapter.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export abstract class BaseSourceAdapter implements SourceAdapter {
4747
if (!rootMetadata) {
4848
const rootMetadataPath = this.getRootMetadataXmlPath(path);
4949
if (rootMetadataPath) {
50-
rootMetadata = parseMetadataXml(rootMetadataPath);
50+
rootMetadata = this.parseMetadataXml(rootMetadataPath);
5151
}
5252
}
5353
if (rootMetadata && this.forceIgnore.denies(rootMetadata.path)) {
@@ -89,7 +89,7 @@ export abstract class BaseSourceAdapter implements SourceAdapter {
8989
* @param path File path of a metadata component
9090
*/
9191
protected parseAsRootMetadataXml(path: SourcePath): MetadataXml {
92-
const metaXml = parseMetadataXml(path);
92+
const metaXml = this.parseMetadataXml(path);
9393
if (metaXml) {
9494
let isRootMetadataXml = false;
9595
if (this.type.strictDirectoryName) {
@@ -116,6 +116,10 @@ export abstract class BaseSourceAdapter implements SourceAdapter {
116116
}
117117
}
118118

119+
protected parseMetadataXml(path: SourcePath): MetadataXml {
120+
return parseMetadataXml(path);
121+
}
122+
119123
/**
120124
* If the path given to `getComponent` serves as the sole definition (metadata and content)
121125
* for a component, parse the name and return it. This allows matching files in metadata
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright (c) 2022, salesforce.com, inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import { dirname, join, sep } from 'path';
8+
import { META_XML_SUFFIX } from '../../common';
9+
import { SourceComponent } from '..';
10+
import { MetadataXml } from '../types';
11+
import { baseName, parentName } from '../../utils';
12+
import { SourcePath } from '../../common';
13+
import { BundleSourceAdapter } from './bundleSourceAdapter';
14+
15+
/**
16+
* Source Adapter for DigitalExperience metadata types. This metadata type is a bundled type of the format
17+
*
18+
* __Example Structure__:
19+
*
20+
*```text
21+
* site/
22+
* ├── foos/
23+
* | ├── sfdc_cms__appPage/
24+
* | | ├── mainAppPage/
25+
* | | | ├── _meta.json
26+
* | | | ├── content.json
27+
* | ├── sfdc_cms__view/
28+
* | | ├── view1/
29+
* | | | ├── _meta.json
30+
* | | | ├── content.json
31+
* | | | ├── fr.json
32+
* | | | ├── en.json
33+
* | | ├── view2/
34+
* | | | ├── _meta.json
35+
* | | | ├── content.json
36+
* | | | ├── ar.json
37+
* | ├── foos.digitalExperience-meta.xml
38+
* content/
39+
* ├── bars/
40+
* | ├── bars.digitalExperience-meta.xml
41+
* ```
42+
*
43+
* In the above structure the metadata xml file ending with "digitalExperience-meta.xml" belongs to DigitalExperienceBundle MD type.
44+
* The "_meta.json" files are child metadata files of DigitalExperienceBundle belonging to DigitalExperience MD type. The rest of the files in the
45+
* corresponding folder are the contents to the DigitalExperience metadata. So, incase of DigitalExperience the metadata file is a JSON file
46+
* and not an XML file
47+
*/
48+
export class DigitalExperienceSourceAdapter extends BundleSourceAdapter {
49+
protected getRootMetadataXmlPath(trigger: string): string {
50+
if (this.isBundleType()) {
51+
return this.getBundleMetadataXmlPath(trigger);
52+
}
53+
return join(dirname(trigger), '_meta.json');
54+
}
55+
56+
/**
57+
* @param contentPath This hook is called only after trimPathToContent() is called. so this will always be a folder strcture
58+
* @returns name of type/apiName format
59+
*/
60+
protected calculateNameFromPath(contentPath: string): string {
61+
return `${parentName(contentPath)}${sep}${baseName(contentPath)}`;
62+
}
63+
64+
protected trimPathToContent(path: string): string {
65+
if (this.isBundleType()) {
66+
return;
67+
}
68+
return dirname(path);
69+
}
70+
71+
protected populate(trigger: string, component?: SourceComponent): SourceComponent {
72+
if (this.isBundleType()) {
73+
// for top level types we don't need to resolve parent
74+
return component;
75+
}
76+
const source = super.populate(trigger, component);
77+
const parentType = this.registry.getParentType(this.type.id);
78+
const parent = new SourceComponent(
79+
{
80+
name: this.getBundleName(source.content),
81+
type: parentType,
82+
xml: this.getBundleMetadataXmlPath(source.content),
83+
},
84+
this.tree,
85+
this.forceIgnore
86+
);
87+
return new SourceComponent(
88+
{
89+
name: this.calculateNameFromPath(source.content),
90+
type: this.type,
91+
content: source.content,
92+
parent,
93+
parentType,
94+
},
95+
this.tree,
96+
this.forceIgnore
97+
);
98+
}
99+
100+
protected parseMetadataXml(path: SourcePath): MetadataXml {
101+
const xml = super.parseMetadataXml(path);
102+
if (xml) {
103+
return {
104+
fullName: this.getBundleName(path),
105+
suffix: xml.suffix,
106+
path: xml.path,
107+
};
108+
}
109+
}
110+
111+
private getBundleName(contentPath: string): string {
112+
const bundlePath = this.getBundleMetadataXmlPath(contentPath);
113+
return `${parentName(dirname(bundlePath))}${sep}${parentName(bundlePath)}`;
114+
}
115+
116+
private getBundleMetadataXmlPath(path: string): string {
117+
if (this.isBundleType() && path.endsWith(META_XML_SUFFIX)) {
118+
// if this is the bundle type and it ends with -meta.xml, then this is the bundle metadata xml path
119+
return path;
120+
}
121+
const pathParts = path.split(sep);
122+
const typeFolderIndex = pathParts.lastIndexOf(this.type.directoryName);
123+
// 3 because we want 'digitaExperiences' directory, 'baseType' directory and 'bundleName' directory
124+
const basePath = pathParts.slice(0, typeFolderIndex + 3).join(sep);
125+
const bundleFileName = pathParts[typeFolderIndex + 2];
126+
const suffix = this.isBundleType() ? this.type.suffix : this.registry.getParentType(this.type.id).suffix;
127+
return `${basePath}${sep}${bundleFileName}.${suffix}${META_XML_SUFFIX}`;
128+
}
129+
130+
private isBundleType(): boolean {
131+
return this.type.id === 'digitalexperiencebundle';
132+
}
133+
}

src/resolve/adapters/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ export { MixedContentSourceAdapter } from './mixedContentSourceAdapter';
1010
export { DecomposedSourceAdapter } from './decomposedSourceAdapter';
1111
export { DefaultSourceAdapter } from './defaultSourceAdapter';
1212
export { BaseSourceAdapter } from './baseSourceAdapter';
13+
export { DigitalExperienceSourceAdapter } from './digitalExperienceSourceAdapter';

0 commit comments

Comments
 (0)