@salesforce/packaging 2.2.9-profiles.0 → 2.2.9-profiles.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/interfaces/packagingInterfacesAndType.d.ts +1 -3
- package/lib/package/packageProfileApi.d.ts +4 -2
- package/lib/package/packageProfileApi.js +28 -33
- package/lib/package/packageVersionCreate.d.ts +6 -1
- package/lib/package/packageVersionCreate.js +48 -16
- package/lib/package/profileRewriter.d.ts +8 -2
- package/lib/package/profileRewriter.js +10 -3
- package/package.json +2 -4
|
@@ -10,16 +10,18 @@ export declare class PackageProfileApi extends AsyncCreatable<ProfileApiOptions>
|
|
|
10
10
|
* For any profile present in the workspace, this function generates a subset of data that only contains references
|
|
11
11
|
* to items in the manifest.
|
|
12
12
|
*
|
|
13
|
+
* return a list of profile file locations that need to be removed from the package because they are empty
|
|
14
|
+
*
|
|
13
15
|
* @param destPath location of new profiles
|
|
14
16
|
* @param manifestTypes: array of objects { name: string, members: string[] } that represent package xml types
|
|
15
17
|
* @param excludedDirectories Directories to not include profiles from
|
|
16
18
|
*/
|
|
17
|
-
generateProfiles(destPath: string, manifestTypes: PackageXml['
|
|
19
|
+
generateProfiles(destPath: string, manifestTypes: PackageXml['types'], excludedDirectories?: string[]): string[];
|
|
18
20
|
/**
|
|
19
21
|
* Filter out all profiles in the manifest and if any profiles exists in the workspace, add them to the manifest.
|
|
20
22
|
*
|
|
21
23
|
* @param typesArr array of objects { name[], members[] } that represent package types JSON.
|
|
22
24
|
* @param excludedDirectories Direcotires not to generate profiles for
|
|
23
25
|
*/
|
|
24
|
-
filterAndGenerateProfilesForManifest(typesArr: PackageXml['
|
|
26
|
+
filterAndGenerateProfilesForManifest(typesArr: PackageXml['types'], excludedDirectories?: string[]): PackageXml['types'];
|
|
25
27
|
}
|
|
@@ -33,39 +33,45 @@ class PackageProfileApi extends kit_1.AsyncCreatable {
|
|
|
33
33
|
* For any profile present in the workspace, this function generates a subset of data that only contains references
|
|
34
34
|
* to items in the manifest.
|
|
35
35
|
*
|
|
36
|
+
* return a list of profile file locations that need to be removed from the package because they are empty
|
|
37
|
+
*
|
|
36
38
|
* @param destPath location of new profiles
|
|
37
39
|
* @param manifestTypes: array of objects { name: string, members: string[] } that represent package xml types
|
|
38
40
|
* @param excludedDirectories Directories to not include profiles from
|
|
39
41
|
*/
|
|
40
42
|
generateProfiles(destPath, manifestTypes, excludedDirectories = []) {
|
|
41
43
|
const logger = core_1.Logger.childFromRoot('PackageProfileApi');
|
|
42
|
-
|
|
44
|
+
return (getProfilesWithNamesAndPaths({
|
|
43
45
|
projectPath: this.project.getPath(),
|
|
44
46
|
excludedDirectories,
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
+
})
|
|
48
|
+
.map(({ profilePath, name: profileName }) => {
|
|
47
49
|
const originalProfile = (0, profileRewriter_1.profileStringToProfile)(fs.readFileSync(profilePath, 'utf-8'));
|
|
48
50
|
const adjustedProfile = (0, profileRewriter_1.profileRewriter)(originalProfile, (0, profileRewriter_1.manifestTypesToMap)(manifestTypes), this.includeUserLicenses);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
return {
|
|
52
|
+
profileName,
|
|
53
|
+
profilePath,
|
|
54
|
+
hasContent: Object.keys(adjustedProfile).length,
|
|
55
|
+
adjustedProfile,
|
|
56
|
+
removedSettings: getRemovedSettings(originalProfile, adjustedProfile),
|
|
57
|
+
xmlFileLocation: getXmlFileLocation(destPath, profilePath),
|
|
58
|
+
};
|
|
59
|
+
})
|
|
60
|
+
// side effect: modify profiles in place
|
|
61
|
+
.filter(({ hasContent, profileName, removedSettings, profilePath, xmlFileLocation, adjustedProfile }) => {
|
|
53
62
|
if (!hasContent) {
|
|
54
63
|
logger.warn(`Profile ${profileName} has no content after filtering. It will still be part of the package but you can remove if it it's not needed.`);
|
|
64
|
+
return true;
|
|
55
65
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
deleteButAllowEnoent(xmlFile);
|
|
66
|
-
logger.info(profileApiMessages.getMessage('profileNotIncluded', [replacedProfileName]));
|
|
67
|
-
return replacedProfileName;
|
|
68
|
-
});
|
|
66
|
+
else {
|
|
67
|
+
logger.info(profileApiMessages.getMessage('addProfileToPackage', [profileName, profilePath]));
|
|
68
|
+
removedSettings.forEach((setting) => {
|
|
69
|
+
logger.info(profileApiMessages.getMessage('removeProfileSetting', [setting, profileName]));
|
|
70
|
+
});
|
|
71
|
+
fs.writeFileSync(xmlFileLocation, (0, profileRewriter_1.profileObjectToString)(adjustedProfile), 'utf-8');
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
.map(({ xmlFileLocation }) => xmlFileLocation.replace(/(.*)(\.profile)/, '$1')));
|
|
69
75
|
}
|
|
70
76
|
/**
|
|
71
77
|
* Filter out all profiles in the manifest and if any profiles exists in the workspace, add them to the manifest.
|
|
@@ -94,20 +100,9 @@ const getProfilesWithNamesAndPaths = ({ projectPath, excludedDirectories, }) =>
|
|
|
94
100
|
.map((profilePath) => ({ profilePath, name: profilePathToName(profilePath) }))
|
|
95
101
|
.filter(isProfilePathWithName);
|
|
96
102
|
const getXmlFileLocation = (destPath, profilePath) => path.join(destPath, path.basename(profilePath).replace(/(.*)(-meta.xml)/, '$1'));
|
|
97
|
-
const deleteButAllowEnoent = (destFilePath) => {
|
|
98
|
-
try {
|
|
99
|
-
fs.unlinkSync(destFilePath);
|
|
100
|
-
}
|
|
101
|
-
catch (err) {
|
|
102
|
-
// It is normal for the file to not exist if the profile is in the workspace but not in the directory being packaged.
|
|
103
|
-
if (err instanceof Error && 'code' in err && err.code !== 'ENOENT') {
|
|
104
|
-
throw err;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
103
|
const getRemovedSettings = (originalProfile, adjustedProfile) => {
|
|
109
104
|
const originalProfileSettings = Object.keys(originalProfile);
|
|
110
|
-
const adjustedProfileSettings = Object.keys(adjustedProfile);
|
|
111
|
-
return originalProfileSettings.filter((setting) => !adjustedProfileSettings.
|
|
105
|
+
const adjustedProfileSettings = new Set(Object.keys(adjustedProfile));
|
|
106
|
+
return originalProfileSettings.filter((setting) => !adjustedProfileSettings.has(setting));
|
|
112
107
|
};
|
|
113
108
|
//# sourceMappingURL=packageProfileApi.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConvertResult } from '@salesforce/source-deploy-retrieve';
|
|
2
|
-
import { MDFolderForArtifactOptions, PackageVersionCreateOptions, PackageVersionCreateRequestResult } from '../interfaces';
|
|
2
|
+
import { MDFolderForArtifactOptions, PackageVersionCreateOptions, PackageVersionCreateRequestResult, PackageXml } from '../interfaces';
|
|
3
3
|
export declare class PackageVersionCreate {
|
|
4
4
|
private options;
|
|
5
5
|
private apiVersionFromPackageXml;
|
|
@@ -66,3 +66,8 @@ export declare class MetadataResolver {
|
|
|
66
66
|
*/
|
|
67
67
|
private convertMetadata;
|
|
68
68
|
}
|
|
69
|
+
export declare const packageXmlStringToPackageXmlJson: (rawXml: string) => PackageXml;
|
|
70
|
+
/**
|
|
71
|
+
* Converts PackageXmlJson to a string representing the Xml
|
|
72
|
+
* */
|
|
73
|
+
export declare const packageXmlJsonToXmlString: (packageXmlJson: PackageXml) => string;
|
|
@@ -6,15 +6,15 @@
|
|
|
6
6
|
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.MetadataResolver = exports.PackageVersionCreate = void 0;
|
|
9
|
+
exports.packageXmlJsonToXmlString = exports.packageXmlStringToPackageXmlJson = exports.MetadataResolver = exports.PackageVersionCreate = void 0;
|
|
10
10
|
const path = require("path");
|
|
11
11
|
const os = require("os");
|
|
12
12
|
const fs = require("fs");
|
|
13
13
|
const core_1 = require("@salesforce/core");
|
|
14
14
|
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
15
15
|
const scratchOrgSettingsGenerator_1 = require("@salesforce/core/lib/org/scratchOrgSettingsGenerator");
|
|
16
|
-
const xml2js = require("xml2js");
|
|
17
16
|
const kit_1 = require("@salesforce/kit");
|
|
17
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
18
18
|
const pkgUtils = require("../utils/packageUtils");
|
|
19
19
|
const packageUtils_1 = require("../utils/packageUtils");
|
|
20
20
|
const interfaces_1 = require("../interfaces");
|
|
@@ -329,16 +329,16 @@ class PackageVersionCreate {
|
|
|
329
329
|
// metadata exclusions. If necessary, read the existing package.xml and then re-write it.
|
|
330
330
|
const currentPackageXml = await fs.promises.readFile(path.join(packageVersMetadataFolder, 'package.xml'), 'utf8');
|
|
331
331
|
// convert to json
|
|
332
|
-
const packageXmlAsJson = (
|
|
333
|
-
if (!packageXmlAsJson
|
|
332
|
+
const packageXmlAsJson = (0, exports.packageXmlStringToPackageXmlJson)(currentPackageXml);
|
|
333
|
+
if (!packageXmlAsJson) {
|
|
334
334
|
throw messages.createError('packageXmlDoesNotContainPackage');
|
|
335
335
|
}
|
|
336
|
-
if (!packageXmlAsJson?.
|
|
336
|
+
if (!packageXmlAsJson?.types) {
|
|
337
337
|
throw messages.createError('packageXmlDoesNotContainPackageTypes');
|
|
338
338
|
}
|
|
339
339
|
fs.mkdirSync(packageVersMetadataFolder, { recursive: true });
|
|
340
340
|
fs.mkdirSync(packageVersProfileFolder, { recursive: true });
|
|
341
|
-
this.apiVersionFromPackageXml = packageXmlAsJson.
|
|
341
|
+
this.apiVersionFromPackageXml = packageXmlAsJson.version;
|
|
342
342
|
const sourceApiVersion = this.project?.getSfProjectJson()?.get('sourceApiVersion');
|
|
343
343
|
const hasSeedMetadata = await this.metadataResolver.resolveMetadata(this.packageObject.seedMetadata?.path, seedMetadataFolder, 'seedMDDirectoryDoesNotExist', sourceApiVersion);
|
|
344
344
|
let hasUnpackagedMetadata = false;
|
|
@@ -351,19 +351,16 @@ class PackageVersionCreate {
|
|
|
351
351
|
.getPackageDirectories()
|
|
352
352
|
.map((packageDir) => packageDir.unpackagedMetadata?.path)
|
|
353
353
|
.filter((packageDirPath) => packageDirPath);
|
|
354
|
-
const typesArr = this.options?.profileApi?.filterAndGenerateProfilesForManifest(packageXmlAsJson.
|
|
354
|
+
const typesArr = this.options?.profileApi?.filterAndGenerateProfilesForManifest(packageXmlAsJson.types, profileExcludeDirs) ??
|
|
355
|
+
packageXmlAsJson.types;
|
|
355
356
|
// Next generate profiles and retrieve any profiles that were excluded because they had no matching nodes.
|
|
356
357
|
const excludedProfiles = this.options?.profileApi?.generateProfiles(packageVersProfileFolder, typesArr, profileExcludeDirs);
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
packageXmlAsJson.Package.types = typesArr;
|
|
362
|
-
// Re-write the package.xml in case profiles have been added or removed
|
|
363
|
-
const xmlBuilder = new xml2js.Builder({
|
|
364
|
-
xmldec: { version: '1.0', encoding: 'UTF-8' },
|
|
358
|
+
packageXmlAsJson.types = typesArr.map((type) => {
|
|
359
|
+
if (type.name !== 'Profile')
|
|
360
|
+
return type;
|
|
361
|
+
return { ...type, members: type.members.filter((m) => !excludedProfiles?.includes(m)) };
|
|
365
362
|
});
|
|
366
|
-
const xml =
|
|
363
|
+
const xml = (0, exports.packageXmlJsonToXmlString)(packageXmlAsJson);
|
|
367
364
|
await fs.promises.writeFile(path.join(packageVersMetadataFolder, 'package.xml'), xml, 'utf-8');
|
|
368
365
|
// Zip the packageVersMetadataFolder folder and put the zip in {packageVersBlobDirectory}/package.zip
|
|
369
366
|
await (0, packageUtils_1.zipDir)(packageVersMetadataFolder, metadataZipFile);
|
|
@@ -850,4 +847,39 @@ class MetadataResolver {
|
|
|
850
847
|
}
|
|
851
848
|
}
|
|
852
849
|
exports.MetadataResolver = MetadataResolver;
|
|
850
|
+
const packageXmlStringToPackageXmlJson = (rawXml) => {
|
|
851
|
+
const parser = new fast_xml_parser_1.XMLParser({
|
|
852
|
+
ignoreAttributes: true,
|
|
853
|
+
parseTagValue: false,
|
|
854
|
+
parseAttributeValue: false,
|
|
855
|
+
cdataPropName: '__cdata',
|
|
856
|
+
ignoreDeclaration: true,
|
|
857
|
+
numberParseOptions: { leadingZeros: false, hex: false },
|
|
858
|
+
// make sure types and members is always an array
|
|
859
|
+
isArray: (name) => ['types', 'members'].includes(name),
|
|
860
|
+
});
|
|
861
|
+
return parser.parse(rawXml).Package;
|
|
862
|
+
};
|
|
863
|
+
exports.packageXmlStringToPackageXmlJson = packageXmlStringToPackageXmlJson;
|
|
864
|
+
/**
|
|
865
|
+
* Converts PackageXmlJson to a string representing the Xml
|
|
866
|
+
* */
|
|
867
|
+
const packageXmlJsonToXmlString = (packageXmlJson) => {
|
|
868
|
+
const builder = new fast_xml_parser_1.XMLBuilder({
|
|
869
|
+
format: true,
|
|
870
|
+
indentBy: ' ',
|
|
871
|
+
ignoreAttributes: false,
|
|
872
|
+
cdataPropName: '__cdata',
|
|
873
|
+
processEntities: false,
|
|
874
|
+
attributeNamePrefix: '@@@',
|
|
875
|
+
});
|
|
876
|
+
return String(builder.build({
|
|
877
|
+
'?xml': {
|
|
878
|
+
'@@@version': '1.0',
|
|
879
|
+
'@@@encoding': 'UTF-8',
|
|
880
|
+
},
|
|
881
|
+
Package: { ...packageXmlJson, '@@@xmlns': 'http://soap.sforce.com/2006/04/metadata' },
|
|
882
|
+
}));
|
|
883
|
+
};
|
|
884
|
+
exports.packageXmlJsonToXmlString = packageXmlJsonToXmlString;
|
|
853
885
|
//# sourceMappingURL=packageVersionCreate.js.map
|
|
@@ -22,10 +22,16 @@ export type CorrectedProfile = Profile & {
|
|
|
22
22
|
*/
|
|
23
23
|
export declare const profileRewriter: (profileJson: CorrectedProfile, packageXml: PackageMap, retainUserLicense?: boolean) => CorrectedProfile;
|
|
24
24
|
export declare const fieldCorrections: (fieldName: string) => string;
|
|
25
|
+
/**
|
|
26
|
+
* @param profileString: raw xml read from the file
|
|
27
|
+
* @returns CorrectedProfile (json representation of the profile)
|
|
28
|
+
*/
|
|
25
29
|
export declare const profileStringToProfile: (profileString: string) => CorrectedProfile;
|
|
26
|
-
/** pass in an object that has the Profile props at the top level.
|
|
30
|
+
/** pass in an object that has the Profile props at the top level.
|
|
31
|
+
* This function will add the outer wrapper `Profile` and convert the result to xml
|
|
32
|
+
* */
|
|
27
33
|
export declare const profileObjectToString: (profileObject: Partial<CorrectedProfile>) => string;
|
|
28
34
|
/** it's easier to do lookups by Metadata Type on a Map */
|
|
29
|
-
export declare const manifestTypesToMap: (original: PackageXml['
|
|
35
|
+
export declare const manifestTypesToMap: (original: PackageXml['types']) => PackageMap;
|
|
30
36
|
type PackageMap = Map<string, string[]>;
|
|
31
37
|
export {};
|
|
@@ -64,19 +64,26 @@ const allMembers = (packageXml) => Array.from(packageXml.values()).flat();
|
|
|
64
64
|
// profile.fieldPermissions will display them with the more specific 'Task' or 'Event'
|
|
65
65
|
const fieldCorrections = (fieldName) => fieldName.replace(/^Event\./, 'Activity.').replace(/^Task\./, 'Activity.');
|
|
66
66
|
exports.fieldCorrections = fieldCorrections;
|
|
67
|
+
/**
|
|
68
|
+
* @param profileString: raw xml read from the file
|
|
69
|
+
* @returns CorrectedProfile (json representation of the profile)
|
|
70
|
+
*/
|
|
67
71
|
const profileStringToProfile = (profileString) => {
|
|
68
72
|
const parser = new fast_xml_parser_1.XMLParser({
|
|
69
|
-
ignoreAttributes:
|
|
73
|
+
ignoreAttributes: true,
|
|
70
74
|
parseTagValue: false,
|
|
71
75
|
parseAttributeValue: false,
|
|
72
76
|
cdataPropName: '__cdata',
|
|
73
77
|
ignoreDeclaration: true,
|
|
74
78
|
numberParseOptions: { leadingZeros: false, hex: false },
|
|
79
|
+
isArray: (name) => rewriteProps.includes(name),
|
|
75
80
|
});
|
|
76
|
-
return parser.parse(profileString);
|
|
81
|
+
return parser.parse(profileString).Profile;
|
|
77
82
|
};
|
|
78
83
|
exports.profileStringToProfile = profileStringToProfile;
|
|
79
|
-
/** pass in an object that has the Profile props at the top level.
|
|
84
|
+
/** pass in an object that has the Profile props at the top level.
|
|
85
|
+
* This function will add the outer wrapper `Profile` and convert the result to xml
|
|
86
|
+
* */
|
|
80
87
|
const profileObjectToString = (profileObject) => {
|
|
81
88
|
const builder = new fast_xml_parser_1.XMLBuilder({
|
|
82
89
|
format: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/packaging",
|
|
3
|
-
"version": "2.2.9-profiles.
|
|
3
|
+
"version": "2.2.9-profiles.1",
|
|
4
4
|
"description": "Packaging library for the Salesforce packaging platform",
|
|
5
5
|
"main": "lib/exported",
|
|
6
6
|
"types": "lib/exported.d.ts",
|
|
@@ -53,8 +53,7 @@
|
|
|
53
53
|
"graphology-traversal": "^0.3.1",
|
|
54
54
|
"graphology-types": "^0.24.7",
|
|
55
55
|
"jsforce": "^2.0.0-beta.27",
|
|
56
|
-
"jszip": "^3.10.1"
|
|
57
|
-
"xml2js": "^0.6.0"
|
|
56
|
+
"jszip": "^3.10.1"
|
|
58
57
|
},
|
|
59
58
|
"devDependencies": {
|
|
60
59
|
"@salesforce/cli-plugins-testkit": "^4.1.1",
|
|
@@ -64,7 +63,6 @@
|
|
|
64
63
|
"@salesforce/ts-sinon": "^1.4.11",
|
|
65
64
|
"@types/globby": "^9.1.0",
|
|
66
65
|
"@types/jszip": "^3.4.1",
|
|
67
|
-
"@types/xml2js": "^0.4.11",
|
|
68
66
|
"@typescript-eslint/eslint-plugin": "^5.60.0",
|
|
69
67
|
"@typescript-eslint/parser": "^5.61.0",
|
|
70
68
|
"chai": "^4.3.7",
|