UNPKG

14.1 kBJavaScriptView Raw
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 */
8Object.defineProperty(exports, "__esModule", { value: true });
9exports.Config = void 0;
10const kit_1 = require("@salesforce/kit");
11const ts_types_1 = require("@salesforce/ts-types");
12const logger_1 = require("../logger");
13const crypto_1 = require("../crypto");
14const messages_1 = require("../messages");
15const sfdxError_1 = require("../sfdxError");
16const sfdc_1 = require("../util/sfdc");
17const sfdcUrl_1 = require("../util/sfdcUrl");
18const configFile_1 = require("./configFile");
19const SFDX_CONFIG_FILE_NAME = 'sfdx-config.json';
20/**
21 * The files where sfdx config values are stored for projects and the global space.
22 *
23 * *Note:* It is not recommended to instantiate this object directly when resolving
24 * config values. Instead use {@link ConfigAggregator}
25 *
26 * ```
27 * const localConfig = await Config.create({});
28 * localConfig.set('defaultusername', 'username@company.org');
29 * await localConfig.write();
30 * ```
31 * https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_cli_config_values.htm
32 */
33class Config extends configFile_1.ConfigFile {
34 constructor(options) {
35 super(options || Config.getDefaultOptions(false));
36 if (!Config.messages) {
37 Config.messages = messages_1.Messages.loadMessages('@salesforce/core', 'config');
38 }
39 // Resolve the config path on creation.
40 this.getPath();
41 }
42 static get propertyConfigMap() {
43 return kit_1.keyBy(Config.allowedProperties, 'key');
44 }
45 /**
46 * Returns the default file name for a config file.
47 *
48 * **See** {@link SFDX_CONFIG_FILE_NAME}
49 */
50 static getFileName() {
51 return SFDX_CONFIG_FILE_NAME;
52 }
53 /**
54 * Returns an array of objects representing the allowed config properties.
55 */
56 static getAllowedProperties() {
57 return Config.allowedProperties;
58 }
59 /**
60 * Add an array of allowed config properties.
61 *
62 * @param metas Array of objects to set as the allowed config properties.
63 */
64 static addAllowedProperties(metas) {
65 const currentMetaKeys = Object.keys(Config.propertyConfigMap);
66 // If logger is needed elsewhere in this file, do not move this outside of the Config class.
67 // It was causing issues with Bunyan log rotation. See https://github.com/forcedotcom/sfdx-core/pull/562
68 const logger = logger_1.Logger.childFromRoot('core:config');
69 metas.forEach((meta) => {
70 if (currentMetaKeys.includes(meta.key)) {
71 logger.info(`Key ${meta.key} already exists in allowedProperties, skipping.`);
72 return;
73 }
74 Config.allowedProperties.push(meta);
75 });
76 }
77 /**
78 * Gets default options.
79 *
80 * @param isGlobal Make the config global.
81 * @param filename Override the default file. {@link Config.getFileName}
82 */
83 static getDefaultOptions(isGlobal = false, filename) {
84 return {
85 isGlobal,
86 isState: true,
87 filename: filename || this.getFileName(),
88 };
89 }
90 /**
91 * The value of a supported config property.
92 *
93 * @param isGlobal True for a global config. False for a local config.
94 * @param propertyName The name of the property to set.
95 * @param value The property value.
96 */
97 static async update(isGlobal, propertyName, value) {
98 const config = await Config.create(Config.getDefaultOptions(isGlobal));
99 const content = await config.read();
100 if (value == null) {
101 delete content[propertyName];
102 }
103 else {
104 kit_1.set(content, propertyName, value);
105 }
106 return config.write(content);
107 }
108 /**
109 * Clear all the configured properties both local and global.
110 */
111 static async clear() {
112 let config = await Config.create(Config.getDefaultOptions(true));
113 config.clear();
114 await config.write();
115 config = await Config.create(Config.getDefaultOptions(false));
116 config.clear();
117 await config.write();
118 }
119 /**
120 * Read, assign, and return the config contents.
121 */
122 async read(force = true) {
123 try {
124 await super.read(false, force);
125 await this.cryptProperties(false);
126 return this.getContents();
127 }
128 finally {
129 await this.clearCrypto();
130 }
131 }
132 /**
133 * Writes Config properties taking into account encrypted properties.
134 *
135 * @param newContents The new Config value to persist.
136 */
137 async write(newContents) {
138 if (newContents != null) {
139 this.setContents(newContents);
140 }
141 await this.cryptProperties(true);
142 await super.write();
143 await this.cryptProperties(false);
144 return this.getContents();
145 }
146 /**
147 * DO NOT CALL - The config file needs to encrypt values which can only be done asynchronously.
148 * Call {@link SfdxConfig.write} instead.
149 *
150 * **Throws** *{@link SfdxError}{ name: 'InvalidWrite' }* Always.
151 *
152 * @param newContents Contents to write
153 */
154 // eslint-disable-next-line @typescript-eslint/no-unused-vars
155 writeSync(newContents) {
156 throw sfdxError_1.SfdxError.create('@salesforce/core', 'config', 'InvalidWrite');
157 }
158 /**
159 * Sets a value for a property.
160 *
161 * **Throws** *{@link SfdxError}{ name: 'InvalidConfigValue' }* If the input validator fails.
162 *
163 * @param key The property to set.
164 * @param value The value of the property.
165 */
166 set(key, value) {
167 var _a;
168 const property = Config.allowedProperties.find((allowedProp) => allowedProp.key === key);
169 if (!property) {
170 throw sfdxError_1.SfdxError.create('@salesforce/core', 'config', 'UnknownConfigKey', [key]);
171 }
172 if (property.input) {
173 if (property.input && property.input.validator(value)) {
174 super.set(property.key, value);
175 }
176 else {
177 throw sfdxError_1.SfdxError.create('@salesforce/core', 'config', 'InvalidConfigValue', [
178 (_a = property.input.failedMessage) !== null && _a !== void 0 ? _a : '',
179 ]);
180 }
181 }
182 else {
183 super.set(property.key, value);
184 }
185 return this.getContents();
186 }
187 /**
188 * Unsets a value for a property.
189 *
190 * **Throws** *{@link SfdxError}{ name: 'UnknownConfigKey' }* If the input validator fails.
191 *
192 * @param key The property to unset.
193 */
194 unset(key) {
195 const property = Config.allowedProperties.find((allowedProp) => allowedProp.key === key);
196 if (!property) {
197 throw sfdxError_1.SfdxError.create('@salesforce/core', 'config', 'UnknownConfigKey', [key]);
198 }
199 return super.unset(property.key);
200 }
201 /**
202 * Initializer for supported config types.
203 */
204 async init() {
205 // Super ConfigFile calls read, which has a dependency on crypto, which finally has a dependency on
206 // Config.propertyConfigMap being set. This is why init is called after the setup.
207 await super.init();
208 }
209 /**
210 * Initialize the crypto dependency.
211 */
212 async initCrypto() {
213 if (!this.crypto) {
214 this.crypto = await crypto_1.Crypto.create();
215 }
216 }
217 /**
218 * Closes the crypto dependency. Crypto should be close after it's used and no longer needed.
219 */
220 // eslint-disable-next-line @typescript-eslint/require-await
221 async clearCrypto() {
222 if (this.crypto) {
223 this.crypto.close();
224 delete this.crypto;
225 }
226 }
227 /**
228 * Get an individual property config.
229 *
230 * @param propertyName The name of the property.
231 */
232 getPropertyConfig(propertyName) {
233 const prop = Config.propertyConfigMap[propertyName];
234 if (!prop) {
235 throw sfdxError_1.SfdxError.create('@salesforce/core', 'config', 'UnknownConfigKey', [propertyName]);
236 }
237 return prop;
238 }
239 /**
240 * Encrypts and content properties that have a encryption attribute.
241 *
242 * @param encrypt `true` to encrypt.
243 */
244 async cryptProperties(encrypt) {
245 const hasEncryptedProperties = this.entries().some(([key]) => {
246 var _a;
247 return !!((_a = Config.propertyConfigMap[key]) === null || _a === void 0 ? void 0 : _a.encrypted);
248 });
249 if (hasEncryptedProperties) {
250 await this.initCrypto();
251 const crypto = ts_types_1.ensure(this.crypto);
252 this.forEach((key, value) => {
253 if (this.getPropertyConfig(key).encrypted && ts_types_1.isString(value)) {
254 this.set(key, ts_types_1.ensure(encrypt ? crypto.encrypt(value) : crypto.decrypt(value)));
255 }
256 });
257 }
258 }
259}
260exports.Config = Config;
261/**
262 * Username associated with the default dev hub org.
263 *
264 * @deprecated Replaced by OrgConfigProperties.TARGET_DEV_HUB in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config}
265 */
266Config.DEFAULT_DEV_HUB_USERNAME = 'defaultdevhubusername';
267/**
268 * Username associate with the default org.
269 *
270 * @deprecated Replaced by OrgConfigProperties.TARGET_ORG in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config}
271 */
272Config.DEFAULT_USERNAME = 'defaultusername';
273/**
274 * The sid for the debugger configuration.
275 */
276Config.ISV_DEBUGGER_SID = 'isvDebuggerSid';
277/**
278 * The url for the debugger configuration.
279 */
280Config.ISV_DEBUGGER_URL = 'isvDebuggerUrl';
281/**
282 * The api version
283 */
284Config.API_VERSION = 'apiVersion';
285/**
286 * Disables telemetry reporting
287 */
288Config.DISABLE_TELEMETRY = 'disableTelemetry';
289/**
290 * Custom templates repo or local location.
291 */
292Config.CUSTOM_ORG_METADATA_TEMPLATES = 'customOrgMetadataTemplates';
293/**
294 * allows users to override the 10,000 result query limit
295 */
296Config.MAX_QUERY_LIMIT = 'maxQueryLimit';
297Config.allowedProperties = [
298 {
299 key: 'instanceUrl',
300 input: {
301 // If a value is provided validate it otherwise no value is unset.
302 validator: (value) => value == null || (ts_types_1.isString(value) && new sfdcUrl_1.SfdcUrl(value).isSalesforceDomain()),
303 get failedMessage() {
304 var _a;
305 return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidInstanceUrl');
306 },
307 },
308 },
309 {
310 key: Config.API_VERSION,
311 hidden: true,
312 input: {
313 // If a value is provided validate it otherwise no value is unset.
314 validator: (value) => value == null || (ts_types_1.isString(value) && sfdc_1.sfdc.validateApiVersion(value)),
315 get failedMessage() {
316 var _a;
317 return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidApiVersion');
318 },
319 },
320 },
321 {
322 key: Config.CUSTOM_ORG_METADATA_TEMPLATES,
323 input: {
324 // If a value is provided validate it otherwise no value is unset.
325 validator: (value) => value == null || ts_types_1.isString(value),
326 get failedMessage() {
327 var _a;
328 return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidCustomOrgMetadataTemplates');
329 },
330 },
331 },
332 { key: Config.DEFAULT_DEV_HUB_USERNAME },
333 { key: Config.DEFAULT_USERNAME },
334 {
335 key: Config.ISV_DEBUGGER_SID,
336 encrypted: true,
337 input: {
338 // If a value is provided validate it otherwise no value is unset.
339 validator: (value) => value == null || ts_types_1.isString(value),
340 get failedMessage() {
341 var _a;
342 return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidIsvDebuggerSid');
343 },
344 },
345 },
346 {
347 key: Config.ISV_DEBUGGER_URL,
348 input: {
349 // If a value is provided validate it otherwise no value is unset.
350 validator: (value) => value == null || ts_types_1.isString(value),
351 get failedMessage() {
352 var _a;
353 return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidIsvDebuggerUrl');
354 },
355 },
356 },
357 {
358 key: Config.DISABLE_TELEMETRY,
359 input: {
360 validator: (value) => value == null || ['true', 'false'].includes(value.toString()),
361 get failedMessage() {
362 var _a;
363 return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidBooleanConfigValue');
364 },
365 },
366 },
367 // This should be brought in by a plugin, but there isn't a way to do that right now.
368 {
369 key: 'restDeploy',
370 hidden: true,
371 input: {
372 validator: (value) => value != null && ['true', 'false'].includes(value.toString()),
373 get failedMessage() {
374 var _a;
375 return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidBooleanConfigValue');
376 },
377 },
378 },
379 {
380 key: Config.MAX_QUERY_LIMIT,
381 input: {
382 // the bit shift will remove the negative bit, and any decimal numbers
383 // then the parseFloat will handle converting it to a number from a string
384 validator: (value) => value >>> 0 === parseFloat(value) && value > 0,
385 get failedMessage() {
386 var _a;
387 return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidNumberConfigValue');
388 },
389 },
390 },
391];
392//# sourceMappingURL=config.js.map
\No newline at end of file