added format command and added trailing commas to reduce conflicts

This commit is contained in:
dswbx
2025-02-26 20:06:03 +01:00
parent 88b5359f1c
commit 7743f71a11
414 changed files with 3622 additions and 3610 deletions

View File

@@ -13,18 +13,18 @@ import { type Template, templates } from "./templates";
const config = {
types: {
runtime: "Runtime",
framework: "Framework"
framework: "Framework",
},
runtime: {
node: "Node.js",
bun: "Bun",
cloudflare: "Cloudflare"
cloudflare: "Cloudflare",
},
framework: {
nextjs: "Next.js",
remix: "Remix",
astro: "Astro"
}
astro: "Astro",
},
} as const;
export const create: CliCommand = (program) => {
@@ -41,7 +41,7 @@ function errorOutro() {
$p.outro(color.red("Failed to create project."));
console.log(
color.yellow("Sorry that this happened. If you think this is a bug, please report it at: ") +
color.cyan("https://github.com/bknd-io/bknd/issues")
color.cyan("https://github.com/bknd-io/bknd/issues"),
);
console.log("");
process.exit(1);
@@ -53,26 +53,26 @@ async function action(options: { template?: string; dir?: string; integration?:
const downloadOpts = {
dir: options.dir || "./",
clean: false
clean: false,
};
const version = await getVersion();
$p.intro(
`👋 Welcome to the ${color.bold(color.cyan("bknd"))} create wizard ${color.bold(`v${version}`)}`
`👋 Welcome to the ${color.bold(color.cyan("bknd"))} create wizard ${color.bold(`v${version}`)}`,
);
await $p.stream.message(
(async function* () {
yield* typewriter("Thanks for choosing to create a new project with bknd!", color.dim);
await wait();
})()
})(),
);
if (!options.dir) {
const dir = await $p.text({
message: "Where to create your project?",
placeholder: downloadOpts.dir,
initialValue: downloadOpts.dir
initialValue: downloadOpts.dir,
});
if ($p.isCancel(dir)) {
process.exit(1);
@@ -84,7 +84,7 @@ async function action(options: { template?: string; dir?: string; integration?:
if (fs.existsSync(downloadOpts.dir)) {
const clean = await $p.confirm({
message: `Directory ${color.cyan(downloadOpts.dir)} exists. Clean it?`,
initialValue: false
initialValue: false,
});
if ($p.isCancel(clean)) {
process.exit(1);
@@ -115,7 +115,7 @@ async function action(options: { template?: string; dir?: string; integration?:
await wait(2);
yield* typewriter("Let's find the perfect template for you.", color.dim);
await wait(2);
})()
})(),
);
const type = await $p.select({
@@ -123,8 +123,8 @@ async function action(options: { template?: string; dir?: string; integration?:
options: Object.entries(config.types).map(([value, name]) => ({
value,
label: name,
hint: Object.values(config[value]).join(", ")
}))
hint: Object.values(config[value]).join(", "),
})),
});
if ($p.isCancel(type)) {
@@ -135,8 +135,8 @@ async function action(options: { template?: string; dir?: string; integration?:
message: `Which ${color.cyan(config.types[type])} do you want to continue with?`,
options: Object.entries(config[type]).map(([value, name]) => ({
value,
label: name
})) as any
label: name,
})) as any,
});
if ($p.isCancel(_integration)) {
process.exit(1);
@@ -157,7 +157,7 @@ async function action(options: { template?: string; dir?: string; integration?:
} else if (choices.length > 1) {
const selected_template = await $p.select({
message: "Pick a template",
options: choices.map((t) => ({ value: t.key, label: t.title, hint: t.description }))
options: choices.map((t) => ({ value: t.key, label: t.title, hint: t.description })),
});
if ($p.isCancel(selected_template)) {
@@ -196,7 +196,7 @@ async function action(options: { template?: string; dir?: string; integration?:
try {
await downloadTemplate(url, {
dir: ctx.dir,
force: downloadOpts.clean ? "clean" : true
force: downloadOpts.clean ? "clean" : true,
});
} catch (e) {
if (e instanceof Error) {
@@ -221,15 +221,15 @@ async function action(options: { template?: string; dir?: string; integration?:
await overridePackageJson(
(pkg) => ({
...pkg,
name: ctx.name
name: ctx.name,
}),
{ dir: ctx.dir }
{ dir: ctx.dir },
);
$p.log.success(`Updated package name to ${color.cyan(ctx.name)}`);
{
const install = await $p.confirm({
message: "Install dependencies?"
message: "Install dependencies?",
});
if ($p.isCancel(install)) {
@@ -263,10 +263,10 @@ async function action(options: { template?: string; dir?: string; integration?:
yield* typewriter(
color.dim("Remember to run ") +
color.cyan("npm install") +
color.dim(" after setup")
color.dim(" after setup"),
);
await wait();
})()
})(),
);
}
}
@@ -284,10 +284,10 @@ async function action(options: { template?: string; dir?: string; integration?:
yield "\n\n";
yield* typewriter(
`Enter your project's directory using ${color.cyan("cd " + ctx.dir)}
If you need help, check ${color.cyan("https://docs.bknd.io")} or join our Discord!`
If you need help, check ${color.cyan("https://docs.bknd.io")} or join our Discord!`,
);
await wait(2);
})()
})(),
);
$p.outro(color.green("Setup complete."));

View File

@@ -16,7 +16,7 @@ export type TPackageJson = Partial<{
export async function overrideJson<File extends object = object>(
file: string,
fn: (pkg: File) => Promise<File> | File,
opts?: { dir?: string; indent?: number }
opts?: { dir?: string; indent?: number },
) {
const pkgPath = path.resolve(opts?.dir ?? process.cwd(), file);
const pkg = await readFile(pkgPath, "utf-8");
@@ -26,7 +26,7 @@ export async function overrideJson<File extends object = object>(
export async function overridePackageJson(
fn: (pkg: TPackageJson) => Promise<TPackageJson> | TPackageJson,
opts?: { dir?: string }
opts?: { dir?: string },
) {
return await overrideJson("package.json", fn, { dir: opts?.dir });
}
@@ -44,7 +44,7 @@ export async function getVersion(pkg: string, version: string = "latest") {
const _deps = ["dependencies", "devDependencies", "optionalDependencies"] as const;
export async function replacePackageJsonVersions(
fn: (pkg: string, version: string) => Promise<string | undefined> | string | undefined,
opts?: { include?: (keyof typeof _deps)[]; dir?: string }
opts?: { include?: (keyof typeof _deps)[]; dir?: string },
) {
const deps = (opts?.include ?? _deps) as string[];
await overridePackageJson(
@@ -62,14 +62,14 @@ export async function replacePackageJsonVersions(
return json;
},
{ dir: opts?.dir }
{ dir: opts?.dir },
);
}
export async function updateBkndPackages(dir?: string, map?: Record<string, string>) {
const versions = {
bknd: "^" + (await sysGetVersion()),
...(map ?? {})
...(map ?? {}),
};
await replacePackageJsonVersions(
async (pkg) => {
@@ -78,6 +78,6 @@ export async function updateBkndPackages(dir?: string, map?: Record<string, stri
}
return;
},
{ dir }
{ dir },
);
}

View File

@@ -22,18 +22,18 @@ export const cloudflare = {
...json,
name: ctx.name,
assets: {
directory: "node_modules/bknd/dist/static"
}
directory: "node_modules/bknd/dist/static",
},
}),
{ dir: ctx.dir }
{ dir: ctx.dir },
);
const db = await $p.select({
message: "What database do you want to use?",
options: [
{ label: "Cloudflare D1", value: "d1" },
{ label: "LibSQL", value: "libsql" }
]
{ label: "LibSQL", value: "libsql" },
],
});
if ($p.isCancel(db)) {
process.exit(1);
@@ -53,10 +53,10 @@ export const cloudflare = {
} catch (e) {
const message = (e as any).message || "An error occurred";
$p.log.warn(
"Couldn't add database. You can add it manually later. Error: " + c.red(message)
"Couldn't add database. You can add it manually later. Error: " + c.red(message),
);
}
}
},
} as const satisfies Template;
async function createD1(ctx: TemplateSetupCtx) {
@@ -69,7 +69,7 @@ async function createD1(ctx: TemplateSetupCtx) {
return "Invalid name";
}
return;
}
},
});
if ($p.isCancel(name)) {
process.exit(1);
@@ -83,11 +83,11 @@ async function createD1(ctx: TemplateSetupCtx) {
{
binding: "DB",
database_name: name,
database_id: uuid()
}
]
database_id: uuid(),
},
],
}),
{ dir: ctx.dir }
{ dir: ctx.dir },
);
await $p.stream.info(
@@ -96,9 +96,9 @@ async function createD1(ctx: TemplateSetupCtx) {
await wait();
yield* typewriter(
`\nNote that if you deploy, you have to create a real database using ${c.cyan("npx wrangler d1 create <name>")} and update your wrangler configuration.`,
c.dim
c.dim,
);
})()
})(),
);
}
@@ -108,10 +108,10 @@ async function createLibsql(ctx: TemplateSetupCtx) {
(json) => ({
...json,
vars: {
DB_URL: "http://127.0.0.1:8080"
}
DB_URL: "http://127.0.0.1:8080",
},
}),
{ dir: ctx.dir }
{ dir: ctx.dir },
);
await overridePackageJson(
@@ -120,10 +120,10 @@ async function createLibsql(ctx: TemplateSetupCtx) {
scripts: {
...pkg.scripts,
db: "turso dev",
dev: "npm run db && wrangler dev"
}
dev: "npm run db && wrangler dev",
},
}),
{ dir: ctx.dir }
{ dir: ctx.dir },
);
await $p.stream.info(
@@ -132,13 +132,13 @@ async function createLibsql(ctx: TemplateSetupCtx) {
await wait();
yield* typewriter(
`\nYou can now run ${c.cyan("npm run db")} to start the database and ${c.cyan("npm run dev")} to start the worker.`,
c.dim
c.dim,
);
await wait();
yield* typewriter(
`\nAlso make sure you have Turso's CLI installed. Check their docs on how to install at ${c.cyan("https://docs.turso.tech/cli/introduction")}`,
c.dim
c.dim,
);
})()
})(),
);
}

View File

@@ -43,7 +43,7 @@ export const templates: Template[] = [
integration: "node",
description: "A basic bknd Node.js server",
path: "gh:bknd-io/bknd/examples/node",
ref: true
ref: true,
},
{
key: "bun",
@@ -51,7 +51,7 @@ export const templates: Template[] = [
integration: "bun",
description: "A basic bknd Bun server",
path: "gh:bknd-io/bknd/examples/bun",
ref: true
ref: true,
},
{
key: "astro",
@@ -59,6 +59,6 @@ export const templates: Template[] = [
integration: "astro",
description: "A basic bknd Astro starter",
path: "gh:bknd-io/bknd/examples/astro",
ref: true
}
ref: true,
},
];

View File

@@ -9,7 +9,7 @@ export const nextjs = {
description: "A basic bknd Next.js starter",
path: "gh:bknd-io/bknd/examples/nextjs",
scripts: {
install: "npm install --force"
install: "npm install --force",
},
ref: true,
preinstall: async (ctx) => {
@@ -20,10 +20,10 @@ export const nextjs = {
dependencies: {
...pkg.dependencies,
react: undefined,
"react-dom": undefined
}
"react-dom": undefined,
},
}),
{ dir: ctx.dir }
{ dir: ctx.dir },
);
}
},
} as const satisfies Template;

View File

@@ -16,10 +16,10 @@ export const remix = {
dependencies: {
...pkg.dependencies,
react: "^18.2.0",
"react-dom": "^18.2.0"
}
"react-dom": "^18.2.0",
},
}),
{ dir: ctx.dir }
{ dir: ctx.dir },
);
}
},
} as const satisfies Template;

