@bungres/kit 0.6.1 → 1.0.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 +12 -3
- package/dist/cli.js +2660 -1132
- package/dist/commands/drop.d.ts.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/rollback.d.ts +3 -0
- package/dist/commands/rollback.d.ts.map +1 -0
- package/dist/commands/seed.d.ts.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/studio.d.ts.map +1 -1
- package/dist/commands/template.d.ts +2 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/tusky.d.ts.map +1 -1
- package/dist/index.js +1955 -175
- package/package.json +4 -2
- package/dist/utils/colors.d.ts +0 -2
- package/dist/utils/colors.d.ts.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,170 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
13
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
+
for (let key of __getOwnPropNames(mod))
|
|
24
|
+
if (!__hasOwnProp.call(to, key))
|
|
25
|
+
__defProp(to, key, {
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
27
|
+
enumerable: true
|
|
28
|
+
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
31
|
+
return to;
|
|
32
|
+
};
|
|
33
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
+
var __require = import.meta.require;
|
|
35
|
+
|
|
36
|
+
// ../../node_modules/.bun/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
|
|
37
|
+
var require_src = __commonJS((exports, module) => {
|
|
38
|
+
var ESC2 = "\x1B";
|
|
39
|
+
var CSI2 = `${ESC2}[`;
|
|
40
|
+
var beep = "\x07";
|
|
41
|
+
var cursor = {
|
|
42
|
+
to(x, y) {
|
|
43
|
+
if (!y)
|
|
44
|
+
return `${CSI2}${x + 1}G`;
|
|
45
|
+
return `${CSI2}${y + 1};${x + 1}H`;
|
|
46
|
+
},
|
|
47
|
+
move(x, y) {
|
|
48
|
+
let ret = "";
|
|
49
|
+
if (x < 0)
|
|
50
|
+
ret += `${CSI2}${-x}D`;
|
|
51
|
+
else if (x > 0)
|
|
52
|
+
ret += `${CSI2}${x}C`;
|
|
53
|
+
if (y < 0)
|
|
54
|
+
ret += `${CSI2}${-y}A`;
|
|
55
|
+
else if (y > 0)
|
|
56
|
+
ret += `${CSI2}${y}B`;
|
|
57
|
+
return ret;
|
|
58
|
+
},
|
|
59
|
+
up: (count = 1) => `${CSI2}${count}A`,
|
|
60
|
+
down: (count = 1) => `${CSI2}${count}B`,
|
|
61
|
+
forward: (count = 1) => `${CSI2}${count}C`,
|
|
62
|
+
backward: (count = 1) => `${CSI2}${count}D`,
|
|
63
|
+
nextLine: (count = 1) => `${CSI2}E`.repeat(count),
|
|
64
|
+
prevLine: (count = 1) => `${CSI2}F`.repeat(count),
|
|
65
|
+
left: `${CSI2}G`,
|
|
66
|
+
hide: `${CSI2}?25l`,
|
|
67
|
+
show: `${CSI2}?25h`,
|
|
68
|
+
save: `${ESC2}7`,
|
|
69
|
+
restore: `${ESC2}8`
|
|
70
|
+
};
|
|
71
|
+
var scroll = {
|
|
72
|
+
up: (count = 1) => `${CSI2}S`.repeat(count),
|
|
73
|
+
down: (count = 1) => `${CSI2}T`.repeat(count)
|
|
74
|
+
};
|
|
75
|
+
var erase = {
|
|
76
|
+
screen: `${CSI2}2J`,
|
|
77
|
+
up: (count = 1) => `${CSI2}1J`.repeat(count),
|
|
78
|
+
down: (count = 1) => `${CSI2}J`.repeat(count),
|
|
79
|
+
line: `${CSI2}2K`,
|
|
80
|
+
lineEnd: `${CSI2}K`,
|
|
81
|
+
lineStart: `${CSI2}1K`,
|
|
82
|
+
lines(count) {
|
|
83
|
+
let clear = "";
|
|
84
|
+
for (let i = 0;i < count; i++)
|
|
85
|
+
clear += this.line + (i < count - 1 ? cursor.up() : "");
|
|
86
|
+
if (count)
|
|
87
|
+
clear += cursor.left;
|
|
88
|
+
return clear;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
module.exports = { cursor, scroll, erase, beep };
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// ../../node_modules/.bun/picocolors@1.1.1/node_modules/picocolors/picocolors.js
|
|
95
|
+
var require_picocolors = __commonJS((exports, module) => {
|
|
96
|
+
var p2 = process || {};
|
|
97
|
+
var argv = p2.argv || [];
|
|
98
|
+
var env = p2.env || {};
|
|
99
|
+
var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p2.platform === "win32" || (p2.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
|
|
100
|
+
var formatter = (open, close, replace = open) => (input2) => {
|
|
101
|
+
let string = "" + input2, index = string.indexOf(close, open.length);
|
|
102
|
+
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
|
|
103
|
+
};
|
|
104
|
+
var replaceClose = (string, close, replace, index) => {
|
|
105
|
+
let result2 = "", cursor3 = 0;
|
|
106
|
+
do {
|
|
107
|
+
result2 += string.substring(cursor3, index) + replace;
|
|
108
|
+
cursor3 = index + close.length;
|
|
109
|
+
index = string.indexOf(close, cursor3);
|
|
110
|
+
} while (~index);
|
|
111
|
+
return result2 + string.substring(cursor3);
|
|
112
|
+
};
|
|
113
|
+
var createColors = (enabled = isColorSupported) => {
|
|
114
|
+
let f2 = enabled ? formatter : () => String;
|
|
115
|
+
return {
|
|
116
|
+
isColorSupported: enabled,
|
|
117
|
+
reset: f2("\x1B[0m", "\x1B[0m"),
|
|
118
|
+
bold: f2("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
|
|
119
|
+
dim: f2("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
|
|
120
|
+
italic: f2("\x1B[3m", "\x1B[23m"),
|
|
121
|
+
underline: f2("\x1B[4m", "\x1B[24m"),
|
|
122
|
+
inverse: f2("\x1B[7m", "\x1B[27m"),
|
|
123
|
+
hidden: f2("\x1B[8m", "\x1B[28m"),
|
|
124
|
+
strikethrough: f2("\x1B[9m", "\x1B[29m"),
|
|
125
|
+
black: f2("\x1B[30m", "\x1B[39m"),
|
|
126
|
+
red: f2("\x1B[31m", "\x1B[39m"),
|
|
127
|
+
green: f2("\x1B[32m", "\x1B[39m"),
|
|
128
|
+
yellow: f2("\x1B[33m", "\x1B[39m"),
|
|
129
|
+
blue: f2("\x1B[34m", "\x1B[39m"),
|
|
130
|
+
magenta: f2("\x1B[35m", "\x1B[39m"),
|
|
131
|
+
cyan: f2("\x1B[36m", "\x1B[39m"),
|
|
132
|
+
white: f2("\x1B[37m", "\x1B[39m"),
|
|
133
|
+
gray: f2("\x1B[90m", "\x1B[39m"),
|
|
134
|
+
bgBlack: f2("\x1B[40m", "\x1B[49m"),
|
|
135
|
+
bgRed: f2("\x1B[41m", "\x1B[49m"),
|
|
136
|
+
bgGreen: f2("\x1B[42m", "\x1B[49m"),
|
|
137
|
+
bgYellow: f2("\x1B[43m", "\x1B[49m"),
|
|
138
|
+
bgBlue: f2("\x1B[44m", "\x1B[49m"),
|
|
139
|
+
bgMagenta: f2("\x1B[45m", "\x1B[49m"),
|
|
140
|
+
bgCyan: f2("\x1B[46m", "\x1B[49m"),
|
|
141
|
+
bgWhite: f2("\x1B[47m", "\x1B[49m"),
|
|
142
|
+
blackBright: f2("\x1B[90m", "\x1B[39m"),
|
|
143
|
+
redBright: f2("\x1B[91m", "\x1B[39m"),
|
|
144
|
+
greenBright: f2("\x1B[92m", "\x1B[39m"),
|
|
145
|
+
yellowBright: f2("\x1B[93m", "\x1B[39m"),
|
|
146
|
+
blueBright: f2("\x1B[94m", "\x1B[39m"),
|
|
147
|
+
magentaBright: f2("\x1B[95m", "\x1B[39m"),
|
|
148
|
+
cyanBright: f2("\x1B[96m", "\x1B[39m"),
|
|
149
|
+
whiteBright: f2("\x1B[97m", "\x1B[39m"),
|
|
150
|
+
bgBlackBright: f2("\x1B[100m", "\x1B[49m"),
|
|
151
|
+
bgRedBright: f2("\x1B[101m", "\x1B[49m"),
|
|
152
|
+
bgGreenBright: f2("\x1B[102m", "\x1B[49m"),
|
|
153
|
+
bgYellowBright: f2("\x1B[103m", "\x1B[49m"),
|
|
154
|
+
bgBlueBright: f2("\x1B[104m", "\x1B[49m"),
|
|
155
|
+
bgMagentaBright: f2("\x1B[105m", "\x1B[49m"),
|
|
156
|
+
bgCyanBright: f2("\x1B[106m", "\x1B[49m"),
|
|
157
|
+
bgWhiteBright: f2("\x1B[107m", "\x1B[49m")
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
module.exports = createColors();
|
|
161
|
+
module.exports.createColors = createColors;
|
|
162
|
+
});
|
|
3
163
|
|
|
4
164
|
// src/schema-loader.ts
|
|
5
165
|
import { resolve, join } from "path";
|
|
6
166
|
|
|
7
|
-
// ../bungres-orm/
|
|
167
|
+
// ../bungres-orm/dist/index.js
|
|
8
168
|
var TableConfigSymbol = Symbol.for("BungresTableConfig");
|
|
9
169
|
function getTableConfig(table) {
|
|
10
170
|
return table[TableConfigSymbol];
|
|
@@ -74,7 +234,6 @@ var table = createTableFactory("snake");
|
|
|
74
234
|
var snakeCase = { table: createTableFactory("snake") };
|
|
75
235
|
var camelCase = { table: createTableFactory("camel") };
|
|
76
236
|
var noCasing = { table: createTableFactory("none") };
|
|
77
|
-
// ../bungres-orm/src/schema/columns.ts
|
|
78
237
|
function buildColumn(dataType, nameOrOpts, opts) {
|
|
79
238
|
let name = "";
|
|
80
239
|
let options = opts;
|
|
@@ -103,6 +262,13 @@ function buildColumn(dataType, nameOrOpts, opts) {
|
|
|
103
262
|
return Object.assign(config2, {
|
|
104
263
|
as(alias) {
|
|
105
264
|
return Object.assign({}, this, { alias });
|
|
265
|
+
},
|
|
266
|
+
array() {
|
|
267
|
+
return Object.assign({}, this, { dataType: `${this.dataType}[]` });
|
|
268
|
+
},
|
|
269
|
+
generatedAlwaysAs(expr) {
|
|
270
|
+
const sqlStr = typeof expr === "string" ? expr : expr.sql;
|
|
271
|
+
return Object.assign({}, this, { generatedAs: sqlStr });
|
|
106
272
|
}
|
|
107
273
|
});
|
|
108
274
|
}
|
|
@@ -132,7 +298,6 @@ var textArray = col("text[]");
|
|
|
132
298
|
var integerArray = col("integer[]");
|
|
133
299
|
var varcharArray = col("varchar[]");
|
|
134
300
|
var uuidArray = col("uuid[]");
|
|
135
|
-
// ../bungres-orm/src/core/sql.ts
|
|
136
301
|
function sql(strings, ...values) {
|
|
137
302
|
let query = "";
|
|
138
303
|
const params = [];
|
|
@@ -175,7 +340,6 @@ function colName(c) {
|
|
|
175
340
|
return c.sql;
|
|
176
341
|
return c.tableName ? `${c.tableName}."${c.name}"` : `"${c.name}"`;
|
|
177
342
|
}
|
|
178
|
-
// ../bungres-orm/src/core/conditions.ts
|
|
179
343
|
function isColumnConfig(val) {
|
|
180
344
|
return val !== null && typeof val === "object" && "name" in val && "dataType" in val;
|
|
181
345
|
}
|
|
@@ -329,14 +493,13 @@ function parseOrderByObject(tableConfig, orderByObj) {
|
|
|
329
493
|
}
|
|
330
494
|
return parts;
|
|
331
495
|
}
|
|
332
|
-
|
|
333
|
-
// ../bungres-orm/src/builders/delete.ts
|
|
334
496
|
class DeleteBuilder {
|
|
335
497
|
_table;
|
|
336
498
|
_executor;
|
|
337
499
|
_where = [];
|
|
338
500
|
_returning;
|
|
339
501
|
_comment;
|
|
502
|
+
_with = [];
|
|
340
503
|
constructor(table2, executor) {
|
|
341
504
|
this._table = table2;
|
|
342
505
|
this._executor = executor;
|
|
@@ -355,6 +518,10 @@ class DeleteBuilder {
|
|
|
355
518
|
}
|
|
356
519
|
return this;
|
|
357
520
|
}
|
|
521
|
+
with(...ctes) {
|
|
522
|
+
this._with.push(...ctes);
|
|
523
|
+
return this;
|
|
524
|
+
}
|
|
358
525
|
returning(...columns) {
|
|
359
526
|
this._returning = columns.length > 0 ? columns : ["*"];
|
|
360
527
|
return this;
|
|
@@ -364,8 +531,20 @@ class DeleteBuilder {
|
|
|
364
531
|
return this;
|
|
365
532
|
}
|
|
366
533
|
toSQL() {
|
|
367
|
-
|
|
534
|
+
const tConfig = getTableConfig(this._table);
|
|
368
535
|
const params = [];
|
|
536
|
+
let prefix = "";
|
|
537
|
+
if (this._with.length > 0) {
|
|
538
|
+
const cteStrs = [];
|
|
539
|
+
for (const cte of this._with) {
|
|
540
|
+
const chunk = cte.query.toSQL();
|
|
541
|
+
const offset = params.length;
|
|
542
|
+
params.push(...chunk.params);
|
|
543
|
+
cteStrs.push(`"${cte.alias}" AS (${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)})`);
|
|
544
|
+
}
|
|
545
|
+
prefix = `WITH ${cteStrs.join(", ")} `;
|
|
546
|
+
}
|
|
547
|
+
let query = `DELETE FROM ${tConfig.qualifiedName}`;
|
|
369
548
|
if (this._where.length > 0) {
|
|
370
549
|
const combined = sqlJoin(this._where, " AND ");
|
|
371
550
|
query += " WHERE " + combined.sql;
|
|
@@ -377,17 +556,19 @@ class DeleteBuilder {
|
|
|
377
556
|
if (this._comment) {
|
|
378
557
|
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
379
558
|
}
|
|
380
|
-
return { sql: query, params };
|
|
559
|
+
return { sql: prefix + query, params };
|
|
381
560
|
}
|
|
382
561
|
}
|
|
383
|
-
|
|
562
|
+
|
|
384
563
|
class InsertBuilder {
|
|
385
564
|
_table;
|
|
386
565
|
_executor;
|
|
387
566
|
_values = [];
|
|
388
567
|
_onConflict;
|
|
568
|
+
_onConflictUpdateConfig;
|
|
389
569
|
_returning;
|
|
390
570
|
_comment;
|
|
571
|
+
_with = [];
|
|
391
572
|
constructor(table2, executor) {
|
|
392
573
|
this._table = table2;
|
|
393
574
|
this._executor = executor;
|
|
@@ -414,6 +595,14 @@ class InsertBuilder {
|
|
|
414
595
|
this._onConflict = clause;
|
|
415
596
|
return this;
|
|
416
597
|
}
|
|
598
|
+
onConflictDoUpdate(config2) {
|
|
599
|
+
this._onConflictUpdateConfig = config2;
|
|
600
|
+
return this;
|
|
601
|
+
}
|
|
602
|
+
with(...ctes) {
|
|
603
|
+
this._with.push(...ctes);
|
|
604
|
+
return this;
|
|
605
|
+
}
|
|
417
606
|
returning(...columns) {
|
|
418
607
|
this._returning = columns.length > 0 ? columns : ["*"];
|
|
419
608
|
return this;
|
|
@@ -439,6 +628,17 @@ class InsertBuilder {
|
|
|
439
628
|
}
|
|
440
629
|
const columnsStr = keys.map((k) => `"${tConfig.columns[k]?.name ?? k}"`).join(", ");
|
|
441
630
|
const params = [];
|
|
631
|
+
let prefix = "";
|
|
632
|
+
if (this._with.length > 0) {
|
|
633
|
+
const cteStrs = [];
|
|
634
|
+
for (const cte of this._with) {
|
|
635
|
+
const chunk = cte.query.toSQL();
|
|
636
|
+
const offset = params.length;
|
|
637
|
+
params.push(...chunk.params);
|
|
638
|
+
cteStrs.push(`"${cte.alias}" AS (${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)})`);
|
|
639
|
+
}
|
|
640
|
+
prefix = `WITH ${cteStrs.join(", ")} `;
|
|
641
|
+
}
|
|
442
642
|
const valuesStrs = this._values.map((v) => {
|
|
443
643
|
const vals = keys.map((k) => {
|
|
444
644
|
const val = v[k];
|
|
@@ -482,6 +682,52 @@ class InsertBuilder {
|
|
|
482
682
|
query += " " + this._onConflict.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
483
683
|
params.push(...this._onConflict.params);
|
|
484
684
|
}
|
|
685
|
+
} else if (this._onConflictUpdateConfig) {
|
|
686
|
+
const config2 = this._onConflictUpdateConfig;
|
|
687
|
+
const targets = Array.isArray(config2.target) ? config2.target : [config2.target];
|
|
688
|
+
const targetStrs = [];
|
|
689
|
+
for (const t of targets) {
|
|
690
|
+
if (typeof t === "string") {
|
|
691
|
+
targetStrs.push(`"${tConfig.columns[t]?.name ?? t}"`);
|
|
692
|
+
} else {
|
|
693
|
+
const offset = params.length;
|
|
694
|
+
targetStrs.push(t.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`));
|
|
695
|
+
params.push(...t.params);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
const setEntries = Object.entries(config2.set);
|
|
699
|
+
if (setEntries.length === 0)
|
|
700
|
+
throw new Error("InsertBuilder: onConflictDoUpdate requires 'set' fields");
|
|
701
|
+
const setClauses = setEntries.map(([key, value]) => {
|
|
702
|
+
const dbCol = tConfig.columns[key]?.name ?? key;
|
|
703
|
+
if (value && typeof value === "object" && "sql" in value && "params" in value) {
|
|
704
|
+
const chunk = value;
|
|
705
|
+
const offset = params.length;
|
|
706
|
+
params.push(...chunk.params);
|
|
707
|
+
return `"${dbCol}" = ${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)}`;
|
|
708
|
+
}
|
|
709
|
+
if (value && typeof value === "object" && !(value instanceof Date)) {
|
|
710
|
+
const colType = tConfig.columns[key]?.dataType;
|
|
711
|
+
if (colType === "json" || colType === "jsonb") {
|
|
712
|
+
params.push(value);
|
|
713
|
+
} else if (Array.isArray(value)) {
|
|
714
|
+
const pgArray = "{" + value.map((item) => {
|
|
715
|
+
if (item === null || item === undefined)
|
|
716
|
+
return "NULL";
|
|
717
|
+
if (typeof item === "string")
|
|
718
|
+
return '"' + item.replace(/"/g, "\\\"") + '"';
|
|
719
|
+
return typeof item === "object" ? '"' + JSON.stringify(item).replace(/"/g, "\\\"") + '"' : String(item);
|
|
720
|
+
}).join(",") + "}";
|
|
721
|
+
params.push(pgArray);
|
|
722
|
+
} else {
|
|
723
|
+
params.push(JSON.stringify(value));
|
|
724
|
+
}
|
|
725
|
+
return `"${dbCol}" = $${params.length}`;
|
|
726
|
+
}
|
|
727
|
+
params.push(value);
|
|
728
|
+
return `"${dbCol}" = $${params.length}`;
|
|
729
|
+
});
|
|
730
|
+
query += ` ON CONFLICT (${targetStrs.join(", ")}) DO UPDATE SET ${setClauses.join(", ")}`;
|
|
485
731
|
}
|
|
486
732
|
if (this._returning) {
|
|
487
733
|
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(tConfig.columns).map((c) => `"${tConfig.columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${tConfig.columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
@@ -489,10 +735,10 @@ class InsertBuilder {
|
|
|
489
735
|
if (this._comment) {
|
|
490
736
|
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
491
737
|
}
|
|
492
|
-
return { sql: query, params };
|
|
738
|
+
return { sql: prefix + query, params };
|
|
493
739
|
}
|
|
494
740
|
}
|
|
495
|
-
|
|
741
|
+
|
|
496
742
|
class SelectBuilder {
|
|
497
743
|
_table;
|
|
498
744
|
_executor;
|
|
@@ -505,6 +751,8 @@ class SelectBuilder {
|
|
|
505
751
|
_select;
|
|
506
752
|
_selection;
|
|
507
753
|
_joins = [];
|
|
754
|
+
_with = [];
|
|
755
|
+
_setOperations = [];
|
|
508
756
|
_comment;
|
|
509
757
|
constructor(table2, executor, selection) {
|
|
510
758
|
this._table = table2;
|
|
@@ -515,12 +763,35 @@ class SelectBuilder {
|
|
|
515
763
|
return this._executor.execute(this).then(onfulfilled, onrejected);
|
|
516
764
|
}
|
|
517
765
|
async single() {
|
|
766
|
+
if (this._limit === undefined) {
|
|
767
|
+
this.limit(1);
|
|
768
|
+
}
|
|
518
769
|
return this._executor.executeSingle(this);
|
|
519
770
|
}
|
|
520
771
|
select(...columns) {
|
|
521
772
|
this._select = columns;
|
|
522
773
|
return this;
|
|
523
774
|
}
|
|
775
|
+
with(...ctes) {
|
|
776
|
+
this._with.push(...ctes);
|
|
777
|
+
return this;
|
|
778
|
+
}
|
|
779
|
+
union(other) {
|
|
780
|
+
this._setOperations.push({ type: "UNION", builder: other });
|
|
781
|
+
return this;
|
|
782
|
+
}
|
|
783
|
+
unionAll(other) {
|
|
784
|
+
this._setOperations.push({ type: "UNION ALL", builder: other });
|
|
785
|
+
return this;
|
|
786
|
+
}
|
|
787
|
+
intersect(other) {
|
|
788
|
+
this._setOperations.push({ type: "INTERSECT", builder: other });
|
|
789
|
+
return this;
|
|
790
|
+
}
|
|
791
|
+
except(other) {
|
|
792
|
+
this._setOperations.push({ type: "EXCEPT", builder: other });
|
|
793
|
+
return this;
|
|
794
|
+
}
|
|
524
795
|
comment(tag) {
|
|
525
796
|
this._comment = tag;
|
|
526
797
|
return this;
|
|
@@ -623,7 +894,23 @@ class SelectBuilder {
|
|
|
623
894
|
}).join(", ");
|
|
624
895
|
} else {
|
|
625
896
|
const qName = getTableConfig(this._table).qualifiedName;
|
|
626
|
-
|
|
897
|
+
const colsKeys = Object.keys(getTableConfig(this._table).columns);
|
|
898
|
+
if (colsKeys.length === 0) {
|
|
899
|
+
cols = "*";
|
|
900
|
+
} else {
|
|
901
|
+
cols = colsKeys.map((c) => `${qName}."${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ");
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
let prefix = "";
|
|
905
|
+
if (this._with.length > 0) {
|
|
906
|
+
const cteStrs = [];
|
|
907
|
+
for (const cte of this._with) {
|
|
908
|
+
const chunk = cte.query.toSQL();
|
|
909
|
+
const offset = params.length;
|
|
910
|
+
params.push(...chunk.params);
|
|
911
|
+
cteStrs.push(`"${cte.alias}" AS (${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)})`);
|
|
912
|
+
}
|
|
913
|
+
prefix = `WITH ${cteStrs.join(", ")} `;
|
|
627
914
|
}
|
|
628
915
|
let query = `SELECT ${cols} FROM ${getTableConfig(this._table).qualifiedName}`;
|
|
629
916
|
if (this._joins.length > 0) {
|
|
@@ -683,10 +970,18 @@ class SelectBuilder {
|
|
|
683
970
|
params.push(this._offset);
|
|
684
971
|
query += ` OFFSET $${params.length}`;
|
|
685
972
|
}
|
|
973
|
+
if (this._setOperations.length > 0) {
|
|
974
|
+
for (const op of this._setOperations) {
|
|
975
|
+
const chunk = op.builder.toSQL();
|
|
976
|
+
const offset = params.length;
|
|
977
|
+
params.push(...chunk.params);
|
|
978
|
+
query += ` ${op.type} ${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)}`;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
686
981
|
if (this._comment) {
|
|
687
982
|
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
688
983
|
}
|
|
689
|
-
return { sql: query, params };
|
|
984
|
+
return { sql: prefix + query, params };
|
|
690
985
|
}
|
|
691
986
|
}
|
|
692
987
|
|
|
@@ -701,7 +996,7 @@ class SelectBuilderIntermediate {
|
|
|
701
996
|
return new SelectBuilder(table2, this._executor, this._selection);
|
|
702
997
|
}
|
|
703
998
|
}
|
|
704
|
-
|
|
999
|
+
|
|
705
1000
|
class UpdateBuilder {
|
|
706
1001
|
_table;
|
|
707
1002
|
_executor;
|
|
@@ -709,6 +1004,7 @@ class UpdateBuilder {
|
|
|
709
1004
|
_where = [];
|
|
710
1005
|
_returning;
|
|
711
1006
|
_comment;
|
|
1007
|
+
_with = [];
|
|
712
1008
|
constructor(table2, executor) {
|
|
713
1009
|
this._table = table2;
|
|
714
1010
|
this._executor = executor;
|
|
@@ -731,6 +1027,10 @@ class UpdateBuilder {
|
|
|
731
1027
|
}
|
|
732
1028
|
return this;
|
|
733
1029
|
}
|
|
1030
|
+
with(...ctes) {
|
|
1031
|
+
this._with.push(...ctes);
|
|
1032
|
+
return this;
|
|
1033
|
+
}
|
|
734
1034
|
returning(...columns) {
|
|
735
1035
|
this._returning = columns.length > 0 ? columns : ["*"];
|
|
736
1036
|
return this;
|
|
@@ -745,6 +1045,17 @@ class UpdateBuilder {
|
|
|
745
1045
|
throw new Error("UpdateBuilder: no fields to set");
|
|
746
1046
|
}
|
|
747
1047
|
const params = [];
|
|
1048
|
+
let prefix = "";
|
|
1049
|
+
if (this._with.length > 0) {
|
|
1050
|
+
const cteStrs = [];
|
|
1051
|
+
for (const cte of this._with) {
|
|
1052
|
+
const chunk = cte.query.toSQL();
|
|
1053
|
+
const offset = params.length;
|
|
1054
|
+
params.push(...chunk.params);
|
|
1055
|
+
cteStrs.push(`"${cte.alias}" AS (${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)})`);
|
|
1056
|
+
}
|
|
1057
|
+
prefix = `WITH ${cteStrs.join(", ")} `;
|
|
1058
|
+
}
|
|
748
1059
|
const setClauses = entries.map(([key, value]) => {
|
|
749
1060
|
const dbCol = getTableConfig(this._table).columns[key]?.name ?? key;
|
|
750
1061
|
if (value && typeof value === "object" && "sql" in value && "params" in value) {
|
|
@@ -787,10 +1098,9 @@ class UpdateBuilder {
|
|
|
787
1098
|
if (this._comment) {
|
|
788
1099
|
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
789
1100
|
}
|
|
790
|
-
return { sql: query, params };
|
|
1101
|
+
return { sql: prefix + query, params };
|
|
791
1102
|
}
|
|
792
1103
|
}
|
|
793
|
-
// ../bungres-orm/src/builders/relational.ts
|
|
794
1104
|
function getPkColumn(tableConfig) {
|
|
795
1105
|
if (tableConfig.primaryKeys?.length > 0)
|
|
796
1106
|
return tableConfig.primaryKeys[0];
|
|
@@ -1048,8 +1358,6 @@ class RelationalQueryBuilder {
|
|
|
1048
1358
|
return { sql: sql2, params };
|
|
1049
1359
|
}
|
|
1050
1360
|
}
|
|
1051
|
-
|
|
1052
|
-
// ../bungres-orm/src/core/db.ts
|
|
1053
1361
|
function parseDBName(url) {
|
|
1054
1362
|
try {
|
|
1055
1363
|
return new URL(url).pathname.slice(1);
|
|
@@ -1158,6 +1466,7 @@ class BungresDB {
|
|
|
1158
1466
|
|
|
1159
1467
|
class BungresTransaction {
|
|
1160
1468
|
_sql;
|
|
1469
|
+
_savepointCounter = 0;
|
|
1161
1470
|
constructor(sql2) {
|
|
1162
1471
|
this._sql = sql2;
|
|
1163
1472
|
}
|
|
@@ -1192,6 +1501,19 @@ class BungresTransaction {
|
|
|
1192
1501
|
const result2 = await this._sql.unsafe(query, params);
|
|
1193
1502
|
return Array.from(result2);
|
|
1194
1503
|
}
|
|
1504
|
+
async transaction(fn) {
|
|
1505
|
+
this._savepointCounter++;
|
|
1506
|
+
const spName = `sp_${this._savepointCounter}`;
|
|
1507
|
+
await this._sql.unsafe(`SAVEPOINT ${spName}`);
|
|
1508
|
+
try {
|
|
1509
|
+
const result2 = await fn(this);
|
|
1510
|
+
await this._sql.unsafe(`RELEASE SAVEPOINT ${spName}`);
|
|
1511
|
+
return result2;
|
|
1512
|
+
} catch (e) {
|
|
1513
|
+
await this._sql.unsafe(`ROLLBACK TO SAVEPOINT ${spName}`);
|
|
1514
|
+
throw e;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1195
1517
|
}
|
|
1196
1518
|
function bungres(config2) {
|
|
1197
1519
|
const db2 = new BungresDB(config2);
|
|
@@ -1215,7 +1537,6 @@ function bungres(config2) {
|
|
|
1215
1537
|
}
|
|
1216
1538
|
return db2;
|
|
1217
1539
|
}
|
|
1218
|
-
// ../bungres-orm/src/ddl.ts
|
|
1219
1540
|
function generateCreateTable(config2, ifNotExists = true) {
|
|
1220
1541
|
const tableName = config2.schema ? `"${config2.schema}"."${config2.name}"` : `"${config2.name}"`;
|
|
1221
1542
|
const exists = ifNotExists ? " IF NOT EXISTS" : "";
|
|
@@ -1225,8 +1546,8 @@ function generateCreateTable(config2, ifNotExists = true) {
|
|
|
1225
1546
|
columnDefs.push(`PRIMARY KEY (${pkCols})`);
|
|
1226
1547
|
}
|
|
1227
1548
|
if (config2.checks) {
|
|
1228
|
-
for (const
|
|
1229
|
-
columnDefs.push(`CHECK (${
|
|
1549
|
+
for (const check2 of config2.checks) {
|
|
1550
|
+
columnDefs.push(`CHECK (${check2})`);
|
|
1230
1551
|
}
|
|
1231
1552
|
}
|
|
1232
1553
|
let sql2 = `CREATE TABLE${exists} ${tableName} (
|
|
@@ -1264,7 +1585,9 @@ function buildColumnDDL(key, col2, tableName) {
|
|
|
1264
1585
|
if (col2.unique && !col2.primaryKey) {
|
|
1265
1586
|
parts.push("UNIQUE");
|
|
1266
1587
|
}
|
|
1267
|
-
if (col2.
|
|
1588
|
+
if (col2.generatedAs) {
|
|
1589
|
+
parts.push(`GENERATED ALWAYS AS (${col2.generatedAs}) STORED`);
|
|
1590
|
+
} else if (col2.defaultFn) {
|
|
1268
1591
|
parts.push(`DEFAULT ${col2.defaultFn}`);
|
|
1269
1592
|
} else if (col2.defaultValue !== undefined) {
|
|
1270
1593
|
parts.push(`DEFAULT ${formatDefaultValue(col2.defaultValue, col2.dataType)}`);
|
|
@@ -1285,6 +1608,13 @@ function buildColumnDDL(key, col2, tableName) {
|
|
|
1285
1608
|
return parts.join(" ");
|
|
1286
1609
|
}
|
|
1287
1610
|
function buildType(col2) {
|
|
1611
|
+
if (col2.enumConfig) {
|
|
1612
|
+
return `"${col2.enumConfig.enumName}"`;
|
|
1613
|
+
}
|
|
1614
|
+
if (col2.dataType.endsWith("[]")) {
|
|
1615
|
+
const baseType = buildType({ ...col2, dataType: col2.dataType.slice(0, -2) });
|
|
1616
|
+
return `${baseType}[]`;
|
|
1617
|
+
}
|
|
1288
1618
|
switch (col2.dataType) {
|
|
1289
1619
|
case "varchar":
|
|
1290
1620
|
return col2.length ? `VARCHAR(${col2.length})` : "VARCHAR";
|
|
@@ -1319,12 +1649,12 @@ function formatDefaultValue(value, dataType) {
|
|
|
1319
1649
|
}
|
|
1320
1650
|
function buildIndex(table2, idx) {
|
|
1321
1651
|
const tableName = table2.schema ? `"${table2.schema}"."${table2.name}"` : `"${table2.name}"`;
|
|
1322
|
-
const
|
|
1652
|
+
const unique2 = idx.unique ? "UNIQUE " : "";
|
|
1323
1653
|
const using = idx.using ? ` USING ${idx.using.toUpperCase()}` : "";
|
|
1324
1654
|
const cols = idx.columns.map((c) => `"${c}"`).join(", ");
|
|
1325
1655
|
const where = idx.where ? ` WHERE ${idx.where}` : "";
|
|
1326
1656
|
const idxName = idx.name ?? `idx_${table2.name}_${idx.columns.join("_")}`;
|
|
1327
|
-
return `CREATE ${
|
|
1657
|
+
return `CREATE ${unique2}INDEX IF NOT EXISTS "${idxName}" ON ${tableName}${using} (${cols})${where};`;
|
|
1328
1658
|
}
|
|
1329
1659
|
function generateAddColumn(tableName, schema, key, col2) {
|
|
1330
1660
|
const tbl = schema ? `"${schema}"."${tableName}"` : `"${tableName}"`;
|
|
@@ -1334,6 +1664,7 @@ function generateDropColumn(tableName, schema, columnName) {
|
|
|
1334
1664
|
const tbl = schema ? `"${schema}"."${tableName}"` : `"${tableName}"`;
|
|
1335
1665
|
return `ALTER TABLE ${tbl} DROP COLUMN IF EXISTS "${columnName}";`;
|
|
1336
1666
|
}
|
|
1667
|
+
|
|
1337
1668
|
// src/schema-loader.ts
|
|
1338
1669
|
async function loadSchemas(patterns, cwd = process.cwd()) {
|
|
1339
1670
|
const globs = Array.isArray(patterns) ? patterns : [patterns];
|
|
@@ -1361,144 +1692,1528 @@ function isTable(value) {
|
|
|
1361
1692
|
return typeof value === "object" && value !== null && TableConfigSymbol in value;
|
|
1362
1693
|
}
|
|
1363
1694
|
|
|
1364
|
-
//
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1695
|
+
// ../../node_modules/.bun/@clack+core@1.4.3/node_modules/@clack/core/dist/index.mjs
|
|
1696
|
+
import { styleText } from "util";
|
|
1697
|
+
import { stdout, stdin } from "process";
|
|
1698
|
+
import * as l from "readline";
|
|
1699
|
+
import l__default from "readline";
|
|
1369
1700
|
|
|
1370
|
-
//
|
|
1371
|
-
|
|
1372
|
-
const
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1701
|
+
// ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
|
|
1702
|
+
var getCodePointsLength = (() => {
|
|
1703
|
+
const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
1704
|
+
return (input2) => {
|
|
1705
|
+
let surrogatePairsNr = 0;
|
|
1706
|
+
SURROGATE_PAIR_RE.lastIndex = 0;
|
|
1707
|
+
while (SURROGATE_PAIR_RE.test(input2)) {
|
|
1708
|
+
surrogatePairsNr += 1;
|
|
1709
|
+
}
|
|
1710
|
+
return input2.length - surrogatePairsNr;
|
|
1711
|
+
};
|
|
1712
|
+
})();
|
|
1713
|
+
var isFullWidth = (x) => {
|
|
1714
|
+
return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
|
|
1715
|
+
};
|
|
1716
|
+
var isWideNotCJKTNotEmoji = (x) => {
|
|
1717
|
+
return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
|
|
1718
|
+
};
|
|
1719
|
+
|
|
1720
|
+
// ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
|
|
1721
|
+
var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
|
|
1722
|
+
var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
|
|
1723
|
+
var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
|
|
1724
|
+
var TAB_RE = /\t{1,1000}/y;
|
|
1725
|
+
var EMOJI_RE = /[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/yu;
|
|
1726
|
+
var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
|
|
1727
|
+
var MODIFIER_RE = /\p{M}+/gu;
|
|
1728
|
+
var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
|
|
1729
|
+
var getStringTruncatedWidth = (input2, truncationOptions = {}, widthOptions = {}) => {
|
|
1730
|
+
const LIMIT = truncationOptions.limit ?? Infinity;
|
|
1731
|
+
const ELLIPSIS = truncationOptions.ellipsis ?? "";
|
|
1732
|
+
const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
|
|
1733
|
+
const ANSI_WIDTH = 0;
|
|
1734
|
+
const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
|
|
1735
|
+
const TAB_WIDTH = widthOptions.tabWidth ?? 8;
|
|
1736
|
+
const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
|
|
1737
|
+
const FULL_WIDTH_WIDTH = 2;
|
|
1738
|
+
const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
|
|
1739
|
+
const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
|
|
1740
|
+
const PARSE_BLOCKS = [
|
|
1741
|
+
[LATIN_RE, REGULAR_WIDTH],
|
|
1742
|
+
[ANSI_RE, ANSI_WIDTH],
|
|
1743
|
+
[CONTROL_RE, CONTROL_WIDTH],
|
|
1744
|
+
[TAB_RE, TAB_WIDTH],
|
|
1745
|
+
[EMOJI_RE, EMOJI_WIDTH],
|
|
1746
|
+
[CJKT_WIDE_RE, WIDE_WIDTH]
|
|
1747
|
+
];
|
|
1748
|
+
let indexPrev = 0;
|
|
1749
|
+
let index = 0;
|
|
1750
|
+
let length = input2.length;
|
|
1751
|
+
let lengthExtra = 0;
|
|
1752
|
+
let truncationEnabled = false;
|
|
1753
|
+
let truncationIndex = length;
|
|
1754
|
+
let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
|
|
1755
|
+
let unmatchedStart = 0;
|
|
1756
|
+
let unmatchedEnd = 0;
|
|
1757
|
+
let width = 0;
|
|
1758
|
+
let widthExtra = 0;
|
|
1759
|
+
outer:
|
|
1760
|
+
while (true) {
|
|
1761
|
+
if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
|
|
1762
|
+
const unmatched = input2.slice(unmatchedStart, unmatchedEnd) || input2.slice(indexPrev, index);
|
|
1763
|
+
lengthExtra = 0;
|
|
1764
|
+
for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
|
|
1765
|
+
const codePoint = char.codePointAt(0) || 0;
|
|
1766
|
+
if (isFullWidth(codePoint)) {
|
|
1767
|
+
widthExtra = FULL_WIDTH_WIDTH;
|
|
1768
|
+
} else if (isWideNotCJKTNotEmoji(codePoint)) {
|
|
1769
|
+
widthExtra = WIDE_WIDTH;
|
|
1770
|
+
} else {
|
|
1771
|
+
widthExtra = REGULAR_WIDTH;
|
|
1772
|
+
}
|
|
1773
|
+
if (width + widthExtra > truncationLimit) {
|
|
1774
|
+
truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
|
|
1775
|
+
}
|
|
1776
|
+
if (width + widthExtra > LIMIT) {
|
|
1777
|
+
truncationEnabled = true;
|
|
1778
|
+
break outer;
|
|
1779
|
+
}
|
|
1780
|
+
lengthExtra += char.length;
|
|
1781
|
+
width += widthExtra;
|
|
1782
|
+
}
|
|
1783
|
+
unmatchedStart = unmatchedEnd = 0;
|
|
1784
|
+
}
|
|
1785
|
+
if (index >= length) {
|
|
1786
|
+
break outer;
|
|
1787
|
+
}
|
|
1788
|
+
for (let i = 0, l = PARSE_BLOCKS.length;i < l; i++) {
|
|
1789
|
+
const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
|
|
1790
|
+
BLOCK_RE.lastIndex = index;
|
|
1791
|
+
if (BLOCK_RE.test(input2)) {
|
|
1792
|
+
lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input2.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
|
|
1793
|
+
widthExtra = lengthExtra * BLOCK_WIDTH;
|
|
1794
|
+
if (width + widthExtra > truncationLimit) {
|
|
1795
|
+
truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
|
|
1796
|
+
}
|
|
1797
|
+
if (width + widthExtra > LIMIT) {
|
|
1798
|
+
truncationEnabled = true;
|
|
1799
|
+
break outer;
|
|
1800
|
+
}
|
|
1801
|
+
width += widthExtra;
|
|
1802
|
+
unmatchedStart = indexPrev;
|
|
1803
|
+
unmatchedEnd = index;
|
|
1804
|
+
index = indexPrev = BLOCK_RE.lastIndex;
|
|
1805
|
+
continue outer;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
index += 1;
|
|
1809
|
+
}
|
|
1810
|
+
return {
|
|
1811
|
+
width: truncationEnabled ? truncationLimit : width,
|
|
1812
|
+
index: truncationEnabled ? truncationIndex : length,
|
|
1813
|
+
truncated: truncationEnabled,
|
|
1814
|
+
ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
|
|
1815
|
+
};
|
|
1816
|
+
};
|
|
1817
|
+
var dist_default = getStringTruncatedWidth;
|
|
1818
|
+
|
|
1819
|
+
// ../../node_modules/.bun/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
|
|
1820
|
+
var NO_TRUNCATION2 = {
|
|
1821
|
+
limit: Infinity,
|
|
1822
|
+
ellipsis: "",
|
|
1823
|
+
ellipsisWidth: 0
|
|
1824
|
+
};
|
|
1825
|
+
var fastStringWidth = (input2, options = {}) => {
|
|
1826
|
+
return dist_default(input2, NO_TRUNCATION2, options).width;
|
|
1827
|
+
};
|
|
1828
|
+
var dist_default2 = fastStringWidth;
|
|
1829
|
+
|
|
1830
|
+
// ../../node_modules/.bun/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
|
|
1831
|
+
var ESC = "\x1B";
|
|
1832
|
+
var CSI = "\x9B";
|
|
1833
|
+
var END_CODE = 39;
|
|
1834
|
+
var ANSI_ESCAPE_BELL = "\x07";
|
|
1835
|
+
var ANSI_CSI = "[";
|
|
1836
|
+
var ANSI_OSC = "]";
|
|
1837
|
+
var ANSI_SGR_TERMINATOR = "m";
|
|
1838
|
+
var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
|
|
1839
|
+
var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
|
|
1840
|
+
var getClosingCode = (openingCode) => {
|
|
1841
|
+
if (openingCode >= 30 && openingCode <= 37)
|
|
1842
|
+
return 39;
|
|
1843
|
+
if (openingCode >= 90 && openingCode <= 97)
|
|
1844
|
+
return 39;
|
|
1845
|
+
if (openingCode >= 40 && openingCode <= 47)
|
|
1846
|
+
return 49;
|
|
1847
|
+
if (openingCode >= 100 && openingCode <= 107)
|
|
1848
|
+
return 49;
|
|
1849
|
+
if (openingCode === 1 || openingCode === 2)
|
|
1850
|
+
return 22;
|
|
1851
|
+
if (openingCode === 3)
|
|
1852
|
+
return 23;
|
|
1853
|
+
if (openingCode === 4)
|
|
1854
|
+
return 24;
|
|
1855
|
+
if (openingCode === 7)
|
|
1856
|
+
return 27;
|
|
1857
|
+
if (openingCode === 8)
|
|
1858
|
+
return 28;
|
|
1859
|
+
if (openingCode === 9)
|
|
1860
|
+
return 29;
|
|
1861
|
+
if (openingCode === 0)
|
|
1862
|
+
return 0;
|
|
1863
|
+
return;
|
|
1864
|
+
};
|
|
1865
|
+
var wrapAnsiCode = (code2) => `${ESC}${ANSI_CSI}${code2}${ANSI_SGR_TERMINATOR}`;
|
|
1866
|
+
var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
|
|
1867
|
+
var wrapWord = (rows, word, columns) => {
|
|
1868
|
+
const characters = word[Symbol.iterator]();
|
|
1869
|
+
let isInsideEscape = false;
|
|
1870
|
+
let isInsideLinkEscape = false;
|
|
1871
|
+
let lastRow = rows.at(-1);
|
|
1872
|
+
let visible = lastRow === undefined ? 0 : dist_default2(lastRow);
|
|
1873
|
+
let currentCharacter = characters.next();
|
|
1874
|
+
let nextCharacter = characters.next();
|
|
1875
|
+
let rawCharacterIndex = 0;
|
|
1876
|
+
while (!currentCharacter.done) {
|
|
1877
|
+
const character = currentCharacter.value;
|
|
1878
|
+
const characterLength = dist_default2(character);
|
|
1879
|
+
if (visible + characterLength <= columns) {
|
|
1880
|
+
rows[rows.length - 1] += character;
|
|
1881
|
+
} else {
|
|
1882
|
+
rows.push(character);
|
|
1883
|
+
visible = 0;
|
|
1884
|
+
}
|
|
1885
|
+
if (character === ESC || character === CSI) {
|
|
1886
|
+
isInsideEscape = true;
|
|
1887
|
+
isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
|
|
1888
|
+
}
|
|
1889
|
+
if (isInsideEscape) {
|
|
1890
|
+
if (isInsideLinkEscape) {
|
|
1891
|
+
if (character === ANSI_ESCAPE_BELL) {
|
|
1892
|
+
isInsideEscape = false;
|
|
1893
|
+
isInsideLinkEscape = false;
|
|
1894
|
+
}
|
|
1895
|
+
} else if (character === ANSI_SGR_TERMINATOR) {
|
|
1896
|
+
isInsideEscape = false;
|
|
1897
|
+
}
|
|
1898
|
+
} else {
|
|
1899
|
+
visible += characterLength;
|
|
1900
|
+
if (visible === columns && !nextCharacter.done) {
|
|
1901
|
+
rows.push("");
|
|
1902
|
+
visible = 0;
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
currentCharacter = nextCharacter;
|
|
1906
|
+
nextCharacter = characters.next();
|
|
1907
|
+
rawCharacterIndex += character.length;
|
|
1376
1908
|
}
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
SELECT 1 FROM information_schema.tables
|
|
1389
|
-
WHERE table_schema = $1 AND table_name = $2
|
|
1390
|
-
) AS exists`, [config2.migrationsSchema, "__bungres_push"]);
|
|
1391
|
-
const pushTableExists = pushTableCheck[0]?.exists ?? false;
|
|
1392
|
-
const tablesToDrop = schemas2.filter((s) => existingTableNames.has(s.config.name));
|
|
1393
|
-
if (tablesToDrop.length === 0 && !migrationTableExists && !pushTableExists) {
|
|
1394
|
-
console.log("No tables to drop (they either don't exist or were already dropped).");
|
|
1395
|
-
return;
|
|
1909
|
+
lastRow = rows.at(-1);
|
|
1910
|
+
if (!visible && lastRow !== undefined && lastRow.length && rows.length > 1) {
|
|
1911
|
+
rows[rows.length - 2] += rows.pop();
|
|
1912
|
+
}
|
|
1913
|
+
};
|
|
1914
|
+
var stringVisibleTrimSpacesRight = (string) => {
|
|
1915
|
+
const words = string.split(" ");
|
|
1916
|
+
let last = words.length;
|
|
1917
|
+
while (last) {
|
|
1918
|
+
if (dist_default2(words[last - 1])) {
|
|
1919
|
+
break;
|
|
1396
1920
|
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1921
|
+
last--;
|
|
1922
|
+
}
|
|
1923
|
+
if (last === words.length) {
|
|
1924
|
+
return string;
|
|
1925
|
+
}
|
|
1926
|
+
return words.slice(0, last).join(" ") + words.slice(last).join("");
|
|
1927
|
+
};
|
|
1928
|
+
var exec = (string, columns, options = {}) => {
|
|
1929
|
+
if (options.trim !== false && string.trim() === "") {
|
|
1930
|
+
return "";
|
|
1931
|
+
}
|
|
1932
|
+
let returnValue = "";
|
|
1933
|
+
let escapeCode;
|
|
1934
|
+
let escapeUrl;
|
|
1935
|
+
const words = string.split(" ");
|
|
1936
|
+
let rows = [""];
|
|
1937
|
+
let rowLength = 0;
|
|
1938
|
+
for (let index = 0;index < words.length; index++) {
|
|
1939
|
+
const word = words[index];
|
|
1940
|
+
if (options.trim !== false) {
|
|
1941
|
+
const row = rows.at(-1) ?? "";
|
|
1942
|
+
const trimmed = row.trimStart();
|
|
1943
|
+
if (row.length !== trimmed.length) {
|
|
1944
|
+
rows[rows.length - 1] = trimmed;
|
|
1945
|
+
rowLength = dist_default2(trimmed);
|
|
1946
|
+
}
|
|
1400
1947
|
}
|
|
1401
|
-
if (
|
|
1402
|
-
|
|
1948
|
+
if (index !== 0) {
|
|
1949
|
+
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
|
1950
|
+
rows.push("");
|
|
1951
|
+
rowLength = 0;
|
|
1952
|
+
}
|
|
1953
|
+
if (rowLength || options.trim === false) {
|
|
1954
|
+
rows[rows.length - 1] += " ";
|
|
1955
|
+
rowLength++;
|
|
1956
|
+
}
|
|
1403
1957
|
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
Are you sure? Type YES to continue: `, "cyan"));
|
|
1412
|
-
for await (const line2 of console) {
|
|
1413
|
-
if (line2.trim().toLowerCase() !== "yes") {
|
|
1414
|
-
console.log("Aborted.");
|
|
1415
|
-
return;
|
|
1416
|
-
}
|
|
1417
|
-
break;
|
|
1958
|
+
const wordLength = dist_default2(word);
|
|
1959
|
+
if (options.hard && wordLength > columns) {
|
|
1960
|
+
const remainingColumns = columns - rowLength;
|
|
1961
|
+
const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
|
|
1962
|
+
const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
|
|
1963
|
+
if (breaksStartingNextLine < breaksStartingThisLine) {
|
|
1964
|
+
rows.push("");
|
|
1418
1965
|
}
|
|
1966
|
+
wrapWord(rows, word, columns);
|
|
1967
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
1968
|
+
continue;
|
|
1419
1969
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1970
|
+
if (rowLength + wordLength > columns && rowLength && wordLength) {
|
|
1971
|
+
if (options.wordWrap === false && rowLength < columns) {
|
|
1972
|
+
wrapWord(rows, word, columns);
|
|
1973
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
1974
|
+
continue;
|
|
1975
|
+
}
|
|
1976
|
+
rows.push("");
|
|
1977
|
+
rowLength = 0;
|
|
1424
1978
|
}
|
|
1425
|
-
if (
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1979
|
+
if (rowLength + wordLength > columns && options.wordWrap === false) {
|
|
1980
|
+
wrapWord(rows, word, columns);
|
|
1981
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
1982
|
+
continue;
|
|
1429
1983
|
}
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1984
|
+
rows[rows.length - 1] += word;
|
|
1985
|
+
rowLength += wordLength;
|
|
1986
|
+
}
|
|
1987
|
+
if (options.trim !== false) {
|
|
1988
|
+
rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
|
|
1989
|
+
}
|
|
1990
|
+
const preString = rows.join(`
|
|
1991
|
+
`);
|
|
1992
|
+
let inSurrogate = false;
|
|
1993
|
+
for (let i = 0;i < preString.length; i++) {
|
|
1994
|
+
const character = preString[i];
|
|
1995
|
+
returnValue += character;
|
|
1996
|
+
if (!inSurrogate) {
|
|
1997
|
+
inSurrogate = character >= "\uD800" && character <= "\uDBFF";
|
|
1998
|
+
if (inSurrogate) {
|
|
1999
|
+
continue;
|
|
2000
|
+
}
|
|
2001
|
+
} else {
|
|
2002
|
+
inSurrogate = false;
|
|
2003
|
+
}
|
|
2004
|
+
if (character === ESC || character === CSI) {
|
|
2005
|
+
GROUP_REGEX.lastIndex = i + 1;
|
|
2006
|
+
const groupsResult = GROUP_REGEX.exec(preString);
|
|
2007
|
+
const groups = groupsResult?.groups;
|
|
2008
|
+
if (groups?.code !== undefined) {
|
|
2009
|
+
const code2 = Number.parseFloat(groups.code);
|
|
2010
|
+
escapeCode = code2 === END_CODE ? undefined : code2;
|
|
2011
|
+
} else if (groups?.uri !== undefined) {
|
|
2012
|
+
escapeUrl = groups.uri.length === 0 ? undefined : groups.uri;
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
if (preString[i + 1] === `
|
|
2016
|
+
`) {
|
|
2017
|
+
if (escapeUrl) {
|
|
2018
|
+
returnValue += wrapAnsiHyperlink("");
|
|
2019
|
+
}
|
|
2020
|
+
const closingCode = escapeCode ? getClosingCode(escapeCode) : undefined;
|
|
2021
|
+
if (escapeCode && closingCode) {
|
|
2022
|
+
returnValue += wrapAnsiCode(closingCode);
|
|
2023
|
+
}
|
|
2024
|
+
} else if (character === `
|
|
2025
|
+
`) {
|
|
2026
|
+
if (escapeCode && getClosingCode(escapeCode)) {
|
|
2027
|
+
returnValue += wrapAnsiCode(escapeCode);
|
|
2028
|
+
}
|
|
2029
|
+
if (escapeUrl) {
|
|
2030
|
+
returnValue += wrapAnsiHyperlink(escapeUrl);
|
|
2031
|
+
}
|
|
1433
2032
|
}
|
|
1434
|
-
console.log(colorize(`
|
|
1435
|
-
Drop complete.`, "green"));
|
|
1436
|
-
} finally {
|
|
1437
|
-
await sql2.end();
|
|
1438
2033
|
}
|
|
2034
|
+
return returnValue;
|
|
2035
|
+
};
|
|
2036
|
+
var CRLF_OR_LF = /\r?\n/;
|
|
2037
|
+
function wrapAnsi(string, columns, options) {
|
|
2038
|
+
return String(string).normalize().split(CRLF_OR_LF).map((line2) => exec(line2, columns, options)).join(`
|
|
2039
|
+
`);
|
|
1439
2040
|
}
|
|
1440
2041
|
|
|
1441
|
-
//
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
const
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
2042
|
+
// ../../node_modules/.bun/@clack+core@1.4.3/node_modules/@clack/core/dist/index.mjs
|
|
2043
|
+
var import_sisteransi = __toESM(require_src(), 1);
|
|
2044
|
+
import { ReadStream } from "tty";
|
|
2045
|
+
function findCursor(s, o, l2) {
|
|
2046
|
+
if (!l2.some((r) => !r.disabled))
|
|
2047
|
+
return s;
|
|
2048
|
+
const t = s + o, n = Math.max(l2.length - 1, 0), e = t < 0 ? n : t > n ? 0 : t;
|
|
2049
|
+
return l2[e]?.disabled ? findCursor(e, o < 0 ? -1 : 1, l2) : e;
|
|
2050
|
+
}
|
|
2051
|
+
function findTextCursor(s, o, l2, i) {
|
|
2052
|
+
const t = i.split(`
|
|
2053
|
+
`);
|
|
2054
|
+
let n = 0, e = s;
|
|
2055
|
+
for (const r of t) {
|
|
2056
|
+
if (e <= r.length)
|
|
2057
|
+
break;
|
|
2058
|
+
e -= r.length + 1, n++;
|
|
2059
|
+
}
|
|
2060
|
+
for (n = Math.max(0, Math.min(t.length - 1, n + l2)), e = Math.min(e, t[n].length) + o;e < 0 && n > 0; )
|
|
2061
|
+
n--, e += t[n].length + 1;
|
|
2062
|
+
for (;e > t[n].length && n < t.length - 1; )
|
|
2063
|
+
e -= t[n].length + 1, n++;
|
|
2064
|
+
e = Math.max(0, Math.min(t[n].length, e));
|
|
2065
|
+
let h = 0;
|
|
2066
|
+
for (let r = 0;r < n; r++)
|
|
2067
|
+
h += t[r].length + 1;
|
|
2068
|
+
return h + e;
|
|
2069
|
+
}
|
|
2070
|
+
var a$1 = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
2071
|
+
var t = [
|
|
2072
|
+
"January",
|
|
2073
|
+
"February",
|
|
2074
|
+
"March",
|
|
2075
|
+
"April",
|
|
2076
|
+
"May",
|
|
2077
|
+
"June",
|
|
2078
|
+
"July",
|
|
2079
|
+
"August",
|
|
2080
|
+
"September",
|
|
2081
|
+
"October",
|
|
2082
|
+
"November",
|
|
2083
|
+
"December"
|
|
2084
|
+
];
|
|
2085
|
+
var settings = {
|
|
2086
|
+
actions: new Set(a$1),
|
|
2087
|
+
aliases: /* @__PURE__ */ new Map([
|
|
2088
|
+
["k", "up"],
|
|
2089
|
+
["j", "down"],
|
|
2090
|
+
["h", "left"],
|
|
2091
|
+
["l", "right"],
|
|
2092
|
+
["\x03", "cancel"],
|
|
2093
|
+
["escape", "cancel"]
|
|
2094
|
+
]),
|
|
2095
|
+
messages: {
|
|
2096
|
+
cancel: "Canceled",
|
|
2097
|
+
error: "Something went wrong"
|
|
2098
|
+
},
|
|
2099
|
+
withGuide: true,
|
|
2100
|
+
date: {
|
|
2101
|
+
monthNames: [...t],
|
|
2102
|
+
messages: {
|
|
2103
|
+
required: "Please enter a valid date",
|
|
2104
|
+
invalidMonth: "There are only 12 months in a year",
|
|
2105
|
+
invalidDay: (n, e) => `There are only ${n} days in ${e}`,
|
|
2106
|
+
afterMin: (n) => `Date must be on or after ${n.toISOString().slice(0, 10)}`,
|
|
2107
|
+
beforeMax: (n) => `Date must be on or before ${n.toISOString().slice(0, 10)}`
|
|
1463
2108
|
}
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
2109
|
+
}
|
|
2110
|
+
};
|
|
2111
|
+
function isActionKey(n, e) {
|
|
2112
|
+
if (typeof n == "string")
|
|
2113
|
+
return settings.aliases.get(n) === e;
|
|
2114
|
+
for (const s of n)
|
|
2115
|
+
if (s !== undefined && isActionKey(s, e))
|
|
2116
|
+
return true;
|
|
2117
|
+
return false;
|
|
2118
|
+
}
|
|
2119
|
+
function diffLines(i, s) {
|
|
2120
|
+
if (i === s)
|
|
2121
|
+
return;
|
|
2122
|
+
const e = i.split(`
|
|
2123
|
+
`), t2 = s.split(`
|
|
2124
|
+
`), r = Math.max(e.length, t2.length), f = [];
|
|
2125
|
+
for (let n = 0;n < r; n++)
|
|
2126
|
+
e[n] !== t2[n] && f.push(n);
|
|
2127
|
+
return {
|
|
2128
|
+
lines: f,
|
|
2129
|
+
numLinesBefore: e.length,
|
|
2130
|
+
numLinesAfter: t2.length,
|
|
2131
|
+
numLines: r
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
var R = globalThis.process.platform.startsWith("win");
|
|
2135
|
+
var CANCEL_SYMBOL = Symbol("clack:cancel");
|
|
2136
|
+
function isCancel(e) {
|
|
2137
|
+
return e === CANCEL_SYMBOL;
|
|
2138
|
+
}
|
|
2139
|
+
function setRawMode(e, r) {
|
|
2140
|
+
const o = e;
|
|
2141
|
+
o.isTTY && o.setRawMode(r);
|
|
2142
|
+
}
|
|
2143
|
+
function block({
|
|
2144
|
+
input: e = stdin,
|
|
2145
|
+
output: r = stdout,
|
|
2146
|
+
overwrite: o = true,
|
|
2147
|
+
hideCursor: t2 = true
|
|
2148
|
+
} = {}) {
|
|
2149
|
+
const s = l.createInterface({
|
|
2150
|
+
input: e,
|
|
2151
|
+
output: r,
|
|
2152
|
+
prompt: "",
|
|
2153
|
+
tabSize: 1
|
|
2154
|
+
});
|
|
2155
|
+
l.emitKeypressEvents(e, s), e instanceof ReadStream && e.isTTY && e.setRawMode(true);
|
|
2156
|
+
const n = (f, { name: a, sequence: p }) => {
|
|
2157
|
+
const c = String(f);
|
|
2158
|
+
if (isActionKey([c, a, p], "cancel")) {
|
|
2159
|
+
t2 && r.write(import_sisteransi.cursor.show), process.exit(0);
|
|
1468
2160
|
return;
|
|
1469
2161
|
}
|
|
1470
|
-
|
|
1471
|
-
const appliedSet = new Set(applied.map((r) => r.name));
|
|
1472
|
-
const pending = files.filter((f) => !appliedSet.has(f));
|
|
1473
|
-
if (pending.length === 0) {
|
|
1474
|
-
console.log(colorize("Everything is up to date.", "green"));
|
|
2162
|
+
if (!o)
|
|
1475
2163
|
return;
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
2164
|
+
const i = a === "return" ? 0 : -1, m = a === "return" ? -1 : 0;
|
|
2165
|
+
l.moveCursor(r, i, m, () => {
|
|
2166
|
+
l.clearLine(r, 1, () => {
|
|
2167
|
+
e.once("keypress", n);
|
|
2168
|
+
});
|
|
2169
|
+
});
|
|
2170
|
+
};
|
|
2171
|
+
return t2 && r.write(import_sisteransi.cursor.hide), e.once("keypress", n), () => {
|
|
2172
|
+
e.off("keypress", n), t2 && r.write(import_sisteransi.cursor.show), e instanceof ReadStream && e.isTTY && !R && e.setRawMode(false), s.terminal = false, s.close();
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
var getColumns = (e) => ("columns" in e) && typeof e.columns == "number" ? e.columns : 80;
|
|
2176
|
+
var getRows = (e) => ("rows" in e) && typeof e.rows == "number" ? e.rows : 20;
|
|
2177
|
+
function wrapTextWithPrefix(e, r, o, t2 = o, s = o, n) {
|
|
2178
|
+
const f = getColumns(e ?? stdout);
|
|
2179
|
+
return wrapAnsi(r, f - o.length, {
|
|
2180
|
+
hard: true,
|
|
2181
|
+
trim: false
|
|
2182
|
+
}).split(`
|
|
2183
|
+
`).map((c, i, m) => {
|
|
2184
|
+
const d = n ? n(c, i) : c;
|
|
2185
|
+
return i === 0 ? `${t2}${d}` : i === m.length - 1 ? `${s}${d}` : `${o}${d}`;
|
|
2186
|
+
}).join(`
|
|
1485
2187
|
`);
|
|
2188
|
+
}
|
|
2189
|
+
function runValidation(e, n) {
|
|
2190
|
+
if ("~standard" in e) {
|
|
2191
|
+
const a = e["~standard"].validate(n);
|
|
2192
|
+
if (a instanceof Promise)
|
|
2193
|
+
throw new TypeError("Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic.");
|
|
2194
|
+
return a.issues?.at(0)?.message;
|
|
2195
|
+
}
|
|
2196
|
+
return e(n);
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
class V {
|
|
2200
|
+
input;
|
|
2201
|
+
output;
|
|
2202
|
+
_abortSignal;
|
|
2203
|
+
rl;
|
|
2204
|
+
opts;
|
|
2205
|
+
_render;
|
|
2206
|
+
_track = false;
|
|
2207
|
+
_prevFrame = "";
|
|
2208
|
+
_subscribers = /* @__PURE__ */ new Map;
|
|
2209
|
+
_cursor = 0;
|
|
2210
|
+
state = "initial";
|
|
2211
|
+
error = "";
|
|
2212
|
+
value;
|
|
2213
|
+
userInput = "";
|
|
2214
|
+
constructor(t2, e = true) {
|
|
2215
|
+
const { input: i = stdin, output: n = stdout, render: s, signal: r, ...o } = t2;
|
|
2216
|
+
this.opts = o, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = s.bind(this), this._track = e, this._abortSignal = r, this.input = i, this.output = n;
|
|
2217
|
+
}
|
|
2218
|
+
unsubscribe() {
|
|
2219
|
+
this._subscribers.clear();
|
|
2220
|
+
}
|
|
2221
|
+
setSubscriber(t2, e) {
|
|
2222
|
+
const i = this._subscribers.get(t2) ?? [];
|
|
2223
|
+
i.push(e), this._subscribers.set(t2, i);
|
|
2224
|
+
}
|
|
2225
|
+
on(t2, e) {
|
|
2226
|
+
this.setSubscriber(t2, { cb: e });
|
|
2227
|
+
}
|
|
2228
|
+
once(t2, e) {
|
|
2229
|
+
this.setSubscriber(t2, { cb: e, once: true });
|
|
2230
|
+
}
|
|
2231
|
+
emit(t2, ...e) {
|
|
2232
|
+
const i = this._subscribers.get(t2) ?? [], n = [];
|
|
2233
|
+
for (const s of i)
|
|
2234
|
+
s.cb(...e), s.once && n.push(() => i.splice(i.indexOf(s), 1));
|
|
2235
|
+
for (const s of n)
|
|
2236
|
+
s();
|
|
2237
|
+
}
|
|
2238
|
+
prompt() {
|
|
2239
|
+
return new Promise((t2) => {
|
|
2240
|
+
if (this._abortSignal) {
|
|
2241
|
+
if (this._abortSignal.aborted)
|
|
2242
|
+
return this.state = "cancel", this.close(), t2(CANCEL_SYMBOL);
|
|
2243
|
+
this._abortSignal.addEventListener("abort", () => {
|
|
2244
|
+
this.state = "cancel", this.close();
|
|
2245
|
+
}, { once: true });
|
|
1486
2246
|
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
2247
|
+
this.rl = l__default.createInterface({
|
|
2248
|
+
input: this.input,
|
|
2249
|
+
tabSize: 2,
|
|
2250
|
+
prompt: "",
|
|
2251
|
+
escapeCodeTimeout: 50,
|
|
2252
|
+
terminal: true
|
|
2253
|
+
}), this.rl.prompt(), this.opts.initialUserInput !== undefined && this._setUserInput(this.opts.initialUserInput, true), this.input.on("keypress", this.onKeypress), setRawMode(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
|
|
2254
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t2(this.value);
|
|
2255
|
+
}), this.once("cancel", () => {
|
|
2256
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t2(CANCEL_SYMBOL);
|
|
1493
2257
|
});
|
|
1494
|
-
|
|
1495
|
-
}
|
|
1496
|
-
console.log(colorize(`
|
|
1497
|
-
Done.`, "green"));
|
|
1498
|
-
} finally {
|
|
1499
|
-
await sql2.end();
|
|
2258
|
+
});
|
|
1500
2259
|
}
|
|
1501
|
-
|
|
2260
|
+
_isActionKey(t2, e) {
|
|
2261
|
+
return t2 === "\t";
|
|
2262
|
+
}
|
|
2263
|
+
_shouldSubmit(t2, e) {
|
|
2264
|
+
return true;
|
|
2265
|
+
}
|
|
2266
|
+
_setValue(t2) {
|
|
2267
|
+
this.value = t2, this.emit("value", this.value);
|
|
2268
|
+
}
|
|
2269
|
+
_setUserInput(t2, e) {
|
|
2270
|
+
this.userInput = t2 ?? "", this.emit("userInput", this.userInput), e && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
|
|
2271
|
+
}
|
|
2272
|
+
_clearUserInput() {
|
|
2273
|
+
this.rl?.write(null, { ctrl: true, name: "u" }), this._setUserInput("");
|
|
2274
|
+
}
|
|
2275
|
+
onKeypress(t2, e) {
|
|
2276
|
+
if (this._track && e.name !== "return" && (e.name && this._isActionKey(t2, e) && this.rl?.write(null, { ctrl: true, name: "h" }), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), e?.name && (!this._track && settings.aliases.has(e.name) && this.emit("cursor", settings.aliases.get(e.name)), settings.actions.has(e.name) && this.emit("cursor", e.name)), t2 && (t2.toLowerCase() === "y" || t2.toLowerCase() === "n") && this.emit("confirm", t2.toLowerCase() === "y"), this.emit("key", t2, e), e?.name === "return" && this._shouldSubmit(t2, e)) {
|
|
2277
|
+
if (this.opts.validate) {
|
|
2278
|
+
const i = runValidation(this.opts.validate, this.value);
|
|
2279
|
+
i && (this.error = i instanceof Error ? i.message : i, this.state = "error", this.rl?.write(this.userInput));
|
|
2280
|
+
}
|
|
2281
|
+
this.state !== "error" && (this.state = "submit");
|
|
2282
|
+
}
|
|
2283
|
+
isActionKey([t2, e?.name, e?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
|
|
2284
|
+
}
|
|
2285
|
+
close() {
|
|
2286
|
+
this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
|
|
2287
|
+
`), setRawMode(this.input, false), this.rl?.close(), this.rl = undefined, this.emit(`${this.state}`, this.value), this.unsubscribe();
|
|
2288
|
+
}
|
|
2289
|
+
restoreCursor() {
|
|
2290
|
+
const t2 = wrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split(`
|
|
2291
|
+
`).length - 1;
|
|
2292
|
+
this.output.write(import_sisteransi.cursor.move(-999, t2 * -1));
|
|
2293
|
+
}
|
|
2294
|
+
render() {
|
|
2295
|
+
const t2 = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
|
|
2296
|
+
hard: true,
|
|
2297
|
+
trim: false
|
|
2298
|
+
});
|
|
2299
|
+
if (t2 !== this._prevFrame) {
|
|
2300
|
+
if (this.state === "initial")
|
|
2301
|
+
this.output.write(import_sisteransi.cursor.hide);
|
|
2302
|
+
else {
|
|
2303
|
+
const e = diffLines(this._prevFrame, t2), i = getRows(this.output);
|
|
2304
|
+
if (this.restoreCursor(), e) {
|
|
2305
|
+
const n = Math.max(0, e.numLinesAfter - i), s = Math.max(0, e.numLinesBefore - i);
|
|
2306
|
+
let r = e.lines.find((o) => o >= n);
|
|
2307
|
+
if (r === undefined) {
|
|
2308
|
+
this._prevFrame = t2;
|
|
2309
|
+
return;
|
|
2310
|
+
}
|
|
2311
|
+
if (e.lines.length === 1) {
|
|
2312
|
+
this.output.write(import_sisteransi.cursor.move(0, r - s)), this.output.write(import_sisteransi.erase.lines(1));
|
|
2313
|
+
const o = t2.split(`
|
|
2314
|
+
`);
|
|
2315
|
+
this.output.write(o[r]), this._prevFrame = t2, this.output.write(import_sisteransi.cursor.move(0, o.length - r - 1));
|
|
2316
|
+
return;
|
|
2317
|
+
} else if (e.lines.length > 1) {
|
|
2318
|
+
if (n < s)
|
|
2319
|
+
r = n;
|
|
2320
|
+
else {
|
|
2321
|
+
const h = r - s;
|
|
2322
|
+
h > 0 && this.output.write(import_sisteransi.cursor.move(0, h));
|
|
2323
|
+
}
|
|
2324
|
+
this.output.write(import_sisteransi.erase.down());
|
|
2325
|
+
const f = t2.split(`
|
|
2326
|
+
`).slice(r);
|
|
2327
|
+
this.output.write(f.join(`
|
|
2328
|
+
`)), this._prevFrame = t2;
|
|
2329
|
+
return;
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
this.output.write(import_sisteransi.erase.down());
|
|
2333
|
+
}
|
|
2334
|
+
this.output.write(t2), this.state === "initial" && (this.state = "active"), this._prevFrame = t2;
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
function p$1(l2, e) {
|
|
2339
|
+
if (l2 === undefined || e.length === 0)
|
|
2340
|
+
return 0;
|
|
2341
|
+
const i = e.findIndex((s) => s.value === l2);
|
|
2342
|
+
return i !== -1 ? i : 0;
|
|
2343
|
+
}
|
|
2344
|
+
function g(l2, e) {
|
|
2345
|
+
return (e.label ?? String(e.value)).toLowerCase().includes(l2.toLowerCase());
|
|
2346
|
+
}
|
|
2347
|
+
function m(l2, e) {
|
|
2348
|
+
if (e)
|
|
2349
|
+
return l2 ? e : e[0];
|
|
2350
|
+
}
|
|
2351
|
+
var T$1 = class T extends V {
|
|
2352
|
+
filteredOptions;
|
|
2353
|
+
multiple;
|
|
2354
|
+
isNavigating = false;
|
|
2355
|
+
selectedValues = [];
|
|
2356
|
+
focusedValue;
|
|
2357
|
+
#e = 0;
|
|
2358
|
+
#s = "";
|
|
2359
|
+
#t;
|
|
2360
|
+
#i;
|
|
2361
|
+
#n;
|
|
2362
|
+
get cursor() {
|
|
2363
|
+
return this.#e;
|
|
2364
|
+
}
|
|
2365
|
+
get userInputWithCursor() {
|
|
2366
|
+
if (!this.userInput)
|
|
2367
|
+
return styleText(["inverse", "hidden"], "_");
|
|
2368
|
+
if (this._cursor >= this.userInput.length)
|
|
2369
|
+
return `${this.userInput}\u2588`;
|
|
2370
|
+
const e = this.userInput.slice(0, this.cursor), t2 = this.userInput.slice(this.cursor, this.cursor + 1), i = this.userInput.slice(this.cursor + 1);
|
|
2371
|
+
return `${e}${styleText("inverse", t2)}${i}`;
|
|
2372
|
+
}
|
|
2373
|
+
get options() {
|
|
2374
|
+
return typeof this.#i == "function" ? this.#i() : this.#i;
|
|
2375
|
+
}
|
|
2376
|
+
constructor(e) {
|
|
2377
|
+
super(e), this.#i = e.options, this.#n = e.placeholder;
|
|
2378
|
+
const t2 = this.options;
|
|
2379
|
+
this.filteredOptions = [...t2], this.multiple = e.multiple === true, this.#t = typeof e.options == "function" ? e.filter : e.filter ?? g;
|
|
2380
|
+
let i;
|
|
2381
|
+
if (e.initialValue && Array.isArray(e.initialValue) ? this.multiple ? i = e.initialValue : i = e.initialValue.slice(0, 1) : !this.multiple && this.options.length > 0 && (i = [this.options[0]?.value]), i)
|
|
2382
|
+
for (const s of i) {
|
|
2383
|
+
const n = t2.findIndex((o) => o.value === s);
|
|
2384
|
+
n !== -1 && (this.toggleSelected(s), this.#e = n);
|
|
2385
|
+
}
|
|
2386
|
+
this.focusedValue = this.options[this.#e]?.value, this.on("key", (s, n) => this.#l(s, n)), this.on("userInput", (s) => this.#u(s));
|
|
2387
|
+
}
|
|
2388
|
+
_isActionKey(e, t2) {
|
|
2389
|
+
return e === "\t" || this.multiple && this.isNavigating && t2.name === "space" && e !== undefined && e !== "";
|
|
2390
|
+
}
|
|
2391
|
+
#l(e, t2) {
|
|
2392
|
+
const i = t2.name === "up", s = t2.name === "down", n = t2.name === "return", o = this.userInput === "" || this.userInput === "\t", u = this.#n, a = this.options, f = u !== undefined && u !== "" && a.some((r) => !r.disabled && (this.#t ? this.#t(u, r) : true));
|
|
2393
|
+
if (t2.name === "tab" && o && f) {
|
|
2394
|
+
this.userInput === "\t" && this._clearUserInput(), this._setUserInput(u, true), this.isNavigating = false;
|
|
2395
|
+
return;
|
|
2396
|
+
}
|
|
2397
|
+
i || s ? (this.#e = findCursor(this.#e, i ? -1 : 1, this.filteredOptions), this.focusedValue = this.filteredOptions[this.#e]?.value, this.multiple || (this.selectedValues = [this.focusedValue]), this.isNavigating = true) : n ? this.value = m(this.multiple, this.selectedValues) : this.multiple ? this.focusedValue !== undefined && (t2.name === "tab" || this.isNavigating && t2.name === "space") ? this.toggleSelected(this.focusedValue) : this.isNavigating = false : (this.focusedValue && (this.selectedValues = [this.focusedValue]), this.isNavigating = false);
|
|
2398
|
+
}
|
|
2399
|
+
deselectAll() {
|
|
2400
|
+
this.selectedValues = [];
|
|
2401
|
+
}
|
|
2402
|
+
toggleSelected(e) {
|
|
2403
|
+
this.filteredOptions.length !== 0 && (this.multiple ? this.selectedValues.includes(e) ? this.selectedValues = this.selectedValues.filter((t2) => t2 !== e) : this.selectedValues = [...this.selectedValues, e] : this.selectedValues = [e]);
|
|
2404
|
+
}
|
|
2405
|
+
#u(e) {
|
|
2406
|
+
if (e !== this.#s) {
|
|
2407
|
+
this.#s = e;
|
|
2408
|
+
const t2 = this.options;
|
|
2409
|
+
e && this.#t ? this.filteredOptions = t2.filter((n) => this.#t?.(e, n)) : this.filteredOptions = [...t2];
|
|
2410
|
+
const i = p$1(this.focusedValue, this.filteredOptions);
|
|
2411
|
+
this.#e = findCursor(i, 0, this.filteredOptions);
|
|
2412
|
+
const s = this.filteredOptions[this.#e];
|
|
2413
|
+
s && !s.disabled ? this.focusedValue = s.value : this.focusedValue = undefined, this.multiple || (this.focusedValue !== undefined ? this.toggleSelected(this.focusedValue) : this.deselectAll());
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2417
|
+
|
|
2418
|
+
class r extends V {
|
|
2419
|
+
get cursor() {
|
|
2420
|
+
return this.value ? 0 : 1;
|
|
2421
|
+
}
|
|
2422
|
+
get _value() {
|
|
2423
|
+
return this.cursor === 0;
|
|
2424
|
+
}
|
|
2425
|
+
constructor(t2) {
|
|
2426
|
+
super(t2, false), this.value = !!t2.initialValue, this.on("userInput", () => {
|
|
2427
|
+
this.value = this._value;
|
|
2428
|
+
}), this.on("confirm", (i) => {
|
|
2429
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = i, this.state = "submit", this.close();
|
|
2430
|
+
}), this.on("cursor", () => {
|
|
2431
|
+
this.value = !this.value;
|
|
2432
|
+
});
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
var _ = {
|
|
2436
|
+
Y: { type: "year", len: 4 },
|
|
2437
|
+
M: { type: "month", len: 2 },
|
|
2438
|
+
D: { type: "day", len: 2 }
|
|
2439
|
+
};
|
|
2440
|
+
function M(r2) {
|
|
2441
|
+
return [...r2].map((t2) => _[t2]);
|
|
2442
|
+
}
|
|
2443
|
+
function P(r2) {
|
|
2444
|
+
const i = new Intl.DateTimeFormat(r2, {
|
|
2445
|
+
year: "numeric",
|
|
2446
|
+
month: "2-digit",
|
|
2447
|
+
day: "2-digit"
|
|
2448
|
+
}).formatToParts(new Date(2000, 0, 15)), s = [];
|
|
2449
|
+
let n = "/";
|
|
2450
|
+
for (const e of i)
|
|
2451
|
+
e.type === "literal" ? n = e.value.trim() || e.value : (e.type === "year" || e.type === "month" || e.type === "day") && s.push({ type: e.type, len: e.type === "year" ? 4 : 2 });
|
|
2452
|
+
return { segments: s, separator: n };
|
|
2453
|
+
}
|
|
2454
|
+
function p(r2) {
|
|
2455
|
+
return Number.parseInt((r2 || "0").replace(/_/g, "0"), 10) || 0;
|
|
2456
|
+
}
|
|
2457
|
+
function f(r2) {
|
|
2458
|
+
return {
|
|
2459
|
+
year: p(r2.year),
|
|
2460
|
+
month: p(r2.month),
|
|
2461
|
+
day: p(r2.day)
|
|
2462
|
+
};
|
|
2463
|
+
}
|
|
2464
|
+
function c(r2, t2) {
|
|
2465
|
+
return new Date(r2 || 2001, t2 || 1, 0).getDate();
|
|
2466
|
+
}
|
|
2467
|
+
function b(r2) {
|
|
2468
|
+
const { year: t2, month: i, day: s } = f(r2);
|
|
2469
|
+
if (!t2 || t2 < 0 || t2 > 9999 || !i || i < 1 || i > 12 || !s || s < 1)
|
|
2470
|
+
return;
|
|
2471
|
+
const n = new Date(Date.UTC(t2, i - 1, s));
|
|
2472
|
+
if (!(n.getUTCFullYear() !== t2 || n.getUTCMonth() !== i - 1 || n.getUTCDate() !== s))
|
|
2473
|
+
return { year: t2, month: i, day: s };
|
|
2474
|
+
}
|
|
2475
|
+
function C(r2) {
|
|
2476
|
+
const t2 = b(r2);
|
|
2477
|
+
return t2 ? new Date(Date.UTC(t2.year, t2.month - 1, t2.day)) : undefined;
|
|
2478
|
+
}
|
|
2479
|
+
function T2(r2, t2, i, s) {
|
|
2480
|
+
const n = i ? {
|
|
2481
|
+
year: i.getUTCFullYear(),
|
|
2482
|
+
month: i.getUTCMonth() + 1,
|
|
2483
|
+
day: i.getUTCDate()
|
|
2484
|
+
} : null, e = s ? {
|
|
2485
|
+
year: s.getUTCFullYear(),
|
|
2486
|
+
month: s.getUTCMonth() + 1,
|
|
2487
|
+
day: s.getUTCDate()
|
|
2488
|
+
} : null;
|
|
2489
|
+
return r2 === "year" ? { min: n?.year ?? 1, max: e?.year ?? 9999 } : r2 === "month" ? {
|
|
2490
|
+
min: n && t2.year === n.year ? n.month : 1,
|
|
2491
|
+
max: e && t2.year === e.year ? e.month : 12
|
|
2492
|
+
} : {
|
|
2493
|
+
min: n && t2.year === n.year && t2.month === n.month ? n.day : 1,
|
|
2494
|
+
max: e && t2.year === e.year && t2.month === e.month ? e.day : c(t2.year, t2.month)
|
|
2495
|
+
};
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
class U extends V {
|
|
2499
|
+
#i;
|
|
2500
|
+
#o;
|
|
2501
|
+
#t;
|
|
2502
|
+
#h;
|
|
2503
|
+
#u;
|
|
2504
|
+
#e = { segmentIndex: 0, positionInSegment: 0 };
|
|
2505
|
+
#n = true;
|
|
2506
|
+
#s = null;
|
|
2507
|
+
inlineError = "";
|
|
2508
|
+
get segmentCursor() {
|
|
2509
|
+
return { ...this.#e };
|
|
2510
|
+
}
|
|
2511
|
+
get segmentValues() {
|
|
2512
|
+
return { ...this.#t };
|
|
2513
|
+
}
|
|
2514
|
+
get segments() {
|
|
2515
|
+
return this.#i;
|
|
2516
|
+
}
|
|
2517
|
+
get separator() {
|
|
2518
|
+
return this.#o;
|
|
2519
|
+
}
|
|
2520
|
+
get formattedValue() {
|
|
2521
|
+
return this.#l(this.#t);
|
|
2522
|
+
}
|
|
2523
|
+
#l(t2) {
|
|
2524
|
+
return this.#i.map((i) => t2[i.type]).join(this.#o);
|
|
2525
|
+
}
|
|
2526
|
+
#r() {
|
|
2527
|
+
this._setUserInput(this.#l(this.#t)), this._setValue(C(this.#t) ?? undefined);
|
|
2528
|
+
}
|
|
2529
|
+
constructor(t2) {
|
|
2530
|
+
const i = t2.format ? { segments: M(t2.format), separator: t2.separator ?? "/" } : P(t2.locale), s = t2.separator ?? i.separator, n = t2.format ? M(t2.format) : i.segments, e = t2.initialValue ?? t2.defaultValue, m2 = e ? {
|
|
2531
|
+
year: String(e.getUTCFullYear()).padStart(4, "0"),
|
|
2532
|
+
month: String(e.getUTCMonth() + 1).padStart(2, "0"),
|
|
2533
|
+
day: String(e.getUTCDate()).padStart(2, "0")
|
|
2534
|
+
} : { year: "____", month: "__", day: "__" }, o = n.map((a) => m2[a.type]).join(s);
|
|
2535
|
+
super({ ...t2, initialUserInput: o }, false), this.#i = n, this.#o = s, this.#t = m2, this.#h = t2.minDate, this.#u = t2.maxDate, this.#r(), this.on("cursor", (a) => this.#f(a)), this.on("key", (a, u) => this.#y(a, u)), this.on("finalize", () => this.#p(t2));
|
|
2536
|
+
}
|
|
2537
|
+
#a() {
|
|
2538
|
+
const t2 = Math.max(0, Math.min(this.#e.segmentIndex, this.#i.length - 1)), i = this.#i[t2];
|
|
2539
|
+
if (i)
|
|
2540
|
+
return this.#e.positionInSegment = Math.max(0, Math.min(this.#e.positionInSegment, i.len - 1)), { segment: i, index: t2 };
|
|
2541
|
+
}
|
|
2542
|
+
#m(t2) {
|
|
2543
|
+
this.inlineError = "", this.#s = null;
|
|
2544
|
+
const i = this.#a();
|
|
2545
|
+
i && (this.#e.segmentIndex = Math.max(0, Math.min(this.#i.length - 1, i.index + t2)), this.#e.positionInSegment = 0, this.#n = true);
|
|
2546
|
+
}
|
|
2547
|
+
#d(t2) {
|
|
2548
|
+
const i = this.#a();
|
|
2549
|
+
if (!i)
|
|
2550
|
+
return;
|
|
2551
|
+
const { segment: s } = i, n = this.#t[s.type], e = !n || n.replace(/_/g, "") === "", m2 = Number.parseInt((n || "0").replace(/_/g, "0"), 10) || 0, o = T2(s.type, f(this.#t), this.#h, this.#u);
|
|
2552
|
+
let a;
|
|
2553
|
+
e ? a = t2 === 1 ? o.min : o.max : a = Math.max(Math.min(o.max, m2 + t2), o.min), this.#t = {
|
|
2554
|
+
...this.#t,
|
|
2555
|
+
[s.type]: a.toString().padStart(s.len, "0")
|
|
2556
|
+
}, this.#n = true, this.#s = null, this.#r();
|
|
2557
|
+
}
|
|
2558
|
+
#f(t2) {
|
|
2559
|
+
if (t2)
|
|
2560
|
+
switch (t2) {
|
|
2561
|
+
case "right":
|
|
2562
|
+
return this.#m(1);
|
|
2563
|
+
case "left":
|
|
2564
|
+
return this.#m(-1);
|
|
2565
|
+
case "up":
|
|
2566
|
+
return this.#d(1);
|
|
2567
|
+
case "down":
|
|
2568
|
+
return this.#d(-1);
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
#y(t2, i) {
|
|
2572
|
+
if (i?.name === "backspace" || i?.sequence === "\x7F" || i?.sequence === "\b" || t2 === "\x7F" || t2 === "\b") {
|
|
2573
|
+
this.inlineError = "";
|
|
2574
|
+
const n = this.#a();
|
|
2575
|
+
if (!n)
|
|
2576
|
+
return;
|
|
2577
|
+
if (!this.#t[n.segment.type].replace(/_/g, "")) {
|
|
2578
|
+
this.#m(-1);
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
this.#t[n.segment.type] = "_".repeat(n.segment.len), this.#n = true, this.#e.positionInSegment = 0, this.#r();
|
|
2582
|
+
return;
|
|
2583
|
+
}
|
|
2584
|
+
if (i?.name === "tab") {
|
|
2585
|
+
this.inlineError = "";
|
|
2586
|
+
const n = this.#a();
|
|
2587
|
+
if (!n)
|
|
2588
|
+
return;
|
|
2589
|
+
const e = i.shift ? -1 : 1, m2 = n.index + e;
|
|
2590
|
+
m2 >= 0 && m2 < this.#i.length && (this.#e.segmentIndex = m2, this.#e.positionInSegment = 0, this.#n = true);
|
|
2591
|
+
return;
|
|
2592
|
+
}
|
|
2593
|
+
if (t2 && /^[0-9]$/.test(t2)) {
|
|
2594
|
+
const n = this.#a();
|
|
2595
|
+
if (!n)
|
|
2596
|
+
return;
|
|
2597
|
+
const { segment: e } = n, m2 = !this.#t[e.type].replace(/_/g, "");
|
|
2598
|
+
if (this.#n && this.#s !== null && !m2) {
|
|
2599
|
+
const h = this.#s + t2, d = { ...this.#t, [e.type]: h }, g2 = this.#g(d, e);
|
|
2600
|
+
if (g2) {
|
|
2601
|
+
this.inlineError = g2, this.#s = null, this.#n = false;
|
|
2602
|
+
return;
|
|
2603
|
+
}
|
|
2604
|
+
this.inlineError = "", this.#t[e.type] = h, this.#s = null, this.#n = false, this.#r(), n.index < this.#i.length - 1 && (this.#e.segmentIndex = n.index + 1, this.#e.positionInSegment = 0, this.#n = true);
|
|
2605
|
+
return;
|
|
2606
|
+
}
|
|
2607
|
+
this.#n && !m2 && (this.#t[e.type] = "_".repeat(e.len), this.#e.positionInSegment = 0), this.#n = false, this.#s = null;
|
|
2608
|
+
const o = this.#t[e.type], a = o.indexOf("_"), u = a >= 0 ? a : Math.min(this.#e.positionInSegment, e.len - 1);
|
|
2609
|
+
if (u < 0 || u >= e.len)
|
|
2610
|
+
return;
|
|
2611
|
+
let l2 = o.slice(0, u) + t2 + o.slice(u + 1), D = false;
|
|
2612
|
+
if (u === 0 && o === "__" && (e.type === "month" || e.type === "day")) {
|
|
2613
|
+
const h = Number.parseInt(t2, 10);
|
|
2614
|
+
l2 = `0${t2}`, D = h <= (e.type === "month" ? 1 : 2);
|
|
2615
|
+
}
|
|
2616
|
+
if (e.type === "year" && (l2 = (o.replace(/_/g, "") + t2).padStart(e.len, "_")), !l2.includes("_")) {
|
|
2617
|
+
const h = { ...this.#t, [e.type]: l2 }, d = this.#g(h, e);
|
|
2618
|
+
if (d) {
|
|
2619
|
+
this.inlineError = d;
|
|
2620
|
+
return;
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
this.inlineError = "", this.#t[e.type] = l2;
|
|
2624
|
+
const y = l2.includes("_") ? undefined : b(this.#t);
|
|
2625
|
+
if (y) {
|
|
2626
|
+
const { year: h, month: d } = y, g2 = c(h, d);
|
|
2627
|
+
this.#t = {
|
|
2628
|
+
year: String(Math.max(0, Math.min(9999, h))).padStart(4, "0"),
|
|
2629
|
+
month: String(Math.max(1, Math.min(12, d))).padStart(2, "0"),
|
|
2630
|
+
day: String(Math.max(1, Math.min(g2, y.day))).padStart(2, "0")
|
|
2631
|
+
};
|
|
2632
|
+
}
|
|
2633
|
+
this.#r();
|
|
2634
|
+
const S = l2.indexOf("_");
|
|
2635
|
+
D ? (this.#n = true, this.#s = t2) : S >= 0 ? this.#e.positionInSegment = S : a >= 0 && n.index < this.#i.length - 1 ? (this.#e.segmentIndex = n.index + 1, this.#e.positionInSegment = 0, this.#n = true) : this.#e.positionInSegment = Math.min(u + 1, e.len - 1);
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
#g(t2, i) {
|
|
2639
|
+
const { month: s, day: n } = f(t2);
|
|
2640
|
+
if (i.type === "month" && (s < 0 || s > 12))
|
|
2641
|
+
return settings.date.messages.invalidMonth;
|
|
2642
|
+
if (i.type === "day" && (n < 0 || n > 31))
|
|
2643
|
+
return settings.date.messages.invalidDay(31, "any month");
|
|
2644
|
+
}
|
|
2645
|
+
#p(t2) {
|
|
2646
|
+
const { year: i, month: s, day: n } = f(this.#t);
|
|
2647
|
+
if (i && s && n) {
|
|
2648
|
+
const e = c(i, s);
|
|
2649
|
+
this.#t = {
|
|
2650
|
+
...this.#t,
|
|
2651
|
+
day: String(Math.min(n, e)).padStart(2, "0")
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
this.value = C(this.#t) ?? t2.defaultValue ?? undefined;
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
var u$2 = class u extends V {
|
|
2658
|
+
options;
|
|
2659
|
+
cursor = 0;
|
|
2660
|
+
#t;
|
|
2661
|
+
getGroupItems(t2) {
|
|
2662
|
+
return this.options.filter((r2) => r2.group === t2);
|
|
2663
|
+
}
|
|
2664
|
+
isGroupSelected(t2) {
|
|
2665
|
+
const r2 = this.getGroupItems(t2), e = this.value;
|
|
2666
|
+
return e === undefined ? false : r2.every((s) => e.includes(s.value));
|
|
2667
|
+
}
|
|
2668
|
+
toggleValue() {
|
|
2669
|
+
const t2 = this.options[this.cursor];
|
|
2670
|
+
if (t2 !== undefined)
|
|
2671
|
+
if (this.value === undefined && (this.value = []), t2.group === true) {
|
|
2672
|
+
const r2 = t2.value, e = this.getGroupItems(r2);
|
|
2673
|
+
this.isGroupSelected(r2) ? this.value = this.value.filter((s) => e.findIndex((i) => i.value === s) === -1) : this.value = [...this.value, ...e.map((s) => s.value)], this.value = Array.from(new Set(this.value));
|
|
2674
|
+
} else {
|
|
2675
|
+
const r2 = this.value.includes(t2.value);
|
|
2676
|
+
this.value = r2 ? this.value.filter((e) => e !== t2.value) : [...this.value, t2.value];
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
constructor(t2) {
|
|
2680
|
+
super(t2, false);
|
|
2681
|
+
const { options: r2 } = t2;
|
|
2682
|
+
this.#t = t2.selectableGroups !== false, this.options = Object.entries(r2).flatMap(([e, s]) => [
|
|
2683
|
+
{ value: e, group: true, label: e },
|
|
2684
|
+
...s.map((i) => ({ ...i, group: e }))
|
|
2685
|
+
]), this.value = [...t2.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: e }) => e === t2.cursorAt), this.#t ? 0 : 1), this.on("cursor", (e) => {
|
|
2686
|
+
switch (e) {
|
|
2687
|
+
case "left":
|
|
2688
|
+
case "up": {
|
|
2689
|
+
this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
|
|
2690
|
+
const s = this.options[this.cursor]?.group === true;
|
|
2691
|
+
!this.#t && s && (this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1);
|
|
2692
|
+
break;
|
|
2693
|
+
}
|
|
2694
|
+
case "down":
|
|
2695
|
+
case "right": {
|
|
2696
|
+
this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
|
|
2697
|
+
const s = this.options[this.cursor]?.group === true;
|
|
2698
|
+
!this.#t && s && (this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1);
|
|
2699
|
+
break;
|
|
2700
|
+
}
|
|
2701
|
+
case "space":
|
|
2702
|
+
this.toggleValue();
|
|
2703
|
+
break;
|
|
2704
|
+
}
|
|
2705
|
+
});
|
|
2706
|
+
}
|
|
2707
|
+
};
|
|
2708
|
+
var o = /* @__PURE__ */ new Set(["up", "down", "left", "right"]);
|
|
2709
|
+
|
|
2710
|
+
class h extends V {
|
|
2711
|
+
#t = false;
|
|
2712
|
+
#s;
|
|
2713
|
+
focused = "editor";
|
|
2714
|
+
get userInputWithCursor() {
|
|
2715
|
+
if (this.state === "submit")
|
|
2716
|
+
return this.userInput;
|
|
2717
|
+
const t2 = this.userInput;
|
|
2718
|
+
if (this.cursor >= t2.length)
|
|
2719
|
+
return `${t2}\u2588`;
|
|
2720
|
+
const s = t2.slice(0, this.cursor), r2 = t2.slice(this.cursor, this.cursor + 1), i = t2.slice(this.cursor + 1);
|
|
2721
|
+
return r2 === `
|
|
2722
|
+
` ? `${s}\u2588
|
|
2723
|
+
${i}` : `${s}${styleText("inverse", r2)}${i}`;
|
|
2724
|
+
}
|
|
2725
|
+
get cursor() {
|
|
2726
|
+
return this._cursor;
|
|
2727
|
+
}
|
|
2728
|
+
#r(t2) {
|
|
2729
|
+
if (this.userInput.length === 0) {
|
|
2730
|
+
this._setUserInput(t2);
|
|
2731
|
+
return;
|
|
2732
|
+
}
|
|
2733
|
+
this._setUserInput(this.userInput.slice(0, this.cursor) + t2 + this.userInput.slice(this.cursor));
|
|
2734
|
+
}
|
|
2735
|
+
#i(t2) {
|
|
2736
|
+
const s = this.value ?? "";
|
|
2737
|
+
switch (t2) {
|
|
2738
|
+
case "up":
|
|
2739
|
+
this._cursor = findTextCursor(this._cursor, 0, -1, s);
|
|
2740
|
+
return;
|
|
2741
|
+
case "down":
|
|
2742
|
+
this._cursor = findTextCursor(this._cursor, 0, 1, s);
|
|
2743
|
+
return;
|
|
2744
|
+
case "left":
|
|
2745
|
+
this._cursor = findTextCursor(this._cursor, -1, 0, s);
|
|
2746
|
+
return;
|
|
2747
|
+
case "right":
|
|
2748
|
+
this._cursor = findTextCursor(this._cursor, 1, 0, s);
|
|
2749
|
+
return;
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
_shouldSubmit(t2, s) {
|
|
2753
|
+
if (this.#s)
|
|
2754
|
+
return this.focused === "submit" ? true : (this.#r(`
|
|
2755
|
+
`), this._cursor++, false);
|
|
2756
|
+
const r2 = this.#t;
|
|
2757
|
+
return this.#t = true, r2 && this.cursor === this.userInput.length ? (this.userInput[this.cursor - 1] === `
|
|
2758
|
+
` && (this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--), true) : (this.#r(`
|
|
2759
|
+
`), this._cursor++, false);
|
|
2760
|
+
}
|
|
2761
|
+
constructor(t2) {
|
|
2762
|
+
const s = t2.initialUserInput ?? t2.initialValue;
|
|
2763
|
+
super({
|
|
2764
|
+
...t2,
|
|
2765
|
+
initialUserInput: s
|
|
2766
|
+
}, false), s !== undefined && (this._cursor = s.length), this.#s = t2.showSubmit ?? false, this.on("key", (r2, i) => {
|
|
2767
|
+
if (i?.name && o.has(i.name)) {
|
|
2768
|
+
this.#t = false, this.#i(i.name);
|
|
2769
|
+
return;
|
|
2770
|
+
}
|
|
2771
|
+
if (r2 === "\t" && this.#s) {
|
|
2772
|
+
this.focused = this.focused === "editor" ? "submit" : "editor";
|
|
2773
|
+
return;
|
|
2774
|
+
}
|
|
2775
|
+
if (i?.name !== "return") {
|
|
2776
|
+
if (this.#t = false, i?.name === "backspace" && this.cursor > 0) {
|
|
2777
|
+
this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--;
|
|
2778
|
+
return;
|
|
2779
|
+
}
|
|
2780
|
+
if (i?.name === "delete" && this.cursor < this.userInput.length) {
|
|
2781
|
+
this._setUserInput(this.userInput.slice(0, this.cursor) + this.userInput.slice(this.cursor + 1));
|
|
2782
|
+
return;
|
|
2783
|
+
}
|
|
2784
|
+
r2 && (this.#s && this.focused === "submit" && (this.focused = "editor"), this.#r(r2 ?? ""), this._cursor++);
|
|
2785
|
+
}
|
|
2786
|
+
}), this.on("userInput", (r2) => {
|
|
2787
|
+
this._setValue(r2);
|
|
2788
|
+
}), this.on("finalize", () => {
|
|
2789
|
+
this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
|
|
2790
|
+
});
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2794
|
+
// ../../node_modules/.bun/@clack+prompts@1.7.0/node_modules/@clack/prompts/dist/index.mjs
|
|
2795
|
+
import { styleText as styleText2, stripVTControlCharacters } from "util";
|
|
2796
|
+
import process$1 from "process";
|
|
2797
|
+
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
2798
|
+
function isUnicodeSupported() {
|
|
2799
|
+
if (process$1.platform !== "win32") {
|
|
2800
|
+
return process$1.env.TERM !== "linux";
|
|
2801
|
+
}
|
|
2802
|
+
return Boolean(process$1.env.CI) || Boolean(process$1.env.WT_SESSION) || Boolean(process$1.env.TERMINUS_SUBLIME) || process$1.env.ConEmuTask === "{cmd::Cmder}" || process$1.env.TERM_PROGRAM === "Terminus-Sublime" || process$1.env.TERM_PROGRAM === "vscode" || process$1.env.TERM === "xterm-256color" || process$1.env.TERM === "alacritty" || process$1.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
2803
|
+
}
|
|
2804
|
+
var unicode = isUnicodeSupported();
|
|
2805
|
+
var isCI = () => process.env.CI === "true";
|
|
2806
|
+
var unicodeOr = (o2, e) => unicode ? o2 : e;
|
|
2807
|
+
var S_STEP_ACTIVE = unicodeOr("\u25C6", "*");
|
|
2808
|
+
var S_STEP_CANCEL = unicodeOr("\u25A0", "x");
|
|
2809
|
+
var S_STEP_ERROR = unicodeOr("\u25B2", "x");
|
|
2810
|
+
var S_STEP_SUBMIT = unicodeOr("\u25C7", "o");
|
|
2811
|
+
var S_BAR_START = unicodeOr("\u250C", "T");
|
|
2812
|
+
var S_BAR = unicodeOr("\u2502", "|");
|
|
2813
|
+
var S_BAR_END = unicodeOr("\u2514", "\u2014");
|
|
2814
|
+
var S_BAR_START_RIGHT = unicodeOr("\u2510", "T");
|
|
2815
|
+
var S_BAR_END_RIGHT = unicodeOr("\u2518", "\u2014");
|
|
2816
|
+
var S_RADIO_ACTIVE = unicodeOr("\u25CF", ">");
|
|
2817
|
+
var S_RADIO_INACTIVE = unicodeOr("\u25CB", " ");
|
|
2818
|
+
var S_CHECKBOX_ACTIVE = unicodeOr("\u25FB", "[\u2022]");
|
|
2819
|
+
var S_CHECKBOX_SELECTED = unicodeOr("\u25FC", "[+]");
|
|
2820
|
+
var S_CHECKBOX_INACTIVE = unicodeOr("\u25FB", "[ ]");
|
|
2821
|
+
var S_PASSWORD_MASK = unicodeOr("\u25AA", "\u2022");
|
|
2822
|
+
var S_BAR_H = unicodeOr("\u2500", "-");
|
|
2823
|
+
var S_CORNER_TOP_RIGHT = unicodeOr("\u256E", "+");
|
|
2824
|
+
var S_CONNECT_LEFT = unicodeOr("\u251C", "+");
|
|
2825
|
+
var S_CORNER_BOTTOM_RIGHT = unicodeOr("\u256F", "+");
|
|
2826
|
+
var S_CORNER_BOTTOM_LEFT = unicodeOr("\u2570", "+");
|
|
2827
|
+
var S_CORNER_TOP_LEFT = unicodeOr("\u256D", "+");
|
|
2828
|
+
var S_INFO = unicodeOr("\u25CF", "\u2022");
|
|
2829
|
+
var S_SUCCESS = unicodeOr("\u25C6", "*");
|
|
2830
|
+
var S_WARN = unicodeOr("\u25B2", "!");
|
|
2831
|
+
var S_ERROR = unicodeOr("\u25A0", "x");
|
|
2832
|
+
var symbol = (o2) => {
|
|
2833
|
+
switch (o2) {
|
|
2834
|
+
case "initial":
|
|
2835
|
+
case "active":
|
|
2836
|
+
return styleText2("cyan", S_STEP_ACTIVE);
|
|
2837
|
+
case "cancel":
|
|
2838
|
+
return styleText2("red", S_STEP_CANCEL);
|
|
2839
|
+
case "error":
|
|
2840
|
+
return styleText2("yellow", S_STEP_ERROR);
|
|
2841
|
+
case "submit":
|
|
2842
|
+
return styleText2("green", S_STEP_SUBMIT);
|
|
2843
|
+
}
|
|
2844
|
+
};
|
|
2845
|
+
var confirm = (i) => {
|
|
2846
|
+
const a2 = i.active ?? "Yes", s = i.inactive ?? "No";
|
|
2847
|
+
return new r({
|
|
2848
|
+
active: a2,
|
|
2849
|
+
inactive: s,
|
|
2850
|
+
signal: i.signal,
|
|
2851
|
+
input: i.input,
|
|
2852
|
+
output: i.output,
|
|
2853
|
+
initialValue: i.initialValue ?? true,
|
|
2854
|
+
render() {
|
|
2855
|
+
const e = i.withGuide ?? settings.withGuide, u3 = `${symbol(this.state)} `, l2 = e ? `${styleText2("gray", S_BAR)} ` : "", f2 = wrapTextWithPrefix(i.output, i.message, l2, u3), o2 = `${e ? `${styleText2("gray", S_BAR)}
|
|
2856
|
+
` : ""}${f2}
|
|
2857
|
+
`, c2 = this.value ? a2 : s;
|
|
2858
|
+
switch (this.state) {
|
|
2859
|
+
case "submit": {
|
|
2860
|
+
const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
|
|
2861
|
+
return `${o2}${r2}${styleText2("dim", c2)}`;
|
|
2862
|
+
}
|
|
2863
|
+
case "cancel": {
|
|
2864
|
+
const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
|
|
2865
|
+
return `${o2}${r2}${styleText2(["strikethrough", "dim"], c2)}${e ? `
|
|
2866
|
+
${styleText2("gray", S_BAR)}` : ""}`;
|
|
2867
|
+
}
|
|
2868
|
+
default: {
|
|
2869
|
+
const r2 = e ? `${styleText2("cyan", S_BAR)} ` : "", g2 = e ? styleText2("cyan", S_BAR_END) : "";
|
|
2870
|
+
return `${o2}${r2}${this.value ? `${styleText2("green", S_RADIO_ACTIVE)} ${a2}` : `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", a2)}`}${i.vertical ? e ? `
|
|
2871
|
+
${styleText2("cyan", S_BAR)} ` : `
|
|
2872
|
+
` : ` ${styleText2("dim", "/")} `}${this.value ? `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", s)}` : `${styleText2("green", S_RADIO_ACTIVE)} ${s}`}
|
|
2873
|
+
${g2}
|
|
2874
|
+
`;
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
}).prompt();
|
|
2879
|
+
};
|
|
2880
|
+
var MULTISELECT_INSTRUCTIONS = [
|
|
2881
|
+
`${styleText2("dim", "\u2191/\u2193")} to navigate`,
|
|
2882
|
+
`${styleText2("dim", "Space:")} select`,
|
|
2883
|
+
`${styleText2("dim", "Enter:")} confirm`
|
|
2884
|
+
];
|
|
2885
|
+
var log = {
|
|
2886
|
+
message: (s = [], {
|
|
2887
|
+
symbol: e = styleText2("gray", S_BAR),
|
|
2888
|
+
secondarySymbol: r2 = styleText2("gray", S_BAR),
|
|
2889
|
+
output: m2 = process.stdout,
|
|
2890
|
+
spacing: l2 = 1,
|
|
2891
|
+
withGuide: c2
|
|
2892
|
+
} = {}) => {
|
|
2893
|
+
const t2 = [], o2 = c2 ?? settings.withGuide, f2 = o2 ? r2 : "", O = o2 ? `${e} ` : "", u3 = o2 ? `${r2} ` : "";
|
|
2894
|
+
for (let i = 0;i < l2; i++)
|
|
2895
|
+
t2.push(f2);
|
|
2896
|
+
const g2 = Array.isArray(s) ? s : s.split(`
|
|
2897
|
+
`);
|
|
2898
|
+
if (g2.length > 0) {
|
|
2899
|
+
const [i, ...y] = g2;
|
|
2900
|
+
i.length > 0 ? t2.push(`${O}${i}`) : t2.push(o2 ? e : "");
|
|
2901
|
+
for (const p2 of y)
|
|
2902
|
+
p2.length > 0 ? t2.push(`${u3}${p2}`) : t2.push(o2 ? r2 : "");
|
|
2903
|
+
}
|
|
2904
|
+
m2.write(`${t2.join(`
|
|
2905
|
+
`)}
|
|
2906
|
+
`);
|
|
2907
|
+
},
|
|
2908
|
+
info: (s, e) => {
|
|
2909
|
+
log.message(s, { ...e, symbol: styleText2("blue", S_INFO) });
|
|
2910
|
+
},
|
|
2911
|
+
success: (s, e) => {
|
|
2912
|
+
log.message(s, { ...e, symbol: styleText2("green", S_SUCCESS) });
|
|
2913
|
+
},
|
|
2914
|
+
step: (s, e) => {
|
|
2915
|
+
log.message(s, { ...e, symbol: styleText2("green", S_STEP_SUBMIT) });
|
|
2916
|
+
},
|
|
2917
|
+
warn: (s, e) => {
|
|
2918
|
+
log.message(s, { ...e, symbol: styleText2("yellow", S_WARN) });
|
|
2919
|
+
},
|
|
2920
|
+
warning: (s, e) => {
|
|
2921
|
+
log.warn(s, e);
|
|
2922
|
+
},
|
|
2923
|
+
error: (s, e) => {
|
|
2924
|
+
log.message(s, { ...e, symbol: styleText2("red", S_ERROR) });
|
|
2925
|
+
}
|
|
2926
|
+
};
|
|
2927
|
+
var intro = (o2 = "", t2) => {
|
|
2928
|
+
const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_START)} ` : "";
|
|
2929
|
+
i.write(`${e}${o2}
|
|
2930
|
+
`);
|
|
2931
|
+
};
|
|
2932
|
+
var outro = (o2 = "", t2) => {
|
|
2933
|
+
const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR)}
|
|
2934
|
+
${styleText2("gray", S_BAR_END)} ` : "";
|
|
2935
|
+
i.write(`${e}${o2}
|
|
2936
|
+
|
|
2937
|
+
`);
|
|
2938
|
+
};
|
|
2939
|
+
var W$1 = (o2) => o2;
|
|
2940
|
+
var C2 = (o2, e, s) => {
|
|
2941
|
+
const a2 = {
|
|
2942
|
+
hard: true,
|
|
2943
|
+
trim: false
|
|
2944
|
+
}, i = wrapAnsi(o2, e, a2).split(`
|
|
2945
|
+
`), c2 = i.reduce((n2, t2) => Math.max(dist_default2(t2), n2), 0), u3 = i.map(s).reduce((n2, t2) => Math.max(dist_default2(t2), n2), 0), g2 = e - (u3 - c2);
|
|
2946
|
+
return wrapAnsi(o2, g2, a2);
|
|
2947
|
+
};
|
|
2948
|
+
var note = (o2 = "", e = "", s) => {
|
|
2949
|
+
const a2 = s?.output ?? process$1.stdout, i = s?.withGuide ?? settings.withGuide, c2 = s?.format ?? W$1, g2 = ["", ...C2(o2, getColumns(a2) - 6, c2).split(`
|
|
2950
|
+
`).map(c2), ""], n2 = dist_default2(e), t2 = Math.max(g2.reduce((m2, F) => {
|
|
2951
|
+
const O = dist_default2(F);
|
|
2952
|
+
return O > m2 ? O : m2;
|
|
2953
|
+
}, 0), n2) + 2, h2 = g2.map((m2) => `${styleText2("gray", S_BAR)} ${m2}${" ".repeat(t2 - dist_default2(m2))}${styleText2("gray", S_BAR)}`).join(`
|
|
2954
|
+
`), T3 = i ? `${styleText2("gray", S_BAR)}
|
|
2955
|
+
` : "", l$1 = i ? S_CONNECT_LEFT : S_CORNER_BOTTOM_LEFT;
|
|
2956
|
+
a2.write(`${T3}${styleText2("green", S_STEP_SUBMIT)} ${styleText2("reset", e)} ${styleText2("gray", S_BAR_H.repeat(Math.max(t2 - n2 - 1, 1)) + S_CORNER_TOP_RIGHT)}
|
|
2957
|
+
${h2}
|
|
2958
|
+
${styleText2("gray", l$1 + S_BAR_H.repeat(t2 + 2) + S_CORNER_BOTTOM_RIGHT)}
|
|
2959
|
+
`);
|
|
2960
|
+
};
|
|
2961
|
+
var W = (l2) => styleText2("magenta", l2);
|
|
2962
|
+
var spinner = ({
|
|
2963
|
+
indicator: l2 = "dots",
|
|
2964
|
+
onCancel: h2,
|
|
2965
|
+
output: n2 = process.stdout,
|
|
2966
|
+
cancelMessage: G,
|
|
2967
|
+
errorMessage: O,
|
|
2968
|
+
frames: E = unicode ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"],
|
|
2969
|
+
delay: F = unicode ? 80 : 120,
|
|
2970
|
+
signal: m2,
|
|
2971
|
+
...I
|
|
2972
|
+
} = {}) => {
|
|
2973
|
+
const u3 = isCI();
|
|
2974
|
+
let M2, T3, d = false, S = false, s = "", p2, w = performance.now();
|
|
2975
|
+
const x = getColumns(n2), k = I?.styleFrame ?? W, g2 = (e) => {
|
|
2976
|
+
const r2 = e > 1 ? O ?? settings.messages.error : G ?? settings.messages.cancel;
|
|
2977
|
+
S = e === 1, d && (a2(r2, e), S && typeof h2 == "function" && h2());
|
|
2978
|
+
}, f2 = () => g2(2), i = () => g2(1), A = () => {
|
|
2979
|
+
process.on("uncaughtExceptionMonitor", f2), process.on("unhandledRejection", f2), process.on("SIGINT", i), process.on("SIGTERM", i), process.on("exit", g2), m2 && m2.addEventListener("abort", i);
|
|
2980
|
+
}, H = () => {
|
|
2981
|
+
process.removeListener("uncaughtExceptionMonitor", f2), process.removeListener("unhandledRejection", f2), process.removeListener("SIGINT", i), process.removeListener("SIGTERM", i), process.removeListener("exit", g2), m2 && m2.removeEventListener("abort", i);
|
|
2982
|
+
}, y = () => {
|
|
2983
|
+
if (p2 === undefined)
|
|
2984
|
+
return;
|
|
2985
|
+
u3 && n2.write(`
|
|
2986
|
+
`);
|
|
2987
|
+
const r2 = wrapAnsi(p2, x, {
|
|
2988
|
+
hard: true,
|
|
2989
|
+
trim: false
|
|
2990
|
+
}).split(`
|
|
2991
|
+
`);
|
|
2992
|
+
r2.length > 1 && n2.write(import_sisteransi2.cursor.up(r2.length - 1)), n2.write(import_sisteransi2.cursor.to(0)), n2.write(import_sisteransi2.erase.down());
|
|
2993
|
+
}, C3 = (e) => e.replace(/\.+$/, ""), _2 = (e) => {
|
|
2994
|
+
const r2 = (performance.now() - e) / 1000, t2 = Math.floor(r2 / 60), o2 = Math.floor(r2 % 60);
|
|
2995
|
+
return t2 > 0 ? `[${t2}m ${o2}s]` : `[${o2}s]`;
|
|
2996
|
+
}, N = I.withGuide ?? settings.withGuide, P2 = (e = "") => {
|
|
2997
|
+
d = true, M2 = block({ output: n2 }), s = C3(e), w = performance.now(), N && n2.write(`${styleText2("gray", S_BAR)}
|
|
2998
|
+
`);
|
|
2999
|
+
let r2 = 0, t2 = 0;
|
|
3000
|
+
A(), T3 = setInterval(() => {
|
|
3001
|
+
if (u3 && s === p2)
|
|
3002
|
+
return;
|
|
3003
|
+
y(), p2 = s;
|
|
3004
|
+
const o2 = k(E[r2]);
|
|
3005
|
+
let v;
|
|
3006
|
+
if (u3)
|
|
3007
|
+
v = `${o2} ${s}...`;
|
|
3008
|
+
else if (l2 === "timer")
|
|
3009
|
+
v = `${o2} ${s} ${_2(w)}`;
|
|
3010
|
+
else {
|
|
3011
|
+
const B = ".".repeat(Math.floor(t2)).slice(0, 3);
|
|
3012
|
+
v = `${o2} ${s}${B}`;
|
|
3013
|
+
}
|
|
3014
|
+
const j = wrapAnsi(v, x, {
|
|
3015
|
+
hard: true,
|
|
3016
|
+
trim: false
|
|
3017
|
+
});
|
|
3018
|
+
n2.write(j), r2 = r2 + 1 < E.length ? r2 + 1 : 0, t2 = t2 < 4 ? t2 + 0.125 : 0;
|
|
3019
|
+
}, F);
|
|
3020
|
+
}, a2 = (e = "", r2 = 0, t2 = false) => {
|
|
3021
|
+
if (!d)
|
|
3022
|
+
return;
|
|
3023
|
+
d = false, clearInterval(T3), y();
|
|
3024
|
+
const o2 = r2 === 0 ? styleText2("green", S_STEP_SUBMIT) : r2 === 1 ? styleText2("red", S_STEP_CANCEL) : styleText2("red", S_STEP_ERROR);
|
|
3025
|
+
s = e ?? s, t2 || (l2 === "timer" ? n2.write(`${o2} ${s} ${_2(w)}
|
|
3026
|
+
`) : n2.write(`${o2} ${s}
|
|
3027
|
+
`)), H(), M2();
|
|
3028
|
+
};
|
|
3029
|
+
return {
|
|
3030
|
+
start: P2,
|
|
3031
|
+
stop: (e = "") => a2(e, 0),
|
|
3032
|
+
message: (e = "") => {
|
|
3033
|
+
s = C3(e ?? s);
|
|
3034
|
+
},
|
|
3035
|
+
cancel: (e = "") => a2(e, 1),
|
|
3036
|
+
error: (e = "") => a2(e, 2),
|
|
3037
|
+
clear: () => a2("", 0, true),
|
|
3038
|
+
get isCancelled() {
|
|
3039
|
+
return S;
|
|
3040
|
+
}
|
|
3041
|
+
};
|
|
3042
|
+
};
|
|
3043
|
+
var u3 = {
|
|
3044
|
+
light: unicodeOr("\u2500", "-"),
|
|
3045
|
+
heavy: unicodeOr("\u2501", "="),
|
|
3046
|
+
block: unicodeOr("\u2588", "#")
|
|
3047
|
+
};
|
|
3048
|
+
var SELECT_INSTRUCTIONS = [
|
|
3049
|
+
`${styleText2("dim", "\u2191/\u2193")} to navigate`,
|
|
3050
|
+
`${styleText2("dim", "Enter:")} confirm`
|
|
3051
|
+
];
|
|
3052
|
+
var i = `${styleText2("gray", S_BAR)} `;
|
|
3053
|
+
|
|
3054
|
+
// src/commands/drop.ts
|
|
3055
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
3056
|
+
async function runDrop(config2, opts = {}) {
|
|
3057
|
+
intro(import_picocolors.default.bgCyan(import_picocolors.default.black(" @bungres/kit drop ")));
|
|
3058
|
+
const s = spinner();
|
|
3059
|
+
s.start("Loading schemas...");
|
|
3060
|
+
const schemas2 = await loadSchemas(config2.schema);
|
|
3061
|
+
if (schemas2.length === 0) {
|
|
3062
|
+
s.stop("No schemas found.");
|
|
3063
|
+
log.warn(import_picocolors.default.yellow("No table definitions found in schema files."));
|
|
3064
|
+
outro("Failed.");
|
|
3065
|
+
return;
|
|
3066
|
+
}
|
|
3067
|
+
s.stop(`Loaded ${schemas2.length} schemas.`);
|
|
3068
|
+
const ms = spinner();
|
|
3069
|
+
ms.start("Checking database tables...");
|
|
3070
|
+
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
3071
|
+
try {
|
|
3072
|
+
const userSchema = config2.dbSchema;
|
|
3073
|
+
const existingUserTablesResult = await sql2.unsafe(`SELECT table_name FROM information_schema.tables WHERE table_schema = $1`, [userSchema]);
|
|
3074
|
+
const existingTableNames = new Set(existingUserTablesResult.map((r2) => r2.table_name));
|
|
3075
|
+
const migTableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
3076
|
+
SELECT 1 FROM information_schema.tables
|
|
3077
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
3078
|
+
) AS exists`, [config2.migrationsSchema, config2.migrationsTable]);
|
|
3079
|
+
const migrationTableExists = migTableCheck[0]?.exists ?? false;
|
|
3080
|
+
const pushTableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
3081
|
+
SELECT 1 FROM information_schema.tables
|
|
3082
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
3083
|
+
) AS exists`, [config2.migrationsSchema, "__bungres_push"]);
|
|
3084
|
+
const pushTableExists = pushTableCheck[0]?.exists ?? false;
|
|
3085
|
+
const tablesToDrop = schemas2.filter((sch) => existingTableNames.has(sch.config.name));
|
|
3086
|
+
if (tablesToDrop.length === 0 && !migrationTableExists && !pushTableExists) {
|
|
3087
|
+
ms.stop("Nothing to do.");
|
|
3088
|
+
log.success(import_picocolors.default.green("No tables to drop (they either don't exist or were already dropped)."));
|
|
3089
|
+
outro("Done.");
|
|
3090
|
+
return;
|
|
3091
|
+
}
|
|
3092
|
+
ms.stop("Database check complete.");
|
|
3093
|
+
const tableNamesToPrint = tablesToDrop.map((sch) => (sch.config.schema ? sch.config.schema + "." : "") + sch.config.name);
|
|
3094
|
+
if (migrationTableExists) {
|
|
3095
|
+
tableNamesToPrint.push(`${config2.migrationsSchema}.${config2.migrationsTable}`);
|
|
3096
|
+
}
|
|
3097
|
+
if (pushTableExists) {
|
|
3098
|
+
tableNamesToPrint.push(`${config2.migrationsSchema}.__bungres_push`);
|
|
3099
|
+
}
|
|
3100
|
+
if (!opts.force) {
|
|
3101
|
+
log.warn(import_picocolors.default.bgRed(import_picocolors.default.white(" \u26A0\uFE0F WARNING ")));
|
|
3102
|
+
log.message(import_picocolors.default.bold(import_picocolors.default.red("This will drop the following tables and ALL their data:")));
|
|
3103
|
+
for (const name of tableNamesToPrint) {
|
|
3104
|
+
log.info(import_picocolors.default.yellow(` - ${name}`));
|
|
3105
|
+
}
|
|
3106
|
+
const confirm2 = await confirm({
|
|
3107
|
+
message: "Are you sure you want to proceed?",
|
|
3108
|
+
initialValue: false
|
|
3109
|
+
});
|
|
3110
|
+
if (isCancel(confirm2) || !confirm2) {
|
|
3111
|
+
outro(import_picocolors.default.gray("Drop aborted."));
|
|
3112
|
+
return;
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
const exSpinner = spinner();
|
|
3116
|
+
exSpinner.start("Dropping tables...");
|
|
3117
|
+
for (const entry of tablesToDrop) {
|
|
3118
|
+
const ddl = `DROP TABLE IF EXISTS "${entry.config.name}" CASCADE;`;
|
|
3119
|
+
await sql2.unsafe(ddl);
|
|
3120
|
+
log.step(import_picocolors.default.gray(`Dropped ${entry.config.name}`));
|
|
3121
|
+
}
|
|
3122
|
+
if (migrationTableExists) {
|
|
3123
|
+
const qualifiedMigTable = `"${config2.migrationsSchema}"."${config2.migrationsTable}"`;
|
|
3124
|
+
await sql2.unsafe(`DROP TABLE IF EXISTS ${qualifiedMigTable} CASCADE`);
|
|
3125
|
+
log.step(import_picocolors.default.gray(`Dropped ${config2.migrationsSchema}.${config2.migrationsTable}`));
|
|
3126
|
+
}
|
|
3127
|
+
if (pushTableExists) {
|
|
3128
|
+
await sql2.unsafe(`DROP TABLE IF EXISTS "${config2.migrationsSchema}"."__bungres_push" CASCADE`);
|
|
3129
|
+
log.step(import_picocolors.default.gray(`Dropped ${config2.migrationsSchema}.__bungres_push`));
|
|
3130
|
+
}
|
|
3131
|
+
exSpinner.stop("Tables dropped.");
|
|
3132
|
+
outro(import_picocolors.default.cyan("\u2728 Drop complete."));
|
|
3133
|
+
} catch (err) {
|
|
3134
|
+
log.error(import_picocolors.default.red(`Drop failed: ${err.message}`));
|
|
3135
|
+
outro("Failed.");
|
|
3136
|
+
} finally {
|
|
3137
|
+
await sql2.end();
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
// src/commands/migrate.ts
|
|
3142
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
3143
|
+
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
3144
|
+
async function runMigrate(config2) {
|
|
3145
|
+
intro(import_picocolors2.default.bgCyan(import_picocolors2.default.black(" @bungres/kit migrate ")));
|
|
3146
|
+
const migrationsDir = resolve2(config2.out);
|
|
3147
|
+
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
3148
|
+
const table2 = config2.migrationsTable;
|
|
3149
|
+
const schema = config2.migrationsSchema;
|
|
3150
|
+
const qualifiedTable = `"${schema}"."${table2}"`;
|
|
3151
|
+
const createSchema = `CREATE SCHEMA IF NOT EXISTS "${schema}";`;
|
|
3152
|
+
const createMigrationsTable = `
|
|
3153
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
|
|
3154
|
+
id SERIAL PRIMARY KEY,
|
|
3155
|
+
name TEXT NOT NULL UNIQUE,
|
|
3156
|
+
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
3157
|
+
);`.trim();
|
|
3158
|
+
const s = spinner();
|
|
3159
|
+
s.start("Checking pending migrations...");
|
|
3160
|
+
try {
|
|
3161
|
+
await sql2.unsafe(createSchema);
|
|
3162
|
+
await sql2.unsafe(createMigrationsTable);
|
|
3163
|
+
const glob = new Bun.Glob("*.sql");
|
|
3164
|
+
const files = [];
|
|
3165
|
+
for await (const file of glob.scan({ cwd: migrationsDir, absolute: false })) {
|
|
3166
|
+
files.push(file);
|
|
3167
|
+
}
|
|
3168
|
+
files.sort();
|
|
3169
|
+
if (files.length === 0) {
|
|
3170
|
+
s.stop("No files found.");
|
|
3171
|
+
log.warn(import_picocolors2.default.yellow(`No migration files found in ${migrationsDir}`));
|
|
3172
|
+
log.info(`Run ${import_picocolors2.default.green("bungres generate")} first.`);
|
|
3173
|
+
outro("Done.");
|
|
3174
|
+
return;
|
|
3175
|
+
}
|
|
3176
|
+
const applied = await sql2.unsafe(`SELECT name FROM ${qualifiedTable}`);
|
|
3177
|
+
const appliedSet = new Set(applied.map((r2) => r2.name));
|
|
3178
|
+
const pending = files.filter((f2) => !appliedSet.has(f2));
|
|
3179
|
+
if (pending.length === 0) {
|
|
3180
|
+
s.stop("Up to date.");
|
|
3181
|
+
log.success(import_picocolors2.default.green("Everything is up to date."));
|
|
3182
|
+
outro("Done.");
|
|
3183
|
+
return;
|
|
3184
|
+
}
|
|
3185
|
+
s.stop(`Found ${pending.length} pending migration(s).`);
|
|
3186
|
+
for (const file of pending) {
|
|
3187
|
+
const ms = spinner();
|
|
3188
|
+
ms.start(`Applying ${file}...`);
|
|
3189
|
+
const content = await Bun.file(join2(migrationsDir, file)).text();
|
|
3190
|
+
let upContent = content;
|
|
3191
|
+
const upMatch = content.match(/-- ==== UP ====([\s\S]*?)(?:-- ==== DOWN ====|$)/i);
|
|
3192
|
+
if (upMatch) {
|
|
3193
|
+
upContent = upMatch[1].trim();
|
|
3194
|
+
}
|
|
3195
|
+
if (config2.verbose) {
|
|
3196
|
+
log.info(import_picocolors2.default.gray(`-- ${file} --
|
|
3197
|
+
${upContent}
|
|
3198
|
+
`));
|
|
3199
|
+
}
|
|
3200
|
+
await sql2.transaction(async (txSql) => {
|
|
3201
|
+
const statements = config2.breakpoints ? upContent.split(/-->statement-breakpoint/g).flatMap((chunk) => chunk.split(";").map((s2) => s2.trim()).filter(Boolean)) : upContent.split(";").map((s2) => s2.trim()).filter(Boolean);
|
|
3202
|
+
for (const stmt of statements) {
|
|
3203
|
+
await txSql.unsafe(stmt + ";");
|
|
3204
|
+
}
|
|
3205
|
+
await txSql.unsafe(`INSERT INTO ${qualifiedTable} (name) VALUES ($1)`, [file]);
|
|
3206
|
+
});
|
|
3207
|
+
ms.stop(import_picocolors2.default.green(`\u2713 Applied ${file}`));
|
|
3208
|
+
}
|
|
3209
|
+
outro(import_picocolors2.default.cyan("\u2728 All migrations applied successfully."));
|
|
3210
|
+
} catch (err) {
|
|
3211
|
+
log.error(import_picocolors2.default.red(`Migration failed: ${err.message}`));
|
|
3212
|
+
outro("Failed.");
|
|
3213
|
+
} finally {
|
|
3214
|
+
await sql2.end();
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
1502
3217
|
|
|
1503
3218
|
// src/commands/fresh.ts
|
|
1504
3219
|
async function runFresh(config2) {
|
|
@@ -1513,6 +3228,7 @@ Fresh complete.`);
|
|
|
1513
3228
|
|
|
1514
3229
|
// src/commands/generate.ts
|
|
1515
3230
|
import { join as join3, resolve as resolve3 } from "path";
|
|
3231
|
+
import { readdirSync } from "fs";
|
|
1516
3232
|
|
|
1517
3233
|
// src/differ.ts
|
|
1518
3234
|
function diffSchemas(prev, next) {
|
|
@@ -1594,20 +3310,20 @@ function diffSchemas(prev, next) {
|
|
|
1594
3310
|
}
|
|
1595
3311
|
}
|
|
1596
3312
|
}
|
|
1597
|
-
const prevIdxNames = new Set((prevConfig.indexes ?? []).map((
|
|
3313
|
+
const prevIdxNames = new Set((prevConfig.indexes ?? []).map((i2) => i2.name ?? `idx_${tableName}_${i2.columns.join("_")}`));
|
|
1598
3314
|
for (const idx of nextConfig.indexes ?? []) {
|
|
1599
3315
|
const idxName = idx.name ?? `idx_${tableName}_${idx.columns.join("_")}`;
|
|
1600
3316
|
if (!prevIdxNames.has(idxName)) {
|
|
1601
3317
|
const tbl = nextConfig.schema ? `"${nextConfig.schema}"."${tableName}"` : `"${tableName}"`;
|
|
1602
|
-
const
|
|
3318
|
+
const unique = idx.unique ? "UNIQUE " : "";
|
|
1603
3319
|
const using = idx.using ? ` USING ${idx.using.toUpperCase()}` : "";
|
|
1604
|
-
const cols = idx.columns.map((
|
|
3320
|
+
const cols = idx.columns.map((c2) => `"${c2}"`).join(", ");
|
|
1605
3321
|
const where = idx.where ? ` WHERE ${idx.where}` : "";
|
|
1606
|
-
statements.push(`CREATE ${
|
|
3322
|
+
statements.push(`CREATE ${unique}INDEX IF NOT EXISTS "${idxName}" ON ${tbl}${using} (${cols})${where};`);
|
|
1607
3323
|
summary.push(`CREATE INDEX ${idxName} ON ${tableName}`);
|
|
1608
3324
|
}
|
|
1609
3325
|
}
|
|
1610
|
-
const nextIdxNames = new Set((nextConfig.indexes ?? []).map((
|
|
3326
|
+
const nextIdxNames = new Set((nextConfig.indexes ?? []).map((i2) => i2.name ?? `idx_${tableName}_${i2.columns.join("_")}`));
|
|
1611
3327
|
for (const idx of prevConfig.indexes ?? []) {
|
|
1612
3328
|
const idxName = idx.name ?? `idx_${tableName}_${idx.columns.join("_")}`;
|
|
1613
3329
|
if (!nextIdxNames.has(idxName)) {
|
|
@@ -1619,11 +3335,11 @@ function diffSchemas(prev, next) {
|
|
|
1619
3335
|
return { statements, summary, warnings };
|
|
1620
3336
|
}
|
|
1621
3337
|
function topoSortConfigs(tables) {
|
|
1622
|
-
const byName = new Map(tables.map((
|
|
3338
|
+
const byName = new Map(tables.map((t2) => [t2.name, t2]));
|
|
1623
3339
|
const visited = new Set;
|
|
1624
3340
|
const result2 = [];
|
|
1625
3341
|
function deps(config2) {
|
|
1626
|
-
return Object.values(config2.columns).map((col2) => col2.references?.table).filter((
|
|
3342
|
+
return Object.values(config2.columns).map((col2) => col2.references?.table).filter((t2) => t2 !== undefined && byName.has(t2) && t2 !== config2.name);
|
|
1627
3343
|
}
|
|
1628
3344
|
function visit(name) {
|
|
1629
3345
|
if (visited.has(name))
|
|
@@ -1688,21 +3404,40 @@ function formatDefault(value, dataType) {
|
|
|
1688
3404
|
}
|
|
1689
3405
|
|
|
1690
3406
|
// src/commands/generate.ts
|
|
1691
|
-
var
|
|
3407
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
1692
3408
|
async function runGenerate(config2, name) {
|
|
1693
|
-
|
|
3409
|
+
intro(import_picocolors3.default.bgCyan(import_picocolors3.default.black(" @bungres/kit generate ")));
|
|
3410
|
+
const s = spinner();
|
|
3411
|
+
s.start("Loading schemas...");
|
|
1694
3412
|
const schemas2 = await loadSchemas(config2.schema);
|
|
1695
3413
|
if (schemas2.length === 0) {
|
|
1696
|
-
|
|
3414
|
+
s.stop("No table definitions found.");
|
|
3415
|
+
log.warn(import_picocolors3.default.yellow("Check your schema glob pattern."));
|
|
3416
|
+
outro("Failed.");
|
|
1697
3417
|
return;
|
|
1698
3418
|
}
|
|
3419
|
+
s.stop(`Loaded ${schemas2.length} schemas.`);
|
|
1699
3420
|
const migrationsDir = resolve3(config2.out);
|
|
3421
|
+
const metaDir = join3(migrationsDir, "meta");
|
|
1700
3422
|
await Bun.$`mkdir -p ${migrationsDir}`.quiet();
|
|
1701
|
-
|
|
1702
|
-
const
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
3423
|
+
await Bun.$`mkdir -p ${metaDir}`.quiet();
|
|
3424
|
+
const currentSnapshot = Object.fromEntries(schemas2.map((s2) => [s2.config.name, s2.config]));
|
|
3425
|
+
let prevSnapshot = {};
|
|
3426
|
+
let isFirstMigration = true;
|
|
3427
|
+
try {
|
|
3428
|
+
const files = readdirSync(metaDir).filter((f2) => f2.endsWith("_snapshot.json")).sort();
|
|
3429
|
+
if (files.length > 0) {
|
|
3430
|
+
const latest = files[files.length - 1];
|
|
3431
|
+
prevSnapshot = JSON.parse(await Bun.file(join3(metaDir, latest)).text());
|
|
3432
|
+
isFirstMigration = false;
|
|
3433
|
+
} else {
|
|
3434
|
+
const legacyFile2 = Bun.file(join3(migrationsDir, ".snapshot.json"));
|
|
3435
|
+
if (await legacyFile2.exists()) {
|
|
3436
|
+
prevSnapshot = JSON.parse(await legacyFile2.text());
|
|
3437
|
+
isFirstMigration = false;
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
} catch (e) {}
|
|
1706
3441
|
const now = new Date;
|
|
1707
3442
|
const yyyy = now.getUTCFullYear();
|
|
1708
3443
|
const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
@@ -1713,60 +3448,86 @@ async function runGenerate(config2, name) {
|
|
|
1713
3448
|
const prefix = `${yyyy}_${mm}_${dd}_${HH}${MM}${SS}`;
|
|
1714
3449
|
const filename = name ? `${prefix}_${name}.sql` : `${prefix}.sql`;
|
|
1715
3450
|
const outPath = join3(migrationsDir, filename);
|
|
1716
|
-
let
|
|
3451
|
+
let upStatements;
|
|
3452
|
+
let downStatements;
|
|
1717
3453
|
let summary;
|
|
1718
3454
|
let warnings = [];
|
|
1719
3455
|
if (isFirstMigration) {
|
|
1720
3456
|
const sorted = topoSort(schemas2);
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
3457
|
+
upStatements = sorted.flatMap((entry) => [
|
|
3458
|
+
`-- ${entry.exportName}`,
|
|
3459
|
+
generateCreateTable(entry.config, true),
|
|
3460
|
+
``
|
|
3461
|
+
]);
|
|
3462
|
+
downStatements = [...sorted].reverse().flatMap((entry) => {
|
|
3463
|
+
const tbl = entry.config.schema ? `"${entry.config.schema}"."${entry.config.name}"` : `"${entry.config.name}"`;
|
|
3464
|
+
return [`DROP TABLE IF EXISTS ${tbl};`];
|
|
3465
|
+
});
|
|
3466
|
+
summary = sorted.map((s2) => `CREATE TABLE ${s2.config.name}`);
|
|
1729
3467
|
} else {
|
|
1730
|
-
const
|
|
1731
|
-
if (
|
|
1732
|
-
|
|
1733
|
-
|
|
3468
|
+
const upDiff = diffSchemas(prevSnapshot, currentSnapshot);
|
|
3469
|
+
if (upDiff.statements.length === 0) {
|
|
3470
|
+
log.warn(import_picocolors3.default.yellow("No schema changes detected. Nothing to generate."));
|
|
3471
|
+
outro("Done.");
|
|
1734
3472
|
return;
|
|
1735
3473
|
}
|
|
1736
|
-
|
|
1737
|
-
summary =
|
|
1738
|
-
warnings =
|
|
3474
|
+
upStatements = upDiff.statements;
|
|
3475
|
+
summary = upDiff.summary;
|
|
3476
|
+
warnings = upDiff.warnings;
|
|
3477
|
+
const downDiff = diffSchemas(currentSnapshot, prevSnapshot);
|
|
3478
|
+
downStatements = downDiff.statements;
|
|
3479
|
+
}
|
|
3480
|
+
log.message(import_picocolors3.default.bold("Schema changes detected:"));
|
|
3481
|
+
for (const s2 of summary) {
|
|
3482
|
+
if (s2.startsWith("CREATE") || s2.startsWith("ALTER TABLE") && s2.includes("ADD")) {
|
|
3483
|
+
log.success(import_picocolors3.default.green(` + ${s2}`));
|
|
3484
|
+
} else if (s2.startsWith("DROP") || s2.startsWith("ALTER TABLE") && s2.includes("DROP")) {
|
|
3485
|
+
log.error(import_picocolors3.default.red(` - ${s2}`));
|
|
3486
|
+
} else {
|
|
3487
|
+
log.info(import_picocolors3.default.blue(` ~ ${s2}`));
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
if (warnings.length > 0) {
|
|
3491
|
+
log.warn(import_picocolors3.default.bgRed(import_picocolors3.default.white(" \u26A0\uFE0F DATA LOSS DETECTED ")));
|
|
3492
|
+
for (const w of warnings)
|
|
3493
|
+
log.warn(import_picocolors3.default.red(` ! ${w}`));
|
|
3494
|
+
}
|
|
3495
|
+
const shouldGenerate = await confirm({
|
|
3496
|
+
message: "Generate this migration?",
|
|
3497
|
+
initialValue: true
|
|
3498
|
+
});
|
|
3499
|
+
if (isCancel(shouldGenerate) || !shouldGenerate) {
|
|
3500
|
+
outro(import_picocolors3.default.gray("Generation cancelled."));
|
|
3501
|
+
return;
|
|
1739
3502
|
}
|
|
3503
|
+
s.start("Writing files...");
|
|
1740
3504
|
const lines = [
|
|
1741
3505
|
`-- Migration: ${filename}`,
|
|
1742
3506
|
`-- Generated by @bungres/kit at ${new Date().toISOString()}`,
|
|
1743
3507
|
`-- Changes: ${summary.join(", ")}`,
|
|
1744
3508
|
``,
|
|
1745
|
-
|
|
3509
|
+
`-- ==== UP ====`,
|
|
3510
|
+
...upStatements,
|
|
3511
|
+
``,
|
|
3512
|
+
`-- ==== DOWN ====`,
|
|
3513
|
+
...downStatements,
|
|
3514
|
+
``
|
|
1746
3515
|
];
|
|
1747
3516
|
await Bun.write(outPath, lines.join(`
|
|
1748
3517
|
`));
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
\u26A0\uFE0F WARNING: Data Loss Detected!`, "red"));
|
|
1758
|
-
for (const w of warnings)
|
|
1759
|
-
console.warn(colorize(` ! ${w}`, "red"));
|
|
1760
|
-
console.warn(colorize(` Please review the generated migration carefully before applying it.
|
|
1761
|
-
`, "yellow"));
|
|
1762
|
-
}
|
|
1763
|
-
console.log(colorize(`
|
|
1764
|
-
Run \`bungres migrate\` to apply it.`, "cyan"));
|
|
3518
|
+
const metaPath = join3(metaDir, `${prefix}_snapshot.json`);
|
|
3519
|
+
await Bun.write(metaPath, JSON.stringify(currentSnapshot, null, 2));
|
|
3520
|
+
const legacyFile = Bun.file(join3(migrationsDir, ".snapshot.json"));
|
|
3521
|
+
if (await legacyFile.exists()) {
|
|
3522
|
+
await Bun.$`rm ${legacyFile.name}`.quiet();
|
|
3523
|
+
}
|
|
3524
|
+
s.stop(`Generated ${import_picocolors3.default.cyan(filename)}`);
|
|
3525
|
+
outro(`Run ${import_picocolors3.default.green("bungres migrate")} to apply it.`);
|
|
1765
3526
|
}
|
|
1766
3527
|
function topoSort(schemas2) {
|
|
1767
3528
|
const byName = new Map(schemas2.map((s) => [s.config.name, s]));
|
|
1768
3529
|
function deps(config2) {
|
|
1769
|
-
return Object.values(config2.columns).map((col2) => col2.references?.table).filter((
|
|
3530
|
+
return Object.values(config2.columns).map((col2) => col2.references?.table).filter((t2) => t2 !== undefined && byName.has(t2) && t2 !== config2.name);
|
|
1770
3531
|
}
|
|
1771
3532
|
const visited = new Set;
|
|
1772
3533
|
const result2 = [];
|
|
@@ -1790,18 +3551,25 @@ function topoSort(schemas2) {
|
|
|
1790
3551
|
import { existsSync } from "fs";
|
|
1791
3552
|
import { mkdir } from "fs/promises";
|
|
1792
3553
|
import { join as join4 } from "path";
|
|
3554
|
+
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
1793
3555
|
async function runInit(cwd = process.cwd()) {
|
|
3556
|
+
intro(import_picocolors4.default.bgCyan(import_picocolors4.default.black(" @bungres/kit init ")));
|
|
1794
3557
|
const configPath = join4(cwd, "bungres.config.ts");
|
|
1795
3558
|
const dbDir = join4(cwd, "src", "db");
|
|
1796
3559
|
if (existsSync(configPath)) {
|
|
1797
|
-
|
|
3560
|
+
log.warn(import_picocolors4.default.yellow("Config file already exists at bungres.config.ts"));
|
|
3561
|
+
outro("Failed.");
|
|
1798
3562
|
return;
|
|
1799
3563
|
}
|
|
3564
|
+
const s = spinner();
|
|
3565
|
+
s.start("Creating project structure...");
|
|
1800
3566
|
try {
|
|
1801
3567
|
await mkdir(dbDir, { recursive: true });
|
|
1802
|
-
|
|
3568
|
+
log.step(`Created ${import_picocolors4.default.cyan("src/db")} directory`);
|
|
1803
3569
|
} catch (e) {
|
|
1804
|
-
|
|
3570
|
+
s.stop("Failed");
|
|
3571
|
+
log.error(`Failed to create src/db directory: ${e}`);
|
|
3572
|
+
outro("Failed.");
|
|
1805
3573
|
return;
|
|
1806
3574
|
}
|
|
1807
3575
|
const configContent = `import { defineConfig } from "@bungres/kit";
|
|
@@ -1816,9 +3584,11 @@ export default defineConfig({
|
|
|
1816
3584
|
`;
|
|
1817
3585
|
try {
|
|
1818
3586
|
await Bun.write(configPath, configContent);
|
|
1819
|
-
|
|
3587
|
+
log.step(`Created ${import_picocolors4.default.cyan("bungres.config.ts")}`);
|
|
1820
3588
|
} catch (e) {
|
|
1821
|
-
|
|
3589
|
+
s.stop("Failed");
|
|
3590
|
+
log.error(`Failed to create config file: ${e}`);
|
|
3591
|
+
outro("Failed.");
|
|
1822
3592
|
return;
|
|
1823
3593
|
}
|
|
1824
3594
|
const schemaContent = `import {
|
|
@@ -1842,9 +3612,9 @@ export const users = table("users", {
|
|
|
1842
3612
|
`;
|
|
1843
3613
|
try {
|
|
1844
3614
|
await Bun.write(join4(dbDir, "schema.ts"), schemaContent);
|
|
1845
|
-
|
|
3615
|
+
log.step(`Created ${import_picocolors4.default.cyan("src/db/schema.ts")} with example table`);
|
|
1846
3616
|
} catch (e) {
|
|
1847
|
-
|
|
3617
|
+
log.error(`Failed to create schema file: ${e}`);
|
|
1848
3618
|
}
|
|
1849
3619
|
const clientContent = `import { bungres } from "@bungres/orm";
|
|
1850
3620
|
import * as schema from "./schema";
|
|
@@ -1855,24 +3625,23 @@ export const db = bungres({ url, schema });
|
|
|
1855
3625
|
`;
|
|
1856
3626
|
try {
|
|
1857
3627
|
await Bun.write(join4(dbDir, "client.ts"), clientContent);
|
|
1858
|
-
|
|
3628
|
+
log.step(`Created ${import_picocolors4.default.cyan("src/db/client.ts")}`);
|
|
1859
3629
|
} catch (e) {
|
|
1860
|
-
|
|
1861
|
-
}
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
console.log(" 4. Run 'bungres migrate' to apply migrations");
|
|
3630
|
+
log.error(`Failed to create client file: ${e}`);
|
|
3631
|
+
}
|
|
3632
|
+
s.stop("Project initialized.");
|
|
3633
|
+
const nextSteps = `1. Set DATABASE_URL in your .env file
|
|
3634
|
+
2. Edit src/db/schema.ts to define your tables
|
|
3635
|
+
3. Run ${import_picocolors4.default.green("bungres generate")} to create migrations
|
|
3636
|
+
4. Run ${import_picocolors4.default.green("bungres migrate")} to apply migrations`;
|
|
3637
|
+
note(nextSteps, "Next steps");
|
|
3638
|
+
outro(import_picocolors4.default.cyan("\u2728 Bungres project initialized!"));
|
|
1870
3639
|
}
|
|
1871
3640
|
|
|
1872
3641
|
// src/commands/pull.ts
|
|
1873
3642
|
import { resolve as resolve4, join as join5 } from "path";
|
|
1874
3643
|
async function introspectDb(sql2, dbSchema) {
|
|
1875
|
-
const
|
|
3644
|
+
const columns = await sql2.unsafe(`SELECT
|
|
1876
3645
|
c.table_name,
|
|
1877
3646
|
c.column_name,
|
|
1878
3647
|
c.data_type,
|
|
@@ -1906,7 +3675,7 @@ async function introspectDb(sql2, dbSchema) {
|
|
|
1906
3675
|
const indexes = await sql2.unsafe(`SELECT tablename, indexname, indexdef
|
|
1907
3676
|
FROM pg_indexes
|
|
1908
3677
|
WHERE schemaname = $1`, [dbSchema]);
|
|
1909
|
-
return groupByTable(
|
|
3678
|
+
return groupByTable(columns, constraints, indexes);
|
|
1910
3679
|
}
|
|
1911
3680
|
async function runPull(config2) {
|
|
1912
3681
|
console.log("@bungres/kit pull: introspecting database...");
|
|
@@ -1929,20 +3698,20 @@ async function runPull(config2) {
|
|
|
1929
3698
|
await sql2.end();
|
|
1930
3699
|
}
|
|
1931
3700
|
}
|
|
1932
|
-
function groupByTable(
|
|
3701
|
+
function groupByTable(columns, constraints, indexes) {
|
|
1933
3702
|
const map = new Map;
|
|
1934
|
-
for (const col2 of
|
|
3703
|
+
for (const col2 of columns) {
|
|
1935
3704
|
if (!map.has(col2.table_name)) {
|
|
1936
3705
|
map.set(col2.table_name, {
|
|
1937
3706
|
tableName: col2.table_name,
|
|
1938
3707
|
columns: [],
|
|
1939
|
-
indexes: indexes.filter((
|
|
3708
|
+
indexes: indexes.filter((i2) => i2.tablename === col2.table_name)
|
|
1940
3709
|
});
|
|
1941
3710
|
}
|
|
1942
|
-
const tableConstraints = constraints.filter((
|
|
1943
|
-
const pkConstraint = tableConstraints.find((
|
|
1944
|
-
const uniqueConstraint = tableConstraints.find((
|
|
1945
|
-
const fkConstraint = tableConstraints.find((
|
|
3711
|
+
const tableConstraints = constraints.filter((c2) => c2.table_name === col2.table_name && c2.column_name === col2.column_name);
|
|
3712
|
+
const pkConstraint = tableConstraints.find((c2) => c2.constraint_type === "PRIMARY KEY");
|
|
3713
|
+
const uniqueConstraint = tableConstraints.find((c2) => c2.constraint_type === "UNIQUE");
|
|
3714
|
+
const fkConstraint = tableConstraints.find((c2) => c2.constraint_type === "FOREIGN KEY");
|
|
1946
3715
|
map.get(col2.table_name).columns.push({
|
|
1947
3716
|
name: col2.column_name,
|
|
1948
3717
|
dataType: col2.data_type,
|
|
@@ -1991,19 +3760,19 @@ function generateSchemaTS(tableMap, dbSchema) {
|
|
|
1991
3760
|
if (table2.indexes.length > 0) {
|
|
1992
3761
|
const idxLines = [];
|
|
1993
3762
|
for (const idx of table2.indexes) {
|
|
1994
|
-
const
|
|
1995
|
-
if (
|
|
1996
|
-
const isUnique = !!
|
|
1997
|
-
const name =
|
|
3763
|
+
const m2 = idx.indexdef.match(/CREATE (UNIQUE )?INDEX (.+) ON (.+) USING (\w+) \((.+)\)(?: WHERE (.+))?/i);
|
|
3764
|
+
if (m2) {
|
|
3765
|
+
const isUnique = !!m2[1];
|
|
3766
|
+
const name = m2[2].trim().replace(/^"|"$/g, "");
|
|
1998
3767
|
if (name.endsWith("_pkey") || name.endsWith("_key"))
|
|
1999
3768
|
continue;
|
|
2000
|
-
const using =
|
|
2001
|
-
const cols =
|
|
3769
|
+
const using = m2[4].toLowerCase();
|
|
3770
|
+
const cols = m2[5].split(",").map((c2) => `"${c2.trim().replace(/^"|"$/g, "")}"`);
|
|
2002
3771
|
let idxStr = `{ name: "${name}", columns: [${cols.join(", ")}], using: "${using}"`;
|
|
2003
3772
|
if (isUnique)
|
|
2004
3773
|
idxStr += `, unique: true`;
|
|
2005
|
-
if (
|
|
2006
|
-
idxStr += `, where: \`${
|
|
3774
|
+
if (m2[6])
|
|
3775
|
+
idxStr += `, where: \`${m2[6].trim()}\``;
|
|
2007
3776
|
idxStr += ` }`;
|
|
2008
3777
|
idxLines.push(idxStr);
|
|
2009
3778
|
}
|
|
@@ -2122,19 +3891,26 @@ function pgTypeToBungresBuilderName(col2) {
|
|
|
2122
3891
|
return "text";
|
|
2123
3892
|
}
|
|
2124
3893
|
function toCamelCase(str) {
|
|
2125
|
-
return str.replace(/_([a-z])/g, (
|
|
3894
|
+
return str.replace(/_([a-z])/g, (_2, c2) => c2.toUpperCase());
|
|
2126
3895
|
}
|
|
2127
3896
|
|
|
2128
3897
|
// src/commands/push.ts
|
|
2129
|
-
|
|
3898
|
+
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
2130
3899
|
async function runPush(config2, opts = {}) {
|
|
2131
|
-
|
|
3900
|
+
intro(import_picocolors5.default.bgCyan(import_picocolors5.default.black(" @bungres/kit push ")));
|
|
3901
|
+
const s = spinner();
|
|
3902
|
+
s.start("Loading schemas...");
|
|
2132
3903
|
const schemas2 = await loadSchemas(config2.schema);
|
|
2133
3904
|
if (schemas2.length === 0) {
|
|
2134
|
-
|
|
3905
|
+
s.stop("No schemas found.");
|
|
3906
|
+
log.warn(import_picocolors5.default.yellow("No table definitions found. Check your schema glob pattern."));
|
|
3907
|
+
outro("Failed.");
|
|
2135
3908
|
return;
|
|
2136
3909
|
}
|
|
3910
|
+
s.stop(`Loaded ${schemas2.length} schemas.`);
|
|
2137
3911
|
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
3912
|
+
const ms = spinner();
|
|
3913
|
+
ms.start("Computing diff from database...");
|
|
2138
3914
|
try {
|
|
2139
3915
|
await sql2.unsafe(`CREATE SCHEMA IF NOT EXISTS "${config2.migrationsSchema}";`);
|
|
2140
3916
|
const qualifiedPush = `"${config2.migrationsSchema}"."__bungres_push"`;
|
|
@@ -2149,56 +3925,62 @@ async function runPush(config2, opts = {}) {
|
|
|
2149
3925
|
if (rows.length > 0) {
|
|
2150
3926
|
prevSnapshot = typeof rows[0].snapshot === "string" ? JSON.parse(rows[0].snapshot) : rows[0].snapshot;
|
|
2151
3927
|
}
|
|
2152
|
-
const currentSnapshot = Object.fromEntries(schemas2.map((
|
|
3928
|
+
const currentSnapshot = Object.fromEntries(schemas2.map((schemaEntry) => [schemaEntry.config.name, schemaEntry.config]));
|
|
2153
3929
|
const diff = diffSchemas(prevSnapshot, currentSnapshot);
|
|
2154
3930
|
if (diff.statements.length === 0) {
|
|
2155
|
-
|
|
2156
|
-
No schema changes detected. Database is up to date
|
|
3931
|
+
ms.stop("Up to date.");
|
|
3932
|
+
log.success(import_picocolors5.default.green("No schema changes detected. Database is up to date."));
|
|
3933
|
+
outro("Done.");
|
|
2157
3934
|
return;
|
|
2158
3935
|
}
|
|
2159
|
-
|
|
2160
|
-
Changes to apply
|
|
2161
|
-
for (const
|
|
2162
|
-
|
|
3936
|
+
ms.stop(`Computed ${diff.statements.length} statements.`);
|
|
3937
|
+
log.message(import_picocolors5.default.bold("Changes to apply:"));
|
|
3938
|
+
for (const change of diff.summary) {
|
|
3939
|
+
if (change.startsWith("CREATE") || change.startsWith("ALTER TABLE") && change.includes("ADD")) {
|
|
3940
|
+
log.success(import_picocolors5.default.green(` + ${change}`));
|
|
3941
|
+
} else if (change.startsWith("DROP") || change.startsWith("ALTER TABLE") && change.includes("DROP")) {
|
|
3942
|
+
log.error(import_picocolors5.default.red(` - ${change}`));
|
|
3943
|
+
} else {
|
|
3944
|
+
log.info(import_picocolors5.default.blue(` ~ ${change}`));
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
2163
3947
|
if (diff.warnings && diff.warnings.length > 0) {
|
|
2164
|
-
|
|
2165
|
-
\u26A0\uFE0F WARNING: Data Loss Detected!`);
|
|
3948
|
+
log.warn(import_picocolors5.default.bgRed(import_picocolors5.default.white(" \u26A0\uFE0F DATA LOSS DETECTED ")));
|
|
2166
3949
|
for (const w of diff.warnings)
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
These changes will be immediately executed against the database!`);
|
|
3950
|
+
log.warn(import_picocolors5.default.red(` ! ${w}`));
|
|
3951
|
+
log.warn(import_picocolors5.default.yellow("These changes will be immediately executed against the database!"));
|
|
2170
3952
|
}
|
|
2171
3953
|
if (!opts.force) {
|
|
2172
|
-
|
|
2173
|
-
Are you sure you want to push these changes?
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
3954
|
+
const confirm2 = await confirm({
|
|
3955
|
+
message: "Are you sure you want to push these changes?",
|
|
3956
|
+
initialValue: true
|
|
3957
|
+
});
|
|
3958
|
+
if (isCancel(confirm2) || !confirm2) {
|
|
3959
|
+
outro(import_picocolors5.default.gray("Push aborted."));
|
|
2177
3960
|
return;
|
|
2178
3961
|
}
|
|
2179
3962
|
}
|
|
2180
|
-
|
|
2181
|
-
Pushing changes
|
|
3963
|
+
const exSpinner = spinner();
|
|
3964
|
+
exSpinner.start("Pushing changes...");
|
|
2182
3965
|
for (const stmt of diff.statements) {
|
|
2183
3966
|
if (config2.verbose) {
|
|
2184
|
-
|
|
3967
|
+
log.info(import_picocolors5.default.gray(`-- ${stmt}`));
|
|
2185
3968
|
}
|
|
2186
3969
|
await sql2.unsafe(stmt);
|
|
2187
3970
|
}
|
|
2188
3971
|
await sql2.unsafe(`INSERT INTO ${qualifiedPush} (snapshot) VALUES ($1);`, [JSON.stringify(currentSnapshot)]);
|
|
2189
|
-
|
|
2190
|
-
Push complete
|
|
3972
|
+
exSpinner.stop(import_picocolors5.default.green("Changes applied successfully."));
|
|
3973
|
+
outro(import_picocolors5.default.cyan("\u2728 Push complete."));
|
|
3974
|
+
} catch (err) {
|
|
3975
|
+
log.error(import_picocolors5.default.red(`Push failed: ${err.message}`));
|
|
3976
|
+
outro("Failed.");
|
|
2191
3977
|
} finally {
|
|
2192
3978
|
await sql2.end();
|
|
2193
3979
|
}
|
|
2194
3980
|
}
|
|
2195
|
-
async function readLine() {
|
|
2196
|
-
const buf = Buffer.alloc(256);
|
|
2197
|
-
const n = fs.readSync(0, buf, 0, 256, null);
|
|
2198
|
-
return buf.subarray(0, n).toString().trim();
|
|
2199
|
-
}
|
|
2200
3981
|
|
|
2201
3982
|
// src/commands/refresh.ts
|
|
3983
|
+
var import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
2202
3984
|
async function runRefresh(config2) {
|
|
2203
3985
|
const schemas2 = await loadSchemas(config2.schema);
|
|
2204
3986
|
if (schemas2.length === 0) {
|
|
@@ -2212,55 +3994,210 @@ async function runRefresh(config2) {
|
|
|
2212
3994
|
for (const entry of schemas2) {
|
|
2213
3995
|
const ddl = `TRUNCATE TABLE "${entry.config.name}" CASCADE;`;
|
|
2214
3996
|
await sql2.unsafe(ddl);
|
|
2215
|
-
console.log(
|
|
3997
|
+
console.log(import_picocolors6.default.green(` \u2713 truncated ${entry.config.name}`));
|
|
2216
3998
|
}
|
|
2217
|
-
console.log(
|
|
2218
|
-
Refresh complete. All tables are now empty
|
|
3999
|
+
console.log(import_picocolors6.default.green(`
|
|
4000
|
+
Refresh complete. All tables are now empty.`));
|
|
4001
|
+
} finally {
|
|
4002
|
+
await sql2.end();
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
|
|
4006
|
+
// src/commands/rollback.ts
|
|
4007
|
+
import { join as join6, resolve as resolve5 } from "path";
|
|
4008
|
+
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
4009
|
+
async function runRollback(config2) {
|
|
4010
|
+
intro(import_picocolors7.default.bgCyan(import_picocolors7.default.black(" @bungres/kit rollback ")));
|
|
4011
|
+
const migrationsDir = resolve5(config2.out);
|
|
4012
|
+
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
4013
|
+
const table2 = config2.migrationsTable;
|
|
4014
|
+
const schema = config2.migrationsSchema;
|
|
4015
|
+
const qualifiedTable = `"${schema}"."${table2}"`;
|
|
4016
|
+
const s = spinner();
|
|
4017
|
+
s.start("Checking applied migrations...");
|
|
4018
|
+
try {
|
|
4019
|
+
const applied = await sql2.unsafe(`SELECT name FROM ${qualifiedTable} ORDER BY name DESC LIMIT 1`);
|
|
4020
|
+
if (applied.length === 0) {
|
|
4021
|
+
s.stop("No migrations to rollback.");
|
|
4022
|
+
log.warn(import_picocolors7.default.yellow("No applied migrations found in the database."));
|
|
4023
|
+
outro("Done.");
|
|
4024
|
+
return;
|
|
4025
|
+
}
|
|
4026
|
+
const lastMigration = applied[0].name;
|
|
4027
|
+
s.stop(`Found migration to rollback: ${import_picocolors7.default.cyan(lastMigration)}`);
|
|
4028
|
+
const shouldRollback = await confirm({
|
|
4029
|
+
message: `Are you sure you want to rollback ${import_picocolors7.default.cyan(lastMigration)}?`,
|
|
4030
|
+
initialValue: true
|
|
4031
|
+
});
|
|
4032
|
+
if (isCancel(shouldRollback) || !shouldRollback) {
|
|
4033
|
+
outro(import_picocolors7.default.gray("Rollback cancelled."));
|
|
4034
|
+
return;
|
|
4035
|
+
}
|
|
4036
|
+
const ms = spinner();
|
|
4037
|
+
ms.start(`Rolling back ${lastMigration}...`);
|
|
4038
|
+
const content = await Bun.file(join6(migrationsDir, lastMigration)).text();
|
|
4039
|
+
let downContent = "";
|
|
4040
|
+
const downMatch = content.match(/-- ==== DOWN ====([\s\S]*)/i);
|
|
4041
|
+
if (downMatch) {
|
|
4042
|
+
downContent = downMatch[1].trim();
|
|
4043
|
+
} else {
|
|
4044
|
+
ms.stop("Failed.");
|
|
4045
|
+
log.error(import_picocolors7.default.red(`No '-- ==== DOWN ====' section found in ${lastMigration}. Cannot rollback safely.`));
|
|
4046
|
+
outro("Failed.");
|
|
4047
|
+
return;
|
|
4048
|
+
}
|
|
4049
|
+
if (!downContent) {
|
|
4050
|
+
log.warn(import_picocolors7.default.yellow(`Down section is empty in ${lastMigration}. Nothing to execute.`));
|
|
4051
|
+
}
|
|
4052
|
+
if (config2.verbose) {
|
|
4053
|
+
log.info(import_picocolors7.default.gray(`-- ${lastMigration} (DOWN) --
|
|
4054
|
+
${downContent}
|
|
4055
|
+
`));
|
|
4056
|
+
}
|
|
4057
|
+
await sql2.transaction(async (txSql) => {
|
|
4058
|
+
if (downContent) {
|
|
4059
|
+
const statements = config2.breakpoints ? downContent.split(/-->statement-breakpoint/g).flatMap((chunk) => chunk.split(";").map((s2) => s2.trim()).filter(Boolean)) : downContent.split(";").map((s2) => s2.trim()).filter(Boolean);
|
|
4060
|
+
for (const stmt of statements) {
|
|
4061
|
+
await txSql.unsafe(stmt + ";");
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
await txSql.unsafe(`DELETE FROM ${qualifiedTable} WHERE name = $1`, [lastMigration]);
|
|
4065
|
+
});
|
|
4066
|
+
ms.stop(import_picocolors7.default.green(`\u2713 Rolled back ${lastMigration}`));
|
|
4067
|
+
outro(import_picocolors7.default.cyan("\u2728 Rollback successful."));
|
|
4068
|
+
} catch (err) {
|
|
4069
|
+
log.error(import_picocolors7.default.red(`Rollback failed: ${err.message}`));
|
|
4070
|
+
outro("Failed.");
|
|
2219
4071
|
} finally {
|
|
2220
4072
|
await sql2.end();
|
|
2221
4073
|
}
|
|
2222
4074
|
}
|
|
2223
4075
|
|
|
2224
4076
|
// src/commands/seed.ts
|
|
2225
|
-
import { resolve as
|
|
4077
|
+
import { resolve as resolve6 } from "path";
|
|
4078
|
+
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
2226
4079
|
async function runSeed(config2) {
|
|
2227
|
-
|
|
2228
|
-
|
|
4080
|
+
intro(import_picocolors8.default.bgCyan(import_picocolors8.default.black(" @bungres/kit seed ")));
|
|
4081
|
+
if (config2.seed) {
|
|
4082
|
+
const seedPath = resolve6(process.cwd(), config2.seed);
|
|
4083
|
+
const file = Bun.file(seedPath);
|
|
4084
|
+
if (await file.exists()) {
|
|
4085
|
+
const s2 = spinner();
|
|
4086
|
+
s2.start(`Running seeder: ${config2.seed}...`);
|
|
4087
|
+
const proc = Bun.spawn(["bun", "run", seedPath], {
|
|
4088
|
+
cwd: process.cwd(),
|
|
4089
|
+
stdout: "inherit",
|
|
4090
|
+
stderr: "inherit",
|
|
4091
|
+
env: { ...Bun.env, DATABASE_URL: config2.dbUrl }
|
|
4092
|
+
});
|
|
4093
|
+
const exitCode = await proc.exited;
|
|
4094
|
+
if (exitCode === 0) {
|
|
4095
|
+
s2.stop("Seed complete.");
|
|
4096
|
+
outro(import_picocolors8.default.cyan("\u2728 Seeding successful."));
|
|
4097
|
+
} else {
|
|
4098
|
+
s2.stop("Seed failed.");
|
|
4099
|
+
log.error(import_picocolors8.default.red(`Seed failed with exit code ${exitCode}.`));
|
|
4100
|
+
outro("Failed.");
|
|
4101
|
+
process.exit(exitCode);
|
|
4102
|
+
}
|
|
4103
|
+
return;
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
log.info(import_picocolors8.default.blue("No custom seed script found. Initiating Auto-Seeder..."));
|
|
4107
|
+
let faker;
|
|
4108
|
+
try {
|
|
4109
|
+
const fakerModule = await import("@faker-js/faker");
|
|
4110
|
+
faker = fakerModule.faker;
|
|
4111
|
+
} catch (err) {
|
|
4112
|
+
log.error(import_picocolors8.default.red("Auto-seeder requires @faker-js/faker."));
|
|
4113
|
+
log.message(`Please install it: ${import_picocolors8.default.green("bun add -d @faker-js/faker")}`);
|
|
4114
|
+
outro("Failed.");
|
|
2229
4115
|
return;
|
|
2230
4116
|
}
|
|
2231
|
-
const
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
4117
|
+
const s = spinner();
|
|
4118
|
+
s.start("Loading schemas for auto-seeding...");
|
|
4119
|
+
const schemas2 = await loadSchemas(config2.schema);
|
|
4120
|
+
if (schemas2.length === 0) {
|
|
4121
|
+
s.stop("No schemas.");
|
|
4122
|
+
outro("Nothing to seed.");
|
|
4123
|
+
return;
|
|
2236
4124
|
}
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
4125
|
+
const tableConfigs = schemas2.map((s2) => s2.config);
|
|
4126
|
+
const sorted = topoSortConfigs(tableConfigs);
|
|
4127
|
+
s.stop(`Loaded ${sorted.length} tables in topological order.`);
|
|
4128
|
+
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
4129
|
+
const insertedData = {};
|
|
4130
|
+
try {
|
|
4131
|
+
for (const table2 of sorted) {
|
|
4132
|
+
const ms = spinner();
|
|
4133
|
+
ms.start(`Seeding ${table2.name}...`);
|
|
4134
|
+
const rowsToInsert = 10;
|
|
4135
|
+
const rows = [];
|
|
4136
|
+
for (let i2 = 0;i2 < rowsToInsert; i2++) {
|
|
4137
|
+
const row = {};
|
|
4138
|
+
for (const [colName2, col2] of Object.entries(table2.columns)) {
|
|
4139
|
+
if (col2.references) {
|
|
4140
|
+
const parentTable = col2.references.table;
|
|
4141
|
+
const parentRows = insertedData[parentTable];
|
|
4142
|
+
if (parentRows && parentRows.length > 0) {
|
|
4143
|
+
const parentRow = parentRows[Math.floor(Math.random() * parentRows.length)];
|
|
4144
|
+
row[col2.name] = parentRow[col2.references.column];
|
|
4145
|
+
continue;
|
|
4146
|
+
}
|
|
4147
|
+
}
|
|
4148
|
+
if (col2.dataType === "uuid")
|
|
4149
|
+
row[col2.name] = faker.string.uuid();
|
|
4150
|
+
else if (col2.dataType === "varchar" || col2.dataType === "text")
|
|
4151
|
+
row[col2.name] = faker.lorem.word();
|
|
4152
|
+
else if (col2.dataType === "integer")
|
|
4153
|
+
row[col2.name] = faker.number.int({ min: 1, max: 1000 });
|
|
4154
|
+
else if (col2.dataType === "boolean")
|
|
4155
|
+
row[col2.name] = faker.datatype.boolean();
|
|
4156
|
+
else if (col2.dataType === "timestamptz" || col2.dataType === "timestamp")
|
|
4157
|
+
row[col2.name] = faker.date.recent().toISOString();
|
|
4158
|
+
else if (col2.dataType === "jsonb" || col2.dataType === "json")
|
|
4159
|
+
row[col2.name] = JSON.stringify({ key: faker.lorem.word() });
|
|
4160
|
+
else
|
|
4161
|
+
row[col2.name] = null;
|
|
4162
|
+
}
|
|
4163
|
+
rows.push(row);
|
|
4164
|
+
}
|
|
4165
|
+
const insertedRows = await sql2.transaction(async (tx) => {
|
|
4166
|
+
const results = [];
|
|
4167
|
+
for (const row of rows) {
|
|
4168
|
+
const keys = Object.keys(row).map((k) => `"${k}"`);
|
|
4169
|
+
const values = Object.values(row);
|
|
4170
|
+
const placeholders = values.map((_2, i2) => `$${i2 + 1}`);
|
|
4171
|
+
const q = `INSERT INTO "${table2.schema || "public"}"."${table2.name}" (${keys.join(", ")}) VALUES (${placeholders.join(", ")}) RETURNING *`;
|
|
4172
|
+
const res = await tx.unsafe(q, values);
|
|
4173
|
+
results.push(res[0]);
|
|
4174
|
+
}
|
|
4175
|
+
return results;
|
|
4176
|
+
});
|
|
4177
|
+
insertedData[table2.name] = insertedRows;
|
|
4178
|
+
ms.stop(import_picocolors8.default.green(`\u2713 Seeded ${rowsToInsert} rows into ${table2.name}`));
|
|
4179
|
+
}
|
|
4180
|
+
outro(import_picocolors8.default.cyan("\u2728 Auto-seeding complete."));
|
|
4181
|
+
} catch (err) {
|
|
4182
|
+
log.error(import_picocolors8.default.red(`Auto-seeding failed: ${err.message}`));
|
|
4183
|
+
outro("Failed.");
|
|
4184
|
+
} finally {
|
|
4185
|
+
await sql2.end();
|
|
2253
4186
|
}
|
|
2254
4187
|
}
|
|
2255
4188
|
|
|
2256
4189
|
// src/commands/status.ts
|
|
2257
|
-
import { resolve as
|
|
4190
|
+
import { resolve as resolve7 } from "path";
|
|
4191
|
+
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
2258
4192
|
async function runStatus(config2) {
|
|
2259
|
-
|
|
4193
|
+
intro(import_picocolors9.default.bgCyan(import_picocolors9.default.black(" @bungres/kit status ")));
|
|
4194
|
+
const migrationsDir = resolve7(config2.out);
|
|
2260
4195
|
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
2261
4196
|
const table2 = config2.migrationsTable;
|
|
2262
4197
|
const schema = config2.migrationsSchema;
|
|
2263
4198
|
const qualifiedTable = `"${schema}"."${table2}"`;
|
|
4199
|
+
const s = spinner();
|
|
4200
|
+
s.start("Checking migration status...");
|
|
2264
4201
|
try {
|
|
2265
4202
|
const tableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
2266
4203
|
SELECT 1 FROM information_schema.tables
|
|
@@ -2274,33 +4211,247 @@ async function runStatus(config2) {
|
|
|
2274
4211
|
}
|
|
2275
4212
|
files.sort();
|
|
2276
4213
|
if (files.length === 0) {
|
|
2277
|
-
|
|
4214
|
+
s.stop("No files found.");
|
|
4215
|
+
log.warn(import_picocolors9.default.yellow("No migration files found."));
|
|
4216
|
+
log.info(`Run ${import_picocolors9.default.green("bungres generate")} first.`);
|
|
4217
|
+
outro("Done.");
|
|
2278
4218
|
return;
|
|
2279
4219
|
}
|
|
2280
4220
|
let appliedSet = new Set;
|
|
2281
4221
|
if (trackingExists) {
|
|
2282
4222
|
const applied = await sql2.unsafe(`SELECT name FROM ${qualifiedTable} ORDER BY applied_at`);
|
|
2283
|
-
appliedSet = new Set(applied.map((
|
|
4223
|
+
appliedSet = new Set(applied.map((r2) => r2.name));
|
|
2284
4224
|
}
|
|
2285
|
-
|
|
2286
|
-
Migration status:
|
|
2287
|
-
`, "cyan"));
|
|
4225
|
+
s.stop("Status check complete.");
|
|
4226
|
+
log.message(import_picocolors9.default.bold("Migration status:"));
|
|
2288
4227
|
let pendingCount = 0;
|
|
2289
4228
|
for (const file of files) {
|
|
2290
4229
|
const isApplied = appliedSet.has(file);
|
|
2291
|
-
|
|
2292
|
-
|
|
4230
|
+
if (isApplied) {
|
|
4231
|
+
log.success(`${import_picocolors9.default.green("\u2713 applied ")} ${file}`);
|
|
4232
|
+
} else {
|
|
2293
4233
|
pendingCount++;
|
|
2294
|
-
|
|
4234
|
+
log.warn(`${import_picocolors9.default.yellow("\u2717 pending ")} ${file}`);
|
|
4235
|
+
}
|
|
2295
4236
|
}
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
4237
|
+
log.info(`${import_picocolors9.default.green(appliedSet.size.toString())} applied, ${import_picocolors9.default.yellow(pendingCount.toString())} pending.`);
|
|
4238
|
+
outro("Done.");
|
|
4239
|
+
} catch (err) {
|
|
4240
|
+
log.error(import_picocolors9.default.red(`Status check failed: ${err.message}`));
|
|
4241
|
+
outro("Failed.");
|
|
2299
4242
|
} finally {
|
|
2300
4243
|
await sql2.end();
|
|
2301
4244
|
}
|
|
2302
4245
|
}
|
|
2303
4246
|
|
|
4247
|
+
// src/commands/studio.ts
|
|
4248
|
+
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
4249
|
+
|
|
4250
|
+
// src/commands/template.ts
|
|
4251
|
+
var indexHtml = `<!DOCTYPE html>
|
|
4252
|
+
<html lang="en">
|
|
4253
|
+
<head>
|
|
4254
|
+
<meta charset="UTF-8">
|
|
4255
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
4256
|
+
<title>Bungres Studio</title>
|
|
4257
|
+
|
|
4258
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
4259
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
4260
|
+
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
4261
|
+
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
|
|
4262
|
+
|
|
4263
|
+
<script src="https://unpkg.com/htmx.org@2.0.0" defer></script>
|
|
4264
|
+
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
|
4265
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
4266
|
+
|
|
4267
|
+
<script>
|
|
4268
|
+
tailwind.config = {
|
|
4269
|
+
darkMode: "class",
|
|
4270
|
+
theme: {
|
|
4271
|
+
extend: {
|
|
4272
|
+
fontFamily: {
|
|
4273
|
+
sans: ['Outfit', 'sans-serif'],
|
|
4274
|
+
mono: ['"Fira Code"', 'monospace'],
|
|
4275
|
+
},
|
|
4276
|
+
colors: {
|
|
4277
|
+
background: 'var(--background)',
|
|
4278
|
+
foreground: 'var(--foreground)',
|
|
4279
|
+
card: 'var(--card)',
|
|
4280
|
+
'card-foreground': 'var(--card-foreground)',
|
|
4281
|
+
popover: 'var(--popover)',
|
|
4282
|
+
'popover-foreground': 'var(--popover-foreground)',
|
|
4283
|
+
primary: 'var(--primary)',
|
|
4284
|
+
'primary-foreground': 'var(--primary-foreground)',
|
|
4285
|
+
secondary: 'var(--secondary)',
|
|
4286
|
+
'secondary-foreground': 'var(--secondary-foreground)',
|
|
4287
|
+
muted: 'var(--muted)',
|
|
4288
|
+
'muted-foreground': 'var(--muted-foreground)',
|
|
4289
|
+
accent: 'var(--accent)',
|
|
4290
|
+
'accent-foreground': 'var(--accent-foreground)',
|
|
4291
|
+
destructive: 'var(--destructive)',
|
|
4292
|
+
border: 'var(--border)',
|
|
4293
|
+
input: 'var(--input)',
|
|
4294
|
+
ring: 'var(--ring)',
|
|
4295
|
+
sidebar: {
|
|
4296
|
+
DEFAULT: 'var(--sidebar)',
|
|
4297
|
+
foreground: 'var(--sidebar-foreground)',
|
|
4298
|
+
primary: 'var(--sidebar-primary)',
|
|
4299
|
+
'primary-foreground': 'var(--sidebar-primary-foreground)',
|
|
4300
|
+
accent: 'var(--sidebar-accent)',
|
|
4301
|
+
'accent-foreground': 'var(--sidebar-accent-foreground)',
|
|
4302
|
+
border: 'var(--sidebar-border)',
|
|
4303
|
+
ring: 'var(--sidebar-ring)',
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
</script>
|
|
4310
|
+
|
|
4311
|
+
<style>
|
|
4312
|
+
:root {
|
|
4313
|
+
--background: oklch(1 0 0);
|
|
4314
|
+
--foreground: oklch(0.148 0.004 228.8);
|
|
4315
|
+
--card: oklch(1 0 0);
|
|
4316
|
+
--card-foreground: oklch(0.148 0.004 228.8);
|
|
4317
|
+
--popover: oklch(1 0 0);
|
|
4318
|
+
--popover-foreground: oklch(0.148 0.004 228.8);
|
|
4319
|
+
--primary: oklch(0.508 0.118 165.612);
|
|
4320
|
+
--primary-foreground: oklch(0.979 0.021 166.113);
|
|
4321
|
+
--secondary: oklch(0.967 0.001 286.375);
|
|
4322
|
+
--secondary-foreground: oklch(0.21 0.006 285.885);
|
|
4323
|
+
--muted: oklch(0.963 0.002 197.1);
|
|
4324
|
+
--muted-foreground: oklch(0.56 0.021 213.5);
|
|
4325
|
+
--accent: oklch(0.963 0.002 197.1);
|
|
4326
|
+
--accent-foreground: oklch(0.218 0.008 223.9);
|
|
4327
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
4328
|
+
--border: oklch(0.925 0.005 214.3);
|
|
4329
|
+
--input: oklch(0.925 0.005 214.3);
|
|
4330
|
+
--ring: oklch(0.723 0.014 214.4);
|
|
4331
|
+
--chart-1: oklch(0.845 0.143 164.978);
|
|
4332
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
4333
|
+
--chart-3: oklch(0.596 0.145 163.225);
|
|
4334
|
+
--chart-4: oklch(0.508 0.118 165.612);
|
|
4335
|
+
--chart-5: oklch(0.432 0.095 166.913);
|
|
4336
|
+
--radius: 0.625rem;
|
|
4337
|
+
--sidebar: oklch(0.987 0.002 197.1);
|
|
4338
|
+
--sidebar-foreground: oklch(0.148 0.004 228.8);
|
|
4339
|
+
--sidebar-primary: oklch(0.596 0.145 163.225);
|
|
4340
|
+
--sidebar-primary-foreground: oklch(0.979 0.021 166.113);
|
|
4341
|
+
--sidebar-accent: oklch(0.963 0.002 197.1);
|
|
4342
|
+
--sidebar-accent-foreground: oklch(0.218 0.008 223.9);
|
|
4343
|
+
--sidebar-border: oklch(0.925 0.005 214.3);
|
|
4344
|
+
--sidebar-ring: oklch(0.723 0.014 214.4);
|
|
4345
|
+
}
|
|
4346
|
+
|
|
4347
|
+
.dark {
|
|
4348
|
+
--background: oklch(0.148 0.004 228.8);
|
|
4349
|
+
--foreground: oklch(0.987 0.002 197.1);
|
|
4350
|
+
--card: oklch(0.218 0.008 223.9);
|
|
4351
|
+
--card-foreground: oklch(0.987 0.002 197.1);
|
|
4352
|
+
--popover: oklch(0.218 0.008 223.9);
|
|
4353
|
+
--popover-foreground: oklch(0.987 0.002 197.1);
|
|
4354
|
+
--primary: oklch(0.432 0.095 166.913);
|
|
4355
|
+
--primary-foreground: oklch(0.979 0.021 166.113);
|
|
4356
|
+
--secondary: oklch(0.274 0.006 286.033);
|
|
4357
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
4358
|
+
--muted: oklch(0.275 0.011 216.9);
|
|
4359
|
+
--muted-foreground: oklch(0.723 0.014 214.4);
|
|
4360
|
+
--accent: oklch(0.275 0.011 216.9);
|
|
4361
|
+
--accent-foreground: oklch(0.987 0.002 197.1);
|
|
4362
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
4363
|
+
--border: oklch(1 0 0 / 10%);
|
|
4364
|
+
--input: oklch(1 0 0 / 15%);
|
|
4365
|
+
--ring: oklch(0.56 0.021 213.5);
|
|
4366
|
+
--chart-1: oklch(0.845 0.143 164.978);
|
|
4367
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
4368
|
+
--chart-3: oklch(0.596 0.145 163.225);
|
|
4369
|
+
--chart-4: oklch(0.508 0.118 165.612);
|
|
4370
|
+
--chart-5: oklch(0.432 0.095 166.913);
|
|
4371
|
+
--sidebar: oklch(0.218 0.008 223.9);
|
|
4372
|
+
--sidebar-foreground: oklch(0.987 0.002 197.1);
|
|
4373
|
+
--sidebar-primary: oklch(0.696 0.17 162.48);
|
|
4374
|
+
--sidebar-primary-foreground: oklch(0.262 0.051 172.552);
|
|
4375
|
+
--sidebar-accent: oklch(0.275 0.011 216.9);
|
|
4376
|
+
--sidebar-accent-foreground: oklch(0.987 0.002 197.1);
|
|
4377
|
+
--sidebar-border: oklch(1 0 0 / 10%);
|
|
4378
|
+
--sidebar-ring: oklch(0.56 0.021 213.5);
|
|
4379
|
+
}
|
|
4380
|
+
|
|
4381
|
+
::-webkit-scrollbar { width: 6px; height: 6px; }
|
|
4382
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
4383
|
+
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
|
|
4384
|
+
::-webkit-scrollbar-thumb:hover { background: var(--muted-foreground); }
|
|
4385
|
+
::-webkit-scrollbar-corner { background: transparent; }
|
|
4386
|
+
[x-cloak] { display: none !important; }
|
|
4387
|
+
.htmx-indicator { opacity: 0; transition: opacity 200ms ease-in; }
|
|
4388
|
+
.htmx-request .htmx-indicator { opacity: 1; }
|
|
4389
|
+
.htmx-request.htmx-indicator { opacity: 1; }
|
|
4390
|
+
</style>
|
|
4391
|
+
</head>
|
|
4392
|
+
<body class="dark bg-background text-foreground font-sans h-screen flex overflow-hidden selection:bg-primary/30">
|
|
4393
|
+
<div x-data="{ currentTable: null, pageSize: 25 }" class="flex h-screen w-full">
|
|
4394
|
+
<aside class="w-64 bg-sidebar border-r border-sidebar-border flex flex-col z-20 shrink-0 text-sidebar-foreground">
|
|
4395
|
+
<div class="p-4 border-b border-sidebar-border flex items-center gap-3 bg-sidebar">
|
|
4396
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-primary">
|
|
4397
|
+
<ellipse cx="12" cy="5" rx="9" ry="3"></ellipse>
|
|
4398
|
+
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"></path>
|
|
4399
|
+
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"></path>
|
|
4400
|
+
</svg>
|
|
4401
|
+
<h1 class="text-sm font-semibold tracking-tight m-0">Bungres Studio</h1>
|
|
4402
|
+
</div>
|
|
4403
|
+
<div class="flex-1 overflow-y-auto p-2" hx-get="/htmx/sidebar" hx-trigger="load">
|
|
4404
|
+
<div class="p-4 text-xs text-muted-foreground animate-pulse text-center">Loading schemas...</div>
|
|
4405
|
+
</div>
|
|
4406
|
+
</aside>
|
|
4407
|
+
<main class="flex-1 flex flex-col relative w-[calc(100vw-16rem)]">
|
|
4408
|
+
<header class="h-14 px-4 border-b border-border flex items-center justify-between bg-card z-10 shrink-0 text-card-foreground">
|
|
4409
|
+
<h2 class="text-sm font-semibold tracking-tight flex items-center gap-2">
|
|
4410
|
+
<template x-if="currentTable">
|
|
4411
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="text-primary">
|
|
4412
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
4413
|
+
<line x1="3" y1="9" x2="21" y2="9"></line>
|
|
4414
|
+
<line x1="9" y1="21" x2="9" y2="9"></line>
|
|
4415
|
+
</svg>
|
|
4416
|
+
</template>
|
|
4417
|
+
<template x-if="!currentTable">
|
|
4418
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="text-muted-foreground">
|
|
4419
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
4420
|
+
<line x1="3" y1="9" x2="21" y2="9"></line>
|
|
4421
|
+
<line x1="9" y1="21" x2="9" y2="9"></line>
|
|
4422
|
+
</svg>
|
|
4423
|
+
</template>
|
|
4424
|
+
<span x-text="currentTable ? currentTable : 'Select a table'"></span>
|
|
4425
|
+
</h2>
|
|
4426
|
+
<button x-bind:disabled="!currentTable" class="bg-card border border-border text-card-foreground px-3 py-1.5 rounded-md text-xs font-medium cursor-pointer transition-all hover:bg-accent hover:text-accent-foreground active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-1.5 group" x-on:click="$dispatch('refresh-table')">
|
|
4427
|
+
<svg class="w-4 h-4 group-hover:rotate-180 transition-transform duration-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
4428
|
+
<polyline points="23 4 23 10 17 10"></polyline>
|
|
4429
|
+
<polyline points="1 20 1 14 7 14"></polyline>
|
|
4430
|
+
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
|
|
4431
|
+
</svg>
|
|
4432
|
+
Refresh
|
|
4433
|
+
</button>
|
|
4434
|
+
</header>
|
|
4435
|
+
<div class="flex-1 overflow-auto relative z-[1] text-left bg-background">
|
|
4436
|
+
<div id="data-container" class="h-full w-full flex flex-col" x-on:refresh-table.window="if(currentTable) htmx.ajax('GET', '/htmx/tables/' + currentTable + '?limit=' + pageSize, {target: '#data-container'})">
|
|
4437
|
+
<div class="flex flex-col items-center justify-center h-full w-full text-muted-foreground animate-[fadeIn_0.5s_ease-out]">
|
|
4438
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="w-16 h-16 mb-4 text-muted">
|
|
4439
|
+
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path>
|
|
4440
|
+
<polyline points="14 2 14 8 20 8"></polyline>
|
|
4441
|
+
</svg>
|
|
4442
|
+
<h3 class="text-foreground m-0 mb-2 text-lg">No Table Selected</h3>
|
|
4443
|
+
<p class="text-sm">Choose a table from the sidebar to view its data</p>
|
|
4444
|
+
</div>
|
|
4445
|
+
</div>
|
|
4446
|
+
</div>
|
|
4447
|
+
</main>
|
|
4448
|
+
</div>
|
|
4449
|
+
<script>
|
|
4450
|
+
document.addEventListener('alpine:init', () => {})
|
|
4451
|
+
</script>
|
|
4452
|
+
</body>
|
|
4453
|
+
</html>`;
|
|
4454
|
+
|
|
2304
4455
|
// src/commands/studio.ts
|
|
2305
4456
|
async function runStudio(config2) {
|
|
2306
4457
|
const schemas2 = await loadSchemas(config2.schema);
|
|
@@ -2326,7 +4477,7 @@ async function runStudio(config2) {
|
|
|
2326
4477
|
fk.columns.forEach((col2) => fkColumns.add(col2));
|
|
2327
4478
|
});
|
|
2328
4479
|
}
|
|
2329
|
-
const
|
|
4480
|
+
const columns = Object.entries(s.config.columns).map(([key, col2]) => {
|
|
2330
4481
|
const fk = col2.references ? {
|
|
2331
4482
|
table: col2.references.table,
|
|
2332
4483
|
column: col2.references.column
|
|
@@ -2341,7 +4492,7 @@ async function runStudio(config2) {
|
|
|
2341
4492
|
return {
|
|
2342
4493
|
name: s.config.name,
|
|
2343
4494
|
exportName: s.exportName,
|
|
2344
|
-
columns
|
|
4495
|
+
columns,
|
|
2345
4496
|
foreignKeys: s.config.foreignKeys || []
|
|
2346
4497
|
};
|
|
2347
4498
|
});
|
|
@@ -2398,804 +4549,181 @@ async function runStudio(config2) {
|
|
|
2398
4549
|
return new Response("Invalid request", { status: 400 });
|
|
2399
4550
|
}
|
|
2400
4551
|
}
|
|
2401
|
-
if (req.method === "GET" && url.pathname === "/") {
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
<
|
|
2417
|
-
<
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
:root {
|
|
2424
|
-
--bg-color: #09090b;
|
|
2425
|
-
--panel-bg: #18181b;
|
|
2426
|
-
--border-color: #27272a;
|
|
2427
|
-
--text-main: #fafafa;
|
|
2428
|
-
--text-muted: #a1a1aa;
|
|
2429
|
-
--accent-color: #8b5cf6;
|
|
2430
|
-
--accent-hover: #7c3aed;
|
|
2431
|
-
--header-bg: #09090b;
|
|
2432
|
-
--row-hover: #27272a;
|
|
2433
|
-
--input-bg: #18181b;
|
|
2434
|
-
--muted-bg: #27272a;
|
|
2435
|
-
|
|
2436
|
-
--type-number: #f472b6;
|
|
2437
|
-
--type-string: #60a5fa;
|
|
2438
|
-
--type-boolean: #34d399;
|
|
2439
|
-
--type-date: #c084fc;
|
|
2440
|
-
--type-json: #fbbf24;
|
|
2441
|
-
--type-null: #71717a;
|
|
2442
|
-
}
|
|
2443
|
-
|
|
2444
|
-
* { box-sizing: border-box; }
|
|
2445
|
-
|
|
2446
|
-
body {
|
|
2447
|
-
margin: 0;
|
|
2448
|
-
padding: 0;
|
|
2449
|
-
font-family: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
2450
|
-
background-color: var(--bg-color);
|
|
2451
|
-
color: var(--text-main);
|
|
2452
|
-
display: flex;
|
|
2453
|
-
height: 100vh;
|
|
2454
|
-
overflow: hidden;
|
|
2455
|
-
}
|
|
2456
|
-
|
|
2457
|
-
/* Sidebar */
|
|
2458
|
-
.sidebar {
|
|
2459
|
-
width: 240px;
|
|
2460
|
-
background-color: var(--panel-bg);
|
|
2461
|
-
border-right: 1px solid var(--border-color);
|
|
2462
|
-
display: flex;
|
|
2463
|
-
flex-direction: column;
|
|
2464
|
-
z-index: 20;
|
|
2465
|
-
}
|
|
2466
|
-
|
|
2467
|
-
.sidebar-header {
|
|
2468
|
-
padding: 16px;
|
|
2469
|
-
border-bottom: 1px solid var(--border-color);
|
|
2470
|
-
display: flex;
|
|
2471
|
-
align-items: center;
|
|
2472
|
-
gap: 8px;
|
|
2473
|
-
background-color: var(--panel-bg);
|
|
2474
|
-
}
|
|
2475
|
-
|
|
2476
|
-
.sidebar-header h1 {
|
|
2477
|
-
margin: 0;
|
|
2478
|
-
font-size: 14px;
|
|
2479
|
-
font-weight: 600;
|
|
2480
|
-
color: var(--text-main);
|
|
2481
|
-
letter-spacing: -0.25px;
|
|
2482
|
-
}
|
|
2483
|
-
|
|
2484
|
-
.sidebar-header svg {
|
|
2485
|
-
color: var(--accent-color);
|
|
2486
|
-
}
|
|
2487
|
-
|
|
2488
|
-
.table-list {
|
|
2489
|
-
flex: 1;
|
|
2490
|
-
overflow-y: auto;
|
|
2491
|
-
padding: 8px;
|
|
2492
|
-
list-style: none;
|
|
2493
|
-
margin: 0;
|
|
2494
|
-
}
|
|
2495
|
-
|
|
2496
|
-
.table-list::-webkit-scrollbar {
|
|
2497
|
-
width: 6px;
|
|
2498
|
-
}
|
|
2499
|
-
.table-list::-webkit-scrollbar-thumb {
|
|
2500
|
-
background: #3f3f46;
|
|
2501
|
-
border-radius: 4px;
|
|
2502
|
-
}
|
|
2503
|
-
|
|
2504
|
-
.table-item {
|
|
2505
|
-
padding: 8px 12px;
|
|
2506
|
-
cursor: pointer;
|
|
2507
|
-
font-size: 13px;
|
|
2508
|
-
font-weight: 500;
|
|
2509
|
-
color: var(--text-muted);
|
|
2510
|
-
border-radius: 6px;
|
|
2511
|
-
transition: all 0.15s ease;
|
|
2512
|
-
display: flex;
|
|
2513
|
-
align-items: center;
|
|
2514
|
-
gap: 8px;
|
|
2515
|
-
margin-bottom: 2px;
|
|
2516
|
-
border: 1px solid transparent;
|
|
2517
|
-
}
|
|
2518
|
-
|
|
2519
|
-
.table-item:hover {
|
|
2520
|
-
background-color: var(--muted-bg);
|
|
2521
|
-
color: var(--text-main);
|
|
2522
|
-
}
|
|
2523
|
-
|
|
2524
|
-
.table-item.active {
|
|
2525
|
-
background-color: var(--accent-color);
|
|
2526
|
-
color: #fff;
|
|
2527
|
-
border-color: var(--accent-color);
|
|
2528
|
-
}
|
|
2529
|
-
|
|
2530
|
-
.table-item svg {
|
|
2531
|
-
flex-shrink: 0;
|
|
2532
|
-
}
|
|
2533
|
-
.table-item.active svg {
|
|
2534
|
-
color: #fff;
|
|
2535
|
-
}
|
|
2536
|
-
|
|
2537
|
-
/* Main Content */
|
|
2538
|
-
.main {
|
|
2539
|
-
flex: 1;
|
|
2540
|
-
display: flex;
|
|
2541
|
-
flex-direction: column;
|
|
2542
|
-
position: relative;
|
|
2543
|
-
}
|
|
2544
|
-
|
|
2545
|
-
.main-header {
|
|
2546
|
-
height: 56px;
|
|
2547
|
-
padding: 0 16px;
|
|
2548
|
-
border-bottom: 1px solid var(--border-color);
|
|
2549
|
-
display: flex;
|
|
2550
|
-
align-items: center;
|
|
2551
|
-
justify-content: space-between;
|
|
2552
|
-
background-color: var(--header-bg);
|
|
2553
|
-
z-index: 10;
|
|
2554
|
-
}
|
|
2555
|
-
|
|
2556
|
-
.main-header h2 {
|
|
2557
|
-
margin: 0;
|
|
2558
|
-
font-size: 14px;
|
|
2559
|
-
font-weight: 600;
|
|
2560
|
-
color: var(--text-main);
|
|
2561
|
-
letter-spacing: -0.25px;
|
|
2562
|
-
display: flex;
|
|
2563
|
-
align-items: center;
|
|
2564
|
-
gap: 8px;
|
|
2565
|
-
}
|
|
2566
|
-
|
|
2567
|
-
.btn {
|
|
2568
|
-
background-color: var(--input-bg);
|
|
2569
|
-
border: 1px solid var(--border-color);
|
|
2570
|
-
color: var(--text-main);
|
|
2571
|
-
padding: 6px 12px;
|
|
2572
|
-
border-radius: 6px;
|
|
2573
|
-
font-size: 13px;
|
|
2574
|
-
font-weight: 500;
|
|
2575
|
-
font-family: 'Outfit', sans-serif;
|
|
2576
|
-
cursor: pointer;
|
|
2577
|
-
transition: all 0.15s ease;
|
|
2578
|
-
display: flex;
|
|
2579
|
-
align-items: center;
|
|
2580
|
-
gap: 6px;
|
|
2581
|
-
}
|
|
2582
|
-
|
|
2583
|
-
.btn:hover:not(:disabled) {
|
|
2584
|
-
background-color: var(--muted-bg);
|
|
2585
|
-
}
|
|
2586
|
-
|
|
2587
|
-
.btn:active:not(:disabled) {
|
|
2588
|
-
transform: translateY(1px);
|
|
2589
|
-
}
|
|
2590
|
-
|
|
2591
|
-
.btn:disabled {
|
|
2592
|
-
opacity: 0.5;
|
|
2593
|
-
cursor: not-allowed;
|
|
2594
|
-
}
|
|
2595
|
-
|
|
2596
|
-
.content-area {
|
|
2597
|
-
flex: 1;
|
|
2598
|
-
overflow: auto;
|
|
2599
|
-
padding: 0;
|
|
2600
|
-
position: relative;
|
|
2601
|
-
z-index: 1;
|
|
2602
|
-
text-align: left;
|
|
2603
|
-
}
|
|
2604
|
-
|
|
2605
|
-
/* Data Table */
|
|
2606
|
-
.data-grid-container {
|
|
2607
|
-
background-color: var(--bg-color);
|
|
2608
|
-
border: 1px solid var(--border-color);
|
|
2609
|
-
border-radius: 0;
|
|
2610
|
-
overflow: hidden;
|
|
2611
|
-
height: 100%;
|
|
2612
|
-
width: 100%;
|
|
2613
|
-
display: flex;
|
|
2614
|
-
flex-direction: column;
|
|
2615
|
-
}
|
|
2616
|
-
|
|
2617
|
-
.data-grid-container > .table-wrapper {
|
|
2618
|
-
flex: 1;
|
|
2619
|
-
overflow: auto;
|
|
2620
|
-
min-height: 0;
|
|
2621
|
-
}
|
|
2622
|
-
|
|
2623
|
-
.data-grid-container::-webkit-scrollbar {
|
|
2624
|
-
width: 8px;
|
|
2625
|
-
height: 8px;
|
|
2626
|
-
}
|
|
2627
|
-
.data-grid-container::-webkit-scrollbar-corner {
|
|
2628
|
-
background: transparent;
|
|
2629
|
-
}
|
|
2630
|
-
.data-grid-container::-webkit-scrollbar-thumb {
|
|
2631
|
-
background: #3f3f46;
|
|
2632
|
-
border-radius: 4px;
|
|
2633
|
-
}
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
table {
|
|
2637
|
-
width: auto;
|
|
2638
|
-
border-collapse: separate;
|
|
2639
|
-
border-spacing: 0;
|
|
2640
|
-
text-align: left;
|
|
2641
|
-
font-size: 14px;
|
|
2642
|
-
table-layout: auto;
|
|
2643
|
-
}
|
|
2644
|
-
|
|
2645
|
-
th {
|
|
2646
|
-
background-color: var(--panel-bg);
|
|
2647
|
-
color: var(--text-main);
|
|
2648
|
-
font-weight: 500;
|
|
2649
|
-
font-size: 12px;
|
|
2650
|
-
padding: 10px 16px;
|
|
2651
|
-
border-bottom: 1px solid var(--border-color);
|
|
2652
|
-
border-right: 1px solid var(--border-color);
|
|
2653
|
-
white-space: nowrap;
|
|
2654
|
-
position: sticky;
|
|
2655
|
-
top: 0;
|
|
2656
|
-
z-index: 10;
|
|
2657
|
-
}
|
|
2658
|
-
|
|
2659
|
-
.col-header {
|
|
2660
|
-
display: flex;
|
|
2661
|
-
flex-direction: column;
|
|
2662
|
-
gap: 2px;
|
|
2663
|
-
}
|
|
2664
|
-
|
|
2665
|
-
.col-name {
|
|
2666
|
-
font-weight: 600;
|
|
2667
|
-
font-size: 13px;
|
|
2668
|
-
display: flex;
|
|
2669
|
-
align-items: center;
|
|
2670
|
-
gap: 6px;
|
|
2671
|
-
}
|
|
2672
|
-
|
|
2673
|
-
.pk-badge {
|
|
2674
|
-
font-size: 10px;
|
|
2675
|
-
background: rgba(251, 191, 36, 0.15);
|
|
2676
|
-
color: #fbbf24;
|
|
2677
|
-
padding: 2px 5px;
|
|
2678
|
-
border-radius: 4px;
|
|
2679
|
-
font-weight: 500;
|
|
2680
|
-
letter-spacing: 0.25px;
|
|
2681
|
-
border: 1px solid rgba(251, 191, 36, 0.3);
|
|
2682
|
-
}
|
|
2683
|
-
|
|
2684
|
-
.fk-badge {
|
|
2685
|
-
font-size: 10px;
|
|
2686
|
-
background: rgba(96, 165, 250, 0.15);
|
|
2687
|
-
color: #60a5fa;
|
|
2688
|
-
padding: 2px 5px;
|
|
2689
|
-
border-radius: 4px;
|
|
2690
|
-
font-weight: 500;
|
|
2691
|
-
letter-spacing: 0.25px;
|
|
2692
|
-
border: 1px solid rgba(96, 165, 250, 0.3);
|
|
2693
|
-
}
|
|
2694
|
-
|
|
2695
|
-
.col-type {
|
|
2696
|
-
font-size: 11px;
|
|
2697
|
-
color: var(--text-muted);
|
|
2698
|
-
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
|
2699
|
-
text-transform: uppercase;
|
|
2700
|
-
}
|
|
2701
|
-
|
|
2702
|
-
td {
|
|
2703
|
-
padding: 10px 16px;
|
|
2704
|
-
border-bottom: 1px solid var(--border-color);
|
|
2705
|
-
border-right: 1px solid var(--border-color);
|
|
2706
|
-
color: var(--text-main);
|
|
2707
|
-
max-width: 300px;
|
|
2708
|
-
overflow: hidden;
|
|
2709
|
-
text-overflow: ellipsis;
|
|
2710
|
-
white-space: nowrap;
|
|
2711
|
-
transition: background-color 0.15s ease;
|
|
2712
|
-
font-size: 13px;
|
|
2713
|
-
}
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
tr:hover td {
|
|
2718
|
-
background-color: var(--row-hover);
|
|
2719
|
-
}
|
|
2720
|
-
|
|
2721
|
-
.type-number { color: var(--type-number); }
|
|
2722
|
-
.type-string { color: var(--type-string); }
|
|
2723
|
-
.type-boolean { color: var(--type-boolean); }
|
|
2724
|
-
.type-date { color: var(--type-date); }
|
|
2725
|
-
.type-json { color: var(--type-json); font-family: monospace; }
|
|
2726
|
-
.type-null { color: var(--type-null); font-style: italic; }
|
|
2727
|
-
|
|
2728
|
-
.cell-value {
|
|
2729
|
-
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
|
2730
|
-
font-size: 13px;
|
|
2731
|
-
}
|
|
2732
|
-
|
|
2733
|
-
.empty-state {
|
|
2734
|
-
display: flex;
|
|
2735
|
-
flex-direction: column;
|
|
2736
|
-
align-items: center;
|
|
2737
|
-
justify-content: center;
|
|
2738
|
-
height: 100%;
|
|
2739
|
-
width: 100%;
|
|
2740
|
-
color: var(--text-muted);
|
|
2741
|
-
animation: fadeIn 0.5s ease-out;
|
|
2742
|
-
}
|
|
2743
|
-
|
|
2744
|
-
.empty-state svg {
|
|
2745
|
-
margin-bottom: 16px;
|
|
2746
|
-
color: #3f3f46;
|
|
2747
|
-
width: 64px;
|
|
2748
|
-
height: 64px;
|
|
2749
|
-
}
|
|
2750
|
-
|
|
2751
|
-
.empty-state h3 {
|
|
2752
|
-
color: var(--text-main);
|
|
2753
|
-
margin: 0 0 8px 0;
|
|
2754
|
-
font-size: 18px;
|
|
2755
|
-
}
|
|
2756
|
-
|
|
2757
|
-
@keyframes fadeIn {
|
|
2758
|
-
from { opacity: 0; transform: translateY(10px); }
|
|
2759
|
-
to { opacity: 1; transform: translateY(0); }
|
|
2760
|
-
}
|
|
2761
|
-
|
|
2762
|
-
@keyframes spin {
|
|
2763
|
-
from { transform: rotate(0deg); }
|
|
2764
|
-
to { transform: rotate(360deg); }
|
|
2765
|
-
}
|
|
2766
|
-
.spinning {
|
|
2767
|
-
animation: spin 1s linear infinite;
|
|
2768
|
-
}
|
|
2769
|
-
|
|
2770
|
-
/* Pagination */
|
|
2771
|
-
.pagination {
|
|
2772
|
-
display: flex;
|
|
2773
|
-
align-items: center;
|
|
2774
|
-
justify-content: space-between;
|
|
2775
|
-
padding: 12px 16px;
|
|
2776
|
-
background-color: var(--panel-bg);
|
|
2777
|
-
border-top: 1px solid var(--border-color);
|
|
2778
|
-
font-size: 13px;
|
|
2779
|
-
color: var(--text-muted);
|
|
2780
|
-
width: fit-content;
|
|
2781
|
-
min-width: 100%;
|
|
2782
|
-
flex-shrink: 0;
|
|
2783
|
-
}
|
|
2784
|
-
|
|
2785
|
-
.pagination-info {
|
|
2786
|
-
display: flex;
|
|
2787
|
-
align-items: center;
|
|
2788
|
-
gap: 12px;
|
|
2789
|
-
}
|
|
2790
|
-
|
|
2791
|
-
.pagination-controls {
|
|
2792
|
-
display: flex;
|
|
2793
|
-
align-items: center;
|
|
2794
|
-
gap: 6px;
|
|
2795
|
-
}
|
|
2796
|
-
|
|
2797
|
-
.pagination-btn {
|
|
2798
|
-
background-color: var(--input-bg);
|
|
2799
|
-
border: 1px solid var(--border-color);
|
|
2800
|
-
color: var(--text-main);
|
|
2801
|
-
padding: 6px 12px;
|
|
2802
|
-
border-radius: 6px;
|
|
2803
|
-
cursor: pointer;
|
|
2804
|
-
font-size: 13px;
|
|
2805
|
-
transition: all 0.15s ease;
|
|
2806
|
-
}
|
|
2807
|
-
|
|
2808
|
-
.pagination-btn:hover:not(:disabled) {
|
|
2809
|
-
background-color: var(--muted-bg);
|
|
2810
|
-
}
|
|
2811
|
-
|
|
2812
|
-
.pagination-btn:disabled {
|
|
2813
|
-
opacity: 0.5;
|
|
2814
|
-
cursor: not-allowed;
|
|
2815
|
-
}
|
|
2816
|
-
|
|
2817
|
-
.pagination-btn.active {
|
|
2818
|
-
background-color: var(--accent-color);
|
|
2819
|
-
border-color: var(--accent-color);
|
|
2820
|
-
}
|
|
2821
|
-
|
|
2822
|
-
.page-input {
|
|
2823
|
-
background-color: var(--input-bg);
|
|
2824
|
-
border: 1px solid var(--border-color);
|
|
2825
|
-
color: var(--text-main);
|
|
2826
|
-
padding: 6px 8px;
|
|
2827
|
-
border-radius: 6px;
|
|
2828
|
-
width: 50px;
|
|
2829
|
-
text-align: center;
|
|
2830
|
-
font-size: 13px;
|
|
2831
|
-
}
|
|
2832
|
-
|
|
2833
|
-
.page-size-select {
|
|
2834
|
-
background-color: var(--input-bg);
|
|
2835
|
-
border: 1px solid var(--border-color);
|
|
2836
|
-
color: var(--text-main);
|
|
2837
|
-
padding: 6px 8px;
|
|
2838
|
-
border-radius: 6px;
|
|
2839
|
-
font-size: 13px;
|
|
2840
|
-
cursor: pointer;
|
|
2841
|
-
}
|
|
2842
|
-
|
|
2843
|
-
.page-size-select:hover {
|
|
2844
|
-
background-color: var(--muted-bg);
|
|
2845
|
-
}
|
|
2846
|
-
</style>
|
|
2847
|
-
</head>
|
|
2848
|
-
<body>
|
|
2849
|
-
|
|
2850
|
-
<div class="sidebar">
|
|
2851
|
-
<div class="sidebar-header">
|
|
2852
|
-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2853
|
-
<ellipse cx="12" cy="5" rx="9" ry="3"></ellipse>
|
|
2854
|
-
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"></path>
|
|
2855
|
-
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"></path>
|
|
2856
|
-
</svg>
|
|
2857
|
-
<h1>Bungres Studio</h1>
|
|
2858
|
-
</div>
|
|
2859
|
-
<ul class="table-list" id="table-list">
|
|
2860
|
-
<!-- Populated by JS -->
|
|
2861
|
-
</ul>
|
|
2862
|
-
</div>
|
|
2863
|
-
|
|
2864
|
-
<div class="main">
|
|
2865
|
-
<div class="main-header">
|
|
2866
|
-
<h2 id="current-table-name">
|
|
2867
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="color: var(--text-muted);">
|
|
2868
|
-
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
2869
|
-
<line x1="3" y1="9" x2="21" y2="9"></line>
|
|
2870
|
-
<line x1="9" y1="21" x2="9" y2="9"></line>
|
|
2871
|
-
</svg>
|
|
2872
|
-
Select a table
|
|
2873
|
-
</h2>
|
|
2874
|
-
<button id="refresh-btn" class="btn" disabled>
|
|
2875
|
-
<svg id="refresh-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2876
|
-
<polyline points="23 4 23 10 17 10"></polyline>
|
|
2877
|
-
<polyline points="1 20 1 14 7 14"></polyline>
|
|
2878
|
-
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
|
|
2879
|
-
</svg>
|
|
2880
|
-
Refresh
|
|
2881
|
-
</button>
|
|
2882
|
-
</div>
|
|
2883
|
-
<div class="content-area">
|
|
2884
|
-
<div id="data-container" class="empty-state">
|
|
2885
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
2886
|
-
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path>
|
|
2887
|
-
<polyline points="14 2 14 8 20 8"></polyline>
|
|
2888
|
-
</svg>
|
|
2889
|
-
<h3>No Table Selected</h3>
|
|
2890
|
-
<p>Choose a table from the sidebar to view its data</p>
|
|
2891
|
-
</div>
|
|
2892
|
-
</div>
|
|
2893
|
-
</div>
|
|
2894
|
-
|
|
2895
|
-
<script>
|
|
2896
|
-
let currentTable = null;
|
|
2897
|
-
let tablesData = [];
|
|
2898
|
-
let tableSchemas = {};
|
|
2899
|
-
let currentPage = 1;
|
|
2900
|
-
let totalPages = 1;
|
|
2901
|
-
let totalRecords = 0;
|
|
2902
|
-
let pageSize = 25;
|
|
2903
|
-
|
|
2904
|
-
// Format values for the data grid
|
|
2905
|
-
function formatValue(val) {
|
|
2906
|
-
if (val === null || val === undefined) return 'null';
|
|
2907
|
-
|
|
2908
|
-
if (typeof val === 'object') {
|
|
2909
|
-
if (val instanceof Date) {
|
|
2910
|
-
return val.toISOString();
|
|
2911
|
-
}
|
|
2912
|
-
// Handle JSON objects
|
|
2913
|
-
const safeJson = JSON.stringify(val)
|
|
2914
|
-
.replace(/&/g, "&")
|
|
2915
|
-
.replace(/</g, "<")
|
|
2916
|
-
.replace(/>/g, ">");
|
|
2917
|
-
return safeJson;
|
|
2918
|
-
}
|
|
2919
|
-
|
|
2920
|
-
if (typeof val === 'string') {
|
|
2921
|
-
// Escape HTML to prevent XSS
|
|
2922
|
-
const safeStr = String(val)
|
|
2923
|
-
.replace(/&/g, "&")
|
|
2924
|
-
.replace(/</g, "<")
|
|
2925
|
-
.replace(/>/g, ">");
|
|
2926
|
-
return safeStr;
|
|
2927
|
-
}
|
|
2928
|
-
|
|
2929
|
-
return String(val);
|
|
2930
|
-
}
|
|
2931
|
-
|
|
2932
|
-
async function loadTables() {
|
|
2933
|
-
try {
|
|
2934
|
-
const res = await fetch('/api/tables');
|
|
2935
|
-
tablesData = await res.json();
|
|
2936
|
-
|
|
2937
|
-
const list = document.getElementById('table-list');
|
|
2938
|
-
list.innerHTML = '';
|
|
2939
|
-
tableSchemas = {};
|
|
2940
|
-
|
|
2941
|
-
tablesData.forEach(t => {
|
|
2942
|
-
tableSchemas[t.name] = t;
|
|
2943
|
-
const li = document.createElement('li');
|
|
2944
|
-
li.className = 'table-item';
|
|
2945
|
-
li.innerHTML = \`
|
|
2946
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
2947
|
-
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
2948
|
-
<line x1="3" y1="9" x2="21" y2="9"></line>
|
|
2949
|
-
<line x1="9" y1="21" x2="9" y2="9"></line>
|
|
2950
|
-
</svg>
|
|
2951
|
-
\${t.name}
|
|
2952
|
-
\`;
|
|
2953
|
-
li.onclick = () => selectTable(t.name);
|
|
2954
|
-
list.appendChild(li);
|
|
4552
|
+
if (req.method === "GET" && url.pathname === "/htmx/sidebar") {
|
|
4553
|
+
let html = '<ul class="flex flex-col gap-0.5 p-2 m-0 list-none">';
|
|
4554
|
+
schemas2.forEach((s) => {
|
|
4555
|
+
const tableName = s.config.name;
|
|
4556
|
+
html += `
|
|
4557
|
+
<li>
|
|
4558
|
+
<button
|
|
4559
|
+
hx-get="/htmx/tables/${tableName}?page=1&limit=25"
|
|
4560
|
+
hx-target="#data-container"
|
|
4561
|
+
@click="currentTable = '${tableName}'; pageSize = 25"
|
|
4562
|
+
:class="currentTable === '${tableName}' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground'"
|
|
4563
|
+
class="w-full text-left px-3 py-2 rounded-md text-sm font-medium flex items-center gap-2 transition-colors focus:outline-none"
|
|
4564
|
+
>
|
|
4565
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
4566
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
4567
|
+
<line x1="3" y1="9" x2="21" y2="9"></line>
|
|
4568
|
+
<line x1="9" y1="21" x2="9" y2="9"></line>
|
|
4569
|
+
</svg>
|
|
4570
|
+
${tableName}
|
|
4571
|
+
</button>
|
|
4572
|
+
</li>
|
|
4573
|
+
`;
|
|
2955
4574
|
});
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
}
|
|
2959
|
-
}
|
|
2960
|
-
|
|
2961
|
-
async function selectTable(name, page = 1) {
|
|
2962
|
-
currentTable = name;
|
|
2963
|
-
currentPage = page;
|
|
2964
|
-
|
|
2965
|
-
// Update UI active state
|
|
2966
|
-
document.querySelectorAll('.table-item').forEach(el => {
|
|
2967
|
-
if (el.textContent.trim() === name) el.classList.add('active');
|
|
2968
|
-
else el.classList.remove('active');
|
|
2969
|
-
});
|
|
2970
|
-
|
|
2971
|
-
document.getElementById('current-table-name').innerHTML = \`
|
|
2972
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="color: var(--accent-color);">
|
|
2973
|
-
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
2974
|
-
<line x1="3" y1="9" x2="21" y2="9"></line>
|
|
2975
|
-
<line x1="9" y1="21" x2="9" y2="9"></line>
|
|
2976
|
-
</svg>
|
|
2977
|
-
\${name}
|
|
2978
|
-
\`;
|
|
2979
|
-
document.getElementById('refresh-btn').disabled = false;
|
|
2980
|
-
|
|
2981
|
-
const container = document.getElementById('data-container');
|
|
2982
|
-
const existingTable = container.querySelector('.data-grid-container');
|
|
2983
|
-
|
|
2984
|
-
if (existingTable) {
|
|
2985
|
-
// Show loading overlay instead of replacing content
|
|
2986
|
-
existingTable.style.opacity = '0.5';
|
|
2987
|
-
existingTable.style.pointerEvents = 'none';
|
|
2988
|
-
} else {
|
|
2989
|
-
container.innerHTML = \`
|
|
2990
|
-
<div class="empty-state">
|
|
2991
|
-
<svg class="spinning" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2992
|
-
<line x1="12" y1="2" x2="12" y2="6"></line>
|
|
2993
|
-
<line x1="12" y1="18" x2="12" y2="22"></line>
|
|
2994
|
-
<line x1="4.93" y1="4.93" x2="7.76" y2="7.76"></line>
|
|
2995
|
-
<line x1="16.24" y1="16.24" x2="19.07" y2="19.07"></line>
|
|
2996
|
-
<line x1="2" y1="12" x2="6" y2="12"></line>
|
|
2997
|
-
<line x1="18" y1="12" x2="22" y2="12"></line>
|
|
2998
|
-
<line x1="4.93" y1="19.07" x2="7.76" y2="16.24"></line>
|
|
2999
|
-
<line x1="16.24" y1="7.76" x2="19.07" y2="4.93"></line>
|
|
3000
|
-
</svg>
|
|
3001
|
-
<p>Loading data...</p>
|
|
3002
|
-
</div>
|
|
3003
|
-
\`;
|
|
4575
|
+
html += "</ul>";
|
|
4576
|
+
return new Response(html, { headers: { "Content-Type": "text/html" } });
|
|
3004
4577
|
}
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
const
|
|
3008
|
-
if (!
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
const rows = response.data || response;
|
|
3012
|
-
totalRecords = response.total || 0;
|
|
3013
|
-
totalPages = response.totalPages || 1;
|
|
3014
|
-
|
|
3015
|
-
const tableSchema = tableSchemas[name];
|
|
3016
|
-
|
|
3017
|
-
if (rows.length === 0) {
|
|
3018
|
-
container.innerHTML = \`
|
|
3019
|
-
<div class="empty-state">
|
|
3020
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
3021
|
-
<circle cx="12" cy="12" r="10"></circle>
|
|
3022
|
-
<line x1="12" y1="8" x2="12" y2="12"></line>
|
|
3023
|
-
<line x1="12" y1="16" x2="12.01" y2="16"></line>
|
|
3024
|
-
</svg>
|
|
3025
|
-
<h3>Table is Empty</h3>
|
|
3026
|
-
<p>No records found in "\${name}"</p>
|
|
3027
|
-
</div>
|
|
3028
|
-
\`;
|
|
3029
|
-
return;
|
|
3030
|
-
}
|
|
3031
|
-
|
|
3032
|
-
// Use all columns from the actual data to ensure foreign keys and all data are shown
|
|
3033
|
-
let columns = [];
|
|
3034
|
-
const allKeys = new Set();
|
|
3035
|
-
rows.forEach(row => {
|
|
3036
|
-
Object.keys(row).forEach(key => allKeys.add(key));
|
|
3037
|
-
});
|
|
3038
|
-
|
|
3039
|
-
// Try to get type info from schema if available
|
|
3040
|
-
const schemaColMap = {};
|
|
3041
|
-
if (tableSchema && tableSchema.columns && tableSchema.columns.length > 0) {
|
|
3042
|
-
tableSchema.columns.forEach(col => {
|
|
3043
|
-
schemaColMap[col.name] = col;
|
|
3044
|
-
});
|
|
4578
|
+
if (req.method === "GET" && url.pathname.startsWith("/htmx/tables/")) {
|
|
4579
|
+
const tableName = url.pathname.split("/")[3];
|
|
4580
|
+
const schema = schemas2.find((s) => s.config.name === tableName);
|
|
4581
|
+
if (!schema) {
|
|
4582
|
+
return new Response(`<div class="p-4 text-red-500">Table not found</div>`, { status: 404, headers: { "Content-Type": "text/html" } });
|
|
3045
4583
|
}
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
const
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
if (typeof val ===
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
type,
|
|
3067
|
-
primaryKey: schemaCol ? schemaCol.primaryKey : false,
|
|
3068
|
-
foreignKey: schemaCol ? schemaCol.foreignKey : null
|
|
4584
|
+
try {
|
|
4585
|
+
const page = parseInt(url.searchParams.get("page") || "1", 10);
|
|
4586
|
+
const limit = parseInt(url.searchParams.get("limit") || "25", 10);
|
|
4587
|
+
const offset = (page - 1) * limit;
|
|
4588
|
+
const countResult = await db2.select({ count: schema.table }).from(schema.table);
|
|
4589
|
+
const total = Array.isArray(countResult) ? countResult.length : 0;
|
|
4590
|
+
const totalPages = Math.ceil(total / limit) || 1;
|
|
4591
|
+
const data = await db2.select().from(schema.table).limit(limit).offset(offset);
|
|
4592
|
+
const formatValue = (val) => {
|
|
4593
|
+
if (val === null || val === undefined)
|
|
4594
|
+
return '<span class="italic text-muted-foreground">null</span>';
|
|
4595
|
+
if (typeof val === "number")
|
|
4596
|
+
return `<span class="text-foreground">${val}</span>`;
|
|
4597
|
+
if (typeof val === "boolean")
|
|
4598
|
+
return `<span class="text-foreground">${val}</span>`;
|
|
4599
|
+
if (val instanceof Date)
|
|
4600
|
+
return `<span class="text-foreground">${val.toISOString()}</span>`;
|
|
4601
|
+
if (typeof val === "object")
|
|
4602
|
+
return `<span class="text-foreground font-mono text-xs">${JSON.stringify(val).replace(/&/g, "&").replace(/</g, "<")}</span>`;
|
|
4603
|
+
return `<span class="text-foreground">${String(val).replace(/&/g, "&").replace(/</g, "<")}</span>`;
|
|
3069
4604
|
};
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
4605
|
+
if (data.length === 0) {
|
|
4606
|
+
return new Response(`
|
|
4607
|
+
<div class="flex flex-col items-center justify-center h-full w-full text-muted-foreground animate-[fadeIn_0.5s_ease-out]">
|
|
4608
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="w-16 h-16 mb-4 text-muted">
|
|
4609
|
+
<circle cx="12" cy="12" r="10"></circle>
|
|
4610
|
+
<line x1="12" y1="8" x2="12" y2="12"></line>
|
|
4611
|
+
<line x1="12" y1="16" x2="12.01" y2="16"></line>
|
|
4612
|
+
</svg>
|
|
4613
|
+
<h3 class="text-foreground m-0 mb-2 text-lg">Table is Empty</h3>
|
|
4614
|
+
<p class="text-sm">No records found in "${tableName}"</p>
|
|
4615
|
+
</div>
|
|
4616
|
+
`, { headers: { "Content-Type": "text/html" } });
|
|
4617
|
+
}
|
|
4618
|
+
const columns = Object.keys(data[0] || {});
|
|
4619
|
+
let html = '<div class="flex flex-col h-full w-full bg-background">';
|
|
4620
|
+
html += '<div class="flex-1 overflow-auto">';
|
|
4621
|
+
html += '<table class="text-left border-collapse text-sm whitespace-nowrap">';
|
|
4622
|
+
html += "<thead><tr>";
|
|
4623
|
+
columns.forEach((col2) => {
|
|
4624
|
+
const colConfig = schema.config.columns ? schema.config.columns[col2] : null;
|
|
4625
|
+
let typeLabel = colConfig ? colConfig.dataType : "unknown";
|
|
4626
|
+
let indexLabel = "";
|
|
4627
|
+
if (colConfig?.primaryKey) {
|
|
4628
|
+
indexLabel += '<span class="ml-1 text-[10px] bg-emerald-500/20 text-emerald-500 px-1 rounded uppercase" title="Primary Key">PK</span>';
|
|
4629
|
+
}
|
|
4630
|
+
if (colConfig?.unique) {
|
|
4631
|
+
indexLabel += '<span class="ml-1 text-[10px] bg-amber-500/20 text-amber-500 px-1 rounded uppercase" title="Unique">UQ</span>';
|
|
4632
|
+
}
|
|
4633
|
+
if (colConfig?.references) {
|
|
4634
|
+
indexLabel += '<span class="ml-1 text-[10px] bg-yellow-500/20 text-yellow-500 px-1 rounded uppercase" title="Foreign Key">FK</span>';
|
|
4635
|
+
}
|
|
4636
|
+
if (schema.config.indexes) {
|
|
4637
|
+
const isIndexed = schema.config.indexes.some((idx) => idx.columns.includes(col2));
|
|
4638
|
+
if (isIndexed) {
|
|
4639
|
+
indexLabel += '<span class="ml-1 text-[10px] bg-blue-500/20 text-blue-500 px-1 rounded uppercase" title="Indexed">IDX</span>';
|
|
4640
|
+
}
|
|
4641
|
+
}
|
|
4642
|
+
html += `<th class="bg-card border-b border-r border-border px-4 py-2.5 font-medium text-muted-foreground sticky top-0 z-10">
|
|
4643
|
+
<div class="flex flex-col gap-0.5">
|
|
4644
|
+
<span class="text-foreground">${col2}</span>
|
|
4645
|
+
<div class="flex items-center flex-wrap gap-1 mt-0.5">
|
|
4646
|
+
<span class="text-[10px] font-mono text-muted-foreground/70 mr-1">${typeLabel}</span>
|
|
4647
|
+
${indexLabel}
|
|
3081
4648
|
</div>
|
|
3082
|
-
<div class="col-type">\${col.type}</div>
|
|
3083
4649
|
</div>
|
|
3084
|
-
</th
|
|
3085
|
-
\`;
|
|
3086
|
-
});
|
|
3087
|
-
html += '</tr></thead><tbody>';
|
|
3088
|
-
|
|
3089
|
-
rows.forEach(row => {
|
|
3090
|
-
html += '<tr>';
|
|
3091
|
-
columns.forEach(col => {
|
|
3092
|
-
html += \`<td>\${formatValue(row[col.name])}</td>\`;
|
|
4650
|
+
</th>`;
|
|
3093
4651
|
});
|
|
3094
|
-
html +=
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
html += '</div></div>';
|
|
3103
|
-
container.innerHTML = html;
|
|
3104
|
-
|
|
3105
|
-
// Fade in the new content
|
|
3106
|
-
const newTable = container.querySelector('.data-grid-container');
|
|
3107
|
-
if (newTable) {
|
|
3108
|
-
newTable.style.opacity = '0';
|
|
3109
|
-
requestAnimationFrame(() => {
|
|
3110
|
-
newTable.style.transition = 'opacity 0.15s ease';
|
|
3111
|
-
newTable.style.opacity = '1';
|
|
4652
|
+
html += "</tr></thead><tbody>";
|
|
4653
|
+
data.forEach((row) => {
|
|
4654
|
+
html += '<tr class="hover:bg-muted/50 transition-colors">';
|
|
4655
|
+
columns.forEach((col2) => {
|
|
4656
|
+
html += `<td class="border-b border-r border-border px-4 py-2 max-w-[300px] overflow-hidden text-ellipsis">${formatValue(row[col2])}</td>`;
|
|
4657
|
+
});
|
|
4658
|
+
html += "</tr>";
|
|
3112
4659
|
});
|
|
4660
|
+
html += "</tbody></table></div>";
|
|
4661
|
+
const startRecord = (page - 1) * limit + 1;
|
|
4662
|
+
const endRecord = Math.min(page * limit, total);
|
|
4663
|
+
html += `
|
|
4664
|
+
<div class="flex items-center justify-between px-4 py-3 bg-card border-t border-border text-xs text-muted-foreground shrink-0 sticky bottom-0 z-10 w-full">
|
|
4665
|
+
<div class="flex items-center gap-4">
|
|
4666
|
+
<span>${total} records</span>
|
|
4667
|
+
<span>${startRecord}-${endRecord}</span>
|
|
4668
|
+
</div>
|
|
4669
|
+
<div class="flex items-center gap-2">
|
|
4670
|
+
<select
|
|
4671
|
+
name="limit"
|
|
4672
|
+
class="bg-background border border-border text-foreground px-2 py-1.5 rounded-md focus:outline-none focus:ring-1 focus:ring-ring cursor-pointer"
|
|
4673
|
+
@change="pageSize = $event.target.value; htmx.ajax('GET', '/htmx/tables/${tableName}?page=1&limit=' + pageSize, {target: '#data-container'})"
|
|
4674
|
+
>
|
|
4675
|
+
<option value="10" ${limit === 10 ? "selected" : ""}>10</option>
|
|
4676
|
+
<option value="25" ${limit === 25 ? "selected" : ""}>25</option>
|
|
4677
|
+
<option value="50" ${limit === 50 ? "selected" : ""}>50</option>
|
|
4678
|
+
<option value="100" ${limit === 100 ? "selected" : ""}>100</option>
|
|
4679
|
+
</select>
|
|
4680
|
+
|
|
4681
|
+
<button
|
|
4682
|
+
${page <= 1 ? "disabled" : ""}
|
|
4683
|
+
hx-get="/htmx/tables/${tableName}?page=${page - 1}&limit=${limit}"
|
|
4684
|
+
hx-target="#data-container"
|
|
4685
|
+
class="bg-background border border-border text-foreground px-3 py-1.5 rounded-md hover:bg-accent hover:text-accent-foreground disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
4686
|
+
>←</button>
|
|
4687
|
+
|
|
4688
|
+
<span class="min-w-[40px] text-center">${page} / ${totalPages}</span>
|
|
4689
|
+
|
|
4690
|
+
<button
|
|
4691
|
+
${page >= totalPages ? "disabled" : ""}
|
|
4692
|
+
hx-get="/htmx/tables/${tableName}?page=${page + 1}&limit=${limit}"
|
|
4693
|
+
hx-target="#data-container"
|
|
4694
|
+
class="bg-background border border-border text-foreground px-3 py-1.5 rounded-md hover:bg-accent hover:text-accent-foreground disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
4695
|
+
>→</button>
|
|
4696
|
+
</div>
|
|
4697
|
+
</div>
|
|
4698
|
+
`;
|
|
4699
|
+
html += "</div>";
|
|
4700
|
+
return new Response(html, { headers: { "Content-Type": "text/html" } });
|
|
4701
|
+
} catch (e) {
|
|
4702
|
+
return new Response(`
|
|
4703
|
+
<div class="p-6">
|
|
4704
|
+
<div class="bg-red-500/10 border border-red-500/20 text-red-400 p-4 rounded-lg">
|
|
4705
|
+
<h3 class="font-semibold mb-1">Error Loading Data</h3>
|
|
4706
|
+
<p class="text-sm opacity-80">${e.message}</p>
|
|
4707
|
+
</div>
|
|
4708
|
+
</div>
|
|
4709
|
+
`, { headers: { "Content-Type": "text/html" } });
|
|
3113
4710
|
}
|
|
3114
|
-
|
|
3115
|
-
} catch (e) {
|
|
3116
|
-
container.innerHTML = \`
|
|
3117
|
-
<div class="empty-state">
|
|
3118
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
3119
|
-
<circle cx="12" cy="12" r="10"></circle>
|
|
3120
|
-
<line x1="12" y1="8" x2="12" y2="12"></line>
|
|
3121
|
-
<line x1="12" y1="16" x2="12.01" y2="16"></line>
|
|
3122
|
-
</svg>
|
|
3123
|
-
<h3 style="color: #ef4444;">Error Loading Data</h3>
|
|
3124
|
-
<p>\${e.message}</p>
|
|
3125
|
-
</div>
|
|
3126
|
-
\`;
|
|
3127
4711
|
}
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
const endRecord = Math.min(currentPage * pageSize, totalRecords);
|
|
3133
|
-
|
|
3134
|
-
let html = '<div class="pagination">';
|
|
3135
|
-
html += '<div class="pagination-info">';
|
|
3136
|
-
html += \`<span>\${totalRecords} records</span>\`;
|
|
3137
|
-
html += \`<span>\${startRecord}-\${endRecord}</span>\`;
|
|
3138
|
-
html += '</div>';
|
|
3139
|
-
|
|
3140
|
-
html += '<div class="pagination-controls">';
|
|
3141
|
-
|
|
3142
|
-
// Page size selector
|
|
3143
|
-
html += '<select class="page-size-select" onchange="changePageSize(this.value)">';
|
|
3144
|
-
[10, 25, 50, 100].forEach(size => {
|
|
3145
|
-
html += \`<option value="\${size}" \${pageSize === size ? 'selected' : ''}>\${size}</option>\`;
|
|
3146
|
-
});
|
|
3147
|
-
html += '</select>';
|
|
3148
|
-
|
|
3149
|
-
// Previous button
|
|
3150
|
-
html += \`<button class="pagination-btn" onclick="changePage(\${currentPage - 1})" \${currentPage === 1 ? 'disabled' : ''}>\u2190</button>\`;
|
|
3151
|
-
|
|
3152
|
-
// Page indicator
|
|
3153
|
-
html += \`<span style="min-width: 60px; text-align: center;">\${currentPage} / \${totalPages}</span>\`;
|
|
3154
|
-
|
|
3155
|
-
// Next button
|
|
3156
|
-
html += \`<button class="pagination-btn" onclick="changePage(\${currentPage + 1})" \${currentPage === totalPages ? 'disabled' : ''}>\u2192</button>\`;
|
|
3157
|
-
|
|
3158
|
-
html += '</div>';
|
|
3159
|
-
html += '</div>';
|
|
3160
|
-
|
|
3161
|
-
return html;
|
|
3162
|
-
}
|
|
3163
|
-
|
|
3164
|
-
function changePageSize(newSize) {
|
|
3165
|
-
pageSize = parseInt(newSize, 10);
|
|
3166
|
-
currentPage = 1;
|
|
3167
|
-
selectTable(currentTable, currentPage);
|
|
3168
|
-
}
|
|
3169
|
-
|
|
3170
|
-
function changePage(page) {
|
|
3171
|
-
if (page < 1 || page > totalPages) return;
|
|
3172
|
-
selectTable(currentTable, page);
|
|
3173
|
-
}
|
|
3174
|
-
|
|
3175
|
-
document.getElementById('refresh-btn').addEventListener('click', async () => {
|
|
3176
|
-
if (!currentTable) return;
|
|
3177
|
-
|
|
3178
|
-
const icon = document.getElementById('refresh-icon');
|
|
3179
|
-
icon.classList.add('spinning');
|
|
3180
|
-
|
|
3181
|
-
try {
|
|
3182
|
-
await selectTable(currentTable);
|
|
3183
|
-
} catch (e) {
|
|
3184
|
-
console.error("Failed to refresh data", e);
|
|
3185
|
-
} finally {
|
|
3186
|
-
setTimeout(() => { icon.classList.remove('spinning'); }, 500);
|
|
4712
|
+
if (req.method === "GET" && url.pathname === "/") {
|
|
4713
|
+
return new Response(indexHtml, {
|
|
4714
|
+
headers: { "Content-Type": "text/html" }
|
|
4715
|
+
});
|
|
3187
4716
|
}
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
`;
|
|
4717
|
+
return new Response("Not found", { status: 404 });
|
|
4718
|
+
}
|
|
4719
|
+
});
|
|
4720
|
+
intro(import_picocolors10.default.bgCyan(import_picocolors10.default.black(" \uD83D\uDC18 Bungres Studio ")));
|
|
4721
|
+
log.success(`Studio is running at ${import_picocolors10.default.green(`http://localhost:${server.port}`)}`);
|
|
4722
|
+
outro(import_picocolors10.default.gray("Press Ctrl+C to stop"));
|
|
4723
|
+
}
|
|
3196
4724
|
|
|
3197
4725
|
// src/commands/tusky.ts
|
|
3198
|
-
|
|
4726
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
3199
4727
|
async function runTusky(config) {
|
|
3200
4728
|
const schemas = await loadSchemas(config.schema);
|
|
3201
4729
|
const schemaObj = {};
|
|
@@ -3203,40 +4731,23 @@ async function runTusky(config) {
|
|
|
3203
4731
|
schemaObj[s.exportName] = s.table;
|
|
3204
4732
|
}
|
|
3205
4733
|
const db = bungres({ url: config.dbUrl, schema: schemaObj });
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
Database connection established.`);
|
|
3211
|
-
console.log(`
|
|
3212
|
-
Pre-loaded Context:`);
|
|
3213
|
-
console.log(" - db (Bungres Database Client)");
|
|
3214
|
-
for (const s of schemas) {
|
|
3215
|
-
console.log(` - ${s.exportName} (Table)`);
|
|
3216
|
-
}
|
|
3217
|
-
console.log(`
|
|
3218
|
-
Example query: await db.select().from(users)`);
|
|
3219
|
-
console.log(`Type .exit to quit.
|
|
3220
|
-
`);
|
|
3221
|
-
const rl = readline.createInterface({
|
|
3222
|
-
input: process.stdin,
|
|
3223
|
-
output: process.stdout,
|
|
3224
|
-
prompt: "bungres> "
|
|
3225
|
-
});
|
|
4734
|
+
intro(import_picocolors11.default.bgCyan(import_picocolors11.default.black(" \uD83D\uDC18 Bungres REPL (Tusky) ")));
|
|
4735
|
+
log.success(import_picocolors11.default.green("Database connection established."));
|
|
4736
|
+
note(`Example: ${import_picocolors11.default.cyan("db.select().from(users);")}
|
|
4737
|
+
Exit: ${import_picocolors11.default.cyan("exit")}`, "Commands");
|
|
3226
4738
|
globalThis.db = db;
|
|
3227
4739
|
for (const s of schemas) {
|
|
3228
4740
|
globalThis[s.exportName] = s.table;
|
|
3229
4741
|
}
|
|
3230
|
-
|
|
3231
|
-
|
|
4742
|
+
process.stdout.write("bungres> ");
|
|
4743
|
+
for await (const line of console) {
|
|
3232
4744
|
const input = line.trim();
|
|
3233
|
-
if (
|
|
3234
|
-
|
|
3235
|
-
return;
|
|
4745
|
+
if (["exit", ".exit", "quit", ".quit", "exit()", "quit()"].includes(input.toLowerCase())) {
|
|
4746
|
+
break;
|
|
3236
4747
|
}
|
|
3237
4748
|
if (!input) {
|
|
3238
|
-
|
|
3239
|
-
|
|
4749
|
+
process.stdout.write("bungres> ");
|
|
4750
|
+
continue;
|
|
3240
4751
|
}
|
|
3241
4752
|
try {
|
|
3242
4753
|
let code = input;
|
|
@@ -3245,22 +4756,32 @@ Example query: await db.select().from(users)`);
|
|
|
3245
4756
|
console.log(`(Running as raw SQL: await db.raw(\`${input}\`))`);
|
|
3246
4757
|
code = `(async () => { return await db.raw(\`${input}\`); })()`;
|
|
3247
4758
|
} else if (input.includes("await ")) {
|
|
3248
|
-
code = `(async () => { return ${input}; })()`;
|
|
4759
|
+
code = `(async () => { return await ${input}; })()`;
|
|
3249
4760
|
}
|
|
4761
|
+
const start = performance.now();
|
|
3250
4762
|
const result = await eval(code);
|
|
3251
|
-
|
|
4763
|
+
const end = performance.now();
|
|
4764
|
+
const duration = (end - start).toFixed(2);
|
|
4765
|
+
if (Array.isArray(result) && result.length > 0 && typeof result[0] === "object") {
|
|
4766
|
+
console.table(result);
|
|
4767
|
+
} else {
|
|
4768
|
+
console.log(result);
|
|
4769
|
+
}
|
|
4770
|
+
console.log(`
|
|
4771
|
+
(Execution time: ${duration}ms)`);
|
|
3252
4772
|
} catch (err) {
|
|
3253
4773
|
console.error(err.message || err);
|
|
3254
4774
|
}
|
|
3255
|
-
|
|
3256
|
-
}
|
|
3257
|
-
|
|
3258
|
-
process.exit(0);
|
|
3259
|
-
});
|
|
4775
|
+
process.stdout.write("bungres> ");
|
|
4776
|
+
}
|
|
4777
|
+
process.exit(0);
|
|
3260
4778
|
}
|
|
3261
4779
|
|
|
4780
|
+
// src/cli.ts
|
|
4781
|
+
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
4782
|
+
|
|
3262
4783
|
// src/config.ts
|
|
3263
|
-
import { join as
|
|
4784
|
+
import { join as join7, resolve as resolve8 } from "path";
|
|
3264
4785
|
var CONFIG_FILES = [
|
|
3265
4786
|
"bungres.config.ts",
|
|
3266
4787
|
"bungres.config.js",
|
|
@@ -3270,9 +4791,9 @@ var CONFIG_FILES = [
|
|
|
3270
4791
|
async function loadConfig(cwd = process.cwd()) {
|
|
3271
4792
|
let userConfig = {};
|
|
3272
4793
|
for (const file of CONFIG_FILES) {
|
|
3273
|
-
const configPath =
|
|
4794
|
+
const configPath = join7(cwd, file);
|
|
3274
4795
|
if (await Bun.file(configPath).exists()) {
|
|
3275
|
-
const mod = await import(
|
|
4796
|
+
const mod = await import(resolve8(configPath));
|
|
3276
4797
|
userConfig = mod.default ?? mod;
|
|
3277
4798
|
break;
|
|
3278
4799
|
}
|
|
@@ -3334,7 +4855,7 @@ async function ensureDatabase2(dbUrl) {
|
|
|
3334
4855
|
// package.json
|
|
3335
4856
|
var package_default = {
|
|
3336
4857
|
name: "@bungres/kit",
|
|
3337
|
-
version: "0.
|
|
4858
|
+
version: "1.0.0",
|
|
3338
4859
|
description: "CLI toolkit for @bungres/orm \u2014 migrate, push, generate, pull",
|
|
3339
4860
|
license: "MIT",
|
|
3340
4861
|
engines: {
|
|
@@ -3384,7 +4905,9 @@ var package_default = {
|
|
|
3384
4905
|
test: "bun test"
|
|
3385
4906
|
},
|
|
3386
4907
|
dependencies: {
|
|
3387
|
-
"@bungres/orm": "
|
|
4908
|
+
"@bungres/orm": "^1.0.0",
|
|
4909
|
+
"@clack/prompts": "^1.7.0",
|
|
4910
|
+
picocolors: "^1.1.1"
|
|
3388
4911
|
},
|
|
3389
4912
|
devDependencies: {
|
|
3390
4913
|
"bun-types": "latest",
|
|
@@ -3395,15 +4918,16 @@ var package_default = {
|
|
|
3395
4918
|
// src/cli.ts
|
|
3396
4919
|
var VERSION = package_default.version;
|
|
3397
4920
|
var HELP = `
|
|
3398
|
-
${
|
|
4921
|
+
${import_picocolors12.default.cyan("\uD83D\uDC18 Bungres ORM CLI")} v${VERSION}
|
|
3399
4922
|
|
|
3400
|
-
${
|
|
4923
|
+
${import_picocolors12.default.yellow("Usage:")}
|
|
3401
4924
|
bungres <command> [options]
|
|
3402
4925
|
|
|
3403
|
-
${
|
|
4926
|
+
${import_picocolors12.default.yellow("Commands:")}
|
|
3404
4927
|
init Initialize bungres project with config file and db folder structure
|
|
3405
4928
|
generate Generate SQL migration files from your schema definitions
|
|
3406
4929
|
migrate Run pending migration files against the database
|
|
4930
|
+
rollback Revert the last applied migration
|
|
3407
4931
|
push Apply schema directly to the DB (no migration files, dev mode)
|
|
3408
4932
|
pull Introspect the database and generate TypeScript schema
|
|
3409
4933
|
status Show applied vs. pending migrations
|
|
@@ -3414,17 +4938,18 @@ ${colorize("Commands:", "yellow")}
|
|
|
3414
4938
|
tusky Boot up a Node REPL connected to the database with schema loaded
|
|
3415
4939
|
drop Drop all tables defined in the schema (dev only)
|
|
3416
4940
|
|
|
3417
|
-
${
|
|
4941
|
+
${import_picocolors12.default.yellow("Options:")}
|
|
3418
4942
|
--config Path to config file (default: bungres.config.ts)
|
|
3419
4943
|
--verbose Enable verbose SQL logging
|
|
3420
4944
|
--force Skip confirmation prompts (use with drop)
|
|
3421
4945
|
--version Show version
|
|
3422
4946
|
--help Show this help
|
|
3423
4947
|
|
|
3424
|
-
${
|
|
4948
|
+
${import_picocolors12.default.yellow("Examples:")}
|
|
3425
4949
|
bungres init
|
|
3426
4950
|
bungres generate
|
|
3427
4951
|
bungres migrate
|
|
4952
|
+
bungres rollback
|
|
3428
4953
|
bungres push
|
|
3429
4954
|
bungres pull
|
|
3430
4955
|
bungres status
|
|
@@ -3454,7 +4979,7 @@ async function main() {
|
|
|
3454
4979
|
const config2 = await loadConfig(process.cwd());
|
|
3455
4980
|
if (flags.verbose)
|
|
3456
4981
|
config2.verbose = true;
|
|
3457
|
-
if (command && ["migrate", "push", "drop", "status", "fresh", "refresh"].includes(command)) {
|
|
4982
|
+
if (command && ["migrate", "rollback", "push", "drop", "status", "fresh", "refresh"].includes(command)) {
|
|
3458
4983
|
await ensureDatabase2(config2.dbUrl);
|
|
3459
4984
|
}
|
|
3460
4985
|
switch (command) {
|
|
@@ -3464,6 +4989,9 @@ async function main() {
|
|
|
3464
4989
|
case "migrate":
|
|
3465
4990
|
await runMigrate(config2);
|
|
3466
4991
|
break;
|
|
4992
|
+
case "rollback":
|
|
4993
|
+
await runRollback(config2);
|
|
4994
|
+
break;
|
|
3467
4995
|
case "push":
|
|
3468
4996
|
await runPush(config2, { force: !!flags.force });
|
|
3469
4997
|
break;
|
|
@@ -3500,14 +5028,14 @@ async function main() {
|
|
|
3500
5028
|
}
|
|
3501
5029
|
function parseFlags(args) {
|
|
3502
5030
|
const flags = {};
|
|
3503
|
-
for (let
|
|
3504
|
-
const arg = args[
|
|
5031
|
+
for (let i2 = 0;i2 < args.length; i2++) {
|
|
5032
|
+
const arg = args[i2];
|
|
3505
5033
|
if (arg?.startsWith("--")) {
|
|
3506
5034
|
const key = arg.slice(2);
|
|
3507
|
-
const next = args[
|
|
5035
|
+
const next = args[i2 + 1];
|
|
3508
5036
|
if (next && !next.startsWith("--")) {
|
|
3509
5037
|
flags[key] = next;
|
|
3510
|
-
|
|
5038
|
+
i2++;
|
|
3511
5039
|
} else {
|
|
3512
5040
|
flags[key] = true;
|
|
3513
5041
|
}
|