frontity
Version:
Frontity cli and entry point to other packages
134 lines (119 loc) • 4.22 kB
text/typescript
import chalk from "chalk";
import { CreateCommandOptions } from "../steps/types";
import { EventPromised } from "../utils/eventPromised";
import {
normalizeOptions,
ensureProjectDir,
createPackageJson,
createReadme,
createFrontitySettings,
createTsConfig,
cloneStarterTheme,
installDependencies,
downloadFavicon,
initializeGit,
revertProgress,
createGitignore,
} from "../steps";
import { hasGit, isInGitRepository } from "../utils";
const defaultOptions: CreateCommandOptions = {
path: process.cwd(),
typescript: false,
noGit: false,
packages: [],
theme: "@frontity/mars-theme",
};
/**
* The types of events supported by the EventEmitter generated by `EventPromised`.
*/
type EventTypes = "error" | "message" | "subscribe";
/**
* The create command, exported to be used programatically.
*
* @param options - The options of the create command. Defined by {@link
* CreateCommandOptions}.
*
* @returns An instance of {@link EventPromised}, which is a promise that can
* also send events using an EventEmitter.
*/
export default (options?: CreateCommandOptions) =>
// EventPromised is a combination of EventEmitter and Promise.
new EventPromised<EventTypes>((resolve, reject, emit) => {
// Run an async action to be able to use `await`.
(async () => {
let step: Promise<any>;
let dirExisted: boolean;
// Parses and validates options.
const { name, theme, path, typescript, noGit }: CreateCommandOptions =
normalizeOptions(defaultOptions, options);
process.on("SIGINT", async () => {
if (typeof dirExisted !== "undefined")
await revertProgress(dirExisted, path);
});
try {
// Ensures that the project dir exists and is empty.
step = ensureProjectDir(path);
emit("message", `Ensuring ${chalk.yellow(path)} directory.`, step);
dirExisted = await step;
// Creates `README.md`
step = createReadme(name, path);
emit("message", `Creating ${chalk.yellow("README.md")}.`, step);
await step;
// Creates `package.json`.
step = createPackageJson(name, theme, path, typescript);
emit("message", `Creating ${chalk.yellow("package.json")}.`, step);
await step;
// Creates `frontity.settings`.
const extension = typescript ? "ts" : "js";
step = createFrontitySettings(extension, name, path, theme);
emit(
"message",
`Creating ${chalk.yellow(`frontity.settings.${extension}`)}.`,
step
);
await step;
// Creates `tsconfig.json`.
if (typescript) {
step = createTsConfig(path);
emit("message", `Creating ${chalk.yellow("tsconfig.json")}.`, step);
await step;
}
// Clones the theme inside `packages`.
step = cloneStarterTheme(theme, path);
emit("message", `Cloning ${chalk.green(theme)}.`, step);
await step;
// Installs dependencies.
step = installDependencies(path);
emit("message", `Installing dependencies.`, step);
await step;
// Download favicon.
step = downloadFavicon(path);
emit("message", `Downloading ${chalk.yellow("favicon.ico")}.`, step);
await step;
// Run this step if `noGit` is false and if git is installed on user's machine
if (!noGit && hasGit()) {
const gitignoreCleanup = await createGitignore(path);
if (isInGitRepository()) {
emit(
"message",
"Already in a git repository. Skipping initialization of a new git repo.",
step
);
} else {
step = initializeGit(path);
emit("message", `Initializing git repo.`, step);
try {
await step;
} catch (e) {
await gitignoreCleanup();
emit("message", `Git initialization failed. Skipping...`, step);
}
}
}
} catch (error) {
if (typeof dirExisted !== "undefined")
await revertProgress(dirExisted, path);
reject(error);
}
})().then(resolve);
});