@salesforce/core 3.31.4 → 3.31.7

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.
Files changed (153) hide show
  1. package/LICENSE.txt +11 -11
  2. package/README.md +222 -222
  3. package/lib/config/aliasesConfig.d.ts +12 -12
  4. package/lib/config/aliasesConfig.js +27 -27
  5. package/lib/config/authInfoConfig.d.ts +19 -19
  6. package/lib/config/authInfoConfig.js +34 -34
  7. package/lib/config/config.d.ts +311 -311
  8. package/lib/config/config.js +574 -574
  9. package/lib/config/configAggregator.d.ts +232 -232
  10. package/lib/config/configAggregator.js +379 -379
  11. package/lib/config/configFile.d.ts +199 -199
  12. package/lib/config/configFile.js +340 -340
  13. package/lib/config/configGroup.d.ts +141 -141
  14. package/lib/config/configGroup.js +224 -224
  15. package/lib/config/configStore.d.ts +241 -241
  16. package/lib/config/configStore.js +352 -352
  17. package/lib/config/envVars.d.ts +101 -101
  18. package/lib/config/envVars.js +456 -456
  19. package/lib/config/orgUsersConfig.d.ts +31 -31
  20. package/lib/config/orgUsersConfig.js +41 -41
  21. package/lib/config/sandboxOrgConfig.d.ts +37 -37
  22. package/lib/config/sandboxOrgConfig.js +50 -50
  23. package/lib/config/sandboxProcessCache.d.ts +16 -16
  24. package/lib/config/sandboxProcessCache.js +37 -37
  25. package/lib/config/tokensConfig.d.ts +10 -10
  26. package/lib/config/tokensConfig.js +28 -28
  27. package/lib/config/ttlConfig.d.ts +34 -34
  28. package/lib/config/ttlConfig.js +54 -54
  29. package/lib/crypto/crypto.d.ts +54 -54
  30. package/lib/crypto/crypto.js +220 -220
  31. package/lib/crypto/keyChain.d.ts +8 -8
  32. package/lib/crypto/keyChain.js +61 -61
  33. package/lib/crypto/keyChainImpl.d.ts +116 -116
  34. package/lib/crypto/keyChainImpl.js +486 -486
  35. package/lib/crypto/secureBuffer.d.ts +46 -46
  36. package/lib/crypto/secureBuffer.js +82 -82
  37. package/lib/deviceOauthService.d.ts +71 -71
  38. package/lib/deviceOauthService.js +191 -191
  39. package/lib/exported.d.ts +38 -38
  40. package/lib/exported.js +118 -118
  41. package/lib/global.d.ts +70 -70
  42. package/lib/global.js +109 -109
  43. package/lib/lifecycleEvents.d.ts +93 -93
  44. package/lib/lifecycleEvents.js +188 -188
  45. package/lib/logger.d.ts +381 -381
  46. package/lib/logger.js +734 -734
  47. package/lib/messages.d.ts +291 -291
  48. package/lib/messages.js +543 -543
  49. package/lib/org/authInfo.d.ts +344 -344
  50. package/lib/org/authInfo.js +892 -892
  51. package/lib/org/authRemover.d.ts +88 -88
  52. package/lib/org/authRemover.js +182 -182
  53. package/lib/org/connection.d.ts +197 -197
  54. package/lib/org/connection.js +395 -395
  55. package/lib/org/index.d.ts +6 -6
  56. package/lib/org/index.js +28 -28
  57. package/lib/org/org.d.ts +558 -558
  58. package/lib/org/org.js +1267 -1267
  59. package/lib/org/orgConfigProperties.d.ts +69 -69
  60. package/lib/org/orgConfigProperties.js +136 -136
  61. package/lib/org/permissionSetAssignment.d.ts +35 -35
  62. package/lib/org/permissionSetAssignment.js +125 -125
  63. package/lib/org/scratchOrgCache.d.ts +20 -20
  64. package/lib/org/scratchOrgCache.js +32 -32
  65. package/lib/org/scratchOrgCreate.d.ts +54 -54
  66. package/lib/org/scratchOrgCreate.js +216 -216
  67. package/lib/org/scratchOrgErrorCodes.d.ts +10 -10
  68. package/lib/org/scratchOrgErrorCodes.js +88 -88
  69. package/lib/org/scratchOrgFeatureDeprecation.d.ts +26 -26
  70. package/lib/org/scratchOrgFeatureDeprecation.js +109 -109
  71. package/lib/org/scratchOrgInfoApi.d.ts +68 -68
  72. package/lib/org/scratchOrgInfoApi.js +413 -413
  73. package/lib/org/scratchOrgInfoGenerator.d.ts +64 -64
  74. package/lib/org/scratchOrgInfoGenerator.js +241 -241
  75. package/lib/org/scratchOrgLifecycleEvents.d.ts +10 -10
  76. package/lib/org/scratchOrgLifecycleEvents.js +40 -40
  77. package/lib/org/scratchOrgSettingsGenerator.d.ts +78 -78
  78. package/lib/org/scratchOrgSettingsGenerator.js +276 -276
  79. package/lib/org/scratchOrgTypes.d.ts +43 -43
  80. package/lib/org/scratchOrgTypes.js +8 -8
  81. package/lib/org/user.d.ts +187 -187
  82. package/lib/org/user.js +448 -448
  83. package/lib/schema/printer.d.ts +79 -79
  84. package/lib/schema/printer.js +260 -260
  85. package/lib/schema/validator.d.ts +70 -70
  86. package/lib/schema/validator.js +169 -169
  87. package/lib/sfError.d.ts +73 -73
  88. package/lib/sfError.js +136 -136
  89. package/lib/sfProject.d.ts +357 -357
  90. package/lib/sfProject.js +671 -671
  91. package/lib/stateAggregator/accessors/aliasAccessor.d.ts +98 -98
  92. package/lib/stateAggregator/accessors/aliasAccessor.js +145 -145
  93. package/lib/stateAggregator/accessors/orgAccessor.d.ts +101 -101
  94. package/lib/stateAggregator/accessors/orgAccessor.js +240 -240
  95. package/lib/stateAggregator/accessors/sandboxAccessor.d.ts +8 -8
  96. package/lib/stateAggregator/accessors/sandboxAccessor.js +27 -27
  97. package/lib/stateAggregator/accessors/tokenAccessor.d.ts +63 -63
  98. package/lib/stateAggregator/accessors/tokenAccessor.js +79 -79
  99. package/lib/stateAggregator/index.d.ts +4 -4
  100. package/lib/stateAggregator/index.js +26 -26
  101. package/lib/stateAggregator/stateAggregator.d.ts +25 -25
  102. package/lib/stateAggregator/stateAggregator.js +45 -45
  103. package/lib/status/myDomainResolver.d.ts +66 -66
  104. package/lib/status/myDomainResolver.js +124 -124
  105. package/lib/status/pollingClient.d.ts +85 -85
  106. package/lib/status/pollingClient.js +115 -115
  107. package/lib/status/streamingClient.d.ts +244 -244
  108. package/lib/status/streamingClient.js +436 -436
  109. package/lib/status/types.d.ts +89 -89
  110. package/lib/status/types.js +17 -17
  111. package/lib/testSetup.d.ts +553 -553
  112. package/lib/testSetup.js +871 -871
  113. package/lib/util/cache.d.ts +11 -11
  114. package/lib/util/cache.js +69 -69
  115. package/lib/util/checkLightningDomain.d.ts +1 -1
  116. package/lib/util/checkLightningDomain.js +28 -28
  117. package/lib/util/directoryWriter.d.ts +12 -12
  118. package/lib/util/directoryWriter.js +53 -53
  119. package/lib/util/getJwtAudienceUrl.d.ts +4 -4
  120. package/lib/util/getJwtAudienceUrl.js +18 -18
  121. package/lib/util/internal.d.ts +58 -58
  122. package/lib/util/internal.js +118 -118
  123. package/lib/util/jsonXmlTools.d.ts +14 -14
  124. package/lib/util/jsonXmlTools.js +38 -38
  125. package/lib/util/mapKeys.d.ts +14 -14
  126. package/lib/util/mapKeys.js +51 -51
  127. package/lib/util/sfdc.d.ts +52 -52
  128. package/lib/util/sfdc.js +85 -85
  129. package/lib/util/sfdcUrl.d.ts +72 -72
  130. package/lib/util/sfdcUrl.js +215 -215
  131. package/lib/util/structuredWriter.d.ts +9 -9
  132. package/lib/util/structuredWriter.js +2 -2
  133. package/lib/util/zipWriter.d.ts +16 -16
  134. package/lib/util/zipWriter.js +67 -67
  135. package/lib/webOAuthServer.d.ts +156 -156
  136. package/lib/webOAuthServer.js +388 -388
  137. package/messages/auth.md +37 -37
  138. package/messages/config.md +156 -156
  139. package/messages/connection.md +30 -30
  140. package/messages/core.json +20 -20
  141. package/messages/core.md +67 -67
  142. package/messages/encryption.md +85 -85
  143. package/messages/envVars.md +303 -303
  144. package/messages/org.md +63 -63
  145. package/messages/permissionSetAssignment.md +31 -31
  146. package/messages/scratchOrgCreate.md +23 -23
  147. package/messages/scratchOrgErrorCodes.md +115 -115
  148. package/messages/scratchOrgFeatureDeprecation.md +11 -11
  149. package/messages/scratchOrgInfoApi.md +15 -15
  150. package/messages/scratchOrgInfoGenerator.md +23 -23
  151. package/messages/streaming.md +23 -23
  152. package/messages/user.md +35 -35
  153. package/package.json +97 -97
