UNPKG

@salesforce/core

Version:

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

561 lines 28.4 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 */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Config = exports.SfProperty = exports.SFDX_ALLOWED_PROPERTIES = exports.SfdxPropertyKeys = exports.SF_ALLOWED_PROPERTIES = exports.SfConfigProperties = void 0; const node_path_1 = require("node:path"); const fs = __importStar(require("node:fs")); const kit_1 = require("@salesforce/kit"); const ts_types_1 = require("@salesforce/ts-types"); const global_1 = require("../global"); const logger_1 = require("../logger/logger"); const messages_1 = require("../messages"); const sfdc_1 = require("../util/sfdc"); const sfdcUrl_1 = require("../util/sfdcUrl"); const orgConfigProperties_1 = require("../org/orgConfigProperties"); const lifecycleEvents_1 = require("../lifecycleEvents"); const configFile_1 = require("./configFile"); const lwwMap_1 = require("./lwwMap"); ; const messages = new messages_1.Messages('@salesforce/core', 'config', new Map([["unknownConfigKey", "Unknown config name: %s."], ["deprecatedConfigKey", "Deprecated config name: %s. Please use %s instead."], ["invalidWrite", "The writeSync method is not allowed on SfdxConfig. Use the async write method instead."], ["invalidConfigValue", "Invalid config value: %s."], ["invalidInstanceUrl", "Specify a valid Salesforce instance URL."], ["invalidApiVersion", "Specify a valid Salesforce API version, for example, 42.0."], ["invalidCustomOrgMetadataTemplates", "Specify a valid repository URL or directory for the custom org metadata templates."], ["invalidIsvDebuggerSid", "Specify a valid Debugger SID."], ["invalidIsvDebuggerUrl", "Specify a valid Debugger URL."], ["invalidNumberConfigValue", "Specify a valid positive integer, for example, 150000."], ["invalidBooleanConfigValue", "The config value can only be set to true or false."], ["invalidProjectWorkspace", "This directory does not contain a valid Salesforce DX project."], ["schemaValidationError", "The config file \"%s\" is not schema valid.\nDue to: %s"], ["schemaValidationError.actions", ["Fix the invalid entries at %s."]], ["missingDefaultPath", "In sfdx-project.json, be sure to specify which package directory (path) is the default. Example: `[{ \"path\": \"packageDirectory1\", \"default\": true }, { \"path\": \"packageDirectory2\" }]`"], ["missingPackageDirectory", "The path \"%s\", specified in sfdx-project.json, does not exist. Be sure this directory is included in your project root."], ["invalidPackageDirectory", "The path \"%s\", specified in sfdx-project.json, must be indicated as a relative path to the project root."], ["multipleDefaultPaths", "In sfdx-project.json, indicate only one package directory (path) as the default."], ["singleNonDefaultPackage", "The sfdx-project.json file must include one, and only one, default package directory (path). Because your sfdx-project.json file contains only one package directory, it must be the default. Remove the `\"default\": false` key and try again."], ["target-org", "Username or alias of the org that all commands run against by default. (sf only)"], ["target-dev-hub", "Username or alias of your default Dev Hub org. (sf only)"], ["defaultUsername", "Username or alias of the org that all commands run against by default. (sfdx only)"], ["defaultDevHubUsername", "Username or alias of your default Dev Hub org. (sfdx only)"], ["isvDebuggerSid", "ISV debugger SID (sfdx only)"], ["isvDebuggerUrl", "ISV debugger URL (sfdx only)"], ["org-isv-debugger-sid", "ISV debugger SID."], ["org-isv-debugger-url", "ISV debugger URL."], ["apiVersion", "API version of your project. Default: API version of your Dev Hub org. (sfdx only)"], ["org-api-version", "API version of your project. Default: API version of your Dev Hub org."], ["disableTelemetry", "Disables the collection of usage and user environment information, etc. Default: false. (sfdx only)"], ["disable-telemetry", "Disables the collection of usage and user environment information, etc. Default: false."], ["maxQueryLimit", "Maximum number of Salesforce records returned by a CLI command. Default: 10,000. (sfdx only)"], ["org-max-query-limit", "Maximum number of Salesforce records returned by a CLI command. Default: 10,000."], ["restDeploy", "Whether deployments use the Metadata REST API (true) or SOAP API (false, default value). (sfdx only)"], ["instanceUrl", "URL of the Salesforce instance hosting your org. Default: https://login.salesforce.com. (sfdx only)"], ["org-instance-url", "URL of the Salesforce instance hosting your org. Default: https://login.salesforce.com."], ["customOrgMetadataTemplates", "A valid repository URL or directory for the custom org metadata templates."], ["org-custom-metadata-templates", "A valid repository URL or directory for the custom org metadata templates."], ["org-capitalize-record-types", "Whether record types are capitalized on scratch org creation."], ["invalidId", "The given id %s is not a valid 15 or 18 character Salesforce ID."]])); const SFDX_CONFIG_FILE_NAME = 'sfdx-config.json'; const CONFIG_FILE_NAME = 'config.json'; var SfConfigProperties; (function (SfConfigProperties) { /** * Disables telemetry reporting */ SfConfigProperties["DISABLE_TELEMETRY"] = "disable-telemetry"; })(SfConfigProperties || (exports.SfConfigProperties = SfConfigProperties = {})); exports.SF_ALLOWED_PROPERTIES = [ { key: SfConfigProperties.DISABLE_TELEMETRY, description: messages.getMessage(SfConfigProperties.DISABLE_TELEMETRY), input: { validator: (value) => value == null || isBooleanOrBooleanString(value), failedMessage: messages.getMessage('invalidBooleanConfigValue'), }, }, ]; var SfdxPropertyKeys; (function (SfdxPropertyKeys) { /** * 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} * will remain in v3 for the foreseeable future so that `sfdx-core` can map between `sf` and `sfdx` config values */ SfdxPropertyKeys["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} * will remain in v3 for the foreseeable future so that `sfdx-core` can map between `sf` and `sfdx` config values */ SfdxPropertyKeys["DEFAULT_USERNAME"] = "defaultusername"; /** * The sid for the debugger configuration. * * @deprecated Replaced by OrgConfigProperties.ORG_ISV_DEBUGGER_SID in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config} */ SfdxPropertyKeys["ISV_DEBUGGER_SID"] = "isvDebuggerSid"; /** * The url for the debugger configuration. * * @deprecated Replaced by OrgConfigProperties.ORG_ISV_DEBUGGER_URL in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config} */ SfdxPropertyKeys["ISV_DEBUGGER_URL"] = "isvDebuggerUrl"; /** * The api version * * @deprecated Replaced by OrgConfigProperties.ORG_API_VERSION in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config} */ SfdxPropertyKeys["API_VERSION"] = "apiVersion"; /** * Disables telemetry reporting * * @deprecated Replaced by SfPropertyKeys.DISABLE_TELEMETRY in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config} */ SfdxPropertyKeys["DISABLE_TELEMETRY"] = "disableTelemetry"; /** * Custom templates repo or local location. * * @deprecated Replaced by OrgConfigProperties.ORG_CUSTOM_METADATA_TEMPLATES in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config} */ SfdxPropertyKeys["CUSTOM_ORG_METADATA_TEMPLATES"] = "customOrgMetadataTemplates"; /** * allows users to override the 10,000 result query limit * * @deprecated Replaced by OrgConfigProperties.ORG_MAX_QUERY_LIMIT in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config} */ SfdxPropertyKeys["MAX_QUERY_LIMIT"] = "maxQueryLimit"; /** * @deprecated */ SfdxPropertyKeys["REST_DEPLOY"] = "restDeploy"; /** * @deprecated Replaced by OrgConfigProperties.ORG_INSTANCE_URL in v3 {@link https://github.com/forcedotcom/sfdx-core/blob/v3/MIGRATING_V2-V3.md#config} */ SfdxPropertyKeys["INSTANCE_URL"] = "instanceUrl"; })(SfdxPropertyKeys || (exports.SfdxPropertyKeys = SfdxPropertyKeys = {})); exports.SFDX_ALLOWED_PROPERTIES = [ { key: SfdxPropertyKeys.INSTANCE_URL, description: messages.getMessage(SfdxPropertyKeys.INSTANCE_URL), newKey: orgConfigProperties_1.OrgConfigProperties.ORG_INSTANCE_URL, deprecated: true, input: { // If a value is provided validate it otherwise no value is unset. validator: (value) => { if (value == null) return true; // validate if the value is a string and is a valid url and is either a salesforce domain // or an internal url. return ((0, ts_types_1.isString)(value) && sfdcUrl_1.SfdcUrl.isValidUrl(value) && (new sfdcUrl_1.SfdcUrl(value).isSalesforceDomain() || new sfdcUrl_1.SfdcUrl(value).isInternalUrl())); }, failedMessage: messages.getMessage('invalidInstanceUrl'), }, }, { key: SfdxPropertyKeys.API_VERSION, newKey: orgConfigProperties_1.OrgConfigProperties.ORG_API_VERSION, deprecated: true, description: messages.getMessage(SfdxPropertyKeys.API_VERSION), hidden: true, input: { // If a value is provided validate it otherwise no value is unset. validator: (value) => value == null || ((0, ts_types_1.isString)(value) && (0, sfdc_1.validateApiVersion)(value)), failedMessage: messages.getMessage('invalidApiVersion'), }, }, { // will remain in v3 for the foreseeable future so that `sfdx-core` can map between `sf` and `sfdx` config values key: SfdxPropertyKeys.DEFAULT_DEV_HUB_USERNAME, newKey: orgConfigProperties_1.OrgConfigProperties.TARGET_DEV_HUB, deprecated: true, description: messages.getMessage('defaultDevHubUsername'), }, { // will remain in v3 for the foreseeable future so that `sfdx-core` can map between `sf` and `sfdx` config values key: SfdxPropertyKeys.DEFAULT_USERNAME, newKey: orgConfigProperties_1.OrgConfigProperties.TARGET_ORG, deprecated: true, description: messages.getMessage('defaultUsername'), }, { key: SfdxPropertyKeys.ISV_DEBUGGER_SID, newKey: orgConfigProperties_1.OrgConfigProperties.ORG_ISV_DEBUGGER_SID, deprecated: true, description: messages.getMessage(SfdxPropertyKeys.ISV_DEBUGGER_SID), encrypted: true, input: { // If a value is provided validate it otherwise no value is unset. validator: (value) => value == null || (0, ts_types_1.isString)(value), failedMessage: messages.getMessage('invalidIsvDebuggerSid'), }, }, { key: SfdxPropertyKeys.ISV_DEBUGGER_URL, newKey: orgConfigProperties_1.OrgConfigProperties.ORG_ISV_DEBUGGER_URL, deprecated: true, description: messages.getMessage(SfdxPropertyKeys.ISV_DEBUGGER_URL), input: { // If a value is provided validate it otherwise no value is unset. validator: (value) => value == null || (0, ts_types_1.isString)(value), failedMessage: messages.getMessage('invalidIsvDebuggerUrl'), }, }, { key: SfdxPropertyKeys.DISABLE_TELEMETRY, newKey: SfConfigProperties.DISABLE_TELEMETRY, deprecated: true, description: messages.getMessage(SfdxPropertyKeys.DISABLE_TELEMETRY), input: { validator: (value) => value == null || isBooleanOrBooleanString(value), failedMessage: messages.getMessage('invalidBooleanConfigValue'), }, }, { key: SfdxPropertyKeys.CUSTOM_ORG_METADATA_TEMPLATES, newKey: orgConfigProperties_1.OrgConfigProperties.ORG_CUSTOM_METADATA_TEMPLATES, deprecated: true, description: messages.getMessage(SfdxPropertyKeys.CUSTOM_ORG_METADATA_TEMPLATES), }, { key: SfdxPropertyKeys.REST_DEPLOY, description: messages.getMessage(SfdxPropertyKeys.REST_DEPLOY), hidden: true, newKey: 'org-metadata-rest-deploy', deprecated: true, input: { validator: (value) => value != null && isBooleanOrBooleanString(value), failedMessage: messages.getMessage('invalidBooleanConfigValue'), }, }, { key: SfdxPropertyKeys.MAX_QUERY_LIMIT, description: messages.getMessage(SfdxPropertyKeys.MAX_QUERY_LIMIT), hidden: true, newKey: orgConfigProperties_1.OrgConfigProperties.ORG_MAX_QUERY_LIMIT, deprecated: true, 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, failedMessage: messages.getMessage('invalidNumberConfigValue'), }, }, ]; // Generic global config properties. Specific properties can be loaded like orgConfigProperties.ts. exports.SfProperty = {}; /** * 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('target-org', '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 { static allowedProperties = [ ...exports.SFDX_ALLOWED_PROPERTIES, ...exports.SF_ALLOWED_PROPERTIES, ...orgConfigProperties_1.ORG_CONFIG_ALLOWED_PROPERTIES, ]; sfdxPath; constructor(options) { super({ ...{ isGlobal: false }, ...(options ?? {}), // Don't let consumers of config override this. If they really really want to, // they can extend this class. isState: true, filename: Config.getFileName(), stateFolder: global_1.Global.SF_STATE_FOLDER, }); // Resolve the config path on creation. this.getPath(); if (global_1.Global.SFDX_INTEROPERABILITY) { this.sfdxPath = buildSfdxPath(this.options); } } /** * Returns the default file name for a config file. * * **See** {@link CONFIG_FILE_NAME} */ static getFileName() { return 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); }); } /** * 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({ isGlobal }); await config.read(); if (value == null) { config.unset(propertyName); } else { config.set(propertyName, value); } return config.write(); } /** * Clear all the configured properties both local and global. */ static async clear() { const [globalConfig, localConfig] = await Promise.all([Config.create({ isGlobal: true }), Config.create()]); globalConfig.clear(); localConfig.clear(); await Promise.all([globalConfig.write(), localConfig.write()]); } static getPropertyConfigMeta(propertyName) { const prop = Config.propertyConfigMap()[propertyName]; if (prop?.deprecated && prop?.newKey) { return Config.propertyConfigMap()[prop.newKey]; } return prop; } static propertyConfigMap() { return (0, kit_1.keyBy)(Config.allowedProperties, 'key'); } /** * Read, assign, and return the config contents. */ async read(force = true) { try { await super.read(false, force); if (global_1.Global.SFDX_INTEROPERABILITY) { // will exist if Global.SFDX_INTEROPERABILITY is enabled // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.contents.merge(stateFromSfdxFileSync(this.sfdxPath, this)); } await this.cryptProperties(false); return this.getContents(); } finally { await this.clearCrypto(); } } readSync(force = true) { super.readSync(false, force); if (global_1.Global.SFDX_INTEROPERABILITY) { // will exist if Global.SFDX_INTEROPERABILITY is enabled // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.contents.merge(stateFromSfdxFileSync(this.sfdxPath, this)); } return this.getContents(); } /** * Writes Config properties taking into account encrypted properties. * * @param newContents The new Config value to persist. */ async write() { await this.cryptProperties(true); // super.write will merge the contents if the target file had newer properties await super.write(); if (global_1.Global.SFDX_INTEROPERABILITY) { // will exist if Global.SFDX_INTEROPERABILITY is enabled // eslint-disable-next-line @typescript-eslint/no-non-null-assertion await writeToSfdx(this.sfdxPath, this.getContents()); } 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 SfError}{ name: 'InvalidWriteError' }* Always. * * @param newContents Contents to write */ // eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this writeSync(newContents) { throw messages.createError('invalidWrite'); } /** * Sets a value for a property. * * **Throws** *{@link SfError}{ name: 'UnknownConfigKeyError' }* An attempt to get a property that's not supported. * **Throws** *{@link SfError}{ name: 'InvalidConfigValueError' }* If the input validator fails. * * @param key The property to set. * @param value The value of the property. */ set(key, value) { const property = Config.allowedProperties.find((allowedProp) => allowedProp.key === key); if (!property) { throw messages.createError('unknownConfigKey', [key]); } if (property.deprecated && property.newKey) { // you're trying to set a deprecated key, but we'll set the new key instead void lifecycleEvents_1.Lifecycle.getInstance().emitWarning(messages.getMessage('deprecatedConfigKey', [key, property.newKey])); return this.set(property.newKey, value); } if (value !== undefined && property.input) { if (property.input?.validator(value)) { super.set(property.key, value); } else { let valueError = value?.toString() ?? ''; if (property.input.failedMessage) { valueError = (0, ts_types_1.isString)(property.input.failedMessage) ? property.input.failedMessage : property.input.failedMessage(value); } throw messages.createError('invalidConfigValue', [valueError]); } } else { super.set(property.key, value); } return this.getContents(); } /** * Unsets a value for a property. * * **Throws** *{@link SfError}{ name: 'UnknownConfigKeyError' }* 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 messages.createError('unknownConfigKey', [key]); } if (property.deprecated && property.newKey) { // you're trying to set a deprecated key, so we'll ALSO unset the new key void lifecycleEvents_1.Lifecycle.getInstance().emitWarning(messages.getMessage('deprecatedConfigKey', [key, property.newKey])); super.unset(property.key); return this.unset(property.newKey); } return super.unset(property.key); } /** * Get an individual property config. * * **Throws** *{@link SfError}{ name: 'UnknownConfigKeyError' }* An attempt to get a property that's not supported. * * @param propertyName The name of the property. */ // eslint-disable-next-line class-methods-use-this getPropertyConfig(propertyName) { const prop = Config.propertyConfigMap()[propertyName]; if (!prop) { const newEquivalent = Config.allowedProperties.find((p) => p.newKey); if (newEquivalent) { return this.getPropertyConfig(newEquivalent.key); } throw messages.createError('unknownConfigKey', [propertyName]); } return prop; } /** * 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(); } /** * Encrypts and content properties that have a encryption attribute. * * @param encrypt `true` to encrypt. */ async cryptProperties(encrypt) { const hasEncryptedProperties = this.entries().some(([key]) => !!Config.propertyConfigMap()[key]?.encrypted); if (hasEncryptedProperties) { await this.initCrypto(); const crypto = (0, ts_types_1.ensure)(this.crypto); this.forEach((key, value) => { if (this.getPropertyConfig(key).encrypted && (0, ts_types_1.isString)(value)) { super.set(key, (0, ts_types_1.ensure)(encrypt ? crypto.encrypt(value) : crypto.decrypt(value))); } }); } } } exports.Config = Config; /** * convert from "new" to "old" config names * - For example, `target-org` will be renamed to `defaultusername`. */ const translateToSfdx = (sfContents) => Object.fromEntries(Object.entries(sfContents).map(([key, value]) => { const propConfig = Config.getAllowedProperties().find((c) => c.newKey === key) ?? {}; return propConfig.deprecated && propConfig.newKey ? [propConfig.key, value] : [key, value]; })); /** * convert from "old" to "new" config names * - For example, `defaultusername` will be renamed to `target-org` */ const translateToSf = (sfdxContents, SfConfig) => Object.fromEntries(Object.entries(sfdxContents).map(([key, value]) => { const propConfig = SfConfig.getPropertyConfig(key); return propConfig.deprecated && propConfig.newKey ? [propConfig.newKey, value] : [key, value]; })); /** given the ConfigFile options, calculate the full path where the config file goes */ const buildSfdxPath = (options) => { // Don't let users store config files in homedir without being in the state folder. const configRootFolder = options.rootFolder ?? configFile_1.ConfigFile.resolveRootFolderSync(!!options.isGlobal); const rootWithState = options.isGlobal === true || options.isState === true ? (0, node_path_1.join)(configRootFolder, global_1.Global.SFDX_STATE_FOLDER) : configRootFolder; return (0, node_path_1.join)(rootWithState, SFDX_CONFIG_FILE_NAME); }; /** * writes (in an unsafe way) the configuration file to the sfdx file location. * Make sure you call ConfigFile.write and getContents so that the contents passed here are not cross-saving something */ const writeToSfdx = async (path, contents) => { try { const translated = translateToSfdx(contents); await fs.promises.mkdir((0, node_path_1.dirname)(path), { recursive: true }); await fs.promises.writeFile(path, JSON.stringify(translated, null, 2)); } catch (e) { const logger = logger_1.Logger.childFromRoot('core:config:writeToSfdx'); logger.debug(`Error writing to sfdx config file at ${path}: ${e instanceof Error ? e.message : ''}`); } }; /** turn the sfdx config file into a LWWState based on its contents and its timestamp */ const stateFromSfdxFileSync = (path, config) => { try { const fileContents = fs.readFileSync(path, 'utf8'); const mtimeNs = fs.statSync(path, { bigint: true }).mtimeNs; const translatedContents = translateToSf((0, kit_1.parseJsonMap)(fileContents, path), config); // get the file timestamp return (0, lwwMap_1.stateFromContents)(translatedContents, mtimeNs); } catch (e) { const logger = logger_1.Logger.childFromRoot('core:config:stateFromSfdxFileSync'); logger.debug(`Error reading state from sfdx config file at ${path}: ${e instanceof Error ? e.message : ''}`); return {}; } }; const isBooleanOrBooleanString = (value) => (typeof value === 'string' && ['true', 'false'].includes(value)) || typeof value === 'boolean'; //# sourceMappingURL=config.js.map