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