drizzle-auto 1.1.2 → 1.1.4
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/index.js +146 -127
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,162 +1,181 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
const path = require("path");
|
|
5
3
|
const chokidar = require("chokidar");
|
|
6
4
|
const { spawn } = require("child_process");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const fs = require("fs");
|
|
7
7
|
|
|
8
|
-
/*
|
|
9
|
-
🎨
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (!fs.existsSync(PKG)) return;
|
|
33
|
-
|
|
34
|
-
const pkg = JSON.parse(fs.readFileSync(PKG, "utf8"));
|
|
35
|
-
pkg.scripts ||= {};
|
|
36
|
-
|
|
37
|
-
if (!pkg.scripts.tea) {
|
|
38
|
-
pkg.scripts.tea = "drizzle-auto";
|
|
39
|
-
fs.writeFileSync(PKG, JSON.stringify(pkg, null, 2));
|
|
40
|
-
console.log(
|
|
41
|
-
`${C.green}☕ Added script:${C.reset} ${C.bold}npm run tea${C.reset}`
|
|
42
|
-
);
|
|
43
|
-
}
|
|
8
|
+
/* =======================
|
|
9
|
+
🎨 NeonPulse UI Core
|
|
10
|
+
======================= */
|
|
11
|
+
const PALETTE = ["\x1b[31m", "\x1b[32m", "\x1b[33m", "\x1b[34m", "\x1b[35m", "\x1b[36m"];
|
|
12
|
+
const RESET = "\x1b[0m";
|
|
13
|
+
const BOLD = "\x1b[1m";
|
|
14
|
+
const DIM = "\x1b[90m";
|
|
15
|
+
|
|
16
|
+
let colorIndex = 0;
|
|
17
|
+
const nextColor = () => PALETTE[colorIndex++ % PALETTE.length];
|
|
18
|
+
const rainbow = (text) => text.split("").map((c) => `${nextColor()}${c}`).join("") + RESET;
|
|
19
|
+
|
|
20
|
+
/* =======================
|
|
21
|
+
⏳ Dynamic Spinner
|
|
22
|
+
======================= */
|
|
23
|
+
const spinnerFrames = ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];
|
|
24
|
+
let spinIndex = 0;
|
|
25
|
+
let spinnerInterval;
|
|
26
|
+
|
|
27
|
+
function startSpinner(text) {
|
|
28
|
+
stopSpinner();
|
|
29
|
+
spinnerInterval = setInterval(() => {
|
|
30
|
+
process.stdout.write(`\r${nextColor()}${spinnerFrames[spinIndex++ % spinnerFrames.length]} ${text}${RESET}`);
|
|
31
|
+
}, 80);
|
|
44
32
|
}
|
|
45
33
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
let found = null;
|
|
52
|
-
|
|
53
|
-
function walk(dir) {
|
|
54
|
-
if (found) return;
|
|
55
|
-
for (const file of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
56
|
-
if (file.name === "node_modules" || file.name.startsWith(".")) continue;
|
|
57
|
-
const full = path.join(dir, file.name);
|
|
58
|
-
|
|
59
|
-
if (file.isDirectory()) walk(full);
|
|
60
|
-
else {
|
|
61
|
-
for (const e of exts) {
|
|
62
|
-
if (file.name === `drizzle.config.${e}`) {
|
|
63
|
-
found = full;
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
34
|
+
function stopSpinner() {
|
|
35
|
+
if (spinnerInterval) {
|
|
36
|
+
clearInterval(spinnerInterval);
|
|
37
|
+
spinnerInterval = null;
|
|
38
|
+
process.stdout.write("\r\x1b[K");
|
|
69
39
|
}
|
|
70
|
-
|
|
71
|
-
walk(ROOT);
|
|
72
|
-
return found;
|
|
73
40
|
}
|
|
74
41
|
|
|
75
|
-
/*
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
42
|
+
/* =======================
|
|
43
|
+
🧠 5-Step Logic Engine
|
|
44
|
+
======================= */
|
|
45
|
+
let isRunning = false;
|
|
46
|
+
let hasActiveError = false;
|
|
47
|
+
|
|
48
|
+
// [STEP 2]: Justify All Infrastructure Files (Dynamic Format Support)
|
|
49
|
+
function justifyFiles() {
|
|
50
|
+
const root = process.cwd();
|
|
51
|
+
|
|
52
|
+
// চেক ১: কনফিগ ফাইল (js, mjs, ts, mts)
|
|
53
|
+
const config = ["ts", "js", "mjs", "mts"]
|
|
54
|
+
.map(ext => `drizzle.config.${ext}`)
|
|
55
|
+
.find(f => fs.existsSync(path.join(root, f)));
|
|
56
|
+
|
|
57
|
+
if (!config) return { ok: false, msg: "drizzle.config.(ts/js/mjs/mts) not found in project." };
|
|
58
|
+
|
|
59
|
+
// চেক ২: স্কিমা ফাইল জাস্টিফিকেশন (কনফিগ থেকে ডাইনামিকালি পাথ রিড করা)
|
|
79
60
|
try {
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
} catch {
|
|
87
|
-
return false;
|
|
61
|
+
const content = fs.readFileSync(path.join(root, config), "utf8");
|
|
62
|
+
const schemaMatch = content.match(/schema:\s*["'](.+?)["']/);
|
|
63
|
+
if (schemaMatch && schemaMatch[1]) {
|
|
64
|
+
const schemaPath = path.join(root, schemaMatch[1]);
|
|
65
|
+
if (!fs.existsSync(schemaPath)) return { ok: false, msg: `Schema file missing at: ${schemaMatch[1]}` };
|
|
66
|
+
}
|
|
67
|
+
} catch (e) {
|
|
68
|
+
return { ok: false, msg: "Failed to read or parse config file." };
|
|
88
69
|
}
|
|
70
|
+
|
|
71
|
+
return { ok: true };
|
|
89
72
|
}
|
|
90
73
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
========================= */
|
|
94
|
-
function run(cmd, args) {
|
|
74
|
+
// [STEP 3, 4, 5]: Command Executor with Strict Error Halt
|
|
75
|
+
function executeCommand(args, stepName) {
|
|
95
76
|
return new Promise((resolve) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
shell: false,
|
|
99
|
-
});
|
|
77
|
+
let hasError = false;
|
|
78
|
+
startSpinner(`[${stepName}] In Progress...`);
|
|
100
79
|
|
|
101
|
-
|
|
102
|
-
});
|
|
103
|
-
}
|
|
80
|
+
const child = spawn("npx", args, { shell: true });
|
|
104
81
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
82
|
+
child.stdout.on("data", (data) => {
|
|
83
|
+
const out = data.toString();
|
|
84
|
+
// Spam filter for cloud/server-side DB pulling logs
|
|
85
|
+
if (!out.includes('Pulling schema')) {
|
|
86
|
+
stopSpinner();
|
|
87
|
+
process.stdout.write(`${DIM}${out}${RESET}`);
|
|
88
|
+
}
|
|
89
|
+
if (/error|failed|ENOTFOUND|ECONNREFUSED/i.test(out)) hasError = true;
|
|
90
|
+
});
|
|
109
91
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
92
|
+
child.stderr.on("data", (data) => {
|
|
93
|
+
const err = data.toString();
|
|
94
|
+
stopSpinner();
|
|
95
|
+
process.stderr.write(`\x1b[31m${err}${RESET}`);
|
|
96
|
+
hasError = true;
|
|
97
|
+
});
|
|
113
98
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
99
|
+
child.on("close", (code) => {
|
|
100
|
+
stopSpinner();
|
|
101
|
+
resolve(code === 0 && !hasError);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
117
105
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
106
|
+
/* =======================
|
|
107
|
+
🔄 The Sequential Workflow
|
|
108
|
+
======================= */
|
|
109
|
+
async function startWorkflow(trigger) {
|
|
110
|
+
if (isRunning) return;
|
|
111
|
+
isRunning = true;
|
|
112
|
+
|
|
113
|
+
if (!hasActiveError) console.clear();
|
|
114
|
+
console.log(BOLD + rainbow("🚀 DRIZZLE-AUTO // UNIVERSAL SERVER-SIDE ENGINE"));
|
|
115
|
+
console.log(`${nextColor()}⚡ Trigger → ${trigger}${RESET}\n`);
|
|
116
|
+
|
|
117
|
+
// STEP 2: Justify Files (Infrastructure Check)
|
|
118
|
+
const audit = justifyFiles();
|
|
119
|
+
if (!audit.ok) {
|
|
120
|
+
console.log(`\n\x1b[31m🛑 STEP 2 FAILED: ${audit.msg}${RESET}`);
|
|
121
|
+
hasActiveError = true;
|
|
122
|
+
isRunning = false;
|
|
122
123
|
return;
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
// STEP 3: Confirm no bug in code (Integrity Check)
|
|
127
|
+
const step3 = await executeCommand(["drizzle-kit", "check"], "Step 3: Bug Check");
|
|
128
|
+
if (!step3) {
|
|
129
|
+
console.log(`\n\x1b[31m🛑 STEP 3 FAILED: Bugs or Drifts detected. Halting Pipeline.${RESET}`);
|
|
130
|
+
hasActiveError = true;
|
|
131
|
+
isRunning = false;
|
|
128
132
|
return;
|
|
129
133
|
}
|
|
130
134
|
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
if (!
|
|
134
|
-
console.log(
|
|
135
|
-
|
|
135
|
+
// STEP 4: Run Drizzle Generate
|
|
136
|
+
const step4 = await executeCommand(["drizzle-kit", "generate"], "Step 4: Generate");
|
|
137
|
+
if (!step4) {
|
|
138
|
+
console.log(`\n\x1b[31m🛑 STEP 4 FAILED: Migration generation failed.${RESET}`);
|
|
139
|
+
hasActiveError = true;
|
|
140
|
+
isRunning = false;
|
|
136
141
|
return;
|
|
137
142
|
}
|
|
138
143
|
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
if (!
|
|
142
|
-
console.log(
|
|
143
|
-
|
|
144
|
+
// STEP 5: Push Changes
|
|
145
|
+
const step5 = await executeCommand(["drizzle-kit", "push"], "Step 5: Push");
|
|
146
|
+
if (!step5) {
|
|
147
|
+
console.log(`\n\x1b[31m🛑 STEP 5 FAILED: DB Push failed. Check connection.${RESET}`);
|
|
148
|
+
hasActiveError = true;
|
|
149
|
+
isRunning = false;
|
|
144
150
|
return;
|
|
145
151
|
}
|
|
146
152
|
|
|
147
|
-
|
|
148
|
-
|
|
153
|
+
// ALL STEPS SUCCESS
|
|
154
|
+
hasActiveError = false;
|
|
155
|
+
console.log(`\n\x1b[32m${BOLD}✨ SUCCESS: 5/5 Steps Completed. All systems justified!${RESET}`);
|
|
156
|
+
|
|
157
|
+
setTimeout(() => {
|
|
158
|
+
isRunning = false;
|
|
159
|
+
console.log(`\n${DIM}🛰️ System justified. Watching for next change...${RESET}`);
|
|
160
|
+
}, 2000);
|
|
149
161
|
}
|
|
150
162
|
|
|
151
|
-
/*
|
|
152
|
-
👀
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
chokidar.watch(ROOT, {
|
|
158
|
-
ignored: [/node_modules/, /\.git/, /\.next/, /dist/],
|
|
163
|
+
/* =======================
|
|
164
|
+
👀 Universal Watcher
|
|
165
|
+
======================= */
|
|
166
|
+
chokidar.watch(".", {
|
|
167
|
+
ignored: [/node_modules/, /\.git/, /\.next/, /dist/, /drizzle/],
|
|
159
168
|
ignoreInitial: true,
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
});
|
|
169
|
+
usePolling: true,
|
|
170
|
+
interval: 300
|
|
171
|
+
}).on("all", (e, f) => startWorkflow(`${e.toUpperCase()} → ${path.basename(f)}`));
|
|
172
|
+
|
|
173
|
+
// Init Call
|
|
174
|
+
startWorkflow("Initial System Audit");
|
|
175
|
+
|
|
176
|
+
// Safety Net
|
|
177
|
+
process.on("uncaughtException", (err) => {
|
|
178
|
+
stopSpinner();
|
|
179
|
+
console.log(`\n\x1b[31m🛡️ Shield Error: ${err.message}${RESET}`);
|
|
180
|
+
isRunning = false;
|
|
181
|
+
});
|