@invect/cli 0.1.1 → 0.1.2
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/dist/{chunk-5XRZFNIV.js → chunk-ILVFFEI6.js} +258 -106
- package/dist/{generate-SCRZDVJT.js → generate-NXZRLIMQ.js} +1 -2
- package/dist/index.js +212 -85
- package/package.json +2 -2
- package/dist/chunk-LKWAVX5Z.js +0 -109
- package/dist/chunk-Q6JKV7VX.js +0 -157
- package/dist/migrate-A2N3YKVS.js +0 -9
|
@@ -3,18 +3,169 @@ import {
|
|
|
3
3
|
generateAppendSchema,
|
|
4
4
|
generatePrismaSchema
|
|
5
5
|
} from "./chunk-K4RRNATQ.js";
|
|
6
|
-
import {
|
|
7
|
-
findConfigPath,
|
|
8
|
-
loadConfig
|
|
9
|
-
} from "./chunk-Q6JKV7VX.js";
|
|
10
6
|
|
|
11
7
|
// src/commands/generate.ts
|
|
12
8
|
import { Command } from "commander";
|
|
9
|
+
import path2 from "path";
|
|
10
|
+
import fs2 from "fs";
|
|
11
|
+
import pc2 from "picocolors";
|
|
12
|
+
import prompts from "prompts";
|
|
13
|
+
import { execSync } from "child_process";
|
|
14
|
+
|
|
15
|
+
// src/utils/config-loader.ts
|
|
13
16
|
import path from "path";
|
|
14
17
|
import fs from "fs";
|
|
15
18
|
import pc from "picocolors";
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
var CONFIG_FILENAMES = [
|
|
20
|
+
"invect.config.ts",
|
|
21
|
+
"invect.config.js",
|
|
22
|
+
"invect.config.mjs"
|
|
23
|
+
];
|
|
24
|
+
var CONFIG_DIRECTORIES = [".", "src", "lib", "config", "utils"];
|
|
25
|
+
function findConfigPath(explicitPath) {
|
|
26
|
+
if (explicitPath) {
|
|
27
|
+
const resolved = path.resolve(process.cwd(), explicitPath);
|
|
28
|
+
if (fs.existsSync(resolved)) {
|
|
29
|
+
return resolved;
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
for (const dir of CONFIG_DIRECTORIES) {
|
|
34
|
+
for (const filename of CONFIG_FILENAMES) {
|
|
35
|
+
const candidate = path.resolve(process.cwd(), dir, filename);
|
|
36
|
+
if (fs.existsSync(candidate)) {
|
|
37
|
+
return candidate;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
function stripJsonComments(jsonString) {
|
|
44
|
+
return jsonString.replace(
|
|
45
|
+
/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g,
|
|
46
|
+
(m, g) => g ? "" : m
|
|
47
|
+
).replace(/,(?=\s*[}\]])/g, "");
|
|
48
|
+
}
|
|
49
|
+
function getPathAliases(cwd) {
|
|
50
|
+
let tsConfigPath = path.join(cwd, "tsconfig.json");
|
|
51
|
+
if (!fs.existsSync(tsConfigPath)) {
|
|
52
|
+
tsConfigPath = path.join(cwd, "jsconfig.json");
|
|
53
|
+
}
|
|
54
|
+
if (!fs.existsSync(tsConfigPath)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const result = getPathAliasesRecursive(tsConfigPath, /* @__PURE__ */ new Set());
|
|
59
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function getPathAliasesRecursive(configPath, visited) {
|
|
65
|
+
const resolvedPath = path.resolve(configPath);
|
|
66
|
+
if (visited.has(resolvedPath)) return {};
|
|
67
|
+
visited.add(resolvedPath);
|
|
68
|
+
if (!fs.existsSync(resolvedPath)) return {};
|
|
69
|
+
let tsConfig;
|
|
70
|
+
try {
|
|
71
|
+
const text = fs.readFileSync(resolvedPath, "utf-8");
|
|
72
|
+
tsConfig = JSON.parse(stripJsonComments(text));
|
|
73
|
+
} catch {
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
const result = {};
|
|
77
|
+
const compilerOptions = tsConfig.compilerOptions;
|
|
78
|
+
const paths = compilerOptions?.paths;
|
|
79
|
+
const baseUrl = compilerOptions?.baseUrl;
|
|
80
|
+
const configDir = path.dirname(resolvedPath);
|
|
81
|
+
if (paths) {
|
|
82
|
+
for (const [alias, targets] of Object.entries(paths)) {
|
|
83
|
+
if (typeof alias === "string" && alias.endsWith("/*") && Array.isArray(targets) && targets.length > 0) {
|
|
84
|
+
const aliasPrefix = alias.slice(0, -2);
|
|
85
|
+
const targetDir = targets[0].replace(/\/\*$/, "");
|
|
86
|
+
const resolvedTarget = baseUrl ? path.resolve(configDir, baseUrl, targetDir) : path.resolve(configDir, targetDir);
|
|
87
|
+
result[aliasPrefix] = resolvedTarget;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const references = tsConfig.references;
|
|
92
|
+
if (references) {
|
|
93
|
+
for (const ref of references) {
|
|
94
|
+
const refPath = path.resolve(configDir, ref.path);
|
|
95
|
+
const refConfigPath = refPath.endsWith(".json") ? refPath : path.join(refPath, "tsconfig.json");
|
|
96
|
+
const refAliases = getPathAliasesRecursive(refConfigPath, visited);
|
|
97
|
+
Object.assign(result, refAliases);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
async function loadConfig(configPath) {
|
|
103
|
+
const aliases = getPathAliases(process.cwd()) || {};
|
|
104
|
+
const { createJiti } = await import("jiti");
|
|
105
|
+
const jiti = createJiti(import.meta.url, {
|
|
106
|
+
interopDefault: true,
|
|
107
|
+
// Pass resolved path aliases so @/ imports work
|
|
108
|
+
alias: aliases
|
|
109
|
+
});
|
|
110
|
+
let configModule;
|
|
111
|
+
try {
|
|
112
|
+
configModule = await jiti.import(configPath);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
115
|
+
if (message.includes("Cannot find module") || message.includes("Cannot resolve")) {
|
|
116
|
+
console.error(pc.red("\n\u2717 Failed to load config file."));
|
|
117
|
+
console.error(pc.dim(" If your config uses import aliases (e.g., @/ or ~/),"));
|
|
118
|
+
console.error(pc.dim(" try using relative paths instead, then run the CLI again."));
|
|
119
|
+
console.error(pc.dim(`
|
|
120
|
+
Error: ${message}
|
|
121
|
+
`));
|
|
122
|
+
}
|
|
123
|
+
throw new Error(`Failed to load config from ${configPath}: ${message}`);
|
|
124
|
+
}
|
|
125
|
+
const raw = resolveConfigExport(configModule);
|
|
126
|
+
if (!raw || typeof raw !== "object") {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Config file at ${configPath} does not export a valid Invect config object.
|
|
129
|
+
Expected: export default { baseDatabaseConfig: ..., plugins: [...] }`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
const config = raw;
|
|
133
|
+
const plugins = Array.isArray(config.plugins) ? config.plugins : [];
|
|
134
|
+
for (let i = 0; i < plugins.length; i++) {
|
|
135
|
+
const plugin = plugins[i];
|
|
136
|
+
if (!plugin || typeof plugin !== "object" || !("id" in plugin)) {
|
|
137
|
+
console.warn(
|
|
138
|
+
pc.yellow(`\u26A0 Plugin at index ${i} does not have an 'id' property \u2014 skipping`)
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const validPlugins = plugins.filter(
|
|
143
|
+
(p) => p !== null && typeof p === "object" && "id" in p
|
|
144
|
+
);
|
|
145
|
+
return {
|
|
146
|
+
plugins: validPlugins,
|
|
147
|
+
baseDatabaseConfig: config.baseDatabaseConfig,
|
|
148
|
+
raw: config,
|
|
149
|
+
configPath
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function resolveConfigExport(module) {
|
|
153
|
+
if (!module || typeof module !== "object") return module;
|
|
154
|
+
const mod = module;
|
|
155
|
+
if ("default" in mod) {
|
|
156
|
+
const def = mod.default;
|
|
157
|
+
if (def && typeof def === "object" && "default" in def) {
|
|
158
|
+
return def.default;
|
|
159
|
+
}
|
|
160
|
+
return def;
|
|
161
|
+
}
|
|
162
|
+
if ("config" in mod) return mod.config;
|
|
163
|
+
if ("invectConfig" in mod) return mod.invectConfig;
|
|
164
|
+
if ("baseDatabaseConfig" in mod || "plugins" in mod) return mod;
|
|
165
|
+
return mod;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/commands/generate.ts
|
|
18
169
|
var generateCommand = new Command("generate").description("Generate Drizzle or Prisma schema files from core + plugin schemas").option(
|
|
19
170
|
"--config <path>",
|
|
20
171
|
"Path to your Invect config file. Defaults to the first config found."
|
|
@@ -33,37 +184,37 @@ var generateCommand = new Command("generate").description("Generate Drizzle or P
|
|
|
33
184
|
"Database dialect (sqlite, postgresql, mysql). Required when using --schema. Auto-detected from drizzle.config.ts when possible."
|
|
34
185
|
).option("-y, --yes", "Skip confirmation prompt and generate directly", false).action(generateAction);
|
|
35
186
|
async function generateAction(options) {
|
|
36
|
-
console.log(
|
|
187
|
+
console.log(pc2.bold("\n\u{1F527} Invect Schema Generator\n"));
|
|
37
188
|
const adapter = (options.adapter || "drizzle").toLowerCase();
|
|
38
189
|
if (adapter !== "drizzle" && adapter !== "prisma") {
|
|
39
190
|
console.error(
|
|
40
|
-
|
|
191
|
+
pc2.red(`\u2717 Unknown adapter "${options.adapter}".`) + "\n" + pc2.dim(" Supported adapters: drizzle (default), prisma\n")
|
|
41
192
|
);
|
|
42
193
|
process.exit(1);
|
|
43
194
|
}
|
|
44
195
|
const configPath = findConfigPath(options.config);
|
|
45
196
|
if (!configPath) {
|
|
46
197
|
console.error(
|
|
47
|
-
|
|
198
|
+
pc2.red("\u2717 Could not find Invect config file.") + "\n\n" + pc2.dim(" Searched for: invect.config.ts in ./, src/, lib/, config/") + "\n" + pc2.dim(" Use --config <path> to specify the config file explicitly.") + "\n\n" + pc2.dim(" You can create one with: " + pc2.cyan("npx invect-cli init")) + "\n"
|
|
48
199
|
);
|
|
49
200
|
process.exit(1);
|
|
50
201
|
}
|
|
51
|
-
console.log(
|
|
202
|
+
console.log(pc2.dim(` Config: ${path2.relative(process.cwd(), configPath)}`));
|
|
52
203
|
let config;
|
|
53
204
|
try {
|
|
54
205
|
config = await loadConfig(configPath);
|
|
55
206
|
} catch (error) {
|
|
56
207
|
console.error(
|
|
57
|
-
|
|
58
|
-
\u2717 Failed to load config.`) + "\n" +
|
|
208
|
+
pc2.red(`
|
|
209
|
+
\u2717 Failed to load config.`) + "\n" + pc2.dim(` ${error instanceof Error ? error.message : String(error)}`) + "\n\n" + pc2.dim(" If your config uses import aliases (e.g., @/ or ~/),") + "\n" + pc2.dim(" try using relative paths instead, then run the CLI again.\n")
|
|
59
210
|
);
|
|
60
211
|
process.exit(1);
|
|
61
212
|
}
|
|
62
213
|
if (adapter === "prisma") {
|
|
63
214
|
await runPrismaMode(config, options);
|
|
64
|
-
|
|
215
|
+
return;
|
|
65
216
|
}
|
|
66
|
-
let schemaFile = options.schema ?
|
|
217
|
+
let schemaFile = options.schema ? path2.resolve(process.cwd(), options.schema) : void 0;
|
|
67
218
|
let dialect = normalizeDialect(options.dialect);
|
|
68
219
|
if (!schemaFile) {
|
|
69
220
|
const detected = detectDrizzleSchema();
|
|
@@ -71,16 +222,16 @@ async function generateAction(options) {
|
|
|
71
222
|
schemaFile = detected.schemaPath;
|
|
72
223
|
dialect = dialect || detected.dialect;
|
|
73
224
|
console.log(
|
|
74
|
-
|
|
225
|
+
pc2.dim(` Schema: ${path2.relative(process.cwd(), schemaFile)}`) + pc2.dim(` (auto-detected from ${detected.configFile})`)
|
|
75
226
|
);
|
|
76
227
|
}
|
|
77
228
|
} else {
|
|
78
|
-
console.log(
|
|
229
|
+
console.log(pc2.dim(` Schema: ${path2.relative(process.cwd(), schemaFile)}`));
|
|
79
230
|
}
|
|
80
231
|
const useAppendMode = !!schemaFile;
|
|
81
232
|
if (useAppendMode && !dialect) {
|
|
82
233
|
console.error(
|
|
83
|
-
|
|
234
|
+
pc2.red("\u2717 Cannot determine database dialect.") + "\n\n" + pc2.dim(" When using --schema, provide --dialect (sqlite, postgresql, or mysql).") + "\n" + pc2.dim(" Or ensure your drizzle.config.ts specifies a dialect.\n")
|
|
84
235
|
);
|
|
85
236
|
process.exit(1);
|
|
86
237
|
}
|
|
@@ -89,14 +240,13 @@ async function generateAction(options) {
|
|
|
89
240
|
} else {
|
|
90
241
|
await runSeparateFilesMode(config, options);
|
|
91
242
|
}
|
|
92
|
-
process.exit(0);
|
|
93
243
|
}
|
|
94
244
|
async function runPrismaMode(config, options) {
|
|
95
245
|
const provider = normalizePrismaProvider(options.dialect) || "postgresql";
|
|
96
|
-
const schemaFile = options.schema ?
|
|
97
|
-
console.log(
|
|
98
|
-
console.log(
|
|
99
|
-
console.log(
|
|
246
|
+
const schemaFile = options.schema ? path2.resolve(process.cwd(), options.schema) : path2.resolve(process.cwd(), "prisma/schema.prisma");
|
|
247
|
+
console.log(pc2.dim(` Adapter: ${pc2.cyan("Prisma")}`));
|
|
248
|
+
console.log(pc2.dim(` Provider: ${pc2.white(provider)}`));
|
|
249
|
+
console.log(pc2.dim(` Schema: ${path2.relative(process.cwd(), schemaFile)}`));
|
|
100
250
|
let result;
|
|
101
251
|
try {
|
|
102
252
|
result = await generatePrismaSchema({
|
|
@@ -105,51 +255,51 @@ async function runPrismaMode(config, options) {
|
|
|
105
255
|
provider
|
|
106
256
|
});
|
|
107
257
|
} catch (error) {
|
|
108
|
-
console.error(
|
|
258
|
+
console.error(pc2.red(`
|
|
109
259
|
\u2717 Prisma schema generation failed:`));
|
|
110
|
-
console.error(
|
|
260
|
+
console.error(pc2.dim(` ${error instanceof Error ? error.message : String(error)}
|
|
111
261
|
`));
|
|
112
262
|
process.exit(1);
|
|
113
263
|
}
|
|
114
264
|
if (result.code === void 0) {
|
|
115
|
-
console.log(
|
|
116
|
-
|
|
265
|
+
console.log(pc2.bold(pc2.green("\n\u2713 Prisma schema is already up to date.\n")));
|
|
266
|
+
return;
|
|
117
267
|
}
|
|
118
|
-
const rel =
|
|
268
|
+
const rel = path2.relative(process.cwd(), result.fileName);
|
|
119
269
|
console.log("");
|
|
120
|
-
console.log(
|
|
270
|
+
console.log(pc2.bold(" Files:"));
|
|
121
271
|
if (result.overwrite) {
|
|
122
|
-
console.log(
|
|
272
|
+
console.log(pc2.yellow(` ~ ${rel}`) + pc2.dim(" (will update)"));
|
|
123
273
|
} else {
|
|
124
|
-
console.log(
|
|
274
|
+
console.log(pc2.green(` + ${rel}`) + pc2.dim(" (will create)"));
|
|
125
275
|
}
|
|
126
276
|
if (!options.yes) {
|
|
127
277
|
console.log("");
|
|
128
278
|
const response = await prompts({
|
|
129
279
|
type: "confirm",
|
|
130
280
|
name: "proceed",
|
|
131
|
-
message: result.overwrite ? `Update ${
|
|
281
|
+
message: result.overwrite ? `Update ${pc2.cyan(rel)}?` : `Create ${pc2.cyan(rel)}?`,
|
|
132
282
|
initial: true
|
|
133
283
|
});
|
|
134
284
|
if (!response.proceed) {
|
|
135
|
-
console.log(
|
|
136
|
-
|
|
285
|
+
console.log(pc2.dim("\n Cancelled.\n"));
|
|
286
|
+
return;
|
|
137
287
|
}
|
|
138
288
|
}
|
|
139
|
-
const dir =
|
|
140
|
-
|
|
141
|
-
|
|
289
|
+
const dir = path2.dirname(result.fileName);
|
|
290
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
291
|
+
fs2.writeFileSync(result.fileName, result.code, "utf-8");
|
|
142
292
|
console.log(
|
|
143
|
-
|
|
293
|
+
pc2.bold(pc2.green(`
|
|
144
294
|
\u2713 Prisma schema ${result.overwrite ? "updated" : "created"}: ${rel}
|
|
145
295
|
`))
|
|
146
296
|
);
|
|
147
|
-
console.log(
|
|
297
|
+
console.log(pc2.dim(" Next steps:"));
|
|
148
298
|
console.log(
|
|
149
|
-
|
|
299
|
+
pc2.dim(" 1. Run ") + pc2.cyan("npx prisma db push") + pc2.dim(" to apply schema changes")
|
|
150
300
|
);
|
|
151
301
|
console.log(
|
|
152
|
-
|
|
302
|
+
pc2.dim(" 2. Run ") + pc2.cyan("npx prisma generate") + pc2.dim(" to regenerate the Prisma client")
|
|
153
303
|
);
|
|
154
304
|
console.log("");
|
|
155
305
|
}
|
|
@@ -169,16 +319,16 @@ async function runAppendMode(config, schemaFile, dialect, options) {
|
|
|
169
319
|
dialect
|
|
170
320
|
});
|
|
171
321
|
} catch (error) {
|
|
172
|
-
console.error(
|
|
322
|
+
console.error(pc2.red(`
|
|
173
323
|
\u2717 Schema generation failed:`));
|
|
174
|
-
console.error(
|
|
324
|
+
console.error(pc2.dim(` ${error instanceof Error ? error.message : String(error)}
|
|
175
325
|
`));
|
|
176
326
|
process.exit(1);
|
|
177
327
|
}
|
|
178
328
|
const { result, stats } = appendResult;
|
|
179
329
|
await printSummary(config, stats);
|
|
180
|
-
const fileExists =
|
|
181
|
-
const currentFileContent = fileExists ?
|
|
330
|
+
const fileExists = fs2.existsSync(schemaFile);
|
|
331
|
+
const currentFileContent = fileExists ? fs2.readFileSync(schemaFile, "utf-8") : "";
|
|
182
332
|
let existingContent = currentFileContent;
|
|
183
333
|
const marker = "// Invect tables \u2014 AUTO-GENERATED by @invect/cli";
|
|
184
334
|
const markerIndex = existingContent.indexOf(marker);
|
|
@@ -233,40 +383,40 @@ async function runAppendMode(config, schemaFile, dialect, options) {
|
|
|
233
383
|
finalContent = finalContent.trimEnd() + "\n" + result.code + "\n";
|
|
234
384
|
if (currentFileContent === finalContent) {
|
|
235
385
|
printSummaryAlreadyUpToDate();
|
|
236
|
-
|
|
386
|
+
return;
|
|
237
387
|
}
|
|
238
|
-
const rel =
|
|
388
|
+
const rel = path2.relative(process.cwd(), schemaFile);
|
|
239
389
|
console.log("");
|
|
240
|
-
console.log(
|
|
390
|
+
console.log(pc2.bold(" Files:"));
|
|
241
391
|
if (fileExists) {
|
|
242
392
|
if (markerIndex !== -1) {
|
|
243
|
-
console.log(
|
|
393
|
+
console.log(pc2.yellow(` ~ ${rel}`) + pc2.dim(" (Invect tables will be regenerated)"));
|
|
244
394
|
} else {
|
|
245
|
-
console.log(
|
|
395
|
+
console.log(pc2.green(` ~ ${rel}`) + pc2.dim(" (Invect tables will be appended)"));
|
|
246
396
|
}
|
|
247
397
|
} else {
|
|
248
|
-
console.log(
|
|
398
|
+
console.log(pc2.green(` + ${rel}`) + pc2.dim(" (will create)"));
|
|
249
399
|
}
|
|
250
400
|
if (!options.yes) {
|
|
251
401
|
console.log("");
|
|
252
402
|
const response = await prompts({
|
|
253
403
|
type: "confirm",
|
|
254
404
|
name: "proceed",
|
|
255
|
-
message: fileExists ? `Append Invect tables to ${
|
|
405
|
+
message: fileExists ? `Append Invect tables to ${pc2.cyan(rel)}?` : `Create ${pc2.cyan(rel)} with Invect tables?`,
|
|
256
406
|
initial: true
|
|
257
407
|
});
|
|
258
408
|
if (!response.proceed) {
|
|
259
|
-
console.log(
|
|
260
|
-
|
|
409
|
+
console.log(pc2.dim("\n Cancelled.\n"));
|
|
410
|
+
return;
|
|
261
411
|
}
|
|
262
412
|
}
|
|
263
|
-
const dir =
|
|
264
|
-
|
|
265
|
-
|
|
413
|
+
const dir = path2.dirname(schemaFile);
|
|
414
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
415
|
+
fs2.writeFileSync(schemaFile, finalContent, "utf-8");
|
|
266
416
|
const schemaFileChanged = currentFileContent !== finalContent;
|
|
267
417
|
console.log(
|
|
268
|
-
|
|
269
|
-
|
|
418
|
+
pc2.bold(
|
|
419
|
+
pc2.green(
|
|
270
420
|
`
|
|
271
421
|
\u2713 Invect tables ${markerIndex !== -1 ? "updated" : "appended"} in ${rel}
|
|
272
422
|
`
|
|
@@ -275,20 +425,20 @@ async function runAppendMode(config, schemaFile, dialect, options) {
|
|
|
275
425
|
);
|
|
276
426
|
if (!schemaFileChanged) {
|
|
277
427
|
console.log(
|
|
278
|
-
|
|
428
|
+
pc2.dim(" Schema file unchanged after regeneration \u2014 skipping drizzle-kit push.\n") + pc2.dim(" The database is already up to date.\n")
|
|
279
429
|
);
|
|
280
430
|
} else if (!options.yes) {
|
|
281
431
|
const { runPush } = await prompts({
|
|
282
432
|
type: "confirm",
|
|
283
433
|
name: "runPush",
|
|
284
|
-
message: `Run ${
|
|
434
|
+
message: `Run ${pc2.cyan("drizzle-kit push")} to apply schema changes?`,
|
|
285
435
|
initial: true
|
|
286
436
|
});
|
|
287
437
|
if (runPush) {
|
|
288
438
|
await runDrizzleKitPush();
|
|
289
439
|
} else {
|
|
290
440
|
console.log(
|
|
291
|
-
|
|
441
|
+
pc2.dim("\n Next: run ") + pc2.cyan("npx drizzle-kit push") + pc2.dim(" to apply schema changes.\n")
|
|
292
442
|
);
|
|
293
443
|
}
|
|
294
444
|
} else {
|
|
@@ -296,7 +446,7 @@ async function runAppendMode(config, schemaFile, dialect, options) {
|
|
|
296
446
|
}
|
|
297
447
|
}
|
|
298
448
|
async function runSeparateFilesMode(config, options) {
|
|
299
|
-
const outputDir =
|
|
449
|
+
const outputDir = path2.resolve(process.cwd(), options.output);
|
|
300
450
|
let generated;
|
|
301
451
|
try {
|
|
302
452
|
generated = await generateAllDrizzleSchemas({
|
|
@@ -304,9 +454,9 @@ async function runSeparateFilesMode(config, options) {
|
|
|
304
454
|
outputDir
|
|
305
455
|
});
|
|
306
456
|
} catch (error) {
|
|
307
|
-
console.error(
|
|
457
|
+
console.error(pc2.red(`
|
|
308
458
|
\u2717 Schema generation failed:`));
|
|
309
|
-
console.error(
|
|
459
|
+
console.error(pc2.dim(` ${error instanceof Error ? error.message : String(error)}
|
|
310
460
|
`));
|
|
311
461
|
process.exit(1);
|
|
312
462
|
}
|
|
@@ -322,19 +472,19 @@ async function runSeparateFilesMode(config, options) {
|
|
|
322
472
|
}) : results;
|
|
323
473
|
const hasChanges = filteredResults.some((r) => r.code !== void 0);
|
|
324
474
|
if (!hasChanges) {
|
|
325
|
-
console.log(
|
|
326
|
-
|
|
475
|
+
console.log(pc2.bold(pc2.green("\n\u2713 Schema files are already up to date.\n")));
|
|
476
|
+
return;
|
|
327
477
|
}
|
|
328
478
|
console.log("");
|
|
329
|
-
console.log(
|
|
479
|
+
console.log(pc2.bold(" Files:"));
|
|
330
480
|
for (const result of filteredResults) {
|
|
331
|
-
const rel =
|
|
481
|
+
const rel = path2.relative(process.cwd(), result.fileName);
|
|
332
482
|
if (result.code === void 0) {
|
|
333
|
-
console.log(
|
|
483
|
+
console.log(pc2.dim(` \xB7 ${rel} (unchanged)`));
|
|
334
484
|
} else if (result.overwrite) {
|
|
335
|
-
console.log(
|
|
485
|
+
console.log(pc2.yellow(` ~ ${rel}`) + pc2.dim(" (will update)"));
|
|
336
486
|
} else {
|
|
337
|
-
console.log(
|
|
487
|
+
console.log(pc2.green(` + ${rel}`) + pc2.dim(" (will create)"));
|
|
338
488
|
}
|
|
339
489
|
}
|
|
340
490
|
if (!options.yes) {
|
|
@@ -346,21 +496,21 @@ async function runSeparateFilesMode(config, options) {
|
|
|
346
496
|
initial: true
|
|
347
497
|
});
|
|
348
498
|
if (!response.proceed) {
|
|
349
|
-
console.log(
|
|
350
|
-
|
|
499
|
+
console.log(pc2.dim("\n Cancelled.\n"));
|
|
500
|
+
return;
|
|
351
501
|
}
|
|
352
502
|
}
|
|
353
503
|
let writtenCount = 0;
|
|
354
504
|
for (const result of filteredResults) {
|
|
355
505
|
if (result.code === void 0) continue;
|
|
356
|
-
const dir =
|
|
357
|
-
|
|
358
|
-
|
|
506
|
+
const dir = path2.dirname(result.fileName);
|
|
507
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
508
|
+
fs2.writeFileSync(result.fileName, result.code, "utf-8");
|
|
359
509
|
writtenCount++;
|
|
360
510
|
}
|
|
361
511
|
console.log(
|
|
362
|
-
|
|
363
|
-
|
|
512
|
+
pc2.bold(
|
|
513
|
+
pc2.green(`
|
|
364
514
|
\u2713 Generated ${writtenCount} schema file${writtenCount !== 1 ? "s" : ""}.
|
|
365
515
|
`)
|
|
366
516
|
)
|
|
@@ -369,7 +519,7 @@ async function runSeparateFilesMode(config, options) {
|
|
|
369
519
|
const { runDrizzleKit } = await prompts({
|
|
370
520
|
type: "confirm",
|
|
371
521
|
name: "runDrizzleKit",
|
|
372
|
-
message: `Run ${
|
|
522
|
+
message: `Run ${pc2.cyan("drizzle-kit generate")} to create SQL migrations?`,
|
|
373
523
|
initial: true
|
|
374
524
|
});
|
|
375
525
|
if (runDrizzleKit) {
|
|
@@ -382,7 +532,7 @@ async function runSeparateFilesMode(config, options) {
|
|
|
382
532
|
}
|
|
383
533
|
}
|
|
384
534
|
function printSummaryAlreadyUpToDate() {
|
|
385
|
-
console.log(
|
|
535
|
+
console.log(pc2.bold(pc2.green("\n\u2713 Schema is already up to date. Nothing to do.\n")));
|
|
386
536
|
}
|
|
387
537
|
async function printSummary(config, stats) {
|
|
388
538
|
const pluginsWithSchema = config.plugins.filter((p) => p.schema);
|
|
@@ -390,13 +540,13 @@ async function printSummary(config, stats) {
|
|
|
390
540
|
(p) => !p.schema && Array.isArray(p.requiredTables) && p.requiredTables.length > 0
|
|
391
541
|
);
|
|
392
542
|
console.log(
|
|
393
|
-
|
|
394
|
-
` Plugins: ${
|
|
543
|
+
pc2.dim(
|
|
544
|
+
` Plugins: ${pc2.white(String(config.plugins.length))} loaded` + (pluginsWithSchema.length > 0 ? `, ${pc2.cyan(String(pluginsWithSchema.length))} with schema` : "")
|
|
395
545
|
)
|
|
396
546
|
);
|
|
397
547
|
console.log(
|
|
398
|
-
|
|
399
|
-
` Tables: ${
|
|
548
|
+
pc2.dim(
|
|
549
|
+
` Tables: ${pc2.white(String(stats.totalTables))} total (${stats.coreTableCount} core` + (stats.pluginTableCount > 0 ? ` + ${pc2.cyan(String(stats.pluginTableCount))} plugin` : "") + ")"
|
|
400
550
|
)
|
|
401
551
|
);
|
|
402
552
|
if (pluginsWithSchema.length > 0) {
|
|
@@ -412,13 +562,13 @@ async function printSummary(config, stats) {
|
|
|
412
562
|
const tableNames = Object.keys(plugin.schema);
|
|
413
563
|
const newTables = tableNames.filter((t) => !(t in coreSchema));
|
|
414
564
|
const extendedTables = tableNames.filter((t) => t in coreSchema);
|
|
415
|
-
console.log(
|
|
565
|
+
console.log(pc2.dim(` Plugin ${pc2.cyan(plugin.id)}:`));
|
|
416
566
|
for (const t of newTables) {
|
|
417
567
|
const fields = Object.keys(
|
|
418
568
|
plugin.schema[t]?.fields || {}
|
|
419
569
|
);
|
|
420
570
|
console.log(
|
|
421
|
-
|
|
571
|
+
pc2.green(` + ${t}`) + pc2.dim(` (new table, ${fields.length} field${fields.length !== 1 ? "s" : ""})`)
|
|
422
572
|
);
|
|
423
573
|
}
|
|
424
574
|
for (const t of extendedTables) {
|
|
@@ -426,7 +576,7 @@ async function printSummary(config, stats) {
|
|
|
426
576
|
plugin.schema[t]?.fields || {}
|
|
427
577
|
);
|
|
428
578
|
console.log(
|
|
429
|
-
|
|
579
|
+
pc2.yellow(` ~ ${t}`) + pc2.dim(` (${fields.length} field${fields.length !== 1 ? "s" : ""} added)`)
|
|
430
580
|
);
|
|
431
581
|
}
|
|
432
582
|
}
|
|
@@ -434,19 +584,19 @@ async function printSummary(config, stats) {
|
|
|
434
584
|
if (pluginsWithRequiredTablesOnly.length > 0) {
|
|
435
585
|
console.log("");
|
|
436
586
|
console.log(
|
|
437
|
-
|
|
587
|
+
pc2.yellow(" \u26A0 Some plugins require tables but do not provide schema definitions:")
|
|
438
588
|
);
|
|
439
589
|
for (const plugin of pluginsWithRequiredTablesOnly) {
|
|
440
590
|
const tables = plugin.requiredTables.join(", ");
|
|
441
591
|
console.log(
|
|
442
|
-
|
|
592
|
+
pc2.dim(` ${pc2.yellow(plugin.id)}: requires `) + pc2.white(tables)
|
|
443
593
|
);
|
|
444
594
|
if (plugin.setupInstructions) {
|
|
445
|
-
console.log(
|
|
595
|
+
console.log(pc2.dim(` \u2192 ${plugin.setupInstructions}`));
|
|
446
596
|
}
|
|
447
597
|
}
|
|
448
598
|
console.log(
|
|
449
|
-
|
|
599
|
+
pc2.dim(
|
|
450
600
|
"\n These tables must be added to your schema manually (or via the plugin's own tooling).\n The generated schema files will NOT include them automatically.\n"
|
|
451
601
|
)
|
|
452
602
|
);
|
|
@@ -455,10 +605,10 @@ async function printSummary(config, stats) {
|
|
|
455
605
|
function detectDrizzleSchema() {
|
|
456
606
|
const configFile = findDrizzleConfig();
|
|
457
607
|
if (!configFile) return null;
|
|
458
|
-
const configPath =
|
|
608
|
+
const configPath = path2.resolve(process.cwd(), configFile);
|
|
459
609
|
let content;
|
|
460
610
|
try {
|
|
461
|
-
content =
|
|
611
|
+
content = fs2.readFileSync(configPath, "utf-8");
|
|
462
612
|
} catch {
|
|
463
613
|
return null;
|
|
464
614
|
}
|
|
@@ -468,7 +618,7 @@ function detectDrizzleSchema() {
|
|
|
468
618
|
if (!schemaPath.endsWith(".ts") && !schemaPath.endsWith(".js")) {
|
|
469
619
|
schemaPath += ".ts";
|
|
470
620
|
}
|
|
471
|
-
schemaPath =
|
|
621
|
+
schemaPath = path2.resolve(process.cwd(), schemaPath);
|
|
472
622
|
let dialect;
|
|
473
623
|
const dialectMatch = content.match(/dialect\s*:\s*['"]([^'"]+)['"]/);
|
|
474
624
|
if (dialectMatch) {
|
|
@@ -488,22 +638,22 @@ function normalizeDialect(dialect) {
|
|
|
488
638
|
return void 0;
|
|
489
639
|
}
|
|
490
640
|
async function runDrizzleKitGenerate() {
|
|
491
|
-
console.log(
|
|
641
|
+
console.log(pc2.dim("\n Running drizzle-kit generate...\n"));
|
|
492
642
|
try {
|
|
493
643
|
const configFile = findDrizzleConfig();
|
|
494
644
|
const cmd = configFile ? `npx drizzle-kit generate --config ${configFile}` : "npx drizzle-kit generate";
|
|
495
645
|
execSync(cmd, { stdio: "inherit", cwd: process.cwd() });
|
|
496
646
|
console.log(
|
|
497
|
-
|
|
647
|
+
pc2.bold(pc2.green("\n\u2713 SQL migrations generated.\n")) + pc2.dim(" Run ") + pc2.cyan("npx invect-cli migrate") + pc2.dim(" to apply them.\n")
|
|
498
648
|
);
|
|
499
649
|
} catch {
|
|
500
650
|
console.error(
|
|
501
|
-
|
|
651
|
+
pc2.yellow("\n\u26A0 drizzle-kit generate failed.") + "\n" + pc2.dim(" Make sure drizzle-kit is installed and drizzle.config.ts exists.") + "\n" + pc2.dim(" You can run it manually: ") + pc2.cyan("npx drizzle-kit generate") + "\n"
|
|
502
652
|
);
|
|
503
653
|
}
|
|
504
654
|
}
|
|
505
655
|
async function runDrizzleKitPush() {
|
|
506
|
-
console.log(
|
|
656
|
+
console.log(pc2.dim("\n Running drizzle-kit push...\n"));
|
|
507
657
|
try {
|
|
508
658
|
const configFile = findDrizzleConfig();
|
|
509
659
|
const cmd = configFile ? `npx drizzle-kit push --config ${configFile}` : "npx drizzle-kit push";
|
|
@@ -514,7 +664,7 @@ async function runDrizzleKitPush() {
|
|
|
514
664
|
});
|
|
515
665
|
if (output) process.stdout.write(output);
|
|
516
666
|
console.log(
|
|
517
|
-
|
|
667
|
+
pc2.bold(pc2.green("\n\u2713 Schema pushed to database.\n"))
|
|
518
668
|
);
|
|
519
669
|
} catch (error) {
|
|
520
670
|
const execError = error;
|
|
@@ -525,13 +675,13 @@ async function runDrizzleKitPush() {
|
|
|
525
675
|
].join("\n");
|
|
526
676
|
if (/already exists/i.test(combinedOutput)) {
|
|
527
677
|
console.log(
|
|
528
|
-
|
|
678
|
+
pc2.bold(pc2.green("\n\u2713 Schema is already applied to the database.\n"))
|
|
529
679
|
);
|
|
530
680
|
} else {
|
|
531
681
|
if (execError.stderr) process.stderr.write(execError.stderr);
|
|
532
682
|
if (execError.stdout) process.stdout.write(execError.stdout);
|
|
533
683
|
console.error(
|
|
534
|
-
|
|
684
|
+
pc2.yellow("\n\u26A0 drizzle-kit push failed.") + "\n" + pc2.dim(" Make sure drizzle-kit is installed and drizzle.config.ts exists.") + "\n" + pc2.dim(" You can run it manually: ") + pc2.cyan("npx drizzle-kit push") + "\n"
|
|
535
685
|
);
|
|
536
686
|
}
|
|
537
687
|
}
|
|
@@ -545,25 +695,27 @@ function findDrizzleConfig() {
|
|
|
545
695
|
"drizzle.config.mysql.ts"
|
|
546
696
|
];
|
|
547
697
|
for (const file of candidates) {
|
|
548
|
-
if (
|
|
698
|
+
if (fs2.existsSync(path2.resolve(process.cwd(), file))) {
|
|
549
699
|
return file;
|
|
550
700
|
}
|
|
551
701
|
}
|
|
552
702
|
return null;
|
|
553
703
|
}
|
|
554
704
|
function printNextSteps() {
|
|
555
|
-
console.log(
|
|
556
|
-
console.log(
|
|
705
|
+
console.log(pc2.dim("\n Next steps:"));
|
|
706
|
+
console.log(pc2.dim(" 1. Review the generated schema files"));
|
|
557
707
|
console.log(
|
|
558
|
-
|
|
708
|
+
pc2.dim(" 2. Run ") + pc2.cyan("npx drizzle-kit generate") + pc2.dim(" to create SQL migrations")
|
|
559
709
|
);
|
|
560
710
|
console.log(
|
|
561
|
-
|
|
711
|
+
pc2.dim(" 3. Run ") + pc2.cyan("npx invect-cli migrate") + pc2.dim(" to apply them")
|
|
562
712
|
);
|
|
563
713
|
console.log("");
|
|
564
714
|
}
|
|
565
715
|
|
|
566
716
|
export {
|
|
717
|
+
findConfigPath,
|
|
718
|
+
loadConfig,
|
|
567
719
|
generateCommand,
|
|
568
720
|
generateAction
|
|
569
721
|
};
|