@salesforce/packaging 2.2.8 → 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 +2 -1
- package/lib/package/packageProfileApi.d.ts +6 -42
- package/lib/package/packageProfileApi.js +58 -234
- package/lib/package/packageVersionCreate.d.ts +6 -1
- package/lib/package/packageVersionCreate.js +63 -36
- package/lib/package/profileRewriter.d.ts +37 -0
- package/lib/package/profileRewriter.js +108 -0
- package/package.json +7 -14
|
@@ -4,6 +4,7 @@ import { SaveResult } from 'jsforce';
|
|
|
4
4
|
import { Attributes } from 'graphology-types';
|
|
5
5
|
import { Optional } from '@salesforce/ts-types';
|
|
6
6
|
import { ConvertResult } from '@salesforce/source-deploy-retrieve';
|
|
7
|
+
import { Package } from 'jsforce/lib/api/metadata';
|
|
7
8
|
import { PackageProfileApi } from '../package/packageProfileApi';
|
|
8
9
|
import { PackageAncestryNode } from '../package/packageAncestry';
|
|
9
10
|
import { PackagingSObjects } from './packagingSObjects';
|
|
@@ -269,7 +270,6 @@ export type PackageVersionCreateRequestQueryOptions = {
|
|
|
269
270
|
export type ProfileApiOptions = {
|
|
270
271
|
project: SfProject;
|
|
271
272
|
includeUserLicenses: boolean;
|
|
272
|
-
generateProfileInformation: boolean;
|
|
273
273
|
};
|
|
274
274
|
export type PackageVersionReportResult = Partial<Omit<PackagingSObjects.Package2Version, 'AncestorId' | 'HasPassedCodeCoverageCheck' | 'HasMetadataRemoved'>> & {
|
|
275
275
|
Package2: Partial<Omit<PackagingSObjects.Package2, 'IsOrgDependent'>> & {
|
|
@@ -370,3 +370,4 @@ export declare const Package1VersionEvents: {
|
|
|
370
370
|
progress: string;
|
|
371
371
|
};
|
|
372
372
|
};
|
|
373
|
+
export type PackageXml = Pick<Package, 'types' | 'version'>;
|
|
@@ -1,63 +1,27 @@
|
|
|
1
1
|
import { SfProject } from '@salesforce/core';
|
|
2
2
|
import { AsyncCreatable } from '@salesforce/kit';
|
|
3
|
-
import { ProfileApiOptions } from '../interfaces';
|
|
3
|
+
import { PackageXml, ProfileApiOptions } from '../interfaces';
|
|
4
4
|
export declare class PackageProfileApi extends AsyncCreatable<ProfileApiOptions> {
|
|
5
|
-
readonly profiles: ProfileInformation[];
|
|
6
|
-
nodeEntities: {
|
|
7
|
-
name: string[];
|
|
8
|
-
parentElement: string[];
|
|
9
|
-
childElement: string[];
|
|
10
|
-
};
|
|
11
|
-
otherProfileSettings: {
|
|
12
|
-
name: string[];
|
|
13
|
-
parentElement: string[];
|
|
14
|
-
childElement: string[];
|
|
15
|
-
};
|
|
16
5
|
project: SfProject;
|
|
17
6
|
includeUserLicenses: boolean;
|
|
18
|
-
generateProfileInformation: boolean;
|
|
19
7
|
constructor(options: ProfileApiOptions);
|
|
20
8
|
init(): Promise<void>;
|
|
21
9
|
/**
|
|
22
10
|
* For any profile present in the workspace, this function generates a subset of data that only contains references
|
|
23
11
|
* to items in the manifest.
|
|
24
12
|
*
|
|
13
|
+
* return a list of profile file locations that need to be removed from the package because they are empty
|
|
14
|
+
*
|
|
25
15
|
* @param destPath location of new profiles
|
|
26
|
-
* @param
|
|
16
|
+
* @param manifestTypes: array of objects { name: string, members: string[] } that represent package xml types
|
|
27
17
|
* @param excludedDirectories Directories to not include profiles from
|
|
28
18
|
*/
|
|
29
|
-
generateProfiles(destPath: string,
|
|
30
|
-
Package: Array<{
|
|
31
|
-
name: string[];
|
|
32
|
-
members: string[];
|
|
33
|
-
}>;
|
|
34
|
-
}, excludedDirectories?: string[]): string[];
|
|
19
|
+
generateProfiles(destPath: string, manifestTypes: PackageXml['types'], excludedDirectories?: string[]): string[];
|
|
35
20
|
/**
|
|
36
21
|
* Filter out all profiles in the manifest and if any profiles exists in the workspace, add them to the manifest.
|
|
37
22
|
*
|
|
38
23
|
* @param typesArr array of objects { name[], members[] } that represent package types JSON.
|
|
39
24
|
* @param excludedDirectories Direcotires not to generate profiles for
|
|
40
25
|
*/
|
|
41
|
-
filterAndGenerateProfilesForManifest(typesArr:
|
|
42
|
-
name: string[];
|
|
43
|
-
members: string[];
|
|
44
|
-
}>, excludedDirectories?: string[]): Array<{
|
|
45
|
-
name: string[];
|
|
46
|
-
members: string[];
|
|
47
|
-
}>;
|
|
48
|
-
getProfileInformation(): ProfileInformation[];
|
|
49
|
-
private copyNodes;
|
|
50
|
-
private findAllProfiles;
|
|
51
|
-
}
|
|
52
|
-
declare class ProfileInformation {
|
|
53
|
-
ProfileName: string;
|
|
54
|
-
ProfilePath: string;
|
|
55
|
-
IsPackaged: boolean;
|
|
56
|
-
settingsRemoved: string[];
|
|
57
|
-
constructor(ProfileName: string, ProfilePath: string, IsPackaged: boolean, settingsRemoved: string[]);
|
|
58
|
-
setIsPackaged(IsPackaged: boolean): void;
|
|
59
|
-
appendRemovedSetting(setting: string): void;
|
|
60
|
-
logDebug(): string;
|
|
61
|
-
logInfo(): string;
|
|
26
|
+
filterAndGenerateProfilesForManifest(typesArr: PackageXml['types'], excludedDirectories?: string[]): PackageXml['types'];
|
|
62
27
|
}
|
|
63
|
-
export {};
|
|
@@ -1,77 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PackageProfileApi = void 0;
|
|
2
4
|
/*
|
|
3
5
|
* Copyright (c) 2022, salesforce.com, inc.
|
|
4
6
|
* All rights reserved.
|
|
5
7
|
* Licensed under the BSD 3-Clause license.
|
|
6
8
|
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
9
|
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.PackageProfileApi = void 0;
|
|
10
10
|
const path = require("path");
|
|
11
11
|
const fs = require("fs");
|
|
12
12
|
const glob = require("glob");
|
|
13
|
-
const xmldom_1 = require("@xmldom/xmldom");
|
|
14
13
|
const core_1 = require("@salesforce/core");
|
|
15
14
|
const kit_1 = require("@salesforce/kit");
|
|
15
|
+
const profileRewriter_1 = require("./profileRewriter");
|
|
16
16
|
core_1.Messages.importMessagesDirectory(__dirname);
|
|
17
17
|
const profileApiMessages = core_1.Messages.loadMessages('@salesforce/packaging', 'profile_api');
|
|
18
|
-
// nodeEntities is used to determine which elements in the profile are relevant to the source being packaged.
|
|
19
|
-
// name refers to the entity type name in source that the element pertains to. As an example, a profile may
|
|
20
|
-
// have an entry like the example below, which should only be added to the packaged profile if the related
|
|
21
|
-
// CustomObject is in the source being packaged:
|
|
22
|
-
// <objectPermissions>
|
|
23
|
-
// <allowCreate>true</allowCreate>
|
|
24
|
-
// ...
|
|
25
|
-
// <object>MyCustomObject__c</object>
|
|
26
|
-
// ...
|
|
27
|
-
// </objectPermissions>
|
|
28
|
-
//
|
|
29
|
-
// For this example: nodeEntities.parentElement = objectPermissions and nodeEntities.childElement = object
|
|
30
|
-
const NODE_ENTITIES = {
|
|
31
|
-
name: [
|
|
32
|
-
'CustomObject',
|
|
33
|
-
'CustomField',
|
|
34
|
-
'Layout',
|
|
35
|
-
'CustomTab',
|
|
36
|
-
'CustomApplication',
|
|
37
|
-
'ApexClass',
|
|
38
|
-
'CustomPermission',
|
|
39
|
-
'ApexPage',
|
|
40
|
-
'ExternalDataSource',
|
|
41
|
-
'RecordType',
|
|
42
|
-
],
|
|
43
|
-
parentElement: [
|
|
44
|
-
'objectPermissions',
|
|
45
|
-
'fieldPermissions',
|
|
46
|
-
'layoutAssignments',
|
|
47
|
-
'tabVisibilities',
|
|
48
|
-
'applicationVisibilities',
|
|
49
|
-
'classAccesses',
|
|
50
|
-
'customPermissions',
|
|
51
|
-
'pageAccesses',
|
|
52
|
-
'externalDataSourceAccesses',
|
|
53
|
-
'recordTypeVisibilities',
|
|
54
|
-
],
|
|
55
|
-
childElement: [
|
|
56
|
-
'object',
|
|
57
|
-
'field',
|
|
58
|
-
'layout',
|
|
59
|
-
'tab',
|
|
60
|
-
'application',
|
|
61
|
-
'apexClass',
|
|
62
|
-
'name',
|
|
63
|
-
'apexPage',
|
|
64
|
-
'externalDataSource',
|
|
65
|
-
'recordType',
|
|
66
|
-
],
|
|
67
|
-
};
|
|
68
|
-
// There are some profile settings that are allowed to be packaged that may not necessarily map to a specific metadata
|
|
69
|
-
// object. We should still handle these accordingly, but a little differently than the above mentioned types.
|
|
70
|
-
const OTHER_PROFILE_SETTINGS = {
|
|
71
|
-
name: ['CustomSettings', 'CustomMetadataTypeAccess'],
|
|
72
|
-
parentElement: ['customSettingAccesses', 'customMetadataTypeAccesses'],
|
|
73
|
-
childElement: ['name', 'name'],
|
|
74
|
-
};
|
|
75
18
|
/*
|
|
76
19
|
* This class provides functions used to re-write .profiles in the workspace when creating a package2 version.
|
|
77
20
|
* All profiles found in the workspaces are extracted out and then re-written to only include metadata in the profile
|
|
@@ -80,14 +23,9 @@ const OTHER_PROFILE_SETTINGS = {
|
|
|
80
23
|
class PackageProfileApi extends kit_1.AsyncCreatable {
|
|
81
24
|
constructor(options) {
|
|
82
25
|
super(options);
|
|
83
|
-
this.profiles = [];
|
|
84
|
-
this.nodeEntities = NODE_ENTITIES;
|
|
85
|
-
this.otherProfileSettings = OTHER_PROFILE_SETTINGS;
|
|
86
26
|
this.includeUserLicenses = false;
|
|
87
|
-
this.generateProfileInformation = false;
|
|
88
27
|
this.project = options.project;
|
|
89
28
|
this.includeUserLicenses = options.includeUserLicenses ?? false;
|
|
90
|
-
this.generateProfileInformation = options.generateProfileInformation ?? false;
|
|
91
29
|
}
|
|
92
30
|
// eslint-disable-next-line class-methods-use-this,@typescript-eslint/no-empty-function
|
|
93
31
|
async init() { }
|
|
@@ -95,91 +33,45 @@ class PackageProfileApi extends kit_1.AsyncCreatable {
|
|
|
95
33
|
* For any profile present in the workspace, this function generates a subset of data that only contains references
|
|
96
34
|
* to items in the manifest.
|
|
97
35
|
*
|
|
36
|
+
* return a list of profile file locations that need to be removed from the package because they are empty
|
|
37
|
+
*
|
|
98
38
|
* @param destPath location of new profiles
|
|
99
|
-
* @param
|
|
39
|
+
* @param manifestTypes: array of objects { name: string, members: string[] } that represent package xml types
|
|
100
40
|
* @param excludedDirectories Directories to not include profiles from
|
|
101
41
|
*/
|
|
102
|
-
generateProfiles(destPath,
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
// Go through each of the other profile settings we might want to include. We pass in "all" the members since these
|
|
131
|
-
// will reference anything that could be packaged. The "copyNodes" function will only include the type if it
|
|
132
|
-
// exists in the profile itself
|
|
133
|
-
this.otherProfileSettings.name.forEach((element) => {
|
|
134
|
-
const idx = this.otherProfileSettings.name.indexOf(element);
|
|
135
|
-
if (idx > -1) {
|
|
136
|
-
hasNodes =
|
|
137
|
-
this.copyNodes(profileDom, this.otherProfileSettings.parentElement[idx], this.otherProfileSettings.childElement[idx], allMembers, profileNode, profileName) || hasNodes;
|
|
138
|
-
}
|
|
42
|
+
generateProfiles(destPath, manifestTypes, excludedDirectories = []) {
|
|
43
|
+
const logger = core_1.Logger.childFromRoot('PackageProfileApi');
|
|
44
|
+
return (getProfilesWithNamesAndPaths({
|
|
45
|
+
projectPath: this.project.getPath(),
|
|
46
|
+
excludedDirectories,
|
|
47
|
+
})
|
|
48
|
+
.map(({ profilePath, name: profileName }) => {
|
|
49
|
+
const originalProfile = (0, profileRewriter_1.profileStringToProfile)(fs.readFileSync(profilePath, 'utf-8'));
|
|
50
|
+
const adjustedProfile = (0, profileRewriter_1.profileRewriter)(originalProfile, (0, profileRewriter_1.manifestTypesToMap)(manifestTypes), this.includeUserLicenses);
|
|
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 }) => {
|
|
62
|
+
if (!hasContent) {
|
|
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;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
logger.info(profileApiMessages.getMessage('addProfileToPackage', [profileName, profilePath]));
|
|
68
|
+
removedSettings.forEach((setting) => {
|
|
69
|
+
logger.info(profileApiMessages.getMessage('removeProfileSetting', [setting, profileName]));
|
|
139
70
|
});
|
|
140
|
-
|
|
141
|
-
if (this.includeUserLicenses) {
|
|
142
|
-
const userLicenses = profileDom.getElementsByTagName('userLicense');
|
|
143
|
-
if (userLicenses) {
|
|
144
|
-
hasNodes = true;
|
|
145
|
-
for (const userLicense of Array.from(userLicenses)) {
|
|
146
|
-
profileNode.appendChild(userLicense.cloneNode(true));
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
const xmlSrcFile = path.basename(profilePath);
|
|
151
|
-
const xmlFile = xmlSrcFile.replace(/(.*)(-meta.xml)/, '$1');
|
|
152
|
-
const destFilePath = path.join(destPath, xmlFile);
|
|
153
|
-
if (hasNodes) {
|
|
154
|
-
const serializer = new xmldom_1.XMLSerializer();
|
|
155
|
-
serializer.serializeToString(newDom);
|
|
156
|
-
fs.writeFileSync(destFilePath, serializer.serializeToString(newDom), 'utf-8');
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
// remove from manifest
|
|
160
|
-
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
161
|
-
const profileName = xmlFile.replace(/(.*)(\.profile)/, '$1');
|
|
162
|
-
excludedProfiles.push(profileName);
|
|
163
|
-
if (this.generateProfileInformation) {
|
|
164
|
-
const profile = this.profiles.find(({ ProfileName }) => ProfileName === profileName);
|
|
165
|
-
if (profile) {
|
|
166
|
-
profile.setIsPackaged(false);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
try {
|
|
170
|
-
fs.unlinkSync(destFilePath);
|
|
171
|
-
}
|
|
172
|
-
catch (err) {
|
|
173
|
-
// It is normal for the file to not exist if the profile is in the workspace but not in the directory being packaged.
|
|
174
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
175
|
-
if (err instanceof Error && 'code' in err && err.code !== 'ENOENT') {
|
|
176
|
-
throw err;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
71
|
+
fs.writeFileSync(xmlFileLocation, (0, profileRewriter_1.profileObjectToString)(adjustedProfile), 'utf-8');
|
|
180
72
|
}
|
|
181
|
-
})
|
|
182
|
-
|
|
73
|
+
})
|
|
74
|
+
.map(({ xmlFileLocation }) => xmlFileLocation.replace(/(.*)(\.profile)/, '$1')));
|
|
183
75
|
}
|
|
184
76
|
/**
|
|
185
77
|
* Filter out all profiles in the manifest and if any profiles exists in the workspace, add them to the manifest.
|
|
@@ -188,97 +80,29 @@ class PackageProfileApi extends kit_1.AsyncCreatable {
|
|
|
188
80
|
* @param excludedDirectories Direcotires not to generate profiles for
|
|
189
81
|
*/
|
|
190
82
|
filterAndGenerateProfilesForManifest(typesArr, excludedDirectories = []) {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (profilePaths) {
|
|
195
|
-
const members = [];
|
|
196
|
-
profilePaths.forEach((profilePath) => {
|
|
197
|
-
// profile metadata can present in any directory in the package structure
|
|
198
|
-
const profileNameMatch = profilePath.match(/([^/]+)\.profile-meta.xml/);
|
|
199
|
-
const profileName = profileNameMatch ? profileNameMatch[1] : null;
|
|
200
|
-
if (profileName) {
|
|
201
|
-
members.push(profileName);
|
|
202
|
-
if (this.generateProfileInformation) {
|
|
203
|
-
this.profiles.push(new ProfileInformation(profileName, profilePath, true, []));
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
if (members.length > 0) {
|
|
208
|
-
filteredTypesArr.push({ name: ['Profile'], members });
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return filteredTypesArr;
|
|
212
|
-
}
|
|
213
|
-
getProfileInformation() {
|
|
214
|
-
return this.profiles;
|
|
215
|
-
}
|
|
216
|
-
copyNodes(originalDom, parentElement, childElement, members, appendToNode, profileName) {
|
|
217
|
-
let nodesAdded = false;
|
|
218
|
-
const nodes = originalDom.getElementsByTagName(parentElement);
|
|
219
|
-
if (!nodes) {
|
|
220
|
-
return nodesAdded;
|
|
221
|
-
}
|
|
222
|
-
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
223
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
224
|
-
const name = nodes[i].getElementsByTagName(childElement)[0].childNodes[0].nodeValue;
|
|
225
|
-
if (name) {
|
|
226
|
-
if (members.includes(name)) {
|
|
227
|
-
// appendChild will take the passed in node (newNode) and find the parent if it exists and then remove
|
|
228
|
-
// the newNode from the parent. This causes issues with the way this is copying the nodes, so pass in a clone instead.
|
|
229
|
-
const currentNode = nodes[i].cloneNode(true);
|
|
230
|
-
appendToNode.appendChild(currentNode);
|
|
231
|
-
nodesAdded = true;
|
|
232
|
-
}
|
|
233
|
-
else if (this.generateProfileInformation) {
|
|
234
|
-
// Tell the user which profile setting has been removed from the package
|
|
235
|
-
const profile = this.profiles.find(({ ProfileName }) => ProfileName === profileName);
|
|
236
|
-
if (profile) {
|
|
237
|
-
profile.appendRemovedSetting(name);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return nodesAdded;
|
|
243
|
-
}
|
|
244
|
-
findAllProfiles(excludedDirectories = []) {
|
|
245
|
-
return glob.sync(path.join(this.project.getPath(), '**', '*.profile-meta.xml'), {
|
|
246
|
-
ignore: excludedDirectories.map((dir) => `**/${dir}/**`),
|
|
83
|
+
const profilePathsWithNames = getProfilesWithNamesAndPaths({
|
|
84
|
+
projectPath: this.project.getPath(),
|
|
85
|
+
excludedDirectories,
|
|
247
86
|
});
|
|
87
|
+
// Filter all profiles, and add back the ones we found names for
|
|
88
|
+
return typesArr
|
|
89
|
+
.filter((kvp) => kvp.name !== 'Profile')
|
|
90
|
+
.concat([{ name: 'Profile', members: profilePathsWithNames.map((i) => i.name) }]);
|
|
248
91
|
}
|
|
249
92
|
}
|
|
250
93
|
exports.PackageProfileApi = PackageProfileApi;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
let info = profileApiMessages.getMessage('addProfileToPackage', [this.ProfileName, this.ProfilePath]);
|
|
266
|
-
this.settingsRemoved.forEach((setting) => {
|
|
267
|
-
info += '\n\t' + profileApiMessages.getMessage('removeProfileSetting', [setting, this.ProfileName]);
|
|
268
|
-
});
|
|
269
|
-
if (!this.IsPackaged) {
|
|
270
|
-
info += '\n\t' + profileApiMessages.getMessage('removeProfile', [this.ProfileName]);
|
|
271
|
-
}
|
|
272
|
-
info += '\n';
|
|
273
|
-
return info;
|
|
274
|
-
}
|
|
275
|
-
logInfo() {
|
|
276
|
-
if (this.IsPackaged) {
|
|
277
|
-
return profileApiMessages.getMessage('addProfileToPackage', [this.ProfileName, this.ProfilePath]);
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
return profileApiMessages.getMessage('profileNotIncluded', [this.ProfileName]);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
94
|
+
const findAllProfiles = ({ projectPath, excludedDirectories = [], }) => glob.sync(path.join(projectPath, '**', '*.profile-meta.xml'), {
|
|
95
|
+
ignore: excludedDirectories.map((dir) => `**/${dir}/**`),
|
|
96
|
+
});
|
|
97
|
+
const isProfilePathWithName = (profilePathWithName) => typeof profilePathWithName.name === 'string';
|
|
98
|
+
const profilePathToName = (profilePath) => profilePath.match(/([^/]+)\.profile-meta.xml/)?.[1];
|
|
99
|
+
const getProfilesWithNamesAndPaths = ({ projectPath, excludedDirectories, }) => findAllProfiles({ projectPath, excludedDirectories })
|
|
100
|
+
.map((profilePath) => ({ profilePath, name: profilePathToName(profilePath) }))
|
|
101
|
+
.filter(isProfilePathWithName);
|
|
102
|
+
const getXmlFileLocation = (destPath, profilePath) => path.join(destPath, path.basename(profilePath).replace(/(.*)(-meta.xml)/, '$1'));
|
|
103
|
+
const getRemovedSettings = (originalProfile, adjustedProfile) => {
|
|
104
|
+
const originalProfileSettings = Object.keys(originalProfile);
|
|
105
|
+
const adjustedProfileSettings = new Set(Object.keys(adjustedProfile));
|
|
106
|
+
return originalProfileSettings.filter((setting) => !adjustedProfileSettings.has(setting));
|
|
107
|
+
};
|
|
284
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");
|
|
@@ -240,8 +240,6 @@ class PackageVersionCreate {
|
|
|
240
240
|
sourceDir: sourceBaseDir,
|
|
241
241
|
sourceApiVersion: this.project?.getSfProjectJson()?.get('sourceApiVersion') ?? undefined,
|
|
242
242
|
};
|
|
243
|
-
// Stores any additional client side info that might be needed later on in the process
|
|
244
|
-
const clientSideInfo = new Map();
|
|
245
243
|
await fs.promises.mkdir(packageVersBlobDirectory, { recursive: true });
|
|
246
244
|
const settingsGenerator = new scratchOrgSettingsGenerator_1.default({ asDirectory: true });
|
|
247
245
|
let packageDescriptorJson = (0, kit_1.cloneJson)(this.packageObject);
|
|
@@ -305,7 +303,19 @@ class PackageVersionCreate {
|
|
|
305
303
|
}
|
|
306
304
|
packageDescriptorJson.ancestorId = ancestorId;
|
|
307
305
|
await fs.promises.writeFile(path.join(packageVersBlobDirectory, DESCRIPTOR_FILE), JSON.stringify(packageDescriptorJson), 'utf-8');
|
|
308
|
-
await this.cleanGeneratedPackage(
|
|
306
|
+
await this.cleanGeneratedPackage({
|
|
307
|
+
packageVersMetadataFolder,
|
|
308
|
+
packageVersProfileFolder,
|
|
309
|
+
unpackagedMetadataFolder,
|
|
310
|
+
seedMetadataFolder,
|
|
311
|
+
metadataZipFile,
|
|
312
|
+
settingsZipFile,
|
|
313
|
+
packageVersBlobDirectory,
|
|
314
|
+
packageVersBlobZipFile,
|
|
315
|
+
unpackagedMetadataZipFile,
|
|
316
|
+
seedMetadataZipFile,
|
|
317
|
+
settingsGenerator,
|
|
318
|
+
});
|
|
309
319
|
return this.createRequestObject(preserveFiles, packageVersTmpRoot, packageVersBlobZipFile);
|
|
310
320
|
}
|
|
311
321
|
verifyHasSource(componentSet) {
|
|
@@ -313,22 +323,22 @@ class PackageVersionCreate {
|
|
|
313
323
|
throw messages.createError('noSourceInRootDirectory', [this.packageObject.path ?? '<unknown>']);
|
|
314
324
|
}
|
|
315
325
|
}
|
|
316
|
-
async cleanGeneratedPackage(packageVersMetadataFolder, packageVersProfileFolder, unpackagedMetadataFolder, seedMetadataFolder, metadataZipFile, settingsZipFile, packageVersBlobDirectory, packageVersBlobZipFile, unpackagedMetadataZipFile, seedMetadataZipFile,
|
|
326
|
+
async cleanGeneratedPackage({ packageVersMetadataFolder, packageVersProfileFolder, unpackagedMetadataFolder, seedMetadataFolder, metadataZipFile, settingsZipFile, packageVersBlobDirectory, packageVersBlobZipFile, unpackagedMetadataZipFile, seedMetadataZipFile, settingsGenerator, }) {
|
|
317
327
|
// As part of the source convert process, the package.xml has been written into the tmp metadata directory.
|
|
318
328
|
// The package.xml may need to be manipulated due to processing profiles in the workspace or additional
|
|
319
329
|
// metadata exclusions. If necessary, read the existing package.xml and then re-write it.
|
|
320
330
|
const currentPackageXml = await fs.promises.readFile(path.join(packageVersMetadataFolder, 'package.xml'), 'utf8');
|
|
321
331
|
// convert to json
|
|
322
|
-
const
|
|
323
|
-
if (!
|
|
332
|
+
const packageXmlAsJson = (0, exports.packageXmlStringToPackageXmlJson)(currentPackageXml);
|
|
333
|
+
if (!packageXmlAsJson) {
|
|
324
334
|
throw messages.createError('packageXmlDoesNotContainPackage');
|
|
325
335
|
}
|
|
326
|
-
if (!
|
|
336
|
+
if (!packageXmlAsJson?.types) {
|
|
327
337
|
throw messages.createError('packageXmlDoesNotContainPackageTypes');
|
|
328
338
|
}
|
|
329
339
|
fs.mkdirSync(packageVersMetadataFolder, { recursive: true });
|
|
330
340
|
fs.mkdirSync(packageVersProfileFolder, { recursive: true });
|
|
331
|
-
this.apiVersionFromPackageXml =
|
|
341
|
+
this.apiVersionFromPackageXml = packageXmlAsJson.version;
|
|
332
342
|
const sourceApiVersion = this.project?.getSfProjectJson()?.get('sourceApiVersion');
|
|
333
343
|
const hasSeedMetadata = await this.metadataResolver.resolveMetadata(this.packageObject.seedMetadata?.path, seedMetadataFolder, 'seedMDDirectoryDoesNotExist', sourceApiVersion);
|
|
334
344
|
let hasUnpackagedMetadata = false;
|
|
@@ -341,32 +351,16 @@ class PackageVersionCreate {
|
|
|
341
351
|
.getPackageDirectories()
|
|
342
352
|
.map((packageDir) => packageDir.unpackagedMetadata?.path)
|
|
343
353
|
.filter((packageDirPath) => packageDirPath);
|
|
344
|
-
const typesArr = this.options?.profileApi?.filterAndGenerateProfilesForManifest(
|
|
345
|
-
|
|
354
|
+
const typesArr = this.options?.profileApi?.filterAndGenerateProfilesForManifest(packageXmlAsJson.types, profileExcludeDirs) ??
|
|
355
|
+
packageXmlAsJson.types;
|
|
346
356
|
// Next generate profiles and retrieve any profiles that were excluded because they had no matching nodes.
|
|
347
|
-
const excludedProfiles = this.options?.profileApi?.generateProfiles(packageVersProfileFolder,
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
typesArr[profileIdx].members = typesArr[profileIdx].members.filter((e) => !excludedProfiles.includes(e));
|
|
353
|
-
}
|
|
354
|
-
packageJson.Package.types = typesArr;
|
|
355
|
-
// Re-write the package.xml in case profiles have been added or removed
|
|
356
|
-
const xmlBuilder = new xml2js.Builder({
|
|
357
|
-
xmldec: { version: '1.0', encoding: 'UTF-8' },
|
|
358
|
-
});
|
|
359
|
-
const xml = xmlBuilder.buildObject(packageJson);
|
|
360
|
-
// Log information about the profiles being packaged up
|
|
361
|
-
const profiles = this.options?.profileApi?.getProfileInformation() ?? [];
|
|
362
|
-
profiles.forEach((profile) => {
|
|
363
|
-
if (this.logger.shouldLog(core_1.LoggerLevel.DEBUG)) {
|
|
364
|
-
this.logger.debug(profile.logDebug());
|
|
365
|
-
}
|
|
366
|
-
else if (this.logger.shouldLog(core_1.LoggerLevel.INFO)) {
|
|
367
|
-
this.logger.info(profile.logInfo());
|
|
368
|
-
}
|
|
357
|
+
const excludedProfiles = this.options?.profileApi?.generateProfiles(packageVersProfileFolder, typesArr, profileExcludeDirs);
|
|
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)) };
|
|
369
362
|
});
|
|
363
|
+
const xml = (0, exports.packageXmlJsonToXmlString)(packageXmlAsJson);
|
|
370
364
|
await fs.promises.writeFile(path.join(packageVersMetadataFolder, 'package.xml'), xml, 'utf-8');
|
|
371
365
|
// Zip the packageVersMetadataFolder folder and put the zip in {packageVersBlobDirectory}/package.zip
|
|
372
366
|
await (0, packageUtils_1.zipDir)(packageVersMetadataFolder, metadataZipFile);
|
|
@@ -512,11 +506,9 @@ class PackageVersionCreate {
|
|
|
512
506
|
return this.pkg.getType();
|
|
513
507
|
}
|
|
514
508
|
async resolveUserLicenses(includeUserLicenses) {
|
|
515
|
-
const shouldGenerateProfileInformation = this.logger.shouldLog(core_1.LoggerLevel.INFO) || this.logger.shouldLog(core_1.LoggerLevel.DEBUG);
|
|
516
509
|
return packageProfileApi_1.PackageProfileApi.create({
|
|
517
510
|
project: this.project,
|
|
518
511
|
includeUserLicenses,
|
|
519
|
-
generateProfileInformation: shouldGenerateProfileInformation,
|
|
520
512
|
});
|
|
521
513
|
}
|
|
522
514
|
async validateOptionsForPackageType() {
|
|
@@ -855,4 +847,39 @@ class MetadataResolver {
|
|
|
855
847
|
}
|
|
856
848
|
}
|
|
857
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;
|
|
858
885
|
//# sourceMappingURL=packageVersionCreate.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Profile } from 'jsforce/api/metadata';
|
|
2
|
+
import { PackageXml } from '../interfaces';
|
|
3
|
+
type ProfileCustomSettingAccess = {
|
|
4
|
+
name: string;
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type CorrectedProfile = Profile & {
|
|
8
|
+
customSettingAccesses: ProfileCustomSettingAccess[];
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* Takes a Profile that's been converted from package.xml to json.
|
|
13
|
+
* Filters out all Profile props that are not
|
|
14
|
+
* 1. used by packaging (ex: ipRanges)
|
|
15
|
+
* 2. present in the package.xml (ex: ClassAccesses for a class not in the package)
|
|
16
|
+
* 3. optionally retains the UserLicense prop only if the param is true
|
|
17
|
+
*
|
|
18
|
+
* @param profileJson json representation of a profile
|
|
19
|
+
* @param packageXml package.xml as json
|
|
20
|
+
* @param retainUserLicense boolean will preserve userLicense if true
|
|
21
|
+
* @returns Profile
|
|
22
|
+
*/
|
|
23
|
+
export declare const profileRewriter: (profileJson: CorrectedProfile, packageXml: PackageMap, retainUserLicense?: boolean) => CorrectedProfile;
|
|
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
|
+
*/
|
|
29
|
+
export declare const profileStringToProfile: (profileString: string) => CorrectedProfile;
|
|
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
|
+
* */
|
|
33
|
+
export declare const profileObjectToString: (profileObject: Partial<CorrectedProfile>) => string;
|
|
34
|
+
/** it's easier to do lookups by Metadata Type on a Map */
|
|
35
|
+
export declare const manifestTypesToMap: (original: PackageXml['types']) => PackageMap;
|
|
36
|
+
type PackageMap = Map<string, string[]>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.manifestTypesToMap = exports.profileObjectToString = exports.profileStringToProfile = exports.fieldCorrections = exports.profileRewriter = void 0;
|
|
4
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* Takes a Profile that's been converted from package.xml to json.
|
|
8
|
+
* Filters out all Profile props that are not
|
|
9
|
+
* 1. used by packaging (ex: ipRanges)
|
|
10
|
+
* 2. present in the package.xml (ex: ClassAccesses for a class not in the package)
|
|
11
|
+
* 3. optionally retains the UserLicense prop only if the param is true
|
|
12
|
+
*
|
|
13
|
+
* @param profileJson json representation of a profile
|
|
14
|
+
* @param packageXml package.xml as json
|
|
15
|
+
* @param retainUserLicense boolean will preserve userLicense if true
|
|
16
|
+
* @returns Profile
|
|
17
|
+
*/
|
|
18
|
+
const profileRewriter = (profileJson, packageXml, retainUserLicense = false) => ({
|
|
19
|
+
...Object.fromEntries(Object.entries(profileJson)
|
|
20
|
+
// remove settings that are not used for packaging
|
|
21
|
+
.filter(isRewriteProp)
|
|
22
|
+
// @ts-expect-error the previous filter restricts us to only things that appear in filterFunctions
|
|
23
|
+
.map(([key, value]) => [key, filterFunctions[key]?.(value, packageXml)] ?? [])
|
|
24
|
+
// some profileSettings might now be empty Arrays if the package.xml didn't have those types, so remove the entire property
|
|
25
|
+
.filter(([, value]) => (Array.isArray(value) ? value.length : true))),
|
|
26
|
+
// this one prop is controlled by a param. Put it back the way it was if the param is true
|
|
27
|
+
...(retainUserLicense && profileJson.userLicense ? { userLicense: profileJson.userLicense } : {}),
|
|
28
|
+
});
|
|
29
|
+
exports.profileRewriter = profileRewriter;
|
|
30
|
+
// it's both a filter and a typeguard to make sure props are represented in filterFunctions
|
|
31
|
+
const isRewriteProp = (prop) => rewriteProps.includes(prop[0]);
|
|
32
|
+
const rewriteProps = [
|
|
33
|
+
'objectPermissions',
|
|
34
|
+
'fieldPermissions',
|
|
35
|
+
'layoutAssignments',
|
|
36
|
+
'applicationVisibilities',
|
|
37
|
+
'classAccesses',
|
|
38
|
+
'externalDataSourceAccesses',
|
|
39
|
+
'tabVisibilities',
|
|
40
|
+
'pageAccesses',
|
|
41
|
+
'customPermissions',
|
|
42
|
+
'customMetadataTypeAccesses',
|
|
43
|
+
'customSettingAccesses',
|
|
44
|
+
'recordTypeVisibilities',
|
|
45
|
+
];
|
|
46
|
+
const filterFunctions = {
|
|
47
|
+
objectPermissions: (props, packageXml) => props.filter((item) => packageXml.get('CustomObject')?.includes(item.object)),
|
|
48
|
+
fieldPermissions: (props, packageXml) => props.filter((item) => packageXml.get('CustomField')?.includes((0, exports.fieldCorrections)(item.field))),
|
|
49
|
+
layoutAssignments: (props, packageXml) => props.filter((item) => packageXml.get('Layout')?.includes(item.layout)),
|
|
50
|
+
tabVisibilities: (props, packageXml) => props.filter((item) => packageXml.get('CustomTab')?.includes(item.tab)),
|
|
51
|
+
applicationVisibilities: (props, packageXml) => props.filter((item) => packageXml.get('Application')?.includes(item.application)),
|
|
52
|
+
classAccesses: (props, packageXml) => props.filter((item) => packageXml.get('ApexClass')?.includes(item.apexClass)),
|
|
53
|
+
customPermissions: (props, packageXml) => props.filter((item) => packageXml.get('CustomPermission')?.includes(item.name)),
|
|
54
|
+
pageAccesses: (props, packageXml) => props.filter((item) => packageXml.get('ApexPage')?.includes(item.apexPage)),
|
|
55
|
+
externalDataSourceAccesses: (props, packageXml) => props.filter((item) => packageXml.get('ExternalDataSource')?.includes(item.externalDataSource)),
|
|
56
|
+
recordTypeVisibilities: (props, packageXml) => props.filter((item) => packageXml.get('RecordType')?.includes(item.recordType)),
|
|
57
|
+
customSettingAccesses: (props, packageXml) => props.filter((item) => allMembers(packageXml).includes(item.name)),
|
|
58
|
+
customMetadataTypeAccesses: (props, packageXml) => props.filter((item) => allMembers(packageXml).includes(item.name)),
|
|
59
|
+
};
|
|
60
|
+
const allMembers = (packageXml) => Array.from(packageXml.values()).flat();
|
|
61
|
+
// github.com/forcedotcom/cli/issues/2278
|
|
62
|
+
// Activity Object is polymorphic (Task and Event)
|
|
63
|
+
// package.xml will display them as 'Activity'
|
|
64
|
+
// profile.fieldPermissions will display them with the more specific 'Task' or 'Event'
|
|
65
|
+
const fieldCorrections = (fieldName) => fieldName.replace(/^Event\./, 'Activity.').replace(/^Task\./, 'Activity.');
|
|
66
|
+
exports.fieldCorrections = fieldCorrections;
|
|
67
|
+
/**
|
|
68
|
+
* @param profileString: raw xml read from the file
|
|
69
|
+
* @returns CorrectedProfile (json representation of the profile)
|
|
70
|
+
*/
|
|
71
|
+
const profileStringToProfile = (profileString) => {
|
|
72
|
+
const parser = new fast_xml_parser_1.XMLParser({
|
|
73
|
+
ignoreAttributes: true,
|
|
74
|
+
parseTagValue: false,
|
|
75
|
+
parseAttributeValue: false,
|
|
76
|
+
cdataPropName: '__cdata',
|
|
77
|
+
ignoreDeclaration: true,
|
|
78
|
+
numberParseOptions: { leadingZeros: false, hex: false },
|
|
79
|
+
isArray: (name) => rewriteProps.includes(name),
|
|
80
|
+
});
|
|
81
|
+
return parser.parse(profileString).Profile;
|
|
82
|
+
};
|
|
83
|
+
exports.profileStringToProfile = profileStringToProfile;
|
|
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
|
+
* */
|
|
87
|
+
const profileObjectToString = (profileObject) => {
|
|
88
|
+
const builder = new fast_xml_parser_1.XMLBuilder({
|
|
89
|
+
format: true,
|
|
90
|
+
indentBy: ' ',
|
|
91
|
+
ignoreAttributes: false,
|
|
92
|
+
cdataPropName: '__cdata',
|
|
93
|
+
processEntities: false,
|
|
94
|
+
attributeNamePrefix: '@@@',
|
|
95
|
+
});
|
|
96
|
+
return String(builder.build({
|
|
97
|
+
'?xml': {
|
|
98
|
+
'@@@version': '1.0',
|
|
99
|
+
'@@@encoding': 'UTF-8',
|
|
100
|
+
},
|
|
101
|
+
Profile: { ...profileObject, '@@@xmlns': 'http://soap.sforce.com/2006/04/metadata' },
|
|
102
|
+
}));
|
|
103
|
+
};
|
|
104
|
+
exports.profileObjectToString = profileObjectToString;
|
|
105
|
+
/** it's easier to do lookups by Metadata Type on a Map */
|
|
106
|
+
const manifestTypesToMap = (original) => new Map(original.map((item) => [item.name, item.members]));
|
|
107
|
+
exports.manifestTypesToMap = manifestTypesToMap;
|
|
108
|
+
//# sourceMappingURL=profileRewriter.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/packaging",
|
|
3
|
-
"version": "2.2.
|
|
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",
|
|
@@ -42,22 +42,18 @@
|
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@oclif/core": "^2.9.4",
|
|
45
|
-
"@salesforce/core": "^4.3.
|
|
46
|
-
"@salesforce/kit": "^3.0.
|
|
45
|
+
"@salesforce/core": "^4.3.10",
|
|
46
|
+
"@salesforce/kit": "^3.0.5",
|
|
47
47
|
"@salesforce/schemas": "^1.6.0",
|
|
48
|
-
"@salesforce/source-deploy-retrieve": "^
|
|
48
|
+
"@salesforce/source-deploy-retrieve": "^9.3.4",
|
|
49
49
|
"@salesforce/ts-types": "^2.0.3",
|
|
50
|
-
"
|
|
51
|
-
"debug": "^4.3.4",
|
|
50
|
+
"fast-xml-parser": "^4.2.5",
|
|
52
51
|
"globby": "^11",
|
|
53
52
|
"graphology": "^0.25.1",
|
|
54
53
|
"graphology-traversal": "^0.3.1",
|
|
55
54
|
"graphology-types": "^0.24.7",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"jszip": "^3.10.1",
|
|
59
|
-
"ts-retry-promise": "^0.7.0",
|
|
60
|
-
"xml2js": "^0.6.0"
|
|
55
|
+
"jsforce": "^2.0.0-beta.27",
|
|
56
|
+
"jszip": "^3.10.1"
|
|
61
57
|
},
|
|
62
58
|
"devDependencies": {
|
|
63
59
|
"@salesforce/cli-plugins-testkit": "^4.1.1",
|
|
@@ -65,14 +61,11 @@
|
|
|
65
61
|
"@salesforce/dev-scripts": "^5.4.3",
|
|
66
62
|
"@salesforce/prettier-config": "^0.0.3",
|
|
67
63
|
"@salesforce/ts-sinon": "^1.4.11",
|
|
68
|
-
"@types/debug": "4.1.8",
|
|
69
64
|
"@types/globby": "^9.1.0",
|
|
70
65
|
"@types/jszip": "^3.4.1",
|
|
71
|
-
"@types/xml2js": "^0.4.11",
|
|
72
66
|
"@typescript-eslint/eslint-plugin": "^5.60.0",
|
|
73
67
|
"@typescript-eslint/parser": "^5.61.0",
|
|
74
68
|
"chai": "^4.3.7",
|
|
75
|
-
"commitizen": "^4.2.6",
|
|
76
69
|
"eslint": "^8.44.0",
|
|
77
70
|
"eslint-config-prettier": "^8.8.0",
|
|
78
71
|
"eslint-config-salesforce": "^2.0.1",
|