vibeorm 1.1.11 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/package.json +10 -6
- package/src/commands/db-seed.ts +12 -3
- package/src/config.ts +46 -8
- package/src/index.ts +22 -3
- package/src/schema-loader.ts +41 -10
package/README.md
CHANGED
|
@@ -327,13 +327,18 @@ Config is resolved in this order (last wins):
|
|
|
327
327
|
|
|
328
328
|
### vibeorm.config.ts
|
|
329
329
|
|
|
330
|
+
The loader expects a **default export**. It will also accept `export const config = { ... }`
|
|
331
|
+
as a fallback for ergonomics, but `export default` is the canonical form.
|
|
332
|
+
|
|
330
333
|
```ts
|
|
331
|
-
|
|
334
|
+
import type { VibeOrmConfig } from "vibeorm/config";
|
|
335
|
+
|
|
336
|
+
export default {
|
|
332
337
|
schema: "./prisma/schema.prisma",
|
|
333
338
|
output: "./generated/vibeorm",
|
|
334
339
|
migrations: "./migrations",
|
|
335
340
|
seed: "./prisma/seed.ts",
|
|
336
|
-
};
|
|
341
|
+
} satisfies VibeOrmConfig;
|
|
337
342
|
```
|
|
338
343
|
|
|
339
344
|
### Typical migration workflow
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeorm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "CLI for VibeORM — generate clients, run migrations, introspect databases",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
".": {
|
|
21
21
|
"default": "./src/index.ts",
|
|
22
22
|
"types": "./src/index.ts"
|
|
23
|
+
},
|
|
24
|
+
"./config": {
|
|
25
|
+
"default": "./src/config.ts",
|
|
26
|
+
"types": "./src/config.ts"
|
|
23
27
|
}
|
|
24
28
|
},
|
|
25
29
|
"files": [
|
|
@@ -41,10 +45,10 @@
|
|
|
41
45
|
"bun": ">=1.1.0"
|
|
42
46
|
},
|
|
43
47
|
"dependencies": {
|
|
44
|
-
"@vibeorm/parser": "1.
|
|
45
|
-
"@vibeorm/generator": "1.
|
|
46
|
-
"@vibeorm/migrate": "1.
|
|
47
|
-
"@vibeorm/runtime": "1.
|
|
48
|
-
"@vibeorm/adapter-bun": "1.
|
|
48
|
+
"@vibeorm/parser": "1.3.0",
|
|
49
|
+
"@vibeorm/generator": "1.3.0",
|
|
50
|
+
"@vibeorm/migrate": "1.3.0",
|
|
51
|
+
"@vibeorm/runtime": "1.3.0",
|
|
52
|
+
"@vibeorm/adapter-bun": "1.3.0"
|
|
49
53
|
}
|
|
50
54
|
}
|
package/src/commands/db-seed.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* vibeorm db seed
|
|
3
3
|
*
|
|
4
|
-
* Run a user-defined seed script.
|
|
4
|
+
* Run a user-defined seed script. Any arguments passed after the `--`
|
|
5
|
+
* separator are forwarded verbatim to the seed script (npm/bun convention):
|
|
6
|
+
*
|
|
7
|
+
* bunx vibeorm db seed -- --scenario=medium --seed-count 10
|
|
8
|
+
*
|
|
9
|
+
* The seed script can then read these from `process.argv.slice(2)`.
|
|
5
10
|
*/
|
|
6
11
|
|
|
7
12
|
import { existsSync } from "fs";
|
|
@@ -10,8 +15,9 @@ import type { VibeOrmConfig } from "../config.ts";
|
|
|
10
15
|
export async function runDbSeed(params: {
|
|
11
16
|
config: VibeOrmConfig;
|
|
12
17
|
flags: Record<string, string>;
|
|
18
|
+
passthroughArgs?: string[];
|
|
13
19
|
}): Promise<void> {
|
|
14
|
-
const { config } = params;
|
|
20
|
+
const { config, passthroughArgs = [] } = params;
|
|
15
21
|
|
|
16
22
|
console.log("VibeORM DB Seed");
|
|
17
23
|
console.log("");
|
|
@@ -30,9 +36,12 @@ export async function runDbSeed(params: {
|
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
console.log(`Running seed: ${seedPath}`);
|
|
39
|
+
if (passthroughArgs.length > 0) {
|
|
40
|
+
console.log(` Forwarding args: ${passthroughArgs.join(" ")}`);
|
|
41
|
+
}
|
|
33
42
|
console.log("");
|
|
34
43
|
|
|
35
|
-
const proc = Bun.spawn(["bun", "run", seedPath], {
|
|
44
|
+
const proc = Bun.spawn(["bun", "run", seedPath, ...passthroughArgs], {
|
|
36
45
|
stdout: "inherit",
|
|
37
46
|
stderr: "inherit",
|
|
38
47
|
});
|
package/src/config.ts
CHANGED
|
@@ -55,20 +55,58 @@ function loadPackageJsonConfig(): Partial<VibeOrmConfig> {
|
|
|
55
55
|
return {};
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
const KNOWN_CONFIG_KEYS = new Set<keyof VibeOrmConfig>(["schema", "output", "migrations", "seed"]);
|
|
59
|
+
|
|
58
60
|
async function loadConfigFile(): Promise<Partial<VibeOrmConfig>> {
|
|
59
61
|
const configPath = resolve(process.cwd(), "vibeorm.config.ts");
|
|
60
62
|
if (!existsSync(configPath)) return {};
|
|
61
63
|
|
|
64
|
+
let mod: Record<string, unknown>;
|
|
62
65
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
} catch {
|
|
69
|
-
// Ignore import errors
|
|
66
|
+
mod = await import(configPath);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
console.warn(`[vibeorm] Failed to import vibeorm.config.ts: ${err instanceof Error ? err.message : String(err)}`);
|
|
69
|
+
return {};
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
|
|
72
|
+
// Accept either `export default { ... }` (recommended) or `export const config = { ... }`.
|
|
73
|
+
// We prefer `default` for consistency with most TS config conventions.
|
|
74
|
+
let raw: unknown = mod.default;
|
|
75
|
+
let source: "default" | "config" | "module" = "default";
|
|
76
|
+
if (raw === undefined && mod.config !== undefined) {
|
|
77
|
+
raw = mod.config;
|
|
78
|
+
source = "config";
|
|
79
|
+
}
|
|
80
|
+
if (raw === undefined) {
|
|
81
|
+
raw = mod;
|
|
82
|
+
source = "module";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!raw || typeof raw !== "object") {
|
|
86
|
+
console.warn(`[vibeorm] vibeorm.config.ts loaded but does not export a config object.`);
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const cfg = raw as Record<string, unknown>;
|
|
91
|
+
const hasKnown = Array.from(KNOWN_CONFIG_KEYS).some((k) => cfg[k] !== undefined);
|
|
92
|
+
if (!hasKnown) {
|
|
93
|
+
console.warn(
|
|
94
|
+
`[vibeorm] vibeorm.config.ts loaded but no recognised keys (schema/output/migrations/seed) were found. ` +
|
|
95
|
+
`Did you mean \`export default { ... }\`? Falling back to defaults.`,
|
|
96
|
+
);
|
|
97
|
+
return {};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (source === "module") {
|
|
101
|
+
// The user almost certainly forgot `export default`; their config is being read off the
|
|
102
|
+
// module namespace by accident. Surface a hint so they don't lose minutes to silent fallback.
|
|
103
|
+
console.warn(
|
|
104
|
+
`[vibeorm] vibeorm.config.ts is missing a default export. ` +
|
|
105
|
+
`Recommended: \`export default { ... } satisfies VibeOrmConfig\`.`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return cfg as Partial<VibeOrmConfig>;
|
|
72
110
|
}
|
|
73
111
|
|
|
74
112
|
export async function resolveConfig(params: { flags?: Record<string, string> }): Promise<VibeOrmConfig> {
|
package/src/index.ts
CHANGED
|
@@ -36,7 +36,19 @@ import { runMigrateRollback } from "./commands/migrate-rollback.ts";
|
|
|
36
36
|
|
|
37
37
|
// ─── Command Router ───────────────────────────────────────────────
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Standard handler signature. `passthroughArgs` contains everything after the
|
|
41
|
+
* first standalone `--` token in the original argv — the canonical
|
|
42
|
+
* npm/bun/pnpm convention for forwarding flags to a wrapped script. Most
|
|
43
|
+
* commands ignore it; `db seed` forwards it to the user's seed script.
|
|
44
|
+
*/
|
|
45
|
+
type CommandHandler = (params: {
|
|
46
|
+
config: VibeOrmConfig;
|
|
47
|
+
flags: Record<string, string>;
|
|
48
|
+
passthroughArgs: string[];
|
|
49
|
+
}) => Promise<void>;
|
|
50
|
+
|
|
51
|
+
const COMMANDS: Record<string, CommandHandler> = {
|
|
40
52
|
"init": runInit,
|
|
41
53
|
"generate": runGenerate,
|
|
42
54
|
"db push": runDbPush,
|
|
@@ -80,7 +92,14 @@ function printHelp(): void {
|
|
|
80
92
|
}
|
|
81
93
|
|
|
82
94
|
async function main(): Promise<void> {
|
|
83
|
-
const
|
|
95
|
+
const rawArgs = process.argv.slice(2);
|
|
96
|
+
|
|
97
|
+
// Split at the first standalone `--` token (npm/bun/pnpm convention).
|
|
98
|
+
// Everything before is for vibeorm; everything after is forwarded to the
|
|
99
|
+
// wrapped script (currently only consumed by `db seed`).
|
|
100
|
+
const separatorIdx = rawArgs.indexOf("--");
|
|
101
|
+
const args = separatorIdx === -1 ? rawArgs : rawArgs.slice(0, separatorIdx);
|
|
102
|
+
const passthroughArgs = separatorIdx === -1 ? [] : rawArgs.slice(separatorIdx + 1);
|
|
84
103
|
|
|
85
104
|
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
86
105
|
printHelp();
|
|
@@ -109,7 +128,7 @@ async function main(): Promise<void> {
|
|
|
109
128
|
const config = await resolveConfig({ flags });
|
|
110
129
|
|
|
111
130
|
const handler = COMMANDS[command]!;
|
|
112
|
-
await handler({ config, flags });
|
|
131
|
+
await handler({ config, flags, passthroughArgs });
|
|
113
132
|
}
|
|
114
133
|
|
|
115
134
|
main().catch((err) => {
|
package/src/schema-loader.ts
CHANGED
|
@@ -1,14 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Schema Loader — supports both single .prisma files and directories
|
|
3
|
-
* containing multiple .prisma files
|
|
3
|
+
* containing multiple .prisma files (including nested subdirectories,
|
|
4
|
+
* matching Prisma 7's multi-file mode).
|
|
4
5
|
*
|
|
5
6
|
* If the path is a file, reads it directly.
|
|
6
|
-
* If the path is a directory, reads
|
|
7
|
-
* (sorted
|
|
7
|
+
* If the path is a directory, walks recursively and reads every `.prisma` file
|
|
8
|
+
* (sorted by relative path so concatenation order is deterministic across OSes).
|
|
9
|
+
* Dotfile-prefixed files (e.g. `.cache.prisma`) are skipped so generated
|
|
10
|
+
* artefacts don't accidentally get included.
|
|
8
11
|
*/
|
|
9
12
|
|
|
10
13
|
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
11
|
-
import { join } from "path";
|
|
14
|
+
import { join, sep } from "path";
|
|
15
|
+
|
|
16
|
+
function collectPrismaFiles(params: { root: string }): string[] {
|
|
17
|
+
const { root } = params;
|
|
18
|
+
// Node 18.17+/Bun supports { recursive: true } — returns string[] of paths
|
|
19
|
+
// relative to `root`, with platform-native separators.
|
|
20
|
+
const entries = readdirSync(root, { recursive: true }) as string[];
|
|
21
|
+
|
|
22
|
+
const files: string[] = [];
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
if (!entry.endsWith(".prisma")) continue;
|
|
25
|
+
// Skip dotfile-prefixed segments at any depth (e.g. `.cache/foo.prisma`,
|
|
26
|
+
// `models/.tmp.prisma`). This protects against accidentally bundling
|
|
27
|
+
// editor scratch files or third-party-tool artefacts.
|
|
28
|
+
const segments = entry.split(sep);
|
|
29
|
+
if (segments.some((s) => s.startsWith("."))) continue;
|
|
30
|
+
|
|
31
|
+
const absolute = join(root, entry);
|
|
32
|
+
// Skip directories that happen to end in `.prisma` (rare but possible).
|
|
33
|
+
if (!statSync(absolute).isFile()) continue;
|
|
34
|
+
|
|
35
|
+
files.push(entry);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Sort by normalised forward-slash path so output is deterministic regardless
|
|
39
|
+
// of the platform's readdir ordering or path separator.
|
|
40
|
+
files.sort((a, b) => a.split(sep).join("/").localeCompare(b.split(sep).join("/")));
|
|
41
|
+
return files;
|
|
42
|
+
}
|
|
12
43
|
|
|
13
44
|
export function loadSchemaSource(params: { schemaPath: string }): string {
|
|
14
45
|
const { schemaPath } = params;
|
|
@@ -26,22 +57,22 @@ export function loadSchemaSource(params: { schemaPath: string }): string {
|
|
|
26
57
|
}
|
|
27
58
|
|
|
28
59
|
if (stat.isDirectory()) {
|
|
29
|
-
const files =
|
|
30
|
-
.filter((f: string) => f.endsWith(".prisma"))
|
|
31
|
-
.sort();
|
|
60
|
+
const files = collectPrismaFiles({ root: schemaPath });
|
|
32
61
|
|
|
33
62
|
if (files.length === 0) {
|
|
34
|
-
console.error(`Error: No .prisma files found
|
|
63
|
+
console.error(`Error: No .prisma files found under ${schemaPath} (searched recursively)`);
|
|
35
64
|
process.exit(1);
|
|
36
65
|
}
|
|
37
66
|
|
|
38
67
|
const sources: string[] = [];
|
|
39
68
|
for (const file of files) {
|
|
40
69
|
const filePath = join(schemaPath, file);
|
|
41
|
-
|
|
70
|
+
// Use the forward-slash form in the header so diffs are stable across OSes.
|
|
71
|
+
const displayPath = file.split(sep).join("/");
|
|
72
|
+
sources.push(`// --- ${displayPath} ---\n` + readFileSync(filePath, "utf-8"));
|
|
42
73
|
}
|
|
43
74
|
|
|
44
|
-
console.log(` Loaded ${files.length} schema files from ${schemaPath}`);
|
|
75
|
+
console.log(` Loaded ${files.length} schema file${files.length === 1 ? "" : "s"} from ${schemaPath}`);
|
|
45
76
|
return sources.join("\n\n");
|
|
46
77
|
}
|
|
47
78
|
|