package/lib/sfProject.js CHANGED
@@ -1,672 +1,672 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SfdxProjectJson = exports.SfdxProject = exports.SfProject = exports.SfProjectJson = void 0;
4
- /*
5
- * Copyright (c) 2020, salesforce.com, inc.
6
- * All rights reserved.
7
- * Licensed under the BSD 3-Clause license.
8
- * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
9
- */
10
- const path_1 = require("path");
11
- const fs = require("fs");
12
- const kit_1 = require("@salesforce/kit");
13
- const ts_types_1 = require("@salesforce/ts-types");
14
- const sfdcUrl_1 = require("./util/sfdcUrl");
15
- const configAggregator_1 = require("./config/configAggregator");
16
- const configFile_1 = require("./config/configFile");
17
- const validator_1 = require("./schema/validator");
18
- const internal_1 = require("./util/internal");
19
- const sfError_1 = require("./sfError");
20
- const sfdc_1 = require("./util/sfdc");
21
- const messages_1 = require("./messages");
22
- messages_1.Messages.importMessagesDirectory(__dirname);
23
- const messages = messages_1.Messages.load('@salesforce/core', 'config', [
24
- 'schemaValidationError',
25
- 'singleNonDefaultPackage',
26
- 'missingDefaultPath',
27
- 'multipleDefaultPaths',
28
- 'invalidPackageDirectory',
29
- 'missingPackageDirectory',
30
- 'invalidId',
31
- ]);
32
- const coreMessages = messages_1.Messages.load('@salesforce/core', 'core', ['invalidJsonCasing']);
33
- /**
34
- * The sfdx-project.json config object. This file determines if a folder is a valid sfdx project.
35
- *
36
- * *Note:* Any non-standard (not owned by Salesforce) properties stored in sfdx-project.json should
37
- * be in a top level property that represents your project or plugin.
38
- *
39
- * ```
40
- * const project = await SfProject.resolve();
41
- * const projectJson = await project.resolveProjectConfig();
42
- * const myPluginProperties = projectJson.get('myplugin') || {};
43
- * myPluginProperties.myprop = 'someValue';
44
- * projectJson.set('myplugin', myPluginProperties);
45
- * await projectJson.write();
46
- * ```
47
- *
48
- * **See** [force:project:create](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_create_new.htm)
49
- */
50
- class SfProjectJson extends configFile_1.ConfigFile {
51
- static getFileName() {
52
- return internal_1.SFDX_PROJECT_JSON;
53
- }
54
- static getDefaultOptions(isGlobal = false) {
55
- const options = configFile_1.ConfigFile.getDefaultOptions(isGlobal, SfProjectJson.getFileName());
56
- options.isState = false;
57
- return options;
58
- }
59
- async read() {
60
- const contents = await super.read();
61
- this.validateKeys();
62
- await this.schemaValidate();
63
- return contents;
64
- }
65
- readSync() {
66
- const contents = super.readSync();
67
- this.validateKeys();
68
- this.schemaValidateSync();
69
- return contents;
70
- }
71
- async write(newContents) {
72
- if (newContents) {
73
- this.setContents(newContents);
74
- }
75
- this.validateKeys();
76
- await this.schemaValidate();
77
- return super.write();
78
- }
79
- writeSync(newContents) {
80
- if (newContents) {
81
- this.setContents(newContents);
82
- }
83
- this.validateKeys();
84
- this.schemaValidateSync();
85
- return super.writeSync();
86
- }
87
- getContents() {
88
- return super.getContents();
89
- }
90
- // eslint-disable-next-line class-methods-use-this
91
- getDefaultOptions(options) {
92
- const defaultOptions = {
93
- isState: false,
94
- };
95
- Object.assign(defaultOptions, options ?? {});
96
- return defaultOptions;
97
- }
98
- /**
99
- * Validates sfdx-project.json against the schema.
100
- *
101
- * Set the `SFDX_PROJECT_JSON_VALIDATION` environment variable to `true` to throw an error when schema validation fails.
102
- * A warning is logged by default when the file is invalid.
103
- *
104
- * ***See*** [sfdx-project.schema.json] ((https://github.com/forcedotcom/schemas/blob/main/sfdx-project.schema.json)
105
- */
106
- async schemaValidate() {
107
- if (!this.hasRead) {
108
- // read calls back into this method after necessarily setting this.hasRead=true
109
- await this.read();
110
- }
111
- else {
112
- try {
113
- const projectJsonSchemaPath = require.resolve('@salesforce/schemas/sfdx-project.schema.json');
114
- const validator = new validator_1.SchemaValidator(this.logger, projectJsonSchemaPath);
115
- await validator.validate(this.getContents());
116
- }
117
- catch (err) {
118
- const error = err;
119
- // Don't throw errors if the global isn't valid, but still warn the user.
120
- if (kit_1.env.getBoolean('SFDX_PROJECT_JSON_VALIDATION', false) && !this.options.isGlobal) {
121
- throw messages.createError('schemaValidationError', [this.getPath(), error.message], [this.getPath()], error);
122
- }
123
- else {
124
- this.logger.warn(messages.getMessage('schemaValidationError', [this.getPath(), error.message]));
125
- }
126
- }
127
- }
128
- }
129
- /**
130
- * Returns the `packageDirectories` within sfdx-project.json, first reading
131
- * and validating the file if necessary.
132
- */
133
- // eslint-disable-next-line @typescript-eslint/require-await
134
- async getPackageDirectories() {
135
- return this.getPackageDirectoriesSync();
136
- }
137
- /**
138
- * Validates sfdx-project.json against the schema.
139
- *
140
- * Set the `SFDX_PROJECT_JSON_VALIDATION` environment variable to `true` to throw an error when schema validation fails.
141
- * A warning is logged by default when the file is invalid.
142
- *
143
- * ***See*** [sfdx-project.schema.json] ((https://github.com/forcedotcom/schemas/blob/main/sfdx-project.schema.json)
144
- */
145
- schemaValidateSync() {
146
- if (!this.hasRead) {
147
- // read calls back into this method after necessarily setting this.hasRead=true
148
- this.readSync();
149
- }
150
- else {
151
- try {
152
- const projectJsonSchemaPath = require.resolve('@salesforce/schemas/sfdx-project.schema.json');
153
- const validator = new validator_1.SchemaValidator(this.logger, projectJsonSchemaPath);
154
- validator.validateSync(this.getContents());
155
- }
156
- catch (err) {
157
- const error = err;
158
- // Don't throw errors if the global isn't valid, but still warn the user.
159
- if (kit_1.env.getBoolean('SFDX_PROJECT_JSON_VALIDATION', false) && !this.options.isGlobal) {
160
- throw messages.createError('schemaValidationError', [this.getPath(), error.message], [this.getPath()], error);
161
- }
162
- else {
163
- this.logger.warn(messages.getMessage('schemaValidationError', [this.getPath(), error.message]));
164
- }
165
- }
166
- }
167
- }
168
- /**
169
- * Returns a read-only list of `packageDirectories` within sfdx-project.json, first reading
170
- * and validating the file if necessary. i.e. modifying this array will not affect the
171
- * sfdx-project.json file.
172
- */
173
- getPackageDirectoriesSync() {
174
- const contents = this.getContents();
175
- // This has to be done on the fly so it won't be written back to the file
176
- // This is a fast operation so no need to cache it so it stays immutable.
177
- const packageDirs = (contents.packageDirectories || []).map((packageDir) => {
178
- if ((0, path_1.isAbsolute)(packageDir.path)) {
179
- throw messages.createError('invalidPackageDirectory', [packageDir.path]);
180
- }
181
- const regex = path_1.sep === '/' ? /\\/g : /\//g;
182
- // Change packageDir paths to have path separators that match the OS
183
- const path = packageDir.path.replace(regex, path_1.sep);
184
- // Normalize and remove any ending path separators
185
- const name = (0, path_1.normalize)(path).replace(new RegExp(`\\${path_1.sep}$`), '');
186
- // Always end in a path sep for standardization on folder paths
187
- const fullPath = `${(0, path_1.dirname)(this.getPath())}${path_1.sep}${name}${path_1.sep}`;
188
- if (!this.doesPackageExist(fullPath)) {
189
- throw messages.createError('missingPackageDirectory', [packageDir.path]);
190
- }
191
- return Object.assign({}, packageDir, { name, path, fullPath });
192
- });
193
- // If we only have one package entry, it must be the default even if not explicitly labelled
194
- if (packageDirs.length === 1) {
195
- if (packageDirs[0].default === false) {
196
- // we have one package but it is explicitly labelled as default=false
197
- throw messages.createError('singleNonDefaultPackage');
198
- }
199
- // add default=true to the package
200
- packageDirs[0].default = true;
201
- }
202
- const defaultDirs = packageDirs.filter((packageDir) => packageDir.default);
203
- // Don't throw about a missing default path if we are in the global file.
204
- // Package directories are not really meant to be set at the global level.
205
- if (defaultDirs.length === 0 && !this.isGlobal()) {
206
- throw messages.createError('missingDefaultPath');
207
- }
208
- else if (defaultDirs.length > 1) {
209
- throw messages.createError('multipleDefaultPaths');
210
- }
211
- return packageDirs;
212
- }
213
- /**
214
- * Returns a read-only list of `packageDirectories` within sfdx-project.json, first reading
215
- * and validating the file if necessary. i.e. modifying this array will not affect the
216
- * sfdx-project.json file.
217
- *
218
- * There can be multiple packages in packageDirectories that point to the same directory.
219
- * This method only returns one packageDirectory entry per unique directory path. This is
220
- * useful when doing source operations based on directories but probably not as useful
221
- * for packaging operations that want to do something for each package entry.
222
- */
223
- getUniquePackageDirectories() {
224
- const visited = new Set();
225
- const uniqueValues = [];
226
- // Keep original order defined in sfdx-project.json
227
- this.getPackageDirectoriesSync().forEach((packageDir) => {
228
- if (!visited.has(packageDir.name)) {
229
- visited.add(packageDir.name);
230
- uniqueValues.push(packageDir);
231
- }
232
- });
233
- return uniqueValues;
234
- }
235
- /**
236
- * Get a list of the unique package names from within sfdx-project.json. Use {@link SfProject.getUniquePackageDirectories}
237
- * for data other than the names.
238
- */
239
- getUniquePackageNames() {
240
- return this.getUniquePackageDirectories().map((pkgDir) => pkgDir.name);
241
- }
242
- /**
243
- * Has package directories defined in the project.
244
- */
245
- hasPackages() {
246
- return this.getContents()?.packageDirectories?.length > 0;
247
- }
248
- /**
249
- * Has multiple package directories (MPD) defined in the project.
250
- */
251
- hasMultiplePackages() {
252
- return this.getContents()?.packageDirectories?.length > 1;
253
- }
254
- /**
255
- * Has at least one package alias defined in the project.
256
- */
257
- // eslint-disable-next-line @typescript-eslint/explicit-function-return-type, @typescript-eslint/require-await
258
- async hasPackageAliases() {
259
- return Object.keys(this.getContents().packageAliases ?? {}).length > 0;
260
- }
261
- /**
262
- * Get package aliases defined in the project.
263
- */
264
- getPackageAliases() {
265
- return this.getContents().packageAliases;
266
- }
267
- /**
268
- * Add a package alias to the project.
269
- * If the alias already exists, it will be overwritten.
270
- *
271
- * @param alias
272
- * @param id
273
- */
274
- addPackageAlias(alias, id) {
275
- // TODO: validate id (e.g. 04t, 0Ho)
276
- if (!/^.{15,18}$/.test(id)) {
277
- throw messages.createError('invalidId', [id]);
278
- }
279
- const contents = this.getContents();
280
- if (!contents.packageAliases) {
281
- contents.packageAliases = {};
282
- }
283
- contents.packageAliases[alias] = id;
284
- this.setContents(contents);
285
- }
286
- /**
287
- * Add a package directory to the project.
288
- * If the package directory already exists, the new directory
289
- * properties will be merged with the existing properties.
290
- *
291
- * @param packageDir
292
- */
293
- addPackageDirectory(packageDir) {
294
- // there is no notion of uniqueness in package directory entries
295
- // so an attempt of matching an existing entry is a bit convoluted
296
- // an entry w/o a package or id is considered a directory entry for which a package has yet to be created
297
- // so first attempt is to find a matching dir entry that where path is the same and id and package are not present
298
- // if that fails, then find a matching dir entry package is present and is same as the new entry
299
- const dirIndex = this.getContents().packageDirectories.findIndex((pd) => {
300
- const withId = pd;
301
- return ((withId.path === packageDir.path && !withId.id && !withId.package) ||
302
- (!!packageDir.package && packageDir.package === withId.package));
303
- });
304
- // merge new package dir with existing entry, if present
305
- const packageDirEntry = Object.assign({}, dirIndex > -1 ? this.getContents().packageDirectories[dirIndex] : packageDir, packageDir);
306
- // update package dir entries
307
- if (dirIndex > -1) {
308
- this.getContents().packageDirectories[dirIndex] = packageDirEntry;
309
- }
310
- else {
311
- this.getContents().packageDirectories.push(packageDirEntry);
312
- }
313
- }
314
- // eslint-disable-next-line class-methods-use-this
315
- doesPackageExist(packagePath) {
316
- return fs.existsSync(packagePath);
317
- }
318
- validateKeys() {
319
- // Verify that the configObject does not have upper case keys; throw if it does. Must be heads down camel case.
320
- const upperCaseKey = sfdc_1.sfdc.findUpperCaseKeys(this.toObject(), SfProjectJson.BLOCKLIST);
321
- if (upperCaseKey) {
322
- throw coreMessages.createError('invalidJsonCasing', [upperCaseKey, this.getPath()]);
323
- }
324
- }
325
- }
326
- exports.SfProjectJson = SfProjectJson;
327
- SfProjectJson.BLOCKLIST = ['packageAliases'];
328
- /**
329
- * Represents an SFDX project directory. This directory contains a {@link SfProjectJson} config file as well as
330
- * a hidden .sfdx folder that contains all the other local project config files.
331
- *
332
- * ```
333
- * const project = await SfProject.resolve();
334
- * const projectJson = await project.resolveProjectConfig();
335
- * console.log(projectJson.sfdcLoginUrl);
336
- * ```
337
- */
338
- class SfProject {
339
- /**
340
- * Do not directly construct instances of this class -- use {@link SfProject.resolve} instead.
341
- *
342
- * @ignore
343
- */
344
- constructor(path) {
345
- this.path = path;
346
- }
347
- /**
348
- * Get a Project from a given path or from the working directory.
349
- *
350
- * @param path The path of the project.
351
- *
352
- * **Throws** *{@link SfError}{ name: 'InvalidProjectWorkspaceError' }* If the current folder is not located in a workspace.
353
- */
354
- static async resolve(path) {
355
- path = await this.resolveProjectPath(path ?? process.cwd());
356
- if (!SfProject.instances.has(path)) {
357
- const project = new SfProject(path);
358
- SfProject.instances.set(path, project);
359
- }
360
- return (0, ts_types_1.ensure)(SfProject.instances.get(path));
361
- }
362
- /**
363
- * Get a Project from a given path or from the working directory.
364
- *
365
- * @param path The path of the project.
366
- *
367
- * **Throws** *{@link SfError}{ name: 'InvalidProjectWorkspaceError' }* If the current folder is not located in a workspace.
368
- */
369
- static getInstance(path) {
370
- // Store instance based on the path of the actual project.
371
- path = this.resolveProjectPathSync(path ?? process.cwd());
372
- if (!SfProject.instances.has(path)) {
373
- const project = new SfProject(path);
374
- SfProject.instances.set(path, project);
375
- }
376
- return (0, ts_types_1.ensure)(SfProject.instances.get(path));
377
- }
378
- /**
379
- * Performs an upward directory search for an sfdx project file. Returns the absolute path to the project.
380
- *
381
- * @param dir The directory path to start traversing from.
382
- *
383
- * **Throws** *{@link SfError}{ name: 'InvalidProjectWorkspaceError' }* If the current folder is not located in a workspace.
384
- *
385
- * **See** {@link traverseForFile}
386
- *
387
- * **See** [process.cwd()](https://nodejs.org/api/process.html#process_process_cwd)
388
- */
389
- static async resolveProjectPath(dir) {
390
- return (0, internal_1.resolveProjectPath)(dir);
391
- }
392
- /**
393
- * Performs a synchronous upward directory search for an sfdx project file. Returns the absolute path to the project.
394
- *
395
- * @param dir The directory path to start traversing from.
396
- *
397
- * **Throws** *{@link SfError}{ name: 'InvalidProjectWorkspaceError' }* If the current folder is not located in a workspace.
398
- *
399
- * **See** {@link traverseForFileSync}
400
- *
401
- * **See** [process.cwd()](https://nodejs.org/api/process.html#process_process_cwd)
402
- */
403
- static resolveProjectPathSync(dir) {
404
- return (0, internal_1.resolveProjectPathSync)(dir);
405
- }
406
- /**
407
- * Returns the project path.
408
- */
409
- getPath() {
410
- return this.path;
411
- }
412
- /**
413
- * Get the sfdx-project.json config. The global sfdx-project.json is used for user defaults
414
- * that are not checked in to the project specific file.
415
- *
416
- * *Note:* When reading values from {@link SfProjectJson}, it is recommended to use
417
- * {@link SfProject.resolveProjectConfig} instead.
418
- *
419
- * @param isGlobal True to get the global project file, otherwise the local project config.
420
- */
421
- async retrieveSfProjectJson(isGlobal = false) {
422
- const options = SfProjectJson.getDefaultOptions(isGlobal);
423
- if (isGlobal) {
424
- if (!this.sfProjectJsonGlobal) {
425
- this.sfProjectJsonGlobal = await SfProjectJson.create(options);
426
- }
427
- return this.sfProjectJsonGlobal;
428
- }
429
- else {
430
- options.rootFolder = this.getPath();
431
- if (!this.sfProjectJson) {
432
- this.sfProjectJson = await SfProjectJson.create(options);
433
- }
434
- return this.sfProjectJson;
435
- }
436
- }
437
- /**
438
- * Get the sfdx-project.json config. The global sfdx-project.json is used for user defaults
439
- * that are not checked in to the project specific file.
440
- *
441
- * *Note:* When reading values from {@link SfProjectJson}, it is recommended to use
442
- * {@link SfProject.resolveProjectConfig} instead.
443
- *
444
- * This is the sync method of {@link SfProject.resolveSfProjectJson}
445
- *
446
- * @param isGlobal True to get the global project file, otherwise the local project config.
447
- */
448
- getSfProjectJson(isGlobal = false) {
449
- const options = SfProjectJson.getDefaultOptions(isGlobal);
450
- if (isGlobal) {
451
- if (!this.sfProjectJsonGlobal) {
452
- this.sfProjectJsonGlobal = new SfProjectJson(options);
453
- this.sfProjectJsonGlobal.readSync();
454
- }
455
- return this.sfProjectJsonGlobal;
456
- }
457
- else {
458
- options.rootFolder = this.getPath();
459
- if (!this.sfProjectJson) {
460
- this.sfProjectJson = new SfProjectJson(options);
461
- this.sfProjectJson.readSync();
462
- }
463
- return this.sfProjectJson;
464
- }
465
- }
466
- /**
467
- * Returns a read-only list of `packageDirectories` within sfdx-project.json, first reading
468
- * and validating the file if necessary. i.e. modifying this array will not affect the
469
- * sfdx-project.json file.
470
- */
471
- getPackageDirectories() {
472
- if (!this.packageDirectories) {
473
- this.packageDirectories = this.getSfProjectJson().getPackageDirectoriesSync();
474
- }
475
- return this.packageDirectories;
476
- }
477
- /**
478
- * Returns a read-only list of `packageDirectories` within sfdx-project.json, first reading
479
- * and validating the file if necessary. i.e. modifying this array will not affect the
480
- * sfdx-project.json file.
481
- *
482
- * There can be multiple packages in packageDirectories that point to the same directory.
483
- * This method only returns one packageDirectory entry per unique directory path. This is
484
- * useful when doing source operations based on directories but probably not as useful
485
- * for packaging operations that want to do something for each package entry.
486
- */
487
- getUniquePackageDirectories() {
488
- return this.getSfProjectJson().getUniquePackageDirectories();
489
- }
490
- /**
491
- * Get a list of the unique package names from within sfdx-project.json. Use {@link SfProject.getUniquePackageDirectories}
492
- * for data other than the names.
493
- */
494
- getUniquePackageNames() {
495
- return this.getSfProjectJson().getUniquePackageNames();
496
- }
497
- /**
498
- * Returns the package from a file path.
499
- *
500
- * @param path A file path. E.g. /Users/jsmith/projects/ebikes-lwc/force-app/apex/my-cls.cls
501
- */
502
- getPackageFromPath(path) {
503
- const packageDirs = this.getPackageDirectories();
504
- const match = packageDirs.find((packageDir) => (0, path_1.basename)(path) === packageDir.path || path.includes(packageDir.fullPath));
505
- return match;
506
- }
507
- /**
508
- * Returns the package name, E.g. 'force-app', from a file path.
509
- *
510
- * @param path A file path. E.g. /Users/jsmith/projects/ebikes-lwc/force-app/apex/my-cls.cls
511
- */
512
- getPackageNameFromPath(path) {
513
- const packageDir = this.getPackageFromPath(path);
514
- return packageDir ? packageDir.package ?? packageDir.path : undefined;
515
- }
516
- /**
517
- * Returns the package directory.
518
- *
519
- * @param packageName Name of the package directory. E.g., 'force-app'
520
- */
521
- getPackage(packageName) {
522
- const packageDirs = this.getPackageDirectories();
523
- return packageDirs.find((packageDir) => packageDir.name === packageName);
524
- }
525
- /**
526
- * Returns the package directory.
527
- *
528
- * @param packageName Name of the package directory. E.g., 'force-app'
529
- */
530
- findPackage(predicate) {
531
- return this.getPackageDirectories().find(predicate);
532
- }
533
- /**
534
- * Returns the absolute path of the package directory ending with the path separator.
535
- * E.g., /Users/jsmith/projects/ebikes-lwc/force-app/
536
- *
537
- * @param packageName Name of the package directory. E.g., 'force-app'
538
- */
539
- getPackagePath(packageName) {
540
- const packageDir = this.getPackage(packageName);
541
- return packageDir?.fullPath;
542
- }
543
- /**
544
- * Has package directories defined in the project.
545
- */
546
- hasPackages() {
547
- return this.getSfProjectJson().hasPackages();
548
- }
549
- /**
550
- * Has multiple package directories (MPD) defined in the project.
551
- */
552
- hasMultiplePackages() {
553
- return this.getSfProjectJson().hasMultiplePackages();
554
- }
555
- /**
556
- * Get the currently activated package on the project. This has no implication on sfdx-project.json
557
- * but is useful for keeping track of package and source specific options in a process.
558
- */
559
- getActivePackage() {
560
- return this.activePackage;
561
- }
562
- /**
563
- * Set the currently activated package on the project. This has no implication on sfdx-project.json
564
- * but is useful for keeping track of package and source specific options in a process.
565
- *
566
- * @param packageName The package name to activate. E.g. 'force-app'
567
- */
568
- setActivePackage(packageName) {
569
- if (packageName == null) {
570
- this.activePackage = null;
571
- }
572
- else {
573
- this.activePackage = this.getPackage(packageName);
574
- }
575
- }
576
- /**
577
- * Get the project's default package directory defined in sfdx-project.json using first 'default: true'
578
- * found. The first entry is returned if no default is specified.
579
- */
580
- getDefaultPackage() {
581
- if (!this.hasPackages()) {
582
- throw new sfError_1.SfError('The sfdx-project.json does not have any packageDirectories defined.');
583
- }
584
- const defaultPackage = this.findPackage((packageDir) => packageDir.default === true);
585
- return defaultPackage ?? this.getPackageDirectories()[0];
586
- }
587
- /**
588
- * The project config is resolved from local and global {@link SfProjectJson},
589
- * {@link ConfigAggregator}, and a set of defaults. It is recommended to use
590
- * this when reading values from SfProjectJson.
591
- *
592
- * The global {@link SfProjectJson} is used to allow the user to provide default values they
593
- * may not want checked into their project's source.
594
- *
595
- * @returns A resolved config object that contains a bunch of different
596
- * properties, including some 3rd party custom properties.
597
- */
598
- async resolveProjectConfig() {
599
- if (!this.projectConfig) {
600
- // Do fs operations in parallel
601
- const [global, local, configAggregator] = await Promise.all([
602
- this.retrieveSfProjectJson(true),
603
- this.retrieveSfProjectJson(),
604
- configAggregator_1.ConfigAggregator.create(),
605
- ]);
606
- await Promise.all([global.read(), local.read()]);
607
- this.projectConfig = (0, kit_1.defaults)(local.toObject(), global.toObject());
608
- // Add fields in sfdx-config.json
609
- Object.assign(this.projectConfig, configAggregator.getConfig());
610
- // we don't have a login url yet, so use instanceUrl from config or default
611
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
612
- if (!this.projectConfig.sfdcLoginUrl) {
613
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
614
- this.projectConfig.sfdcLoginUrl = configAggregator.getConfig()['org-instance-url'] ?? sfdcUrl_1.SfdcUrl.PRODUCTION;
615
- }
616
- // LEGACY - Allow override of sfdcLoginUrl via env var FORCE_SFDC_LOGIN_URL
617
- if (process.env.FORCE_SFDC_LOGIN_URL) {
618
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
619
- this.projectConfig.sfdcLoginUrl = process.env.FORCE_SFDC_LOGIN_URL;
620
- }
621
- // Allow override of signupTargetLoginUrl via env var SFDX_SCRATCH_ORG_CREATION_LOGIN_URL
622
- if (process.env.SFDX_SCRATCH_ORG_CREATION_LOGIN_URL) {
623
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
624
- this.projectConfig.signupTargetLoginUrl = process.env.SFDX_SCRATCH_ORG_CREATION_LOGIN_URL;
625
- }
626
- }
627
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
628
- return this.projectConfig;
629
- }
630
- async hasPackageAliases() {
631
- return this.getSfProjectJson().hasPackageAliases();
632
- }
633
- /**
634
- * Returns a read-only list of `packageDirectories` within sfdx-project.json, first reading
635
- * and validating the file if necessary. i.e. modifying this array will not affect the
636
- * sfdx-project.json file.
637
- */
638
- getPackageAliases() {
639
- if (!this.packageAliases) {
640
- this.packageAliases = this.getSfProjectJson().getPackageAliases();
641
- }
642
- return this.packageAliases;
643
- }
644
- getPackageIdFromAlias(alias) {
645
- const packageAliases = this.getPackageAliases();
646
- return packageAliases ? packageAliases[alias] : undefined;
647
- }
648
- getAliasesFromPackageId(id) {
649
- if (!/^.{15,18}$/.test(id)) {
650
- throw messages.createError('invalidId', [id]);
651
- }
652
- return Object.entries(this.getPackageAliases() ?? {})
653
- .filter(([, value]) => value?.startsWith(id))
654
- .map(([key]) => key);
655
- }
656
- }
657
- exports.SfProject = SfProject;
658
- // Cache of SfProject instances per path.
659
- SfProject.instances = new Map();
660
- /**
661
- * @deprecated use SfProject instead
662
- */
663
- class SfdxProject extends SfProject {
664
- }
665
- exports.SfdxProject = SfdxProject;
666
- /**
667
- * @deprecated use SfProjectJson instead
668
- */
669
- class SfdxProjectJson extends SfProjectJson {
670
- }
671
- exports.SfdxProjectJson = SfdxProjectJson;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SfdxProjectJson = exports.SfdxProject = exports.SfProject = exports.SfProjectJson = void 0;
4
+ /*
5
+ * Copyright (c) 2020, salesforce.com, inc.
6
+ * All rights reserved.
7
+ * Licensed under the BSD 3-Clause license.
8
+ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
9
+ */
10
+ const path_1 = require("path");
11
+ const fs = require("fs");
12
+ const kit_1 = require("@salesforce/kit");
13
+ const ts_types_1 = require("@salesforce/ts-types");
14
+ const sfdcUrl_1 = require("./util/sfdcUrl");
15
+ const configAggregator_1 = require("./config/configAggregator");
16
+ const configFile_1 = require("./config/configFile");
17
+ const validator_1 = require("./schema/validator");
18
+ const internal_1 = require("./util/internal");
19
+ const sfError_1 = require("./sfError");
20
+ const sfdc_1 = require("./util/sfdc");
21
+ const messages_1 = require("./messages");
22
+ messages_1.Messages.importMessagesDirectory(__dirname);
23
+ const messages = messages_1.Messages.load('@salesforce/core', 'config', [
24
+ 'schemaValidationError',
25
+ 'singleNonDefaultPackage',
26
+ 'missingDefaultPath',
27
+ 'multipleDefaultPaths',
28
+ 'invalidPackageDirectory',
29
+ 'missingPackageDirectory',
30
+ 'invalidId',
31
+ ]);
32
+ const coreMessages = messages_1.Messages.load('@salesforce/core', 'core', ['invalidJsonCasing']);
33
+ /**
34
+ * The sfdx-project.json config object. This file determines if a folder is a valid sfdx project.
35
+ *
36
+ * *Note:* Any non-standard (not owned by Salesforce) properties stored in sfdx-project.json should
37
+ * be in a top level property that represents your project or plugin.
38
+ *
39
+ * ```
40
+ * const project = await SfProject.resolve();
41
+ * const projectJson = await project.resolveProjectConfig();
42
+ * const myPluginProperties = projectJson.get('myplugin') || {};
43
+ * myPluginProperties.myprop = 'someValue';
44
+ * projectJson.set('myplugin', myPluginProperties);
45
+ * await projectJson.write();
46
+ * ```
47
+ *
48
+ * **See** [force:project:create](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_create_new.htm)
49
+ */
50
+ class SfProjectJson extends configFile_1.ConfigFile {
51
+ static getFileName() {
52
+ return internal_1.SFDX_PROJECT_JSON;
53
+ }
54
+ static getDefaultOptions(isGlobal = false) {
55
+ const options = configFile_1.ConfigFile.getDefaultOptions(isGlobal, SfProjectJson.getFileName());
56
+ options.isState = false;
57
+ return options;
58
+ }
59
+ async read() {
60
+ const contents = await super.read();
61
+ this.validateKeys();
62
+ await this.schemaValidate();
63
+ return contents;
64
+ }
65
+ readSync() {
66
+ const contents = super.readSync();
67
+ this.validateKeys();
68
+ this.schemaValidateSync();
69
+ return contents;
70
+ }
71
+ async write(newContents) {
72
+ if (newContents) {
73
+ this.setContents(newContents);
74
+ }
75
+ this.validateKeys();
76
+ await this.schemaValidate();
77
+ return super.write();
78
+ }
79
+ writeSync(newContents) {
80
+ if (newContents) {
81
+ this.setContents(newContents);
82
+ }
83
+ this.validateKeys();
84
+ this.schemaValidateSync();
85
+ return super.writeSync();
86
+ }
87
+ getContents() {
88
+ return super.getContents();
89
+ }
90
+ // eslint-disable-next-line class-methods-use-this
91
+ getDefaultOptions(options) {
92
+ const defaultOptions = {
93
+ isState: false,
94
+ };
95
+ Object.assign(defaultOptions, options ?? {});
96
+ return defaultOptions;
97
+ }
98
+ /**
99
+ * Validates sfdx-project.json against the schema.
100
+ *
101
+ * Set the `SFDX_PROJECT_JSON_VALIDATION` environment variable to `true` to throw an error when schema validation fails.
102
+ * A warning is logged by default when the file is invalid.
103
+ *
104
+ * ***See*** [sfdx-project.schema.json] ((https://github.com/forcedotcom/schemas/blob/main/sfdx-project.schema.json)
105
+ */
106
+ async schemaValidate() {
107
+ if (!this.hasRead) {
108
+ // read calls back into this method after necessarily setting this.hasRead=true
109
+ await this.read();
110
+ }
111
+ else {
112
+ try {
113
+ const projectJsonSchemaPath = require.resolve('@salesforce/schemas/sfdx-project.schema.json');
114
+ const validator = new validator_1.SchemaValidator(this.logger, projectJsonSchemaPath);
115
+ await validator.validate(this.getContents());
116
+ }
117
+ catch (err) {
118
+ const error = err;
119
+ // Don't throw errors if the global isn't valid, but still warn the user.
120
+ if (kit_1.env.getBoolean('SFDX_PROJECT_JSON_VALIDATION', false) && !this.options.isGlobal) {
121
+ throw messages.createError('schemaValidationError', [this.getPath(), error.message], [this.getPath()], error);
122
+ }
123
+ else {
124
+ this.logger.warn(messages.getMessage('schemaValidationError', [this.getPath(), error.message]));
125
+ }
126
+ }
127
+ }
128
+ }
129
+ /**
130
+ * Returns the `packageDirectories` within sfdx-project.json, first reading
131
+ * and validating the file if necessary.
132
+ */
133
+ // eslint-disable-next-line @typescript-eslint/require-await
134
+ async getPackageDirectories() {
135
+ return this.getPackageDirectoriesSync();
136
+ }
137
+ /**
138
+ * Validates sfdx-project.json against the schema.
139
+ *
140
+ * Set the `SFDX_PROJECT_JSON_VALIDATION` environment variable to `true` to throw an error when schema validation fails.
141
+ * A warning is logged by default when the file is invalid.
142
+ *
143
+ * ***See*** [sfdx-project.schema.json] ((https://github.com/forcedotcom/schemas/blob/main/sfdx-project.schema.json)
144
+ */
145
+ schemaValidateSync() {
146
+ if (!this.hasRead) {
147
+ // read calls back into this method after necessarily setting this.hasRead=true
148
+ this.readSync();
149
+ }
150
+ else {
151
+ try {
152
+ const projectJsonSchemaPath = require.resolve('@salesforce/schemas/sfdx-project.schema.json');
153
+ const validator = new validator_1.SchemaValidator(this.logger, projectJsonSchemaPath);
154
+ validator.validateSync(this.getContents());
155
+ }
156
+ catch (err) {
157
+ const error = err;
158
+ // Don't throw errors if the global isn't valid, but still warn the user.
159
+ if (kit_1.env.getBoolean('SFDX_PROJECT_JSON_VALIDATION', false) && !this.options.isGlobal) {
160
+ throw messages.createError('schemaValidationError', [this.getPath(), error.message], [this.getPath()], error);
161
+ }
162
+ else {
163
+ this.logger.warn(messages.getMessage('schemaValidationError', [this.getPath(), error.message]));
164
+ }
165
+ }
166
+ }
167
+ }
168
+ /**
169
+ * Returns a read-only list of `packageDirectories` within sfdx-project.json, first reading
170
+ * and validating the file if necessary. i.e. modifying this array will not affect the
171
+ * sfdx-project.json file.
172
+ */
173
+ getPackageDirectoriesSync() {
174
+ const contents = this.getContents();
175
+ // This has to be done on the fly so it won't be written back to the file
176
+ // This is a fast operation so no need to cache it so it stays immutable.
177
+ const packageDirs = (contents.packageDirectories || []).map((packageDir) => {
178
+ if ((0, path_1.isAbsolute)(packageDir.path)) {
179
+ throw messages.createError('invalidPackageDirectory', [packageDir.path]);
180
+ }
181
+ const regex = path_1.sep === '/' ? /\\/g : /\//g;
182
+ // Change packageDir paths to have path separators that match the OS
183
+ const path = packageDir.path.replace(regex, path_1.sep);
184
+ // Normalize and remove any ending path separators
185
+ const name = (0, path_1.normalize)(path).replace(new RegExp(`\\${path_1.sep}$`), '');
186
+ // Always end in a path sep for standardization on folder paths
187
+ const fullPath = `${(0, path_1.dirname)(this.getPath())}${path_1.sep}${name}${path_1.sep}`;
188
+ if (!this.doesPackageExist(fullPath)) {
189
+ throw messages.createError('missingPackageDirectory', [packageDir.path]);
190
+ }
191
+ return Object.assign({}, packageDir, { name, path, fullPath });
192
+ });
193
+ // If we only have one package entry, it must be the default even if not explicitly labelled
194
+ if (packageDirs.length === 1) {
195
+ if (packageDirs[0].default === false) {
196
+ // we have one package but it is explicitly labelled as default=false
197
+ throw messages.createError('singleNonDefaultPackage');
198
+ }
199
+ // add default=true to the package
200
+ packageDirs[0].default = true;
201
+ }
202
+ const defaultDirs = packageDirs.filter((packageDir) => packageDir.default);
203
+ // Don't throw about a missing default path if we are in the global file.
204
+ // Package directories are not really meant to be set at the global level.
205
+ if (defaultDirs.length === 0 && !this.isGlobal()) {
206
+ throw messages.createError('missingDefaultPath');
207
+ }
208
+ else if (defaultDirs.length > 1) {
209
+ throw messages.createError('multipleDefaultPaths');
210
+ }
211
+ return packageDirs;
212
+ }
213
+ /**
214
+ * Returns a read-only list of `packageDirectories` within sfdx-project.json, first reading
215
+ * and validating the file if necessary. i.e. modifying this array will not affect the
216
+ * sfdx-project.json file.
217
+ *
218
+ * There can be multiple packages in packageDirectories that point to the same directory.
219
+ * This method only returns one packageDirectory entry per unique directory path. This is
220
+ * useful when doing source operations based on directories but probably not as useful
221
+ * for packaging operations that want to do something for each package entry.
222
+ */
223
+ getUniquePackageDirectories() {
224
+ const visited = new Set();
225
+ const uniqueValues = [];
226
+ // Keep original order defined in sfdx-project.json
227
+ this.getPackageDirectoriesSync().forEach((packageDir) => {
228
+ if (!visited.has(packageDir.name)) {
229
+ visited.add(packageDir.name);
230
+ uniqueValues.push(packageDir);
231
+ }
232
+ });
233
+ return uniqueValues;
234
+ }
235
+ /**
236
+ * Get a list of the unique package names from within sfdx-project.json. Use {@link SfProject.getUniquePackageDirectories}
237
+ * for data other than the names.
238
+ */
239
+ getUniquePackageNames() {
240
+ return this.getUniquePackageDirectories().map((pkgDir) => pkgDir.name);
241
+ }
242
+ /**
243
+ * Has package directories defined in the project.
244
+ */
245
+ hasPackages() {
246
+ return this.getContents()?.packageDirectories?.length > 0;
247
+ }
248
+ /**
249
+ * Has multiple package directories (MPD) defined in the project.
250
+ */
251
+ hasMultiplePackages() {
252
+ return this.getContents()?.packageDirectories?.length > 1;
253
+ }
254
+ /**
255
+ * Has at least one package alias defined in the project.
256
+ */
257
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type, @typescript-eslint/require-await
258
+ async hasPackageAliases() {
259
+ return Object.keys(this.getContents().packageAliases ?? {}).length > 0;
260
+ }
261
+ /**
262
+ * Get package aliases defined in the project.
263
+ */
264
+ getPackageAliases() {
265
+ return this.getContents().packageAliases;
266
+ }
267
+ /**
268
+ * Add a package alias to the project.
269
+ * If the alias already exists, it will be overwritten.
270
+ *
271
+ * @param alias
272
+ * @param id
273
+ */
274
+ addPackageAlias(alias, id) {
275
+ // TODO: validate id (e.g. 04t, 0Ho)
276
+ if (!/^.{15,18}$/.test(id)) {
277
+ throw messages.createError('invalidId', [id]);
278
+ }
279
+ const contents = this.getContents();
280
+ if (!contents.packageAliases) {
281
+ contents.packageAliases = {};
282
+ }
283
+ contents.packageAliases[alias] = id;
284
+ this.setContents(contents);
285
+ }
286
+ /**
287
+ * Add a package directory to the project.
288
+ * If the package directory already exists, the new directory
289
+ * properties will be merged with the existing properties.
290
+ *
291
+ * @param packageDir
292
+ */
293
+ addPackageDirectory(packageDir) {
294
+ // there is no notion of uniqueness in package directory entries
295
+ // so an attempt of matching an existing entry is a bit convoluted
296
+ // an entry w/o a package or id is considered a directory entry for which a package has yet to be created
297
+ // so first attempt is to find a matching dir entry that where path is the same and id and package are not present
298
+ // if that fails, then find a matching dir entry package is present and is same as the new entry
299
+ const dirIndex = this.getContents().packageDirectories.findIndex((pd) => {
300
+ const withId = pd;
301
+ return ((withId.path === packageDir.path && !withId.id && !withId.package) ||
302
+ (!!packageDir.package && packageDir.package === withId.package));
303
+ });
304
+ // merge new package dir with existing entry, if present
305
+ const packageDirEntry = Object.assign({}, dirIndex > -1 ? this.getContents().packageDirectories[dirIndex] : packageDir, packageDir);
306
+ // update package dir entries
307
+ if (dirIndex > -1) {
308
+ this.getContents().packageDirectories[dirIndex] = packageDirEntry;
309
+ }
310
+ else {
311
+ this.getContents().packageDirectories.push(packageDirEntry);
312
+ }
313
+ }
314
+ // eslint-disable-next-line class-methods-use-this
315
+ doesPackageExist(packagePath) {
316
+ return fs.existsSync(packagePath);
317
+ }
318
+ validateKeys() {
319
+ // Verify that the configObject does not have upper case keys; throw if it does. Must be heads down camel case.
320
+ const upperCaseKey = sfdc_1.sfdc.findUpperCaseKeys(this.toObject(), SfProjectJson.BLOCKLIST);
321
+ if (upperCaseKey) {
322
+ throw coreMessages.createError('invalidJsonCasing', [upperCaseKey, this.getPath()]);
323
+ }
324
+ }
325
+ }
326
+ exports.SfProjectJson = SfProjectJson;
327
+ SfProjectJson.BLOCKLIST = ['packageAliases'];
328
+ /**
329
+ * Represents an SFDX project directory. This directory contains a {@link SfProjectJson} config file as well as
330
+ * a hidden .sfdx folder that contains all the other local project config files.
331
+ *
332
+ * ```
333
+ * const project = await SfProject.resolve();
334
+ * const projectJson = await project.resolveProjectConfig();
335
+ * console.log(projectJson.sfdcLoginUrl);
336
+ * ```
337
+ */
338
+ class SfProject {
339
+ /**
340
+ * Do not directly construct instances of this class -- use {@link SfProject.resolve} instead.
341
+ *
342
+ * @ignore
343
+ */
344
+ constructor(path) {
345
+ this.path = path;
346
+ }
347
+ /**
348
+ * Get a Project from a given path or from the working directory.
349
+ *
350
+ * @param path The path of the project.
351
+ *
352
+ * **Throws** *{@link SfError}{ name: 'InvalidProjectWorkspaceError' }* If the current folder is not located in a workspace.
353
+ */
354
+ static async resolve(path) {
355
+ path = await this.resolveProjectPath(path ?? process.cwd());
356
+ if (!SfProject.instances.has(path)) {
357
+ const project = new SfProject(path);
358
+ SfProject.instances.set(path, project);
359
+ }
360
+ return (0, ts_types_1.ensure)(SfProject.instances.get(path));
361
+ }
362
+ /**
363
+ * Get a Project from a given path or from the working directory.
364
+ *
365
+ * @param path The path of the project.
366
+ *
367
+ * **Throws** *{@link SfError}{ name: 'InvalidProjectWorkspaceError' }* If the current folder is not located in a workspace.
368
+ */
369
+ static getInstance(path) {
370
+ // Store instance based on the path of the actual project.
371
+ path = this.resolveProjectPathSync(path ?? process.cwd());
372
+ if (!SfProject.instances.has(path)) {
373
+ const project = new SfProject(path);
374
+ SfProject.instances.set(path, project);
375
+ }
376
+ return (0, ts_types_1.ensure)(SfProject.instances.get(path));
377
+ }
378
+ /**
379
+ * Performs an upward directory search for an sfdx project file. Returns the absolute path to the project.
380
+ *
381
+ * @param dir The directory path to start traversing from.
382
+ *
383
+ * **Throws** *{@link SfError}{ name: 'InvalidProjectWorkspaceError' }* If the current folder is not located in a workspace.
384
+ *
385
+ * **See** {@link traverseForFile}
386
+ *
387
+ * **See** [process.cwd()](https://nodejs.org/api/process.html#process_process_cwd)
388
+ */
389
+ static async resolveProjectPath(dir) {
390
+ return (0, internal_1.resolveProjectPath)(dir);
391
+ }
392
+ /**
393
+ * Performs a synchronous upward directory search for an sfdx project file. Returns the absolute path to the project.
394
+ *
395
+ * @param dir The directory path to start traversing from.
396
+ *
397
+ * **Throws** *{@link SfError}{ name: 'InvalidProjectWorkspaceError' }* If the current folder is not located in a workspace.
398
+ *
399
+ * **See** {@link traverseForFileSync}
400
+ *
401
+ * **See** [process.cwd()](https://nodejs.org/api/process.html#process_process_cwd)
402
+ */
403
+ static resolveProjectPathSync(dir) {
404
+ return (0, internal_1.resolveProjectPathSync)(dir);
405
+ }
406
+ /**
407
+ * Returns the project path.
408
+ */
409
+ getPath() {
410
+ return this.path;
411
+ }
412
+ /**
413
+ * Get the sfdx-project.json config. The global sfdx-project.json is used for user defaults
414
+ * that are not checked in to the project specific file.
415
+ *
416
+ * *Note:* When reading values from {@link SfProjectJson}, it is recommended to use
417
+ * {@link SfProject.resolveProjectConfig} instead.
418
+ *
419
+ * @param isGlobal True to get the global project file, otherwise the local project config.
420
+ */
421
+ async retrieveSfProjectJson(isGlobal = false) {
422
+ const options = SfProjectJson.getDefaultOptions(isGlobal);
423
+ if (isGlobal) {
424
+ if (!this.sfProjectJsonGlobal) {
425
+ this.sfProjectJsonGlobal = await SfProjectJson.create(options);
426
+ }
427
+ return this.sfProjectJsonGlobal;
428
+ }
429
+ else {
430
+ options.rootFolder = this.getPath();
431
+ if (!this.sfProjectJson) {
432
+ this.sfProjectJson = await SfProjectJson.create(options);
433
+ }
434
+ return this.sfProjectJson;
435
+ }
436
+ }
437
+ /**
438
+ * Get the sfdx-project.json config. The global sfdx-project.json is used for user defaults
439
+ * that are not checked in to the project specific file.
440
+ *
441
+ * *Note:* When reading values from {@link SfProjectJson}, it is recommended to use
442
+ * {@link SfProject.resolveProjectConfig} instead.
443
+ *
444
+ * This is the sync method of {@link SfProject.resolveSfProjectJson}
445
+ *
446
+ * @param isGlobal True to get the global project file, otherwise the local project config.
447
+ */
448
+ getSfProjectJson(isGlobal = false) {
449
+ const options = SfProjectJson.getDefaultOptions(isGlobal);
450
+ if (isGlobal) {
451
+ if (!this.sfProjectJsonGlobal) {
452
+ this.sfProjectJsonGlobal = new SfProjectJson(options);
453
+ this.sfProjectJsonGlobal.readSync();
454
+ }
455
+ return this.sfProjectJsonGlobal;
456
+ }
457
+ else {
458
+ options.rootFolder = this.getPath();
459
+ if (!this.sfProjectJson) {
460
+ this.sfProjectJson = new SfProjectJson(options);
461
+ this.sfProjectJson.readSync();
462
+ }
463
+ return this.sfProjectJson;
464
+ }
465
+ }
466
+ /**
467
+ * Returns a read-only list of `packageDirectories` within sfdx-project.json, first reading
468
+ * and validating the file if necessary. i.e. modifying this array will not affect the
469
+ * sfdx-project.json file.
470
+ */
471
+ getPackageDirectories() {
472
+ if (!this.packageDirectories) {
473
+ this.packageDirectories = this.getSfProjectJson().getPackageDirectoriesSync();
474
+ }
475
+ return this.packageDirectories;
476
+ }
477
+ /**
478
+ * Returns a read-only list of `packageDirectories` within sfdx-project.json, first reading
479
+ * and validating the file if necessary. i.e. modifying this array will not affect the
480
+ * sfdx-project.json file.
481
+ *
482
+ * There can be multiple packages in packageDirectories that point to the same directory.
483
+ * This method only returns one packageDirectory entry per unique directory path. This is
484
+ * useful when doing source operations based on directories but probably not as useful
485
+ * for packaging operations that want to do something for each package entry.
486
+ */
487
+ getUniquePackageDirectories() {
488
+ return this.getSfProjectJson().getUniquePackageDirectories();
489
+ }
490
+ /**
491
+ * Get a list of the unique package names from within sfdx-project.json. Use {@link SfProject.getUniquePackageDirectories}
492
+ * for data other than the names.
493
+ */
494
+ getUniquePackageNames() {
495
+ return this.getSfProjectJson().getUniquePackageNames();
496
+ }
497
+ /**
498
+ * Returns the package from a file path.
499
+ *
500
+ * @param path A file path. E.g. /Users/jsmith/projects/ebikes-lwc/force-app/apex/my-cls.cls
501
+ */
502
+ getPackageFromPath(path) {
503
+ const packageDirs = this.getPackageDirectories();
504
+ const match = packageDirs.find((packageDir) => (0, path_1.basename)(path) === packageDir.path || path.includes(packageDir.fullPath));
505
+ return match;
506
+ }
507
+ /**
508
+ * Returns the package name, E.g. 'force-app', from a file path.
509
+ *
510
+ * @param path A file path. E.g. /Users/jsmith/projects/ebikes-lwc/force-app/apex/my-cls.cls
511
+ */
512
+ getPackageNameFromPath(path) {
513
+ const packageDir = this.getPackageFromPath(path);
514
+ return packageDir ? packageDir.package ?? packageDir.path : undefined;
515
+ }
516
+ /**
517
+ * Returns the package directory.
518
+ *
519
+ * @param packageName Name of the package directory. E.g., 'force-app'
520
+ */
521
+ getPackage(packageName) {
522
+ const packageDirs = this.getPackageDirectories();
523
+ return packageDirs.find((packageDir) => packageDir.name === packageName);
524
+ }
525
+ /**
526
+ * Returns the package directory.
527
+ *
528
+ * @param packageName Name of the package directory. E.g., 'force-app'
529
+ */
530
+ findPackage(predicate) {
531
+ return this.getPackageDirectories().find(predicate);
532
+ }
533
+ /**
534
+ * Returns the absolute path of the package directory ending with the path separator.
535
+ * E.g., /Users/jsmith/projects/ebikes-lwc/force-app/
536
+ *
537
+ * @param packageName Name of the package directory. E.g., 'force-app'
538
+ */
539
+ getPackagePath(packageName) {
540
+ const packageDir = this.getPackage(packageName);
541
+ return packageDir?.fullPath;
542
+ }
543
+ /**
544
+ * Has package directories defined in the project.
545
+ */
546
+ hasPackages() {
547
+ return this.getSfProjectJson().hasPackages();
548
+ }
549
+ /**
550
+ * Has multiple package directories (MPD) defined in the project.
551
+ */
552
+ hasMultiplePackages() {
553
+ return this.getSfProjectJson().hasMultiplePackages();
554
+ }
555
+ /**
556
+ * Get the currently activated package on the project. This has no implication on sfdx-project.json
557
+ * but is useful for keeping track of package and source specific options in a process.
558
+ */
559
+ getActivePackage() {
560
+ return this.activePackage;
561
+ }
562
+ /**
563
+ * Set the currently activated package on the project. This has no implication on sfdx-project.json
564
+ * but is useful for keeping track of package and source specific options in a process.
565
+ *
566
+ * @param packageName The package name to activate. E.g. 'force-app'
567
+ */
568
+ setActivePackage(packageName) {
569
+ if (packageName == null) {
570
+ this.activePackage = null;
571
+ }
572
+ else {
573
+ this.activePackage = this.getPackage(packageName);
574
+ }
575
+ }
576
+ /**
577
+ * Get the project's default package directory defined in sfdx-project.json using first 'default: true'
578
+ * found. The first entry is returned if no default is specified.
579
+ */
580
+ getDefaultPackage() {
581
+ if (!this.hasPackages()) {
582
+ throw new sfError_1.SfError('The sfdx-project.json does not have any packageDirectories defined.');
583
+ }
584
+ const defaultPackage = this.findPackage((packageDir) => packageDir.default === true);
585
+ return defaultPackage ?? this.getPackageDirectories()[0];
586
+ }
587
+ /**
588
+ * The project config is resolved from local and global {@link SfProjectJson},
589
+ * {@link ConfigAggregator}, and a set of defaults. It is recommended to use
590
+ * this when reading values from SfProjectJson.
591
+ *
592
+ * The global {@link SfProjectJson} is used to allow the user to provide default values they
593
+ * may not want checked into their project's source.
594
+ *
595
+ * @returns A resolved config object that contains a bunch of different
596
+ * properties, including some 3rd party custom properties.
597
+ */
598
+ async resolveProjectConfig() {
599
+ if (!this.projectConfig) {
600
+ // Do fs operations in parallel
601
+ const [global, local, configAggregator] = await Promise.all([
602
+ this.retrieveSfProjectJson(true),
603
+ this.retrieveSfProjectJson(),
604
+ configAggregator_1.ConfigAggregator.create(),
605
+ ]);
606
+ await Promise.all([global.read(), local.read()]);
607
+ this.projectConfig = (0, kit_1.defaults)(local.toObject(), global.toObject());
608
+ // Add fields in sfdx-config.json
609
+ Object.assign(this.projectConfig, configAggregator.getConfig());
610
+ // we don't have a login url yet, so use instanceUrl from config or default
611
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
612
+ if (!this.projectConfig.sfdcLoginUrl) {
613
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
614
+ this.projectConfig.sfdcLoginUrl = configAggregator.getConfig()['org-instance-url'] ?? sfdcUrl_1.SfdcUrl.PRODUCTION;
615
+ }
616
+ // LEGACY - Allow override of sfdcLoginUrl via env var FORCE_SFDC_LOGIN_URL
617
+ if (process.env.FORCE_SFDC_LOGIN_URL) {
618
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
619
+ this.projectConfig.sfdcLoginUrl = process.env.FORCE_SFDC_LOGIN_URL;
620
+ }
621
+ // Allow override of signupTargetLoginUrl via env var SFDX_SCRATCH_ORG_CREATION_LOGIN_URL
622
+ if (process.env.SFDX_SCRATCH_ORG_CREATION_LOGIN_URL) {
623
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
624
+ this.projectConfig.signupTargetLoginUrl = process.env.SFDX_SCRATCH_ORG_CREATION_LOGIN_URL;
625
+ }
626
+ }
627
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
628
+ return this.projectConfig;
629
+ }
630
+ async hasPackageAliases() {
631
+ return this.getSfProjectJson().hasPackageAliases();
632
+ }
633
+ /**
634
+ * Returns a read-only list of `packageDirectories` within sfdx-project.json, first reading
635
+ * and validating the file if necessary. i.e. modifying this array will not affect the
636
+ * sfdx-project.json file.
637
+ */
638
+ getPackageAliases() {
639
+ if (!this.packageAliases) {
640
+ this.packageAliases = this.getSfProjectJson().getPackageAliases();
641
+ }
642
+ return this.packageAliases;
643
+ }
644
+ getPackageIdFromAlias(alias) {
645
+ const packageAliases = this.getPackageAliases();
646
+ return packageAliases ? packageAliases[alias] : undefined;
647
+ }
648
+ getAliasesFromPackageId(id) {
649
+ if (!/^.{15,18}$/.test(id)) {
650
+ throw messages.createError('invalidId', [id]);
651
+ }
652
+ return Object.entries(this.getPackageAliases() ?? {})
653
+ .filter(([, value]) => value?.startsWith(id))
654
+ .map(([key]) => key);
655
+ }
656
+ }
657
+ exports.SfProject = SfProject;
658
+ // Cache of SfProject instances per path.
659
+ SfProject.instances = new Map();
660
+ /**
661
+ * @deprecated use SfProject instead
662
+ */
663
+ class SfdxProject extends SfProject {
664
+ }
665
+ exports.SfdxProject = SfdxProject;
666
+ /**
667
+ * @deprecated use SfProjectJson instead
668
+ */
669
+ class SfdxProjectJson extends SfProjectJson {
670
+ }
671
+ exports.SfdxProjectJson = SfdxProjectJson;
672
672
  //# sourceMappingURL=sfProject.js.map