UNPKG

@pega/custom-dx-components

Version:

Utility for building custom UI components

478 lines (380 loc) 14.5 kB
import fs from 'fs'; import { promisify } from 'util'; import { join } from 'path'; import inquirer from 'inquirer'; import ncp from 'ncp'; import chalk from 'chalk'; import { sanitize, checkPathAccess, showVersion, getComponentsObj, getDirectoryFiles, addDebugLog, checkLibraryAndArchives, getConfigDefaults, getLibraryBased, unZipFromArchive, zipVersionAndArchive, getLibraryArchivesVersions, getLibraryArchiveDirectories, cleanUpTemp } from '../../util.js'; import { TASKS_CONFIG_JSON_FILENAME, COMPONENTS_DIRECTORY_PATH, ARCHIVES_PATH, TEMP_PATH } from '../../constants.js'; import { getComponentKeyQuestion, getLibraryQuestions, getLibraryVersionQuestion } from './helper.js'; export const DXCB_CONFIG_INTERNAL_JSON_FILENAME = 'src/dxcb.config.json'; const currentDirectory = process.cwd(); const pegaConfigJsonPath = join(currentDirectory, TASKS_CONFIG_JSON_FILENAME); import { convertIntoPascalCase, getComponentDirectoryPath } from '../../util.js'; const copy = promisify(ncp); export const updateConfig = async ( { oldComponentKey, newComponentKey, compName, library, version, compLabel, targetDirectory, }, options, onlyCompanion = false ) => { addDebugLog("updateConfig", `oldComponentKey: ${oldComponentKey}, newComponentKey: ${newComponentKey}`, ""); let configData = fs.readFileSync(join(targetDirectory, "/config.json"), { encoding: 'utf8' }); configData = configData && JSON.parse(configData); configData.name = newComponentKey; if (configData.componentKey) configData.componentKey = newComponentKey; configData.library = library; configData.version = version; if (compLabel != "") { configData.label = compLabel; configData.description = compLabel; } // stringify "4", makes the json string look like JSON in the file, formatted instead of a single line fs.writeFileSync(join(targetDirectory, "/config.json"), JSON.stringify(configData, null, 4), { encoding: 'utf8', flag:'w' }); }; export const updateFile = async ( fileName, oldComponentKeyPC, newComponentKeyPC, targetDirectory, ) => { addDebugLog("updateFile", `fileName: ${fileName}, oldComponentKeyPC: ${oldComponentKeyPC}, newComponentKeyPC: ${newComponentKeyPC}, targetDirectory: ${targetDirectory}`, ""); let fileData = fs.readFileSync(join(targetDirectory, "/", fileName), { encoding: 'utf8' }); if (fileData.indexOf(oldComponentKeyPC) >= 0) { fileData = fileData.replaceAll(oldComponentKeyPC, newComponentKeyPC); fs.writeFileSync(join(targetDirectory, "/", fileName), fileData, { encoding: 'utf8',flag:'w' }); } }; // rename the component export const renameComponent = async ( componentKey, library, version, copyMove, compName = "", compLabel = "", options ) => { addDebugLog("renameComponent", `library: ${library}, componentKey: ${componentKey}`, ""); // const componentName = componentKey.split("_")[2]; const newComponentKey = `${library}_${compName}`; const oldComponentKey = componentKey; const newComponentKeyPC = convertIntoPascalCase(newComponentKey); const oldComponentKeyPC = convertIntoPascalCase(oldComponentKey); const currentDirectory = process.cwd(); const tempDirectory = join(currentDirectory, TEMP_PATH, "src", "components"); const existingDirectory = await getComponentDirectoryPath(componentKey); const targetDirectory = await getComponentDirectoryPath(newComponentKey, tempDirectory); if (copyMove === "Move") { // custom component try { fs.renameSync(existingDirectory, targetDirectory); } catch(err) { console.log(err) } } else { // copy // custom component try { fs.cpSync(existingDirectory, targetDirectory, { recursive: true}); } catch(err) { console.log(err) } } const targetFileList = await getDirectoryFiles(targetDirectory); for (var fileIndex in targetFileList) { const fileName = targetFileList[fileIndex]; if (fileName === "config.json") { await updateConfig( { oldComponentKey, newComponentKey, compName, library, version, compLabel, targetDirectory, }, options ); } else { await updateFile( fileName, oldComponentKeyPC, newComponentKeyPC, targetDirectory ); } } // for return newComponentKey; }; export const moveComp = async(componentKey, copyMove, orgLibName, version, copyShared, localComponents, options) => { // put lib/version into temp directory const currentDirectory = process.cwd(); const tempDirectory = join(currentDirectory, TEMP_PATH); const archiveDirectory = join (currentDirectory, ARCHIVES_PATH, `${orgLibName}`, `${version}`); const fileName = `${orgLibName}_${version}.arch.zip`; const archFileName = join(archiveDirectory, fileName); const currentCompPath = join(currentDirectory, "src", "components"); const tempCompPath = join(tempDirectory, "src", "components"); const configDef = getConfigDefaults(); await unZipFromArchive(archFileName); const copiedOrMoved = copyMove === "Copy" ? "Copied" : "Moved"; let newComponentKey; if (componentKey === 'ALL') { for (let index in localComponents) { // skip first ALL if (index > 0) { const localComponentKey = localComponents[index]; newComponentKey = await localMoveCopyComp(localComponentKey.value, orgLibName, version, copyMove, currentDirectory, tempDirectory); if (newComponentKey) { console.log(`${copiedOrMoved} ${chalk.green(`${localComponentKey.value}`)} to ${chalk.green(`${orgLibName}/${version}`)} as ${chalk.green(`${newComponentKey}`)}`); } else { console.log(chalk.yellow(`Not ${copiedOrMoved}`)); } } } const currentSharedPath = join(currentCompPath, "shared"); const targetSharedPath = join(tempCompPath, "shared"); // copy shared if (copyShared) { fs.cpSync(currentSharedPath, targetSharedPath, { recursive: true, force: true }); } // rearchive temp directory await zipVersionAndArchive(orgLibName, version, tempDirectory); // delete temp directory fs.rmSync(tempDirectory, { recursive: true, force: true, maxRetries: 5 }); } else { const newComponentKey = await localMoveCopyComp(componentKey, orgLibName, version, copyMove, currentDirectory, tempDirectory); if (newComponentKey) { const currentSharedPath = join(currentCompPath, "shared"); const targetSharedPath = join(tempCompPath, "shared"); // copy shared if (copyShared) { fs.cpSync(currentSharedPath, targetSharedPath, { recursive: true, force: true }); } console.log(`\n${copiedOrMoved} ${chalk.green(`${componentKey}`)} to ${chalk.green(`${orgLibName}/${version}`)} as ${chalk.green(`${newComponentKey}`)}\n`); // rearchive temp directory await zipVersionAndArchive(orgLibName, version, tempDirectory); // update current /src/components because we copied to it (as well as the archive) if (orgLibName === configDef.currentOrgLib && version === configDef.buildVersion && copyMove === "Copy") { fs.cpSync(join(tempCompPath, newComponentKey), join(currentCompPath, newComponentKey), { recursive: true, force: true }); } } else { console.log(chalk.yellow(`No components were ${copiedOrMoved}`)); } // delete temp directory fs.rmSync(tempDirectory, { recursive: true, force: true, maxRetries: 5 }); } } export const localMoveCopyComp = async(componentKey, orgLibName, version, copyMove, currentDirectory, tempDirectory ) => { const currentCompPath = join(currentDirectory, "src", "components"); const tempCompPath = join(tempDirectory, "src", "components"); const configDef = getConfigDefaults(); const tempCompName = componentKey.split("_")[2]; let newTempComponentKey = `${orgLibName}_${tempCompName}`; const tempDirComp = join(tempCompPath, `${newTempComponentKey}`); let compLabel = ""; let compName = tempCompName; if (fs.existsSync(join(tempCompPath, componentKey)) && version === configDef.buildVersion && copyMove === "Copy") { // need to rename console.log(`\n${chalk.yellow(`${tempCompName}`)} exists, select new name and label for copied component.`); const nameAnswers = await inquirer.prompt([ { name: 'componentName', message: 'Enter component name (required)', validate: value => { /* value should not be empty It should not have spaces It should not start with a number Only case-insensitive alphanumeric values are allowed */ if (value && !/^\d/.test(value) && value === sanitize(value)) { return true; } return 'Only alphanumeric values are allowed, starting with alphabets, no spaces.'; } }, { name: 'componentLabel', message: 'Enter component label for display (required)', validate: value => { if (value) { return true; } return 'Please provide value for label'; } } ]); // compName = nameAnswers.componentName; compLabel = nameAnswers.componentLabel; } else if (fs.existsSync(tempDirComp)) { const answers = await inquirer.prompt([ { name: 'confirmOverride', type: 'confirm', message: `Component ${chalk.yellow(`${tempCompName}`)} currently exists in ${chalk.yellow(`${orgLibName}/${version}`)}, override?`, default: false } ]); if (!answers.confirmOverride) { return null; } else { // delete the one in the temp directory, so can move/copy latest fs.rmSync(tempDirComp, { recursive: true, force: true, maxRetries: 2 }); } } // rename the component const newComponentKey = await renameComponent(componentKey, orgLibName, version, copyMove, compName, compLabel); return newComponentKey; } export default async options => { await showVersion(); await checkLibraryAndArchives(); addDebugLog("move", "", "+"); await checkPathAccess(pegaConfigJsonPath); const isLibraryBased = getLibraryBased(); if (!isLibraryBased) { console.log(`Command only supported for ${chalk.bold.green('library mode')} components.`) process.exit(); } await cleanUpTemp(); let data = fs.readFileSync(pegaConfigJsonPath, { encoding: 'utf8' }); data = data && JSON.parse(data); if (!data[COMPONENTS_DIRECTORY_PATH]) { console.error( `${chalk.red.bold('ERROR')} Unable find to components directory path in config.json` ); process.exit(1); } let copyMove; let copyMoveLC; let componentKey; let orgLibName; let version; let copyShared; let localComponents = await getComponentsObj(); const configDef = getConfigDefaults(); if (!localComponents || localComponents.length === 0 ) { console.log(chalk.red.bold("No components to move/copy.")); process.exit(); } if (options.params.length >= 8) { copyMove = options.params[3]; componentKey = options.params[4]; orgLibName = options.params[5]; version = options.params[6]; copyShared = options.params[7]; await moveComp( componentKey, copyMove, orgLibName, version, copyShared, localComponents, options ); } else { // VS Code plugin would send in the component let paramComponentKey; if (options.params.length == 4) { paramComponentKey = options.params[3]; } const configDef = getConfigDefaults(); console.log(`Current library: ${chalk.green(`${configDef.displayLibVersion}`)}`); // test to see if current library has more than one version // if no available versions can not move/copy to it, so send in current lib // as library to be removed from the list let removeOrgLib = ""; let libVersions; try { // libVersions = await getLibraryArchivesVersions(configDef.currentOrgLib, configDef.buildVersion); libVersions = await getLibraryArchivesVersions(configDef.currentOrgLib, "0.0.0"); } catch (ex) {} if (!libVersions || libVersions.length === 0) { removeOrgLib = configDef.currentOrgLib; } const archLibs = await getLibraryArchiveDirectories(removeOrgLib); if (!archLibs || archLibs.length === 0) { console.log(chalk.red.bold("No available libraries to move/copy to.")); process.exit(); } const copyMoveQuestion = [ { name: 'copyMove', type: 'rawlist', message: "Copy or Move", choices: ["Copy", "Move"], default: "Copy" } ]; const copyMoveAnswer = await inquirer.prompt(copyMoveQuestion); ({copyMove} = copyMoveAnswer); copyMoveLC = copyMove.toLowerCase(); if (localComponents && localComponents.length > 1 ) { localComponents.unshift({name: 'ALL', value: 'ALL'}); } const keyQuestions = await getComponentKeyQuestion(localComponents, copyMoveLC, paramComponentKey); const answers = await inquirer.prompt(keyQuestions); ({ componentKey = paramComponentKey} = answers); const libQuestions = await getLibraryQuestions(archLibs); const libAnswers = await inquirer.prompt(libQuestions); orgLibName = libAnswers.libraryName; const buildVersion = configDef.currentOrgLib === orgLibName ? (copyMove === "Move" ? configDef.buildVersion : "" ) : ""; try { libVersions = await getLibraryArchivesVersions(orgLibName, buildVersion); } catch (ex) {} if (libVersions.length == 0) { console.log(`Current library: ${chalk.green(`${orgLibName}`)} has NO available versions to move to.`); process.exit(); } const versionQuestions = await getLibraryVersionQuestion(orgLibName, libVersions, copyMoveLC); const versionAnswers = await inquirer.prompt(versionQuestions); ({version, copyShared} = versionAnswers); await moveComp( componentKey, copyMove, orgLibName, version, copyShared, localComponents, options ); } addDebugLog("rename", "END", "-"); };