UNPKG

salesforce-alm

Version:

This package contains tools, and APIs, for an improved salesforce.com developer experience.

208 lines (206 loc) 7.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.canRead = exports.deleteOrderComparator = exports.cleanEmptyDirs = exports.getNestedDirectoryPaths = exports.encodeMetadataString = exports.replaceForwardSlashes = exports.removeParentDirFromPath = exports.fileNamesWithoutExtensionsMatch = exports.getContentPathWithNonStdExtFromMetadataPath = exports.getPathToDir = exports.getGrandparentDirectoryName = exports.getParentDirectoryName = exports.getFileName = exports.removeMetadataFileExtFrom = void 0; /* * 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 */ const path = require("path"); const fs = require("fs-extra"); const _ = require("lodash"); const glob = require("glob"); const MetadataRegistry = require("./metadataRegistry"); /** * Returns the given filePath without '-meta.xml' * * @param {string} filePath * @returns {string} */ exports.removeMetadataFileExtFrom = function (filePath) { return filePath.replace(MetadataRegistry.getMetadataFileExt(), ''); }; /** * Returns the fileName stripped of any file extensions * * @param {string} filePath * @param {TypeDefObj} typeDef * @returns {string} */ exports.getFileName = function (filePath) { const filePathWithoutMetadataExt = exports.removeMetadataFileExtFrom(filePath); return path.basename(filePathWithoutMetadataExt, path.extname(filePathWithoutMetadataExt)); }; /** * Returns the parent directory name * Example: /parentDir/fileName.ext returns 'parentDir' * * @param {string} filePath * @returns {string} */ exports.getParentDirectoryName = function (filePath) { return path.basename(path.dirname(filePath)); }; /** * Returns the grandparent directory name * Example: grandparentDir/parentDir/fileName.ext returns 'grandparentDir' * * @param {string} filePath * @returns {string} */ exports.getGrandparentDirectoryName = function (filePath) { return path.basename(path.dirname(path.dirname(filePath))); }; /** * Returns the truncated path to the given directory * Example: filePath='path/to/specialDir/containing/stuff' dirName='specialDir' returns 'path/to/specialDir' * * @param {string} filePath * @param {string} dirName * @returns {string} */ exports.getPathToDir = function (filePath, dirName) { const filePathParts = filePath.split(path.sep); const indexOfGivenDir = filePathParts.indexOf(dirName); if (indexOfGivenDir !== -1) { let newFilePath = path.join(...filePathParts.slice(0, indexOfGivenDir + 1)); if (filePath.startsWith(path.sep)) { newFilePath = `${path.sep}${newFilePath}`; } return newFilePath; } return null; }; exports.getContentPathWithNonStdExtFromMetadataPath = function (metadataFilePath) { const fileNameWithoutExtensions = exports.getFileName(metadataFilePath); let matchingWorkspaceFiles = glob.sync(path.join(path.dirname(metadataFilePath), `${fileNameWithoutExtensions}*`)); matchingWorkspaceFiles = matchingWorkspaceFiles.map((filePath) => path.resolve(filePath)); // glob returns paths using the forward slash only, which breaks tests in Windows return matchingWorkspaceFiles.find((docFile) => exports.fileNamesWithoutExtensionsMatch(path.basename(docFile), fileNameWithoutExtensions) && !docFile.endsWith(MetadataRegistry.getMetadataFileExt())); }; exports.fileNamesWithoutExtensionsMatch = function (filename1, filename2) { return path.basename(filename1, path.extname(filename1)) === path.basename(filename2, path.extname(filename2)); }; exports.removeParentDirFromPath = function (filePath) { const fileName = path.basename(filePath); return path.join(path.dirname(path.dirname(filePath)), fileName); }; /** * Replace forward slashes with path separators * * @param {string} str * @returns {string} */ exports.replaceForwardSlashes = function (str) { return str.replace(/\//g, path.sep); }; /** * Encode a string similarly to how Metadata API encodes (spaces not encoded) * * @param {string} str * @returns {string} */ exports.encodeMetadataString = function (str) { return encodeURIComponent(str).replace(/%20/g, ' '); }; /** * gets a list of sub-directories from a parent directory. * * @param {string} filePath The path to look for nested directories * @returns {string[]} An array of all sub directories */ exports.getNestedDirectoryPaths = function (filePath) { const accum = []; const _recur = (_filePath) => { if (_filePath) { try { // Is the sub folder accessible? fs.accessSync(_filePath, fs.constants.R_OK); const stats = fs.statSync(_filePath); // Is it a directory? if (stats.isDirectory()) { accum.push(_filePath); const dirListing = fs.readdirSync(_filePath); // Is the folder empty? dirListing.forEach((_path) => { const subPath = path.join(_filePath, _path); _recur(subPath); }); } } catch (e) { // If we can't access the filepath then lets stop. } } }; _recur(filePath); return accum; }; /** * Removes all the empty sub-directories * * @param {string} filePath The parent path to look for empty directories. This directory will also be removed if it * ends up being empty. */ function cleanEmptyDirs(filePath) { const paths = exports.getNestedDirectoryPaths(filePath); // Sort all directory paths based on level count in descending order. paths.sort((a, b) => { const aLevelCount = _.split(a, path.sep).length; const bLevelCount = _.split(b, path.sep).length; if (aLevelCount > bLevelCount) { return -1; } return aLevelCount < bLevelCount ? 1 : 0; }); // Iterate and deleted all the empty folders. If a parent becomes empty because it only contained empty folders it // will be deleted later because its level is one less. paths.forEach((_path) => { const dirListing = fs.readdirSync(_path); if (dirListing.length === 0) { fs.removeSync(_path); } }); } exports.cleanEmptyDirs = cleanEmptyDirs; /** * Comparator function to sort an array of strings by parent child relationship. * * @param left {string} The left path string * @param right {string} The right path string * @returns * if the right path starts with the left path return 1 * if the left path starts with the right path return -1 * Everything else returns the result of left.localeCompare(right) */ function deleteOrderComparator(left, right) { if (left.startsWith(right) && left.length > right.length) { return -1; } if (right.startsWith(left) && right.length > left.length) { return 1; } return left.localeCompare(right); } exports.deleteOrderComparator = deleteOrderComparator; /** * A better file exists function that ensures a file can be read from the filesystem. * * @param path The absolute files path or relative path to a file from the CWD. */ // eslint-disable-next-line @typescript-eslint/no-shadow function canRead(path) { if (path) { try { fs.access(path, fs.constants.R_OK); return true; } catch (e) { return false; } } return false; } exports.canRead = canRead; //# sourceMappingURL=sourcePathUtil.js.map