UNPKG

@salesforce/core

Version:

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

196 lines 7.42 kB
"use strict"; /* * Copyright (c) 2021, 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.getFileLocation = exports.AliasAccessor = exports.FILENAME = exports.DEFAULT_GROUP = void 0; const node_path_1 = require("node:path"); const node_os_1 = require("node:os"); const promises_1 = require("node:fs/promises"); const proper_lockfile_1 = require("proper-lockfile"); const kit_1 = require("@salesforce/kit"); const global_1 = require("../../global"); const sfError_1 = require("../../sfError"); const lockRetryOptions_1 = require("../../util/lockRetryOptions"); exports.DEFAULT_GROUP = 'orgs'; exports.FILENAME = 'alias.json'; class AliasAccessor extends kit_1.AsyncOptionalCreatable { // set in init method fileLocation; /** orgs is the default group */ aliasStore; getAll(entity) { // This will only return aliases under "orgs". This will need to be modified // if/when we want to support more aliases groups. if (entity) { const nameFromEntity = getNameOf(entity); return Array.from(this.aliasStore.entries()) .filter(([, value]) => nameFromEntity === value) .map(([alias]) => alias); } else { return Object.fromEntries(this.aliasStore.entries()); } } /** * Returns the first alias found for a given entity * * @param entity the aliasable entity that you want to get the alias of */ get(entity) { return this.getAll(entity)[0] ?? null; } /** * Returns the value that corresponds to the given alias if it exists * * @param alias the alias that corresponds to a value */ getValue(alias) { return this.aliasStore.get(alias) ?? null; } /** * Returns the username that corresponds to the given alias if it exists * * @param alias the alias that corresponds to a username */ getUsername(alias) { return this.aliasStore.get(alias) ?? null; } /** * If the provided string is an alias, it returns the corresponding username. * If the provided string is not an alias, we assume that the provided string * is the username and return it. * * This method is helpful when you don't know if the string you have is a username * or an alias. * * @param usernameOrAlias a string that might be a username or might be an alias */ resolveUsername(usernameOrAlias) { return this.getUsername(usernameOrAlias) ?? usernameOrAlias; } /** * If the provided string is an alias, return it. * If the provided string is not an alias, return the username of the provided alias * * This method is helpful when you don't know if the string you have is a username * or an alias. * * @param usernameOrAlias a string that might be a username or might be an alias */ resolveAlias(usernameOrAlias) { if (this.aliasStore.has(usernameOrAlias)) return usernameOrAlias; return Array.from(this.aliasStore.entries()).find(([, value]) => value === usernameOrAlias)?.[0]; } /** * Set an alias for the given aliasable entity. Writes to the file * * @param alias the alias you want to set * @param entity the aliasable entity that's being aliased */ async setAndSave(alias, entity) { // get a very fresh copy to merge with to avoid conflicts, then lock await this.readFileToAliasStore(true); this.aliasStore.set(alias, getNameOf(entity)); return this.saveAliasStoreToFile(); } /** * Unset the given alias(es). Writes to the file * */ async unsetAndSave(alias) { await this.readFileToAliasStore(true); this.aliasStore.delete(alias); return this.saveAliasStoreToFile(); } /** * Unset all the aliases for the given array of entity. * * @param entity the aliasable entity for which you want to unset all aliases */ async unsetValuesAndSave(aliasees) { await this.readFileToAliasStore(true); (0, kit_1.ensureArray)(aliasees) .flatMap((a) => this.getAll(a)) .map((a) => this.aliasStore.delete(a)); return this.saveAliasStoreToFile(); } /** * Returns true if the provided alias exists * * @param alias the alias you want to check */ has(alias) { return this.aliasStore.has(alias); } async init() { this.fileLocation = (0, exports.getFileLocation)(); await this.readFileToAliasStore(); } /** * go to the fileSystem and read the file, storing a copy in the class's store * if the file doesn't exist, create it empty */ async readFileToAliasStore(useLock = false) { if (useLock) { await (0, proper_lockfile_1.lock)(this.fileLocation, lockRetryOptions_1.lockRetryOptions); } try { this.aliasStore = fileContentsRawToAliasStore(await (0, promises_1.readFile)(this.fileLocation, 'utf-8')); } catch (e) { if (e instanceof Error && 'code' in e && e.code === 'ENOENT') { this.aliasStore = new Map(); await (0, promises_1.mkdir)((0, node_path_1.dirname)(this.fileLocation), { recursive: true }); await this.saveAliasStoreToFile(); return; } if (useLock) return unlockIfLocked(this.fileLocation); throw e; } } async saveAliasStoreToFile() { await (0, promises_1.writeFile)(this.fileLocation, aliasStoreToRawFileContents(this.aliasStore)); return unlockIfLocked(this.fileLocation); } } exports.AliasAccessor = AliasAccessor; /** * Returns the username of given aliasable entity */ const getNameOf = (entity) => { if (typeof entity === 'string') return entity; const aliaseeName = entity.username; if (!aliaseeName) { throw new sfError_1.SfError(`Invalid aliasee, it must contain a user or username property: ${JSON.stringify(entity)}`); } return aliaseeName; }; const fileContentsRawToAliasStore = (contents) => { const fileContents = JSON.parse(contents); // handle when alias file exists but is missing the org property return new Map(Object.entries(fileContents[exports.DEFAULT_GROUP] ?? {})); }; const aliasStoreToRawFileContents = (aliasStore) => JSON.stringify({ [exports.DEFAULT_GROUP]: Object.fromEntries(Array.from(aliasStore.entries())) }); // exported for testSetup mocking const getFileLocation = () => (0, node_path_1.join)((0, node_os_1.homedir)(), global_1.Global.SFDX_STATE_FOLDER, exports.FILENAME); exports.getFileLocation = getFileLocation; const unlockIfLocked = async (fileLocation) => { try { await (0, proper_lockfile_1.unlock)(fileLocation); } catch (e) { // ignore the error. If it wasn't locked, that's what we wanted if (errorIsNotAcquired(e)) return; throw e; } }; const errorIsNotAcquired = (e) => e instanceof Error && 'code' in e && e.code === 'ENOTACQUIRED'; //# sourceMappingURL=aliasAccessor.js.map