UNPKG

typia

Version:

Superfast runtime validators with only one line

172 lines (156 loc) 5.38 kB
import fs from "fs"; import { DetectResult, detect } from "package-manager-detector"; import { ArgumentParser } from "./setup/ArgumentParser"; import { CommandExecutor } from "./setup/CommandExecutor"; import { PackageManager } from "./setup/PackageManager"; import { PluginConfigurator } from "./setup/PluginConfigurator"; export namespace TypiaSetupWizard { export interface IArguments { manager: "npm" | "pnpm" | "yarn" | "bun"; project: string | null; } export const setup = async (): Promise<void> => { console.log("----------------------------------------"); console.log(" Typia Setup Wizard"); console.log("----------------------------------------"); // PREPARE ASSETS const pack: PackageManager = await PackageManager.mount(); const args: IArguments = await ArgumentParser.parse(pack, inquiry); // INSTALL TYPESCRIPT COMPILERS pack.install({ dev: true, modulo: "typescript", version: await getTypeScriptVersion(), }); pack.install({ dev: true, modulo: "ts-patch", version: "latest" }); args.project ??= (() => { const runner: string = pack.manager === "npm" ? "npx" : pack.manager; CommandExecutor.run(`${runner} tsc --init`); return (args.project = "tsconfig.json"); })(); // SETUP TRANSFORMER await pack.save((data) => { // COMPOSE PREPARE COMMAND data.scripts ??= {}; if ( typeof data.scripts.prepare === "string" && data.scripts.prepare.trim().length !== 0 ) { if (data.scripts.prepare.includes("ts-patch install") === false) data.scripts.prepare = "ts-patch install && " + data.scripts.prepare; } else data.scripts.prepare = "ts-patch install"; // NO MORE "typia patch" REQUIRED data.scripts.prepare = data.scripts.prepare .split("&&") .map((str) => str.trim()) .filter((str) => str !== "typia patch") .join(" && "); // FOR OLDER VERSIONS if (typeof data.scripts.postinstall === "string") { data.scripts.postinstall = data.scripts.postinstall .split("&&") .map((str) => str.trim()) .filter((str) => str.indexOf("ts-patch install") === -1) .join(" && "); if (data.scripts.postinstall.length === 0) delete data.scripts.postinstall; } }); // CONFIGURE TYPIA await PluginConfigurator.configure(args); CommandExecutor.run(`${pack.manager} run prepare`); }; const inquiry: ArgumentParser.Inquiry<IArguments> = async ( pack, command, prompt, action, ) => { // PREPARE ASSETS command.option("--manager [manager", "package manager"); command.option("--project [project]", "tsconfig.json file location"); // INTERNAL PROCEDURES const questioned = { value: false }; const select = (name: string) => (message: string) => async <Choice extends string>( choices: Choice[], filter?: (choice: string) => Choice, ): Promise<Choice> => { questioned.value = true; return ( await prompt()({ type: "list", name: name, message: message, choices: choices, ...(filter ? { filter } : {}), }) )[name]; }; const configure = async (): Promise<string | null> => { const fileList: string[] = await ( await fs.promises.readdir(process.cwd()) ) .filter( (str) => str.substring(0, 8) === "tsconfig" && str.substring(str.length - 5) === ".json", ) .sort((x, y) => x === "tsconfig.json" ? -1 : y === "tsconfig.json" ? 1 : x < y ? -1 : 1, ); if (fileList.length === 0) { if (process.cwd() !== pack.directory) throw new URIError(`Unable to find "tsconfig.json" file.`); return null; } else if (fileList.length === 1) return fileList[0]!; return select("tsconfig")("TS Config File")(fileList); }; // DO CONSTRUCT return action(async (options) => { pack.manager = options.manager ??= (await detectManager()) ?? (await select("manager")("Package Manager")( [ "npm" as const, "pnpm" as const, "bun" as const, "yarn (berry is not supported)" as "yarn", ], (value) => value.split(" ")[0] as "yarn", )); options.project ??= await configure(); if (questioned.value) console.log(""); return options as IArguments; }); }; const detectManager = async (): Promise< "npm" | "pnpm" | "yarn" | "bun" | null > => { const result: DetectResult | null = await detect({ cwd: process.cwd() }); switch (result?.name) { case "npm": case "deno": return null; // NPM case is still selectable & Deno is not supported default: return result?.name ?? null; } }; const getTypeScriptVersion = async (): Promise<string> => { const content: string = await fs.promises.readFile( `${__dirname}/../../package.json`, "utf-8", ); const json: { devDependencies: { typescript: string } } = JSON.parse(content); return json.devDependencies.typescript; }; }