UNPKG

@salesforce/packaging

Version:

Packaging library for the Salesforce packaging platform

109 lines 5.93 kB
"use strict"; 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