UNPKG

10 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.ConfigAggregator = void 0;
10const kit_1 = require("@salesforce/kit");
11const ts_types_1 = require("@salesforce/ts-types");
12const sfdxError_1 = require("../sfdxError");
13const config_1 = require("./config");
14const propertyToEnvName = (property) => `SFDX_${kit_1.snakeCase(property).toUpperCase()}`;
15/**
16 * Aggregate global and local project config files, as well as environment variables for
17 * `sfdx-config.json`. The resolution happens in the following bottom-up order:
18 *
19 * 1. Environment variables (`SFDX_LOG_LEVEL`)
20 * 1. Workspace settings (`<workspace-root>/.sfdx/sfdx-config.json`)
21 * 1. Global settings (`$HOME/.sfdx/sfdx-config.json`)
22 *
23 * Use {@link ConfigAggregator.create} to instantiate the aggregator.
24 *
25 * ```
26 * const aggregator = await ConfigAggregator.create();
27 * console.log(aggregator.getPropertyValue('defaultusername'));
28 * ```
29 */
30class ConfigAggregator extends kit_1.AsyncOptionalCreatable {
31 /**
32 * **Do not directly construct instances of this class -- use {@link ConfigAggregator.create} instead.**
33 *
34 * @ignore
35 */
36 constructor(options) {
37 super(options || {});
38 // Don't throw an project error with the aggregator, since it should resolve to global if
39 // there is no project.
40 try {
41 this.localConfig = new config_1.Config(config_1.Config.getDefaultOptions(false));
42 }
43 catch (err) {
44 if (err.name !== 'InvalidProjectWorkspace') {
45 throw err;
46 }
47 }
48 this.globalConfig = new config_1.Config(config_1.Config.getDefaultOptions(true));
49 this.setAllowedProperties(config_1.Config.getAllowedProperties());
50 }
51 get config() {
52 return this.resolveProperties(this.globalConfig.getContents(), this.localConfig && this.localConfig.getContents());
53 }
54 /**
55 * Get the static ConfigAggregator instance. If one doesn't exist, one will be created with
56 * the **encrypted** config values. Encrypted config values need to be resolved
57 * asynchronously by calling {@link ConfigAggregator.reload}
58 */
59 // Use typing from AsyncOptionalCreatable to support extending ConfigAggregator.
60 // We really don't want ConfigAggregator extended but typescript doesn't support a final.
61 static getInstance() {
62 if (!ConfigAggregator.instance) {
63 ConfigAggregator.instance = new this();
64 ConfigAggregator.instance.loadPropertiesSync();
65 }
66 return ConfigAggregator.instance;
67 }
68 // Use typing from AsyncOptionalCreatable to support extending ConfigAggregator.
69 // We really don't want ConfigAggregator extended but typescript doesn't support a final.
70 static async create(options) {
71 let config = ConfigAggregator.instance;
72 if (!config) {
73 config = ConfigAggregator.instance = new this(options);
74 await config.init();
75 }
76 if (ConfigAggregator.encrypted) {
77 await config.loadProperties();
78 }
79 return ConfigAggregator.instance;
80 }
81 /**
82 * Get the info for a given key. If the ConfigAggregator was not asynchronously created OR
83 * the {@link ConfigAggregator.reload} was not called, the config value may be encrypted.
84 *
85 * @param key The config key.
86 */
87 static getValue(key) {
88 return this.getInstance().getInfo(key);
89 }
90 /**
91 * Initialize this instances async dependencies.
92 */
93 async init() {
94 await this.loadProperties();
95 }
96 /**
97 * Get a resolved config property.
98 *
99 * **Throws** *{@link SfdxError}{ name: 'UnknownConfigKey' }* An attempt to get a property that's not supported.
100 *
101 * @param key The key of the property.
102 */
103 getPropertyValue(key) {
104 if (this.getAllowedProperties().some((element) => key === element.key)) {
105 return this.getConfig()[key];
106 }
107 else {
108 throw new sfdxError_1.SfdxError(`Unknown config key: ${key}`, 'UnknownConfigKey');
109 }
110 }
111 /**
112 * Get a resolved config property.
113 *
114 * @param key The key of the property.
115 */
116 getInfo(key) {
117 const location = this.getLocation(key);
118 return {
119 key,
120 location,
121 value: this.getPropertyValue(key),
122 path: this.getPath(key),
123 isLocal: () => location === "Local" /* LOCAL */,
124 isGlobal: () => location === "Global" /* GLOBAL */,
125 isEnvVar: () => location === "Environment" /* ENVIRONMENT */,
126 };
127 }
128 /**
129 * Gets a resolved config property location.
130 *
131 * For example, `getLocation('logLevel')` will return:
132 * 1. `Location.GLOBAL` if resolved to an environment variable.
133 * 1. `Location.LOCAL` if resolved to local project config.
134 * 1. `Location.ENVIRONMENT` if resolved to the global config.
135 *
136 * @param key The key of the property.
137 */
138 getLocation(key) {
139 if (this.getEnvVars().get(key) != null) {
140 return "Environment" /* ENVIRONMENT */;
141 }
142 if (this.localConfig && this.localConfig.get(key)) {
143 return "Local" /* LOCAL */;
144 }
145 if (this.globalConfig && this.globalConfig.get(key)) {
146 return "Global" /* GLOBAL */;
147 }
148 }
149 /**
150 * Get a resolved file path or environment variable name of the property.
151 *
152 * For example, `getPath('logLevel')` will return:
153 * 1. `$SFDX_LOG_LEVEL` if resolved to an environment variable.
154 * 1. `./.sfdx/sfdx-config.json` if resolved to the local config.
155 * 1. `~/.sfdx/sfdx-config.json` if resolved to the global config.
156 * 1. `undefined`, if not resolved.
157 *
158 * **Note:** that the path returned may be the absolute path instead of
159 * relative paths such as `./` and `~/`.
160 *
161 * @param key The key of the property.
162 */
163 getPath(key) {
164 if (this.envVars[key] != null) {
165 return `$${propertyToEnvName(key)}`;
166 }
167 if (this.localConfig && this.localConfig.getContents()[key] != null) {
168 return this.localConfig.getPath();
169 }
170 if (this.globalConfig.getContents()[key] != null) {
171 return this.globalConfig.getPath();
172 }
173 }
174 /**
175 * Get all resolved config property keys, values, locations, and paths.
176 *
177 * ```
178 * > console.log(aggregator.getConfigInfo());
179 * [
180 * { key: 'logLevel', val: 'INFO', location: 'Environment', path: '$SFDX_LOG_LEVEL'}
181 * { key: 'defaultusername', val: '<username>', location: 'Local', path: './.sfdx/sfdx-config.json'}
182 * ]
183 * ```
184 */
185 getConfigInfo() {
186 const infos = Object.keys(this.getConfig())
187 .filter((key) => this.getAllowedProperties().some((element) => key === element.key))
188 .map((key) => this.getInfo(key))
189 .filter((info) => !!info);
190 return kit_1.sortBy(infos, 'key');
191 }
192 /**
193 * Get the local project config instance.
194 */
195 getLocalConfig() {
196 return this.localConfig;
197 }
198 /**
199 * Get the global config instance.
200 */
201 getGlobalConfig() {
202 return this.globalConfig;
203 }
204 /**
205 * Get the resolved config object from the local, global and environment config instances.
206 */
207 getConfig() {
208 return this.config;
209 }
210 /**
211 * Get the config properties that are environment variables.
212 */
213 getEnvVars() {
214 return new Map(ts_types_1.definiteEntriesOf(this.envVars));
215 }
216 /**
217 * Re-read all property configurations from disk.
218 */
219 async reload() {
220 await this.loadProperties();
221 return this;
222 }
223 /**
224 * Loads all the properties and aggregates them according to location.
225 */
226 async loadProperties() {
227 this.resolveProperties(await this.globalConfig.read(), this.localConfig && (await this.localConfig.read()));
228 ConfigAggregator.encrypted = false;
229 }
230 /**
231 * Loads all the properties and aggregates them according to location.
232 */
233 loadPropertiesSync() {
234 this.resolveProperties(this.globalConfig.readSync(), this.localConfig && this.localConfig.readSync());
235 }
236 resolveProperties(globalConfig, localConfig) {
237 const accumulator = {};
238 this.setEnvVars(this.getAllowedProperties().reduce((obj, property) => {
239 const val = process.env[propertyToEnvName(property.key)];
240 if (val != null) {
241 obj[property.key] = val;
242 }
243 return obj;
244 }, accumulator));
245 // Global config must be read first so it is on the left hand of the
246 // object assign and is overwritten by the local config.
247 const configs = [globalConfig];
248 // We might not be in a project workspace
249 if (localConfig) {
250 configs.push(localConfig);
251 }
252 configs.push(this.envVars);
253 const json = {};
254 const reduced = configs.filter(ts_types_1.isJsonMap).reduce((acc, el) => kit_1.merge(acc, el), json);
255 return reduced;
256 }
257 /**
258 * Get the allowed properties.
259 */
260 getAllowedProperties() {
261 return this.allowedProperties;
262 }
263 /**
264 * Set the allowed properties.
265 *
266 * @param properties The properties to set.
267 */
268 setAllowedProperties(properties) {
269 this.allowedProperties = properties;
270 }
271 /**
272 * Sets the env variables.
273 *
274 * @param envVars The env variables to set.
275 */
276 setEnvVars(envVars) {
277 this.envVars = envVars;
278 }
279}
280exports.ConfigAggregator = ConfigAggregator;
281ConfigAggregator.encrypted = true;
282//# sourceMappingURL=configAggregator.js.map
\No newline at end of file