UNPKG

salesforce-alm

Version:

This package contains tools, and APIs, for an improved salesforce.com developer experience.

204 lines (202 loc) 9.17 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 */ // Node const path = require("path"); const util = require("util"); const core_1 = require("@salesforce/core"); // Thirdparty const optional = require("optional-js"); const BBPromise = require("bluebird"); const _ = require("lodash"); // Local const logApi = require("../core/logApi"); const almError = require("../core/almError"); const MetadataRegistry = require("./metadataRegistry"); const metadataTypeFactory_1 = require("./metadataTypeFactory"); const Builder = require('fast-xml-parser').j2xParser; function createOutputXmlManifestFile(fileName, packageManifestJson) { const builder = new Builder({ format: true, attrNodeName: '$', }); const xmlDeclaration = '<?xml version="1.0" encoding="UTF-8"?>\n'; const xml = xmlDeclaration.concat(builder.parse(packageManifestJson)).trim(); return core_1.fs.writeFile(fileName, xml).then(() => ({ file: fileName, manifest: packageManifestJson, })); } function generateMetadataManifestJson(packageName, typesAsKeyValuePairsArray, apiVersion) { const MdapiPackage = require('./mdapiPackage'); // eslint-disable-line global-require const mdPackage = new MdapiPackage(); mdPackage.setVersion(apiVersion); if (!util.isNullOrUndefined(packageName)) { mdPackage.setPackageName(packageName); } typesAsKeyValuePairsArray.forEach((typeNamePair) => { mdPackage.addMember(typeNamePair.name, typeNamePair.type); }); return mdPackage.getPackage(); } function processMetadataFile(dir, file, childLogger, metadataRegistry) { const filePath = path.resolve(dir, file); const metadataType = metadataTypeFactory_1.MetadataTypeFactory.getMetadataTypeFromSourcePath(filePath, metadataRegistry); let fileInfo = null; if (metadataType) { const fullName = metadataType.getAggregateFullNameFromFilePath(filePath); if (!util.isNullOrUndefined(fullName)) { fileInfo = { type: metadataType.getMetadataName(), name: fullName }; } } if (fileInfo === null) { childLogger.info(`WARNING: Error parsing metadata file. Ignoring - ${filePath}`); } return BBPromise.resolve(fileInfo); } function readMetadataDirectoryContent(dir) { return core_1.fs .readdir(dir) .then((files) => BBPromise.map(files, (file) => core_1.fs.stat(path.resolve(dir, file)).then((stats) => ({ name: file, isDirectory: stats.isDirectory(), })))) .then((fileInfoArray) => { const dirContent = { metadataFiles: [], dirs: [] }; fileInfoArray.forEach((fileInfo) => { if (fileInfo.isDirectory) { dirContent.dirs.push(fileInfo.name); } else if (fileInfo.name.endsWith(MetadataRegistry.getMetadataFileExt())) { dirContent.metadataFiles.push(fileInfo.name); } }); return dirContent; }); } function processMetadataDirectory(dir, childLogger, metadataRegistry, manifestcreate) { return readMetadataDirectoryContent(dir) .then((entriesToBeProcessed) => BBPromise.map(entriesToBeProcessed.metadataFiles, (file) => processMetadataFile(dir, file, childLogger, metadataRegistry)).then((resultFromFiles) => BBPromise.all([ resultFromFiles, BBPromise.map(entriesToBeProcessed.dirs, (childDir) => processMetadataDirectory(path.resolve(dir, childDir), childLogger, metadataRegistry, manifestcreate)), ]))) .then((resultAsKeyValuePairs) => { // Flatten result from previous step which contains multi-level arrays due // to the way promise combines results from files in current directory and files // in child directory. const elementsToProcess = []; const flattenedResultObj = []; elementsToProcess.push(resultAsKeyValuePairs); while (elementsToProcess.length > 0) { const nextElement = elementsToProcess[0]; if (Array.isArray(nextElement)) { if (nextElement.length > 0) { for (const element of nextElement) { if (element) { elementsToProcess.push(element); } } } } else if (nextElement) { flattenedResultObj.push(nextElement); } elementsToProcess.shift(); } return flattenedResultObj; }); } /** * API object to create manifest file. * * @constructor */ const manifestCreate = function (org, beforeManifestGenerationHook) { this.org = org; this.config = this.org.config; this.apiVersion = this.config.getAppConfig().sourceApiVersion; this.logger = logApi.child('manifest-create'); this._fsStat = core_1.fs.stat; this._fsMkdir = core_1.fs.mkdirp; this.beforeManifestGenerationHook = beforeManifestGenerationHook; }; manifestCreate.prototype.execute = function execute(context) { const projectDirectory = this.config.getProjectPath(); const appConfig = this.config.getAppConfig(); // use defaultArtifact which is root dir of source (if set, prepend project dir) const defaultSourceDirectory = !util.isNullOrUndefined(appConfig.defaultPackagePath) ? path.join(projectDirectory, appConfig.defaultPackagePath) : projectDirectory; const rootDirectory = optional.ofNullable(context.sourcedir).orElse(defaultSourceDirectory); this.outputDirectory = optional.ofNullable(context.outputdir).orElse(projectDirectory); const outputFile = path.resolve(this.outputDirectory, 'package.xml'); const apiVersion = this.apiVersion; return this._validateDirectory(rootDirectory, almError('InvalidArgumentDirectoryPath', ['sourcedir', rootDirectory])) .then(() => this._createDirIfNotExists(this.outputDirectory)) .then(() => this._validateDirectory(this.outputDirectory, almError('InvalidArgumentDirectoryPath', ['outputdir', this.outputDirectory]))) .then(() => { this.metadataRegistry = new MetadataRegistry(); return processMetadataDirectory(rootDirectory, this.logger, this.metadataRegistry); }) .then((resultAsKeyValuePairs) => { if (this.beforeManifestGenerationHook) { resultAsKeyValuePairs = this.beforeManifestGenerationHook(resultAsKeyValuePairs); } if (context.exclusions) { resultAsKeyValuePairs = resultAsKeyValuePairs.filter((element) => _.isNil(context.exclusions.find((exclusion) => exclusion.type === element.type && exclusion.name === element.name))); } const packageManifestJson = generateMetadataManifestJson(context.packageName, resultAsKeyValuePairs, apiVersion); return createOutputXmlManifestFile(outputFile, packageManifestJson); }); }; manifestCreate.prototype.createManifest = function (context, packageName, typeFullNamePairs) { const outputDir = optional.ofNullable(context.outputdir).orElse(this.config.getProjectPath()); const outputFile = path.resolve(outputDir, optional.ofNullable(context.outputfile).orElse('package.xml')); const sourceApiVersion = !util.isNullOrUndefined(context.sourceApiVersion) ? context.sourceApiVersion : this.apiVersion; const packageManifestJson = generateMetadataManifestJson(packageName, typeFullNamePairs, sourceApiVersion); return createOutputXmlManifestFile(outputFile, packageManifestJson); }; /** * Creates an mdapi compatible package.xml manifest from an mdapiPackage * * @param {object} context - looking for context.outputdir; location for writing the package.xml * @param {object} mdapiPackage - The mdapi package */ manifestCreate.prototype.createManifestForMdapiPackage = function (context, mdapiPackage, metadataRegistry) { const outputFile = path.resolve(optional.ofNullable(context.outputdir).orElse(this.config.getProjectPath()), 'package.xml'); return createOutputXmlManifestFile(outputFile, mdapiPackage.getPackage(metadataRegistry)); }; manifestCreate.prototype._validateDirectory = function (dir, failWithErr) { return this._fsStat(dir) .then((dirStats) => { if (!dirStats.isDirectory()) { return BBPromise.reject(failWithErr); } return BBPromise.resolve(); }) .catch((err) => { if (err.code === 'ENOENT') { return BBPromise.reject(almError('PathDoesNotExist', dir)); } return BBPromise.reject(err); }); }; manifestCreate.prototype._createDirIfNotExists = function (dir) { return (this._fsStat(dir) // eslint-disable-next-line @typescript-eslint/no-empty-function .then(() => { }) .catch((err) => { if (err.code === 'ENOENT') { return this._fsMkdir(dir); } return BBPromise.reject(err); })); }; module.exports = manifestCreate; //# sourceMappingURL=manifestCreateApi.js.map