@pega/custom-dx-components
Version:
Utility for building custom UI components
386 lines (299 loc) • 10.8 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,
getDirectoryFiles,
addDebugLog,
checkLibraryAndArchives,
getConfigDefaults,
getComponents,
getUseInputConfig,
getInputConfigForCommand,
convertYNToBoolean
} from '../../util.js';
import { TASKS_CONFIG_JSON_FILENAME } from '../../constants.js';
import { getFilePathQuestions, getFileNameQuestions, updateSavedFilePath } from './helper.js';
import buildComponent from '../build-comp/index.js';
import inquirerFuzzyPath from '@pega/inquirer-fuzzy-path';
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);
let gFilePath = "";
export const updateConfig = async (
{
oldComponentKey,
newComponentKey,
library,
version,
targetDirectory,
newLabel = "",
organization
},
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;
configData.organization = organization;
if (newLabel != "") {
configData.label = newLabel;
configData.description = newLabel;
}
// 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' });
};
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' });
}
};
// rename the component
export const renameComponent = async (
componentKey,
orgLib,
version,
newName = "",
newLabel = "",
organization,
options
) => {
addDebugLog("renameComponent", `orgLib: ${orgLib}, componentKey: ${componentKey}`, "");
const componentName = newName != "" ? newName : componentKey.split("_")[2];
const newComponentKey = `${orgLib}_${componentName}`;
const library = orgLib.split("_")[1];
const oldComponentKey = componentKey;
const newComponentKeyPC = convertIntoPascalCase(newComponentKey);
const oldComponentKeyPC = convertIntoPascalCase(oldComponentKey);
const currentDirectory = await getComponentDirectoryPath(componentKey);
const targetDirectory = await getComponentDirectoryPath(newComponentKey);
// custom component
try {
fs.renameSync(currentDirectory, targetDirectory);
} 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,
componentName,
library,
version,
targetDirectory,
newLabel,
organization
},
options
);
}
else {
await updateFile(
fileName,
oldComponentKeyPC,
newComponentKeyPC,
targetDirectory );
}
} // for
return newComponentKey;
};
export const importComp = async(filePath, fileName, askValidate) => {
addDebugLog("importComp", `filePath: ${filePath}, fileName: ${fileName}`, "");
const currentDirectory = process.cwd();
// const compDirectory = join(currentDirectory, "src", "components");
const copyFilePath = join(filePath, fileName);
const configDef = getConfigDefaults();
const copyDir = await getComponentDirectoryPath(fileName);
let configData;
let newName = "";
let newLabel = "";
if (fs.existsSync(copyDir)) {
configData = fs.readFileSync(join(copyDir, "/config.json"), { encoding: 'utf8' });
configData = configData && JSON.parse(configData);
const compName = configData.componentKey.split("_")[2];
const potentialCompKey = `${configDef.currentOrgLib}_${compName}`;
const currentCompList = await getComponents();
if (currentCompList && currentCompList.includes(potentialCompKey)) {
console.log(`\nComponent ${chalk.yellow(`${potentialCompKey}`)} already exists.`);
const proceedAnswers = await inquirer.prompt([
{
name: 'proceedAs',
type: 'rawlist',
message: `Proceed as ?`,
default: 'No import',
choices: ['No import', 'Overwrite', 'New name']
},
{
name: 'componentName',
message: 'Enter component name (required)',
when(answers) {
return answers.proceedAs === 'New name';
},
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)',
when(answers) {
return answers.proceedAs === 'New name';
},
validate: value => {
if (value) {
return true;
}
return 'Please provide value for label';
}
}
]);
switch (proceedAnswers.proceedAs) {
case 'No import':
// removed copied
// fs.rmSync(copyDir, { recursive: true, force: true, maxRetries: 2 });
process.exit();
break;
case 'Overwrite':
// remove existing
const existingComp = await getComponentDirectoryPath(potentialCompKey);
fs.rmSync(existingComp, { recursive: true, force: true, maxRetries: 2 });
break;
case 'New name':
newName = proceedAnswers.componentName;
newLabel = proceedAnswers.componentLabel;
break;
}
}
}
if (fs.existsSync(copyFilePath)) {
fs.cpSync(copyFilePath, copyDir, { recursive: true, force: true });
configData = fs.readFileSync(join(copyDir, "/config.json"), { encoding: 'utf8' });
configData = configData && JSON.parse(configData);
const newCompKey = await renameComponent(configData.componentKey, configDef.currentOrgLib, configDef.buildVersion, newName, newLabel, configDef.organization, null);
console.log(`\n${chalk.green(`${fileName}`)} has been imported as ${chalk.green(`${newCompKey}`)}\n`);
if (askValidate) {
const validateAnswers = await inquirer.prompt([
{
name: 'doValidate',
type: 'confirm',
message: `Validate ${chalk.yellow(`${newCompKey}`)}`,
default: true
}]);
if (validateAnswers.doValidate) {
const args = [ '','', '', `${newCompKey}`];
let myOptions = {};
myOptions["params"] = args;
await buildComponent(myOptions);
}
}
}
}
export const getFolderList = async (filePath) => {
addDebugLog("getFolderList", `filePath: ${filePath}`, "");
if (fs.existsSync(filePath)) {
return fs
.readdirSync(filePath, { withFileTypes: true })
.filter(dirent => dirent.isDirectory() && !dirent.name.startsWith("."))
.map(dirent => dirent.name);
}
else {
console.log(chalk.red.bold(`File path: ${filePath} does not exist or no permissions.`));
process.exit(1);
}
}
export const hasConfig = (dir) => {
const configPath = join(gFilePath, dir, "config.json");
if (fs.existsSync(configPath)) {
return true;
}
return false;
}
export const getComponentList = async(filePath) => {
addDebugLog("getComponentList", `filePath: ${filePath}`, "");
let compList = await getFolderList(filePath);
gFilePath = filePath;
if (compList.length > 0) {
return compList.filter(hasConfig);
}
return compList;
}
export default async options => {
await showVersion();
await checkLibraryAndArchives();
await checkPathAccess(pegaConfigJsonPath);
const useInputConfig = getUseInputConfig();
addDebugLog("importComponent", "", "+");
if (options.params.length >= 5) {
const filePath = options.params[3];
const fileName = options.params[4];
let askValidate = true;
if (options.params.length >= 6) {
if (options.params[5] === "noAskValidate") {
askValidate = false;
}
}
await importComp( filePath, fileName, askValidate);
}
else {
let filePath;
let fileName;
if (useInputConfig) {
const inputConfig = await getInputConfigForCommand("importComponent");
filePath = inputConfig.fileLocation;
fileName = inputConfig.fileName;
await importComp( filePath, fileName, false);
}
else {
inquirer.registerPrompt('fuzzypath', inquirerFuzzyPath);
const filePathQuestions = await getFilePathQuestions();
const filePathAnswers = await inquirer.prompt(filePathQuestions);
const { filePath } = filePathAnswers;
const compFileList = await getComponentList(filePath);
if (!compFileList || compFileList.length === 0) {
console.log(chalk.red.bold(`No component files exist at path: ${filePath}`));
process.exit();
}
await updateSavedFilePath(filePath);
const fileNameQuestions = await getFileNameQuestions(compFileList);
const fileNameAnswers = await inquirer.prompt(fileNameQuestions);
const {fileName} = fileNameAnswers;
await importComp( filePath, fileName, true);
}
}
addDebugLog("importComponent", "END", "-");
};