UNPKG

@salesforce/core

Version:

Core libraries to interact with SFDX projects, orgs, and APIs.

392 lines 14.1 kB
"use strict"; /* * Copyright (c) 2020, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Config = void 0; const kit_1 = require("@salesforce/kit"); const ts_types_1 = require("@salesforce/ts-types"); const logger_1 = require("../logger"); const crypto_1 = require("../crypto"); const messages_1 = require("../messages"); const sfdxError_1 = require("../sfdxError"); const sfdc_1 = require("../util/sfdc"); const sfdcUrl_1 = require("../util/sfdcUrl"); const configFile_1 = require("./configFile"); const SFDX_CONFIG_FILE_NAME = 'sfdx-config.json'; /** * The files where sfdx config values are stored for projects and the global space. * * *Note:* It is not recommended to instantiate this object directly when resolving * config values. Instead use {@link ConfigAggregator} * * ``` * const localConfig = await Config.create({}); * localConfig.set('defaultusername', 'username@company.org'); * await localConfig.write(); * ``` * https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_cli_config_values.htm */ class Config extends configFile_1.ConfigFile { constructor(options) { super(options || Config.getDefaultOptions(false)); if (!Config.messages) { Config.messages = messages_1.Messages.loadMessages('@salesforce/core', 'config'); } // Resolve the config path on creation. this.getPath(); } static get propertyConfigMap() { return kit_1.keyBy(Config.allowedProperties, 'key'); } /** * Returns the default file name for a config file. * * **See** {@link SFDX_CONFIG_FILE_NAME} */ static getFileName() { return SFDX_CONFIG_FILE_NAME; } /** * Returns an array of objects representing the allowed config properties. */ static getAllowedProperties() { return Config.allowedProperties; } /** * Add an array of allowed config properties. * * @param metas Array of objects to set as the allowed config properties. */ static addAllowedProperties(metas) { const currentMetaKeys = Object.keys(Config.propertyConfigMap); // If logger is needed elsewhere in this file, do not move this outside of the Config class. // It was causing issues with Bunyan log rotation. See https://github.com/forcedotcom/sfdx-core/pull/562 const logger = logger_1.Logger.childFromRoot('core:config'); metas.forEach((meta) => { if (currentMetaKeys.includes(meta.key)) { logger.info(`Key ${meta.key} already exists in allowedProperties, skipping.`); return; } Config.allowedProperties.push(meta); }); } /** * Gets default options. * * @param isGlobal Make the config global. * @param filename Override the default file. {@link Config.getFileName} */ static getDefaultOptions(isGlobal = false, filename) { return { isGlobal, isState: true, filename: filename || this.getFileName(), }; } /** * The value of a supported config property. * * @param isGlobal True for a global config. False for a local config. * @param propertyName The name of the property to set. * @param value The property value. */ static async update(isGlobal, propertyName, value) { const config = await Config.create(Config.getDefaultOptions(isGlobal)); const content = await config.read(); if (value == null) { delete content[propertyName]; } else { kit_1.set(content, propertyName, value); } return config.write(content); } /** * Clear all the configured properties both local and global. */ static async clear() { let config = await Config.create(Config.getDefaultOptions(true)); config.clear(); await config.write(); config = await Config.create(Config.getDefaultOptions(false)); config.clear(); await config.write(); } /** * Read, assign, and return the config contents. */ async read(force = true) { try { await super.read(false, force); await this.cryptProperties(false); return this.getContents(); } finally { await this.clearCrypto(); } } /** * Writes Config properties taking into account encrypted properties. * * @param newContents The new Config value to persist. */ async write(newContents) { if (newContents != null) { this.setContents(newContents); } await this.cryptProperties(true); await super.write(); await this.cryptProperties(false); return this.getContents(); } /** * DO NOT CALL - The config file needs to encrypt values which can only be done asynchronously. * Call {@link SfdxConfig.write} instead. * * **Throws** *{@link SfdxError}{ name: 'InvalidWrite' }* Always. * * @param newContents Contents to write */ // eslint-disable-next-line @typescript-eslint/no-unused-vars writeSync(newContents) { throw sfdxError_1.SfdxError.create('@salesforce/core', 'config', 'InvalidWrite'); } /** * Sets a value for a property. * * **Throws** *{@link SfdxError}{ name: 'InvalidConfigValue' }* If the input validator fails. * * @param key The property to set. * @param value The value of the property. */ set(key, value) { var _a; const property = Config.allowedProperties.find((allowedProp) => allowedProp.key === key); if (!property) { throw sfdxError_1.SfdxError.create('@salesforce/core', 'config', 'UnknownConfigKey', [key]); } if (property.input) { if (property.input && property.input.validator(value)) { super.set(property.key, value); } else { throw sfdxError_1.SfdxError.create('@salesforce/core', 'config', 'InvalidConfigValue', [ (_a = property.input.failedMessage) !== null && _a !== void 0 ? _a : '', ]); } } else { super.set(property.key, value); } return this.getContents(); } /** * Unsets a value for a property. * * **Throws** *{@link SfdxError}{ name: 'UnknownConfigKey' }* If the input validator fails. * * @param key The property to unset. */ unset(key) { const property = Config.allowedProperties.find((allowedProp) => allowedProp.key === key); if (!property) { throw sfdxError_1.SfdxError.create('@salesforce/core', 'config', 'UnknownConfigKey', [key]); } return super.unset(property.key); } /** * Initializer for supported config types. */ async init() { // Super ConfigFile calls read, which has a dependency on crypto, which finally has a dependency on // Config.propertyConfigMap being set. This is why init is called after the setup. await super.init(); } /** * Initialize the crypto dependency. */ async initCrypto() { if (!this.crypto) { this.crypto = await crypto_1.Crypto.create(); } } /** * Closes the crypto dependency. Crypto should be close after it's used and no longer needed. */ // eslint-disable-next-line @typescript-eslint/require-await async clearCrypto() { if (this.crypto) { this.crypto.close(); delete this.crypto; } } /** * Get an individual property config. * * @param propertyName The name of the property. */ getPropertyConfig(propertyName) { const prop = Config.propertyConfigMap[propertyName]; if (!prop) { throw sfdxError_1.SfdxError.create('@salesforce/core', 'config', 'UnknownConfigKey', [propertyName]); } return prop; } /** * Encrypts and content properties that have a encryption attribute. * * @param encrypt `true` to encrypt. */ async cryptProperties(encrypt) { const hasEncryptedProperties = this.entries().some(([key]) => { var _a; return !!((_a = Config.propertyConfigMap[key]) === null || _a === void 0 ? void 0 : _a.encrypted); }); if (hasEncryptedProperties) { await this.initCrypto(); const crypto = ts_types_1.ensure(this.crypto); this.forEach((key, value) => { if (this.getPropertyConfig(key).encrypted && ts_types_1.isString(value)) { this.set(key, ts_types_1.ensure(encrypt ? crypto.encrypt(value) : crypto.decrypt(value))); } }); } } } exports.Config = Config; /** * Username associated with the default dev hub org. * * @deprecated Replaced by OrgConfigProperties.TARGET_DEV_HUB in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config} */ Config.DEFAULT_DEV_HUB_USERNAME = 'defaultdevhubusername'; /** * Username associate with the default org. * * @deprecated Replaced by OrgConfigProperties.TARGET_ORG in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config} */ Config.DEFAULT_USERNAME = 'defaultusername'; /** * The sid for the debugger configuration. */ Config.ISV_DEBUGGER_SID = 'isvDebuggerSid'; /** * The url for the debugger configuration. */ Config.ISV_DEBUGGER_URL = 'isvDebuggerUrl'; /** * The api version */ Config.API_VERSION = 'apiVersion'; /** * Disables telemetry reporting */ Config.DISABLE_TELEMETRY = 'disableTelemetry'; /** * Custom templates repo or local location. */ Config.CUSTOM_ORG_METADATA_TEMPLATES = 'customOrgMetadataTemplates'; /** * allows users to override the 10,000 result query limit */ Config.MAX_QUERY_LIMIT = 'maxQueryLimit'; Config.allowedProperties = [ { key: 'instanceUrl', input: { // If a value is provided validate it otherwise no value is unset. validator: (value) => value == null || (ts_types_1.isString(value) && new sfdcUrl_1.SfdcUrl(value).isSalesforceDomain()), get failedMessage() { var _a; return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidInstanceUrl'); }, }, }, { key: Config.API_VERSION, hidden: true, input: { // If a value is provided validate it otherwise no value is unset. validator: (value) => value == null || (ts_types_1.isString(value) && sfdc_1.sfdc.validateApiVersion(value)), get failedMessage() { var _a; return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidApiVersion'); }, }, }, { key: Config.CUSTOM_ORG_METADATA_TEMPLATES, input: { // If a value is provided validate it otherwise no value is unset. validator: (value) => value == null || ts_types_1.isString(value), get failedMessage() { var _a; return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidCustomOrgMetadataTemplates'); }, }, }, { key: Config.DEFAULT_DEV_HUB_USERNAME }, { key: Config.DEFAULT_USERNAME }, { key: Config.ISV_DEBUGGER_SID, encrypted: true, input: { // If a value is provided validate it otherwise no value is unset. validator: (value) => value == null || ts_types_1.isString(value), get failedMessage() { var _a; return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidIsvDebuggerSid'); }, }, }, { key: Config.ISV_DEBUGGER_URL, input: { // If a value is provided validate it otherwise no value is unset. validator: (value) => value == null || ts_types_1.isString(value), get failedMessage() { var _a; return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidIsvDebuggerUrl'); }, }, }, { key: Config.DISABLE_TELEMETRY, input: { validator: (value) => value == null || ['true', 'false'].includes(value.toString()), get failedMessage() { var _a; return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidBooleanConfigValue'); }, }, }, // This should be brought in by a plugin, but there isn't a way to do that right now. { key: 'restDeploy', hidden: true, input: { validator: (value) => value != null && ['true', 'false'].includes(value.toString()), get failedMessage() { var _a; return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidBooleanConfigValue'); }, }, }, { key: Config.MAX_QUERY_LIMIT, input: { // the bit shift will remove the negative bit, and any decimal numbers // then the parseFloat will handle converting it to a number from a string validator: (value) => value >>> 0 === parseFloat(value) && value > 0, get failedMessage() { var _a; return (_a = Config.messages) === null || _a === void 0 ? void 0 : _a.getMessage('InvalidNumberConfigValue'); }, }, }, ]; //# sourceMappingURL=config.js.map