@salesforce/source-deploy-retrieve
Version:
JavaScript library to run Salesforce metadata deploys and retrieves
132 lines • 12.7 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefaultMetadataTransformer = 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 node_path_1 = require("node:path");
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_2 = require("node:path");
const messages_1 = require("@salesforce/core/messages");
const lifecycle_1 = require("@salesforce/core/lifecycle");
const constants_1 = require("../../common/constants");
const path_1 = require("../../utils/path");
const replacements_1 = require("../replacements");
const baseMetadataTransformer_1 = require("./baseMetadataTransformer");
const ORIGINAL_SUFFIX_REGEX = new RegExp('(.)([a-zA-Z]+)(' + constants_1.META_XML_SUFFIX + ')$');
/**
* The default metadata transformer.
*
* If a metadata type doesn't have a transformer assigned to it, this one is used
* during the conversion process. It leaves the component's metadata xml and source
* files as-is.
*/
class DefaultMetadataTransformer extends baseMetadataTransformer_1.BaseMetadataTransformer {
// eslint-disable-next-line @typescript-eslint/require-await, class-methods-use-this
async toMetadataFormat(component) {
return getWriteInfos(component, 'metadata');
}
// eslint-disable-next-line @typescript-eslint/require-await, class-methods-use-this
async toSourceFormat({ component, mergeWith, }) {
return getWriteInfos(component, 'source', mergeWith);
}
}
exports.DefaultMetadataTransformer = DefaultMetadataTransformer;
const getWriteInfos = (component, targetFormat, mergeWith) => component
.walkContent()
.map((path) => ({
source: (0, replacements_1.getReplacementStreamForReadable)(component, path),
output: getContentSourceDestination(path, targetFormat, component, mergeWith),
}))
.concat(component.xml
? [
{
source: (0, replacements_1.getReplacementStreamForReadable)(component, component.xml),
output: getXmlDestination(targetFormat, component, mergeWith),
},
]
: []);
// assumes component has content
const getContentSourceDestination = (source, targetFormat, component, mergeWith) => {
if (mergeWith?.content) {
if (component.content && component.tree.isDirectory(component.content)) {
// DEs are always inside a dir.
if (component.type.strategies?.adapter === 'digitalExperience') {
const parts = source.split(node_path_2.sep);
const file = parts.pop() ?? '';
const dir = (0, node_path_1.join)(mergeWith.content, parts.pop() ?? '');
if (source.endsWith('content.json') ||
source.endsWith('_meta.json') ||
!(node_fs_1.default.existsSync(dir) && node_fs_1.default.statSync(dir).isDirectory())) {
return (0, node_path_1.join)(mergeWith.content, (0, node_path_1.basename)(source));
}
else {
// if a directory exists with the same name as source, merge into there
return (0, node_path_1.join)(dir, file);
}
}
else {
const relative = (0, path_1.trimUntil)(source, (0, node_path_1.basename)(component.content));
return (0, node_path_1.join)((0, node_path_1.dirname)(mergeWith.content), relative);
}
}
return mergeWith.content;
}
return component.getPackageRelativePath(source, targetFormat);
};
// assumes component has xml
const getXmlDestination = (targetFormat, component, mergeWith) => {
if (mergeWith?.xml && targetFormat === 'source') {
return mergeWith.xml;
}
const { folderContentType, suffix, legacySuffix } = component.type;
if (!component.xml) {
;
const messages = new messages_1.Messages('@salesforce/source-deploy-retrieve', 'sdr', new Map([["md_request_fail", "Metadata API request failed: %s"], ["error_convert_invalid_format", "Invalid conversion format '%s'"], ["error_could_not_infer_type", "%s: Could not infer a metadata type"], ["error_unexpected_child_type", "Unexpected child metadata [%s] found for parent type [%s]"], ["noParent", "Could not find parent type for %s (%s)"], ["error_expected_source_files", "%s: Expected source files for type '%s'"], ["error_failed_convert", "Component conversion failed: %s"], ["error_merge_metadata_target_unsupported", "Merge convert for metadata target format currently unsupported"], ["error_missing_adapter", "Missing adapter '%s' for metadata type '%s'"], ["error_missing_transformer", "Missing transformer '%s' for metadata type '%s'"], ["error_missing_type_definition", "Missing metadata type definition in registry for id '%s'."], ["error_missing_child_type_definition", "Type %s does not have a child type definition %s."], ["noChildTypes", "No child types found in registry for %s (reading %s at %s)"], ["error_no_metadata_xml_ignore", "Metadata xml file %s is forceignored but is required for %s."], ["noSourceIgnore", "%s metadata types require source files, but %s is forceignored."], ["noSourceIgnore.actions", "- Metadata types with content are composed of two files: a content file (ie MyApexClass.cls) and a -meta.xml file (i.e MyApexClass.cls-meta.xml). You must include both files in your .forceignore file. Or try appending \u201C\\*\u201D to your existing .forceignore entry.\n\nSee <https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm> for examples"], ["error_path_not_found", "%s: File or folder not found"], ["noContentFound", "SourceComponent %s (metadata type = %s) is missing its content file."], ["noContentFound.actions", ["Ensure the content file exists in the expected location.", "If the content file is in your .forceignore file, ensure the meta-xml file is also ignored to completely exclude it."]], ["error_parsing_xml", "SourceComponent %s (metadata type = %s) does not have an associated metadata xml to parse"], ["error_expected_file_path", "%s: path is to a directory, expected a file"], ["error_expected_directory_path", "%s: path is to a file, expected a directory"], ["error_directory_not_found_or_not_directory", "%s: path is not a directory"], ["error_no_directory_stream", "%s doesn't support readable streams on directories."], ["error_no_source_to_deploy", "No source-backed components present in the package."], ["error_no_components_to_retrieve", "No components in the package to retrieve."], ["error_static_resource_expected_archive_type", "A StaticResource directory must have a content type of application/zip or application/jar - found %s for %s."], ["error_static_resource_missing_resource_file", "A StaticResource must have an associated .resource file, missing %s.resource-meta.xml"], ["error_no_job_id", "The %s operation is missing a job ID. Initialize an operation with an ID, or start a new job."], ["missingApiVersion", "Could not determine an API version to use for the generated manifest. Tried looking for sourceApiVersion in sfdx-project.json, apiVersion from config vars, and the highest apiVersion from the APEX REST endpoint. Using API version 58.0 as a last resort."], ["invalid_xml_parsing", "error parsing %s due to:\\n message: %s\\n line: %s\\n code: %s"], ["zipBufferError", "Zip buffer was not created during conversion"], ["undefinedComponentSet", "Unable to construct a componentSet. Check the logs for more information."], ["replacementsFileNotRead", "The file \"%s\" specified in the \"replacements\" property of sfdx-project.json could not be read."], ["unsupportedBundleType", "Unsupported Bundle Type: %s"], ["filePathGeneratorNoTypeSupport", "Type not supported for filepath generation: %s"], ["missingFolderType", "The registry has %s as is inFolder but it does not have a folderType"], ["tooManyFiles", "Multiple files found for path: %s."], ["cantGetName", "Unable to calculate fullName from path: %s (%s)"], ["missingMetaFileSuffix", "The metadata registry is configured incorrectly for %s. Expected a metaFileSuffix."], ["uniqueIdElementNotInRegistry", "No uniqueIdElement found in registry for %s (reading %s at %s)."], ["uniqueIdElementNotInChild", "The uniqueIdElement %s was not found the child (reading %s at %s)."], ["suggest_type_header", "A metadata type lookup for \"%s\" found the following close matches:"], ["suggest_type_did_you_mean", "-- Did you mean \".%s%s\" instead for the \"%s\" metadata type?"], ["suggest_type_more_suggestions", "Additional suggestions:\nConfirm the file name, extension, and directory names are correct. Validate against the registry at:\n<https://github.com/forcedotcom/source-deploy-retrieve/blob/main/src/registry/metadataRegistry.json>\n\nIf the type is not listed in the registry, check that it has Metadata API support via the Metadata Coverage Report:\n<https://developer.salesforce.com/docs/metadata-coverage>\n\nIf the type is available via Metadata API but not in the registry\n\n- Open an issue <https://github.com/forcedotcom/cli/issues>\n- Add the type via PR. Instructions: <https://github.com/forcedotcom/source-deploy-retrieve/blob/main/contributing/metadata.md>"], ["type_name_suggestions", "Confirm the metadata type name is correct. Validate against the registry at:\n<https://github.com/forcedotcom/source-deploy-retrieve/blob/main/src/registry/metadataRegistry.json>\n\nIf the type is not listed in the registry, check that it has Metadata API support via the Metadata Coverage Report:\n<https://developer.salesforce.com/docs/metadata-coverage>\n\nIf the type is available via Metadata API but not in the registry\n\n- Open an issue <https://github.com/forcedotcom/cli/issues>\n- Add the type via PR. Instructions: <https://github.com/forcedotcom/source-deploy-retrieve/blob/main/contributing/metadata.md>"]]));
throw messages.createError('error_parsing_xml', [component.fullName, component.type.name]);
}
let xmlDestination = component.getPackageRelativePath(component.xml, targetFormat);
// quirks:
// - append or strip the -meta.xml suffix to the path if there's no content and if it's not DigitalExperienceBundle
// for folder components:
// - remove file extension but preserve -meta.xml suffix if folder type and to 'metadata format'
// - insert file extension behind the -meta.xml suffix if folder type and to 'source format'
if (!component.content && !['digitalexperiencebundle'].includes(component.type.id)) {
if (targetFormat === 'metadata') {
if (folderContentType) {
xmlDestination = xmlDestination.replace(`.${suffix ?? ''}`, '');
}
else if (xmlDestination.includes(constants_1.META_XML_SUFFIX)) {
xmlDestination = xmlDestination.slice(0, xmlDestination.lastIndexOf(constants_1.META_XML_SUFFIX));
}
else {
void lifecycle_1.Lifecycle.getInstance().emitWarning(`Found a file (${xmlDestination}) that appears to be in metadata format, but the directory it's in is for source formatted files.`);
}
}
else {
xmlDestination = folderContentType
? xmlDestination.replace(constants_1.META_XML_SUFFIX, `.${suffix ?? ''}${constants_1.META_XML_SUFFIX}`)
: `${xmlDestination}${constants_1.META_XML_SUFFIX}`;
}
}
else if (suffix) {
if (component.type.name === 'Document' && targetFormat === 'metadata' && component.content) {
xmlDestination = xmlDestination.replace(new RegExp('.' + suffix + constants_1.META_XML_SUFFIX + '$'), '.' + (0, path_1.extName)(component.content) + constants_1.META_XML_SUFFIX);
}
else {
xmlDestination = xmlDestination.replace(ORIGINAL_SUFFIX_REGEX, '.' + suffix + constants_1.META_XML_SUFFIX);
}
}
if (legacySuffix && suffix && xmlDestination.includes(legacySuffix)) {
void lifecycle_1.Lifecycle.getInstance().emitWarning(`The ${component.type.name} component ${component.fullName} uses the legacy suffix ${legacySuffix}. This suffix is deprecated and will be removed in a future release.`);
xmlDestination = xmlDestination.replace(legacySuffix, suffix);
}
return xmlDestination;
};
//# sourceMappingURL=defaultMetadataTransformer.js.map
;