View File

@@ -23,7 +23,7 @@ const subjects = {
relativeDistPath: getRelativeDistPath(),
cwd: process.cwd(),
dir: path.dirname(url.fileURLToPath(import.meta.url)),
resolvedPkg: path.resolve(getRootPath(), "package.json")
resolvedPkg: path.resolve(getRootPath(), "package.json"),
});
},
routes: async () => {
@@ -32,7 +32,7 @@ const subjects = {
const app = createApp({ connection: credentials });
await app.build();
showRoutes(app.server);
}
},
};
async function action(subject: string) {

View File

@@ -14,13 +14,13 @@ export async function serveStatic(server: Platform): Promise<MiddlewareHandler>
const m = await import("@hono/node-server/serve-static");
return m.serveStatic({
// somehow different for node
root: getRelativeDistPath() + "/static"
root: getRelativeDistPath() + "/static",
});
}
case "bun": {
const m = await import("hono/bun");
return m.serveStatic({
root: path.resolve(getRelativeDistPath(), "static")
root: path.resolve(getRelativeDistPath(), "static"),
});
}
}
@@ -40,14 +40,14 @@ export async function startServer(server: Platform, app: any, options: { port: n
const serve = await import("@hono/node-server").then((m) => m.serve);
serve({
fetch: (req) => app.fetch(req),
port
port,
});
break;
}
case "bun": {
Bun.serve({
fetch: (req) => app.fetch(req),
port
port,
});
break;
}

View File

@@ -13,7 +13,7 @@ import {
attachServeStatic,
getConfigPath,
getConnectionCredentialsFromEnv,
startServer
startServer,
} from "./platform";
dotenv.config();
@@ -26,26 +26,26 @@ export const run: CliCommand = (program) => {
new Option("-p, --port <port>", "port to run on")
.env("PORT")
.default(config.server.default_port)
.argParser((v) => Number.parseInt(v))
.argParser((v) => Number.parseInt(v)),
)
.addOption(
new Option("-m, --memory", "use in-memory database").conflicts([
"config",
"db-url",
"db-token"
])
"db-token",
]),
)
.addOption(new Option("-c, --config <config>", "config file"))
.addOption(
new Option("--db-url <db>", "database url, can be any valid libsql url").conflicts(
"config"
)
"config",
),
)
.addOption(new Option("--db-token <db>", "database token").conflicts("config"))
.addOption(
new Option("--server <server>", "server type")
.choices(PLATFORMS)
.default(isBun ? "bun" : "node")
.default(isBun ? "bun" : "node"),
)
.action(action);
};
@@ -76,7 +76,7 @@ async function makeApp(config: MakeAppConfig) {
await config.onBuilt(app);
}
},
"sync"
"sync",
);
await app.build();
@@ -95,7 +95,7 @@ export async function makeConfigApp(config: CliBkndConfig, platform?: Platform)
await config.onBuilt?.(app);
},
"sync"
"sync",
);
await config.beforeBuild?.(app);
@@ -141,7 +141,7 @@ async function action(options: {
console.info("Using connection", c.cyan(connection.url));
app = await makeApp({
connection,
server: { platform: options.server }
server: { platform: options.server },
});
}

View File

@@ -48,7 +48,7 @@ async function create(app: App, options: any) {
return "Invalid email";
}
return;
}
},
});
const password = await $password({
@@ -58,7 +58,7 @@ async function create(app: App, options: any) {
return "Invalid password";
}
return;
}
},
});
if (typeof email !== "string" || typeof password !== "string") {
@@ -69,8 +69,8 @@ async function create(app: App, options: any) {
try {
const created = await app.createUser({
email,
password: await strategy.hash(password as string)
})
password: await strategy.hash(password as string),
});
console.log("Created:", created);
} catch (e) {
console.error("Error", e);
@@ -90,7 +90,7 @@ async function update(app: App, options: any) {
return "Invalid email";
}
return;
}
},
})) as string;
if (typeof email !== "string") {
console.log("Cancelled");
@@ -111,7 +111,7 @@ async function update(app: App, options: any) {
return "Invalid password";
}
return;
}
},
});
if (typeof password !== "string") {
console.log("Cancelled");
@@ -130,7 +130,7 @@ async function update(app: App, options: any) {
.ctx()
.em.mutator(users_entity)
.updateOne(user.id, {
strategy_value: await strategy.hash(password as string)
strategy_value: await strategy.hash(password as string),
});
togglePw(false);
@@ -138,4 +138,4 @@ async function update(app: App, options: any) {
} catch (e) {
console.error("Error", e);
}
}
}

