UNPKG

@dxatscale/sfprofiles

Version:
350 lines (324 loc) 16.4 kB
import * as path from 'path'; import { MetadataInfo, METADATA_INFO, MetadataDescribe, SOURCE_EXTENSION_REGEX } from './metadataInfo'; import FileUtils from 'utils/fileutils'; import _ from 'lodash'; import ignore from 'ignore'; import * as fs from 'fs-extra'; import * as glob from 'glob'; import { Sfpowerkit } from 'utils/sfpowerkit'; import SFPLogger, {LoggerLevel } from '@dxatscale/sfp-logger'; const SEP = /\/|\\/; export default class MetadataFiles { public static sourceOnly = false; forceignore: any; public constructor() { if (fs.existsSync('.forceignore')) { this.forceignore = ignore().add(fs.readFileSync('.forceignore', 'utf8').toString()); } else { this.forceignore = ignore(); } } static getFullApiName(fileName: string): string { let fullName = ''; let metadateType = MetadataInfo.getMetadataName(fileName); let splitFilepath = fileName.split(SEP); let isObjectChild = METADATA_INFO.CustomObject.childXmlNames.includes(metadateType); if (isObjectChild) { let objectName = splitFilepath[splitFilepath.length - 3]; let fieldName = splitFilepath[splitFilepath.length - 1].split('.')[0]; fullName = objectName.concat('.' + fieldName); } else { fullName = splitFilepath[splitFilepath.length - 1].split('.')[0]; } return fullName; } static getFullApiNameWithExtension(fileName: string): string { let fullName = ''; let metadateType = MetadataInfo.getMetadataName(fileName); let splitFilepath = fileName.split(SEP); let isObjectChild = METADATA_INFO.CustomObject.childXmlNames.includes(metadateType); if (isObjectChild) { let objectName = splitFilepath[splitFilepath.length - 3]; let fieldName = splitFilepath[splitFilepath.length - 1]; fullName = objectName.concat('.' + fieldName); } else { fullName = splitFilepath[splitFilepath.length - 1]; } return fullName; } public static isCustomMetadata(filepath: string, name: string): boolean { let result = true; let splitFilepath = filepath.split(SEP); let componentName = splitFilepath[splitFilepath.length - 1]; componentName = componentName.substring(0, componentName.indexOf('.')); if (name === METADATA_INFO.CustomField.xmlName || name === METADATA_INFO.CustomObject.xmlName) { //Custom Field or Custom Object result = componentName.endsWith('__c') || componentName.endsWith('__mdt'); } return result; } public static getMemberNameFromFilepath(filepath: string, name: string): string { let member: string; let splitFilepath = filepath.split(SEP); let lastIndex = splitFilepath.length - 1; let isObjectChild = METADATA_INFO.CustomObject.childXmlNames.includes(name); let metadataDescribe: MetadataDescribe = METADATA_INFO[name]; if (isObjectChild) { let objectName = splitFilepath[lastIndex - 2]; let fieldName = splitFilepath[lastIndex].split('.')[0]; member = objectName.concat('.' + fieldName); } else if (metadataDescribe.inFolder) { let baseName = metadataDescribe.directoryName; let baseIndex = filepath.indexOf(baseName) + baseName.length; let cmpPath = filepath.substring(baseIndex + 1); // add 1 to remove the path seperator cmpPath = cmpPath.substring(0, cmpPath.indexOf('.')); member = cmpPath.replace(SEP, '/'); } else { if (SOURCE_EXTENSION_REGEX.test(splitFilepath[lastIndex])) { member = splitFilepath[lastIndex].replace(SOURCE_EXTENSION_REGEX, ''); } else { const auraRegExp = new RegExp('aura'); const lwcRegExp = new RegExp('lwc'); const staticResourceRegExp = new RegExp('staticresources'); const experienceBundleRegExp = new RegExp('experiences'); if (auraRegExp.test(filepath) || lwcRegExp.test(filepath)) { member = splitFilepath[lastIndex - 1]; } else if (staticResourceRegExp.test(filepath)) { //Return the fileName let baseName = 'staticresources'; let baseIndex = filepath.indexOf(baseName) + baseName.length; let cmpPath = filepath.substring(baseIndex + 1); // add 1 to remove the path seperator member = cmpPath.split(SEP)[0]; let extension = path.parse(member).ext; member = member.replace(new RegExp(extension + '$'), ''); } else if (experienceBundleRegExp.test(filepath)) { //Return the fileName let baseName = 'experiences'; let baseIndex = filepath.indexOf(baseName) + baseName.length; let cmpPath = filepath.substring(baseIndex + 1); // add 1 to remove the path seperator member = cmpPath.split(SEP)[0]; let extension = path.parse(member).ext; member = member.replace(new RegExp(extension + '$'), ''); } else { let extension = path.parse(splitFilepath[lastIndex]).ext; member = splitFilepath[lastIndex].replace(new RegExp(extension + '$'), ''); } } } return member; } public loadComponents(srcFolder: string, checkIgnore = true): void { let metadataFiles: string[] = FileUtils.getAllFilesSync(srcFolder); let keys = Object.keys(METADATA_INFO); if (Array.isArray(metadataFiles) && metadataFiles.length > 0) { metadataFiles.forEach((metadataFile) => { let found = false; for (let i = 0; i < keys.length; i++) { let match = false; if (metadataFile.endsWith(METADATA_INFO[keys[i]].sourceExtension)) { match = true; } else if ( METADATA_INFO[keys[i]].inFolder && metadataFile.endsWith(METADATA_INFO[keys[i]].folderExtension) ) { match = true; } if (match) { if (_.isNil(METADATA_INFO[keys[i]].files)) { METADATA_INFO[keys[i]].files = []; METADATA_INFO[keys[i]].components = []; } if (!checkIgnore || (checkIgnore && this.accepts(metadataFile))) { METADATA_INFO[keys[i]].files.push(metadataFile); let name = FileUtils.getFileNameWithoutExtension( metadataFile, METADATA_INFO[keys[i]].sourceExtension ); if (METADATA_INFO[keys[i]].isChildComponent) { let fileParts = metadataFile.split(SEP); let parentName = fileParts[fileParts.length - 3]; if (keys[i] === 'CustomField' && parentName === 'Activity') { //Add Activity fiels on Task and Event for reconcile METADATA_INFO[keys[i]].components.push('Task.' + name); METADATA_INFO[keys[i]].components.push('Event.' + name); } name = parentName + '.' + name; } METADATA_INFO[keys[i]].components.push(name); } found = true; break; } } if (!found) { const auraRegExp = new RegExp('aura'); if (auraRegExp.test(metadataFile) && SOURCE_EXTENSION_REGEX.test(metadataFile)) { if (_.isNil(METADATA_INFO.AuraDefinitionBundle.files)) { METADATA_INFO.AuraDefinitionBundle.files = []; METADATA_INFO.AuraDefinitionBundle.components = []; } if (!checkIgnore || (checkIgnore && this.accepts(metadataFile))) { METADATA_INFO.AuraDefinitionBundle.files.push(metadataFile); let name = FileUtils.getFileNameWithoutExtension(metadataFile); METADATA_INFO.AuraDefinitionBundle.components.push(name); } } } }); } else { keys.forEach((key) => { if (_.isNil(METADATA_INFO[key].files)) { METADATA_INFO[key].files = []; METADATA_INFO[key].components = []; } }); } } //Check if a component is accepted by forceignore. public accepts(filePath: string) { return !this.forceignore.ignores(path.relative(process.cwd(), filePath)); } public async isInModuleFolder(filePath: string) { const packageDirectories = await Sfpowerkit.getProjectDirectories(); if (!packageDirectories || packageDirectories.length == 0) { return false; } const moduleFolder = packageDirectories.find((packageFolder) => { let packageFolderNormalized = path.relative('', packageFolder); packageFolderNormalized = packageFolderNormalized + path.sep; return filePath.startsWith(packageFolderNormalized); }); return moduleFolder !== undefined; } /** * Copy a file to an outpu directory. If the filePath is a Metadata file Path, * All the metadata requirement are also copied. For example MyApexClass.cls-meta.xml will also copy MyApexClass.cls. * Enforcing the .forceignore to ignire file ignored in the project. * @param filePath * @param outputFolder */ public static copyFile(filePath: string, outputFolder: string) { SFPLogger.log(`Copying file ${filePath} from file system to ${outputFolder}`, LoggerLevel.DEBUG); const LWC_IGNORE_FILES = ['jsconfig.json', '.eslintrc.json']; const pairStatResources = METADATA_INFO.StaticResource.directoryName; const pairStatResourcesRegExp = new RegExp(pairStatResources); const pairAuaraRegExp = new RegExp(METADATA_INFO.AuraDefinitionBundle.directoryName); let copyOutputFolder = outputFolder; if (!fs.existsSync(filePath)) { return; } let exists = fs.existsSync(path.join(outputFolder, filePath)); if (exists) { return; } if (filePath.startsWith('.')) { let parts = path.parse(filePath); if (parts.dir === '') { fs.copyFileSync(filePath, path.join(outputFolder, filePath)); return; } } let fileName = path.parse(filePath).base; //exclude lwc ignored files if (LWC_IGNORE_FILES.includes(fileName)) { return; } let filePathParts = filePath.split(SEP); if (fs.existsSync(outputFolder) == false) { fs.mkdirSync(outputFolder); } // Create folder structure for (let i = 0; i < filePathParts.length - 1; i++) { let folder = filePathParts[i].replace('"', ''); outputFolder = path.join(outputFolder, folder); if (fs.existsSync(outputFolder) == false) { fs.mkdirSync(outputFolder); } } // Copy all file with same base name let associatedFilePattern = ''; if (SOURCE_EXTENSION_REGEX.test(filePath)) { associatedFilePattern = filePath.replace(SOURCE_EXTENSION_REGEX, '.*'); } else { let extension = path.parse(filePath).ext; associatedFilePattern = filePath.replace(extension, '.*'); } let files = glob.sync(associatedFilePattern); for (let i = 0; i < files.length; i++) { if (fs.lstatSync(files[i]).isDirectory() == false) { let oneFilePath = path.join('.', files[i]); let oneFilePathParts = oneFilePath.split(SEP); fileName = oneFilePathParts[oneFilePathParts.length - 1]; let outputPath = path.join(outputFolder, fileName); fs.copyFileSync(files[i], outputPath); } } // Hadle ObjectTranslations // If a file fieldTranslation is copied, make sure the ObjectTranslation File is also copied if (filePath.endsWith('Translation-meta.xml') && filePath.indexOf('globalValueSet') < 0) { let parentFolder = filePathParts[filePathParts.length - 2]; let objectTranslation = parentFolder + METADATA_INFO.CustomObjectTranslation.sourceExtension; let outputPath = path.join(outputFolder, objectTranslation); let sourceFile = filePath.replace(fileName, objectTranslation); if (fs.existsSync(sourceFile) == true) { fs.copyFileSync(sourceFile, outputPath); } } //FOR STATIC RESOURCES - WHERE THE CORRESPONDING DIRECTORY + THE ROOT META FILE HAS TO BE INCLUDED if (pairStatResourcesRegExp.test(filePath)) { outputFolder = path.join('.', copyOutputFolder); let srcFolder = '.'; let staticRecourceRoot = ''; let resourceFile = ''; for (let i = 0; i < filePathParts.length; i++) { outputFolder = path.join(outputFolder, filePathParts[i]); srcFolder = path.join(srcFolder, filePathParts[i]); if (filePathParts[i] === METADATA_INFO.StaticResource.directoryName) { let fileOrDirname = filePathParts[i + 1]; let fileOrDirnameParts = fileOrDirname.split('.'); srcFolder = path.join(srcFolder, fileOrDirnameParts[0]); outputFolder = path.join(outputFolder, fileOrDirnameParts[0]); resourceFile = srcFolder + METADATA_INFO.StaticResource.sourceExtension; METADATA_INFO.StaticResource.sourceExtension; staticRecourceRoot = outputFolder + METADATA_INFO.StaticResource.sourceExtension; if (fs.existsSync(srcFolder)) { if (fs.existsSync(outputFolder) == false) { fs.mkdirSync(outputFolder); } } break; } } if (fs.existsSync(srcFolder)) { FileUtils.copyRecursiveSync(srcFolder, outputFolder); } if (fs.existsSync(resourceFile)) { fs.copyFileSync(resourceFile, staticRecourceRoot); } } //FOR AURA components and LWC components if (pairAuaraRegExp.test(filePath)) { outputFolder = path.join('.', copyOutputFolder); let srcFolder = '.'; for (let i = 0; i < filePathParts.length; i++) { outputFolder = path.join(outputFolder, filePathParts[i]); srcFolder = path.join(srcFolder, filePathParts[i]); if (filePathParts[i] === 'aura' || filePathParts[i] === 'lwc') { let fileOrDirname = filePathParts[i + 1]; let fileOrDirnameParts = fileOrDirname.split('.'); srcFolder = path.join(srcFolder, fileOrDirnameParts[0]); outputFolder = path.join(outputFolder, fileOrDirnameParts[0]); if (fs.existsSync(srcFolder)) { if (fs.existsSync(outputFolder) == false) { fs.mkdirSync(outputFolder); } } break; } } if (fs.existsSync(srcFolder)) { FileUtils.copyRecursiveSync(srcFolder, outputFolder); } } } }