piral-cli
Version:
The standard CLI for creating and building a Piral instance or a Pilet.
266 lines (230 loc) • 6.93 kB
text/typescript
import { resolve, basename } from 'path';
import { SourceLanguage, LogLevels, NpmClientType } from '../types';
import {
ForceOverwrite,
createDirectory,
createFileIfNotExists,
copyPiralFiles,
patchPiletPackage,
scaffoldPiletSourceFiles,
installNpmDependencies,
readPiralPackage,
getPiletsInfo,
runScript,
checkAppShellPackage,
setLogLevel,
fail,
progress,
log,
logDone,
determineNpmClient,
copyScaffoldingFiles,
getPiralPath,
getPiletScaffoldData,
config,
initNpmProject,
cliVersion,
installPiralInstance,
piletJson,
defaultSchemaVersion,
piletJsonSchemaUrl,
ensure,
getCertificate,
getAgent,
} from '../common';
export interface NewPiletOptions {
/**
* The package registry to use for resolving the specified Piral app.
*/
registry?: string;
/**
* The target directory for scaffolding. By default, the current directory.
*/
target?: string;
/**
* The source package containing a Piral instance for templating the scaffold process.
*/
source?: string;
/**
* Defines a custom certificate for the website emulator.
*/
cert?: string;
/**
* Allow self-signed certificates.
*/
allowSelfSigned?: boolean;
/**
* Determines if files should be overwritten by the scaffolding.
*/
forceOverwrite?: ForceOverwrite;
/**
* Determines the programming language for the new pilet.
* @example 'ts'
*/
language?: SourceLanguage;
/**
* States if the npm dependencies should be installed when scaffolding.
*/
install?: boolean;
/**
* Sets the boilerplate template to be used when scaffolding.
* @example 'empty'
*/
template?: string;
/**
* Sets the log level to use (1-5).
*/
logLevel?: LogLevels;
/**
* The npm client to be used when scaffolding.
* @example 'yarn'
*/
npmClient?: NpmClientType;
/**
* Sets the default bundler to install.
* @example 'parcel'
*/
bundlerName?: string;
/**
* Places additional variables that should used when scaffolding.
*/
variables?: Record<string, string>;
/**
* Sets Pilet's name
*/
name?: string;
}
export const newPiletDefaults: NewPiletOptions = {
target: '.',
registry: config.registry,
source: undefined,
forceOverwrite: ForceOverwrite.no,
language: config.language,
install: true,
template: undefined,
logLevel: LogLevels.info,
npmClient: undefined,
bundlerName: 'none',
variables: {},
name: undefined,
cert: undefined,
allowSelfSigned: config.allowSelfSigned,
};
export async function newPilet(baseDir = process.cwd(), options: NewPiletOptions = {}) {
const {
target = newPiletDefaults.target,
registry = newPiletDefaults.registry,
source = newPiletDefaults.source,
forceOverwrite = newPiletDefaults.forceOverwrite,
language = newPiletDefaults.language,
install = newPiletDefaults.install,
template = newPiletDefaults.template,
logLevel = newPiletDefaults.logLevel,
bundlerName = newPiletDefaults.bundlerName,
variables = newPiletDefaults.variables,
npmClient: defaultNpmClient = newPiletDefaults.npmClient,
name = newPiletDefaults.name,
cert = newPiletDefaults.cert,
allowSelfSigned = newPiletDefaults.allowSelfSigned,
} = options;
ensure('baseDir', baseDir, 'string');
ensure('source', source, 'string');
ensure('target', target, 'string');
ensure('template', template, ['string', 'undefined']);
ensure('variables', variables, 'object');
const fullBase = resolve(process.cwd(), baseDir);
const root = resolve(fullBase, target);
setLogLevel(logLevel);
progress('Preparing source and target ...');
const success = await createDirectory(root);
if (success) {
const npmClient = await determineNpmClient(root, defaultNpmClient);
const ca = await getCertificate(cert);
const agent = getAgent({ ca, allowSelfSigned });
const projectName = name || basename(root);
progress(`Scaffolding new pilet in %s ...`, root);
await createFileIfNotExists(
root,
'package.json',
JSON.stringify(
{
name: projectName,
version: '1.0.0',
description: '',
keywords: ['pilet'],
dependencies: {},
devDependencies: {},
peerDependencies: {},
scripts: {},
main: 'dist/index.js',
files: ['dist'],
},
undefined,
2,
),
);
await initNpmProject(npmClient, projectName, root);
if (registry !== newPiletDefaults.registry) {
progress(`Setting up npm registry (%s) ...`, registry);
await createFileIfNotExists(
root,
'.npmrc',
`registry=${registry}
always-auth=true`,
forceOverwrite,
);
}
await createFileIfNotExists(
root,
piletJson,
JSON.stringify(
{
$schema: piletJsonSchemaUrl,
schemaVersion: defaultSchemaVersion,
piralInstances: {},
},
undefined,
2,
),
);
const sourceName = source || `empty-piral@${cliVersion}`;
const packageName = await installPiralInstance(sourceName, fullBase, root, npmClient, agent, true);
const piralInfo = await readPiralPackage(root, packageName);
const isEmulator = checkAppShellPackage(piralInfo);
const { preScaffold, postScaffold, files, template: preSelectedTemplate } = getPiletsInfo(piralInfo);
if (preScaffold) {
progress(`Running preScaffold script ...`);
log('generalDebug_0003', `Run: ${preScaffold}`);
await runScript(preScaffold, root);
}
progress(`Taking care of templating ...`);
const data = getPiletScaffoldData(language, root, packageName, variables);
await patchPiletPackage(root, piralInfo, isEmulator, npmClient, {
language,
bundler: bundlerName,
});
const chosenTemplate = template || preSelectedTemplate || 'default';
await scaffoldPiletSourceFiles(chosenTemplate, registry, data, forceOverwrite);
if (isEmulator) {
// in the emulator case we get the files (and files_once) from the contained tarballs
await copyPiralFiles(root, packageName, piralInfo, ForceOverwrite.yes, data);
} else {
// otherwise, we perform the same action as in the emulator creation
// just with a different target; not a created directory, but the root
const packageRoot = getPiralPath(root, packageName);
await copyScaffoldingFiles(packageRoot, root, files, piralInfo, data);
}
if (install) {
progress(`Installing dependencies ...`);
await installNpmDependencies(npmClient, root);
}
if (postScaffold) {
progress(`Running postScaffold script ...`);
log('generalDebug_0003', `Run: ${postScaffold}`);
await runScript(postScaffold, root);
}
logDone(`Pilet scaffolded successfully!`);
} else {
fail('cannotCreateDirectory_0044');
}
}