@lastshotlabs/snapshot 0.1.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 +1598 -0
- package/dist/cli.js +4529 -0
- package/dist/index.cjs +1135 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +396 -0
- package/dist/index.d.ts +396 -0
- package/dist/index.js +1106 -0
- package/dist/index.js.map +1 -0
- package/dist/vite.cjs +1186 -0
- package/dist/vite.d.cts +18 -0
- package/dist/vite.d.ts +18 -0
- package/dist/vite.js +1174 -0
- package/package.json +67 -0
package/dist/vite.js
ADDED
|
@@ -0,0 +1,1174 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// node_modules/sisteransi/src/index.js
|
|
28
|
+
var require_src = __commonJS({
|
|
29
|
+
"node_modules/sisteransi/src/index.js"(exports, module) {
|
|
30
|
+
"use strict";
|
|
31
|
+
var ESC = "\x1B";
|
|
32
|
+
var CSI = `${ESC}[`;
|
|
33
|
+
var beep = "\x07";
|
|
34
|
+
var cursor = {
|
|
35
|
+
to(x2, y) {
|
|
36
|
+
if (!y) return `${CSI}${x2 + 1}G`;
|
|
37
|
+
return `${CSI}${y + 1};${x2 + 1}H`;
|
|
38
|
+
},
|
|
39
|
+
move(x2, y) {
|
|
40
|
+
let ret = "";
|
|
41
|
+
if (x2 < 0) ret += `${CSI}${-x2}D`;
|
|
42
|
+
else if (x2 > 0) ret += `${CSI}${x2}C`;
|
|
43
|
+
if (y < 0) ret += `${CSI}${-y}A`;
|
|
44
|
+
else if (y > 0) ret += `${CSI}${y}B`;
|
|
45
|
+
return ret;
|
|
46
|
+
},
|
|
47
|
+
up: (count = 1) => `${CSI}${count}A`,
|
|
48
|
+
down: (count = 1) => `${CSI}${count}B`,
|
|
49
|
+
forward: (count = 1) => `${CSI}${count}C`,
|
|
50
|
+
backward: (count = 1) => `${CSI}${count}D`,
|
|
51
|
+
nextLine: (count = 1) => `${CSI}E`.repeat(count),
|
|
52
|
+
prevLine: (count = 1) => `${CSI}F`.repeat(count),
|
|
53
|
+
left: `${CSI}G`,
|
|
54
|
+
hide: `${CSI}?25l`,
|
|
55
|
+
show: `${CSI}?25h`,
|
|
56
|
+
save: `${ESC}7`,
|
|
57
|
+
restore: `${ESC}8`
|
|
58
|
+
};
|
|
59
|
+
var scroll = {
|
|
60
|
+
up: (count = 1) => `${CSI}S`.repeat(count),
|
|
61
|
+
down: (count = 1) => `${CSI}T`.repeat(count)
|
|
62
|
+
};
|
|
63
|
+
var erase = {
|
|
64
|
+
screen: `${CSI}2J`,
|
|
65
|
+
up: (count = 1) => `${CSI}1J`.repeat(count),
|
|
66
|
+
down: (count = 1) => `${CSI}J`.repeat(count),
|
|
67
|
+
line: `${CSI}2K`,
|
|
68
|
+
lineEnd: `${CSI}K`,
|
|
69
|
+
lineStart: `${CSI}1K`,
|
|
70
|
+
lines(count) {
|
|
71
|
+
let clear = "";
|
|
72
|
+
for (let i = 0; i < count; i++)
|
|
73
|
+
clear += this.line + (i < count - 1 ? cursor.up() : "");
|
|
74
|
+
if (count)
|
|
75
|
+
clear += cursor.left;
|
|
76
|
+
return clear;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
module.exports = { cursor, scroll, erase, beep };
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// src/vite/index.ts
|
|
84
|
+
import path2 from "path";
|
|
85
|
+
|
|
86
|
+
// src/cli/sync.ts
|
|
87
|
+
import fs from "fs/promises";
|
|
88
|
+
import path from "path";
|
|
89
|
+
import { createHash } from "crypto";
|
|
90
|
+
|
|
91
|
+
// node_modules/@clack/core/dist/index.mjs
|
|
92
|
+
var import_sisteransi = __toESM(require_src(), 1);
|
|
93
|
+
import { styleText as D } from "util";
|
|
94
|
+
import { stdout as R, stdin as q } from "process";
|
|
95
|
+
import * as k from "readline";
|
|
96
|
+
import ot from "readline";
|
|
97
|
+
import { ReadStream as J } from "tty";
|
|
98
|
+
var P = new RegExp("[\\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");
|
|
99
|
+
var ct = new RegExp("\\p{M}+", "gu");
|
|
100
|
+
var ft = { limit: 1 / 0, ellipsis: "" };
|
|
101
|
+
var pt = { limit: 1 / 0, ellipsis: "", ellipsisWidth: 0 };
|
|
102
|
+
var j = "\x07";
|
|
103
|
+
var Q = "[";
|
|
104
|
+
var dt = "]";
|
|
105
|
+
var U = `${dt}8;;`;
|
|
106
|
+
var et = new RegExp(`(?:\\${Q}(?<code>\\d+)m|\\${U}(?<uri>.*)${j})`, "y");
|
|
107
|
+
var At = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
108
|
+
var _ = { actions: new Set(At), aliases: /* @__PURE__ */ new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["", "cancel"], ["escape", "cancel"]]), messages: { cancel: "Canceled", error: "Something went wrong" }, withGuide: true };
|
|
109
|
+
function H(t2, e) {
|
|
110
|
+
if (typeof t2 == "string") return _.aliases.get(t2) === e;
|
|
111
|
+
for (const s of t2) if (s !== void 0 && H(s, e)) return true;
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
var bt = globalThis.process.platform.startsWith("win");
|
|
115
|
+
function xt({ input: t2 = q, output: e = R, overwrite: s = true, hideCursor: i = true } = {}) {
|
|
116
|
+
const r = k.createInterface({ input: t2, output: e, prompt: "", tabSize: 1 });
|
|
117
|
+
k.emitKeypressEvents(t2, r), t2 instanceof J && t2.isTTY && t2.setRawMode(true);
|
|
118
|
+
const n = (u, { name: a, sequence: l }) => {
|
|
119
|
+
const E = String(u);
|
|
120
|
+
if (H([E, a, l], "cancel")) {
|
|
121
|
+
i && e.write(import_sisteransi.cursor.show), process.exit(0);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (!s) return;
|
|
125
|
+
const g = a === "return" ? 0 : -1, m = a === "return" ? -1 : 0;
|
|
126
|
+
k.moveCursor(e, g, m, () => {
|
|
127
|
+
k.clearLine(e, 1, () => {
|
|
128
|
+
t2.once("keypress", n);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
return i && e.write(import_sisteransi.cursor.hide), t2.once("keypress", n), () => {
|
|
133
|
+
t2.off("keypress", n), i && e.write(import_sisteransi.cursor.show), t2 instanceof J && t2.isTTY && !bt && t2.setRawMode(false), r.terminal = false, r.close();
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
var rt = (t2) => "columns" in t2 && typeof t2.columns == "number" ? t2.columns : 80;
|
|
137
|
+
|
|
138
|
+
// node_modules/@clack/prompts/dist/index.mjs
|
|
139
|
+
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
140
|
+
import { styleText as t, stripVTControlCharacters as ue } from "util";
|
|
141
|
+
import N2 from "process";
|
|
142
|
+
import { readdirSync as $t2, existsSync as dt2, lstatSync as xe } from "fs";
|
|
143
|
+
import { dirname as _e, join as ht } from "path";
|
|
144
|
+
function pt2() {
|
|
145
|
+
return N2.platform !== "win32" ? N2.env.TERM !== "linux" : !!N2.env.CI || !!N2.env.WT_SESSION || !!N2.env.TERMINUS_SUBLIME || N2.env.ConEmuTask === "{cmd::Cmder}" || N2.env.TERM_PROGRAM === "Terminus-Sublime" || N2.env.TERM_PROGRAM === "vscode" || N2.env.TERM === "xterm-256color" || N2.env.TERM === "alacritty" || N2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
146
|
+
}
|
|
147
|
+
var ee = pt2();
|
|
148
|
+
var ce = () => process.env.CI === "true";
|
|
149
|
+
var I2 = (e, r) => ee ? e : r;
|
|
150
|
+
var Re = I2("\u25C6", "*");
|
|
151
|
+
var $e = I2("\u25A0", "x");
|
|
152
|
+
var de = I2("\u25B2", "x");
|
|
153
|
+
var V = I2("\u25C7", "o");
|
|
154
|
+
var he = I2("\u250C", "T");
|
|
155
|
+
var h = I2("\u2502", "|");
|
|
156
|
+
var x = I2("\u2514", "\u2014");
|
|
157
|
+
var Oe = I2("\u2510", "T");
|
|
158
|
+
var Pe = I2("\u2518", "\u2014");
|
|
159
|
+
var z = I2("\u25CF", ">");
|
|
160
|
+
var H2 = I2("\u25CB", " ");
|
|
161
|
+
var te = I2("\u25FB", "[\u2022]");
|
|
162
|
+
var U2 = I2("\u25FC", "[+]");
|
|
163
|
+
var q2 = I2("\u25FB", "[ ]");
|
|
164
|
+
var Ne = I2("\u25AA", "\u2022");
|
|
165
|
+
var se = I2("\u2500", "-");
|
|
166
|
+
var pe = I2("\u256E", "+");
|
|
167
|
+
var We = I2("\u251C", "+");
|
|
168
|
+
var me = I2("\u256F", "+");
|
|
169
|
+
var ge = I2("\u2570", "+");
|
|
170
|
+
var Ge = I2("\u256D", "+");
|
|
171
|
+
var fe = I2("\u25CF", "\u2022");
|
|
172
|
+
var Fe = I2("\u25C6", "*");
|
|
173
|
+
var ye = I2("\u25B2", "!");
|
|
174
|
+
var Ee = I2("\u25A0", "x");
|
|
175
|
+
var mt = (e) => e === 161 || e === 164 || e === 167 || e === 168 || e === 170 || e === 173 || e === 174 || e >= 176 && e <= 180 || e >= 182 && e <= 186 || e >= 188 && e <= 191 || e === 198 || e === 208 || e === 215 || e === 216 || e >= 222 && e <= 225 || e === 230 || e >= 232 && e <= 234 || e === 236 || e === 237 || e === 240 || e === 242 || e === 243 || e >= 247 && e <= 250 || e === 252 || e === 254 || e === 257 || e === 273 || e === 275 || e === 283 || e === 294 || e === 295 || e === 299 || e >= 305 && e <= 307 || e === 312 || e >= 319 && e <= 322 || e === 324 || e >= 328 && e <= 331 || e === 333 || e === 338 || e === 339 || e === 358 || e === 359 || e === 363 || e === 462 || e === 464 || e === 466 || e === 468 || e === 470 || e === 472 || e === 474 || e === 476 || e === 593 || e === 609 || e === 708 || e === 711 || e >= 713 && e <= 715 || e === 717 || e === 720 || e >= 728 && e <= 731 || e === 733 || e === 735 || e >= 768 && e <= 879 || e >= 913 && e <= 929 || e >= 931 && e <= 937 || e >= 945 && e <= 961 || e >= 963 && e <= 969 || e === 1025 || e >= 1040 && e <= 1103 || e === 1105 || e === 8208 || e >= 8211 && e <= 8214 || e === 8216 || e === 8217 || e === 8220 || e === 8221 || e >= 8224 && e <= 8226 || e >= 8228 && e <= 8231 || e === 8240 || e === 8242 || e === 8243 || e === 8245 || e === 8251 || e === 8254 || e === 8308 || e === 8319 || e >= 8321 && e <= 8324 || e === 8364 || e === 8451 || e === 8453 || e === 8457 || e === 8467 || e === 8470 || e === 8481 || e === 8482 || e === 8486 || e === 8491 || e === 8531 || e === 8532 || e >= 8539 && e <= 8542 || e >= 8544 && e <= 8555 || e >= 8560 && e <= 8569 || e === 8585 || e >= 8592 && e <= 8601 || e === 8632 || e === 8633 || e === 8658 || e === 8660 || e === 8679 || e === 8704 || e === 8706 || e === 8707 || e === 8711 || e === 8712 || e === 8715 || e === 8719 || e === 8721 || e === 8725 || e === 8730 || e >= 8733 && e <= 8736 || e === 8739 || e === 8741 || e >= 8743 && e <= 8748 || e === 8750 || e >= 8756 && e <= 8759 || e === 8764 || e === 8765 || e === 8776 || e === 8780 || e === 8786 || e === 8800 || e === 8801 || e >= 8804 && e <= 8807 || e === 8810 || e === 8811 || e === 8814 || e === 8815 || e === 8834 || e === 8835 || e === 8838 || e === 8839 || e === 8853 || e === 8857 || e === 8869 || e === 8895 || e === 8978 || e >= 9312 && e <= 9449 || e >= 9451 && e <= 9547 || e >= 9552 && e <= 9587 || e >= 9600 && e <= 9615 || e >= 9618 && e <= 9621 || e === 9632 || e === 9633 || e >= 9635 && e <= 9641 || e === 9650 || e === 9651 || e === 9654 || e === 9655 || e === 9660 || e === 9661 || e === 9664 || e === 9665 || e >= 9670 && e <= 9672 || e === 9675 || e >= 9678 && e <= 9681 || e >= 9698 && e <= 9701 || e === 9711 || e === 9733 || e === 9734 || e === 9737 || e === 9742 || e === 9743 || e === 9756 || e === 9758 || e === 9792 || e === 9794 || e === 9824 || e === 9825 || e >= 9827 && e <= 9829 || e >= 9831 && e <= 9834 || e === 9836 || e === 9837 || e === 9839 || e === 9886 || e === 9887 || e === 9919 || e >= 9926 && e <= 9933 || e >= 9935 && e <= 9939 || e >= 9941 && e <= 9953 || e === 9955 || e === 9960 || e === 9961 || e >= 9963 && e <= 9969 || e === 9972 || e >= 9974 && e <= 9977 || e === 9979 || e === 9980 || e === 9982 || e === 9983 || e === 10045 || e >= 10102 && e <= 10111 || e >= 11094 && e <= 11097 || e >= 12872 && e <= 12879 || e >= 57344 && e <= 63743 || e >= 65024 && e <= 65039 || e === 65533 || e >= 127232 && e <= 127242 || e >= 127248 && e <= 127277 || e >= 127280 && e <= 127337 || e >= 127344 && e <= 127373 || e === 127375 || e === 127376 || e >= 127387 && e <= 127404 || e >= 917760 && e <= 917999 || e >= 983040 && e <= 1048573 || e >= 1048576 && e <= 1114109;
|
|
176
|
+
var gt = (e) => e === 12288 || e >= 65281 && e <= 65376 || e >= 65504 && e <= 65510;
|
|
177
|
+
var ft2 = (e) => e >= 4352 && e <= 4447 || e === 8986 || e === 8987 || e === 9001 || e === 9002 || e >= 9193 && e <= 9196 || e === 9200 || e === 9203 || e === 9725 || e === 9726 || e === 9748 || e === 9749 || e >= 9800 && e <= 9811 || e === 9855 || e === 9875 || e === 9889 || e === 9898 || e === 9899 || e === 9917 || e === 9918 || e === 9924 || e === 9925 || e === 9934 || e === 9940 || e === 9962 || e === 9970 || e === 9971 || e === 9973 || e === 9978 || e === 9981 || e === 9989 || e === 9994 || e === 9995 || e === 10024 || e === 10060 || e === 10062 || e >= 10067 && e <= 10069 || e === 10071 || e >= 10133 && e <= 10135 || e === 10160 || e === 10175 || e === 11035 || e === 11036 || e === 11088 || e === 11093 || e >= 11904 && e <= 11929 || e >= 11931 && e <= 12019 || e >= 12032 && e <= 12245 || e >= 12272 && e <= 12287 || e >= 12289 && e <= 12350 || e >= 12353 && e <= 12438 || e >= 12441 && e <= 12543 || e >= 12549 && e <= 12591 || e >= 12593 && e <= 12686 || e >= 12688 && e <= 12771 || e >= 12783 && e <= 12830 || e >= 12832 && e <= 12871 || e >= 12880 && e <= 19903 || e >= 19968 && e <= 42124 || e >= 42128 && e <= 42182 || e >= 43360 && e <= 43388 || e >= 44032 && e <= 55203 || e >= 63744 && e <= 64255 || e >= 65040 && e <= 65049 || e >= 65072 && e <= 65106 || e >= 65108 && e <= 65126 || e >= 65128 && e <= 65131 || e >= 94176 && e <= 94180 || e === 94192 || e === 94193 || e >= 94208 && e <= 100343 || e >= 100352 && e <= 101589 || e >= 101632 && e <= 101640 || e >= 110576 && e <= 110579 || e >= 110581 && e <= 110587 || e === 110589 || e === 110590 || e >= 110592 && e <= 110882 || e === 110898 || e >= 110928 && e <= 110930 || e === 110933 || e >= 110948 && e <= 110951 || e >= 110960 && e <= 111355 || e === 126980 || e === 127183 || e === 127374 || e >= 127377 && e <= 127386 || e >= 127488 && e <= 127490 || e >= 127504 && e <= 127547 || e >= 127552 && e <= 127560 || e === 127568 || e === 127569 || e >= 127584 && e <= 127589 || e >= 127744 && e <= 127776 || e >= 127789 && e <= 127797 || e >= 127799 && e <= 127868 || e >= 127870 && e <= 127891 || e >= 127904 && e <= 127946 || e >= 127951 && e <= 127955 || e >= 127968 && e <= 127984 || e === 127988 || e >= 127992 && e <= 128062 || e === 128064 || e >= 128066 && e <= 128252 || e >= 128255 && e <= 128317 || e >= 128331 && e <= 128334 || e >= 128336 && e <= 128359 || e === 128378 || e === 128405 || e === 128406 || e === 128420 || e >= 128507 && e <= 128591 || e >= 128640 && e <= 128709 || e === 128716 || e >= 128720 && e <= 128722 || e >= 128725 && e <= 128727 || e >= 128732 && e <= 128735 || e === 128747 || e === 128748 || e >= 128756 && e <= 128764 || e >= 128992 && e <= 129003 || e === 129008 || e >= 129292 && e <= 129338 || e >= 129340 && e <= 129349 || e >= 129351 && e <= 129535 || e >= 129648 && e <= 129660 || e >= 129664 && e <= 129672 || e >= 129680 && e <= 129725 || e >= 129727 && e <= 129733 || e >= 129742 && e <= 129755 || e >= 129760 && e <= 129768 || e >= 129776 && e <= 129784 || e >= 131072 && e <= 196605 || e >= 196608 && e <= 262141;
|
|
178
|
+
var we = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/y;
|
|
179
|
+
var re = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
|
|
180
|
+
var ie = /\t{1,1000}/y;
|
|
181
|
+
var Ae = new RegExp("[\\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");
|
|
182
|
+
var ne = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
|
|
183
|
+
var Ft = new RegExp("\\p{M}+", "gu");
|
|
184
|
+
var yt2 = { limit: 1 / 0, ellipsis: "" };
|
|
185
|
+
var Le = (e, r = {}, s = {}) => {
|
|
186
|
+
const i = r.limit ?? 1 / 0, a = r.ellipsis ?? "", o = r?.ellipsisWidth ?? (a ? Le(a, yt2, s).width : 0), u = s.ansiWidth ?? 0, l = s.controlWidth ?? 0, n = s.tabWidth ?? 8, c = s.ambiguousWidth ?? 1, p = s.emojiWidth ?? 2, f = s.fullWidthWidth ?? 2, g = s.regularWidth ?? 1, E = s.wideWidth ?? 2;
|
|
187
|
+
let $ = 0, m = 0, d = e.length, F = 0, y = false, v = d, C = Math.max(0, i - o), A = 0, b = 0, w = 0, S = 0;
|
|
188
|
+
e: for (; ; ) {
|
|
189
|
+
if (b > A || m >= d && m > $) {
|
|
190
|
+
const T = e.slice(A, b) || e.slice($, m);
|
|
191
|
+
F = 0;
|
|
192
|
+
for (const M of T.replaceAll(Ft, "")) {
|
|
193
|
+
const O = M.codePointAt(0) || 0;
|
|
194
|
+
if (gt(O) ? S = f : ft2(O) ? S = E : c !== g && mt(O) ? S = c : S = g, w + S > C && (v = Math.min(v, Math.max(A, $) + F)), w + S > i) {
|
|
195
|
+
y = true;
|
|
196
|
+
break e;
|
|
197
|
+
}
|
|
198
|
+
F += M.length, w += S;
|
|
199
|
+
}
|
|
200
|
+
A = b = 0;
|
|
201
|
+
}
|
|
202
|
+
if (m >= d) break;
|
|
203
|
+
if (ne.lastIndex = m, ne.test(e)) {
|
|
204
|
+
if (F = ne.lastIndex - m, S = F * g, w + S > C && (v = Math.min(v, m + Math.floor((C - w) / g))), w + S > i) {
|
|
205
|
+
y = true;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
w += S, A = $, b = m, m = $ = ne.lastIndex;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (we.lastIndex = m, we.test(e)) {
|
|
212
|
+
if (w + u > C && (v = Math.min(v, m)), w + u > i) {
|
|
213
|
+
y = true;
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
w += u, A = $, b = m, m = $ = we.lastIndex;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (re.lastIndex = m, re.test(e)) {
|
|
220
|
+
if (F = re.lastIndex - m, S = F * l, w + S > C && (v = Math.min(v, m + Math.floor((C - w) / l))), w + S > i) {
|
|
221
|
+
y = true;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
w += S, A = $, b = m, m = $ = re.lastIndex;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (ie.lastIndex = m, ie.test(e)) {
|
|
228
|
+
if (F = ie.lastIndex - m, S = F * n, w + S > C && (v = Math.min(v, m + Math.floor((C - w) / n))), w + S > i) {
|
|
229
|
+
y = true;
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
w += S, A = $, b = m, m = $ = ie.lastIndex;
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (Ae.lastIndex = m, Ae.test(e)) {
|
|
236
|
+
if (w + p > C && (v = Math.min(v, m)), w + p > i) {
|
|
237
|
+
y = true;
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
w += p, A = $, b = m, m = $ = Ae.lastIndex;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
m += 1;
|
|
244
|
+
}
|
|
245
|
+
return { width: y ? C : w, index: y ? v : d, truncated: y, ellipsed: y && i >= o };
|
|
246
|
+
};
|
|
247
|
+
var Et = { limit: 1 / 0, ellipsis: "", ellipsisWidth: 0 };
|
|
248
|
+
var D2 = (e, r = {}) => Le(e, Et, r).width;
|
|
249
|
+
var ae = "\x1B";
|
|
250
|
+
var je = "\x9B";
|
|
251
|
+
var vt = 39;
|
|
252
|
+
var Ce = "\x07";
|
|
253
|
+
var ke = "[";
|
|
254
|
+
var wt = "]";
|
|
255
|
+
var Ve = "m";
|
|
256
|
+
var Se = `${wt}8;;`;
|
|
257
|
+
var He = new RegExp(`(?:\\${ke}(?<code>\\d+)m|\\${Se}(?<uri>.*)${Ce})`, "y");
|
|
258
|
+
var At2 = (e) => {
|
|
259
|
+
if (e >= 30 && e <= 37 || e >= 90 && e <= 97) return 39;
|
|
260
|
+
if (e >= 40 && e <= 47 || e >= 100 && e <= 107) return 49;
|
|
261
|
+
if (e === 1 || e === 2) return 22;
|
|
262
|
+
if (e === 3) return 23;
|
|
263
|
+
if (e === 4) return 24;
|
|
264
|
+
if (e === 7) return 27;
|
|
265
|
+
if (e === 8) return 28;
|
|
266
|
+
if (e === 9) return 29;
|
|
267
|
+
if (e === 0) return 0;
|
|
268
|
+
};
|
|
269
|
+
var Ue = (e) => `${ae}${ke}${e}${Ve}`;
|
|
270
|
+
var Ke = (e) => `${ae}${Se}${e}${Ce}`;
|
|
271
|
+
var Ct2 = (e) => e.map((r) => D2(r));
|
|
272
|
+
var Ie = (e, r, s) => {
|
|
273
|
+
const i = r[Symbol.iterator]();
|
|
274
|
+
let a = false, o = false, u = e.at(-1), l = u === void 0 ? 0 : D2(u), n = i.next(), c = i.next(), p = 0;
|
|
275
|
+
for (; !n.done; ) {
|
|
276
|
+
const f = n.value, g = D2(f);
|
|
277
|
+
l + g <= s ? e[e.length - 1] += f : (e.push(f), l = 0), (f === ae || f === je) && (a = true, o = r.startsWith(Se, p + 1)), a ? o ? f === Ce && (a = false, o = false) : f === Ve && (a = false) : (l += g, l === s && !c.done && (e.push(""), l = 0)), n = c, c = i.next(), p += f.length;
|
|
278
|
+
}
|
|
279
|
+
u = e.at(-1), !l && u !== void 0 && u.length > 0 && e.length > 1 && (e[e.length - 2] += e.pop());
|
|
280
|
+
};
|
|
281
|
+
var St = (e) => {
|
|
282
|
+
const r = e.split(" ");
|
|
283
|
+
let s = r.length;
|
|
284
|
+
for (; s > 0 && !(D2(r[s - 1]) > 0); ) s--;
|
|
285
|
+
return s === r.length ? e : r.slice(0, s).join(" ") + r.slice(s).join("");
|
|
286
|
+
};
|
|
287
|
+
var It2 = (e, r, s = {}) => {
|
|
288
|
+
if (s.trim !== false && e.trim() === "") return "";
|
|
289
|
+
let i = "", a, o;
|
|
290
|
+
const u = e.split(" "), l = Ct2(u);
|
|
291
|
+
let n = [""];
|
|
292
|
+
for (const [$, m] of u.entries()) {
|
|
293
|
+
s.trim !== false && (n[n.length - 1] = (n.at(-1) ?? "").trimStart());
|
|
294
|
+
let d = D2(n.at(-1) ?? "");
|
|
295
|
+
if ($ !== 0 && (d >= r && (s.wordWrap === false || s.trim === false) && (n.push(""), d = 0), (d > 0 || s.trim === false) && (n[n.length - 1] += " ", d++)), s.hard && l[$] > r) {
|
|
296
|
+
const F = r - d, y = 1 + Math.floor((l[$] - F - 1) / r);
|
|
297
|
+
Math.floor((l[$] - 1) / r) < y && n.push(""), Ie(n, m, r);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (d + l[$] > r && d > 0 && l[$] > 0) {
|
|
301
|
+
if (s.wordWrap === false && d < r) {
|
|
302
|
+
Ie(n, m, r);
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
n.push("");
|
|
306
|
+
}
|
|
307
|
+
if (d + l[$] > r && s.wordWrap === false) {
|
|
308
|
+
Ie(n, m, r);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
n[n.length - 1] += m;
|
|
312
|
+
}
|
|
313
|
+
s.trim !== false && (n = n.map(($) => St($)));
|
|
314
|
+
const c = n.join(`
|
|
315
|
+
`), p = c[Symbol.iterator]();
|
|
316
|
+
let f = p.next(), g = p.next(), E = 0;
|
|
317
|
+
for (; !f.done; ) {
|
|
318
|
+
const $ = f.value, m = g.value;
|
|
319
|
+
if (i += $, $ === ae || $ === je) {
|
|
320
|
+
He.lastIndex = E + 1;
|
|
321
|
+
const y = He.exec(c)?.groups;
|
|
322
|
+
if (y?.code !== void 0) {
|
|
323
|
+
const v = Number.parseFloat(y.code);
|
|
324
|
+
a = v === vt ? void 0 : v;
|
|
325
|
+
} else y?.uri !== void 0 && (o = y.uri.length === 0 ? void 0 : y.uri);
|
|
326
|
+
}
|
|
327
|
+
const d = a ? At2(a) : void 0;
|
|
328
|
+
m === `
|
|
329
|
+
` ? (o && (i += Ke("")), a && d && (i += Ue(d))) : $ === `
|
|
330
|
+
` && (a && d && (i += Ue(a)), o && (i += Ke(o))), E += $.length, f = g, g = p.next();
|
|
331
|
+
}
|
|
332
|
+
return i;
|
|
333
|
+
};
|
|
334
|
+
function J2(e, r, s) {
|
|
335
|
+
return String(e).normalize().replaceAll(`\r
|
|
336
|
+
`, `
|
|
337
|
+
`).split(`
|
|
338
|
+
`).map((i) => It2(i, r, s)).join(`
|
|
339
|
+
`);
|
|
340
|
+
}
|
|
341
|
+
var R2 = { message: (e = [], { symbol: r = t("gray", h), secondarySymbol: s = t("gray", h), output: i = process.stdout, spacing: a = 1, withGuide: o } = {}) => {
|
|
342
|
+
const u = [], l = o ?? _.withGuide, n = l ? s : "", c = l ? `${r} ` : "", p = l ? `${s} ` : "";
|
|
343
|
+
for (let g = 0; g < a; g++) u.push(n);
|
|
344
|
+
const f = Array.isArray(e) ? e : e.split(`
|
|
345
|
+
`);
|
|
346
|
+
if (f.length > 0) {
|
|
347
|
+
const [g, ...E] = f;
|
|
348
|
+
g.length > 0 ? u.push(`${c}${g}`) : u.push(l ? r : "");
|
|
349
|
+
for (const $ of E) $.length > 0 ? u.push(`${p}${$}`) : u.push(l ? s : "");
|
|
350
|
+
}
|
|
351
|
+
i.write(`${u.join(`
|
|
352
|
+
`)}
|
|
353
|
+
`);
|
|
354
|
+
}, info: (e, r) => {
|
|
355
|
+
R2.message(e, { ...r, symbol: t("blue", fe) });
|
|
356
|
+
}, success: (e, r) => {
|
|
357
|
+
R2.message(e, { ...r, symbol: t("green", Fe) });
|
|
358
|
+
}, step: (e, r) => {
|
|
359
|
+
R2.message(e, { ...r, symbol: t("green", V) });
|
|
360
|
+
}, warn: (e, r) => {
|
|
361
|
+
R2.message(e, { ...r, symbol: t("yellow", ye) });
|
|
362
|
+
}, warning: (e, r) => {
|
|
363
|
+
R2.warn(e, r);
|
|
364
|
+
}, error: (e, r) => {
|
|
365
|
+
R2.message(e, { ...r, symbol: t("red", Ee) });
|
|
366
|
+
} };
|
|
367
|
+
var Kt = (e) => t("magenta", e);
|
|
368
|
+
var be = ({ indicator: e = "dots", onCancel: r, output: s = process.stdout, cancelMessage: i, errorMessage: a, frames: o = ee ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], delay: u = ee ? 80 : 120, signal: l, ...n } = {}) => {
|
|
369
|
+
const c = ce();
|
|
370
|
+
let p, f, g = false, E = false, $ = "", m, d = performance.now();
|
|
371
|
+
const F = rt(s), y = n?.styleFrame ?? Kt, v = (B) => {
|
|
372
|
+
const P2 = B > 1 ? a ?? _.messages.error : i ?? _.messages.cancel;
|
|
373
|
+
E = B === 1, g && (k2(P2, B), E && typeof r == "function" && r());
|
|
374
|
+
}, C = () => v(2), A = () => v(1), b = () => {
|
|
375
|
+
process.on("uncaughtExceptionMonitor", C), process.on("unhandledRejection", C), process.on("SIGINT", A), process.on("SIGTERM", A), process.on("exit", v), l && l.addEventListener("abort", A);
|
|
376
|
+
}, w = () => {
|
|
377
|
+
process.removeListener("uncaughtExceptionMonitor", C), process.removeListener("unhandledRejection", C), process.removeListener("SIGINT", A), process.removeListener("SIGTERM", A), process.removeListener("exit", v), l && l.removeEventListener("abort", A);
|
|
378
|
+
}, S = () => {
|
|
379
|
+
if (m === void 0) return;
|
|
380
|
+
c && s.write(`
|
|
381
|
+
`);
|
|
382
|
+
const B = J2(m, F, { hard: true, trim: false }).split(`
|
|
383
|
+
`);
|
|
384
|
+
B.length > 1 && s.write(import_sisteransi2.cursor.up(B.length - 1)), s.write(import_sisteransi2.cursor.to(0)), s.write(import_sisteransi2.erase.down());
|
|
385
|
+
}, T = (B) => B.replace(/\.+$/, ""), M = (B) => {
|
|
386
|
+
const P2 = (performance.now() - B) / 1e3, G = Math.floor(P2 / 60), L = Math.floor(P2 % 60);
|
|
387
|
+
return G > 0 ? `[${G}m ${L}s]` : `[${L}s]`;
|
|
388
|
+
}, O = n.withGuide ?? _.withGuide, le = (B = "") => {
|
|
389
|
+
g = true, p = xt({ output: s }), $ = T(B), d = performance.now(), O && s.write(`${t("gray", h)}
|
|
390
|
+
`);
|
|
391
|
+
let P2 = 0, G = 0;
|
|
392
|
+
b(), f = setInterval(() => {
|
|
393
|
+
if (c && $ === m) return;
|
|
394
|
+
S(), m = $;
|
|
395
|
+
const L = y(o[P2]);
|
|
396
|
+
let Z;
|
|
397
|
+
if (c) Z = `${L} ${$}...`;
|
|
398
|
+
else if (e === "timer") Z = `${L} ${$} ${M(d)}`;
|
|
399
|
+
else {
|
|
400
|
+
const et2 = ".".repeat(Math.floor(G)).slice(0, 3);
|
|
401
|
+
Z = `${L} ${$}${et2}`;
|
|
402
|
+
}
|
|
403
|
+
const Ze = J2(Z, F, { hard: true, trim: false });
|
|
404
|
+
s.write(Ze), P2 = P2 + 1 < o.length ? P2 + 1 : 0, G = G < 4 ? G + 0.125 : 0;
|
|
405
|
+
}, u);
|
|
406
|
+
}, k2 = (B = "", P2 = 0, G = false) => {
|
|
407
|
+
if (!g) return;
|
|
408
|
+
g = false, clearInterval(f), S();
|
|
409
|
+
const L = P2 === 0 ? t("green", V) : P2 === 1 ? t("red", $e) : t("red", de);
|
|
410
|
+
$ = B ?? $, G || (e === "timer" ? s.write(`${L} ${$} ${M(d)}
|
|
411
|
+
`) : s.write(`${L} ${$}
|
|
412
|
+
`)), w(), p();
|
|
413
|
+
};
|
|
414
|
+
return { start: le, stop: (B = "") => k2(B, 0), message: (B = "") => {
|
|
415
|
+
$ = T(B ?? $);
|
|
416
|
+
}, cancel: (B = "") => k2(B, 1), error: (B = "") => k2(B, 2), clear: () => k2("", 0, true), get isCancelled() {
|
|
417
|
+
return E;
|
|
418
|
+
} };
|
|
419
|
+
};
|
|
420
|
+
var ze = { light: I2("\u2500", "-"), heavy: I2("\u2501", "="), block: I2("\u2588", "#") };
|
|
421
|
+
var Qe = `${t("gray", h)} `;
|
|
422
|
+
|
|
423
|
+
// src/cli/sync.ts
|
|
424
|
+
var clackLogger = {
|
|
425
|
+
info: (msg) => R2.info(msg),
|
|
426
|
+
success: (msg) => R2.success(msg),
|
|
427
|
+
warn: (msg) => R2.warn(msg),
|
|
428
|
+
error: (msg) => R2.error(msg)
|
|
429
|
+
};
|
|
430
|
+
var consoleLogger = {
|
|
431
|
+
info: (msg) => console.log(`[snapshot] ${msg}`),
|
|
432
|
+
success: (msg) => console.log(`[snapshot] \u2713 ${msg}`),
|
|
433
|
+
warn: (msg) => console.warn(`[snapshot] \u26A0 ${msg}`),
|
|
434
|
+
error: (msg) => console.error(`[snapshot] \u2717 ${msg}`)
|
|
435
|
+
};
|
|
436
|
+
async function readSyncConfig(cwd) {
|
|
437
|
+
try {
|
|
438
|
+
const content = await fs.readFile(path.join(cwd, "snapshot.config.json"), "utf8");
|
|
439
|
+
return JSON.parse(content);
|
|
440
|
+
} catch {
|
|
441
|
+
}
|
|
442
|
+
try {
|
|
443
|
+
const content = await fs.readFile(path.join(cwd, "package.json"), "utf8");
|
|
444
|
+
const pkg = JSON.parse(content);
|
|
445
|
+
return pkg.snapshot ?? {};
|
|
446
|
+
} catch {
|
|
447
|
+
}
|
|
448
|
+
return {};
|
|
449
|
+
}
|
|
450
|
+
function resolveBackendDirs(cwd, backend, globalOpts, isMulti) {
|
|
451
|
+
let defaultApiDir;
|
|
452
|
+
let defaultHooksDir;
|
|
453
|
+
let defaultTypesPath;
|
|
454
|
+
if (isMulti && backend.name) {
|
|
455
|
+
const slug = backend.name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
456
|
+
defaultApiDir = `src/api/${slug}`;
|
|
457
|
+
defaultHooksDir = `src/hooks/${slug}`;
|
|
458
|
+
defaultTypesPath = `src/types/${slug}-api.ts`;
|
|
459
|
+
} else {
|
|
460
|
+
defaultApiDir = "src/api";
|
|
461
|
+
defaultHooksDir = "src/hooks/api";
|
|
462
|
+
defaultTypesPath = "src/types/api.ts";
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
apiDir: path.resolve(cwd, backend.apiDir ?? globalOpts.apiDir ?? defaultApiDir),
|
|
466
|
+
hooksDir: path.resolve(cwd, backend.hooksDir ?? globalOpts.hooksDir ?? defaultHooksDir),
|
|
467
|
+
typesFile: path.resolve(cwd, backend.typesPath ?? globalOpts.typesPath ?? defaultTypesPath),
|
|
468
|
+
snapshotImport: backend.snapshotImport ?? globalOpts.snapshotImport ?? "@lib/snapshot"
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
function toRelativeImport(fromDir, toPath) {
|
|
472
|
+
let rel = path.relative(fromDir, toPath).replace(/\\/g, "/");
|
|
473
|
+
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
474
|
+
return rel.replace(/\.ts$/, "");
|
|
475
|
+
}
|
|
476
|
+
function schemaHash(schema) {
|
|
477
|
+
return createHash("sha1").update(JSON.stringify(schema)).digest("hex");
|
|
478
|
+
}
|
|
479
|
+
function refName(ref) {
|
|
480
|
+
return ref.replace("#/components/schemas/", "");
|
|
481
|
+
}
|
|
482
|
+
function collectRefs(schema) {
|
|
483
|
+
const refs = /* @__PURE__ */ new Set();
|
|
484
|
+
if (schema.$ref) {
|
|
485
|
+
refs.add(refName(schema.$ref));
|
|
486
|
+
return refs;
|
|
487
|
+
}
|
|
488
|
+
if (schema.items) collectRefs(schema.items).forEach((r) => refs.add(r));
|
|
489
|
+
if (schema.properties) {
|
|
490
|
+
for (const prop of Object.values(schema.properties)) {
|
|
491
|
+
collectRefs(prop).forEach((r) => refs.add(r));
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
for (const arr of [schema.oneOf, schema.anyOf, schema.allOf]) {
|
|
495
|
+
if (arr) for (const s of arr) collectRefs(s).forEach((r) => refs.add(r));
|
|
496
|
+
}
|
|
497
|
+
return refs;
|
|
498
|
+
}
|
|
499
|
+
function schemaToTs(schema, depth = 0) {
|
|
500
|
+
if (schema.$ref) return refName(schema.$ref);
|
|
501
|
+
if (schema.enum) {
|
|
502
|
+
return schema.enum.map((v) => v === null ? "null" : typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
|
|
503
|
+
}
|
|
504
|
+
if (schema.allOf) {
|
|
505
|
+
const parts = schema.allOf.map((s) => schemaToTs(s, depth));
|
|
506
|
+
return parts.length === 1 ? parts[0] : parts.join(" & ");
|
|
507
|
+
}
|
|
508
|
+
if (schema.oneOf || schema.anyOf) {
|
|
509
|
+
return (schema.oneOf ?? schema.anyOf).map((s) => schemaToTs(s, depth)).join(" | ");
|
|
510
|
+
}
|
|
511
|
+
const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
|
|
512
|
+
const isNullable = schema.nullable === true || types.includes("null");
|
|
513
|
+
const baseTypes = types.filter((t2) => t2 !== "null");
|
|
514
|
+
let base;
|
|
515
|
+
if (baseTypes.includes("array") || schema.items) {
|
|
516
|
+
const item = schema.items ? schemaToTs(schema.items, depth) : "unknown";
|
|
517
|
+
base = item.includes(" | ") ? `(${item})[]` : `${item}[]`;
|
|
518
|
+
} else if (baseTypes.includes("object") || schema.properties || schema.additionalProperties) {
|
|
519
|
+
if (schema.properties && Object.keys(schema.properties).length > 0) {
|
|
520
|
+
const ind = " ".repeat(depth + 1);
|
|
521
|
+
const close = " ".repeat(depth);
|
|
522
|
+
const lines = Object.entries(schema.properties).map(([key, val]) => {
|
|
523
|
+
const opt = schema.required?.includes(key) ? "" : "?";
|
|
524
|
+
const valNull = val.nullable ? " | null" : "";
|
|
525
|
+
const safeProp = /[^a-zA-Z0-9_$]/.test(key) ? `'${key}'` : key;
|
|
526
|
+
return `${ind}${safeProp}${opt}: ${schemaToTs(val, depth + 1)}${valNull}`;
|
|
527
|
+
});
|
|
528
|
+
base = `{
|
|
529
|
+
${lines.join("\n")}
|
|
530
|
+
${close}}`;
|
|
531
|
+
} else if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
532
|
+
base = `Record<string, ${schemaToTs(schema.additionalProperties, depth)}>`;
|
|
533
|
+
} else {
|
|
534
|
+
base = "Record<string, unknown>";
|
|
535
|
+
}
|
|
536
|
+
} else if (baseTypes.includes("string")) {
|
|
537
|
+
base = "string";
|
|
538
|
+
} else if (baseTypes.includes("integer") || baseTypes.includes("number")) {
|
|
539
|
+
base = "number";
|
|
540
|
+
} else if (baseTypes.includes("boolean")) {
|
|
541
|
+
base = "boolean";
|
|
542
|
+
} else {
|
|
543
|
+
base = "unknown";
|
|
544
|
+
}
|
|
545
|
+
return isNullable ? `${base} | null` : base;
|
|
546
|
+
}
|
|
547
|
+
function schemaToZod(schema, componentSchemas, visiting = /* @__PURE__ */ new Set()) {
|
|
548
|
+
if (schema.$ref) {
|
|
549
|
+
const name = refName(schema.$ref);
|
|
550
|
+
if (visiting.has(name)) return "z.unknown()";
|
|
551
|
+
const resolved = componentSchemas[name];
|
|
552
|
+
return resolved ? schemaToZod(resolved, componentSchemas, /* @__PURE__ */ new Set([...visiting, name])) : "z.unknown()";
|
|
553
|
+
}
|
|
554
|
+
if (schema.enum) {
|
|
555
|
+
const allStrings = schema.enum.every((v) => typeof v === "string");
|
|
556
|
+
if (allStrings && schema.enum.length > 0) {
|
|
557
|
+
return `z.enum([${schema.enum.map((v) => `'${v}'`).join(", ")}])`;
|
|
558
|
+
}
|
|
559
|
+
const literals = schema.enum.map(
|
|
560
|
+
(v) => v === null ? "z.null()" : `z.literal(${typeof v === "string" ? `'${v}'` : String(v)})`
|
|
561
|
+
);
|
|
562
|
+
return `z.union([${literals.join(", ")}])`;
|
|
563
|
+
}
|
|
564
|
+
if (schema.allOf) {
|
|
565
|
+
if (schema.allOf.length === 1) return schemaToZod(schema.allOf[0], componentSchemas, visiting);
|
|
566
|
+
const parts = schema.allOf.map((s) => schemaToZod(s, componentSchemas, visiting));
|
|
567
|
+
return parts.reduce((acc, cur) => `z.intersection(${acc}, ${cur})`);
|
|
568
|
+
}
|
|
569
|
+
if (schema.oneOf || schema.anyOf) {
|
|
570
|
+
const arr = schema.oneOf ?? schema.anyOf;
|
|
571
|
+
return `z.union([${arr.map((s) => schemaToZod(s, componentSchemas, visiting)).join(", ")}])`;
|
|
572
|
+
}
|
|
573
|
+
const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
|
|
574
|
+
const isNullable = schema.nullable === true || types.includes("null");
|
|
575
|
+
const baseTypes = types.filter((t2) => t2 !== "null");
|
|
576
|
+
let base;
|
|
577
|
+
if (baseTypes.includes("array") || schema.items) {
|
|
578
|
+
const item = schema.items ? schemaToZod(schema.items, componentSchemas, visiting) : "z.unknown()";
|
|
579
|
+
base = `z.array(${item})`;
|
|
580
|
+
} else if (baseTypes.includes("object") || schema.properties || schema.additionalProperties) {
|
|
581
|
+
if (schema.properties && Object.keys(schema.properties).length > 0) {
|
|
582
|
+
const props = Object.entries(schema.properties).map(([key, val]) => {
|
|
583
|
+
const zodVal = schemaToZod(val, componentSchemas, visiting);
|
|
584
|
+
const nullable = val.nullable ? ".nullable()" : "";
|
|
585
|
+
const opt = schema.required?.includes(key) ? "" : ".optional()";
|
|
586
|
+
const safeProp = /[^a-zA-Z0-9_$]/.test(key) ? `'${key}'` : key;
|
|
587
|
+
return ` ${safeProp}: ${zodVal}${nullable}${opt},`;
|
|
588
|
+
});
|
|
589
|
+
base = `z.object({
|
|
590
|
+
${props.join("\n")}
|
|
591
|
+
})`;
|
|
592
|
+
} else if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
593
|
+
base = `z.record(z.string(), ${schemaToZod(schema.additionalProperties, componentSchemas, visiting)})`;
|
|
594
|
+
} else {
|
|
595
|
+
base = "z.record(z.string(), z.unknown())";
|
|
596
|
+
}
|
|
597
|
+
} else if (baseTypes.includes("string")) {
|
|
598
|
+
base = "z.string()";
|
|
599
|
+
} else if (baseTypes.includes("integer") || baseTypes.includes("number")) {
|
|
600
|
+
base = "z.number()";
|
|
601
|
+
} else if (baseTypes.includes("boolean")) {
|
|
602
|
+
base = "z.boolean()";
|
|
603
|
+
} else {
|
|
604
|
+
base = "z.unknown()";
|
|
605
|
+
}
|
|
606
|
+
return isNullable ? `${base}.nullable()` : base;
|
|
607
|
+
}
|
|
608
|
+
function generateTypesContent(schemas, hasPaginated) {
|
|
609
|
+
const lines = [
|
|
610
|
+
"// Generated by bunx snapshot sync. Do not edit manually.",
|
|
611
|
+
""
|
|
612
|
+
];
|
|
613
|
+
if (hasPaginated) {
|
|
614
|
+
lines.push(`export interface PaginatedResponse<T> {`);
|
|
615
|
+
lines.push(` data: T[]`);
|
|
616
|
+
lines.push(` total: number`);
|
|
617
|
+
lines.push(` page: number`);
|
|
618
|
+
lines.push(` perPage: number`);
|
|
619
|
+
lines.push(`}`);
|
|
620
|
+
lines.push("");
|
|
621
|
+
}
|
|
622
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
623
|
+
if (schema.description) lines.push(`/** ${schema.description} */`);
|
|
624
|
+
const isObject = schema.type === "object" || !!schema.properties || Array.isArray(schema.type) && schema.type.includes("object");
|
|
625
|
+
const isComplex = schema.enum || schema.oneOf || schema.anyOf || schema.allOf || schema.$ref;
|
|
626
|
+
if (isObject && !isComplex) {
|
|
627
|
+
const ind = " ";
|
|
628
|
+
const props = schema.properties ? Object.entries(schema.properties).map(([key, val]) => {
|
|
629
|
+
const opt = schema.required?.includes(key) ? "" : "?";
|
|
630
|
+
const valNull = val.nullable ? " | null" : "";
|
|
631
|
+
const comment = val.description ? ` /** ${val.description} */
|
|
632
|
+
` : "";
|
|
633
|
+
const safeProp = /[^a-zA-Z0-9_$]/.test(key) ? `'${key}'` : key;
|
|
634
|
+
return `${comment}${ind}${safeProp}${opt}: ${schemaToTs(val, 1)}${valNull}`;
|
|
635
|
+
}) : [];
|
|
636
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
637
|
+
lines.push(`export interface ${name} extends Record<string, unknown> {`);
|
|
638
|
+
} else {
|
|
639
|
+
lines.push(`export interface ${name} {`);
|
|
640
|
+
}
|
|
641
|
+
lines.push(...props);
|
|
642
|
+
lines.push("}");
|
|
643
|
+
} else {
|
|
644
|
+
lines.push(`export type ${name} = ${schemaToTs(schema)}`);
|
|
645
|
+
}
|
|
646
|
+
lines.push("");
|
|
647
|
+
}
|
|
648
|
+
return lines.join("\n");
|
|
649
|
+
}
|
|
650
|
+
function toCamelCase(str) {
|
|
651
|
+
return str.replace(/[-_]([a-zA-Z0-9])/g, (_2, c) => c.toUpperCase());
|
|
652
|
+
}
|
|
653
|
+
function plainFnName(method, pathStr, operationId) {
|
|
654
|
+
if (operationId) return toCamelCase(operationId);
|
|
655
|
+
const segs = pathStr.split("/").filter(Boolean).map((seg) => {
|
|
656
|
+
if (seg.startsWith("{") && seg.endsWith("}")) {
|
|
657
|
+
const n = seg.slice(1, -1);
|
|
658
|
+
return "By" + n.charAt(0).toUpperCase() + n.slice(1);
|
|
659
|
+
}
|
|
660
|
+
const camel = toCamelCase(seg);
|
|
661
|
+
return camel.charAt(0).toUpperCase() + camel.slice(1);
|
|
662
|
+
});
|
|
663
|
+
return method + segs.join("");
|
|
664
|
+
}
|
|
665
|
+
function hookName(method, fnName) {
|
|
666
|
+
const isQuery = method === "get";
|
|
667
|
+
const pascal = fnName.charAt(0).toUpperCase() + fnName.slice(1);
|
|
668
|
+
if (pascal.endsWith("Query") || pascal.endsWith("Mutation")) return `use${pascal}`;
|
|
669
|
+
return `use${pascal}${isQuery ? "Query" : "Mutation"}`;
|
|
670
|
+
}
|
|
671
|
+
function successSchema(responses) {
|
|
672
|
+
for (const code of ["200", "201", "202"]) {
|
|
673
|
+
const r = responses[code];
|
|
674
|
+
if (r?.content?.["application/json"]?.schema) return r.content["application/json"].schema;
|
|
675
|
+
}
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
function requestBodySchema(rb) {
|
|
679
|
+
if (!rb) return null;
|
|
680
|
+
return rb.content?.["application/json"]?.schema ?? null;
|
|
681
|
+
}
|
|
682
|
+
function nonJsonBodyContentType(rb) {
|
|
683
|
+
if (!rb?.content) return null;
|
|
684
|
+
if ("application/json" in rb.content) return null;
|
|
685
|
+
return Object.keys(rb.content)[0] ?? null;
|
|
686
|
+
}
|
|
687
|
+
function rawPathTemplate(pathStr, pathParams) {
|
|
688
|
+
if (pathParams.length === 0) return `'${pathStr}'`;
|
|
689
|
+
const tpl = pathStr.replace(/\{([^}]+)\}/g, (_2, n) => `\${${n}}`);
|
|
690
|
+
return `\`${tpl}\``;
|
|
691
|
+
}
|
|
692
|
+
function paginatedUrlTemplate(pathStr, pathParams) {
|
|
693
|
+
if (pathParams.length === 0) {
|
|
694
|
+
return `\`${pathStr}?page=\${page}&perPage=\${perPage}\``;
|
|
695
|
+
}
|
|
696
|
+
const tpl = pathStr.replace(/\{([^}]+)\}/g, (_2, n) => `\${${n}}`);
|
|
697
|
+
return `\`${tpl}?page=\${page}&perPage=\${perPage}\``;
|
|
698
|
+
}
|
|
699
|
+
function queryKey(pathStr, queryParams = []) {
|
|
700
|
+
const parts = pathStr.split("/").filter(Boolean).map(
|
|
701
|
+
(seg) => seg.startsWith("{") && seg.endsWith("}") ? `params.${seg.slice(1, -1)}` : `'${seg}'`
|
|
702
|
+
);
|
|
703
|
+
for (const p of queryParams) {
|
|
704
|
+
parts.push(`params.${p.name}`);
|
|
705
|
+
}
|
|
706
|
+
return `[${parts.join(", ")}]`;
|
|
707
|
+
}
|
|
708
|
+
function paramType(p) {
|
|
709
|
+
return schemaToTs(p.schema ?? { type: "string" });
|
|
710
|
+
}
|
|
711
|
+
function isPaginatedSchema(schema) {
|
|
712
|
+
if (!schema.properties) return null;
|
|
713
|
+
const { data, total } = schema.properties;
|
|
714
|
+
if (!data || !data.items && data.type !== "array") return null;
|
|
715
|
+
if (!total || !["integer", "number"].includes(total.type)) return null;
|
|
716
|
+
const itemSchema = data.items ?? {};
|
|
717
|
+
return { itemSchema };
|
|
718
|
+
}
|
|
719
|
+
function generateOperation(method, pathStr, op, pathLevelParams, componentSchemas, zod) {
|
|
720
|
+
const isQuery = method === "get";
|
|
721
|
+
const allParams = [
|
|
722
|
+
...pathLevelParams,
|
|
723
|
+
...(op.parameters ?? []).filter(
|
|
724
|
+
(p) => !pathLevelParams.find((pp) => pp.name === p.name && pp.in === p.in)
|
|
725
|
+
)
|
|
726
|
+
];
|
|
727
|
+
const pathParams = allParams.filter((p) => p.in === "path");
|
|
728
|
+
const queryParams = allParams.filter((p) => p.in === "query");
|
|
729
|
+
const hasPathParams = pathParams.length > 0;
|
|
730
|
+
const hasQueryParams = queryParams.length > 0;
|
|
731
|
+
const fnName = plainFnName(method, pathStr, op.operationId);
|
|
732
|
+
const name = hookName(method, fnName);
|
|
733
|
+
const successSch = successSchema(op.responses);
|
|
734
|
+
const paginatedResult = isQuery && successSch ? isPaginatedSchema(successSch) : null;
|
|
735
|
+
const isPaginated = paginatedResult !== null;
|
|
736
|
+
const respType = (() => {
|
|
737
|
+
if (isPaginated && paginatedResult) {
|
|
738
|
+
return `PaginatedResponse<${schemaToTs(paginatedResult.itemSchema)}>`;
|
|
739
|
+
}
|
|
740
|
+
return successSch ? schemaToTs(successSch) : "void";
|
|
741
|
+
})();
|
|
742
|
+
const bodyType = (() => {
|
|
743
|
+
const s = requestBodySchema(op.requestBody);
|
|
744
|
+
return s ? schemaToTs(s) : "void";
|
|
745
|
+
})();
|
|
746
|
+
const hasBody = bodyType !== "void";
|
|
747
|
+
const nonJsonType = nonJsonBodyContentType(op.requestBody);
|
|
748
|
+
const jsdocParts = [];
|
|
749
|
+
if (op.deprecated) jsdocParts.push("@deprecated");
|
|
750
|
+
if (op.summary) jsdocParts.push(op.summary);
|
|
751
|
+
if (nonJsonType) jsdocParts.push(`NOTE: request body is ${nonJsonType} \u2014 body typed as void`);
|
|
752
|
+
const jsdoc = jsdocParts.length > 0 ? `/** ${jsdocParts.join(" \u2014 ")} */
|
|
753
|
+
` : "";
|
|
754
|
+
if (isPaginated) {
|
|
755
|
+
const pathArgsStr = pathParams.map((p) => `${p.name}: ${paramType(p)}`).join(", ");
|
|
756
|
+
const pathArgsWithComma = pathArgsStr ? `${pathArgsStr}, ` : "";
|
|
757
|
+
const paginatedUrl = paginatedUrlTemplate(pathStr, pathParams);
|
|
758
|
+
const plainFn2 = `${jsdoc}export const ${fnName} = (${pathArgsWithComma}page = 1, perPage = 20): Promise<${respType}> =>
|
|
759
|
+
api.get<${respType}>(${paginatedUrl})`;
|
|
760
|
+
const pathKeyParts = pathStr.split("/").filter(Boolean).map(
|
|
761
|
+
(seg) => seg.startsWith("{") && seg.endsWith("}") ? `params.${seg.slice(1, -1)}` : `'${seg}'`
|
|
762
|
+
);
|
|
763
|
+
const paginatedQueryKey = `[${[...pathKeyParts, "params.page ?? 1", "params.perPage ?? 20"].join(", ")}]`;
|
|
764
|
+
const paramsType = hasPathParams ? `{ ${pathParams.map((p) => `${p.name}: ${paramType(p)}`).join("; ")}; page?: number; perPage?: number }` : `{ page?: number; perPage?: number }`;
|
|
765
|
+
const callPathArgs = pathParams.map((p) => `params.${p.name}`).join(", ");
|
|
766
|
+
const callAllArgs = callPathArgs ? `${callPathArgs}, params.page ?? 1, params.perPage ?? 20` : `params.page ?? 1, params.perPage ?? 20`;
|
|
767
|
+
const hookLines = [];
|
|
768
|
+
if (jsdocParts.length > 0) hookLines.push(`/** ${jsdocParts.join(" \u2014 ")} */`);
|
|
769
|
+
hookLines.push(`export function ${name}(`);
|
|
770
|
+
hookLines.push(` params: ${paramsType} = {},`);
|
|
771
|
+
hookLines.push(
|
|
772
|
+
` options?: Omit<UseQueryOptions<${respType}, ApiError>, 'queryKey' | 'queryFn'>`
|
|
773
|
+
);
|
|
774
|
+
hookLines.push(`) {`);
|
|
775
|
+
hookLines.push(` return useQuery({`);
|
|
776
|
+
hookLines.push(` queryKey: ${paginatedQueryKey},`);
|
|
777
|
+
hookLines.push(` queryFn: () => ${fnName}(${callAllArgs}),`);
|
|
778
|
+
hookLines.push(` ...options,`);
|
|
779
|
+
hookLines.push(` })`);
|
|
780
|
+
hookLines.push(`}`);
|
|
781
|
+
return { apiCode: plainFn2, hookCode: hookLines.join("\n"), fnNames: [fnName], isPaginated: true };
|
|
782
|
+
}
|
|
783
|
+
const fnArgParts = [
|
|
784
|
+
...pathParams.map((p) => `${p.name}: ${paramType(p)}`),
|
|
785
|
+
...!isQuery && hasBody ? [`body: ${bodyType}`] : [],
|
|
786
|
+
...queryParams.map((p) => `${p.name}${p.required ? "" : "?"}: ${paramType(p)}`)
|
|
787
|
+
];
|
|
788
|
+
const fnArgs = fnArgParts.join(", ");
|
|
789
|
+
let plainFn;
|
|
790
|
+
if (hasQueryParams) {
|
|
791
|
+
const pathTpl = pathStr.replace(/\{([^}]+)\}/g, (_2, n) => `\${${n}}`);
|
|
792
|
+
const qSetLines = queryParams.map(
|
|
793
|
+
(p) => p.required ? ` _q.set('${p.name}', String(${p.name}))` : ` if (${p.name} != null) _q.set('${p.name}', String(${p.name}))`
|
|
794
|
+
);
|
|
795
|
+
const urlExpr = `\`${pathTpl}?\${_q}\``;
|
|
796
|
+
const needsBody = method !== "get" && method !== "delete";
|
|
797
|
+
const returnCall = hasBody ? `return api.${method}<${respType}>(${urlExpr}, body)` : needsBody ? `return api.${method}<${respType}>(${urlExpr}, undefined)` : `return api.${method}<${respType}>(${urlExpr})`;
|
|
798
|
+
plainFn = `${jsdoc}export const ${fnName} = (${fnArgs}): Promise<${respType}> => {
|
|
799
|
+
const _q = new URLSearchParams()
|
|
800
|
+
` + qSetLines.join("\n") + `
|
|
801
|
+
${returnCall}
|
|
802
|
+
}`;
|
|
803
|
+
} else {
|
|
804
|
+
const rawUrl = rawPathTemplate(pathStr, pathParams);
|
|
805
|
+
const needsBody = method !== "get" && method !== "delete";
|
|
806
|
+
const apiCall = hasBody ? `api.${method}<${respType}>(${rawUrl}, body)` : needsBody ? `api.${method}<${respType}>(${rawUrl}, undefined)` : `api.${method}<${respType}>(${rawUrl})`;
|
|
807
|
+
plainFn = `${jsdoc}export const ${fnName} = (${fnArgs}): Promise<${respType}> =>
|
|
808
|
+
${apiCall}`;
|
|
809
|
+
}
|
|
810
|
+
const lines = [];
|
|
811
|
+
if (jsdocParts.length > 0) lines.push(`/** ${jsdocParts.join(" \u2014 ")} */`);
|
|
812
|
+
if (isQuery) {
|
|
813
|
+
const paramFields = [
|
|
814
|
+
...pathParams.map((p) => `${p.name}: ${paramType(p)}`),
|
|
815
|
+
...queryParams.map((p) => `${p.name}${p.required ? "" : "?"}: ${paramType(p)}`)
|
|
816
|
+
];
|
|
817
|
+
const hasAnyParams = paramFields.length > 0;
|
|
818
|
+
const allParamsOptional = pathParams.length === 0 && queryParams.every((p) => !p.required);
|
|
819
|
+
const paramsDefault = hasAnyParams && allParamsOptional ? " = {}" : "";
|
|
820
|
+
const paramsArg = hasAnyParams ? `params: { ${paramFields.join("; ")} }${paramsDefault}, ` : "";
|
|
821
|
+
const allCallArgs = [
|
|
822
|
+
...pathParams.map((p) => `params.${p.name}`),
|
|
823
|
+
...queryParams.map((p) => `params.${p.name}`)
|
|
824
|
+
];
|
|
825
|
+
lines.push(`export function ${name}(`);
|
|
826
|
+
lines.push(
|
|
827
|
+
` ${paramsArg}options?: Omit<UseQueryOptions<${respType}, ApiError>, 'queryKey' | 'queryFn'>`
|
|
828
|
+
);
|
|
829
|
+
lines.push(`) {`);
|
|
830
|
+
lines.push(` return useQuery({`);
|
|
831
|
+
lines.push(` queryKey: ${queryKey(pathStr, queryParams)},`);
|
|
832
|
+
if (allCallArgs.length > 0) {
|
|
833
|
+
lines.push(` queryFn: () => ${fnName}(${allCallArgs.join(", ")}),`);
|
|
834
|
+
} else {
|
|
835
|
+
lines.push(` queryFn: ${fnName},`);
|
|
836
|
+
}
|
|
837
|
+
lines.push(` ...options,`);
|
|
838
|
+
lines.push(` })`);
|
|
839
|
+
lines.push(`}`);
|
|
840
|
+
} else {
|
|
841
|
+
let variablesType;
|
|
842
|
+
let mutationFnExpr;
|
|
843
|
+
const mutationQueryFields = queryParams.map(
|
|
844
|
+
(p) => `${p.name}${p.required ? "" : "?"}: ${paramType(p)}`
|
|
845
|
+
);
|
|
846
|
+
const queryCallArgs = queryParams.map((p) => `vars.${p.name}`);
|
|
847
|
+
if (!hasPathParams && !hasBody && !hasQueryParams) {
|
|
848
|
+
variablesType = "void";
|
|
849
|
+
mutationFnExpr = `() => ${fnName}()`;
|
|
850
|
+
} else if (!hasPathParams && !hasQueryParams) {
|
|
851
|
+
variablesType = bodyType;
|
|
852
|
+
mutationFnExpr = fnName;
|
|
853
|
+
} else {
|
|
854
|
+
const fields = [
|
|
855
|
+
...pathParams.map((p) => `${p.name}: ${paramType(p)}`),
|
|
856
|
+
...hasBody ? [`body: ${bodyType}`] : [],
|
|
857
|
+
...mutationQueryFields
|
|
858
|
+
];
|
|
859
|
+
variablesType = `{ ${fields.join("; ")} }`;
|
|
860
|
+
const callArgs = [
|
|
861
|
+
...pathParams.map((p) => `vars.${p.name}`),
|
|
862
|
+
...hasBody ? [`vars.body`] : [],
|
|
863
|
+
...queryCallArgs
|
|
864
|
+
];
|
|
865
|
+
mutationFnExpr = `(vars) => ${fnName}(${callArgs.join(", ")})`;
|
|
866
|
+
}
|
|
867
|
+
lines.push(`export function ${name}(`);
|
|
868
|
+
lines.push(
|
|
869
|
+
` options?: UseMutationOptions<${respType}, ApiError, ${variablesType}> & { invalidateKeys?: QueryKey[] }`
|
|
870
|
+
);
|
|
871
|
+
lines.push(`) {`);
|
|
872
|
+
lines.push(` const { invalidateKeys, ...mutationOptions } = options ?? {}`);
|
|
873
|
+
lines.push(` const queryClient = useQueryClient()`);
|
|
874
|
+
lines.push(` return useMutation({`);
|
|
875
|
+
lines.push(` mutationFn: ${mutationFnExpr},`);
|
|
876
|
+
lines.push(` ...mutationOptions,`);
|
|
877
|
+
lines.push(` onSuccess: (...args) => {`);
|
|
878
|
+
lines.push(` invalidateKeys?.forEach((key) => queryClient.invalidateQueries({ queryKey: key }))`);
|
|
879
|
+
lines.push(` mutationOptions.onSuccess?.(...args)`);
|
|
880
|
+
lines.push(` },`);
|
|
881
|
+
lines.push(` })`);
|
|
882
|
+
lines.push(`}`);
|
|
883
|
+
}
|
|
884
|
+
const apiParts = [plainFn];
|
|
885
|
+
if (!isQuery && hasBody && zod) {
|
|
886
|
+
const bodySchema = requestBodySchema(op.requestBody);
|
|
887
|
+
if (bodySchema) {
|
|
888
|
+
const zodSchemaName = `${fnName}Schema`;
|
|
889
|
+
const zodTypeName = fnName.charAt(0).toUpperCase() + fnName.slice(1) + "Input";
|
|
890
|
+
const zodSchemaStr = schemaToZod(bodySchema, componentSchemas);
|
|
891
|
+
apiParts.push(
|
|
892
|
+
`/** Zod schema for ${name} form validation */
|
|
893
|
+
export const ${zodSchemaName} = ${zodSchemaStr}
|
|
894
|
+
export type ${zodTypeName} = z.infer<typeof ${zodSchemaName}>`
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return { apiCode: apiParts.join("\n\n"), hookCode: lines.join("\n"), fnNames: [fnName], isPaginated: false };
|
|
899
|
+
}
|
|
900
|
+
function collectTagRefs(ops) {
|
|
901
|
+
const typeRefs = /* @__PURE__ */ new Set();
|
|
902
|
+
for (const { operation, pathLevelParams } of ops) {
|
|
903
|
+
const s = successSchema(operation.responses);
|
|
904
|
+
if (s) collectRefs(s).forEach((r) => typeRefs.add(r));
|
|
905
|
+
const b = requestBodySchema(operation.requestBody);
|
|
906
|
+
if (b) collectRefs(b).forEach((r) => typeRefs.add(r));
|
|
907
|
+
for (const p of [...operation.parameters ?? [], ...pathLevelParams]) {
|
|
908
|
+
if (p.schema) collectRefs(p.schema).forEach((r) => typeRefs.add(r));
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
for (const { method, operation } of ops) {
|
|
912
|
+
if (method !== "get") continue;
|
|
913
|
+
const s = successSchema(operation.responses);
|
|
914
|
+
if (!s) continue;
|
|
915
|
+
const pagResult = isPaginatedSchema(s);
|
|
916
|
+
if (pagResult) collectRefs(pagResult.itemSchema).forEach((r) => typeRefs.add(r));
|
|
917
|
+
}
|
|
918
|
+
return typeRefs;
|
|
919
|
+
}
|
|
920
|
+
function generateTagFiles(ops, slug, componentSchemas, zod, importPaths) {
|
|
921
|
+
const ip = importPaths ?? {
|
|
922
|
+
snapshotImport: "@lib/snapshot",
|
|
923
|
+
typesRelForApi: "../types/api",
|
|
924
|
+
typesRelForHooks: "../../types/api",
|
|
925
|
+
apiRelBase: "../../api"
|
|
926
|
+
};
|
|
927
|
+
const typeRefs = collectTagRefs(ops);
|
|
928
|
+
const generated = ops.map(
|
|
929
|
+
({ method, pathStr, operation, pathLevelParams }) => generateOperation(method, pathStr, operation, pathLevelParams, componentSchemas, zod)
|
|
930
|
+
);
|
|
931
|
+
const hasPaginated = generated.some((g) => g.isPaginated);
|
|
932
|
+
const hasZod = zod && generated.some((g) => g.apiCode.includes("z.infer"));
|
|
933
|
+
const allFnNames = generated.flatMap((g) => g.fnNames);
|
|
934
|
+
const localTypeImports = [...typeRefs].sort();
|
|
935
|
+
if (hasPaginated) localTypeImports.unshift("PaginatedResponse");
|
|
936
|
+
const apiLines = [
|
|
937
|
+
"// Generated by bunx snapshot sync. Do not edit manually.",
|
|
938
|
+
"",
|
|
939
|
+
`import { api } from '${ip.snapshotImport}'`
|
|
940
|
+
];
|
|
941
|
+
if (hasZod) apiLines.push("import { z } from 'zod'");
|
|
942
|
+
if (localTypeImports.length > 0) {
|
|
943
|
+
apiLines.push(`import type { ${localTypeImports.join(", ")} } from '${ip.typesRelForApi}'`);
|
|
944
|
+
}
|
|
945
|
+
apiLines.push("");
|
|
946
|
+
for (const { apiCode } of generated) {
|
|
947
|
+
apiLines.push(apiCode);
|
|
948
|
+
apiLines.push("");
|
|
949
|
+
}
|
|
950
|
+
const hasQueries = ops.some(({ method }) => method === "get");
|
|
951
|
+
const hasMutations = ops.some(({ method }) => method !== "get");
|
|
952
|
+
const rqImports = [];
|
|
953
|
+
if (hasQueries) rqImports.push("useQuery", "type UseQueryOptions");
|
|
954
|
+
if (hasMutations) rqImports.push("useMutation", "useQueryClient", "type UseMutationOptions", "type QueryKey");
|
|
955
|
+
const hooksLines = [
|
|
956
|
+
"// Generated by bunx snapshot sync. Do not edit manually.",
|
|
957
|
+
"",
|
|
958
|
+
`import { ${rqImports.join(", ")} } from '@tanstack/react-query'`,
|
|
959
|
+
"import { ApiError } from '@lastshotlabs/snapshot'",
|
|
960
|
+
`import { ${allFnNames.join(", ")} } from '${ip.apiRelBase}/${slug}'`
|
|
961
|
+
];
|
|
962
|
+
if (localTypeImports.length > 0) {
|
|
963
|
+
hooksLines.push(`import type { ${localTypeImports.join(", ")} } from '${ip.typesRelForHooks}'`);
|
|
964
|
+
}
|
|
965
|
+
hooksLines.push("");
|
|
966
|
+
for (const { hookCode } of generated) {
|
|
967
|
+
hooksLines.push(hookCode);
|
|
968
|
+
hooksLines.push("");
|
|
969
|
+
}
|
|
970
|
+
return {
|
|
971
|
+
apiContent: apiLines.join("\n"),
|
|
972
|
+
hooksContent: hooksLines.join("\n"),
|
|
973
|
+
hasPaginated
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
async function readEnvUrl(cwd) {
|
|
977
|
+
try {
|
|
978
|
+
const content = await fs.readFile(path.join(cwd, ".env"), "utf8");
|
|
979
|
+
for (const line of content.split("\n")) {
|
|
980
|
+
const m = line.match(/^VITE_API_URL\s*=\s*(.+)$/);
|
|
981
|
+
if (m) return m[1].trim().replace(/^["']|["']$/g, "");
|
|
982
|
+
}
|
|
983
|
+
} catch {
|
|
984
|
+
}
|
|
985
|
+
return void 0;
|
|
986
|
+
}
|
|
987
|
+
async function loadSchema(opts) {
|
|
988
|
+
if (opts.filePath) {
|
|
989
|
+
const abs = path.resolve(opts.cwd, opts.filePath);
|
|
990
|
+
const content = await fs.readFile(abs, "utf8");
|
|
991
|
+
return JSON.parse(content);
|
|
992
|
+
}
|
|
993
|
+
let apiUrl = opts.apiUrl ?? process.env["VITE_API_URL"] ?? await readEnvUrl(opts.cwd);
|
|
994
|
+
if (!apiUrl) {
|
|
995
|
+
throw new Error(
|
|
996
|
+
"No API URL found. Pass --api <url>, --file <path>, or set VITE_API_URL in .env"
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
apiUrl = apiUrl.replace(/\/$/, "");
|
|
1000
|
+
const res = await fetch(`${apiUrl}/openapi.json`);
|
|
1001
|
+
if (!res.ok) {
|
|
1002
|
+
const err = new Error(`Server returned ${res.status} for ${apiUrl}/openapi.json`);
|
|
1003
|
+
err.status = res.status;
|
|
1004
|
+
throw err;
|
|
1005
|
+
}
|
|
1006
|
+
return await res.json();
|
|
1007
|
+
}
|
|
1008
|
+
async function runSyncOnce(opts, logger, backend, isMulti) {
|
|
1009
|
+
const { cwd } = opts;
|
|
1010
|
+
const sp = be();
|
|
1011
|
+
let schema;
|
|
1012
|
+
const effectiveFilePath = backend.filePath ?? opts.filePath;
|
|
1013
|
+
if (effectiveFilePath) {
|
|
1014
|
+
sp.start(`Reading schema from ${effectiveFilePath}`);
|
|
1015
|
+
} else {
|
|
1016
|
+
sp.start("Fetching schema...");
|
|
1017
|
+
}
|
|
1018
|
+
try {
|
|
1019
|
+
schema = await loadSchema({ ...opts, apiUrl: backend.apiUrl ?? opts.apiUrl, filePath: backend.filePath ?? opts.filePath });
|
|
1020
|
+
} catch (err) {
|
|
1021
|
+
sp.stop("Failed");
|
|
1022
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1023
|
+
logger.error(msg);
|
|
1024
|
+
if (err instanceof Error && "status" in err) {
|
|
1025
|
+
const status = err.status;
|
|
1026
|
+
if (status === 401 || status === 403) {
|
|
1027
|
+
logger.info("Tip: check your bunshot config \u2014 /openapi.json may require authentication");
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
throw err;
|
|
1031
|
+
}
|
|
1032
|
+
const title = schema.info?.title ?? "API";
|
|
1033
|
+
const version = schema.info?.version ?? "";
|
|
1034
|
+
sp.stop(`Schema: ${title}${version ? ` ${version}` : ""}`);
|
|
1035
|
+
const componentSchemas = schema.components?.schemas ?? {};
|
|
1036
|
+
const byTag = /* @__PURE__ */ new Map();
|
|
1037
|
+
for (const [pathStr, pathItem] of Object.entries(schema.paths ?? {})) {
|
|
1038
|
+
const pathLevelParams = pathItem.parameters ?? [];
|
|
1039
|
+
for (const method of ["get", "post", "put", "patch", "delete"]) {
|
|
1040
|
+
const operation = pathItem[method];
|
|
1041
|
+
if (!operation) continue;
|
|
1042
|
+
const tag = operation.tags?.[0] ?? "index";
|
|
1043
|
+
if (!byTag.has(tag)) byTag.set(tag, []);
|
|
1044
|
+
byTag.get(tag).push({ method, pathStr, operation, pathLevelParams });
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
if (byTag.size === 0) {
|
|
1048
|
+
logger.warn("No operations found in schema \u2014 no hook files generated");
|
|
1049
|
+
}
|
|
1050
|
+
const { apiDir, hooksDir, typesFile, snapshotImport } = resolveBackendDirs(cwd, backend, opts, isMulti);
|
|
1051
|
+
const importPaths = {
|
|
1052
|
+
snapshotImport,
|
|
1053
|
+
typesRelForApi: toRelativeImport(apiDir, typesFile),
|
|
1054
|
+
typesRelForHooks: toRelativeImport(hooksDir, typesFile),
|
|
1055
|
+
apiRelBase: toRelativeImport(hooksDir, apiDir)
|
|
1056
|
+
};
|
|
1057
|
+
await fs.mkdir(apiDir, { recursive: true });
|
|
1058
|
+
await fs.mkdir(hooksDir, { recursive: true });
|
|
1059
|
+
await fs.mkdir(path.dirname(typesFile), { recursive: true });
|
|
1060
|
+
let globalHasPaginated = false;
|
|
1061
|
+
for (const [tag, ops] of byTag.entries()) {
|
|
1062
|
+
const slug = tag.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
1063
|
+
const fileName = `${slug}.ts`;
|
|
1064
|
+
const { apiContent, hooksContent, hasPaginated } = generateTagFiles(ops, slug, componentSchemas, backend.zod ?? opts.zod, importPaths);
|
|
1065
|
+
if (hasPaginated) globalHasPaginated = true;
|
|
1066
|
+
await fs.writeFile(path.join(apiDir, fileName), apiContent, "utf8");
|
|
1067
|
+
await fs.writeFile(path.join(hooksDir, fileName), hooksContent, "utf8");
|
|
1068
|
+
const apiRel = path.relative(cwd, path.join(apiDir, fileName)).replace(/\\/g, "/");
|
|
1069
|
+
const hooksRel = path.relative(cwd, path.join(hooksDir, fileName)).replace(/\\/g, "/");
|
|
1070
|
+
logger.success(`${apiRel} + ${hooksRel} \u2014 ${ops.length} operation(s)`);
|
|
1071
|
+
}
|
|
1072
|
+
const schemaCount = Object.keys(componentSchemas).length;
|
|
1073
|
+
if (schemaCount === 0) {
|
|
1074
|
+
const exists = await fs.access(typesFile).then(() => true).catch(() => false);
|
|
1075
|
+
if (exists) {
|
|
1076
|
+
const typesRel = path.relative(cwd, typesFile).replace(/\\/g, "/");
|
|
1077
|
+
logger.warn(`${typesRel} \u2014 0 schemas in spec, keeping existing file`);
|
|
1078
|
+
}
|
|
1079
|
+
} else {
|
|
1080
|
+
const typesContent = generateTypesContent(componentSchemas, globalHasPaginated);
|
|
1081
|
+
await fs.writeFile(typesFile, typesContent, "utf8");
|
|
1082
|
+
const typesRel = path.relative(cwd, typesFile).replace(/\\/g, "/");
|
|
1083
|
+
logger.success(`${typesRel} \u2014 ${schemaCount} type(s)`);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
async function runSync(opts) {
|
|
1087
|
+
const logger = opts.logger ?? clackLogger;
|
|
1088
|
+
const fileConfig = await readSyncConfig(opts.cwd);
|
|
1089
|
+
const backends = fileConfig.backends && fileConfig.backends.length > 0 ? fileConfig.backends : [fileConfig];
|
|
1090
|
+
const isMulti = !!(fileConfig.backends && fileConfig.backends.length > 0);
|
|
1091
|
+
const runAll = async () => {
|
|
1092
|
+
for (const backend of backends) {
|
|
1093
|
+
if (isMulti && backend.name) logger.info(`\u2500\u2500 ${backend.name} \u2500\u2500`);
|
|
1094
|
+
await runSyncOnce(opts, logger, backend, isMulti);
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
await runAll();
|
|
1098
|
+
if (!opts.watch) return;
|
|
1099
|
+
logger.info("Watching for schema changes... (Ctrl+C to stop)");
|
|
1100
|
+
const lastHashes = /* @__PURE__ */ new Map();
|
|
1101
|
+
for (let i = 0; i < backends.length; i++) {
|
|
1102
|
+
const b = backends[i];
|
|
1103
|
+
try {
|
|
1104
|
+
const schema = await loadSchema({ ...opts, apiUrl: b.apiUrl ?? opts.apiUrl, filePath: b.filePath ?? opts.filePath });
|
|
1105
|
+
lastHashes.set(i, schemaHash(schema));
|
|
1106
|
+
} catch {
|
|
1107
|
+
lastHashes.set(i, "");
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
const pollMs = backends.some((b) => b.filePath ?? opts.filePath) ? 1e3 : 3e3;
|
|
1111
|
+
const interval = setInterval(async () => {
|
|
1112
|
+
for (let i = 0; i < backends.length; i++) {
|
|
1113
|
+
const b = backends[i];
|
|
1114
|
+
try {
|
|
1115
|
+
const schema = await loadSchema({ ...opts, apiUrl: b.apiUrl ?? opts.apiUrl, filePath: b.filePath ?? opts.filePath });
|
|
1116
|
+
const h2 = schemaHash(schema);
|
|
1117
|
+
if (h2 === lastHashes.get(i)) continue;
|
|
1118
|
+
lastHashes.set(i, h2);
|
|
1119
|
+
if (isMulti && b.name) logger.info(`\u2500\u2500 ${b.name} (changed) \u2500\u2500`);
|
|
1120
|
+
await runSyncOnce(opts, logger, b, isMulti);
|
|
1121
|
+
} catch (e) {
|
|
1122
|
+
logger.error(e instanceof Error ? e.message : String(e));
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}, pollMs);
|
|
1126
|
+
process.on("SIGINT", () => {
|
|
1127
|
+
clearInterval(interval);
|
|
1128
|
+
process.exit(0);
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// src/vite/index.ts
|
|
1133
|
+
function snapshotSync(opts = {}) {
|
|
1134
|
+
const syncOpts = {
|
|
1135
|
+
apiUrl: opts.apiUrl,
|
|
1136
|
+
filePath: opts.file,
|
|
1137
|
+
zod: opts.zod,
|
|
1138
|
+
cwd: process.cwd(),
|
|
1139
|
+
logger: consoleLogger
|
|
1140
|
+
};
|
|
1141
|
+
return {
|
|
1142
|
+
name: "snapshot-sync",
|
|
1143
|
+
async buildStart() {
|
|
1144
|
+
if (opts.file) {
|
|
1145
|
+
const exists = await import("fs/promises").then((fs2) => fs2.access(path2.resolve(syncOpts.cwd, opts.file))).then(() => true).catch(() => false);
|
|
1146
|
+
if (!exists) {
|
|
1147
|
+
console.warn(
|
|
1148
|
+
`[snapshot] ${opts.file} not found \u2014 skipping auto-sync. Run \`bun run sync\` or drop a schema file to enable.`
|
|
1149
|
+
);
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
await runSync(syncOpts);
|
|
1154
|
+
},
|
|
1155
|
+
configureServer(server) {
|
|
1156
|
+
if (opts.file) {
|
|
1157
|
+
server.watcher.add(opts.file);
|
|
1158
|
+
server.watcher.on("change", async (changedFile) => {
|
|
1159
|
+
if (changedFile === opts.file || changedFile.endsWith(opts.file)) {
|
|
1160
|
+
await runSync({ ...syncOpts, watch: false }).catch(console.error);
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
server.watcher.on("add", async (addedFile) => {
|
|
1164
|
+
if (addedFile === opts.file || addedFile.endsWith(opts.file)) {
|
|
1165
|
+
await runSync({ ...syncOpts, watch: false }).catch(console.error);
|
|
1166
|
+
}
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
export {
|
|
1173
|
+
snapshotSync
|
|
1174
|
+
};
|