UNPKG

@npio/cli

Version:

A free visual website editor, powered with your own SolidJS components.

202 lines (171 loc) 5.78 kB
"use strict"; import { createId, init } from "@paralleldrive/cuid2"; import { spawnSync } from "child_process"; import { access, mkdir, readFile, writeFile } from "fs/promises"; import { getSchemaRootDir, initialize, runtimePath, titleCase, } from "nitropage/internals"; import { name, version } from "nitropage/package.json"; import path, { dirname } from "path"; import c from "picocolors"; import sade from "sade"; import { fileURLToPath, pathToFileURL } from "url"; import { configCommands } from "./config"; import { demoCommands } from "./demo"; import { userCommands } from "./user"; import { getDatabaseProvider } from "./util"; const { default: config } = await import( pathToFileURL( path.join(process.cwd(), runtimePath, "server.config.ts"), ).toString() ); initialize(config, { cli: true }); const prog = sade(name).version(version); prog .command("update") .describe( "Import the Nitropage specific prisma models into your schema folder", ) .option( "--migrate, -m", `Run ${c.magenta("prisma migrate dev")} after import`, ) .action(async (opts: { migrate: boolean }) => { const depPath = path.dirname(fileURLToPath(import.meta.url)); // TODO: find the prisma schema location based on prisma conventions // https://www.prisma.io/docs/concepts/components/prisma-schema#prisma-schema-file-location let provider = await getDatabaseProvider(); const supportedProviders = ["sqlite"]; if (!supportedProviders.includes(provider)) { const fallbackProvider = "sqlite"; console.warn( c.magenta( `Detected datasource provider ${c.bold( provider, )} is not officially supported. Trying ${c.bold( fallbackProvider, )} instead.`, ), ); provider = fallbackProvider; } console.log(`Importing schema for ${c.bold(provider)} datasource provider`); const schemaSourcePath = path.resolve( depPath, "..", "prisma", `${provider}.prisma`, ); const sourceSchema = await readFile(schemaSourcePath, { encoding: "utf8" }); const sourceRegex = /(model[\S\s]*)/; const sourceModels = sourceSchema.match(sourceRegex)![1]; const npSchema = "// Generated by Nitropage, do not manually change this file.\n\n" + sourceModels; const npSchemaPath = path.join(getSchemaRootDir(), "nitropage.prisma"); await writeFile(npSchemaPath, npSchema); console.log(`Updated prisma schema: ${c.green(npSchemaPath)}`); if (!opts.migrate) { return; } spawnSync("pnpm", "prisma migrate dev".split(" "), { stdio: "inherit", }); }); prog .command("env") .describe("Generate a basic .env file") .action(async () => { const provider = await getDatabaseProvider(); const providerExamples = { sqlite: "file:../.data/dev.db", postgres: "postgresql://USER:PASSWORD@HOST:PORT/DATABASE", mysql: "mysql://USER:PASSWORD@HOST:PORT/DATABASE", mongodb: "mongodb://USERNAME:PASSWORD@HOST/DATABASE", }; const result = `# URL Options: https://pris.ly/d/connection-strings DATABASE_URL=${(providerExamples as any)[provider] || providerExamples.sqlite} NP_AUTH_SALT=${init({ length: 20 })()} NP_AUTH_PASSWORD=${init({ length: 32 })()}`; console.log(result); }); prog .command("blueprint <name>") .describe("Generate a new blueprint") .example("blueprint button") .example("blueprint menu") .option("--out-dir, -d", "Provide path to elements", "src/blueprints") .action(async (blueprintName: string, opts: { d: string }) => { const componentsPath = path.join(process.cwd(), opts.d); await access(componentsPath); const findAvailableName = async function ( number?: number, ): Promise<{ filename: string; filepath: string; number?: number }> { if (number != null && number > 9) { throw new Error( `Blueprint name ${c.bold( blueprintName, )} is already used nine times, what are you doing?`, ); } const suffix = number != null ? number : ""; const filename = `${blueprintName}${suffix}.np.tsx`; const filepath = path.join(componentsPath, filename); const exists = await access(filepath) .then(() => true) .catch(() => false); if (!exists) { return { filename, filepath, number }; } number = number || 1; number++; return findAvailableName(number); }; const { filepath, number } = await findAvailableName(); await mkdir(dirname(filepath), { recursive: true }); const titleSuffix = number != null ? " " + number : ""; const title = `${titleCase(blueprintName)}${titleSuffix}`; const titleJson = number != null ? "\n" + ` title: () => "${title}",` : ""; const template = `import { BaseBlueprint, BlueprintComponent, createBlueprint } from "nitropage"; import { useCss } from "nitropage/css"; const MyComponent: BlueprintComponent<typeof blueprint> = function (props) { const css = useCss(); return ( <div class={css({ padding: "3rem", })} {...props.elementProps} > {props.handles} <props.Slot key="default" /> </div> ); }; export const blueprint = createBlueprint( () => { return {${titleJson} slots: { default: {} }, data: {}, } satisfies BaseBlueprint; }, import.meta.hot, ); export default MyComponent; export const id = "${createId()}"; `; await writeFile(filepath, template); console.log( c.green( `Scaffolded new blueprint "${c.bold(title)}" in ${c.bold(filepath)}`, ), ); }); configCommands(prog); userCommands(prog); demoCommands(prog); prog.parse(process.argv);