@pega/custom-dx-components
Version:
Utility for building custom UI components
478 lines (380 loc) • 14.5 kB
JavaScript
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", "-");
};