UNPKG

@salesforce/source-deploy-retrieve

Version:

JavaScript library to run Salesforce metadata deploys and retrieves

146 lines 6.29 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 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.fnJoin = exports.calculateRelativePath = void 0; exports.baseName = baseName; exports.baseWithoutSuffixes = baseWithoutSuffixes; exports.extName = extName; exports.parentName = parentName; exports.trimUntil = trimUntil; exports.parseMetadataXml = parseMetadataXml; exports.parseNestedFullName = parseNestedFullName; const node_path_1 = require("node:path"); const constants_1 = require("../common/constants"); /** * Get the file or directory name at the end of a path. Different from `path.basename` * in that it strips anything after the first '.' in the name. * * @param fsPath The path to evaluate */ function baseName(fsPath) { return (0, node_path_1.basename)(fsPath).split('.')[0]; } /** * the above baseName function doesn't handle components whose names have a `.` in them. * this will handle that, but requires you to specify the mdType to check suffixes for. * * @param fsPath The path to evaluate */ function baseWithoutSuffixes(fsPath, mdType) { return (0, node_path_1.basename)(fsPath).replace(constants_1.META_XML_SUFFIX, '').split('.').filter(stringIsNotSuffix(mdType)).join('.'); } const stringIsNotSuffix = (type) => (part) => part !== type.suffix && (!type.legacySuffix || part !== type.legacySuffix); /** * Get the name of file path extension. Different from path.extname in that it * does not include the '.' in the extension name. Returns an empty string if * there is no extension. * * @param fsPath The path to evaluate */ function extName(fsPath) { const split = (0, node_path_1.extname)(fsPath).split('.'); return split.length > 1 ? split[1] : split[0]; } /** * Get the name of the parent to the last portion of a path * * @param fsPath The path to evaluate */ function parentName(fsPath) { return (0, node_path_1.basename)((0, node_path_1.dirname)(fsPath)); } /** * Trim a path up until and including the given part. Returns `fsPath` * if the path `part` was not found. * * @param fsPath Path to trim * @param part Path part to trim up until * @param untilLast Trim until the *last* occurrence of `part` */ function trimUntil(fsPath, part, untilLast = false) { const parts = fsPath.split(node_path_1.sep); const partIndex = untilLast ? parts.lastIndexOf(part) : parts.findIndex((p) => part === p); if (partIndex === -1) { return fsPath; } return parts.slice(partIndex).join(node_path_1.sep); } /** * Returns the `MetadataXml` info from a given file path. If the path is not a * metadata xml file (-meta.xml), returns `undefined`. * * @param fsPath - File path to parse * @returns MetadataXml info or undefined */ function parseMetadataXml(fsPath) { const match = new RegExp(/(.+)\.(.+)-meta\.xml/).exec((0, node_path_1.basename)(fsPath)); if (match) { return { fullName: match[1], suffix: match[2], path: fsPath }; } } /** * Returns the fullName for a nested metadata source file. This is for metadata * types that can be nested more than 1 level such as report and reportFolder, * dashboard and dashboardFolder, etc. It uses the directory name for the metadata type * as the starting point (non-inclusively) to parse the fullName. * * Examples: * (source format path) * fsPath: force-app/main/default/reports/foo/bar/My_Report.report-meta.xml * returns: foo/bar/My_Report * * (mdapi format path) * fsPath: unpackaged/reports/foo/bar-meta.xml * returns: foo/bar * * @param fsPath - File path to parse * @param directoryName - name of directory to use as a parsing index * @returns the FullName */ function parseNestedFullName(fsPath, directoryName) { const pathSplits = fsPath.split(node_path_1.sep); // Exit if the directoryName is not included in the file path. if (!pathSplits.includes(directoryName)) { return; } const pathPrefix = pathSplits.slice(pathSplits.lastIndexOf(directoryName) + 1); // the eslint comment should remain until strictMode is fully implemented // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion const fileName = pathSplits.pop().replace('-meta.xml', '').split('.')[0]; pathPrefix[pathPrefix.length - 1] = fileName; return pathPrefix.join('/'); } const calculateRelativePath = (format) => (types) => (fullName) => (fsPath) => { const base = format === 'source' ? constants_1.DEFAULT_PACKAGE_ROOT_SFDX : ''; const { directoryName, suffix, inFolder, folderType, folderContentType } = types.self; // if there isn't a suffix, assume this is a mixed content component that must // reside in the directoryName of its type. trimUntil maintains the folder structure // the file resides in for the new destination. This also applies to inFolder types: // (report, dashboard, emailTemplate, document) and their folder container types: // (reportFolder, dashboardFolder, emailFolder, documentFolder) // It also applies to DigitalExperienceBundle types as we need to maintain the folder structure if (!suffix || Boolean(inFolder) || typeof folderContentType === 'string' || ['digitalexperiencebundle', 'digitalexperience'].includes(types.self.id)) { return (0, node_path_1.join)(base, trimUntil(fsPath, directoryName, true)); } if (folderType) { // types like Territory2Model have child types inside them. We have to preserve those folder structures if (types.parentType?.folderType && types.parentType?.folderType !== types.self.id) { return (0, node_path_1.join)(base, trimUntil(fsPath, types.parentType.directoryName)); } return (0, node_path_1.join)(base, directoryName, fullName.split('/')[0], (0, node_path_1.basename)(fsPath)); } return (0, node_path_1.join)(base, directoryName, (0, node_path_1.basename)(fsPath)); }; exports.calculateRelativePath = calculateRelativePath; /** (a)(b)=> a/b */ const fnJoin = (a) => (b) => (0, node_path_1.join)(a, b); exports.fnJoin = fnJoin; //# sourceMappingURL=path.js.map