UNPKG

@nestia/sdk

Version:

Nestia SDK and Swagger generator

128 lines (117 loc) 4.09 kB
import { INestiaConfig } from "../../INestiaConfig"; import { NestiaSdkApplication } from "../../NestiaSdkApplication"; import { NestiaConfigLoader } from "./NestiaConfigLoader"; import { NestiaSdkWatcher } from "./NestiaSdkWatcher"; export namespace NestiaSdkCommand { export const sdk = () => main({ title: "SDK library", generate: (app) => app.sdk(), validate: (config) => !!config.output, solution: "configure INestiaConfig.output property.", }); export const swagger = () => main({ title: "Swagger Document", generate: (app) => app.swagger(), validate: (config) => !!config.swagger?.output, solution: "configure INestiaConfig.swagger property.", watch: hasFlagArgument("watch"), }); export const e2e = () => main({ title: "E2E Functions", generate: (app) => app.e2e(), validate: (config) => !!config.e2e, solution: [ "configure two properties:", "", " - INestiaConfig.output", " - INestiaConfig.e2e", ].join("\n"), }); export const all = () => main({ title: "everything", generate: (app) => app.all(), validate: () => true, solution: [ "configure at least one property of below:", "", " - INestiaConfig.output", " - INestiaConfig.swagger.output", ].join("\n"), }); const main = async (props: { title: string; solution: string; generate: (app: NestiaSdkApplication) => Promise<void>; validate: (config: INestiaConfig) => boolean; watch?: boolean; }) => { // LOAD CONFIG INFO const project: string = getFileArgument({ type: "project", extension: "json", }) ?? "tsconfig.json"; process.env.NESTIA_PROJECT = project; const configFile: string = getFileArgument({ type: "config", extension: "ts", }) ?? "nestia.config.ts"; const configurations = async (): Promise<INestiaConfig[]> => { const command: NestiaConfigLoader.ICompilerOptions = await NestiaConfigLoader.compilerOptions(project); return NestiaConfigLoader.configurations( configFile, command.raw.compilerOptions ?? {}, ); }; const generate = async (configurations: INestiaConfig[]): Promise<void> => { if ( configurations.length > 1 && configurations.some(props.validate) === false ) throw new Error( `Every configurations are invalid to generate ${props.title}, ${props.solution}`, ); for (const config of configurations) { if (configurations.length > 1 && props.validate(config) === false) continue; const app: NestiaSdkApplication = new NestiaSdkApplication(config); await props.generate(app); } }; if (props.watch === true) return NestiaSdkWatcher.watch({ configFile, configurations, generate, projectFile: project, }); await generate(await configurations()); }; const getFileArgument = (props: { type: string; extension: string; }): string | null => { const argv: string[] = process.argv.slice(3); const index: number = argv.findIndex((str) => str === `--${props.type}`); if (index === -1) return null; // Bound the VALUE position, not the whole argument list. The two only // coincide when the flag is the sole argument, so any preceding token used // to send `undefined` into endsWith() and report a TypeError instead of this // diagnostic. A following flag is a missing value too, not a badly named // file. const file: string | undefined = argv[index + 1]; if (file === undefined || file.startsWith("--")) throw new Error(`${props.type} file must be provided`); if (file.endsWith(props.extension) === false) throw new Error(`${props.type} file must be ${props.extension} file`); return file; }; const hasFlagArgument = (type: string): boolean => process.argv.slice(3).some((str) => str === `--${type}`); }