@salesforce/packaging
Version:
Packaging library for the Salesforce packaging platform
109 lines • 5.93 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.manifestTypesToMap = exports.profileObjectToString = exports.profileStringToProfile = exports.fieldCorrections = exports.profileRewriter = void 0;
const fast_xml_parser_1 = require("fast-xml-parser");
/**
*
* Takes a Profile that's been converted from package.xml to json.
* Filters out all Profile props that are not
* 1. used by packaging (ex: ipRanges)
* 2. present in the package.xml (ex: ClassAccesses for a class not in the package)
* 3. optionally retains the UserLicense prop only if the param is true
*
* @param profileJson json representation of a profile
* @param packageXml package.xml as json
* @param retainUserLicense boolean will preserve userLicense if true
* @returns Profile
*/
const profileRewriter = (profileJson, packageXml, retainUserLicense = false) => ({
...Object.fromEntries(Object.entries(profileJson)
// remove settings that are not used for packaging
.filter(isRewriteProp)
// @ts-expect-error the previous filter restricts us to only things that appear in filterFunctions
.map(([key, value]) => [key, filterFunctions[key]?.(value, packageXml)] ?? [])
// some profileSettings might now be empty Arrays if the package.xml didn't have those types, so remove the entire property
.filter(([, value]) => (Array.isArray(value) ? value.length : true))),
// this one prop is controlled by a param. Put it back the way it was if the param is true
...(retainUserLicense && profileJson.userLicense ? { userLicense: profileJson.userLicense } : {}),
});
exports.profileRewriter = profileRewriter;
// it's both a filter and a typeguard to make sure props are represented in filterFunctions
const isRewriteProp = (prop) => rewriteProps.includes(prop[0]);
const rewriteProps = [
'objectPermissions',
'fieldPermissions',
'layoutAssignments',
'applicationVisibilities',
'classAccesses',
'externalDataSourceAccesses',
'tabVisibilities',
'pageAccesses',
'customPermissions',
'customMetadataTypeAccesses',
'customSettingAccesses',
'recordTypeVisibilities',
];
const filterFunctions = {
objectPermissions: (props, packageXml) => props.filter((item) => packageXml.get('CustomObject')?.includes(item.object)),
fieldPermissions: (props, packageXml) => props.filter((item) => packageXml.get('CustomField')?.includes((0, exports.fieldCorrections)(item.field))),
layoutAssignments: (props, packageXml) => props.filter((item) => packageXml.get('Layout')?.includes(item.layout)),
tabVisibilities: (props, packageXml) => props.filter((item) => packageXml.get('CustomTab')?.includes(item.tab)),
applicationVisibilities: (props, packageXml) => props.filter((item) => packageXml.get('CustomApplication')?.includes(item.application)),
classAccesses: (props, packageXml) => props.filter((item) => packageXml.get('ApexClass')?.includes(item.apexClass)),
customPermissions: (props, packageXml) => props.filter((item) => packageXml.get('CustomPermission')?.includes(item.name)),
pageAccesses: (props, packageXml) => props.filter((item) => packageXml.get('ApexPage')?.includes(item.apexPage)),
externalDataSourceAccesses: (props, packageXml) => props.filter((item) => packageXml.get('ExternalDataSource')?.includes(item.externalDataSource)),
recordTypeVisibilities: (props, packageXml) => props.filter((item) => packageXml.get('RecordType')?.includes(item.recordType)),
customSettingAccesses: (props, packageXml) => props.filter((item) => allMembers(packageXml).includes(item.name)),
customMetadataTypeAccesses: (props, packageXml) => props.filter((item) => allMembers(packageXml).includes(item.name)),
};
const allMembers = (packageXml) => Array.from(packageXml.values()).flat();
// github.com/forcedotcom/cli/issues/2278
// Activity Object is polymorphic (Task and Event)
// package.xml will display them as 'Activity'
// profile.fieldPermissions will display them with the more specific 'Task' or 'Event'
const fieldCorrections = (fieldName) => fieldName.replace(/^Event\./, 'Activity.').replace(/^Task\./, 'Activity.');
exports.fieldCorrections = fieldCorrections;
/**
* @param profileString: raw xml read from the file
* @returns CorrectedProfile (json representation of the profile)
*/
const profileStringToProfile = (profileString) => {
const parser = new fast_xml_parser_1.XMLParser({
ignoreAttributes: true,
parseTagValue: false,
parseAttributeValue: false,
cdataPropName: '__cdata',
ignoreDeclaration: true,
numberParseOptions: { leadingZeros: false, hex: false },
isArray: (name) => rewriteProps.includes(name),
});
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
return parser.parse(profileString).Profile;
};
exports.profileStringToProfile = profileStringToProfile;
/** pass in an object that has the Profile props at the top level.
* This function will add the outer wrapper `Profile` and convert the result to xml
* */
const profileObjectToString = (profileObject) => {
const builder = new fast_xml_parser_1.XMLBuilder({
format: true,
indentBy: ' ',
ignoreAttributes: false,
cdataPropName: '__cdata',
processEntities: false,
attributeNamePrefix: '@@@',
});
return String(builder.build({
'?xml': {
'@@@version': '1.0',
'@@@encoding': 'UTF-8',
},
Profile: { ...profileObject, '@@@xmlns': 'http://soap.sforce.com/2006/04/metadata' },
}));
};
exports.profileObjectToString = profileObjectToString;
/** it's easier to do lookups by Metadata Type on a Map */
const manifestTypesToMap = (original) => new Map(original.map((item) => [item.name, item.members]));
exports.manifestTypesToMap = manifestTypesToMap;
//# sourceMappingURL=profileRewriter.js.map