@salesforce/source-tracking
Version:
API for tracking local and remote Salesforce metadata changes
114 lines • 6.31 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.registrySupportsType = exports.mappingsForSourceMemberTypesToMetadataType = exports.getMetadataKeyFromFileResponse = void 0;
/*
* Copyright 2025, Salesforce, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const node_path_1 = require("node:path");
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
const lifecycle_1 = require("@salesforce/core/lifecycle");
const functions_1 = require("./functions");
// See UT for examples of the complexity this must handle
// keys always use forward slashes, even on Windows
const pathAfterFullName = (fileResponse) => fileResponse?.filePath
? (0, node_path_1.join)((0, node_path_1.dirname)(fileResponse.filePath).substring((0, node_path_1.dirname)(fileResponse.filePath).lastIndexOf(fileResponse.fullName)), (0, node_path_1.basename)(fileResponse.filePath)).replace(/\\/gi, '/')
: '';
const registryAccess = new source_deploy_retrieve_1.RegistryAccess();
// only compute once
const aliasTypes = registryAccess
.getAliasTypes()
// allow assertion because aliasTypes are defined as having that property
.map((aliasType) => [aliasType.name, registryAccess.getTypeByName(aliasType.aliasFor).name]);
const reverseAliasTypes = new Map(aliasTypes.map(([alias, type]) => [type, alias]));
// handle all "weird" type/name translation between SourceMember and SDR FileResponse
// These get de-duplicated in a set later, so it's ok to have one per file
const getMetadataKeyFromFileResponse = (fileResponse) => {
// also create an element for the parent object
if (fileResponse.type === 'CustomField' && fileResponse.filePath) {
const splits = (0, node_path_1.normalize)(fileResponse.filePath).split(node_path_1.sep);
const objectFolderIndex = splits.indexOf('objects');
return [
(0, functions_1.getMetadataKey)('CustomObject', splits[objectFolderIndex + 1]),
(0, functions_1.getMetadataKey)(fileResponse.type, fileResponse.fullName),
];
}
// Aura/LWC need to have both the bundle level and file level keys
if (fileResponse.type === 'LightningComponentBundle' && fileResponse.filePath) {
return [
(0, functions_1.getMetadataKey)('LightningComponentResource', pathAfterFullName(fileResponse)),
(0, functions_1.getMetadataKey)(fileResponse.type, fileResponse.fullName),
];
}
if (fileResponse.type === 'AuraDefinitionBundle' && fileResponse.filePath) {
return [
(0, functions_1.getMetadataKey)('AuraDefinition', pathAfterFullName(fileResponse)),
(0, functions_1.getMetadataKey)(fileResponse.type, fileResponse.fullName),
];
}
// CustomLabels (file) => CustomLabel[] (how they're stored in SourceMembers)
if (fileResponse.type === 'CustomLabels' && fileResponse.filePath) {
return source_deploy_retrieve_1.ComponentSet.fromSource(fileResponse.filePath)
.getSourceComponents()
.toArray()
.flatMap((component) => component.getChildren().map((child) => (0, functions_1.getMetadataKey)('CustomLabel', child.fullName)));
}
// if we've aliased a type, we'll have to possibly sync both types--you can't tell from the sourceComponent retrieved which way it was stored on the server
if (reverseAliasTypes.has(fileResponse.type)) {
return [
(0, functions_1.getMetadataKey)(fileResponse.type, fileResponse.fullName),
(0, functions_1.getMetadataKey)(reverseAliasTypes.get(fileResponse.type), fileResponse.fullName),
];
}
// standard key for everything else
return [(0, functions_1.getMetadataKey)(fileResponse.type, fileResponse.fullName)];
};
exports.getMetadataKeyFromFileResponse = getMetadataKeyFromFileResponse;
exports.mappingsForSourceMemberTypesToMetadataType = new Map([
...aliasTypes,
['AuraDefinition', 'AuraDefinitionBundle'],
['LightningComponentResource', 'LightningComponentBundle'],
]);
const registrySupportsType = (registry = new source_deploy_retrieve_1.RegistryAccess()) => (type) => {
if (exports.mappingsForSourceMemberTypesToMetadataType.has(type)) {
return true;
}
if (type === 'PicklistValue') {
/* "PicklistValue" appears occasionally in sourceMembers, but it's not a real, addressable type in the registry
* It only appears when a picklist value is reactivated, so I'd call this a SourceMember bug
* We also can't make it a child type in the SDR registry because it it can be a parent of either CustomField/Picklist OR GlobalValueSet
* in both parent cases (GVS and CustomField), the the parent is marked as changed in SourceMembers, to the behavior is ok igoring the PicklistValue
* This suppresses the warning, and could be removed if the SourceMember bug is fixed
*/
return false;
}
if (type === 'ExperienceResource') {
/* ExperienceResource is a child of ExperienceBundle but fine-grained source tracking isn't supported for
* ExperienceBundle since it's not defined that way in the SDR registry. Since ExperienceBundle is
* essentially deprecated in favor of DigitalExperienceBundle this is not something we're going to support.
*/
return false;
}
try {
// this must use getTypeByName because findType doesn't support addressable child types (ex: customField!)
registry.getTypeByName(type);
return true;
}
catch (e) {
void lifecycle_1.Lifecycle.getInstance().emitWarning(`Unable to find type ${type} in registry`);
return false;
}
};
exports.registrySupportsType = registrySupportsType;
//# sourceMappingURL=metadataKeys.js.map
;