create-react-router 7.16.0 → 8.0.0-pre.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/dist/cli.d.ts +2 -1
- package/dist/cli.js +1527 -1907
- package/package.json +19 -21
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* create-react-router
|
|
3
|
+
* create-react-router v8.0.0-pre.0
|
|
4
4
|
*
|
|
5
5
|
* Copyright (c) Remix Software Inc.
|
|
6
6
|
*
|
|
@@ -9,1996 +9,1628 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @license MIT
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
var color = {
|
|
76
|
-
supportsColor: SUPPORTS_COLOR,
|
|
77
|
-
heading: safeColor(import_picocolors.default.bold),
|
|
78
|
-
arg: safeColor(import_picocolors.default.yellowBright),
|
|
79
|
-
error: safeColor(import_picocolors.default.red),
|
|
80
|
-
warning: safeColor(import_picocolors.default.yellow),
|
|
81
|
-
hint: safeColor(import_picocolors.default.blue),
|
|
82
|
-
bold: safeColor(import_picocolors.default.bold),
|
|
83
|
-
black: safeColor(import_picocolors.default.black),
|
|
84
|
-
white: safeColor(import_picocolors.default.white),
|
|
85
|
-
blue: safeColor(import_picocolors.default.blue),
|
|
86
|
-
cyan: safeColor(import_picocolors.default.cyan),
|
|
87
|
-
red: safeColor(import_picocolors.default.red),
|
|
88
|
-
yellow: safeColor(import_picocolors.default.yellow),
|
|
89
|
-
green: safeColor(import_picocolors.default.green),
|
|
90
|
-
blackBright: safeColor(import_picocolors.default.blackBright),
|
|
91
|
-
whiteBright: safeColor(import_picocolors.default.whiteBright),
|
|
92
|
-
blueBright: safeColor(import_picocolors.default.blueBright),
|
|
93
|
-
cyanBright: safeColor(import_picocolors.default.cyanBright),
|
|
94
|
-
redBright: safeColor(import_picocolors.default.redBright),
|
|
95
|
-
yellowBright: safeColor(import_picocolors.default.yellowBright),
|
|
96
|
-
greenBright: safeColor(import_picocolors.default.greenBright),
|
|
97
|
-
bgBlack: safeColor(import_picocolors.default.bgBlack),
|
|
98
|
-
bgWhite: safeColor(import_picocolors.default.bgWhite),
|
|
99
|
-
bgBlue: safeColor(import_picocolors.default.bgBlue),
|
|
100
|
-
bgCyan: safeColor(import_picocolors.default.bgCyan),
|
|
101
|
-
bgRed: safeColor(import_picocolors.default.bgRed),
|
|
102
|
-
bgYellow: safeColor(import_picocolors.default.bgYellow),
|
|
103
|
-
bgGreen: safeColor(import_picocolors.default.bgGreen),
|
|
104
|
-
bgBlackBright: safeColor(import_picocolors.default.bgBlackBright),
|
|
105
|
-
bgWhiteBright: safeColor(import_picocolors.default.bgWhiteBright),
|
|
106
|
-
bgBlueBright: safeColor(import_picocolors.default.bgBlueBright),
|
|
107
|
-
bgCyanBright: safeColor(import_picocolors.default.bgCyanBright),
|
|
108
|
-
bgRedBright: safeColor(import_picocolors.default.bgRedBright),
|
|
109
|
-
bgYellowBright: safeColor(import_picocolors.default.bgYellowBright),
|
|
110
|
-
bgGreenBright: safeColor(import_picocolors.default.bgGreenBright),
|
|
111
|
-
gray: safeColor(import_picocolors.default.gray),
|
|
112
|
-
dim: safeColor(import_picocolors.default.dim),
|
|
113
|
-
reset: safeColor(import_picocolors.default.reset),
|
|
114
|
-
inverse: safeColor(import_picocolors.default.inverse),
|
|
115
|
-
hex: (hex) => safeColor(hexColor(hex)),
|
|
116
|
-
underline: import_picocolors.default.underline
|
|
12
|
+
import process from "node:process";
|
|
13
|
+
import fs, { existsSync } from "node:fs";
|
|
14
|
+
import { cp, readFile, readdir, realpath, writeFile } from "node:fs/promises";
|
|
15
|
+
import os from "node:os";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import stripAnsi from "strip-ansi";
|
|
18
|
+
import { execa } from "execa";
|
|
19
|
+
import arg from "arg";
|
|
20
|
+
import * as semver from "semver";
|
|
21
|
+
import sortPackageJSON from "sort-package-json";
|
|
22
|
+
import { beep, cursor, erase } from "sisteransi";
|
|
23
|
+
import EventEmitter from "node:events";
|
|
24
|
+
import readline from "node:readline";
|
|
25
|
+
import pc from "picocolors";
|
|
26
|
+
import url from "node:url";
|
|
27
|
+
import stream from "node:stream";
|
|
28
|
+
import { promisify } from "node:util";
|
|
29
|
+
import gunzip from "gunzip-maybe";
|
|
30
|
+
import tar from "tar-fs";
|
|
31
|
+
//#region utils.ts
|
|
32
|
+
const SUPPORTS_COLOR = pc.isColorSupported;
|
|
33
|
+
const color = {
|
|
34
|
+
supportsColor: SUPPORTS_COLOR,
|
|
35
|
+
heading: safeColor(pc.bold),
|
|
36
|
+
arg: safeColor(pc.yellowBright),
|
|
37
|
+
error: safeColor(pc.red),
|
|
38
|
+
warning: safeColor(pc.yellow),
|
|
39
|
+
hint: safeColor(pc.blue),
|
|
40
|
+
bold: safeColor(pc.bold),
|
|
41
|
+
black: safeColor(pc.black),
|
|
42
|
+
white: safeColor(pc.white),
|
|
43
|
+
blue: safeColor(pc.blue),
|
|
44
|
+
cyan: safeColor(pc.cyan),
|
|
45
|
+
red: safeColor(pc.red),
|
|
46
|
+
yellow: safeColor(pc.yellow),
|
|
47
|
+
green: safeColor(pc.green),
|
|
48
|
+
blackBright: safeColor(pc.blackBright),
|
|
49
|
+
whiteBright: safeColor(pc.whiteBright),
|
|
50
|
+
blueBright: safeColor(pc.blueBright),
|
|
51
|
+
cyanBright: safeColor(pc.cyanBright),
|
|
52
|
+
redBright: safeColor(pc.redBright),
|
|
53
|
+
yellowBright: safeColor(pc.yellowBright),
|
|
54
|
+
greenBright: safeColor(pc.greenBright),
|
|
55
|
+
bgBlack: safeColor(pc.bgBlack),
|
|
56
|
+
bgWhite: safeColor(pc.bgWhite),
|
|
57
|
+
bgBlue: safeColor(pc.bgBlue),
|
|
58
|
+
bgCyan: safeColor(pc.bgCyan),
|
|
59
|
+
bgRed: safeColor(pc.bgRed),
|
|
60
|
+
bgYellow: safeColor(pc.bgYellow),
|
|
61
|
+
bgGreen: safeColor(pc.bgGreen),
|
|
62
|
+
bgBlackBright: safeColor(pc.bgBlackBright),
|
|
63
|
+
bgWhiteBright: safeColor(pc.bgWhiteBright),
|
|
64
|
+
bgBlueBright: safeColor(pc.bgBlueBright),
|
|
65
|
+
bgCyanBright: safeColor(pc.bgCyanBright),
|
|
66
|
+
bgRedBright: safeColor(pc.bgRedBright),
|
|
67
|
+
bgYellowBright: safeColor(pc.bgYellowBright),
|
|
68
|
+
bgGreenBright: safeColor(pc.bgGreenBright),
|
|
69
|
+
gray: safeColor(pc.gray),
|
|
70
|
+
dim: safeColor(pc.dim),
|
|
71
|
+
reset: safeColor(pc.reset),
|
|
72
|
+
inverse: safeColor(pc.inverse),
|
|
73
|
+
hex: (hex) => safeColor(hexColor(hex)),
|
|
74
|
+
underline: pc.underline
|
|
117
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Converts a hex color string to an ANSI true-color (24-bit) formatter.
|
|
78
|
+
* Used by the loading indicator gradient animation.
|
|
79
|
+
*/
|
|
118
80
|
function hexColor(hex) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
81
|
+
let h = hex.replace("#", "");
|
|
82
|
+
let r = parseInt(h.substring(0, 2), 16);
|
|
83
|
+
let g = parseInt(h.substring(2, 4), 16);
|
|
84
|
+
let b = parseInt(h.substring(4, 6), 16);
|
|
85
|
+
return (input) => `\x1b[38;2;${r};${g};${b}m${input}\x1b[39m`;
|
|
124
86
|
}
|
|
125
87
|
function safeColor(style) {
|
|
126
|
-
|
|
88
|
+
return SUPPORTS_COLOR ? style : identity;
|
|
127
89
|
}
|
|
128
|
-
|
|
129
|
-
|
|
90
|
+
const unicode = { enabled: os.platform() !== "win32" };
|
|
91
|
+
const shouldUseAscii = () => !unicode.enabled;
|
|
130
92
|
function isInteractive() {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
return Boolean(
|
|
135
|
-
import_node_process.default.stdout.isTTY && import_node_process.default.env.TERM !== "dumb" && !("CI" in import_node_process.default.env)
|
|
136
|
-
);
|
|
93
|
+
if ("CREATE_REACT_ROUTER_FORCE_INTERACTIVE" in process.env) return true;
|
|
94
|
+
return Boolean(process.stdout.isTTY && process.env.TERM !== "dumb" && !("CI" in process.env));
|
|
137
95
|
}
|
|
138
96
|
function log(message) {
|
|
139
|
-
|
|
97
|
+
return process.stdout.write(message + "\n");
|
|
140
98
|
}
|
|
141
|
-
|
|
99
|
+
let stderr = process.stderr;
|
|
142
100
|
function logError(message) {
|
|
143
|
-
|
|
101
|
+
return stderr.write(message + "\n");
|
|
144
102
|
}
|
|
145
103
|
function logBullet(logger, colorizePrefix, colorizeText, symbol, prefix, text) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
);
|
|
152
|
-
logger(`${" ".repeat(9)}${formattedText}`);
|
|
153
|
-
} else {
|
|
154
|
-
logger(
|
|
155
|
-
`${" ".repeat(5)} ${colorizePrefix(symbol)} ${colorizePrefix(
|
|
156
|
-
prefix
|
|
157
|
-
)} ${formattedText}`
|
|
158
|
-
);
|
|
159
|
-
}
|
|
104
|
+
let formattedText = (Array.isArray(text) ? text : [text || ""].filter(Boolean)).map((textPart) => colorizeText(textPart)).join("");
|
|
105
|
+
if (process.stdout.columns < 80) {
|
|
106
|
+
logger(`${" ".repeat(5)} ${colorizePrefix(symbol)} ${colorizePrefix(prefix)}`);
|
|
107
|
+
logger(`${" ".repeat(9)}${formattedText}`);
|
|
108
|
+
} else logger(`${" ".repeat(5)} ${colorizePrefix(symbol)} ${colorizePrefix(prefix)} ${formattedText}`);
|
|
160
109
|
}
|
|
161
110
|
function debug(prefix, text) {
|
|
162
|
-
|
|
111
|
+
logBullet(log, color.yellow, color.dim, "●", prefix, text);
|
|
163
112
|
}
|
|
164
113
|
function info(prefix, text) {
|
|
165
|
-
|
|
114
|
+
logBullet(log, color.cyan, color.dim, "◼", prefix, text);
|
|
166
115
|
}
|
|
167
116
|
function error(prefix, text) {
|
|
168
|
-
|
|
169
|
-
|
|
117
|
+
log("");
|
|
118
|
+
logBullet(logError, color.red, color.error, "▲", prefix, text);
|
|
170
119
|
}
|
|
171
120
|
function sleep(ms) {
|
|
172
|
-
|
|
121
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
173
122
|
}
|
|
174
123
|
function toValidProjectName(projectName) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
return projectName.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z\d\-~]+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
|
|
124
|
+
if (isValidProjectName(projectName)) return projectName;
|
|
125
|
+
return projectName.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z\d\-~]+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
|
|
179
126
|
}
|
|
180
127
|
function isValidProjectName(projectName) {
|
|
181
|
-
|
|
182
|
-
projectName
|
|
183
|
-
);
|
|
128
|
+
return /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(projectName);
|
|
184
129
|
}
|
|
185
130
|
function identity(v) {
|
|
186
|
-
|
|
131
|
+
return v;
|
|
187
132
|
}
|
|
188
133
|
function strip(str) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
].join("|");
|
|
193
|
-
let RGX = new RegExp(pattern, "g");
|
|
194
|
-
return typeof str === "string" ? str.replace(RGX, "") : str;
|
|
134
|
+
let pattern = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"].join("|");
|
|
135
|
+
let RGX = new RegExp(pattern, "g");
|
|
136
|
+
return typeof str === "string" ? str.replace(RGX, "") : str;
|
|
195
137
|
}
|
|
196
138
|
function reverse(arr) {
|
|
197
|
-
|
|
139
|
+
return [...arr].reverse();
|
|
198
140
|
}
|
|
199
141
|
function isValidJsonObject(obj) {
|
|
200
|
-
|
|
142
|
+
return !!(obj && typeof obj === "object" && !Array.isArray(obj));
|
|
201
143
|
}
|
|
202
144
|
async function directoryExists(p) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
145
|
+
try {
|
|
146
|
+
return (await fs.promises.stat(p)).isDirectory();
|
|
147
|
+
} catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
209
150
|
}
|
|
210
151
|
async function ensureDirectory(dir) {
|
|
211
|
-
|
|
212
|
-
await import_node_fs.default.promises.mkdir(dir, { recursive: true });
|
|
213
|
-
}
|
|
152
|
+
if (!await directoryExists(dir)) await fs.promises.mkdir(dir, { recursive: true });
|
|
214
153
|
}
|
|
215
154
|
function isUrl(value) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
function clear(
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
return import_sisteransi.erase.lines(rows);
|
|
155
|
+
try {
|
|
156
|
+
new URL(value);
|
|
157
|
+
return true;
|
|
158
|
+
} catch (e) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function clear(prompt, perLine) {
|
|
163
|
+
if (!perLine) return erase.line + cursor.to(0);
|
|
164
|
+
let rows = 0;
|
|
165
|
+
let lines = prompt.split(/\r?\n/);
|
|
166
|
+
for (let line of lines) rows += 1 + Math.floor(Math.max(strip(line).length - 1, 0) / perLine);
|
|
167
|
+
return erase.lines(rows);
|
|
231
168
|
}
|
|
232
169
|
function lines(msg, perLine) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
170
|
+
let lines = String(strip(msg) || "").split(/\r?\n/);
|
|
171
|
+
if (!perLine) return lines.length;
|
|
172
|
+
return lines.map((l) => Math.ceil(l.length / perLine)).reduce((a, b) => a + b);
|
|
236
173
|
}
|
|
237
174
|
function action(key, isSelect) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
175
|
+
if (key.meta && key.name !== "escape") return;
|
|
176
|
+
if (key.ctrl) {
|
|
177
|
+
if (key.name === "a") return "first";
|
|
178
|
+
if (key.name === "c") return "abort";
|
|
179
|
+
if (key.name === "d") return "abort";
|
|
180
|
+
if (key.name === "e") return "last";
|
|
181
|
+
if (key.name === "g") return "reset";
|
|
182
|
+
}
|
|
183
|
+
if (isSelect) {
|
|
184
|
+
if (key.name === "j") return "down";
|
|
185
|
+
if (key.name === "k") return "up";
|
|
186
|
+
}
|
|
187
|
+
if (key.name === "return") return "submit";
|
|
188
|
+
if (key.name === "enter") return "submit";
|
|
189
|
+
if (key.name === "backspace") return "delete";
|
|
190
|
+
if (key.name === "delete") return "deleteForward";
|
|
191
|
+
if (key.name === "abort") return "abort";
|
|
192
|
+
if (key.name === "escape") return "exit";
|
|
193
|
+
if (key.name === "tab") return "next";
|
|
194
|
+
if (key.name === "pagedown") return "nextPage";
|
|
195
|
+
if (key.name === "pageup") return "prevPage";
|
|
196
|
+
if (key.name === "home") return "home";
|
|
197
|
+
if (key.name === "end") return "end";
|
|
198
|
+
if (key.name === "up") return "up";
|
|
199
|
+
if (key.name === "down") return "down";
|
|
200
|
+
if (key.name === "right") return "right";
|
|
201
|
+
if (key.name === "left") return "left";
|
|
202
|
+
return false;
|
|
266
203
|
}
|
|
267
204
|
function stripDirectoryFromPath(dir, filePath) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
var IGNORED_TEMPLATE_DIRECTORIES = [".git", "node_modules"];
|
|
205
|
+
let stripped = filePath;
|
|
206
|
+
if (dir.endsWith(path.sep) && filePath.startsWith(dir) || !dir.endsWith(path.sep) && filePath.startsWith(dir + path.sep)) {
|
|
207
|
+
stripped = filePath.slice(dir.length);
|
|
208
|
+
if (stripped.startsWith(path.sep)) stripped = stripped.slice(1);
|
|
209
|
+
}
|
|
210
|
+
return stripped;
|
|
211
|
+
}
|
|
212
|
+
const IGNORED_TEMPLATE_DIRECTORIES = [".git", "node_modules"];
|
|
278
213
|
async function getDirectoryFilesRecursive(dir) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
214
|
+
return (await readdir(dir, { recursive: true })).filter((file) => {
|
|
215
|
+
let parts = file.split(path.sep);
|
|
216
|
+
return parts.length <= 1 || !IGNORED_TEMPLATE_DIRECTORIES.includes(parts[0]);
|
|
217
|
+
});
|
|
283
218
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if (this.firstRender) this.firstRender = false;
|
|
352
|
-
}
|
|
353
|
-
_(c, key) {
|
|
354
|
-
throw new Error("Method _ not implemented.");
|
|
355
|
-
}
|
|
219
|
+
//#endregion
|
|
220
|
+
//#region prompts-prompt-base.ts
|
|
221
|
+
/**
|
|
222
|
+
* Adapted from https://github.com/withastro/cli-kit
|
|
223
|
+
* @license MIT License Copyright (c) 2022 Nate Moore
|
|
224
|
+
*/
|
|
225
|
+
var Prompt = class extends EventEmitter {
|
|
226
|
+
firstRender;
|
|
227
|
+
in;
|
|
228
|
+
out;
|
|
229
|
+
onRender;
|
|
230
|
+
close;
|
|
231
|
+
aborted;
|
|
232
|
+
exited;
|
|
233
|
+
closed;
|
|
234
|
+
name = "Prompt";
|
|
235
|
+
constructor(opts = {}) {
|
|
236
|
+
super();
|
|
237
|
+
this.firstRender = true;
|
|
238
|
+
this.in = opts.stdin || process.stdin;
|
|
239
|
+
this.out = opts.stdout || process.stdout;
|
|
240
|
+
this.onRender = (opts.onRender || (() => void 0)).bind(this);
|
|
241
|
+
let rl = readline.createInterface({
|
|
242
|
+
input: this.in,
|
|
243
|
+
escapeCodeTimeout: 50
|
|
244
|
+
});
|
|
245
|
+
readline.emitKeypressEvents(this.in, rl);
|
|
246
|
+
if (this.in.isTTY) this.in.setRawMode(true);
|
|
247
|
+
let isSelect = ["SelectPrompt", "MultiSelectPrompt"].indexOf(this.constructor.name) > -1;
|
|
248
|
+
let keypress = (str, key) => {
|
|
249
|
+
if (this.in.isTTY) this.in.setRawMode(true);
|
|
250
|
+
let a = action(key, isSelect);
|
|
251
|
+
if (a === false) try {
|
|
252
|
+
this._(str, key);
|
|
253
|
+
} catch (e) {}
|
|
254
|
+
else if (typeof this[a] === "function") this[a](key);
|
|
255
|
+
};
|
|
256
|
+
this.close = () => {
|
|
257
|
+
this.out.write(cursor.show);
|
|
258
|
+
this.in.removeListener("keypress", keypress);
|
|
259
|
+
if (this.in.isTTY) this.in.setRawMode(false);
|
|
260
|
+
rl.close();
|
|
261
|
+
this.emit(this.aborted ? "abort" : this.exited ? "exit" : "submit", this.value);
|
|
262
|
+
this.closed = true;
|
|
263
|
+
};
|
|
264
|
+
this.in.on("keypress", keypress);
|
|
265
|
+
}
|
|
266
|
+
get type() {
|
|
267
|
+
throw new Error("Method type not implemented.");
|
|
268
|
+
}
|
|
269
|
+
bell() {
|
|
270
|
+
this.out.write(beep);
|
|
271
|
+
}
|
|
272
|
+
fire() {
|
|
273
|
+
this.emit("state", {
|
|
274
|
+
value: this.value,
|
|
275
|
+
aborted: !!this.aborted,
|
|
276
|
+
exited: !!this.exited
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
render() {
|
|
280
|
+
this.onRender(color);
|
|
281
|
+
if (this.firstRender) this.firstRender = false;
|
|
282
|
+
}
|
|
283
|
+
_(c, key) {
|
|
284
|
+
throw new Error("Method _ not implemented.");
|
|
285
|
+
}
|
|
356
286
|
};
|
|
357
|
-
|
|
358
|
-
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region prompts-confirm.ts
|
|
289
|
+
/**
|
|
290
|
+
* Adapted from https://github.com/withastro/cli-kit
|
|
291
|
+
* @license MIT License Copyright (c) 2022 Nate Moore
|
|
292
|
+
*/
|
|
359
293
|
var ConfirmPrompt = class extends Prompt {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
this.msg,
|
|
474
|
-
this.done ? "" : this.hint ? color.dim(` (${this.hint})`) : "",
|
|
475
|
-
"\n"
|
|
476
|
-
];
|
|
477
|
-
outputText.push(" ".repeat(strip(this.label).length));
|
|
478
|
-
if (this.done) {
|
|
479
|
-
outputText.push(" ", color.dim(`${this.choices[this.cursor].label}`));
|
|
480
|
-
} else {
|
|
481
|
-
outputText.push(
|
|
482
|
-
" ",
|
|
483
|
-
this.choices.map(
|
|
484
|
-
(choice, i) => i === this.cursor ? `${color.green("\u25CF")} ${choice.label} ` : color.dim(`\u25CB ${choice.label} `)
|
|
485
|
-
).join(color.dim(" "))
|
|
486
|
-
);
|
|
487
|
-
}
|
|
488
|
-
this.outputText = outputText.join("");
|
|
489
|
-
this.out.write(import_sisteransi3.erase.line + import_sisteransi3.cursor.to(0) + this.outputText);
|
|
490
|
-
}
|
|
294
|
+
label;
|
|
295
|
+
msg;
|
|
296
|
+
value;
|
|
297
|
+
initialValue;
|
|
298
|
+
hint;
|
|
299
|
+
choices;
|
|
300
|
+
cursor;
|
|
301
|
+
done;
|
|
302
|
+
name = "ConfirmPrompt";
|
|
303
|
+
outputText;
|
|
304
|
+
constructor(opts) {
|
|
305
|
+
super(opts);
|
|
306
|
+
this.label = opts.label;
|
|
307
|
+
this.hint = opts.hint;
|
|
308
|
+
this.msg = opts.message;
|
|
309
|
+
this.value = opts.initial;
|
|
310
|
+
this.initialValue = !!opts.initial;
|
|
311
|
+
this.choices = [{
|
|
312
|
+
value: true,
|
|
313
|
+
label: "Yes"
|
|
314
|
+
}, {
|
|
315
|
+
value: false,
|
|
316
|
+
label: "No"
|
|
317
|
+
}];
|
|
318
|
+
this.cursor = this.choices.findIndex((c) => c.value === this.initialValue);
|
|
319
|
+
this.render();
|
|
320
|
+
}
|
|
321
|
+
get type() {
|
|
322
|
+
return "confirm";
|
|
323
|
+
}
|
|
324
|
+
exit() {
|
|
325
|
+
this.abort();
|
|
326
|
+
}
|
|
327
|
+
abort() {
|
|
328
|
+
this.done = this.aborted = true;
|
|
329
|
+
this.fire();
|
|
330
|
+
this.render();
|
|
331
|
+
this.out.write("\n");
|
|
332
|
+
this.close();
|
|
333
|
+
}
|
|
334
|
+
submit() {
|
|
335
|
+
this.value = this.value || false;
|
|
336
|
+
this.cursor = this.choices.findIndex((c) => c.value === this.value);
|
|
337
|
+
this.done = true;
|
|
338
|
+
this.aborted = false;
|
|
339
|
+
this.fire();
|
|
340
|
+
this.render();
|
|
341
|
+
this.out.write("\n");
|
|
342
|
+
this.close();
|
|
343
|
+
}
|
|
344
|
+
moveCursor(n) {
|
|
345
|
+
this.cursor = n;
|
|
346
|
+
this.value = this.choices[n].value;
|
|
347
|
+
this.fire();
|
|
348
|
+
}
|
|
349
|
+
reset() {
|
|
350
|
+
this.moveCursor(0);
|
|
351
|
+
this.fire();
|
|
352
|
+
this.render();
|
|
353
|
+
}
|
|
354
|
+
first() {
|
|
355
|
+
this.moveCursor(0);
|
|
356
|
+
this.render();
|
|
357
|
+
}
|
|
358
|
+
last() {
|
|
359
|
+
this.moveCursor(this.choices.length - 1);
|
|
360
|
+
this.render();
|
|
361
|
+
}
|
|
362
|
+
left() {
|
|
363
|
+
if (this.cursor === 0) this.moveCursor(this.choices.length - 1);
|
|
364
|
+
else this.moveCursor(this.cursor - 1);
|
|
365
|
+
this.render();
|
|
366
|
+
}
|
|
367
|
+
right() {
|
|
368
|
+
if (this.cursor === this.choices.length - 1) this.moveCursor(0);
|
|
369
|
+
else this.moveCursor(this.cursor + 1);
|
|
370
|
+
this.render();
|
|
371
|
+
}
|
|
372
|
+
_(c, key) {
|
|
373
|
+
if (!Number.isNaN(Number.parseInt(c))) {
|
|
374
|
+
let n = Number.parseInt(c) - 1;
|
|
375
|
+
this.moveCursor(n);
|
|
376
|
+
this.render();
|
|
377
|
+
return this.submit();
|
|
378
|
+
}
|
|
379
|
+
if (c.toLowerCase() === "y") {
|
|
380
|
+
this.value = true;
|
|
381
|
+
return this.submit();
|
|
382
|
+
}
|
|
383
|
+
if (c.toLowerCase() === "n") {
|
|
384
|
+
this.value = false;
|
|
385
|
+
return this.submit();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
render() {
|
|
389
|
+
if (this.closed) return;
|
|
390
|
+
if (this.firstRender) this.out.write(cursor.hide);
|
|
391
|
+
else this.out.write(clear(this.outputText, this.out.columns));
|
|
392
|
+
super.render();
|
|
393
|
+
let outputText = [
|
|
394
|
+
"\n",
|
|
395
|
+
this.label,
|
|
396
|
+
" ",
|
|
397
|
+
this.msg,
|
|
398
|
+
this.done ? "" : this.hint ? color.dim(` (${this.hint})`) : "",
|
|
399
|
+
"\n"
|
|
400
|
+
];
|
|
401
|
+
outputText.push(" ".repeat(strip(this.label).length));
|
|
402
|
+
if (this.done) outputText.push(" ", color.dim(`${this.choices[this.cursor].label}`));
|
|
403
|
+
else outputText.push(" ", this.choices.map((choice, i) => i === this.cursor ? `${color.green("●")} ${choice.label} ` : color.dim(`○ ${choice.label} `)).join(color.dim(" ")));
|
|
404
|
+
this.outputText = outputText.join("");
|
|
405
|
+
this.out.write(erase.line + cursor.to(0) + this.outputText);
|
|
406
|
+
}
|
|
491
407
|
};
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
408
|
+
//#endregion
|
|
409
|
+
//#region prompts-select.ts
|
|
410
|
+
/**
|
|
411
|
+
* Adapted from https://github.com/withastro/cli-kit
|
|
412
|
+
* @license MIT License Copyright (c) 2022 Nate Moore
|
|
413
|
+
*/
|
|
495
414
|
var SelectPrompt = class extends Prompt {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
this.label,
|
|
626
|
-
" ",
|
|
627
|
-
this.msg,
|
|
628
|
-
this.done ? "" : this.hint ? (this.out.columns < 80 ? "\n" + " ".repeat(8) : "") + color.dim(` (${this.hint})`) : "",
|
|
629
|
-
"\n"
|
|
630
|
-
];
|
|
631
|
-
let prefix = " ".repeat(strip(this.label).length);
|
|
632
|
-
if (this.done) {
|
|
633
|
-
outputText.push(
|
|
634
|
-
`${prefix} `,
|
|
635
|
-
color.dim(`${this.choices[this.cursor]?.label}`)
|
|
636
|
-
);
|
|
637
|
-
} else {
|
|
638
|
-
outputText.push(
|
|
639
|
-
this.choices.map(
|
|
640
|
-
(choice, i) => i === this.cursor ? `${prefix} ${color.green(
|
|
641
|
-
shouldUseAscii() ? ">" : "\u25CF"
|
|
642
|
-
)} ${this.highlight(choice.label)} ${choice.hint ? color.dim(choice.hint) : ""}` : color.dim(
|
|
643
|
-
`${prefix} ${shouldUseAscii() ? "\u2014" : "\u25CB"} ${choice.label} `
|
|
644
|
-
)
|
|
645
|
-
).join("\n")
|
|
646
|
-
);
|
|
647
|
-
}
|
|
648
|
-
this.outputText = outputText.join("");
|
|
649
|
-
this.out.write(import_sisteransi4.erase.line + import_sisteransi4.cursor.to(0) + this.outputText);
|
|
650
|
-
}
|
|
415
|
+
choices;
|
|
416
|
+
label;
|
|
417
|
+
msg;
|
|
418
|
+
hint;
|
|
419
|
+
value;
|
|
420
|
+
initialValue;
|
|
421
|
+
search;
|
|
422
|
+
done;
|
|
423
|
+
cursor;
|
|
424
|
+
name = "SelectPrompt";
|
|
425
|
+
_timeout;
|
|
426
|
+
outputText;
|
|
427
|
+
constructor(opts) {
|
|
428
|
+
if (!opts.choices || !Array.isArray(opts.choices) || opts.choices.length < 1) throw new Error("SelectPrompt must contain choices");
|
|
429
|
+
super(opts);
|
|
430
|
+
this.label = opts.label;
|
|
431
|
+
this.hint = opts.hint;
|
|
432
|
+
this.msg = opts.message;
|
|
433
|
+
this.value = opts.initial;
|
|
434
|
+
this.choices = opts.choices;
|
|
435
|
+
this.initialValue = opts.initial || this.choices[0].value;
|
|
436
|
+
this.cursor = this.choices.findIndex((c) => c.value === this.initialValue);
|
|
437
|
+
this.search = null;
|
|
438
|
+
this.render();
|
|
439
|
+
}
|
|
440
|
+
get type() {
|
|
441
|
+
return "select";
|
|
442
|
+
}
|
|
443
|
+
exit() {
|
|
444
|
+
this.abort();
|
|
445
|
+
}
|
|
446
|
+
abort() {
|
|
447
|
+
this.done = this.aborted = true;
|
|
448
|
+
this.cursor = this.choices.findIndex((c) => c.value === this.initialValue);
|
|
449
|
+
this.fire();
|
|
450
|
+
this.render();
|
|
451
|
+
this.out.write("\n");
|
|
452
|
+
this.close();
|
|
453
|
+
}
|
|
454
|
+
submit() {
|
|
455
|
+
this.value = this.value || void 0;
|
|
456
|
+
this.cursor = this.choices.findIndex((c) => c.value === this.value);
|
|
457
|
+
this.done = true;
|
|
458
|
+
this.aborted = false;
|
|
459
|
+
this.fire();
|
|
460
|
+
this.render();
|
|
461
|
+
this.out.write("\n");
|
|
462
|
+
this.close();
|
|
463
|
+
}
|
|
464
|
+
delete() {
|
|
465
|
+
this.search = null;
|
|
466
|
+
this.render();
|
|
467
|
+
}
|
|
468
|
+
_(c, key) {
|
|
469
|
+
if (this._timeout) clearTimeout(this._timeout);
|
|
470
|
+
if (!Number.isNaN(Number.parseInt(c))) {
|
|
471
|
+
let n = Number.parseInt(c) - 1;
|
|
472
|
+
this.moveCursor(n);
|
|
473
|
+
this.render();
|
|
474
|
+
return this.submit();
|
|
475
|
+
}
|
|
476
|
+
this.search = this.search || "";
|
|
477
|
+
this.search += c.toLowerCase();
|
|
478
|
+
let n = (!this.search ? this.choices.slice(this.cursor) : this.choices).findIndex((c) => c.label.toLowerCase().includes(this.search));
|
|
479
|
+
if (n > -1) {
|
|
480
|
+
this.moveCursor(n);
|
|
481
|
+
this.render();
|
|
482
|
+
}
|
|
483
|
+
this._timeout = setTimeout(() => {
|
|
484
|
+
this.search = null;
|
|
485
|
+
}, 500);
|
|
486
|
+
}
|
|
487
|
+
moveCursor(n) {
|
|
488
|
+
this.cursor = n;
|
|
489
|
+
this.value = this.choices[n].value;
|
|
490
|
+
this.fire();
|
|
491
|
+
}
|
|
492
|
+
reset() {
|
|
493
|
+
this.moveCursor(0);
|
|
494
|
+
this.fire();
|
|
495
|
+
this.render();
|
|
496
|
+
}
|
|
497
|
+
first() {
|
|
498
|
+
this.moveCursor(0);
|
|
499
|
+
this.render();
|
|
500
|
+
}
|
|
501
|
+
last() {
|
|
502
|
+
this.moveCursor(this.choices.length - 1);
|
|
503
|
+
this.render();
|
|
504
|
+
}
|
|
505
|
+
up() {
|
|
506
|
+
if (this.cursor === 0) this.moveCursor(this.choices.length - 1);
|
|
507
|
+
else this.moveCursor(this.cursor - 1);
|
|
508
|
+
this.render();
|
|
509
|
+
}
|
|
510
|
+
down() {
|
|
511
|
+
if (this.cursor === this.choices.length - 1) this.moveCursor(0);
|
|
512
|
+
else this.moveCursor(this.cursor + 1);
|
|
513
|
+
this.render();
|
|
514
|
+
}
|
|
515
|
+
highlight(label) {
|
|
516
|
+
if (!this.search) return label;
|
|
517
|
+
let n = label.toLowerCase().indexOf(this.search.toLowerCase());
|
|
518
|
+
if (n === -1) return label;
|
|
519
|
+
return [
|
|
520
|
+
label.slice(0, n),
|
|
521
|
+
color.underline(label.slice(n, n + this.search.length)),
|
|
522
|
+
label.slice(n + this.search.length)
|
|
523
|
+
].join("");
|
|
524
|
+
}
|
|
525
|
+
render() {
|
|
526
|
+
if (this.closed) return;
|
|
527
|
+
if (this.firstRender) this.out.write(cursor.hide);
|
|
528
|
+
else this.out.write(clear(this.outputText, this.out.columns));
|
|
529
|
+
super.render();
|
|
530
|
+
let outputText = [
|
|
531
|
+
"\n",
|
|
532
|
+
this.label,
|
|
533
|
+
" ",
|
|
534
|
+
this.msg,
|
|
535
|
+
this.done ? "" : this.hint ? (this.out.columns < 80 ? "\n" + " ".repeat(8) : "") + color.dim(` (${this.hint})`) : "",
|
|
536
|
+
"\n"
|
|
537
|
+
];
|
|
538
|
+
let prefix = " ".repeat(strip(this.label).length);
|
|
539
|
+
if (this.done) outputText.push(`${prefix} `, color.dim(`${this.choices[this.cursor]?.label}`));
|
|
540
|
+
else outputText.push(this.choices.map((choice, i) => i === this.cursor ? `${prefix} ${color.green(shouldUseAscii() ? ">" : "●")} ${this.highlight(choice.label)} ${choice.hint ? color.dim(choice.hint) : ""}` : color.dim(`${prefix} ${shouldUseAscii() ? "—" : "○"} ${choice.label} `)).join("\n"));
|
|
541
|
+
this.outputText = outputText.join("");
|
|
542
|
+
this.out.write(erase.line + cursor.to(0) + this.outputText);
|
|
543
|
+
}
|
|
651
544
|
};
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
545
|
+
//#endregion
|
|
546
|
+
//#region prompts-multi-select.ts
|
|
547
|
+
/**
|
|
548
|
+
* Adapted from https://github.com/withastro/cli-kit
|
|
549
|
+
* @license MIT License Copyright (c) 2022 Nate Moore
|
|
550
|
+
*/
|
|
655
551
|
var MultiSelectPrompt = class extends Prompt {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if (this.done) {
|
|
766
|
-
outputText.push(
|
|
767
|
-
this.choices.map(
|
|
768
|
-
(choice) => choice.selected ? `${prefix} ${color.dim(`${choice.label}`)}
|
|
769
|
-
` : ""
|
|
770
|
-
).join("").trimEnd()
|
|
771
|
-
);
|
|
772
|
-
} else {
|
|
773
|
-
outputText.push(
|
|
774
|
-
this.choices.map(
|
|
775
|
-
(choice, i) => i === this.cursor ? `${prefix.slice(0, -2)}${color.cyanBright("\u25B6")} ${choice.selected ? color.green("\u25A0") : color.whiteBright("\u25A1")} ${color.underline(choice.label)} ${choice.hint ? color.dim(choice.hint) : ""}` : color[choice.selected ? "reset" : "dim"](
|
|
776
|
-
`${prefix} ${choice.selected ? color.green("\u25A0") : "\u25A1"} ${choice.label} `
|
|
777
|
-
)
|
|
778
|
-
).join("\n")
|
|
779
|
-
);
|
|
780
|
-
outputText.push(
|
|
781
|
-
`
|
|
782
|
-
|
|
783
|
-
${prefix} Press ${color.inverse(" C ")} to continue`
|
|
784
|
-
);
|
|
785
|
-
}
|
|
786
|
-
this.outputText = outputText.join("");
|
|
787
|
-
this.out.write(import_sisteransi5.erase.line + import_sisteransi5.cursor.to(0) + this.outputText);
|
|
788
|
-
}
|
|
552
|
+
choices;
|
|
553
|
+
label;
|
|
554
|
+
msg;
|
|
555
|
+
hint;
|
|
556
|
+
value;
|
|
557
|
+
initialValue;
|
|
558
|
+
done;
|
|
559
|
+
cursor;
|
|
560
|
+
name = "MultiSelectPrompt";
|
|
561
|
+
outputText;
|
|
562
|
+
constructor(opts) {
|
|
563
|
+
if (!opts.choices || !Array.isArray(opts.choices) || opts.choices.length < 1) throw new Error("MultiSelectPrompt must contain choices");
|
|
564
|
+
super(opts);
|
|
565
|
+
this.label = opts.label;
|
|
566
|
+
this.msg = opts.message;
|
|
567
|
+
this.hint = opts.hint;
|
|
568
|
+
this.value = [];
|
|
569
|
+
this.choices = opts.choices.map((choice) => ({
|
|
570
|
+
...choice,
|
|
571
|
+
selected: false
|
|
572
|
+
})) || [];
|
|
573
|
+
this.initialValue = opts.initial || this.choices[0].value;
|
|
574
|
+
this.cursor = this.choices.findIndex((c) => c.value === this.initialValue);
|
|
575
|
+
this.render();
|
|
576
|
+
}
|
|
577
|
+
get type() {
|
|
578
|
+
return "multiselect";
|
|
579
|
+
}
|
|
580
|
+
exit() {
|
|
581
|
+
this.abort();
|
|
582
|
+
}
|
|
583
|
+
abort() {
|
|
584
|
+
this.done = this.aborted = true;
|
|
585
|
+
this.cursor = this.choices.findIndex((c) => c.value === this.initialValue);
|
|
586
|
+
this.fire();
|
|
587
|
+
this.render();
|
|
588
|
+
this.out.write("\n");
|
|
589
|
+
this.close();
|
|
590
|
+
}
|
|
591
|
+
submit() {
|
|
592
|
+
return this.toggle();
|
|
593
|
+
}
|
|
594
|
+
finish() {
|
|
595
|
+
this.value = this.value;
|
|
596
|
+
this.done = true;
|
|
597
|
+
this.aborted = false;
|
|
598
|
+
this.fire();
|
|
599
|
+
this.render();
|
|
600
|
+
this.out.write("\n");
|
|
601
|
+
this.close();
|
|
602
|
+
}
|
|
603
|
+
moveCursor(n) {
|
|
604
|
+
this.cursor = n;
|
|
605
|
+
this.fire();
|
|
606
|
+
}
|
|
607
|
+
toggle() {
|
|
608
|
+
let choice = this.choices[this.cursor];
|
|
609
|
+
if (!choice) return;
|
|
610
|
+
choice.selected = !choice.selected;
|
|
611
|
+
this.render();
|
|
612
|
+
}
|
|
613
|
+
_(c, key) {
|
|
614
|
+
if (c === " ") return this.toggle();
|
|
615
|
+
if (c.toLowerCase() === "c") return this.finish();
|
|
616
|
+
}
|
|
617
|
+
reset() {
|
|
618
|
+
this.moveCursor(0);
|
|
619
|
+
this.fire();
|
|
620
|
+
this.render();
|
|
621
|
+
}
|
|
622
|
+
first() {
|
|
623
|
+
this.moveCursor(0);
|
|
624
|
+
this.render();
|
|
625
|
+
}
|
|
626
|
+
last() {
|
|
627
|
+
this.moveCursor(this.choices.length - 1);
|
|
628
|
+
this.render();
|
|
629
|
+
}
|
|
630
|
+
up() {
|
|
631
|
+
if (this.cursor === 0) this.moveCursor(this.choices.length - 1);
|
|
632
|
+
else this.moveCursor(this.cursor - 1);
|
|
633
|
+
this.render();
|
|
634
|
+
}
|
|
635
|
+
down() {
|
|
636
|
+
if (this.cursor === this.choices.length - 1) this.moveCursor(0);
|
|
637
|
+
else this.moveCursor(this.cursor + 1);
|
|
638
|
+
this.render();
|
|
639
|
+
}
|
|
640
|
+
render() {
|
|
641
|
+
if (this.closed) return;
|
|
642
|
+
if (this.firstRender) this.out.write(cursor.hide);
|
|
643
|
+
else this.out.write(clear(this.outputText, this.out.columns));
|
|
644
|
+
super.render();
|
|
645
|
+
let outputText = [
|
|
646
|
+
"\n",
|
|
647
|
+
this.label,
|
|
648
|
+
" ",
|
|
649
|
+
this.msg,
|
|
650
|
+
"\n"
|
|
651
|
+
];
|
|
652
|
+
let prefix = " ".repeat(strip(this.label).length);
|
|
653
|
+
if (this.done) outputText.push(this.choices.map((choice) => choice.selected ? `${prefix} ${color.dim(`${choice.label}`)}\n` : "").join("").trimEnd());
|
|
654
|
+
else {
|
|
655
|
+
outputText.push(this.choices.map((choice, i) => i === this.cursor ? `${prefix.slice(0, -2)}${color.cyanBright("▶")} ${choice.selected ? color.green("■") : color.whiteBright("□")} ${color.underline(choice.label)} ${choice.hint ? color.dim(choice.hint) : ""}` : color[choice.selected ? "reset" : "dim"](`${prefix} ${choice.selected ? color.green("■") : "□"} ${choice.label} `)).join("\n"));
|
|
656
|
+
outputText.push(`\n\n${prefix} Press ${color.inverse(" C ")} to continue`);
|
|
657
|
+
}
|
|
658
|
+
this.outputText = outputText.join("");
|
|
659
|
+
this.out.write(erase.line + cursor.to(0) + this.outputText);
|
|
660
|
+
}
|
|
789
661
|
};
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
662
|
+
//#endregion
|
|
663
|
+
//#region prompts-text.ts
|
|
664
|
+
/**
|
|
665
|
+
* Adapted from https://github.com/withastro/cli-kit
|
|
666
|
+
* @license MIT License Copyright (c) 2022 Nate Moore
|
|
667
|
+
*/
|
|
793
668
|
var TextPrompt = class extends Prompt {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
this.done ? "" : this.hint ? (this.out.columns < 80 ? "\n" + " ".repeat(8) : "") + color.dim(` (${this.hint})`) : "",
|
|
990
|
-
"\n" + prefix,
|
|
991
|
-
" ",
|
|
992
|
-
this.done ? color.dim(this.rendered) : this.rendered
|
|
993
|
-
].join("");
|
|
994
|
-
if (this.error) {
|
|
995
|
-
this.outputError += ` ${color.redBright(
|
|
996
|
-
(shouldUseAscii() ? "> " : "\u25B6 ") + this.errorMsg
|
|
997
|
-
)}`;
|
|
998
|
-
}
|
|
999
|
-
this.out.write(
|
|
1000
|
-
import_sisteransi6.erase.line + import_sisteransi6.cursor.to(0) + this.outputText + import_sisteransi6.cursor.save + this.outputError + import_sisteransi6.cursor.restore + import_sisteransi6.cursor.move(
|
|
1001
|
-
this.placeholder ? (this.rendered.length - 9) * -1 : this.cursorOffset,
|
|
1002
|
-
0
|
|
1003
|
-
)
|
|
1004
|
-
);
|
|
1005
|
-
}
|
|
669
|
+
transform;
|
|
670
|
+
label;
|
|
671
|
+
scale;
|
|
672
|
+
msg;
|
|
673
|
+
initial;
|
|
674
|
+
hint;
|
|
675
|
+
validator;
|
|
676
|
+
errorMsg;
|
|
677
|
+
cursor;
|
|
678
|
+
cursorOffset;
|
|
679
|
+
clear;
|
|
680
|
+
done;
|
|
681
|
+
error;
|
|
682
|
+
red;
|
|
683
|
+
outputError;
|
|
684
|
+
name = "TextPrompt";
|
|
685
|
+
_value;
|
|
686
|
+
placeholder;
|
|
687
|
+
rendered;
|
|
688
|
+
outputText;
|
|
689
|
+
constructor(opts) {
|
|
690
|
+
super(opts);
|
|
691
|
+
this.transform = {
|
|
692
|
+
render: (v) => v,
|
|
693
|
+
scale: 1
|
|
694
|
+
};
|
|
695
|
+
this.label = opts.label;
|
|
696
|
+
this.scale = this.transform.scale;
|
|
697
|
+
this.msg = opts.message;
|
|
698
|
+
this.hint = opts.hint;
|
|
699
|
+
this.initial = opts.initial || "";
|
|
700
|
+
this.validator = opts.validate || (() => true);
|
|
701
|
+
this.value = "";
|
|
702
|
+
this.errorMsg = opts.error || "Please enter a valid value";
|
|
703
|
+
this.cursor = Number(!!this.initial);
|
|
704
|
+
this.cursorOffset = 0;
|
|
705
|
+
this.clear = clear(``, this.out.columns);
|
|
706
|
+
this.render();
|
|
707
|
+
}
|
|
708
|
+
get type() {
|
|
709
|
+
return "text";
|
|
710
|
+
}
|
|
711
|
+
set value(v) {
|
|
712
|
+
if (!v && this.initial) {
|
|
713
|
+
this.placeholder = true;
|
|
714
|
+
this.rendered = color.dim(this.initial);
|
|
715
|
+
} else {
|
|
716
|
+
this.placeholder = false;
|
|
717
|
+
this.rendered = this.transform.render(v);
|
|
718
|
+
}
|
|
719
|
+
this._value = v;
|
|
720
|
+
this.fire();
|
|
721
|
+
}
|
|
722
|
+
get value() {
|
|
723
|
+
return this._value;
|
|
724
|
+
}
|
|
725
|
+
reset() {
|
|
726
|
+
this.value = "";
|
|
727
|
+
this.cursor = Number(!!this.initial);
|
|
728
|
+
this.cursorOffset = 0;
|
|
729
|
+
this.fire();
|
|
730
|
+
this.render();
|
|
731
|
+
}
|
|
732
|
+
exit() {
|
|
733
|
+
this.abort();
|
|
734
|
+
}
|
|
735
|
+
abort() {
|
|
736
|
+
this.value = this.value || this.initial;
|
|
737
|
+
this.done = this.aborted = true;
|
|
738
|
+
this.error = false;
|
|
739
|
+
this.red = false;
|
|
740
|
+
this.fire();
|
|
741
|
+
this.render();
|
|
742
|
+
this.out.write("\n");
|
|
743
|
+
this.close();
|
|
744
|
+
}
|
|
745
|
+
async validate() {
|
|
746
|
+
let valid = await this.validator(this.value);
|
|
747
|
+
if (typeof valid === `string`) {
|
|
748
|
+
this.errorMsg = valid;
|
|
749
|
+
valid = false;
|
|
750
|
+
}
|
|
751
|
+
this.error = !valid;
|
|
752
|
+
}
|
|
753
|
+
async submit() {
|
|
754
|
+
this.value = this.value || this.initial;
|
|
755
|
+
this.cursorOffset = 0;
|
|
756
|
+
this.cursor = this.rendered.length;
|
|
757
|
+
await this.validate();
|
|
758
|
+
if (this.error) {
|
|
759
|
+
this.red = true;
|
|
760
|
+
this.fire();
|
|
761
|
+
this.render();
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
this.done = true;
|
|
765
|
+
this.aborted = false;
|
|
766
|
+
this.fire();
|
|
767
|
+
this.render();
|
|
768
|
+
this.out.write("\n");
|
|
769
|
+
this.close();
|
|
770
|
+
}
|
|
771
|
+
next() {
|
|
772
|
+
if (!this.placeholder) return this.bell();
|
|
773
|
+
this.value = this.initial;
|
|
774
|
+
this.cursor = this.rendered.length;
|
|
775
|
+
this.fire();
|
|
776
|
+
this.render();
|
|
777
|
+
}
|
|
778
|
+
moveCursor(n) {
|
|
779
|
+
if (this.placeholder) return;
|
|
780
|
+
this.cursor = this.cursor + n;
|
|
781
|
+
this.cursorOffset += n;
|
|
782
|
+
}
|
|
783
|
+
_(c, key) {
|
|
784
|
+
let s1 = this.value.slice(0, this.cursor);
|
|
785
|
+
let s2 = this.value.slice(this.cursor);
|
|
786
|
+
this.value = `${s1}${c}${s2}`;
|
|
787
|
+
this.red = false;
|
|
788
|
+
this.cursor = this.placeholder ? 0 : s1.length + 1;
|
|
789
|
+
this.render();
|
|
790
|
+
}
|
|
791
|
+
delete() {
|
|
792
|
+
if (this.isCursorAtStart()) return this.bell();
|
|
793
|
+
let s1 = this.value.slice(0, this.cursor - 1);
|
|
794
|
+
let s2 = this.value.slice(this.cursor);
|
|
795
|
+
this.value = `${s1}${s2}`;
|
|
796
|
+
this.red = false;
|
|
797
|
+
this.outputError = "";
|
|
798
|
+
this.error = false;
|
|
799
|
+
if (this.isCursorAtStart()) this.cursorOffset = 0;
|
|
800
|
+
else {
|
|
801
|
+
this.cursorOffset++;
|
|
802
|
+
this.moveCursor(-1);
|
|
803
|
+
}
|
|
804
|
+
this.render();
|
|
805
|
+
}
|
|
806
|
+
deleteForward() {
|
|
807
|
+
if (this.cursor * this.scale >= this.rendered.length || this.placeholder) return this.bell();
|
|
808
|
+
let s1 = this.value.slice(0, this.cursor);
|
|
809
|
+
let s2 = this.value.slice(this.cursor + 1);
|
|
810
|
+
this.value = `${s1}${s2}`;
|
|
811
|
+
this.red = false;
|
|
812
|
+
this.outputError = "";
|
|
813
|
+
this.error = false;
|
|
814
|
+
if (this.isCursorAtEnd()) this.cursorOffset = 0;
|
|
815
|
+
else this.cursorOffset++;
|
|
816
|
+
this.render();
|
|
817
|
+
}
|
|
818
|
+
first() {
|
|
819
|
+
this.cursor = 0;
|
|
820
|
+
this.render();
|
|
821
|
+
}
|
|
822
|
+
last() {
|
|
823
|
+
this.cursor = this.value.length;
|
|
824
|
+
this.render();
|
|
825
|
+
}
|
|
826
|
+
left() {
|
|
827
|
+
if (this.cursor <= 0 || this.placeholder) return this.bell();
|
|
828
|
+
this.moveCursor(-1);
|
|
829
|
+
this.render();
|
|
830
|
+
}
|
|
831
|
+
right() {
|
|
832
|
+
if (this.cursor * this.scale >= this.rendered.length || this.placeholder) return this.bell();
|
|
833
|
+
this.moveCursor(1);
|
|
834
|
+
this.render();
|
|
835
|
+
}
|
|
836
|
+
isCursorAtStart() {
|
|
837
|
+
return this.cursor === 0 || this.placeholder && this.cursor === 1;
|
|
838
|
+
}
|
|
839
|
+
isCursorAtEnd() {
|
|
840
|
+
return this.cursor === this.rendered.length || this.placeholder && this.cursor === this.rendered.length + 1;
|
|
841
|
+
}
|
|
842
|
+
render() {
|
|
843
|
+
if (this.closed) return;
|
|
844
|
+
if (!this.firstRender) {
|
|
845
|
+
if (this.outputError) this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
|
|
846
|
+
this.out.write(clear(this.outputText, this.out.columns));
|
|
847
|
+
}
|
|
848
|
+
super.render();
|
|
849
|
+
this.outputError = "";
|
|
850
|
+
let prefix = " ".repeat(strip(this.label).length);
|
|
851
|
+
this.outputText = [
|
|
852
|
+
"\n",
|
|
853
|
+
this.label,
|
|
854
|
+
" ",
|
|
855
|
+
this.msg,
|
|
856
|
+
this.done ? "" : this.hint ? (this.out.columns < 80 ? "\n" + " ".repeat(8) : "") + color.dim(` (${this.hint})`) : "",
|
|
857
|
+
"\n" + prefix,
|
|
858
|
+
" ",
|
|
859
|
+
this.done ? color.dim(this.rendered) : this.rendered
|
|
860
|
+
].join("");
|
|
861
|
+
if (this.error) this.outputError += ` ${color.redBright((shouldUseAscii() ? "> " : "▶ ") + this.errorMsg)}`;
|
|
862
|
+
this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore + cursor.move(this.placeholder ? (this.rendered.length - 9) * -1 : this.cursorOffset, 0));
|
|
863
|
+
}
|
|
1006
864
|
};
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
865
|
+
//#endregion
|
|
866
|
+
//#region prompt.ts
|
|
867
|
+
const prompts = {
|
|
868
|
+
text: (args) => toPrompt(TextPrompt, args),
|
|
869
|
+
confirm: (args) => toPrompt(ConfirmPrompt, args),
|
|
870
|
+
select: (args) => toPrompt(SelectPrompt, args),
|
|
871
|
+
multiselect: (args) => toPrompt(MultiSelectPrompt, args)
|
|
1014
872
|
};
|
|
1015
873
|
async function prompt(questions, opts = {}) {
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
return answers;
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
return answers;
|
|
874
|
+
let { onSubmit = identity, onCancel = () => process.exit(0), stdin = process.stdin, stdout = process.stdout } = opts;
|
|
875
|
+
let answers = {};
|
|
876
|
+
let questionsArray = Array.isArray(questions) ? questions : [questions];
|
|
877
|
+
let answer;
|
|
878
|
+
let quit;
|
|
879
|
+
let name;
|
|
880
|
+
let type;
|
|
881
|
+
for (let question of questionsArray) {
|
|
882
|
+
({name, type} = question);
|
|
883
|
+
try {
|
|
884
|
+
answer = await prompts[type](Object.assign({
|
|
885
|
+
stdin,
|
|
886
|
+
stdout
|
|
887
|
+
}, question));
|
|
888
|
+
answers[name] = answer;
|
|
889
|
+
quit = await onSubmit(question, answer, answers);
|
|
890
|
+
} catch (e) {
|
|
891
|
+
quit = !await onCancel(question, answers);
|
|
892
|
+
}
|
|
893
|
+
if (quit) return answers;
|
|
894
|
+
}
|
|
895
|
+
return answers;
|
|
1042
896
|
}
|
|
1043
897
|
function toPrompt(el, args, opts = {}) {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
"#ffffed",
|
|
1085
|
-
"#f7f8ca",
|
|
1086
|
-
"#f7f8ca",
|
|
1087
|
-
"#eae6ba",
|
|
1088
|
-
"#eae6ba",
|
|
1089
|
-
"#eae6ba",
|
|
1090
|
-
"#dadada",
|
|
1091
|
-
"#dadada",
|
|
1092
|
-
"#ffffff"
|
|
898
|
+
if (el !== TextPrompt && el !== ConfirmPrompt && el !== SelectPrompt && el !== MultiSelectPrompt) throw new Error(`Invalid prompt type: ${el.name}`);
|
|
899
|
+
return new Promise((res, rej) => {
|
|
900
|
+
let p = new el(args, opts);
|
|
901
|
+
let onAbort = args.onAbort || opts.onAbort || identity;
|
|
902
|
+
let onSubmit = args.onSubmit || opts.onSubmit || identity;
|
|
903
|
+
let onExit = args.onExit || opts.onExit || identity;
|
|
904
|
+
p.on("state", args.onState || identity);
|
|
905
|
+
p.on("submit", (x) => res(onSubmit(x)));
|
|
906
|
+
p.on("exit", (x) => res(onExit(x)));
|
|
907
|
+
p.on("abort", (x) => rej(onAbort(x)));
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
//#endregion
|
|
911
|
+
//#region loading-indicator.ts
|
|
912
|
+
const GRADIENT_COLORS = [
|
|
913
|
+
"#ffffff",
|
|
914
|
+
"#dadada",
|
|
915
|
+
"#dadada",
|
|
916
|
+
"#a8deaa",
|
|
917
|
+
"#a8deaa",
|
|
918
|
+
"#a8deaa",
|
|
919
|
+
"#d0f0bd",
|
|
920
|
+
"#d0f0bd",
|
|
921
|
+
"#ffffed",
|
|
922
|
+
"#ffffed",
|
|
923
|
+
"#ffffed",
|
|
924
|
+
"#ffffed",
|
|
925
|
+
"#ffffed",
|
|
926
|
+
"#ffffed",
|
|
927
|
+
"#ffffed",
|
|
928
|
+
"#ffffed",
|
|
929
|
+
"#ffffed",
|
|
930
|
+
"#f7f8ca",
|
|
931
|
+
"#f7f8ca",
|
|
932
|
+
"#eae6ba",
|
|
933
|
+
"#eae6ba",
|
|
934
|
+
"#eae6ba",
|
|
935
|
+
"#dadada",
|
|
936
|
+
"#dadada",
|
|
937
|
+
"#ffffff"
|
|
1093
938
|
];
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
);
|
|
1103
|
-
var INDICATOR_FULL_FRAMES = [
|
|
1104
|
-
...LEADING_FRAMES,
|
|
1105
|
-
...GRADIENT_COLORS,
|
|
1106
|
-
...TRAILING_FRAMES,
|
|
1107
|
-
...reverse(GRADIENT_COLORS)
|
|
939
|
+
const MAX_FRAMES = 8;
|
|
940
|
+
const LEADING_FRAMES = Array.from({ length: MAX_FRAMES * 2 }, () => GRADIENT_COLORS[0]);
|
|
941
|
+
const TRAILING_FRAMES = Array.from({ length: MAX_FRAMES * 2 }, () => GRADIENT_COLORS[GRADIENT_COLORS.length - 1]);
|
|
942
|
+
const INDICATOR_FULL_FRAMES = [
|
|
943
|
+
...LEADING_FRAMES,
|
|
944
|
+
...GRADIENT_COLORS,
|
|
945
|
+
...TRAILING_FRAMES,
|
|
946
|
+
...reverse(GRADIENT_COLORS)
|
|
1108
947
|
];
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
);
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
if (result === tooSlow) {
|
|
1124
|
-
let loading = await gradient(color.green(start), {
|
|
1125
|
-
stdin,
|
|
1126
|
-
stdout,
|
|
1127
|
-
noMotion
|
|
1128
|
-
});
|
|
1129
|
-
await act;
|
|
1130
|
-
loading.stop();
|
|
1131
|
-
}
|
|
1132
|
-
stdout.write(`${" ".repeat(5)} ${color.green("\u2714")} ${color.green(end)}
|
|
1133
|
-
`);
|
|
948
|
+
const INDICATOR_GRADIENT = reverse(INDICATOR_FULL_FRAMES.map((_, i) => loadingIndicatorFrame(i)));
|
|
949
|
+
async function renderLoadingIndicator({ start, end, while: update = () => sleep(100), noMotion = false, stdin = process.stdin, stdout = process.stdout }) {
|
|
950
|
+
let act = update();
|
|
951
|
+
let tooSlow = Object.create(null);
|
|
952
|
+
if (await Promise.race([sleep(500).then(() => tooSlow), act]) === tooSlow) {
|
|
953
|
+
let loading = await gradient(color.green(start), {
|
|
954
|
+
stdin,
|
|
955
|
+
stdout,
|
|
956
|
+
noMotion
|
|
957
|
+
});
|
|
958
|
+
await act;
|
|
959
|
+
loading.stop();
|
|
960
|
+
}
|
|
961
|
+
stdout.write(`${" ".repeat(5)} ${color.green("✔")} ${color.green(end)}\n`);
|
|
1134
962
|
}
|
|
1135
963
|
function loadingIndicatorFrame(offset = 0) {
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
}
|
|
1143
|
-
return frames;
|
|
964
|
+
let frames = INDICATOR_FULL_FRAMES.slice(offset, offset + (MAX_FRAMES - 2));
|
|
965
|
+
if (frames.length < MAX_FRAMES - 2) {
|
|
966
|
+
let filled = new Array(MAX_FRAMES - frames.length - 2).fill(GRADIENT_COLORS[0]);
|
|
967
|
+
frames.push(...filled);
|
|
968
|
+
}
|
|
969
|
+
return frames;
|
|
1144
970
|
}
|
|
1145
971
|
function getGradientAnimationFrames() {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
logUpdate.clear();
|
|
1194
|
-
rl.close();
|
|
1195
|
-
}
|
|
1196
|
-
};
|
|
1197
|
-
loadingIndicator2.start();
|
|
1198
|
-
return loadingIndicator2;
|
|
972
|
+
return INDICATOR_GRADIENT.map((colors) => " " + colors.map((g, i) => color.hex(g)("█")).join(""));
|
|
973
|
+
}
|
|
974
|
+
async function gradient(text, { stdin = process.stdin, stdout = process.stdout, noMotion = false } = {}) {
|
|
975
|
+
let { createLogUpdate } = await import("log-update");
|
|
976
|
+
let logUpdate = createLogUpdate(stdout);
|
|
977
|
+
let frameIndex = 0;
|
|
978
|
+
let frames = getGradientAnimationFrames();
|
|
979
|
+
let rl = readline.createInterface({
|
|
980
|
+
input: stdin,
|
|
981
|
+
escapeCodeTimeout: 50
|
|
982
|
+
});
|
|
983
|
+
readline.emitKeypressEvents(stdin, rl);
|
|
984
|
+
if (stdin.isTTY) stdin.setRawMode(true);
|
|
985
|
+
function keypress(char) {
|
|
986
|
+
if (char === "") {
|
|
987
|
+
loadingIndicator.stop();
|
|
988
|
+
process.exit(0);
|
|
989
|
+
}
|
|
990
|
+
if (stdin.isTTY) stdin.setRawMode(true);
|
|
991
|
+
stdout.write(cursor.hide + erase.lines(1));
|
|
992
|
+
}
|
|
993
|
+
let done = false;
|
|
994
|
+
let loadingIndicator = {
|
|
995
|
+
start() {
|
|
996
|
+
stdout.write(cursor.hide);
|
|
997
|
+
stdin.on("keypress", keypress);
|
|
998
|
+
logUpdate(`${frames[0]} ${text}`);
|
|
999
|
+
async function loop() {
|
|
1000
|
+
if (done) return;
|
|
1001
|
+
if (frameIndex < frames.length - 1) frameIndex++;
|
|
1002
|
+
else frameIndex = 0;
|
|
1003
|
+
let frame = frames[frameIndex];
|
|
1004
|
+
logUpdate(`${(noMotion ? getMotionlessFrame(frameIndex) : color.supportsColor ? frame : getColorlessFrame(frameIndex)).padEnd(MAX_FRAMES - 1, " ")} ${text}`);
|
|
1005
|
+
if (!done) await sleep(20);
|
|
1006
|
+
loop();
|
|
1007
|
+
}
|
|
1008
|
+
loop();
|
|
1009
|
+
},
|
|
1010
|
+
stop() {
|
|
1011
|
+
done = true;
|
|
1012
|
+
stdin.removeListener("keypress", keypress);
|
|
1013
|
+
logUpdate.clear();
|
|
1014
|
+
rl.close();
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
loadingIndicator.start();
|
|
1018
|
+
return loadingIndicator;
|
|
1199
1019
|
}
|
|
1200
1020
|
function getColorlessFrame(frameIndex) {
|
|
1201
|
-
|
|
1021
|
+
return (frameIndex % 3 === 0 ? ".. .. " : frameIndex % 3 === 1 ? " .. .." : ". .. .").padEnd(27, " ");
|
|
1202
1022
|
}
|
|
1203
1023
|
function getMotionlessFrame(frameIndex) {
|
|
1204
|
-
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
// copy-template.ts
|
|
1208
|
-
var import_node_process5 = __toESM(require("process"));
|
|
1209
|
-
var import_node_url = __toESM(require("url"));
|
|
1210
|
-
var import_node_fs2 = __toESM(require("fs"));
|
|
1211
|
-
var import_node_path2 = __toESM(require("path"));
|
|
1212
|
-
var import_node_stream = __toESM(require("stream"));
|
|
1213
|
-
var import_node_util = require("util");
|
|
1214
|
-
var import_web_fetch = require("@remix-run/web-fetch");
|
|
1215
|
-
var import_gunzip_maybe = __toESM(require("gunzip-maybe"));
|
|
1216
|
-
var import_tar_fs = __toESM(require("tar-fs"));
|
|
1217
|
-
var import_proxy_agent = require("proxy-agent");
|
|
1218
|
-
var defaultAgent = new import_proxy_agent.ProxyAgent();
|
|
1219
|
-
var httpsAgent = new import_proxy_agent.ProxyAgent();
|
|
1220
|
-
httpsAgent.protocol = "https:";
|
|
1221
|
-
function agent(url2) {
|
|
1222
|
-
return new URL(url2).protocol === "https:" ? httpsAgent : defaultAgent;
|
|
1024
|
+
return " ".repeat(MAX_FRAMES - 1);
|
|
1223
1025
|
}
|
|
1026
|
+
//#endregion
|
|
1027
|
+
//#region copy-template.ts
|
|
1224
1028
|
async function copyTemplate(template, destPath, options) {
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1029
|
+
let { log = () => {} } = options;
|
|
1030
|
+
/**
|
|
1031
|
+
* Valid templates are:
|
|
1032
|
+
* - local file or directory on disk
|
|
1033
|
+
* - GitHub owner/repo shorthand
|
|
1034
|
+
* - GitHub owner/repo/directory shorthand
|
|
1035
|
+
* - full GitHub repo URL
|
|
1036
|
+
* - any tarball URL
|
|
1037
|
+
*/
|
|
1038
|
+
try {
|
|
1039
|
+
if (isLocalFilePath(template)) {
|
|
1040
|
+
log(`Using the template from local file at "${template}"`);
|
|
1041
|
+
let filepath = template.startsWith("file://") ? url.fileURLToPath(template) : template;
|
|
1042
|
+
return await copyTemplateFromLocalFilePath(filepath, destPath) ? { localTemplateDirectory: filepath } : void 0;
|
|
1043
|
+
}
|
|
1044
|
+
if (isGithubRepoShorthand(template)) {
|
|
1045
|
+
log(`Using the template from the "${template}" repo`);
|
|
1046
|
+
await copyTemplateFromGithubRepoShorthand(template, destPath, options);
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
if (isValidGithubRepoUrl(template)) {
|
|
1050
|
+
log(`Using the template from "${template}"`);
|
|
1051
|
+
await copyTemplateFromGithubRepoUrl(template, destPath, options);
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
if (isUrl(template)) {
|
|
1055
|
+
log(`Using the template from "${template}"`);
|
|
1056
|
+
await copyTemplateFromGenericUrl(template, destPath, options);
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
throw new CopyTemplateError(`"${color.bold(template)}" is an invalid template. Run ${color.bold("create-react-router --help")} to see supported template formats.`);
|
|
1060
|
+
} catch (error) {
|
|
1061
|
+
await options.onError(error);
|
|
1062
|
+
}
|
|
1257
1063
|
}
|
|
1258
1064
|
function isLocalFilePath(input) {
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
return false;
|
|
1265
|
-
}
|
|
1065
|
+
try {
|
|
1066
|
+
return input.startsWith("file://") || fs.existsSync(path.isAbsolute(input) ? input : path.resolve(process.cwd(), input));
|
|
1067
|
+
} catch (e) {
|
|
1068
|
+
return false;
|
|
1069
|
+
}
|
|
1266
1070
|
}
|
|
1267
|
-
async function copyTemplateFromRemoteTarball(
|
|
1268
|
-
|
|
1071
|
+
async function copyTemplateFromRemoteTarball(url, destPath, options) {
|
|
1072
|
+
return await downloadAndExtractTarball(destPath, url, options);
|
|
1269
1073
|
}
|
|
1270
1074
|
async function copyTemplateFromGithubRepoShorthand(repoShorthand, destPath, options) {
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
);
|
|
1075
|
+
let [owner, name, ...path] = repoShorthand.split("/");
|
|
1076
|
+
await downloadAndExtractRepoTarball({
|
|
1077
|
+
owner,
|
|
1078
|
+
name,
|
|
1079
|
+
filePath: path.length ? path.join("/") : null
|
|
1080
|
+
}, destPath, options);
|
|
1278
1081
|
}
|
|
1279
1082
|
async function copyTemplateFromGithubRepoUrl(repoUrl, destPath, options) {
|
|
1280
|
-
|
|
1083
|
+
await downloadAndExtractRepoTarball(getRepoInfo(repoUrl), destPath, options);
|
|
1281
1084
|
}
|
|
1282
|
-
async function copyTemplateFromGenericUrl(
|
|
1283
|
-
|
|
1085
|
+
async function copyTemplateFromGenericUrl(url, destPath, options) {
|
|
1086
|
+
await copyTemplateFromRemoteTarball(url, destPath, options);
|
|
1284
1087
|
}
|
|
1285
1088
|
async function copyTemplateFromLocalFilePath(filePath, destPath) {
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
"The provided template is not a valid local directory or tarball."
|
|
1295
|
-
);
|
|
1296
|
-
}
|
|
1297
|
-
var pipeline = (0, import_node_util.promisify)(import_node_stream.default.pipeline);
|
|
1089
|
+
if (filePath.endsWith(".tar.gz") || filePath.endsWith(".tgz")) {
|
|
1090
|
+
await extractLocalTarball(filePath, destPath);
|
|
1091
|
+
return false;
|
|
1092
|
+
}
|
|
1093
|
+
if (fs.statSync(filePath).isDirectory()) return true;
|
|
1094
|
+
throw new CopyTemplateError("The provided template is not a valid local directory or tarball.");
|
|
1095
|
+
}
|
|
1096
|
+
const pipeline = promisify(stream.pipeline);
|
|
1298
1097
|
async function extractLocalTarball(tarballPath, destPath) {
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
);
|
|
1305
|
-
} catch (error2) {
|
|
1306
|
-
throw new CopyTemplateError(
|
|
1307
|
-
`There was a problem extracting the file from the provided template. Template filepath: \`${tarballPath}\` Destination directory: \`${destPath}\` ${error2}`
|
|
1308
|
-
);
|
|
1309
|
-
}
|
|
1098
|
+
try {
|
|
1099
|
+
await pipeline(fs.createReadStream(tarballPath), gunzip(), tar.extract(destPath, { strip: 1 }));
|
|
1100
|
+
} catch (error) {
|
|
1101
|
+
throw new CopyTemplateError(`There was a problem extracting the file from the provided template. Template filepath: \`${tarballPath}\` Destination directory: \`${destPath}\` ${error}`);
|
|
1102
|
+
}
|
|
1310
1103
|
}
|
|
1311
1104
|
async function downloadAndExtractRepoTarball(repo, destPath, options) {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
}
|
|
1323
|
-
return await downloadAndExtractTarball(destPath, url2, {
|
|
1324
|
-
...options,
|
|
1325
|
-
filePath: repo.filePath ?? null
|
|
1326
|
-
});
|
|
1105
|
+
if (repo.branch && repo.filePath) return await downloadAndExtractTarball(destPath, `https://codeload.github.com/${repo.owner}/${repo.name}/tar.gz/${repo.branch}`, {
|
|
1106
|
+
...options,
|
|
1107
|
+
filePath: repo.filePath
|
|
1108
|
+
});
|
|
1109
|
+
let url = `https://api.github.com/repos/${repo.owner}/${repo.name}/tarball`;
|
|
1110
|
+
if (repo.branch) url += `/${repo.branch}`;
|
|
1111
|
+
return await downloadAndExtractTarball(destPath, url, {
|
|
1112
|
+
...options,
|
|
1113
|
+
filePath: repo.filePath ?? null
|
|
1114
|
+
});
|
|
1327
1115
|
}
|
|
1328
1116
|
async function downloadAndExtractTarball(downloadPath, tarballUrl, { token, filePath }) {
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
filePathHasFiles = true;
|
|
1396
|
-
header.name = header.name.replace(filePath, "");
|
|
1397
|
-
} else {
|
|
1398
|
-
header.name = "__IGNORE__";
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
return header;
|
|
1402
|
-
},
|
|
1403
|
-
ignore(_filename, header) {
|
|
1404
|
-
if (!header) {
|
|
1405
|
-
throw Error("Header is undefined");
|
|
1406
|
-
}
|
|
1407
|
-
return header.name === "__IGNORE__";
|
|
1408
|
-
}
|
|
1409
|
-
})
|
|
1410
|
-
);
|
|
1411
|
-
} catch (e) {
|
|
1412
|
-
throw new CopyTemplateError(
|
|
1413
|
-
`There was a problem extracting the file from the provided template. Template URL: \`${tarballUrl}\` Destination directory: \`${downloadPath}\``
|
|
1414
|
-
);
|
|
1415
|
-
}
|
|
1416
|
-
if (filePath && !filePathHasFiles) {
|
|
1417
|
-
throw new CopyTemplateError(
|
|
1418
|
-
`The path "${filePath}" was not found in this ${isGithubUrl ? "GitHub repo." : "tarball."}`
|
|
1419
|
-
);
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
async function writeReadableStreamToWritable(stream2, writable) {
|
|
1423
|
-
let reader = stream2.getReader();
|
|
1424
|
-
let flushable = writable;
|
|
1425
|
-
try {
|
|
1426
|
-
while (true) {
|
|
1427
|
-
let { done, value } = await reader.read();
|
|
1428
|
-
if (done) {
|
|
1429
|
-
writable.end();
|
|
1430
|
-
break;
|
|
1431
|
-
}
|
|
1432
|
-
writable.write(value);
|
|
1433
|
-
if (typeof flushable.flush === "function") {
|
|
1434
|
-
flushable.flush();
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
} catch (error2) {
|
|
1438
|
-
writable.destroy(error2);
|
|
1439
|
-
throw error2;
|
|
1440
|
-
}
|
|
1117
|
+
let resourceUrl = tarballUrl;
|
|
1118
|
+
let headers = {};
|
|
1119
|
+
let isGithubUrl = new URL(tarballUrl).host.endsWith("github.com");
|
|
1120
|
+
if (token && isGithubUrl) headers.Authorization = `token ${token}`;
|
|
1121
|
+
if (isGithubReleaseAssetUrl(tarballUrl)) {
|
|
1122
|
+
let info = getGithubReleaseAssetInfo(tarballUrl);
|
|
1123
|
+
headers.Accept = "application/vnd.github.v3+json";
|
|
1124
|
+
let releaseUrl = info.tag === "latest" ? `https://api.github.com/repos/${info.owner}/${info.name}/releases/latest` : `https://api.github.com/repos/${info.owner}/${info.name}/releases/tags/${info.tag}`;
|
|
1125
|
+
let response = await fetch(releaseUrl, { headers });
|
|
1126
|
+
if (response.status !== 200) throw new CopyTemplateError(`There was a problem fetching the file from GitHub. The request responded with a ${response.status} status. Please try again later.`);
|
|
1127
|
+
let body = await response.json();
|
|
1128
|
+
if (!body || typeof body !== "object" || !body.assets || !Array.isArray(body.assets)) throw new CopyTemplateError("There was a problem fetching the file from GitHub. No asset was found at that url. Please try again later.");
|
|
1129
|
+
let assetId = body.assets.find((asset) => {
|
|
1130
|
+
return info.tag === "latest" ? asset?.browser_download_url?.includes(info.asset) : asset?.browser_download_url === tarballUrl;
|
|
1131
|
+
})?.id;
|
|
1132
|
+
if (assetId == null) throw new CopyTemplateError("There was a problem fetching the file from GitHub. No asset was found at that url. Please try again later.");
|
|
1133
|
+
resourceUrl = `https://api.github.com/repos/${info.owner}/${info.name}/releases/assets/${assetId}`;
|
|
1134
|
+
headers.Accept = "application/octet-stream";
|
|
1135
|
+
}
|
|
1136
|
+
let response = await fetch(resourceUrl, { headers });
|
|
1137
|
+
if (!response.body || response.status !== 200) {
|
|
1138
|
+
if (token) throw new CopyTemplateError(`There was a problem fetching the file${isGithubUrl ? " from GitHub" : ""}. The request responded with a ${response.status} status. Perhaps your \`--token\`is expired or invalid.`);
|
|
1139
|
+
throw new CopyTemplateError(`There was a problem fetching the file${isGithubUrl ? " from GitHub" : ""}. The request responded with a ${response.status} status. Please try again later.`);
|
|
1140
|
+
}
|
|
1141
|
+
if (filePath) filePath = filePath.split(path.sep).join(path.posix.sep);
|
|
1142
|
+
let filePathHasFiles = false;
|
|
1143
|
+
try {
|
|
1144
|
+
let input = new stream.PassThrough();
|
|
1145
|
+
writeReadableStreamToWritable(response.body, input);
|
|
1146
|
+
await pipeline(input, gunzip(), tar.extract(downloadPath, {
|
|
1147
|
+
map(header) {
|
|
1148
|
+
let originalDirName = header.name.split("/")[0];
|
|
1149
|
+
header.name = header.name.replace(`${originalDirName}/`, "");
|
|
1150
|
+
if (filePath) if (filePath.endsWith(path.posix.sep) && header.name.startsWith(filePath) || !filePath.endsWith(path.posix.sep) && header.name.startsWith(filePath + path.posix.sep)) {
|
|
1151
|
+
filePathHasFiles = true;
|
|
1152
|
+
header.name = header.name.replace(filePath, "");
|
|
1153
|
+
} else header.name = "__IGNORE__";
|
|
1154
|
+
return header;
|
|
1155
|
+
},
|
|
1156
|
+
ignore(_filename, header) {
|
|
1157
|
+
if (!header) throw Error("Header is undefined");
|
|
1158
|
+
return header.name === "__IGNORE__";
|
|
1159
|
+
}
|
|
1160
|
+
}));
|
|
1161
|
+
} catch (e) {
|
|
1162
|
+
throw new CopyTemplateError(`There was a problem extracting the file from the provided template. Template URL: \`${tarballUrl}\` Destination directory: \`${downloadPath}\``);
|
|
1163
|
+
}
|
|
1164
|
+
if (filePath && !filePathHasFiles) throw new CopyTemplateError(`The path "${filePath}" was not found in this ${isGithubUrl ? "GitHub repo." : "tarball."}`);
|
|
1165
|
+
}
|
|
1166
|
+
async function writeReadableStreamToWritable(stream, writable) {
|
|
1167
|
+
let reader = stream.getReader();
|
|
1168
|
+
let flushable = writable;
|
|
1169
|
+
try {
|
|
1170
|
+
while (true) {
|
|
1171
|
+
let { done, value } = await reader.read();
|
|
1172
|
+
if (done) {
|
|
1173
|
+
writable.end();
|
|
1174
|
+
break;
|
|
1175
|
+
}
|
|
1176
|
+
writable.write(value);
|
|
1177
|
+
if (typeof flushable.flush === "function") flushable.flush();
|
|
1178
|
+
}
|
|
1179
|
+
} catch (error) {
|
|
1180
|
+
writable.destroy(error);
|
|
1181
|
+
throw error;
|
|
1182
|
+
}
|
|
1441
1183
|
}
|
|
1442
1184
|
function isValidGithubRepoUrl(input) {
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
// https://github.com/:owner/:repo
|
|
1452
|
-
// https://github.com/:owner/:repo/tree/:ref
|
|
1453
|
-
pathSegments.length >= 2 && (pathSegments.length > 2 ? pathSegments[2] === "tree" && pathSegments.length >= 4 : true);
|
|
1454
|
-
} catch (e) {
|
|
1455
|
-
return false;
|
|
1456
|
-
}
|
|
1185
|
+
if (!isUrl(input)) return false;
|
|
1186
|
+
try {
|
|
1187
|
+
let url = new URL(input);
|
|
1188
|
+
let pathSegments = url.pathname.slice(1).split("/");
|
|
1189
|
+
return url.protocol === "https:" && url.hostname === "github.com" && pathSegments.length >= 2 && (pathSegments.length > 2 ? pathSegments[2] === "tree" && pathSegments.length >= 4 : true);
|
|
1190
|
+
} catch (e) {
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1457
1193
|
}
|
|
1458
1194
|
function isGithubRepoShorthand(value) {
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1195
|
+
if (isUrl(value)) return false;
|
|
1196
|
+
return /^[\w-]+\/[\w-.]+(\/[\w-.]+)*$/.test(value);
|
|
1197
|
+
}
|
|
1198
|
+
function isGithubReleaseAssetUrl(url) {
|
|
1199
|
+
/**
|
|
1200
|
+
* Accounts for the following formats:
|
|
1201
|
+
* https://github.com/owner/repository/releases/download/v0.0.1/template.tar.gz
|
|
1202
|
+
* ~or~
|
|
1203
|
+
* https://github.com/owner/repository/releases/latest/download/template.tar.gz
|
|
1204
|
+
*/
|
|
1205
|
+
return url.startsWith("https://github.com") && (url.includes("/releases/download/") || url.includes("/releases/latest/download/"));
|
|
1466
1206
|
}
|
|
1467
1207
|
function getGithubReleaseAssetInfo(browserUrl) {
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
asset,
|
|
1478
|
-
tag
|
|
1479
|
-
};
|
|
1208
|
+
let [, owner, name, , downloadOrLatest, tag, asset] = new URL(browserUrl).pathname.split("/");
|
|
1209
|
+
if (downloadOrLatest === "latest" && tag === "download") tag = "latest";
|
|
1210
|
+
return {
|
|
1211
|
+
browserUrl,
|
|
1212
|
+
owner,
|
|
1213
|
+
name,
|
|
1214
|
+
asset,
|
|
1215
|
+
tag
|
|
1216
|
+
};
|
|
1480
1217
|
}
|
|
1481
1218
|
function getRepoInfo(validatedGithubUrl) {
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
// If we've validated the GitHub URL and there is a tree, there will also be
|
|
1497
|
-
// a branch
|
|
1498
|
-
branch,
|
|
1499
|
-
filePath: filePath === "" || filePath === "/" ? null : filePath
|
|
1500
|
-
};
|
|
1219
|
+
let [, owner, name, tree, branch, ...file] = new URL(validatedGithubUrl).pathname.split("/");
|
|
1220
|
+
let filePath = file.join("/");
|
|
1221
|
+
if (tree === void 0) return {
|
|
1222
|
+
owner,
|
|
1223
|
+
name,
|
|
1224
|
+
branch: null,
|
|
1225
|
+
filePath: null
|
|
1226
|
+
};
|
|
1227
|
+
return {
|
|
1228
|
+
owner,
|
|
1229
|
+
name,
|
|
1230
|
+
branch,
|
|
1231
|
+
filePath: filePath === "" || filePath === "/" ? null : filePath
|
|
1232
|
+
};
|
|
1501
1233
|
}
|
|
1502
1234
|
var CopyTemplateError = class extends Error {
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1235
|
+
constructor(message) {
|
|
1236
|
+
super(message);
|
|
1237
|
+
this.name = "CopyTemplateError";
|
|
1238
|
+
}
|
|
1507
1239
|
};
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
).version;
|
|
1597
|
-
} else {
|
|
1598
|
-
log(
|
|
1599
|
-
`
|
|
1600
|
-
${color.warning(
|
|
1601
|
-
`${selectedReactRouterVersion} is an invalid version specifier. Using React Router v${version}.`
|
|
1602
|
-
)}`
|
|
1603
|
-
);
|
|
1604
|
-
selectedReactRouterVersion = void 0;
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
let context = {
|
|
1608
|
-
tempDir: import_node_path3.default.join(
|
|
1609
|
-
await (0, import_promises2.realpath)(import_node_os2.default.tmpdir()),
|
|
1610
|
-
`create-react-router--${Math.random().toString(36).substr(2, 8)}`
|
|
1611
|
-
),
|
|
1612
|
-
cwd,
|
|
1613
|
-
overwrite,
|
|
1614
|
-
interactive,
|
|
1615
|
-
debug: debug2,
|
|
1616
|
-
git: git ?? (noGit ? false : yes),
|
|
1617
|
-
help,
|
|
1618
|
-
install: install ?? (noInstall ? false : yes),
|
|
1619
|
-
showInstallOutput,
|
|
1620
|
-
noMotion,
|
|
1621
|
-
pkgManager: validatePackageManager(
|
|
1622
|
-
pkgManager ?? // npm, pnpm, Yarn, Bun and Deno (v2.0.5+) set the user agent environment variable that can be used
|
|
1623
|
-
// to determine which package manager ran the command.
|
|
1624
|
-
(import_node_process6.default.env.npm_config_user_agent ?? "npm").split("/")[0]
|
|
1625
|
-
),
|
|
1626
|
-
projectName,
|
|
1627
|
-
prompt,
|
|
1628
|
-
reactRouterVersion: selectedReactRouterVersion || version,
|
|
1629
|
-
template,
|
|
1630
|
-
token,
|
|
1631
|
-
versionRequested
|
|
1632
|
-
};
|
|
1633
|
-
return context;
|
|
1240
|
+
//#endregion
|
|
1241
|
+
//#region package.json
|
|
1242
|
+
var version = "8.0.0-pre.0";
|
|
1243
|
+
//#endregion
|
|
1244
|
+
//#region index.ts
|
|
1245
|
+
async function createReactRouter(argv) {
|
|
1246
|
+
let ctx = await getContext(argv);
|
|
1247
|
+
if (ctx.help) {
|
|
1248
|
+
printHelp(ctx);
|
|
1249
|
+
return;
|
|
1250
|
+
}
|
|
1251
|
+
if (ctx.versionRequested) {
|
|
1252
|
+
log(version);
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
let steps = [
|
|
1256
|
+
introStep,
|
|
1257
|
+
projectNameStep,
|
|
1258
|
+
copyTemplateToTempDirStep,
|
|
1259
|
+
copyTempDirToAppDirStep,
|
|
1260
|
+
gitInitQuestionStep,
|
|
1261
|
+
installDependenciesQuestionStep,
|
|
1262
|
+
installDependenciesStep,
|
|
1263
|
+
gitInitStep,
|
|
1264
|
+
doneStep
|
|
1265
|
+
];
|
|
1266
|
+
try {
|
|
1267
|
+
for (let step of steps) await step(ctx);
|
|
1268
|
+
} catch (err) {
|
|
1269
|
+
if (ctx.debug) console.error(err);
|
|
1270
|
+
throw err;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
async function getContext(argv) {
|
|
1274
|
+
let flags = arg({
|
|
1275
|
+
"--debug": Boolean,
|
|
1276
|
+
"--react-router-version": String,
|
|
1277
|
+
"-v": "--react-router-version",
|
|
1278
|
+
"--template": String,
|
|
1279
|
+
"--token": String,
|
|
1280
|
+
"--yes": Boolean,
|
|
1281
|
+
"-y": "--yes",
|
|
1282
|
+
"--install": Boolean,
|
|
1283
|
+
"--no-install": Boolean,
|
|
1284
|
+
"--package-manager": String,
|
|
1285
|
+
"--show-install-output": Boolean,
|
|
1286
|
+
"--git-init": Boolean,
|
|
1287
|
+
"--no-git-init": Boolean,
|
|
1288
|
+
"--help": Boolean,
|
|
1289
|
+
"-h": "--help",
|
|
1290
|
+
"--version": Boolean,
|
|
1291
|
+
"--V": "--version",
|
|
1292
|
+
"--no-color": Boolean,
|
|
1293
|
+
"--no-motion": Boolean,
|
|
1294
|
+
"--overwrite": Boolean
|
|
1295
|
+
}, {
|
|
1296
|
+
argv,
|
|
1297
|
+
permissive: true
|
|
1298
|
+
});
|
|
1299
|
+
let { "--debug": debug = false, "--help": help = false, "--react-router-version": selectedReactRouterVersion, "--template": template, "--token": token, "--install": install, "--no-install": noInstall, "--package-manager": pkgManager, "--show-install-output": showInstallOutput = false, "--git-init": git, "--no-git-init": noGit, "--no-motion": noMotion, "--yes": yes, "--version": versionRequested, "--overwrite": overwrite } = flags;
|
|
1300
|
+
let cwd = flags["_"][0];
|
|
1301
|
+
let interactive = isInteractive();
|
|
1302
|
+
let projectName = cwd;
|
|
1303
|
+
if (!interactive) yes = true;
|
|
1304
|
+
if (selectedReactRouterVersion) if (semver.valid(selectedReactRouterVersion)) {} else if (semver.coerce(selectedReactRouterVersion)) selectedReactRouterVersion = semver.coerce(selectedReactRouterVersion).version;
|
|
1305
|
+
else {
|
|
1306
|
+
log(`\n${color.warning(`${selectedReactRouterVersion} is an invalid version specifier. Using React Router v${version}.`)}`);
|
|
1307
|
+
selectedReactRouterVersion = void 0;
|
|
1308
|
+
}
|
|
1309
|
+
return {
|
|
1310
|
+
tempDir: path.join(await realpath(os.tmpdir()), `create-react-router--${Math.random().toString(36).substr(2, 8)}`),
|
|
1311
|
+
cwd,
|
|
1312
|
+
overwrite,
|
|
1313
|
+
interactive,
|
|
1314
|
+
debug,
|
|
1315
|
+
git: git ?? (noGit ? false : yes),
|
|
1316
|
+
help,
|
|
1317
|
+
install: install ?? (noInstall ? false : yes),
|
|
1318
|
+
showInstallOutput,
|
|
1319
|
+
noMotion,
|
|
1320
|
+
pkgManager: validatePackageManager(pkgManager ?? (process.env.npm_config_user_agent ?? "npm").split("/")[0]),
|
|
1321
|
+
projectName,
|
|
1322
|
+
prompt,
|
|
1323
|
+
reactRouterVersion: selectedReactRouterVersion || version,
|
|
1324
|
+
template,
|
|
1325
|
+
token,
|
|
1326
|
+
versionRequested
|
|
1327
|
+
};
|
|
1634
1328
|
}
|
|
1635
1329
|
async function introStep(ctx) {
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
`Using default options. This is equivalent to running with the `,
|
|
1646
|
-
color.reset("--yes"),
|
|
1647
|
-
` flag.`
|
|
1648
|
-
]);
|
|
1649
|
-
}
|
|
1330
|
+
log(`\n${" ".repeat(9)}${color.green(color.bold("create-react-router"))} ${color.bold(`v${ctx.reactRouterVersion}`)}`);
|
|
1331
|
+
if (!ctx.interactive) {
|
|
1332
|
+
log("");
|
|
1333
|
+
info("Shell is not interactive.", [
|
|
1334
|
+
`Using default options. This is equivalent to running with the `,
|
|
1335
|
+
color.reset("--yes"),
|
|
1336
|
+
` flag.`
|
|
1337
|
+
]);
|
|
1338
|
+
}
|
|
1650
1339
|
}
|
|
1651
1340
|
async function projectNameStep(ctx) {
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1341
|
+
if (!ctx.interactive && !ctx.cwd) {
|
|
1342
|
+
error("Oh no!", "No project directory provided");
|
|
1343
|
+
throw new Error("No project directory provided");
|
|
1344
|
+
}
|
|
1345
|
+
if (ctx.cwd) {
|
|
1346
|
+
await sleep(100);
|
|
1347
|
+
info("Directory:", [
|
|
1348
|
+
"Using ",
|
|
1349
|
+
color.reset(ctx.cwd),
|
|
1350
|
+
" as project directory"
|
|
1351
|
+
]);
|
|
1352
|
+
}
|
|
1353
|
+
if (!ctx.cwd) {
|
|
1354
|
+
let { name } = await ctx.prompt({
|
|
1355
|
+
name: "name",
|
|
1356
|
+
type: "text",
|
|
1357
|
+
label: title("dir"),
|
|
1358
|
+
message: "Where should we create your new project?",
|
|
1359
|
+
initial: "./my-react-router-app"
|
|
1360
|
+
});
|
|
1361
|
+
ctx.cwd = name;
|
|
1362
|
+
ctx.projectName = toValidProjectName(name);
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
let name = ctx.cwd;
|
|
1366
|
+
if (name === "." || name === "./") {
|
|
1367
|
+
let parts = process.cwd().split(path.sep);
|
|
1368
|
+
name = parts[parts.length - 1];
|
|
1369
|
+
} else if (name.startsWith("./") || name.startsWith("../")) {
|
|
1370
|
+
let parts = name.split("/");
|
|
1371
|
+
name = parts[parts.length - 1];
|
|
1372
|
+
}
|
|
1373
|
+
ctx.projectName = toValidProjectName(name);
|
|
1685
1374
|
}
|
|
1686
1375
|
async function copyTemplateToTempDirStep(ctx) {
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
ctx.tempDir = import_node_path3.default.resolve(result.localTemplateDirectory);
|
|
1724
|
-
}
|
|
1725
|
-
},
|
|
1726
|
-
ctx
|
|
1727
|
-
});
|
|
1376
|
+
if (ctx.template) {
|
|
1377
|
+
log("");
|
|
1378
|
+
info("Template:", [
|
|
1379
|
+
"Using ",
|
|
1380
|
+
color.reset(ctx.template),
|
|
1381
|
+
"..."
|
|
1382
|
+
]);
|
|
1383
|
+
} else {
|
|
1384
|
+
log("");
|
|
1385
|
+
info("Using default template", ["See https://github.com/remix-run/react-router-templates for more"]);
|
|
1386
|
+
}
|
|
1387
|
+
let template = ctx.template ?? "https://github.com/remix-run/react-router-templates/tree/main/default";
|
|
1388
|
+
await loadingIndicator({
|
|
1389
|
+
start: "Template copying...",
|
|
1390
|
+
end: "Template copied",
|
|
1391
|
+
while: async () => {
|
|
1392
|
+
await ensureDirectory(ctx.tempDir);
|
|
1393
|
+
if (ctx.debug) debug(`Extracting to: ${ctx.tempDir}`);
|
|
1394
|
+
let result = await copyTemplate(template, ctx.tempDir, {
|
|
1395
|
+
debug: ctx.debug,
|
|
1396
|
+
token: ctx.token,
|
|
1397
|
+
async onError(err) {
|
|
1398
|
+
error("Oh no!", err instanceof CopyTemplateError ? err.message : "Something went wrong. Run `create-react-router --debug` to see more info.\n\nOpen an issue to report the problem at https://github.com/remix-run/react-router/issues/new");
|
|
1399
|
+
throw err;
|
|
1400
|
+
},
|
|
1401
|
+
async log(message) {
|
|
1402
|
+
if (ctx.debug) {
|
|
1403
|
+
debug(message);
|
|
1404
|
+
await sleep(500);
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
if (result?.localTemplateDirectory) ctx.tempDir = path.resolve(result.localTemplateDirectory);
|
|
1409
|
+
},
|
|
1410
|
+
ctx
|
|
1411
|
+
});
|
|
1728
1412
|
}
|
|
1729
1413
|
async function copyTempDirToAppDirStep(ctx) {
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
`Destination directory contains files that would be overwritten
|
|
1753
|
-
and no \`--overwrite\` flag was included in a non-interactive
|
|
1754
|
-
environment. The following files would be overwritten:` + getFileList(" ")
|
|
1755
|
-
);
|
|
1756
|
-
throw new Error(
|
|
1757
|
-
"File collisions detected in a non-interactive environment"
|
|
1758
|
-
);
|
|
1759
|
-
} else {
|
|
1760
|
-
if (ctx.debug) {
|
|
1761
|
-
debug(`Colliding files:${getFileList(" ")}`);
|
|
1762
|
-
}
|
|
1763
|
-
let { overwrite } = await ctx.prompt({
|
|
1764
|
-
name: "overwrite",
|
|
1765
|
-
type: "confirm",
|
|
1766
|
-
label: title("overwrite"),
|
|
1767
|
-
message: `Your project directory contains files that will be overwritten by
|
|
1414
|
+
await ensureDirectory(ctx.cwd);
|
|
1415
|
+
let files1 = await getDirectoryFilesRecursive(ctx.tempDir);
|
|
1416
|
+
let files2 = await getDirectoryFilesRecursive(ctx.cwd);
|
|
1417
|
+
let collisions = files1.filter((f) => files2.includes(f)).sort((a, b) => a.localeCompare(b));
|
|
1418
|
+
if (collisions.length > 0) {
|
|
1419
|
+
let getFileList = (prefix) => {
|
|
1420
|
+
let moreFiles = collisions.length - 5;
|
|
1421
|
+
let lines = ["", ...collisions.slice(0, 5)];
|
|
1422
|
+
if (moreFiles > 0) lines.push(`and ${moreFiles} more...`);
|
|
1423
|
+
return lines.join(`\n${prefix}`);
|
|
1424
|
+
};
|
|
1425
|
+
if (ctx.overwrite) info("Overwrite:", `overwriting files due to \`--overwrite\`:${getFileList(" ")}`);
|
|
1426
|
+
else if (!ctx.interactive) {
|
|
1427
|
+
error("Oh no!", "Destination directory contains files that would be overwritten\n and no `--overwrite` flag was included in a non-interactive\n environment. The following files would be overwritten:" + getFileList(" "));
|
|
1428
|
+
throw new Error("File collisions detected in a non-interactive environment");
|
|
1429
|
+
} else {
|
|
1430
|
+
if (ctx.debug) debug(`Colliding files:${getFileList(" ")}`);
|
|
1431
|
+
let { overwrite } = await ctx.prompt({
|
|
1432
|
+
name: "overwrite",
|
|
1433
|
+
type: "confirm",
|
|
1434
|
+
label: title("overwrite"),
|
|
1435
|
+
message: `Your project directory contains files that will be overwritten by
|
|
1768
1436
|
this template (you can force with \`--overwrite\`)
|
|
1769
1437
|
|
|
1770
|
-
Files that would be overwritten:${getFileList(" ")}
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
}
|
|
1789
|
-
return false;
|
|
1790
|
-
}
|
|
1791
|
-
return true;
|
|
1792
|
-
},
|
|
1793
|
-
recursive: true
|
|
1794
|
-
});
|
|
1795
|
-
await updatePackageJSON(ctx);
|
|
1438
|
+
Files that would be overwritten:${getFileList(" ")}\n\n Do you wish to continue?\n `,
|
|
1439
|
+
initial: false
|
|
1440
|
+
});
|
|
1441
|
+
if (!overwrite) throw new Error("Exiting to avoid overwriting files");
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
await cp(ctx.tempDir, ctx.cwd, {
|
|
1445
|
+
filter(src) {
|
|
1446
|
+
let file = stripDirectoryFromPath(ctx.tempDir, src);
|
|
1447
|
+
if (IGNORED_TEMPLATE_DIRECTORIES.includes(file)) {
|
|
1448
|
+
if (ctx.debug) debug(`Skipping copy of ${file} directory from template`);
|
|
1449
|
+
return false;
|
|
1450
|
+
}
|
|
1451
|
+
return true;
|
|
1452
|
+
},
|
|
1453
|
+
recursive: true
|
|
1454
|
+
});
|
|
1455
|
+
await updatePackageJSON(ctx);
|
|
1796
1456
|
}
|
|
1797
1457
|
async function installDependenciesQuestionStep(ctx) {
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1458
|
+
if (ctx.install === void 0) {
|
|
1459
|
+
let { deps = true } = await ctx.prompt({
|
|
1460
|
+
name: "deps",
|
|
1461
|
+
type: "confirm",
|
|
1462
|
+
label: title("deps"),
|
|
1463
|
+
message: `Install dependencies with ${ctx.pkgManager}?`,
|
|
1464
|
+
hint: "recommended",
|
|
1465
|
+
initial: true
|
|
1466
|
+
});
|
|
1467
|
+
ctx.install = deps;
|
|
1468
|
+
}
|
|
1809
1469
|
}
|
|
1810
1470
|
async function installDependenciesStep(ctx) {
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1471
|
+
let { install, pkgManager, showInstallOutput, cwd } = ctx;
|
|
1472
|
+
if (!install) {
|
|
1473
|
+
await sleep(100);
|
|
1474
|
+
info("Skipping install step.", [
|
|
1475
|
+
"Remember to install dependencies after setup with ",
|
|
1476
|
+
color.reset(`${pkgManager} install`),
|
|
1477
|
+
"."
|
|
1478
|
+
]);
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1481
|
+
function runInstall() {
|
|
1482
|
+
return installDependencies({
|
|
1483
|
+
cwd,
|
|
1484
|
+
pkgManager,
|
|
1485
|
+
showInstallOutput
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
if (showInstallOutput) {
|
|
1489
|
+
log("");
|
|
1490
|
+
info(`Install`, `Dependencies installing with ${pkgManager}...`);
|
|
1491
|
+
log("");
|
|
1492
|
+
await runInstall();
|
|
1493
|
+
log("");
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
log("");
|
|
1497
|
+
await loadingIndicator({
|
|
1498
|
+
start: `Dependencies installing with ${pkgManager}...`,
|
|
1499
|
+
end: "Dependencies installed",
|
|
1500
|
+
while: runInstall,
|
|
1501
|
+
ctx
|
|
1502
|
+
});
|
|
1843
1503
|
}
|
|
1844
1504
|
async function gitInitQuestionStep(ctx) {
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
}
|
|
1860
|
-
ctx.git = git ?? false;
|
|
1505
|
+
if (existsSync(path.join(ctx.cwd, ".git"))) {
|
|
1506
|
+
info("Nice!", `Git has already been initialized`);
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
let git = ctx.git;
|
|
1510
|
+
if (ctx.git === void 0) ({git} = await ctx.prompt({
|
|
1511
|
+
name: "git",
|
|
1512
|
+
type: "confirm",
|
|
1513
|
+
label: title("git"),
|
|
1514
|
+
message: `Initialize a new git repository?`,
|
|
1515
|
+
hint: "recommended",
|
|
1516
|
+
initial: true
|
|
1517
|
+
}));
|
|
1518
|
+
ctx.git = git ?? false;
|
|
1861
1519
|
}
|
|
1862
1520
|
async function gitInitStep(ctx) {
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1521
|
+
if (!ctx.git) return;
|
|
1522
|
+
if (existsSync(path.join(ctx.cwd, ".git"))) {
|
|
1523
|
+
log("");
|
|
1524
|
+
info("Nice!", `Git has already been initialized`);
|
|
1525
|
+
return;
|
|
1526
|
+
}
|
|
1527
|
+
log("");
|
|
1528
|
+
await loadingIndicator({
|
|
1529
|
+
start: "Git initializing...",
|
|
1530
|
+
end: "Git initialized",
|
|
1531
|
+
while: async () => {
|
|
1532
|
+
let options = {
|
|
1533
|
+
cwd: ctx.cwd,
|
|
1534
|
+
stdio: "ignore"
|
|
1535
|
+
};
|
|
1536
|
+
let commitMsg = "Initial commit from create-react-router";
|
|
1537
|
+
try {
|
|
1538
|
+
await execa("git", ["init"], options);
|
|
1539
|
+
await execa("git", ["add", "."], options);
|
|
1540
|
+
await execa("git", [
|
|
1541
|
+
"commit",
|
|
1542
|
+
"-m",
|
|
1543
|
+
commitMsg
|
|
1544
|
+
], options);
|
|
1545
|
+
} catch (err) {
|
|
1546
|
+
error("Oh no!", "Failed to initialize git.");
|
|
1547
|
+
throw err;
|
|
1548
|
+
}
|
|
1549
|
+
},
|
|
1550
|
+
ctx
|
|
1551
|
+
});
|
|
1889
1552
|
}
|
|
1890
1553
|
async function doneStep(ctx) {
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
`
|
|
1915
|
-
${prefix}Join the community at ${color.cyan(`https://rmx.as/discord`)}
|
|
1916
|
-
`
|
|
1917
|
-
);
|
|
1918
|
-
await sleep(200);
|
|
1919
|
-
}
|
|
1920
|
-
var validPackageManagers = ["npm", "yarn", "pnpm", "bun", "deno"];
|
|
1554
|
+
let projectDir = path.relative(process.cwd(), ctx.cwd);
|
|
1555
|
+
let max = process.stdout.columns;
|
|
1556
|
+
let prefix = max < 80 ? " " : " ".repeat(9);
|
|
1557
|
+
await sleep(200);
|
|
1558
|
+
log(`\n ${color.bgWhite(color.black(" done "))} That's it!`);
|
|
1559
|
+
await sleep(100);
|
|
1560
|
+
if (projectDir !== "") {
|
|
1561
|
+
let enter = [`\n${prefix}Enter your project directory using`, color.cyan(`cd .${path.sep}${projectDir}`)];
|
|
1562
|
+
let len = enter[0].length + stripAnsi(enter[1]).length;
|
|
1563
|
+
log(enter.join(len > max ? "\n" + prefix : " "));
|
|
1564
|
+
}
|
|
1565
|
+
log(`${prefix}Check out ${color.bold("README.md")} for development and deploy instructions.`);
|
|
1566
|
+
await sleep(100);
|
|
1567
|
+
log(`\n${prefix}Join the community at ${color.cyan(`https://rmx.as/discord`)}\n`);
|
|
1568
|
+
await sleep(200);
|
|
1569
|
+
}
|
|
1570
|
+
const validPackageManagers = [
|
|
1571
|
+
"npm",
|
|
1572
|
+
"yarn",
|
|
1573
|
+
"pnpm",
|
|
1574
|
+
"bun",
|
|
1575
|
+
"deno"
|
|
1576
|
+
];
|
|
1921
1577
|
function validatePackageManager(pkgManager) {
|
|
1922
|
-
|
|
1923
|
-
}
|
|
1924
|
-
async function installDependencies({
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
} catch (err) {
|
|
1935
|
-
error("Oh no!", "Failed to install dependencies.");
|
|
1936
|
-
throw err;
|
|
1937
|
-
}
|
|
1578
|
+
return validPackageManagers.find((name) => pkgManager === name) ?? "npm";
|
|
1579
|
+
}
|
|
1580
|
+
async function installDependencies({ pkgManager, cwd, showInstallOutput }) {
|
|
1581
|
+
try {
|
|
1582
|
+
await execa(pkgManager, ["install"], {
|
|
1583
|
+
cwd,
|
|
1584
|
+
stdio: showInstallOutput ? "inherit" : "ignore"
|
|
1585
|
+
});
|
|
1586
|
+
} catch (err) {
|
|
1587
|
+
error("Oh no!", "Failed to install dependencies.");
|
|
1588
|
+
throw err;
|
|
1589
|
+
}
|
|
1938
1590
|
}
|
|
1939
1591
|
async function updatePackageJSON(ctx) {
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
`The provided template must be a React Router project with a \`package.json\` file, but its ${pkgKey} value is invalid.`
|
|
1970
|
-
);
|
|
1971
|
-
throw new Error(`package.json ${pkgKey} are invalid`);
|
|
1972
|
-
}
|
|
1973
|
-
for (let dependency in dependencies) {
|
|
1974
|
-
let version2 = dependencies[dependency];
|
|
1975
|
-
if ((dependency.startsWith("@react-router/") || dependency === "react-router" || dependency === "react-router-dom") && version2 === "*") {
|
|
1976
|
-
dependencies[dependency] = semver.prerelease(ctx.reactRouterVersion) ? (
|
|
1977
|
-
// Templates created from prereleases should pin to a specific version
|
|
1978
|
-
ctx.reactRouterVersion
|
|
1979
|
-
) : "^" + ctx.reactRouterVersion;
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
}
|
|
1983
|
-
packageJSON.name = ctx.projectName;
|
|
1984
|
-
(0, import_promises2.writeFile)(
|
|
1985
|
-
packageJSONPath,
|
|
1986
|
-
JSON.stringify((0, import_sort_package_json.default)(packageJSON), null, 2),
|
|
1987
|
-
"utf-8"
|
|
1988
|
-
);
|
|
1592
|
+
let packageJSONPath = path.join(ctx.cwd, "package.json");
|
|
1593
|
+
if (!existsSync(packageJSONPath)) {
|
|
1594
|
+
let relativePath = path.relative(process.cwd(), ctx.cwd);
|
|
1595
|
+
error("Oh no!", `The provided template must be a React Router project with a \`package.json\` file, but that file does not exist in ${color.bold(relativePath)}.`);
|
|
1596
|
+
throw new Error(`package.json does not exist in ${ctx.cwd}`);
|
|
1597
|
+
}
|
|
1598
|
+
let contents = await readFile(packageJSONPath, "utf-8");
|
|
1599
|
+
let packageJSON;
|
|
1600
|
+
try {
|
|
1601
|
+
packageJSON = JSON.parse(contents);
|
|
1602
|
+
if (!isValidJsonObject(packageJSON)) throw Error();
|
|
1603
|
+
} catch (err) {
|
|
1604
|
+
error("Oh no!", "The provided template must be a React Router project with a `package.json` file, but that file is invalid.");
|
|
1605
|
+
throw err;
|
|
1606
|
+
}
|
|
1607
|
+
for (let pkgKey of ["dependencies", "devDependencies"]) {
|
|
1608
|
+
let dependencies = packageJSON[pkgKey];
|
|
1609
|
+
if (!dependencies) continue;
|
|
1610
|
+
if (!isValidJsonObject(dependencies)) {
|
|
1611
|
+
error("Oh no!", `The provided template must be a React Router project with a \`package.json\` file, but its ${pkgKey} value is invalid.`);
|
|
1612
|
+
throw new Error(`package.json ${pkgKey} are invalid`);
|
|
1613
|
+
}
|
|
1614
|
+
for (let dependency in dependencies) {
|
|
1615
|
+
let version = dependencies[dependency];
|
|
1616
|
+
if ((dependency.startsWith("@react-router/") || dependency === "react-router") && version === "*") dependencies[dependency] = semver.prerelease(ctx.reactRouterVersion) ? ctx.reactRouterVersion : "^" + ctx.reactRouterVersion;
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
packageJSON.name = ctx.projectName;
|
|
1620
|
+
writeFile(packageJSONPath, JSON.stringify(sortPackageJSON(packageJSON), null, 2), "utf-8");
|
|
1989
1621
|
}
|
|
1990
1622
|
async function loadingIndicator(args) {
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1623
|
+
let { ctx, ...rest } = args;
|
|
1624
|
+
await renderLoadingIndicator({
|
|
1625
|
+
...rest,
|
|
1626
|
+
noMotion: args.ctx.noMotion
|
|
1627
|
+
});
|
|
1996
1628
|
}
|
|
1997
1629
|
function title(text) {
|
|
1998
|
-
|
|
1630
|
+
return align(color.bgWhite(` ${color.black(text)} `), "end", 7) + " ";
|
|
1999
1631
|
}
|
|
2000
1632
|
function printHelp(ctx) {
|
|
2001
|
-
|
|
1633
|
+
log(`
|
|
2002
1634
|
${title("create-react-router")}
|
|
2003
1635
|
|
|
2004
1636
|
${color.heading("Usage")}:
|
|
@@ -2034,51 +1666,39 @@ React Router projects are created from templates. A template can be:
|
|
|
2034
1666
|
- a file path to a directory of files
|
|
2035
1667
|
- a file path to a tarball
|
|
2036
1668
|
${[
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
}, "")}
|
|
1669
|
+
"remix-run/react-router/templates/basic",
|
|
1670
|
+
"remix-run/react-router/examples/basic",
|
|
1671
|
+
":username/:repo",
|
|
1672
|
+
":username/:repo/:directory",
|
|
1673
|
+
"https://github.com/:username/:repo",
|
|
1674
|
+
"https://github.com/:username/:repo/tree/:branch",
|
|
1675
|
+
"https://github.com/:username/:repo/tree/:branch/:directory",
|
|
1676
|
+
"https://github.com/:username/:repo/archive/refs/tags/:tag.tar.gz",
|
|
1677
|
+
"https://example.com/template.tar.gz",
|
|
1678
|
+
"./path/to/template",
|
|
1679
|
+
"./path/to/template.tar.gz"
|
|
1680
|
+
].reduce((str, example) => {
|
|
1681
|
+
return `${str}\n${color.dim("$")} ${color.greenBright("create-react-router")} my-app ${color.arg(`--template ${example}`)}`;
|
|
1682
|
+
}, "")}
|
|
2052
1683
|
|
|
2053
1684
|
To create a new project from a template in a private GitHub repo,
|
|
2054
1685
|
pass the \`token\` flag with a personal access token with access
|
|
2055
1686
|
to that repo.
|
|
2056
|
-
|
|
2057
|
-
log(output);
|
|
1687
|
+
`);
|
|
2058
1688
|
}
|
|
2059
1689
|
function align(text, dir, len) {
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
import_node_process7.default.on("SIGTERM", () => import_node_process7.default.exit(0));
|
|
2076
|
-
var argv = import_node_process7.default.argv.slice(2).filter((arg2) => arg2 !== "--");
|
|
2077
|
-
createReactRouter(argv).then(
|
|
2078
|
-
() => import_node_process7.default.exit(0),
|
|
2079
|
-
() => import_node_process7.default.exit(1)
|
|
2080
|
-
);
|
|
2081
|
-
/**
|
|
2082
|
-
* Adapted from https://github.com/withastro/cli-kit
|
|
2083
|
-
* @license MIT License Copyright (c) 2022 Nate Moore
|
|
2084
|
-
*/
|
|
1690
|
+
let pad = Math.max(len - strip(text).length, 0);
|
|
1691
|
+
switch (dir) {
|
|
1692
|
+
case "start": return text + " ".repeat(pad);
|
|
1693
|
+
case "end": return " ".repeat(pad) + text;
|
|
1694
|
+
case "center": return " ".repeat(Math.floor(pad / 2)) + text + " ".repeat(Math.floor(pad / 2));
|
|
1695
|
+
default: return text;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
//#endregion
|
|
1699
|
+
//#region cli.ts
|
|
1700
|
+
process.on("SIGINT", () => process.exit(0));
|
|
1701
|
+
process.on("SIGTERM", () => process.exit(0));
|
|
1702
|
+
createReactRouter(process.argv.slice(2).filter((arg) => arg !== "--")).then(() => process.exit(0), () => process.exit(1));
|
|
1703
|
+
//#endregion
|
|
1704
|
+
export {};
|