Skip to content

Commit 06c30b8

Browse files
committed
feat(cli): ♻️ Begin new CLI rewrite with oclif
1 parent 7b05a34 commit 06c30b8

File tree

21 files changed

+569
-11
lines changed

21 files changed

+569
-11
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,5 @@ glitch-old
179179
glitch
180180
glitch.tar.gz
181181
glitch-dev
182-
*.pem
182+
*.pem
183+
oclif.manifest.json

bun.lockb

171 KB
Binary file not shown.

drizzle/db.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { config } from "config-manager";
1+
import { config } from "~/packages/config-manager";
22
import { drizzle } from "drizzle-orm/node-postgres";
33
import { migrate } from "drizzle-orm/postgres-js/migrator";
44
import { LogLevel, type LogManager, type MultiLogManager } from "log-manager";
@@ -13,7 +13,10 @@ export const client = new Client({
1313
database: config.database.database,
1414
});
1515

16-
export const setupDatabase = async (logger: LogManager | MultiLogManager) => {
16+
export const setupDatabase = async (
17+
logger: LogManager | MultiLogManager,
18+
info = true,
19+
) => {
1720
try {
1821
await client.connect();
1922
} catch (e) {
@@ -28,7 +31,8 @@ export const setupDatabase = async (logger: LogManager | MultiLogManager) => {
2831
}
2932

3033
// Migrate the database
31-
await logger.log(LogLevel.INFO, "Database", "Migrating database...");
34+
info &&
35+
(await logger.log(LogLevel.INFO, "Database", "Migrating database..."));
3236

3337
try {
3438
await migrate(db, {
@@ -44,7 +48,7 @@ export const setupDatabase = async (logger: LogManager | MultiLogManager) => {
4448
process.exit(1);
4549
}
4650

47-
await logger.log(LogLevel.INFO, "Database", "Database migrated");
51+
info && (await logger.log(LogLevel.INFO, "Database", "Database migrated"));
4852
};
4953

5054
export const db = drizzle(client, { schema });

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"build": "bun run build.ts",
3636
"cloc": "cloc . --exclude-dir node_modules,dist,.output,.nuxt,meta,logs,glitch,glitch-dev --exclude-ext sql,log,pem",
3737
"wc": "find server database *.ts docs packages types utils drizzle tests -type f -print0 | wc -m --files0-from=-",
38-
"cli": "bun run cli.ts",
38+
"cli": "bun run packages/cli/bin/run.ts",
3939
"prune": "ts-prune | grep -v server/ | grep -v dist/ | grep -v '(used in module)'"
4040
},
4141
"trustedDependencies": [

packages/cli/base.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Command } from "@oclif/core";
2+
3+
export abstract class BaseCommand<T extends typeof Command> extends Command {
4+
protected async init(): Promise<void> {
5+
await super.init();
6+
7+
const { setupDatabase } = await import("~drizzle/db");
8+
const { consoleLogger } = await import("@loggers");
9+
10+
(async () => {
11+
await setupDatabase(consoleLogger, false);
12+
})();
13+
}
14+
}

packages/cli/bin/dev.cmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@echo off
2+
3+
bun "%~dp0\dev" %*

packages/cli/bin/dev.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env -S bun
2+
3+
import { execute } from "@oclif/core";
4+
5+
await execute({ development: true, dir: import.meta.url });

packages/cli/bin/run.cmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@echo off
2+
3+
bun "%~dp0\run" %*

packages/cli/bin/run.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bun
2+
3+
import { execute } from "@oclif/core";
4+
5+
await execute({ dir: import.meta.url });

packages/cli/classes.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { and, eq, like } from "drizzle-orm";
2+
import { Users } from "~drizzle/schema";
3+
import type { User } from "~packages/database-interface/user";
4+
import { BaseCommand } from "./base";
5+
import { Args, Flags, type Command, type Interfaces } from "@oclif/core";
6+
7+
export type FlagsType<T extends typeof Command> = Interfaces.InferredFlags<
8+
(typeof BaseCommand)["baseFlags"] & T["flags"]
9+
>;
10+
export type ArgsType<T extends typeof Command> = Interfaces.InferredArgs<
11+
T["args"]
12+
>;
13+
14+
export abstract class UserFinderCommand<
15+
T extends typeof BaseCommand,
16+
> extends BaseCommand<typeof UserFinderCommand> {
17+
static baseFlags = {
18+
pattern: Flags.boolean({
19+
char: "p",
20+
description:
21+
"Process as a wildcard pattern (don't forget to escape)",
22+
}),
23+
type: Flags.string({
24+
char: "t",
25+
description: "Type of identifier",
26+
options: ["id", "username", "note", "display-name", "email"],
27+
default: "id",
28+
}),
29+
limit: Flags.integer({
30+
char: "n",
31+
description: "Limit the number of users",
32+
default: 100,
33+
}),
34+
print: Flags.boolean({
35+
allowNo: true,
36+
default: true,
37+
char: "P",
38+
description: "Print user(s) found before processing",
39+
}),
40+
};
41+
42+
static baseArgs = {
43+
identifier: Args.string({
44+
description:
45+
"Identifier of the user (by default this must be an ID)",
46+
required: true,
47+
}),
48+
};
49+
50+
protected flags!: FlagsType<T>;
51+
protected args!: ArgsType<T>;
52+
53+
public async init(): Promise<void> {
54+
await super.init();
55+
const { args, flags } = await this.parse({
56+
flags: this.ctor.flags,
57+
baseFlags: (super.ctor as typeof BaseCommand).baseFlags,
58+
args: this.ctor.args,
59+
strict: this.ctor.strict,
60+
});
61+
this.flags = flags as FlagsType<T>;
62+
this.args = args as ArgsType<T>;
63+
}
64+
65+
public async findUsers(): Promise<User[]> {
66+
const operator = this.flags.pattern ? like : eq;
67+
// Replace wildcards with an SQL LIKE pattern
68+
const identifier = this.flags.pattern
69+
? this.args.identifier.replace(/\*/g, "%")
70+
: this.args.identifier;
71+
72+
const { User } = await import("~packages/database-interface/user");
73+
74+
return await User.manyFromSql(
75+
and(
76+
this.flags.type === "id"
77+
? operator(Users.id, identifier)
78+
: undefined,
79+
this.flags.type === "username"
80+
? operator(Users.username, identifier)
81+
: undefined,
82+
this.flags.type === "note"
83+
? operator(Users.note, identifier)
84+
: undefined,
85+
this.flags.type === "display-name"
86+
? operator(Users.displayName, identifier)
87+
: undefined,
88+
this.flags.type === "email"
89+
? operator(Users.email, identifier)
90+
: undefined,
91+
),
92+
undefined,
93+
this.flags.limit,
94+
);
95+
}
96+
}

0 commit comments

Comments
 (0)