@pega/custom-dx-components
Version:
Utility for building custom UI components
357 lines (284 loc) • 9.54 kB
JavaScript
import chalk from 'chalk';
import path from 'path';
import { join } from 'path';
import fetch from 'node-fetch';
import archiver from 'archiver';
import fs from 'fs';
import {
addDebugLog,
getConfigDefaults,
getLibraryArchiveDirectories,
getLibraryArchivesVersions,
setConfigExportRelativePath,
getComponentDirectoryPath,
getPegaServerConfig,
forceDefaultsUpdate } from '../../util.js';
export const SOURCE_OF_COMPONENT_TYPES = {
SERVER: 'Server',
LOCAL: 'Local'
};
export const getFilePathQuestions = async () => {
addDebugLog("getFilePathQuestions", "", "");
console.log("\nFile path examples:");
if (path.sep === "/") {
console.log("\tMac OS/Unix:\t/Users/name/...");
}
else {
console.log("\tWindows:\tC:\\Users\\name\\...\n");
}
const configDef = getConfigDefaults();
const currentDirectory = process.cwd();
const arPathParts = currentDirectory.split(path.sep);
let defaultPath = join(arPathParts[0], arPathParts[1], arPathParts[2], configDef.exportRelativePath);
let startDirectory = join(arPathParts[0], arPathParts[1], arPathParts[2]);
if (path.sep === "/") {
defaultPath = "/".concat(defaultPath);
startDirectory = "/".concat(startDirectory).concat("/");
}
return [
{
name: 'filePath',
type: 'fuzzypath',
message: 'Enter full file path of directory to export zip file:',
default: defaultPath,
excludePath: nodePath => nodePath.startsWith('node_modules'),
// excludePath :: (String) -> Bool
// excludePath to exclude some paths from the file-system scan
excludeFilter: nodePath => nodePath.indexOf('/.') >= 0,
// excludeFilter :: (String) -> Bool
// excludeFilter to exclude some paths from the final list, e.g. '.'
itemType: 'directory',
// itemType :: 'any' | 'directory' | 'file'
// specify the type of nodes to display
// default value: 'any'
// example: itemType: 'file' - hides directories from the item list
rootPath: startDirectory,
// rootPath :: String
// Root search directory
suggestOnly: true,
// suggestOnly :: Bool
// Restrict prompt answer to available choices or use them as suggestions
depthLimit: 2,
// depthLimit :: integer >= 0
// Limit the depth of sub-folders to scan
// Defaults to infinite depth if undefined
}
];
};
export const getFileNameQuestions = async (zipFileList) => {
addDebugLog("getFileNameQuestions", "", "");
return [
{
name: 'fileName',
type: 'rawlist',
message: `Select zip file`,
choices: zipFileList
},
];
};
export const getLibraryQuestion = async () => {
addDebugLog("getLibraryQuestion", "", "");
const componentDefaults = getConfigDefaults();
const orgLib = getConfigDefaults();
const currentOrgLib = `${orgLib.organization}_${orgLib.library}`;
const archVersionList = await getLibraryArchiveDirectories("");
return [
{
name: 'orgLibName',
type: 'rawlist',
message: `Select a library (current library is ${chalk.bold.green(`${currentOrgLib}`)}) `,
choices: archVersionList
}
];
};
export const getLibraryVersionQuestion = async (newOrgLib) => {
addDebugLog("getLibraryVersionQuestion", "", "");
const archVersionList = await getLibraryArchivesVersions(newOrgLib, "0.0.0");
return [
{
name: 'selectedVersion',
type: 'rawlist',
message: `Select a version `,
choices: archVersionList
}
];
};
export const getServerOrDirectoryQuestion = async () => {
addDebugLog("getLibraryVersionQuestion", "", "");
return [
{
name: 'exportTo',
type: 'rawlist',
message: `Export to`,
choices: [{name: 'Local directory', value: 'Directory'}, {name: 'Server', value: 'Server'}],
default: 'Directory'
}
];
};
export const getFullArchiveQuestions = async () => {
return [
{
name: 'fullArchive',
type: 'rawlist',
message: 'Type of export',
choices: [{name: 'Full Archive (code)', value: 'Full'}, {name: 'CL Binary (runtime only)', value: 'Binary'}],
default: 'Full'
}
];
}
export const getComponentInfoQuestions = async (rPackageJSON, library) => {
return [
{
name: 'author',
message: 'Author of this component',
default: rPackageJSON.author
},
{
name: 'isLocalized',
type: 'confirm',
message: 'Is this component fully localized',
default: false
},
{
name: 'isAccessible',
type: 'confirm',
message: 'Is this component accessible',
default: false
},
{
name: 'isSecure',
type: 'confirm',
message: 'Is this component and dependent modules secure',
default: false
},
{
name: 'license',
message: 'License of this component (MIT, Apache, GPL, etc.)',
default: rPackageJSON.license
},
{
name: 'organization',
message: 'Organization name',
default: rPackageJSON.organization
},
{
name: 'library',
message: 'Library name',
default: library
}
];
}
export const zipComponent = async componentKey => {
addDebugLog("zipComponent", `componentKey: ${componentKey}`, "");
const srcDirectory = await getComponentDirectoryPath(componentKey);
const buildDirectory = await path.join(path.resolve(), 'dist/components', componentKey);
const configJson = `${srcDirectory}/config.json`;
const localizationJson = `${srcDirectory}/localizations.json`;
const archive = archiver('zip', { zlib: { level: 9 } });
const zipChunks = [];
archive.on('data', chunk => zipChunks.push(chunk));
// Add src directory
archive.directory(srcDirectory, 'src');
// Add config.json file
if (fs.existsSync(configJson)) {
archive.file(configJson, { name: path.basename(configJson) });
}
let lJson = "";
// Add localizations.json file if it exists
if (fs.existsSync(localizationJson)) {
archive.file(localizationJson, { name: path.basename(localizationJson) });
lJson = JSON.parse(Buffer.from(fs.readFileSync((localizationJson))).toString());
}
// Add build directory
archive.directory(buildDirectory, false);
await archive.finalize();
const zipBuffer = Buffer.concat(zipChunks);
console.log(chalk.green(`component zipped with size: ${Math.ceil(zipBuffer.length / 1024)} KB`));
const zipContent = zipBuffer.toString('base64');
//let configContent = Buffer.from(fs.readFileSync(configJson)).toString();
const configContent = JSON.parse(Buffer.from(fs.readFileSync(configJson)).toString());
// configContent = configContent.replaceAll("\n", "");
let output = { configContent };
if (lJson != "") {
output = { ...output, localizationJson: lJson};
}
if (fs.existsSync('dist')) {
fs.rm('dist', { recursive: true }, err => {
if (err) {
throw err;
}
});
}
return { zipContent, ...output};
};
export const zipRC = async (content, archiveDirectory, archiveFileName) => {
addDebugLog("zipRC", ``, "");
// const configContent = Buffer.from(fs.readFileSync(configJson)).toString();
// const mainDirectory = process.cwd();
// const archiveDirectory = join (mainDirectory, ARCHIVES_PATH, `${componentKey}`, `${version}`);
if (!fs.existsSync(archiveDirectory)) {
fs.mkdirSync(archiveDirectory, { recursive: true });
}
const archiveFile = join(archiveDirectory, archiveFileName);
const output = fs.createWriteStream(archiveFile);
const archive = archiver('zip', {
zlib: { level: 9 } // Sets the compression level.
});
const zipChunks = [];
archive.on('data', chunk => zipChunks.push(chunk));
archive.append( JSON.stringify(content), { name: 'componentData.json' });
// pipe archive data to the file
archive.pipe(output);
output.on('end', function() {
console.log('Data has been drained');
});
// good practice to catch warnings (ie stat failures and other non-blocking errors)
archive.on('warning', function(err) {
if (err.code === 'ENOENT') {
// log warning
} else {
// throw error
throw err;
}
});
// good practice to catch this error explicitly
archive.on('error', function(err) {
throw err;
});
await archive.finalize();
return output;
};
export const updateSavedExportFilePath = async(filePath) => {
const currentDirectory = process.cwd();
const arPathParts = currentDirectory.split(path.sep);
const configDef = getConfigDefaults();
let defaultPath = join(path.sep, arPathParts[0], arPathParts[1], arPathParts[2]);
if (path.sep != "/") {
// windows
if (defaultPath.indexOf(path.sep) === 0) {
// if start with \\, then remove
defaultPath = defaultPath.substring(1);
}
if (filePath.indexOf(defaultPath) === 0) {
let relativePath = "";
if (filePath !== defaultPath) {
// same starting path, so we can save the relative
relativePath = filePath.replace(defaultPath.concat(path.sep), "");
}
await setConfigExportRelativePath(relativePath);
await forceDefaultsUpdate();
}
}
else {
// mac
if (filePath.indexOf(defaultPath) === 0) {
let relativePath = "";
if (filePath !== defaultPath) {
// same starting path, so we can save the relative
relativePath = filePath.replace(defaultPath.concat("/"), "");
}
await setConfigExportRelativePath(relativePath);
await forceDefaultsUpdate();
}
}
}