@salesforce/core 3.31.7 → 3.31.9
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/LICENSE.txt +11 -11
- package/README.md +222 -222
- package/lib/config/aliasesConfig.d.ts +12 -12
- package/lib/config/aliasesConfig.js +27 -27
- package/lib/config/authInfoConfig.d.ts +19 -19
- package/lib/config/authInfoConfig.js +34 -34
- package/lib/config/config.d.ts +311 -311
- package/lib/config/config.js +574 -574
- package/lib/config/configAggregator.d.ts +232 -232
- package/lib/config/configAggregator.js +379 -379
- package/lib/config/configFile.d.ts +199 -199
- package/lib/config/configFile.js +340 -340
- package/lib/config/configGroup.d.ts +141 -141
- package/lib/config/configGroup.js +224 -224
- package/lib/config/configStore.d.ts +241 -241
- package/lib/config/configStore.js +352 -352
- package/lib/config/envVars.d.ts +101 -101
- package/lib/config/envVars.js +456 -456
- package/lib/config/orgUsersConfig.d.ts +31 -31
- package/lib/config/orgUsersConfig.js +41 -41
- package/lib/config/sandboxOrgConfig.d.ts +37 -37
- package/lib/config/sandboxOrgConfig.js +50 -50
- package/lib/config/sandboxProcessCache.d.ts +16 -16
- package/lib/config/sandboxProcessCache.js +37 -37
- package/lib/config/tokensConfig.d.ts +10 -10
- package/lib/config/tokensConfig.js +28 -28
- package/lib/config/ttlConfig.d.ts +34 -34
- package/lib/config/ttlConfig.js +54 -54
- package/lib/crypto/crypto.d.ts +54 -54
- package/lib/crypto/crypto.js +220 -220
- package/lib/crypto/keyChain.d.ts +8 -8
- package/lib/crypto/keyChain.js +61 -61
- package/lib/crypto/keyChainImpl.d.ts +116 -116
- package/lib/crypto/keyChainImpl.js +486 -486
- package/lib/crypto/secureBuffer.d.ts +46 -46
- package/lib/crypto/secureBuffer.js +82 -82
- package/lib/deviceOauthService.d.ts +71 -71
- package/lib/deviceOauthService.js +191 -191
- package/lib/exported.d.ts +38 -38
- package/lib/exported.js +118 -118
- package/lib/global.d.ts +70 -70
- package/lib/global.js +109 -109
- package/lib/lifecycleEvents.d.ts +93 -93
- package/lib/lifecycleEvents.js +188 -188
- package/lib/logger.d.ts +381 -381
- package/lib/logger.js +734 -734
- package/lib/messages.d.ts +291 -291
- package/lib/messages.js +543 -543
- package/lib/org/authInfo.d.ts +344 -344
- package/lib/org/authInfo.js +892 -892
- package/lib/org/authRemover.d.ts +88 -88
- package/lib/org/authRemover.js +182 -182
- package/lib/org/connection.d.ts +197 -197
- package/lib/org/connection.js +395 -395
- package/lib/org/index.d.ts +6 -6
- package/lib/org/index.js +28 -28
- package/lib/org/org.d.ts +558 -558
- package/lib/org/org.js +1267 -1267
- package/lib/org/orgConfigProperties.d.ts +69 -69
- package/lib/org/orgConfigProperties.js +136 -136
- package/lib/org/permissionSetAssignment.d.ts +35 -35
- package/lib/org/permissionSetAssignment.js +125 -125
- package/lib/org/scratchOrgCache.d.ts +20 -20
- package/lib/org/scratchOrgCache.js +32 -32
- package/lib/org/scratchOrgCreate.d.ts +54 -54
- package/lib/org/scratchOrgCreate.js +216 -216
- package/lib/org/scratchOrgErrorCodes.d.ts +10 -10
- package/lib/org/scratchOrgErrorCodes.js +88 -88
- package/lib/org/scratchOrgFeatureDeprecation.d.ts +26 -26
- package/lib/org/scratchOrgFeatureDeprecation.js +109 -109
- package/lib/org/scratchOrgInfoApi.d.ts +68 -68
- package/lib/org/scratchOrgInfoApi.js +416 -413
- package/lib/org/scratchOrgInfoGenerator.d.ts +64 -64
- package/lib/org/scratchOrgInfoGenerator.js +241 -241
- package/lib/org/scratchOrgLifecycleEvents.d.ts +10 -10
- package/lib/org/scratchOrgLifecycleEvents.js +40 -40
- package/lib/org/scratchOrgSettingsGenerator.d.ts +78 -78
- package/lib/org/scratchOrgSettingsGenerator.js +276 -276
- package/lib/org/scratchOrgTypes.d.ts +43 -43
- package/lib/org/scratchOrgTypes.js +8 -8
- package/lib/org/user.d.ts +187 -187
- package/lib/org/user.js +448 -448
- package/lib/schema/printer.d.ts +79 -79
- package/lib/schema/printer.js +260 -260
- package/lib/schema/validator.d.ts +70 -70
- package/lib/schema/validator.js +169 -169
- package/lib/sfError.d.ts +73 -73
- package/lib/sfError.js +136 -136
- package/lib/sfProject.d.ts +357 -357
- package/lib/sfProject.js +671 -671
- package/lib/stateAggregator/accessors/aliasAccessor.d.ts +98 -98
- package/lib/stateAggregator/accessors/aliasAccessor.js +145 -145
- package/lib/stateAggregator/accessors/orgAccessor.d.ts +101 -101
- package/lib/stateAggregator/accessors/orgAccessor.js +240 -240
- package/lib/stateAggregator/accessors/sandboxAccessor.d.ts +8 -8
- package/lib/stateAggregator/accessors/sandboxAccessor.js +27 -27
- package/lib/stateAggregator/accessors/tokenAccessor.d.ts +63 -63
- package/lib/stateAggregator/accessors/tokenAccessor.js +79 -79
- package/lib/stateAggregator/index.d.ts +4 -4
- package/lib/stateAggregator/index.js +26 -26
- package/lib/stateAggregator/stateAggregator.d.ts +25 -25
- package/lib/stateAggregator/stateAggregator.js +45 -45
- package/lib/status/myDomainResolver.d.ts +66 -66
- package/lib/status/myDomainResolver.js +124 -124
- package/lib/status/pollingClient.d.ts +85 -85
- package/lib/status/pollingClient.js +115 -115
- package/lib/status/streamingClient.d.ts +244 -244
- package/lib/status/streamingClient.js +436 -436
- package/lib/status/types.d.ts +89 -89
- package/lib/status/types.js +17 -17
- package/lib/testSetup.d.ts +553 -553
- package/lib/testSetup.js +871 -871
- package/lib/util/cache.d.ts +11 -11
- package/lib/util/cache.js +69 -69
- package/lib/util/checkLightningDomain.d.ts +1 -1
- package/lib/util/checkLightningDomain.js +28 -28
- package/lib/util/directoryWriter.d.ts +12 -12
- package/lib/util/directoryWriter.js +53 -53
- package/lib/util/getJwtAudienceUrl.d.ts +4 -4
- package/lib/util/getJwtAudienceUrl.js +18 -18
- package/lib/util/internal.d.ts +58 -58
- package/lib/util/internal.js +118 -118
- package/lib/util/jsonXmlTools.d.ts +14 -14
- package/lib/util/jsonXmlTools.js +38 -38
- package/lib/util/mapKeys.d.ts +14 -14
- package/lib/util/mapKeys.js +51 -51
- package/lib/util/sfdc.d.ts +52 -52
- package/lib/util/sfdc.js +85 -85
- package/lib/util/sfdcUrl.d.ts +72 -72
- package/lib/util/sfdcUrl.js +215 -215
- package/lib/util/structuredWriter.d.ts +9 -9
- package/lib/util/structuredWriter.js +2 -2
- package/lib/util/zipWriter.d.ts +16 -16
- package/lib/util/zipWriter.js +67 -67
- package/lib/webOAuthServer.d.ts +156 -156
- package/lib/webOAuthServer.js +388 -388
- package/messages/auth.md +37 -37
- package/messages/config.md +156 -156
- package/messages/connection.md +30 -30
- package/messages/core.json +20 -20
- package/messages/core.md +67 -67
- package/messages/encryption.md +85 -85
- package/messages/envVars.md +303 -303
- package/messages/org.md +63 -63
- package/messages/permissionSetAssignment.md +31 -31
- package/messages/scratchOrgCreate.md +23 -23
- package/messages/scratchOrgErrorCodes.md +115 -115
- package/messages/scratchOrgFeatureDeprecation.md +11 -11
- package/messages/scratchOrgInfoApi.md +19 -15
- package/messages/scratchOrgInfoGenerator.md +23 -23
- package/messages/streaming.md +23 -23
- package/messages/user.md +35 -35
- package/package.json +97 -97
package/lib/config/configFile.js
CHANGED
|
@@ -1,341 +1,341 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2020, salesforce.com, inc.
|
|
4
|
-
* All rights reserved.
|
|
5
|
-
* Licensed under the BSD 3-Clause license.
|
|
6
|
-
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.ConfigFile = void 0;
|
|
10
|
-
const fs = require("fs");
|
|
11
|
-
const fs_1 = require("fs");
|
|
12
|
-
const os_1 = require("os");
|
|
13
|
-
const path_1 = require("path");
|
|
14
|
-
const ts_types_1 = require("@salesforce/ts-types");
|
|
15
|
-
const kit_1 = require("@salesforce/kit");
|
|
16
|
-
const global_1 = require("../global");
|
|
17
|
-
const logger_1 = require("../logger");
|
|
18
|
-
const sfError_1 = require("../sfError");
|
|
19
|
-
const internal_1 = require("../util/internal");
|
|
20
|
-
const configStore_1 = require("./configStore");
|
|
21
|
-
/**
|
|
22
|
-
* Represents a json config file used to manage settings and state. Global config
|
|
23
|
-
* files are stored in the home directory hidden state folder (.sfdx) and local config
|
|
24
|
-
* files are stored in the project path, either in the hidden state folder or wherever
|
|
25
|
-
* specified.
|
|
26
|
-
*
|
|
27
|
-
* ```
|
|
28
|
-
* class MyConfig extends ConfigFile {
|
|
29
|
-
* public static getFileName(): string {
|
|
30
|
-
* return 'myConfigFilename.json';
|
|
31
|
-
* }
|
|
32
|
-
* }
|
|
33
|
-
* const myConfig = await MyConfig.create({
|
|
34
|
-
* isGlobal: true
|
|
35
|
-
* });
|
|
36
|
-
* myConfig.set('mykey', 'myvalue');
|
|
37
|
-
* await myConfig.write();
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
class ConfigFile extends configStore_1.BaseConfigStore {
|
|
41
|
-
/**
|
|
42
|
-
* Create an instance of a config file without reading the file. Call `read` or `readSync`
|
|
43
|
-
* after creating the ConfigFile OR instantiate with {@link ConfigFile.create} instead.
|
|
44
|
-
*
|
|
45
|
-
* @param options The options for the class instance
|
|
46
|
-
* @ignore
|
|
47
|
-
*/
|
|
48
|
-
constructor(options) {
|
|
49
|
-
super(options);
|
|
50
|
-
// whether file contents have been read
|
|
51
|
-
this.hasRead = false;
|
|
52
|
-
this.logger = logger_1.Logger.childFromRoot(this.constructor.name);
|
|
53
|
-
const statics = this.constructor;
|
|
54
|
-
let defaultOptions = {};
|
|
55
|
-
try {
|
|
56
|
-
defaultOptions = statics.getDefaultOptions();
|
|
57
|
-
}
|
|
58
|
-
catch (e) {
|
|
59
|
-
/* Some implementations don't let you call default options */
|
|
60
|
-
}
|
|
61
|
-
// Merge default and passed in options
|
|
62
|
-
this.options = Object.assign(defaultOptions, this.options);
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Returns the config's filename.
|
|
66
|
-
*/
|
|
67
|
-
static getFileName() {
|
|
68
|
-
// Can not have abstract static methods, so throw a runtime error.
|
|
69
|
-
throw new sfError_1.SfError('Unknown filename for config file.');
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Returns the default options for the config file.
|
|
73
|
-
*
|
|
74
|
-
* @param isGlobal If the file should be stored globally or locally.
|
|
75
|
-
* @param filename The name of the config file.
|
|
76
|
-
*/
|
|
77
|
-
static getDefaultOptions(isGlobal = false, filename) {
|
|
78
|
-
return {
|
|
79
|
-
isGlobal,
|
|
80
|
-
isState: true,
|
|
81
|
-
filename: filename ?? this.getFileName(),
|
|
82
|
-
stateFolder: global_1.Global.SFDX_STATE_FOLDER,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Helper used to determine what the local and global folder point to. Returns the file path of the root folder.
|
|
87
|
-
*
|
|
88
|
-
* @param isGlobal True if the config should be global. False for local.
|
|
89
|
-
*/
|
|
90
|
-
static async resolveRootFolder(isGlobal) {
|
|
91
|
-
return isGlobal ? (0, os_1.homedir)() : (0, internal_1.resolveProjectPath)();
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Helper used to determine what the local and global folder point to. Returns the file path of the root folder.
|
|
95
|
-
*
|
|
96
|
-
* @param isGlobal True if the config should be global. False for local.
|
|
97
|
-
*/
|
|
98
|
-
static resolveRootFolderSync(isGlobal) {
|
|
99
|
-
return isGlobal ? (0, os_1.homedir)() : (0, internal_1.resolveProjectPathSync)();
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Determines if the config file is read/write accessible. Returns `true` if the user has capabilities specified
|
|
103
|
-
* by perm.
|
|
104
|
-
*
|
|
105
|
-
* @param {number} perm The permission.
|
|
106
|
-
*
|
|
107
|
-
* **See** {@link https://nodejs.org/dist/latest/docs/api/fs.html#fs_fs_access_path_mode_callback}
|
|
108
|
-
*/
|
|
109
|
-
async access(perm) {
|
|
110
|
-
try {
|
|
111
|
-
await fs.promises.access(this.getPath(), perm);
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
catch (err) {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Determines if the config file is read/write accessible. Returns `true` if the user has capabilities specified
|
|
120
|
-
* by perm.
|
|
121
|
-
*
|
|
122
|
-
* @param {number} perm The permission.
|
|
123
|
-
*
|
|
124
|
-
* **See** {@link https://nodejs.org/dist/latest/docs/api/fs.html#fs_fs_access_path_mode_callback}
|
|
125
|
-
*/
|
|
126
|
-
accessSync(perm) {
|
|
127
|
-
try {
|
|
128
|
-
fs.accessSync(this.getPath(), perm);
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
catch (err) {
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Read the config file and set the config contents. Returns the config contents of the config file. As an
|
|
137
|
-
* optimization, files are only read once per process and updated in memory and via `write()`. To force
|
|
138
|
-
* a read from the filesystem pass `force=true`.
|
|
139
|
-
* **Throws** *{@link SfError}{ name: 'UnexpectedJsonFileFormat' }* There was a problem reading or parsing the file.
|
|
140
|
-
*
|
|
141
|
-
* @param [throwOnNotFound = false] Optionally indicate if a throw should occur on file read.
|
|
142
|
-
* @param [force = false] Optionally force the file to be read from disk even when already read within the process.
|
|
143
|
-
*/
|
|
144
|
-
async read(throwOnNotFound = false, force = false) {
|
|
145
|
-
try {
|
|
146
|
-
// Only need to read config files once. They are kept up to date
|
|
147
|
-
// internally and updated persistently via write().
|
|
148
|
-
if (!this.hasRead || force) {
|
|
149
|
-
this.logger.info(`Reading config file: ${this.getPath()}`);
|
|
150
|
-
const obj = (0, kit_1.parseJsonMap)(await fs.promises.readFile(this.getPath(), 'utf8'));
|
|
151
|
-
this.setContentsFromObject(obj);
|
|
152
|
-
}
|
|
153
|
-
return this.getContents();
|
|
154
|
-
}
|
|
155
|
-
catch (err) {
|
|
156
|
-
if (err.code === 'ENOENT') {
|
|
157
|
-
if (!throwOnNotFound) {
|
|
158
|
-
this.setContents();
|
|
159
|
-
return this.getContents();
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
throw err;
|
|
163
|
-
}
|
|
164
|
-
finally {
|
|
165
|
-
// Necessarily set this even when an error happens to avoid infinite re-reading.
|
|
166
|
-
// To attempt another read, pass `force=true`.
|
|
167
|
-
this.hasRead = true;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Read the config file and set the config contents. Returns the config contents of the config file. As an
|
|
172
|
-
* optimization, files are only read once per process and updated in memory and via `write()`. To force
|
|
173
|
-
* a read from the filesystem pass `force=true`.
|
|
174
|
-
* **Throws** *{@link SfError}{ name: 'UnexpectedJsonFileFormat' }* There was a problem reading or parsing the file.
|
|
175
|
-
*
|
|
176
|
-
* @param [throwOnNotFound = false] Optionally indicate if a throw should occur on file read.
|
|
177
|
-
* @param [force = false] Optionally force the file to be read from disk even when already read within the process.
|
|
178
|
-
*/
|
|
179
|
-
readSync(throwOnNotFound = false, force = false) {
|
|
180
|
-
try {
|
|
181
|
-
// Only need to read config files once. They are kept up to date
|
|
182
|
-
// internally and updated persistently via write().
|
|
183
|
-
if (!this.hasRead || force) {
|
|
184
|
-
this.logger.info(`Reading config file: ${this.getPath()}`);
|
|
185
|
-
const obj = (0, kit_1.parseJsonMap)(fs.readFileSync(this.getPath(), 'utf8'));
|
|
186
|
-
this.setContentsFromObject(obj);
|
|
187
|
-
}
|
|
188
|
-
return this.getContents();
|
|
189
|
-
}
|
|
190
|
-
catch (err) {
|
|
191
|
-
if (err.code === 'ENOENT') {
|
|
192
|
-
if (!throwOnNotFound) {
|
|
193
|
-
this.setContents();
|
|
194
|
-
return this.getContents();
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
throw err;
|
|
198
|
-
}
|
|
199
|
-
finally {
|
|
200
|
-
// Necessarily set this even when an error happens to avoid infinite re-reading.
|
|
201
|
-
// To attempt another read, pass `force=true`.
|
|
202
|
-
this.hasRead = true;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Write the config file with new contents. If no new contents are provided it will write the existing config
|
|
207
|
-
* contents that were set from {@link ConfigFile.read}, or an empty file if {@link ConfigFile.read} was not called.
|
|
208
|
-
*
|
|
209
|
-
* @param newContents The new contents of the file.
|
|
210
|
-
*/
|
|
211
|
-
async write(newContents) {
|
|
212
|
-
if (newContents) {
|
|
213
|
-
this.setContents(newContents);
|
|
214
|
-
}
|
|
215
|
-
try {
|
|
216
|
-
await fs.promises.mkdir((0, path_1.dirname)(this.getPath()), { recursive: true });
|
|
217
|
-
}
|
|
218
|
-
catch (err) {
|
|
219
|
-
throw sfError_1.SfError.wrap(err);
|
|
220
|
-
}
|
|
221
|
-
this.logger.info(`Writing to config file: ${this.getPath()}`);
|
|
222
|
-
await fs.promises.writeFile(this.getPath(), JSON.stringify(this.toObject(), null, 2));
|
|
223
|
-
return this.getContents();
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Write the config file with new contents. If no new contents are provided it will write the existing config
|
|
227
|
-
* contents that were set from {@link ConfigFile.read}, or an empty file if {@link ConfigFile.read} was not called.
|
|
228
|
-
*
|
|
229
|
-
* @param newContents The new contents of the file.
|
|
230
|
-
*/
|
|
231
|
-
writeSync(newContents) {
|
|
232
|
-
if ((0, ts_types_1.isPlainObject)(newContents)) {
|
|
233
|
-
this.setContents(newContents);
|
|
234
|
-
}
|
|
235
|
-
try {
|
|
236
|
-
fs.mkdirSync((0, path_1.dirname)(this.getPath()), { recursive: true });
|
|
237
|
-
}
|
|
238
|
-
catch (err) {
|
|
239
|
-
throw sfError_1.SfError.wrap(err);
|
|
240
|
-
}
|
|
241
|
-
this.logger.info(`Writing to config file: ${this.getPath()}`);
|
|
242
|
-
fs.writeFileSync(this.getPath(), JSON.stringify(this.toObject(), null, 2));
|
|
243
|
-
return this.getContents();
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Check to see if the config file exists. Returns `true` if the config file exists and has access, false otherwise.
|
|
247
|
-
*/
|
|
248
|
-
async exists() {
|
|
249
|
-
return this.access(fs_1.constants.R_OK);
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Check to see if the config file exists. Returns `true` if the config file exists and has access, false otherwise.
|
|
253
|
-
*/
|
|
254
|
-
existsSync() {
|
|
255
|
-
return this.accessSync(fs_1.constants.R_OK);
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Get the stats of the file. Returns the stats of the file.
|
|
259
|
-
*
|
|
260
|
-
* {@link fs.stat}
|
|
261
|
-
*/
|
|
262
|
-
async stat() {
|
|
263
|
-
return fs.promises.stat(this.getPath());
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Get the stats of the file. Returns the stats of the file.
|
|
267
|
-
*
|
|
268
|
-
* {@link fs.stat}
|
|
269
|
-
*/
|
|
270
|
-
statSync() {
|
|
271
|
-
return fs.statSync(this.getPath());
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Delete the config file if it exists.
|
|
275
|
-
*
|
|
276
|
-
* **Throws** *`Error`{ name: 'TargetFileNotFound' }* If the {@link ConfigFile.getFilename} file is not found.
|
|
277
|
-
* {@link fs.unlink}
|
|
278
|
-
*/
|
|
279
|
-
async unlink() {
|
|
280
|
-
const exists = await this.exists();
|
|
281
|
-
if (exists) {
|
|
282
|
-
return fs.promises.unlink(this.getPath());
|
|
283
|
-
}
|
|
284
|
-
throw new sfError_1.SfError(`Target file doesn't exist. path: ${this.getPath()}`, 'TargetFileNotFound');
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Delete the config file if it exists.
|
|
288
|
-
*
|
|
289
|
-
* **Throws** *`Error`{ name: 'TargetFileNotFound' }* If the {@link ConfigFile.getFilename} file is not found.
|
|
290
|
-
* {@link fs.unlink}
|
|
291
|
-
*/
|
|
292
|
-
unlinkSync() {
|
|
293
|
-
const exists = this.existsSync();
|
|
294
|
-
if (exists) {
|
|
295
|
-
return fs.unlinkSync(this.getPath());
|
|
296
|
-
}
|
|
297
|
-
throw new sfError_1.SfError(`Target file doesn't exist. path: ${this.getPath()}`, 'TargetFileNotFound');
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Returns the absolute path to the config file.
|
|
301
|
-
*
|
|
302
|
-
* The first time getPath is called, the path is resolved and becomes immutable. This allows implementers to
|
|
303
|
-
* override options properties, like filePath, on the init method for async creation. If that is required for
|
|
304
|
-
* creation, the config files can not be synchronously created.
|
|
305
|
-
*/
|
|
306
|
-
getPath() {
|
|
307
|
-
if (!this.path) {
|
|
308
|
-
if (!this.options.filename) {
|
|
309
|
-
throw new sfError_1.SfError('The ConfigOptions filename parameter is invalid.', 'InvalidParameter');
|
|
310
|
-
}
|
|
311
|
-
// Don't let users store config files in homedir without being in the state folder.
|
|
312
|
-
let configRootFolder = this.options.rootFolder
|
|
313
|
-
? this.options.rootFolder
|
|
314
|
-
: ConfigFile.resolveRootFolderSync(Boolean(this.options.isGlobal));
|
|
315
|
-
if (this.options.isGlobal === true || this.options.isState === true) {
|
|
316
|
-
configRootFolder = (0, path_1.join)(configRootFolder, this.options.stateFolder ?? global_1.Global.SFDX_STATE_FOLDER);
|
|
317
|
-
}
|
|
318
|
-
this.path = (0, path_1.join)(configRootFolder, this.options.filePath ? this.options.filePath : '', this.options.filename);
|
|
319
|
-
}
|
|
320
|
-
return this.path;
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* Returns `true` if this config is using the global path, `false` otherwise.
|
|
324
|
-
*/
|
|
325
|
-
isGlobal() {
|
|
326
|
-
return !!this.options.isGlobal;
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* Used to initialize asynchronous components.
|
|
330
|
-
*
|
|
331
|
-
* **Throws** *`Error`{ code: 'ENOENT' }* If the {@link ConfigFile.getFilename} file is not found when
|
|
332
|
-
* options.throwOnNotFound is true.
|
|
333
|
-
*/
|
|
334
|
-
async init() {
|
|
335
|
-
await super.init();
|
|
336
|
-
// Read the file, which also sets the path and throws any errors around project paths.
|
|
337
|
-
await this.read(this.options.throwOnNotFound);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
exports.ConfigFile = ConfigFile;
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2020, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ConfigFile = void 0;
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const fs_1 = require("fs");
|
|
12
|
+
const os_1 = require("os");
|
|
13
|
+
const path_1 = require("path");
|
|
14
|
+
const ts_types_1 = require("@salesforce/ts-types");
|
|
15
|
+
const kit_1 = require("@salesforce/kit");
|
|
16
|
+
const global_1 = require("../global");
|
|
17
|
+
const logger_1 = require("../logger");
|
|
18
|
+
const sfError_1 = require("../sfError");
|
|
19
|
+
const internal_1 = require("../util/internal");
|
|
20
|
+
const configStore_1 = require("./configStore");
|
|
21
|
+
/**
|
|
22
|
+
* Represents a json config file used to manage settings and state. Global config
|
|
23
|
+
* files are stored in the home directory hidden state folder (.sfdx) and local config
|
|
24
|
+
* files are stored in the project path, either in the hidden state folder or wherever
|
|
25
|
+
* specified.
|
|
26
|
+
*
|
|
27
|
+
* ```
|
|
28
|
+
* class MyConfig extends ConfigFile {
|
|
29
|
+
* public static getFileName(): string {
|
|
30
|
+
* return 'myConfigFilename.json';
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* const myConfig = await MyConfig.create({
|
|
34
|
+
* isGlobal: true
|
|
35
|
+
* });
|
|
36
|
+
* myConfig.set('mykey', 'myvalue');
|
|
37
|
+
* await myConfig.write();
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
class ConfigFile extends configStore_1.BaseConfigStore {
|
|
41
|
+
/**
|
|
42
|
+
* Create an instance of a config file without reading the file. Call `read` or `readSync`
|
|
43
|
+
* after creating the ConfigFile OR instantiate with {@link ConfigFile.create} instead.
|
|
44
|
+
*
|
|
45
|
+
* @param options The options for the class instance
|
|
46
|
+
* @ignore
|
|
47
|
+
*/
|
|
48
|
+
constructor(options) {
|
|
49
|
+
super(options);
|
|
50
|
+
// whether file contents have been read
|
|
51
|
+
this.hasRead = false;
|
|
52
|
+
this.logger = logger_1.Logger.childFromRoot(this.constructor.name);
|
|
53
|
+
const statics = this.constructor;
|
|
54
|
+
let defaultOptions = {};
|
|
55
|
+
try {
|
|
56
|
+
defaultOptions = statics.getDefaultOptions();
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
/* Some implementations don't let you call default options */
|
|
60
|
+
}
|
|
61
|
+
// Merge default and passed in options
|
|
62
|
+
this.options = Object.assign(defaultOptions, this.options);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns the config's filename.
|
|
66
|
+
*/
|
|
67
|
+
static getFileName() {
|
|
68
|
+
// Can not have abstract static methods, so throw a runtime error.
|
|
69
|
+
throw new sfError_1.SfError('Unknown filename for config file.');
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns the default options for the config file.
|
|
73
|
+
*
|
|
74
|
+
* @param isGlobal If the file should be stored globally or locally.
|
|
75
|
+
* @param filename The name of the config file.
|
|
76
|
+
*/
|
|
77
|
+
static getDefaultOptions(isGlobal = false, filename) {
|
|
78
|
+
return {
|
|
79
|
+
isGlobal,
|
|
80
|
+
isState: true,
|
|
81
|
+
filename: filename ?? this.getFileName(),
|
|
82
|
+
stateFolder: global_1.Global.SFDX_STATE_FOLDER,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Helper used to determine what the local and global folder point to. Returns the file path of the root folder.
|
|
87
|
+
*
|
|
88
|
+
* @param isGlobal True if the config should be global. False for local.
|
|
89
|
+
*/
|
|
90
|
+
static async resolveRootFolder(isGlobal) {
|
|
91
|
+
return isGlobal ? (0, os_1.homedir)() : (0, internal_1.resolveProjectPath)();
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Helper used to determine what the local and global folder point to. Returns the file path of the root folder.
|
|
95
|
+
*
|
|
96
|
+
* @param isGlobal True if the config should be global. False for local.
|
|
97
|
+
*/
|
|
98
|
+
static resolveRootFolderSync(isGlobal) {
|
|
99
|
+
return isGlobal ? (0, os_1.homedir)() : (0, internal_1.resolveProjectPathSync)();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Determines if the config file is read/write accessible. Returns `true` if the user has capabilities specified
|
|
103
|
+
* by perm.
|
|
104
|
+
*
|
|
105
|
+
* @param {number} perm The permission.
|
|
106
|
+
*
|
|
107
|
+
* **See** {@link https://nodejs.org/dist/latest/docs/api/fs.html#fs_fs_access_path_mode_callback}
|
|
108
|
+
*/
|
|
109
|
+
async access(perm) {
|
|
110
|
+
try {
|
|
111
|
+
await fs.promises.access(this.getPath(), perm);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Determines if the config file is read/write accessible. Returns `true` if the user has capabilities specified
|
|
120
|
+
* by perm.
|
|
121
|
+
*
|
|
122
|
+
* @param {number} perm The permission.
|
|
123
|
+
*
|
|
124
|
+
* **See** {@link https://nodejs.org/dist/latest/docs/api/fs.html#fs_fs_access_path_mode_callback}
|
|
125
|
+
*/
|
|
126
|
+
accessSync(perm) {
|
|
127
|
+
try {
|
|
128
|
+
fs.accessSync(this.getPath(), perm);
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Read the config file and set the config contents. Returns the config contents of the config file. As an
|
|
137
|
+
* optimization, files are only read once per process and updated in memory and via `write()`. To force
|
|
138
|
+
* a read from the filesystem pass `force=true`.
|
|
139
|
+
* **Throws** *{@link SfError}{ name: 'UnexpectedJsonFileFormat' }* There was a problem reading or parsing the file.
|
|
140
|
+
*
|
|
141
|
+
* @param [throwOnNotFound = false] Optionally indicate if a throw should occur on file read.
|
|
142
|
+
* @param [force = false] Optionally force the file to be read from disk even when already read within the process.
|
|
143
|
+
*/
|
|
144
|
+
async read(throwOnNotFound = false, force = false) {
|
|
145
|
+
try {
|
|
146
|
+
// Only need to read config files once. They are kept up to date
|
|
147
|
+
// internally and updated persistently via write().
|
|
148
|
+
if (!this.hasRead || force) {
|
|
149
|
+
this.logger.info(`Reading config file: ${this.getPath()}`);
|
|
150
|
+
const obj = (0, kit_1.parseJsonMap)(await fs.promises.readFile(this.getPath(), 'utf8'));
|
|
151
|
+
this.setContentsFromObject(obj);
|
|
152
|
+
}
|
|
153
|
+
return this.getContents();
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
if (err.code === 'ENOENT') {
|
|
157
|
+
if (!throwOnNotFound) {
|
|
158
|
+
this.setContents();
|
|
159
|
+
return this.getContents();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
throw err;
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
// Necessarily set this even when an error happens to avoid infinite re-reading.
|
|
166
|
+
// To attempt another read, pass `force=true`.
|
|
167
|
+
this.hasRead = true;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Read the config file and set the config contents. Returns the config contents of the config file. As an
|
|
172
|
+
* optimization, files are only read once per process and updated in memory and via `write()`. To force
|
|
173
|
+
* a read from the filesystem pass `force=true`.
|
|
174
|
+
* **Throws** *{@link SfError}{ name: 'UnexpectedJsonFileFormat' }* There was a problem reading or parsing the file.
|
|
175
|
+
*
|
|
176
|
+
* @param [throwOnNotFound = false] Optionally indicate if a throw should occur on file read.
|
|
177
|
+
* @param [force = false] Optionally force the file to be read from disk even when already read within the process.
|
|
178
|
+
*/
|
|
179
|
+
readSync(throwOnNotFound = false, force = false) {
|
|
180
|
+
try {
|
|
181
|
+
// Only need to read config files once. They are kept up to date
|
|
182
|
+
// internally and updated persistently via write().
|
|
183
|
+
if (!this.hasRead || force) {
|
|
184
|
+
this.logger.info(`Reading config file: ${this.getPath()}`);
|
|
185
|
+
const obj = (0, kit_1.parseJsonMap)(fs.readFileSync(this.getPath(), 'utf8'));
|
|
186
|
+
this.setContentsFromObject(obj);
|
|
187
|
+
}
|
|
188
|
+
return this.getContents();
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
if (err.code === 'ENOENT') {
|
|
192
|
+
if (!throwOnNotFound) {
|
|
193
|
+
this.setContents();
|
|
194
|
+
return this.getContents();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
throw err;
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
// Necessarily set this even when an error happens to avoid infinite re-reading.
|
|
201
|
+
// To attempt another read, pass `force=true`.
|
|
202
|
+
this.hasRead = true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Write the config file with new contents. If no new contents are provided it will write the existing config
|
|
207
|
+
* contents that were set from {@link ConfigFile.read}, or an empty file if {@link ConfigFile.read} was not called.
|
|
208
|
+
*
|
|
209
|
+
* @param newContents The new contents of the file.
|
|
210
|
+
*/
|
|
211
|
+
async write(newContents) {
|
|
212
|
+
if (newContents) {
|
|
213
|
+
this.setContents(newContents);
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
await fs.promises.mkdir((0, path_1.dirname)(this.getPath()), { recursive: true });
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
throw sfError_1.SfError.wrap(err);
|
|
220
|
+
}
|
|
221
|
+
this.logger.info(`Writing to config file: ${this.getPath()}`);
|
|
222
|
+
await fs.promises.writeFile(this.getPath(), JSON.stringify(this.toObject(), null, 2));
|
|
223
|
+
return this.getContents();
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Write the config file with new contents. If no new contents are provided it will write the existing config
|
|
227
|
+
* contents that were set from {@link ConfigFile.read}, or an empty file if {@link ConfigFile.read} was not called.
|
|
228
|
+
*
|
|
229
|
+
* @param newContents The new contents of the file.
|
|
230
|
+
*/
|
|
231
|
+
writeSync(newContents) {
|
|
232
|
+
if ((0, ts_types_1.isPlainObject)(newContents)) {
|
|
233
|
+
this.setContents(newContents);
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
fs.mkdirSync((0, path_1.dirname)(this.getPath()), { recursive: true });
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
throw sfError_1.SfError.wrap(err);
|
|
240
|
+
}
|
|
241
|
+
this.logger.info(`Writing to config file: ${this.getPath()}`);
|
|
242
|
+
fs.writeFileSync(this.getPath(), JSON.stringify(this.toObject(), null, 2));
|
|
243
|
+
return this.getContents();
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Check to see if the config file exists. Returns `true` if the config file exists and has access, false otherwise.
|
|
247
|
+
*/
|
|
248
|
+
async exists() {
|
|
249
|
+
return this.access(fs_1.constants.R_OK);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Check to see if the config file exists. Returns `true` if the config file exists and has access, false otherwise.
|
|
253
|
+
*/
|
|
254
|
+
existsSync() {
|
|
255
|
+
return this.accessSync(fs_1.constants.R_OK);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Get the stats of the file. Returns the stats of the file.
|
|
259
|
+
*
|
|
260
|
+
* {@link fs.stat}
|
|
261
|
+
*/
|
|
262
|
+
async stat() {
|
|
263
|
+
return fs.promises.stat(this.getPath());
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Get the stats of the file. Returns the stats of the file.
|
|
267
|
+
*
|
|
268
|
+
* {@link fs.stat}
|
|
269
|
+
*/
|
|
270
|
+
statSync() {
|
|
271
|
+
return fs.statSync(this.getPath());
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Delete the config file if it exists.
|
|
275
|
+
*
|
|
276
|
+
* **Throws** *`Error`{ name: 'TargetFileNotFound' }* If the {@link ConfigFile.getFilename} file is not found.
|
|
277
|
+
* {@link fs.unlink}
|
|
278
|
+
*/
|
|
279
|
+
async unlink() {
|
|
280
|
+
const exists = await this.exists();
|
|
281
|
+
if (exists) {
|
|
282
|
+
return fs.promises.unlink(this.getPath());
|
|
283
|
+
}
|
|
284
|
+
throw new sfError_1.SfError(`Target file doesn't exist. path: ${this.getPath()}`, 'TargetFileNotFound');
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Delete the config file if it exists.
|
|
288
|
+
*
|
|
289
|
+
* **Throws** *`Error`{ name: 'TargetFileNotFound' }* If the {@link ConfigFile.getFilename} file is not found.
|
|
290
|
+
* {@link fs.unlink}
|
|
291
|
+
*/
|
|
292
|
+
unlinkSync() {
|
|
293
|
+
const exists = this.existsSync();
|
|
294
|
+
if (exists) {
|
|
295
|
+
return fs.unlinkSync(this.getPath());
|
|
296
|
+
}
|
|
297
|
+
throw new sfError_1.SfError(`Target file doesn't exist. path: ${this.getPath()}`, 'TargetFileNotFound');
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Returns the absolute path to the config file.
|
|
301
|
+
*
|
|
302
|
+
* The first time getPath is called, the path is resolved and becomes immutable. This allows implementers to
|
|
303
|
+
* override options properties, like filePath, on the init method for async creation. If that is required for
|
|
304
|
+
* creation, the config files can not be synchronously created.
|
|
305
|
+
*/
|
|
306
|
+
getPath() {
|
|
307
|
+
if (!this.path) {
|
|
308
|
+
if (!this.options.filename) {
|
|
309
|
+
throw new sfError_1.SfError('The ConfigOptions filename parameter is invalid.', 'InvalidParameter');
|
|
310
|
+
}
|
|
311
|
+
// Don't let users store config files in homedir without being in the state folder.
|
|
312
|
+
let configRootFolder = this.options.rootFolder
|
|
313
|
+
? this.options.rootFolder
|
|
314
|
+
: ConfigFile.resolveRootFolderSync(Boolean(this.options.isGlobal));
|
|
315
|
+
if (this.options.isGlobal === true || this.options.isState === true) {
|
|
316
|
+
configRootFolder = (0, path_1.join)(configRootFolder, this.options.stateFolder ?? global_1.Global.SFDX_STATE_FOLDER);
|
|
317
|
+
}
|
|
318
|
+
this.path = (0, path_1.join)(configRootFolder, this.options.filePath ? this.options.filePath : '', this.options.filename);
|
|
319
|
+
}
|
|
320
|
+
return this.path;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Returns `true` if this config is using the global path, `false` otherwise.
|
|
324
|
+
*/
|
|
325
|
+
isGlobal() {
|
|
326
|
+
return !!this.options.isGlobal;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Used to initialize asynchronous components.
|
|
330
|
+
*
|
|
331
|
+
* **Throws** *`Error`{ code: 'ENOENT' }* If the {@link ConfigFile.getFilename} file is not found when
|
|
332
|
+
* options.throwOnNotFound is true.
|
|
333
|
+
*/
|
|
334
|
+
async init() {
|
|
335
|
+
await super.init();
|
|
336
|
+
// Read the file, which also sets the path and throws any errors around project paths.
|
|
337
|
+
await this.read(this.options.throwOnNotFound);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
exports.ConfigFile = ConfigFile;
|
|
341
341
|
//# sourceMappingURL=configFile.js.map
|