UNPKG

@salesforce/source-deploy-retrieve

Version:

JavaScript library to run Salesforce metadata deploys and retrieves

142 lines 6.39 kB
"use strict"; /* * 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