@pega/custom-dx-components
Version:
Utility for building custom UI components
410 lines (338 loc) • 14.1 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', '-');
};