View File

@@ -12,7 +12,7 @@ export default function ansiRegex({ onlyFirst = false } = {}) {
const ST = "(?:\\u0007|\\u001B\\u005C|\\u009C)";
const pattern = [
`[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?${ST})`,
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))",
].join("|");
return new RegExp(pattern, onlyFirst ? undefined : "g");
@@ -22,7 +22,7 @@ const DEFAULT_WAIT_WRITER = _SPEEDUP ? 0 : 20;
export async function* typewriter(
text: string,
transform?: (char: string) => string,
_delay?: number
_delay?: number,
) {
const delay = DEFAULT_WAIT_WRITER * (_delay ?? 1);
const regex = ansiRegex();

View File

@@ -44,7 +44,7 @@ export function exec(command: string, opts?: { silent?: boolean; env?: Record<st
const stdio = opts?.silent ? "pipe" : "inherit";
const output = execSync(command, {
stdio: ["inherit", stdio, stdio],
env: { ...process.env, ...opts?.env }
env: { ...process.env, ...opts?.env },
});
if (!opts?.silent) {
return;
@@ -54,20 +54,20 @@ export function exec(command: string, opts?: { silent?: boolean; env?: Record<st
export function execAsync(
command: string,
opts?: { silent?: boolean; env?: Record<string, string> }
opts?: { silent?: boolean; env?: Record<string, string> },
) {
return new Promise((resolve, reject) => {
nodeExec(
command,
{
env: { ...process.env, ...opts?.env }
env: { ...process.env, ...opts?.env },
},
(err, stdout, stderr) => {
if (err) {
return reject(err);
}
resolve(stdout);
}
},
);
});
}