@pega/custom-dx-components
Version:
Utility for building custom UI components
383 lines (314 loc) • 10.3 kB
JavaScript
import path from 'path';
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 {
checkPathAccess,
showVersion,
getComponentsObj,
getDirectoryFiles,
addDebugLog,
checkLibraryAndArchives,
getConfigDefaults,
getLibraryBased } from '../../util.js';
import { TASKS_CONFIG_JSON_FILENAME, COMPONENTS_DIRECTORY_PATH, COMPONENTS_PATH } from '../../constants.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,
getPegaConfig,
sanitize,
validateSemver
} from '../../util.js';
import { COMPONENT_SCHEMA } from '../../constants.js';
const copy = promisify(ncp);
export const updateConfig = async (
{
oldComponentKey,
newComponentKey,
library,
organization,
componentName,
componentLabel,
version,
description,
allowedApplications,
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;
configData.label = componentLabel;
configData.organization = organization;
if (configData.componentKey) configData.componentKey = newComponentKey;
configData.library = library;
configData.version = version;
configData.description = (description != '') ? description : componentLabel;
// if (allowedApplications.trim() === '') {
// allowedApplications = [];
// } else {
// if (allowedApplications.indexOf(',') !== -1) {
// allowedApplications = allowedApplications.split(',');
// }
// allowedApplications = [].concat(allowedApplications);
// }
// allowedApplications = allowedApplications.filter(el => !!el.trim()).map(el => el.trim());
// configData.allowedApplications = allowedApplications;
// 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' });
}
};
export const renameComponent = async (
{
library,
organization,
componentKey,
componentName,
componentLabel,
version,
description,
allowedApplications
},
options,
onlyCompanion = false
) => {
addDebugLog("renameComponent", `library: ${library}, organization: ${organization}, componentKey: ${componentKey}`, "");
let pegaConfig = await getPegaConfig();
const newComponentKey = `${organization}_${library}_${componentName}`;
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,
componentLabel,
library,
version,
description,
allowedApplications,
organization,
targetDirectory,
},
options
);
}
else {
await updateFile(
fileName,
oldComponentKeyPC,
newComponentKeyPC,
targetDirectory );
}
} // for
console.log(chalk.green(`Component ${oldComponentKey} renamed to ${newComponentKey}`));
};
export default async options => {
await showVersion();
await checkLibraryAndArchives();
addDebugLog("rename", "", "+");
await checkPathAccess(pegaConfigJsonPath);
const isLibraryBased = getLibraryBased();
let data = fs.readFileSync(pegaConfigJsonPath, { encoding: 'utf8' });
data = data && JSON.parse(data);
if (!data[COMPONENTS_DIRECTORY_PATH]) {
console.error(
`${chalk.red.bold('ERROR')} Unable to find components directory path in config.json`
);
process.exit(1);
}
const componentData = data[COMPONENTS_PATH];
const { library } = componentData;
const { organization } = JSON.parse(fs.readFileSync(path.resolve('package.json'), 'utf8'));
let componentDefaults = getConfigDefaults();
componentDefaults.library = library;
const localComponents = await getComponentsObj();
if (options.params.length >= 11) {
const componentKey = options.params[3];
const componentName = options.params[4];
const componentLabel = options.params[5];
const organization = options.params[6];
const version = options.params[7];
const library = options.params[8];
const allowedApplications = options.params[9];
const description = options.params[10];
await renameComponent(
{
componentKey,
componentName,
componentLabel,
library,
version,
description,
allowedApplications,
organization
},
options
);
}
else {
// VS Code plugin would send in the component
let paramComponentKey;
if (options.params.length == 4) {
paramComponentKey = options.params[3];
}
const questions = [
{
name: 'componentKey',
type: 'rawlist',
pageSize: 15,
message: 'Select component to rename',
choices: localComponents,
when: () => !paramComponentKey
},
{
name: 'componentName',
message: 'Enter new component name (required, no spaces)',
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';
}
},
{
name: 'componentLabel',
message: 'Enter new component label for display (required)',
validate: value => {
if (value) {
return true;
}
return 'Please provide value for label';
}
},
{
name: 'organization',
message: 'Enter new component organization',
default: organization,
validate: value => {
if (value) {
return true;
}
return 'Please provide value for organization';
},
when: () => !isLibraryBased
},
{
name: 'version',
message: 'Enter new component version',
default: componentDefaults.version,
validate: value => {
if (validateSemver(value)) {
return true;
}
return 'Please provide semver compatible version e.g 0.0.1';
},
when: () => !isLibraryBased
},
{
name: 'library',
message: 'Enter new library name (required)',
default: componentDefaults.library,
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';
},
when: () => !isLibraryBased
},
// {
// name: 'allowedApplications',
// message: 'Please enter the application names to be supported (comma-separated). ',
// suffix: 'Keep empty for all applications',
// when: () => !isLibraryBased
// },
{
name: 'description',
message: 'Enter new description for the component (defaults to new label)',
default: componentDefaults.description,
/* if left blank and no defaults, mustache will use componentLabel, because description is used in app studio and
shouldn't be blank */
}
];
await inquirer.prompt(questions).then(async answers => {
const {
componentKey = paramComponentKey,
componentName,
componentLabel,
description,
} = answers;
let {
organization,
library,
version,
allowedApplications } = answers;
if (isLibraryBased) {
// these answers come from defaults
const orgLib = getConfigDefaults();
library = orgLib.library;
version = orgLib.buildVersion;
organization = orgLib.organization;
allowedApplications = "";
}
await renameComponent(
{
componentKey,
componentName,
componentLabel,
library,
version,
description,
allowedApplications,
organization
},
options
);
});
}
addDebugLog("rename", "END", "-");
};