@salesforce/source-deploy-retrieve
Version:
JavaScript library to run Salesforce metadata deploys and retrieves
142 lines • 6.39 kB
JavaScript
/*
* Copyright (c) 2023, 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.shouldConvertPaths = exports.toKey = exports.isComponentNotFoundWarningMessage = exports.getState = exports.getDeployMessages = exports.createResponses = exports.sanitizeDeployMessage = void 0;
const posix_1 = require("node:path/posix");
const core_1 = require("@salesforce/core");
const kit_1 = require("@salesforce/kit");
const registry_1 = require("../registry/registry");
const types_1 = require("./types");
const diagnosticUtil_1 = require("./diagnosticUtil");
/**
* Fix any issues with the deploy message returned by the api.
* TODO: remove cases if fixes are made in the api.
*/
const sanitizeDeployMessage = (message) => {
if (!hasComponentType(message)) {
throw new core_1.SfError(`Missing componentType in deploy message ${message.fullName} ${message.fileName}`);
}
// mdapi error messages have the type as "FooSettings" but SDR only recognizes "Settings"
if (message.componentType.endsWith('Settings') && message.fileName.endsWith('.settings')) {
return {
...message,
componentType: 'Settings',
};
}
if (message.componentType === registry_1.registry.types.lightningcomponentbundle.name) {
return {
...message,
fullName: message.fullName.replace(/markup:\/\/[a-z|0-9|_]+:/i, ''),
};
}
if (message.componentType === registry_1.registry.types.document.name) {
return {
...message,
// strip document extension from fullName
fullName: (0, posix_1.join)((0, posix_1.dirname)(message.fullName), (0, posix_1.basename)(message.fullName, (0, posix_1.extname)(message.fullName))),
};
}
// Treat emailTemplateFolder as EmailFolder
if (message.componentType === registry_1.registry.types.emailtemplatefolder.name) {
return {
...message,
// strip document extension from fullName
componentType: registry_1.registry.types.emailfolder.name,
};
}
return message;
};
exports.sanitizeDeployMessage = sanitizeDeployMessage;
// components with children are already taken care of through the messages, so don't walk their content directories.
const shouldWalkContent = (component) => typeof component.content === 'string' &&
(!component.type.children ||
Object.values(component.type.children.types).some((t) => t.unaddressableWithoutParent === true || t.isAddressable === false));
const createResponses = (component, responseMessages) => responseMessages.flatMap((message) => {
const state = (0, exports.getState)(message);
const base = { fullName: component.fullName, type: component.type.name };
if (state === types_1.ComponentStatus.Failed) {
return [{ ...base, state, ...(0, diagnosticUtil_1.parseDeployDiagnostic)(component, message) }];
}
else {
return [
...(shouldWalkContent(component)
? component.walkContent().map((filePath) => ({ ...base, state, filePath }))
: []),
...(component.xml ? [{ ...base, state, filePath: component.xml }] : []),
];
}
});
exports.createResponses = createResponses;
/**
* Groups messages from the deploy result by component fullName and type
*/
const getDeployMessages = (result) => {
const messageMap = new Map();
const failedComponentKeys = new Set();
const failureMessages = (0, kit_1.ensureArray)(result.details.componentFailures);
const successMessages = (0, kit_1.ensureArray)(result.details.componentSuccesses);
for (const failure of failureMessages) {
const sanitized = (0, exports.sanitizeDeployMessage)(failure);
const componentLike = {
fullName: sanitized.fullName,
type: sanitized.componentType,
};
const key = (0, exports.toKey)(componentLike);
if (!messageMap.has(key)) {
messageMap.set(key, []);
}
messageMap.get(key)?.push(sanitized);
failedComponentKeys.add(key);
}
for (const success of successMessages) {
const sanitized = (0, exports.sanitizeDeployMessage)(success);
const componentLike = {
fullName: sanitized.fullName,
type: sanitized.componentType,
};
const key = (0, exports.toKey)(componentLike);
// this will ensure successes aren't reported if there is a failure for
// the same component. e.g. lwc returns failures and successes
if (!failedComponentKeys.has(key)) {
messageMap.set(key, [sanitized]);
}
}
return messageMap;
};
exports.getDeployMessages = getDeployMessages;
const getState = (message) => {
if (isTrue(message.created)) {
return types_1.ComponentStatus.Created;
}
else if (isTrue(message.changed)) {
return types_1.ComponentStatus.Changed;
}
else if (isTrue(message.deleted)) {
return types_1.ComponentStatus.Deleted;
}
else if (!isTrue(message.success)) {
return types_1.ComponentStatus.Failed;
}
return types_1.ComponentStatus.Unchanged;
};
exports.getState = getState;
/* Type guard for asserting that a DeployMessages has a componentType, problem, and problemType === Warning*/
const isComponentNotFoundWarningMessage = (message) => hasComponentType(message) &&
message.problemType === 'Warning' &&
typeof message.problem === 'string' &&
message.problem?.startsWith(`No ${message.componentType} named: `);
exports.isComponentNotFoundWarningMessage = isComponentNotFoundWarningMessage;
const hasComponentType = (message) => typeof message.componentType === 'string';
const toKey = (component) => {
const type = typeof component.type === 'string' ? component.type : component.type.name;
return `${type}#${exports.shouldConvertPaths ? component.fullName.split(posix_1.sep).join(posix_1.posix.sep) : component.fullName}`;
};
exports.toKey = toKey;
const isTrue = (value) => value === 'true' || value === true;
exports.shouldConvertPaths = posix_1.sep !== posix_1.posix.sep;
//# sourceMappingURL=deployMessages.js.map
;