salesforce-alm
Version:
This package contains tools, and APIs, for an improved salesforce.com developer experience.
141 lines (139 loc) • 7.11 kB
JavaScript
;
/*
* 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.BundlePathHelper = void 0;
const path = require("path");
const glob = require("glob");
const MetadataRegistry = require("./metadataRegistry");
const PathUtil = require("./sourcePathUtil");
const { env } = require('@salesforce/kit');
// A safer while loop that will exit and throw an error when a user provided guard function
// is provided or the default guard function returns true.
function guardedWhile(conditionFn, func, guard) {
let i = 0;
const max_loops = parseInt(env.getString('SFDX_GUARDED_WHILE_MAX_ITERATIONS', '10000'), 10);
const _guard = guard || (() => i > max_loops);
while (conditionFn()) {
i++;
if (_guard()) {
throw new Error('WARNING: Infinite loop detected.');
}
func();
}
}
/**
* This class contains helper functions to calculate Bundle type paths (AuraDefinitionBundle, LightningComponentBundle)
*/
class BundlePathHelper {
static getPathFromBundleTypeFileProperties(fullName, defaultSourceDir, defaultDirName, bundleFileTypeProperties) {
const bundleName = fullName.split(path.sep)[0];
const pathToDefaultTypeDirectory = path.join(defaultSourceDir, defaultDirName);
const fileName = BundlePathHelper.getMetadataFileNameFromBundleFileProperties(fullName, bundleFileTypeProperties);
return path.join(pathToDefaultTypeDirectory, bundleName, fileName);
}
static getMetadataFileNameFromBundleFileProperties(fullName, bundleFileTypeProperties) {
const normalizedFullName = path.normalize(fullName);
const bundleName = normalizedFullName.split(path.sep)[0];
const matchingBundle = bundleFileTypeProperties.find((fileProperty) => {
const normalizedBFTPFullName = path.normalize(fileProperty.fullName);
return normalizedBFTPFullName.split(path.sep)[0] === bundleName;
});
return `${path.basename(matchingBundle.fileName)}${MetadataRegistry.getMetadataFileExt()}`;
}
static findMetadataFilePathInBundleDir(filePath, bundleTypeDefaultDirName) {
if (filePath.endsWith(MetadataRegistry.getMetadataFileExt())) {
return filePath;
}
else {
// Each bundle has one metadata file path that ends with its definition suffix + '-meta.xml'
// and is located directly in the bundle directory (not a subfolder)
// This finds and scans the bundle directory to find the existing aggregate metadata file path
let bundlePath;
let pathName = path.dirname(filePath);
let folderName = path.basename(pathName);
// LightningComponentBundle folder structure can be multi-level; Scan for the direct child folder
// which is the bundle path
const findPath = () => {
bundlePath = pathName;
pathName = path.dirname(pathName);
folderName = path.basename(pathName);
};
guardedWhile(() => !(folderName === bundleTypeDefaultDirName), findPath);
const matchingFilePaths = glob.sync(path.join(bundlePath, `*${MetadataRegistry.getMetadataFileExt()}`));
if (matchingFilePaths.length > 0) {
// glob returns paths using the forward slash only, which breaks in Windows
return PathUtil.replaceForwardSlashes(matchingFilePaths[0]);
}
// In the case that a bundle has been deleted from the workspace, a search for its definition file
// will produce no results. In this case, return the filePath being processed.
return filePath;
}
}
static buildFullNameFromFilePath(filePath, defaultDirectory) {
const filePathWithoutMetadataExt = PathUtil.removeMetadataFileExtFrom(filePath);
let pathName = path.dirname(filePathWithoutMetadataExt);
let bundleName = path.basename(pathName);
const fileName = path.basename(filePathWithoutMetadataExt);
let fullName = path.join(bundleName, fileName);
// Walk back up directory structure to build fullName to include subfolder hierarchy within the fullName
const findPath = () => {
pathName = path.dirname(pathName);
bundleName = path.basename(pathName);
fullName = path.join(bundleName, fullName);
};
guardedWhile(() => !(path.basename(path.dirname(pathName)) === defaultDirectory), findPath);
return fullName;
}
static scanFilePathForAggregateFullName(filePath, defaultDirectory) {
const parsedFilePath = path.parse(filePath);
// If the filePath is the bundle dir, return that
if (path.basename(parsedFilePath.dir) === defaultDirectory && parsedFilePath.ext === '') {
return parsedFilePath.name;
}
const pathArray = parsedFilePath.dir.split(path.sep);
const defaultDirIndex = pathArray.lastIndexOf(defaultDirectory);
// Return undefined if the defaultDirectory is not in the filePath, or if we find it but
// there's no bundle name directory (unlikely, but guards against array index out of bounds).
if (defaultDirIndex === -1 || defaultDirIndex + 1 > pathArray.length) {
return;
}
// Return the bundle name from the filePath
return pathArray[defaultDirIndex + 1];
}
static getAllNestedBundleContentPaths(bundleDirPath, forceIgnore) {
const bundlePaths = glob.sync(path.join(bundleDirPath, '**'), {
nodir: true,
});
return Promise.resolve(bundlePaths
.map((bundlePath) => PathUtil.replaceForwardSlashes(bundlePath))
.filter((bundlePath) => forceIgnore.accepts(bundlePath) && !bundlePath.endsWith(MetadataRegistry.getMetadataFileExt())));
}
static getExtendedBundlePath(fileName, bundleName) {
// Is there a nested directory or directories; if so this takes the full file name and
// returns the directory path between the file and bundleName
let extendedPath;
if (fileName && fileName.includes(bundleName)) {
let nestedDir = path.dirname(fileName);
let nestedDirName = path.basename(nestedDir);
const findPath = () => {
if (extendedPath) {
extendedPath = path.join(nestedDirName, extendedPath);
}
else {
extendedPath = nestedDirName;
}
nestedDir = path.dirname(nestedDir);
nestedDirName = path.basename(nestedDir);
};
guardedWhile(() => nestedDirName !== bundleName, findPath);
}
return extendedPath;
}
}
exports.BundlePathHelper = BundlePathHelper;
//# sourceMappingURL=bundlePathHelper.js.map