@pega/custom-dx-components
Version:
Utility for building custom UI components
209 lines (183 loc) • 6 kB
JavaScript
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import { promisify } from 'util';
import { exec } from 'child_process';
import chalk from 'chalk';
import { execa } from 'execa';
import ncp from 'ncp';
import { Listr } from 'listr2';
import gitignore from 'gitignore';
import inquirer from 'inquirer';
import {
compileMustacheTemplate,
isPascalCase,
convertIntoPascalCase,
sanitize
} from '../../util.js';
import { getInitProjectQuestions } from './helper.js';
const execPromise = promisify(exec);
const copy = promisify(ncp);
const writeGitignore = promisify(gitignore.writeFile);
const writeFile = promisify(fs.writeFile);
const createGitignore = async options => {
const file = fs.createWriteStream(path.join(options.targetDirectory, '.gitignore'), {
flags: 'a'
});
return writeGitignore({
type: 'Node',
file
});
};
const createLicense = async options => {
const targetPath = path.join(options.targetDirectory, 'LICENSE');
const licenseContent = 'Enter license text here';
return writeFile(targetPath, licenseContent, 'utf8');
};
const copyProjectTemplate = async options => {
await copy(options.templateDirectory, options.targetDirectory, {
clobber: false
});
const packageJsonPath = path.join(options.targetDirectory, 'package.json.mustache');
const templateNPMRCPath = path.join(options.targetDirectory, 'templateNPMRC.txt');
let { organization, projectName } = options;
projectName = sanitize(projectName).toLowerCase();
organization = sanitize(organization);
if (!isPascalCase(organization)) {
organization = convertIntoPascalCase(organization);
}
options = {
...options,
organization,
projectName
};
const output = compileMustacheTemplate(packageJsonPath, options);
fs.writeFileSync(packageJsonPath, output);
fs.renameSync(packageJsonPath, packageJsonPath.replace('.mustache', ''));
// rename template NPMRC to .npmrc, need to do this because npmjs won't publish an .npmrc file
fs.renameSync(templateNPMRCPath, templateNPMRCPath.replace('templateNPMRC.txt', '.npmrc'));
await createLicense(options);
};
const initGit = async options => {
const result = await execa('git', ['init'], {
cwd: options.targetDirectory
});
if (result.failed) {
return Promise.reject(new Error('Failed to initialize git'));
}
};
export default async options => {
options.templateDirectory = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
'template'
);
let projectName = 'test';
const questions = getInitProjectQuestions();
await inquirer.prompt(questions).then(async answers => {
projectName = answers.projectName;
projectName = sanitize(projectName).toLowerCase();
options = { ...options, ...answers };
const projectDirectory = `./${projectName}`;
if (!fs.existsSync(projectDirectory)) {
fs.mkdirSync(projectDirectory);
} else {
console.log(chalk.bold.red(`A project with name ${projectName} already exists. Exiting...`));
process.exit();
}
const targetDirectory = options.targetDirectory || process.cwd();
options.targetDirectory = path.join(targetDirectory, projectName);
options.componentDirectory = path.join(
options.targetDirectory,
'node_modules/@pega/custom-dx-components'
);
options.componentLibraryUtilsDirectory = path.join(
options.targetDirectory,
'node_modules/@pega/constellation-dx-components-build-utils'
);
});
const installDependenciesText = `Installing dependencies. This will take a couple of minutes.`;
const tasks = new Listr(
[
{
title: `Creating a new custom component project in ${chalk.blue(options.targetDirectory)}`,
task: () => copyProjectTemplate(options)
},
{
title: 'Create gitignore',
task: () => createGitignore(options)
},
{
title: 'Initialize git',
task: () => initGit(options),
enabled: () => options.git
},
/*
{
title: installDependenciesText,
task: () =>
execPromise('npm i --force --production=false', { cwd: options.targetDirectory })
},
*/
{
title: installDependenciesText,
task: () =>
execPromise('npm i --force --dev', { cwd: options.targetDirectory })
},
/*
{
title: 'Installing tasks dependencies',
task: () =>
execPromise('npm i --force --production=false', { cwd: options.componentDirectory })
},
{
title: 'Installing tasks library dependencies',
task: () =>
execPromise('npm i --force --production=false', {
cwd: options.componentLibraryUtilsDirectory
})
},
*/
{
title: 'Updating',
task: () => execPromise('npm update --dev', { cwd: options.targetDirectory })
}
/* {
title: 'Installing quick run',
task: () => execPromise('npm i -g npm-quick-run', { cwd: options.targetDirectory })
} */
],
{
exitOnError: false
}
);
await tasks.run();
console.log('\n');
console.log(
`${chalk.green('Success!!')} Project created at ${chalk.blueBright(options.targetDirectory)}`
);
console.log(
'\n',
`Inside that directory, you can run several commands:`,
'\n\n',
`${chalk.blueBright('npm run startStorybook')}`,
`\n Start Storybook in development mode`,
'\n\n',
`${chalk.blueBright('npm run create')}`,
'\n',
`${chalk.blueBright('npm run list')}`,
`\n Try out custom-component actions like create, list, publish, etc`,
'\n\n',
`${chalk.blueBright('npm run lint')}`,
`\n Run eslint for component source files`,
'\n'
);
console.log(
`We suggest that you begin by typing:`,
'\n\n',
`${chalk.blueBright('cd')} ${chalk.bold(projectName)}`,
'\n',
`${chalk.blueBright('npm run startStorybook')}`,
'\n'
);
return true;
};