create-clientkit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +228 -0
- package/THIRD-PARTY.md +61 -0
- package/bin/cli.js +52 -0
- package/dist/cli.js +2556 -0
- package/package.json +84 -0
- package/templates/astro-tailwind/base/README.md +131 -0
- package/templates/astro-tailwind/base/_gitattributes +5 -0
- package/templates/astro-tailwind/base/_gitignore +23 -0
- package/templates/astro-tailwind/base/_package.json +28 -0
- package/templates/astro-tailwind/base/astro.config.mjs +32 -0
- package/templates/astro-tailwind/base/public/favicon.svg +5 -0
- package/templates/astro-tailwind/base/src/components/Brand.astro +89 -0
- package/templates/astro-tailwind/base/src/components/Footer.astro +88 -0
- package/templates/astro-tailwind/base/src/components/Header.astro +104 -0
- package/templates/astro-tailwind/base/src/components/LaunchNotice.astro +156 -0
- package/templates/astro-tailwind/base/src/components/Seo.astro +73 -0
- package/templates/astro-tailwind/base/src/components/SocialLinks.astro +75 -0
- package/templates/astro-tailwind/base/src/components/StructuredData.astro +39 -0
- package/templates/astro-tailwind/base/src/config/site.config.ts +141 -0
- package/templates/astro-tailwind/base/src/layouts/BaseLayout.astro +121 -0
- package/templates/astro-tailwind/base/src/lib/seo.ts +87 -0
- package/templates/astro-tailwind/base/src/pages/404.astro +147 -0
- package/templates/astro-tailwind/base/src/pages/index.astro +31 -0
- package/templates/astro-tailwind/base/src/pages/robots.txt.ts +32 -0
- package/templates/astro-tailwind/base/src/styles/global.css +330 -0
- package/templates/astro-tailwind/base/tsconfig.json +11 -0
- package/templates/astro-tailwind/modes/coming-soon/_package.json +3 -0
- package/templates/astro-tailwind/modes/coming-soon/src/pages/index.astro +149 -0
- package/templates/astro-tailwind/modes/full/_package.json +3 -0
- package/templates/astro-tailwind/modes/full/src/pages/index.astro +237 -0
- package/templates/astro-tailwind/template.json +23 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,2556 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// node_modules/sisteransi/src/index.js
|
|
28
|
+
var require_src = __commonJS({
|
|
29
|
+
"node_modules/sisteransi/src/index.js"(exports, module) {
|
|
30
|
+
"use strict";
|
|
31
|
+
var ESC = "\x1B";
|
|
32
|
+
var CSI = `${ESC}[`;
|
|
33
|
+
var beep = "\x07";
|
|
34
|
+
var cursor = {
|
|
35
|
+
to(x2, y3) {
|
|
36
|
+
if (!y3) return `${CSI}${x2 + 1}G`;
|
|
37
|
+
return `${CSI}${y3 + 1};${x2 + 1}H`;
|
|
38
|
+
},
|
|
39
|
+
move(x2, y3) {
|
|
40
|
+
let ret = "";
|
|
41
|
+
if (x2 < 0) ret += `${CSI}${-x2}D`;
|
|
42
|
+
else if (x2 > 0) ret += `${CSI}${x2}C`;
|
|
43
|
+
if (y3 < 0) ret += `${CSI}${-y3}A`;
|
|
44
|
+
else if (y3 > 0) ret += `${CSI}${y3}B`;
|
|
45
|
+
return ret;
|
|
46
|
+
},
|
|
47
|
+
up: (count = 1) => `${CSI}${count}A`,
|
|
48
|
+
down: (count = 1) => `${CSI}${count}B`,
|
|
49
|
+
forward: (count = 1) => `${CSI}${count}C`,
|
|
50
|
+
backward: (count = 1) => `${CSI}${count}D`,
|
|
51
|
+
nextLine: (count = 1) => `${CSI}E`.repeat(count),
|
|
52
|
+
prevLine: (count = 1) => `${CSI}F`.repeat(count),
|
|
53
|
+
left: `${CSI}G`,
|
|
54
|
+
hide: `${CSI}?25l`,
|
|
55
|
+
show: `${CSI}?25h`,
|
|
56
|
+
save: `${ESC}7`,
|
|
57
|
+
restore: `${ESC}8`
|
|
58
|
+
};
|
|
59
|
+
var scroll = {
|
|
60
|
+
up: (count = 1) => `${CSI}S`.repeat(count),
|
|
61
|
+
down: (count = 1) => `${CSI}T`.repeat(count)
|
|
62
|
+
};
|
|
63
|
+
var erase = {
|
|
64
|
+
screen: `${CSI}2J`,
|
|
65
|
+
up: (count = 1) => `${CSI}1J`.repeat(count),
|
|
66
|
+
down: (count = 1) => `${CSI}J`.repeat(count),
|
|
67
|
+
line: `${CSI}2K`,
|
|
68
|
+
lineEnd: `${CSI}K`,
|
|
69
|
+
lineStart: `${CSI}1K`,
|
|
70
|
+
lines(count) {
|
|
71
|
+
let clear = "";
|
|
72
|
+
for (let i = 0; i < count; i++)
|
|
73
|
+
clear += this.line + (i < count - 1 ? cursor.up() : "");
|
|
74
|
+
if (count)
|
|
75
|
+
clear += cursor.left;
|
|
76
|
+
return clear;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
module.exports = { cursor, scroll, erase, beep };
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// node_modules/picocolors/picocolors.js
|
|
84
|
+
var require_picocolors = __commonJS({
|
|
85
|
+
"node_modules/picocolors/picocolors.js"(exports, module) {
|
|
86
|
+
"use strict";
|
|
87
|
+
var p2 = process || {};
|
|
88
|
+
var argv = p2.argv || [];
|
|
89
|
+
var env = p2.env || {};
|
|
90
|
+
var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p2.platform === "win32" || (p2.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
|
|
91
|
+
var formatter = (open, close, replace = open) => (input) => {
|
|
92
|
+
let string = "" + input, index = string.indexOf(close, open.length);
|
|
93
|
+
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
|
|
94
|
+
};
|
|
95
|
+
var replaceClose = (string, close, replace, index) => {
|
|
96
|
+
let result = "", cursor = 0;
|
|
97
|
+
do {
|
|
98
|
+
result += string.substring(cursor, index) + replace;
|
|
99
|
+
cursor = index + close.length;
|
|
100
|
+
index = string.indexOf(close, cursor);
|
|
101
|
+
} while (~index);
|
|
102
|
+
return result + string.substring(cursor);
|
|
103
|
+
};
|
|
104
|
+
var createColors = (enabled = isColorSupported) => {
|
|
105
|
+
let f = enabled ? formatter : () => String;
|
|
106
|
+
return {
|
|
107
|
+
isColorSupported: enabled,
|
|
108
|
+
reset: f("\x1B[0m", "\x1B[0m"),
|
|
109
|
+
bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
|
|
110
|
+
dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
|
|
111
|
+
italic: f("\x1B[3m", "\x1B[23m"),
|
|
112
|
+
underline: f("\x1B[4m", "\x1B[24m"),
|
|
113
|
+
inverse: f("\x1B[7m", "\x1B[27m"),
|
|
114
|
+
hidden: f("\x1B[8m", "\x1B[28m"),
|
|
115
|
+
strikethrough: f("\x1B[9m", "\x1B[29m"),
|
|
116
|
+
black: f("\x1B[30m", "\x1B[39m"),
|
|
117
|
+
red: f("\x1B[31m", "\x1B[39m"),
|
|
118
|
+
green: f("\x1B[32m", "\x1B[39m"),
|
|
119
|
+
yellow: f("\x1B[33m", "\x1B[39m"),
|
|
120
|
+
blue: f("\x1B[34m", "\x1B[39m"),
|
|
121
|
+
magenta: f("\x1B[35m", "\x1B[39m"),
|
|
122
|
+
cyan: f("\x1B[36m", "\x1B[39m"),
|
|
123
|
+
white: f("\x1B[37m", "\x1B[39m"),
|
|
124
|
+
gray: f("\x1B[90m", "\x1B[39m"),
|
|
125
|
+
bgBlack: f("\x1B[40m", "\x1B[49m"),
|
|
126
|
+
bgRed: f("\x1B[41m", "\x1B[49m"),
|
|
127
|
+
bgGreen: f("\x1B[42m", "\x1B[49m"),
|
|
128
|
+
bgYellow: f("\x1B[43m", "\x1B[49m"),
|
|
129
|
+
bgBlue: f("\x1B[44m", "\x1B[49m"),
|
|
130
|
+
bgMagenta: f("\x1B[45m", "\x1B[49m"),
|
|
131
|
+
bgCyan: f("\x1B[46m", "\x1B[49m"),
|
|
132
|
+
bgWhite: f("\x1B[47m", "\x1B[49m"),
|
|
133
|
+
blackBright: f("\x1B[90m", "\x1B[39m"),
|
|
134
|
+
redBright: f("\x1B[91m", "\x1B[39m"),
|
|
135
|
+
greenBright: f("\x1B[92m", "\x1B[39m"),
|
|
136
|
+
yellowBright: f("\x1B[93m", "\x1B[39m"),
|
|
137
|
+
blueBright: f("\x1B[94m", "\x1B[39m"),
|
|
138
|
+
magentaBright: f("\x1B[95m", "\x1B[39m"),
|
|
139
|
+
cyanBright: f("\x1B[96m", "\x1B[39m"),
|
|
140
|
+
whiteBright: f("\x1B[97m", "\x1B[39m"),
|
|
141
|
+
bgBlackBright: f("\x1B[100m", "\x1B[49m"),
|
|
142
|
+
bgRedBright: f("\x1B[101m", "\x1B[49m"),
|
|
143
|
+
bgGreenBright: f("\x1B[102m", "\x1B[49m"),
|
|
144
|
+
bgYellowBright: f("\x1B[103m", "\x1B[49m"),
|
|
145
|
+
bgBlueBright: f("\x1B[104m", "\x1B[49m"),
|
|
146
|
+
bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
|
|
147
|
+
bgCyanBright: f("\x1B[106m", "\x1B[49m"),
|
|
148
|
+
bgWhiteBright: f("\x1B[107m", "\x1B[49m")
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
module.exports = createColors();
|
|
152
|
+
module.exports.createColors = createColors;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// src/args.ts
|
|
157
|
+
import { parseArgs } from "util";
|
|
158
|
+
|
|
159
|
+
// src/errors.ts
|
|
160
|
+
var CliError = class extends Error {
|
|
161
|
+
exitCode;
|
|
162
|
+
hint;
|
|
163
|
+
constructor(message, options = {}) {
|
|
164
|
+
super(message, options.cause !== void 0 ? { cause: options.cause } : void 0);
|
|
165
|
+
this.name = "CliError";
|
|
166
|
+
this.exitCode = options.exitCode ?? 1;
|
|
167
|
+
this.hint = options.hint;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
var CancelledError = class extends Error {
|
|
171
|
+
constructor() {
|
|
172
|
+
super("Cancelled.");
|
|
173
|
+
this.name = "CancelledError";
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
var EXIT_OK = 0;
|
|
177
|
+
var EXIT_ERROR = 1;
|
|
178
|
+
var EXIT_USAGE = 2;
|
|
179
|
+
var EXIT_CANCELLED = 130;
|
|
180
|
+
|
|
181
|
+
// src/args.ts
|
|
182
|
+
var OPTIONS = {
|
|
183
|
+
help: { type: "boolean", short: "h" },
|
|
184
|
+
version: { type: "boolean", short: "v" },
|
|
185
|
+
template: { type: "string", short: "t" },
|
|
186
|
+
"list-templates": { type: "boolean" },
|
|
187
|
+
name: { type: "string" },
|
|
188
|
+
url: { type: "string" },
|
|
189
|
+
mode: { type: "string", short: "m" },
|
|
190
|
+
yes: { type: "boolean", short: "y" },
|
|
191
|
+
from: { type: "string" },
|
|
192
|
+
"dry-run": { type: "boolean" },
|
|
193
|
+
"no-git": { type: "boolean" },
|
|
194
|
+
"no-install": { type: "boolean" },
|
|
195
|
+
pm: { type: "string" },
|
|
196
|
+
debug: { type: "boolean" }
|
|
197
|
+
};
|
|
198
|
+
function parseCliArgs(argv) {
|
|
199
|
+
let parsed;
|
|
200
|
+
try {
|
|
201
|
+
parsed = parseArgs({
|
|
202
|
+
args: [...argv],
|
|
203
|
+
options: OPTIONS,
|
|
204
|
+
allowPositionals: true,
|
|
205
|
+
strict: true
|
|
206
|
+
});
|
|
207
|
+
} catch (error) {
|
|
208
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
209
|
+
throw new CliError(message, {
|
|
210
|
+
exitCode: EXIT_USAGE,
|
|
211
|
+
hint: "Run `create-clientkit --help` to see the supported flags.",
|
|
212
|
+
cause: error
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const values = parsed.values;
|
|
216
|
+
const asBool = (key) => values[key] === true;
|
|
217
|
+
const asStr = (key) => typeof values[key] === "string" ? values[key] : void 0;
|
|
218
|
+
if (parsed.positionals.length > 1) {
|
|
219
|
+
throw new CliError(
|
|
220
|
+
`Expected at most one target directory, but received ${parsed.positionals.length}.`,
|
|
221
|
+
{
|
|
222
|
+
exitCode: EXIT_USAGE,
|
|
223
|
+
hint: 'Quote the path if it contains spaces: create-clientkit "my site".'
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
positionals: parsed.positionals,
|
|
229
|
+
help: asBool("help"),
|
|
230
|
+
version: asBool("version"),
|
|
231
|
+
listTemplates: asBool("list-templates"),
|
|
232
|
+
yes: asBool("yes"),
|
|
233
|
+
dryRun: asBool("dry-run"),
|
|
234
|
+
debug: asBool("debug"),
|
|
235
|
+
noGit: asBool("no-git"),
|
|
236
|
+
noInstall: asBool("no-install"),
|
|
237
|
+
template: asStr("template"),
|
|
238
|
+
name: asStr("name"),
|
|
239
|
+
url: asStr("url"),
|
|
240
|
+
mode: asStr("mode"),
|
|
241
|
+
from: asStr("from"),
|
|
242
|
+
pm: asStr("pm")
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function assertFlagCombinations(flags) {
|
|
246
|
+
if (flags.listTemplates && (flags.positionals.length > 0 || flags.from !== void 0)) {
|
|
247
|
+
throw new CliError("--list-templates cannot be combined with a target directory or --from.", {
|
|
248
|
+
exitCode: EXIT_USAGE,
|
|
249
|
+
hint: "Run `create-clientkit --list-templates` on its own."
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// src/commands/create.ts
|
|
255
|
+
import { readdirSync as readdirSync4 } from "fs";
|
|
256
|
+
import path7 from "path";
|
|
257
|
+
|
|
258
|
+
// node_modules/@clack/prompts/dist/index.mjs
|
|
259
|
+
import { stripVTControlCharacters as S2 } from "util";
|
|
260
|
+
|
|
261
|
+
// node_modules/@clack/core/dist/index.mjs
|
|
262
|
+
var import_sisteransi = __toESM(require_src(), 1);
|
|
263
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
264
|
+
import { stdin as j, stdout as M } from "process";
|
|
265
|
+
import * as g from "readline";
|
|
266
|
+
import O from "readline";
|
|
267
|
+
import { Writable as X } from "stream";
|
|
268
|
+
function DD({ onlyFirst: e2 = false } = {}) {
|
|
269
|
+
const t = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
|
|
270
|
+
return new RegExp(t, e2 ? void 0 : "g");
|
|
271
|
+
}
|
|
272
|
+
var uD = DD();
|
|
273
|
+
function P(e2) {
|
|
274
|
+
if (typeof e2 != "string") throw new TypeError(`Expected a \`string\`, got \`${typeof e2}\``);
|
|
275
|
+
return e2.replace(uD, "");
|
|
276
|
+
}
|
|
277
|
+
function L(e2) {
|
|
278
|
+
return e2 && e2.__esModule && Object.prototype.hasOwnProperty.call(e2, "default") ? e2.default : e2;
|
|
279
|
+
}
|
|
280
|
+
var W = { exports: {} };
|
|
281
|
+
(function(e2) {
|
|
282
|
+
var u2 = {};
|
|
283
|
+
e2.exports = u2, u2.eastAsianWidth = function(F2) {
|
|
284
|
+
var s = F2.charCodeAt(0), i = F2.length == 2 ? F2.charCodeAt(1) : 0, D2 = s;
|
|
285
|
+
return 55296 <= s && s <= 56319 && 56320 <= i && i <= 57343 && (s &= 1023, i &= 1023, D2 = s << 10 | i, D2 += 65536), D2 == 12288 || 65281 <= D2 && D2 <= 65376 || 65504 <= D2 && D2 <= 65510 ? "F" : D2 == 8361 || 65377 <= D2 && D2 <= 65470 || 65474 <= D2 && D2 <= 65479 || 65482 <= D2 && D2 <= 65487 || 65490 <= D2 && D2 <= 65495 || 65498 <= D2 && D2 <= 65500 || 65512 <= D2 && D2 <= 65518 ? "H" : 4352 <= D2 && D2 <= 4447 || 4515 <= D2 && D2 <= 4519 || 4602 <= D2 && D2 <= 4607 || 9001 <= D2 && D2 <= 9002 || 11904 <= D2 && D2 <= 11929 || 11931 <= D2 && D2 <= 12019 || 12032 <= D2 && D2 <= 12245 || 12272 <= D2 && D2 <= 12283 || 12289 <= D2 && D2 <= 12350 || 12353 <= D2 && D2 <= 12438 || 12441 <= D2 && D2 <= 12543 || 12549 <= D2 && D2 <= 12589 || 12593 <= D2 && D2 <= 12686 || 12688 <= D2 && D2 <= 12730 || 12736 <= D2 && D2 <= 12771 || 12784 <= D2 && D2 <= 12830 || 12832 <= D2 && D2 <= 12871 || 12880 <= D2 && D2 <= 13054 || 13056 <= D2 && D2 <= 19903 || 19968 <= D2 && D2 <= 42124 || 42128 <= D2 && D2 <= 42182 || 43360 <= D2 && D2 <= 43388 || 44032 <= D2 && D2 <= 55203 || 55216 <= D2 && D2 <= 55238 || 55243 <= D2 && D2 <= 55291 || 63744 <= D2 && D2 <= 64255 || 65040 <= D2 && D2 <= 65049 || 65072 <= D2 && D2 <= 65106 || 65108 <= D2 && D2 <= 65126 || 65128 <= D2 && D2 <= 65131 || 110592 <= D2 && D2 <= 110593 || 127488 <= D2 && D2 <= 127490 || 127504 <= D2 && D2 <= 127546 || 127552 <= D2 && D2 <= 127560 || 127568 <= D2 && D2 <= 127569 || 131072 <= D2 && D2 <= 194367 || 177984 <= D2 && D2 <= 196605 || 196608 <= D2 && D2 <= 262141 ? "W" : 32 <= D2 && D2 <= 126 || 162 <= D2 && D2 <= 163 || 165 <= D2 && D2 <= 166 || D2 == 172 || D2 == 175 || 10214 <= D2 && D2 <= 10221 || 10629 <= D2 && D2 <= 10630 ? "Na" : D2 == 161 || D2 == 164 || 167 <= D2 && D2 <= 168 || D2 == 170 || 173 <= D2 && D2 <= 174 || 176 <= D2 && D2 <= 180 || 182 <= D2 && D2 <= 186 || 188 <= D2 && D2 <= 191 || D2 == 198 || D2 == 208 || 215 <= D2 && D2 <= 216 || 222 <= D2 && D2 <= 225 || D2 == 230 || 232 <= D2 && D2 <= 234 || 236 <= D2 && D2 <= 237 || D2 == 240 || 242 <= D2 && D2 <= 243 || 247 <= D2 && D2 <= 250 || D2 == 252 || D2 == 254 || D2 == 257 || D2 == 273 || D2 == 275 || D2 == 283 || 294 <= D2 && D2 <= 295 || D2 == 299 || 305 <= D2 && D2 <= 307 || D2 == 312 || 319 <= D2 && D2 <= 322 || D2 == 324 || 328 <= D2 && D2 <= 331 || D2 == 333 || 338 <= D2 && D2 <= 339 || 358 <= D2 && D2 <= 359 || D2 == 363 || D2 == 462 || D2 == 464 || D2 == 466 || D2 == 468 || D2 == 470 || D2 == 472 || D2 == 474 || D2 == 476 || D2 == 593 || D2 == 609 || D2 == 708 || D2 == 711 || 713 <= D2 && D2 <= 715 || D2 == 717 || D2 == 720 || 728 <= D2 && D2 <= 731 || D2 == 733 || D2 == 735 || 768 <= D2 && D2 <= 879 || 913 <= D2 && D2 <= 929 || 931 <= D2 && D2 <= 937 || 945 <= D2 && D2 <= 961 || 963 <= D2 && D2 <= 969 || D2 == 1025 || 1040 <= D2 && D2 <= 1103 || D2 == 1105 || D2 == 8208 || 8211 <= D2 && D2 <= 8214 || 8216 <= D2 && D2 <= 8217 || 8220 <= D2 && D2 <= 8221 || 8224 <= D2 && D2 <= 8226 || 8228 <= D2 && D2 <= 8231 || D2 == 8240 || 8242 <= D2 && D2 <= 8243 || D2 == 8245 || D2 == 8251 || D2 == 8254 || D2 == 8308 || D2 == 8319 || 8321 <= D2 && D2 <= 8324 || D2 == 8364 || D2 == 8451 || D2 == 8453 || D2 == 8457 || D2 == 8467 || D2 == 8470 || 8481 <= D2 && D2 <= 8482 || D2 == 8486 || D2 == 8491 || 8531 <= D2 && D2 <= 8532 || 8539 <= D2 && D2 <= 8542 || 8544 <= D2 && D2 <= 8555 || 8560 <= D2 && D2 <= 8569 || D2 == 8585 || 8592 <= D2 && D2 <= 8601 || 8632 <= D2 && D2 <= 8633 || D2 == 8658 || D2 == 8660 || D2 == 8679 || D2 == 8704 || 8706 <= D2 && D2 <= 8707 || 8711 <= D2 && D2 <= 8712 || D2 == 8715 || D2 == 8719 || D2 == 8721 || D2 == 8725 || D2 == 8730 || 8733 <= D2 && D2 <= 8736 || D2 == 8739 || D2 == 8741 || 8743 <= D2 && D2 <= 8748 || D2 == 8750 || 8756 <= D2 && D2 <= 8759 || 8764 <= D2 && D2 <= 8765 || D2 == 8776 || D2 == 8780 || D2 == 8786 || 8800 <= D2 && D2 <= 8801 || 8804 <= D2 && D2 <= 8807 || 8810 <= D2 && D2 <= 8811 || 8814 <= D2 && D2 <= 8815 || 8834 <= D2 && D2 <= 8835 || 8838 <= D2 && D2 <= 8839 || D2 == 8853 || D2 == 8857 || D2 == 8869 || D2 == 8895 || D2 == 8978 || 9312 <= D2 && D2 <= 9449 || 9451 <= D2 && D2 <= 9547 || 9552 <= D2 && D2 <= 9587 || 9600 <= D2 && D2 <= 9615 || 9618 <= D2 && D2 <= 9621 || 9632 <= D2 && D2 <= 9633 || 9635 <= D2 && D2 <= 9641 || 9650 <= D2 && D2 <= 9651 || 9654 <= D2 && D2 <= 9655 || 9660 <= D2 && D2 <= 9661 || 9664 <= D2 && D2 <= 9665 || 9670 <= D2 && D2 <= 9672 || D2 == 9675 || 9678 <= D2 && D2 <= 9681 || 9698 <= D2 && D2 <= 9701 || D2 == 9711 || 9733 <= D2 && D2 <= 9734 || D2 == 9737 || 9742 <= D2 && D2 <= 9743 || 9748 <= D2 && D2 <= 9749 || D2 == 9756 || D2 == 9758 || D2 == 9792 || D2 == 9794 || 9824 <= D2 && D2 <= 9825 || 9827 <= D2 && D2 <= 9829 || 9831 <= D2 && D2 <= 9834 || 9836 <= D2 && D2 <= 9837 || D2 == 9839 || 9886 <= D2 && D2 <= 9887 || 9918 <= D2 && D2 <= 9919 || 9924 <= D2 && D2 <= 9933 || 9935 <= D2 && D2 <= 9953 || D2 == 9955 || 9960 <= D2 && D2 <= 9983 || D2 == 10045 || D2 == 10071 || 10102 <= D2 && D2 <= 10111 || 11093 <= D2 && D2 <= 11097 || 12872 <= D2 && D2 <= 12879 || 57344 <= D2 && D2 <= 63743 || 65024 <= D2 && D2 <= 65039 || D2 == 65533 || 127232 <= D2 && D2 <= 127242 || 127248 <= D2 && D2 <= 127277 || 127280 <= D2 && D2 <= 127337 || 127344 <= D2 && D2 <= 127386 || 917760 <= D2 && D2 <= 917999 || 983040 <= D2 && D2 <= 1048573 || 1048576 <= D2 && D2 <= 1114109 ? "A" : "N";
|
|
286
|
+
}, u2.characterLength = function(F2) {
|
|
287
|
+
var s = this.eastAsianWidth(F2);
|
|
288
|
+
return s == "F" || s == "W" || s == "A" ? 2 : 1;
|
|
289
|
+
};
|
|
290
|
+
function t(F2) {
|
|
291
|
+
return F2.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
|
|
292
|
+
}
|
|
293
|
+
u2.length = function(F2) {
|
|
294
|
+
for (var s = t(F2), i = 0, D2 = 0; D2 < s.length; D2++) i = i + this.characterLength(s[D2]);
|
|
295
|
+
return i;
|
|
296
|
+
}, u2.slice = function(F2, s, i) {
|
|
297
|
+
textLen = u2.length(F2), s = s || 0, i = i || 1, s < 0 && (s = textLen + s), i < 0 && (i = textLen + i);
|
|
298
|
+
for (var D2 = "", C2 = 0, n = t(F2), E = 0; E < n.length; E++) {
|
|
299
|
+
var a = n[E], o2 = u2.length(a);
|
|
300
|
+
if (C2 >= s - (o2 == 2 ? 1 : 0)) if (C2 + o2 <= i) D2 += a;
|
|
301
|
+
else break;
|
|
302
|
+
C2 += o2;
|
|
303
|
+
}
|
|
304
|
+
return D2;
|
|
305
|
+
};
|
|
306
|
+
})(W);
|
|
307
|
+
var tD = W.exports;
|
|
308
|
+
var eD = L(tD);
|
|
309
|
+
var FD = function() {
|
|
310
|
+
return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
|
|
311
|
+
};
|
|
312
|
+
var sD = L(FD);
|
|
313
|
+
function p(e2, u2 = {}) {
|
|
314
|
+
if (typeof e2 != "string" || e2.length === 0 || (u2 = { ambiguousIsNarrow: true, ...u2 }, e2 = P(e2), e2.length === 0)) return 0;
|
|
315
|
+
e2 = e2.replace(sD(), " ");
|
|
316
|
+
const t = u2.ambiguousIsNarrow ? 1 : 2;
|
|
317
|
+
let F2 = 0;
|
|
318
|
+
for (const s of e2) {
|
|
319
|
+
const i = s.codePointAt(0);
|
|
320
|
+
if (i <= 31 || i >= 127 && i <= 159 || i >= 768 && i <= 879) continue;
|
|
321
|
+
switch (eD.eastAsianWidth(s)) {
|
|
322
|
+
case "F":
|
|
323
|
+
case "W":
|
|
324
|
+
F2 += 2;
|
|
325
|
+
break;
|
|
326
|
+
case "A":
|
|
327
|
+
F2 += t;
|
|
328
|
+
break;
|
|
329
|
+
default:
|
|
330
|
+
F2 += 1;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return F2;
|
|
334
|
+
}
|
|
335
|
+
var w = 10;
|
|
336
|
+
var N = (e2 = 0) => (u2) => `\x1B[${u2 + e2}m`;
|
|
337
|
+
var I = (e2 = 0) => (u2) => `\x1B[${38 + e2};5;${u2}m`;
|
|
338
|
+
var R = (e2 = 0) => (u2, t, F2) => `\x1B[${38 + e2};2;${u2};${t};${F2}m`;
|
|
339
|
+
var r = { modifier: { reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], blackBright: [90, 39], gray: [90, 39], grey: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], bgBlackBright: [100, 49], bgGray: [100, 49], bgGrey: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } };
|
|
340
|
+
Object.keys(r.modifier);
|
|
341
|
+
var iD = Object.keys(r.color);
|
|
342
|
+
var CD = Object.keys(r.bgColor);
|
|
343
|
+
[...iD, ...CD];
|
|
344
|
+
function rD() {
|
|
345
|
+
const e2 = /* @__PURE__ */ new Map();
|
|
346
|
+
for (const [u2, t] of Object.entries(r)) {
|
|
347
|
+
for (const [F2, s] of Object.entries(t)) r[F2] = { open: `\x1B[${s[0]}m`, close: `\x1B[${s[1]}m` }, t[F2] = r[F2], e2.set(s[0], s[1]);
|
|
348
|
+
Object.defineProperty(r, u2, { value: t, enumerable: false });
|
|
349
|
+
}
|
|
350
|
+
return Object.defineProperty(r, "codes", { value: e2, enumerable: false }), r.color.close = "\x1B[39m", r.bgColor.close = "\x1B[49m", r.color.ansi = N(), r.color.ansi256 = I(), r.color.ansi16m = R(), r.bgColor.ansi = N(w), r.bgColor.ansi256 = I(w), r.bgColor.ansi16m = R(w), Object.defineProperties(r, { rgbToAnsi256: { value: (u2, t, F2) => u2 === t && t === F2 ? u2 < 8 ? 16 : u2 > 248 ? 231 : Math.round((u2 - 8) / 247 * 24) + 232 : 16 + 36 * Math.round(u2 / 255 * 5) + 6 * Math.round(t / 255 * 5) + Math.round(F2 / 255 * 5), enumerable: false }, hexToRgb: { value: (u2) => {
|
|
351
|
+
const t = /[a-f\d]{6}|[a-f\d]{3}/i.exec(u2.toString(16));
|
|
352
|
+
if (!t) return [0, 0, 0];
|
|
353
|
+
let [F2] = t;
|
|
354
|
+
F2.length === 3 && (F2 = [...F2].map((i) => i + i).join(""));
|
|
355
|
+
const s = Number.parseInt(F2, 16);
|
|
356
|
+
return [s >> 16 & 255, s >> 8 & 255, s & 255];
|
|
357
|
+
}, enumerable: false }, hexToAnsi256: { value: (u2) => r.rgbToAnsi256(...r.hexToRgb(u2)), enumerable: false }, ansi256ToAnsi: { value: (u2) => {
|
|
358
|
+
if (u2 < 8) return 30 + u2;
|
|
359
|
+
if (u2 < 16) return 90 + (u2 - 8);
|
|
360
|
+
let t, F2, s;
|
|
361
|
+
if (u2 >= 232) t = ((u2 - 232) * 10 + 8) / 255, F2 = t, s = t;
|
|
362
|
+
else {
|
|
363
|
+
u2 -= 16;
|
|
364
|
+
const C2 = u2 % 36;
|
|
365
|
+
t = Math.floor(u2 / 36) / 5, F2 = Math.floor(C2 / 6) / 5, s = C2 % 6 / 5;
|
|
366
|
+
}
|
|
367
|
+
const i = Math.max(t, F2, s) * 2;
|
|
368
|
+
if (i === 0) return 30;
|
|
369
|
+
let D2 = 30 + (Math.round(s) << 2 | Math.round(F2) << 1 | Math.round(t));
|
|
370
|
+
return i === 2 && (D2 += 60), D2;
|
|
371
|
+
}, enumerable: false }, rgbToAnsi: { value: (u2, t, F2) => r.ansi256ToAnsi(r.rgbToAnsi256(u2, t, F2)), enumerable: false }, hexToAnsi: { value: (u2) => r.ansi256ToAnsi(r.hexToAnsi256(u2)), enumerable: false } }), r;
|
|
372
|
+
}
|
|
373
|
+
var ED = rD();
|
|
374
|
+
var d = /* @__PURE__ */ new Set(["\x1B", "\x9B"]);
|
|
375
|
+
var oD = 39;
|
|
376
|
+
var y = "\x07";
|
|
377
|
+
var V = "[";
|
|
378
|
+
var nD = "]";
|
|
379
|
+
var G = "m";
|
|
380
|
+
var _ = `${nD}8;;`;
|
|
381
|
+
var z = (e2) => `${d.values().next().value}${V}${e2}${G}`;
|
|
382
|
+
var K = (e2) => `${d.values().next().value}${_}${e2}${y}`;
|
|
383
|
+
var aD = (e2) => e2.split(" ").map((u2) => p(u2));
|
|
384
|
+
var k = (e2, u2, t) => {
|
|
385
|
+
const F2 = [...u2];
|
|
386
|
+
let s = false, i = false, D2 = p(P(e2[e2.length - 1]));
|
|
387
|
+
for (const [C2, n] of F2.entries()) {
|
|
388
|
+
const E = p(n);
|
|
389
|
+
if (D2 + E <= t ? e2[e2.length - 1] += n : (e2.push(n), D2 = 0), d.has(n) && (s = true, i = F2.slice(C2 + 1).join("").startsWith(_)), s) {
|
|
390
|
+
i ? n === y && (s = false, i = false) : n === G && (s = false);
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
D2 += E, D2 === t && C2 < F2.length - 1 && (e2.push(""), D2 = 0);
|
|
394
|
+
}
|
|
395
|
+
!D2 && e2[e2.length - 1].length > 0 && e2.length > 1 && (e2[e2.length - 2] += e2.pop());
|
|
396
|
+
};
|
|
397
|
+
var hD = (e2) => {
|
|
398
|
+
const u2 = e2.split(" ");
|
|
399
|
+
let t = u2.length;
|
|
400
|
+
for (; t > 0 && !(p(u2[t - 1]) > 0); ) t--;
|
|
401
|
+
return t === u2.length ? e2 : u2.slice(0, t).join(" ") + u2.slice(t).join("");
|
|
402
|
+
};
|
|
403
|
+
var lD = (e2, u2, t = {}) => {
|
|
404
|
+
if (t.trim !== false && e2.trim() === "") return "";
|
|
405
|
+
let F2 = "", s, i;
|
|
406
|
+
const D2 = aD(e2);
|
|
407
|
+
let C2 = [""];
|
|
408
|
+
for (const [E, a] of e2.split(" ").entries()) {
|
|
409
|
+
t.trim !== false && (C2[C2.length - 1] = C2[C2.length - 1].trimStart());
|
|
410
|
+
let o2 = p(C2[C2.length - 1]);
|
|
411
|
+
if (E !== 0 && (o2 >= u2 && (t.wordWrap === false || t.trim === false) && (C2.push(""), o2 = 0), (o2 > 0 || t.trim === false) && (C2[C2.length - 1] += " ", o2++)), t.hard && D2[E] > u2) {
|
|
412
|
+
const c = u2 - o2, f = 1 + Math.floor((D2[E] - c - 1) / u2);
|
|
413
|
+
Math.floor((D2[E] - 1) / u2) < f && C2.push(""), k(C2, a, u2);
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (o2 + D2[E] > u2 && o2 > 0 && D2[E] > 0) {
|
|
417
|
+
if (t.wordWrap === false && o2 < u2) {
|
|
418
|
+
k(C2, a, u2);
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
C2.push("");
|
|
422
|
+
}
|
|
423
|
+
if (o2 + D2[E] > u2 && t.wordWrap === false) {
|
|
424
|
+
k(C2, a, u2);
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
C2[C2.length - 1] += a;
|
|
428
|
+
}
|
|
429
|
+
t.trim !== false && (C2 = C2.map((E) => hD(E)));
|
|
430
|
+
const n = [...C2.join(`
|
|
431
|
+
`)];
|
|
432
|
+
for (const [E, a] of n.entries()) {
|
|
433
|
+
if (F2 += a, d.has(a)) {
|
|
434
|
+
const { groups: c } = new RegExp(`(?:\\${V}(?<code>\\d+)m|\\${_}(?<uri>.*)${y})`).exec(n.slice(E).join("")) || { groups: {} };
|
|
435
|
+
if (c.code !== void 0) {
|
|
436
|
+
const f = Number.parseFloat(c.code);
|
|
437
|
+
s = f === oD ? void 0 : f;
|
|
438
|
+
} else c.uri !== void 0 && (i = c.uri.length === 0 ? void 0 : c.uri);
|
|
439
|
+
}
|
|
440
|
+
const o2 = ED.codes.get(Number(s));
|
|
441
|
+
n[E + 1] === `
|
|
442
|
+
` ? (i && (F2 += K("")), s && o2 && (F2 += z(o2))) : a === `
|
|
443
|
+
` && (s && o2 && (F2 += z(s)), i && (F2 += K(i)));
|
|
444
|
+
}
|
|
445
|
+
return F2;
|
|
446
|
+
};
|
|
447
|
+
function Y(e2, u2, t) {
|
|
448
|
+
return String(e2).normalize().replace(/\r\n/g, `
|
|
449
|
+
`).split(`
|
|
450
|
+
`).map((F2) => lD(F2, u2, t)).join(`
|
|
451
|
+
`);
|
|
452
|
+
}
|
|
453
|
+
var xD = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
454
|
+
var B = { actions: new Set(xD), aliases: /* @__PURE__ */ new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["", "cancel"], ["escape", "cancel"]]) };
|
|
455
|
+
function $(e2, u2) {
|
|
456
|
+
if (typeof e2 == "string") return B.aliases.get(e2) === u2;
|
|
457
|
+
for (const t of e2) if (t !== void 0 && $(t, u2)) return true;
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
function BD(e2, u2) {
|
|
461
|
+
if (e2 === u2) return;
|
|
462
|
+
const t = e2.split(`
|
|
463
|
+
`), F2 = u2.split(`
|
|
464
|
+
`), s = [];
|
|
465
|
+
for (let i = 0; i < Math.max(t.length, F2.length); i++) t[i] !== F2[i] && s.push(i);
|
|
466
|
+
return s;
|
|
467
|
+
}
|
|
468
|
+
var AD = globalThis.process.platform.startsWith("win");
|
|
469
|
+
var S = /* @__PURE__ */ Symbol("clack:cancel");
|
|
470
|
+
function pD(e2) {
|
|
471
|
+
return e2 === S;
|
|
472
|
+
}
|
|
473
|
+
function m(e2, u2) {
|
|
474
|
+
const t = e2;
|
|
475
|
+
t.isTTY && t.setRawMode(u2);
|
|
476
|
+
}
|
|
477
|
+
var gD = Object.defineProperty;
|
|
478
|
+
var vD = (e2, u2, t) => u2 in e2 ? gD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
|
|
479
|
+
var h = (e2, u2, t) => (vD(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
|
|
480
|
+
var x = class {
|
|
481
|
+
constructor(u2, t = true) {
|
|
482
|
+
h(this, "input"), h(this, "output"), h(this, "_abortSignal"), h(this, "rl"), h(this, "opts"), h(this, "_render"), h(this, "_track", false), h(this, "_prevFrame", ""), h(this, "_subscribers", /* @__PURE__ */ new Map()), h(this, "_cursor", 0), h(this, "state", "initial"), h(this, "error", ""), h(this, "value");
|
|
483
|
+
const { input: F2 = j, output: s = M, render: i, signal: D2, ...C2 } = u2;
|
|
484
|
+
this.opts = C2, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = i.bind(this), this._track = t, this._abortSignal = D2, this.input = F2, this.output = s;
|
|
485
|
+
}
|
|
486
|
+
unsubscribe() {
|
|
487
|
+
this._subscribers.clear();
|
|
488
|
+
}
|
|
489
|
+
setSubscriber(u2, t) {
|
|
490
|
+
const F2 = this._subscribers.get(u2) ?? [];
|
|
491
|
+
F2.push(t), this._subscribers.set(u2, F2);
|
|
492
|
+
}
|
|
493
|
+
on(u2, t) {
|
|
494
|
+
this.setSubscriber(u2, { cb: t });
|
|
495
|
+
}
|
|
496
|
+
once(u2, t) {
|
|
497
|
+
this.setSubscriber(u2, { cb: t, once: true });
|
|
498
|
+
}
|
|
499
|
+
emit(u2, ...t) {
|
|
500
|
+
const F2 = this._subscribers.get(u2) ?? [], s = [];
|
|
501
|
+
for (const i of F2) i.cb(...t), i.once && s.push(() => F2.splice(F2.indexOf(i), 1));
|
|
502
|
+
for (const i of s) i();
|
|
503
|
+
}
|
|
504
|
+
prompt() {
|
|
505
|
+
return new Promise((u2, t) => {
|
|
506
|
+
if (this._abortSignal) {
|
|
507
|
+
if (this._abortSignal.aborted) return this.state = "cancel", this.close(), u2(S);
|
|
508
|
+
this._abortSignal.addEventListener("abort", () => {
|
|
509
|
+
this.state = "cancel", this.close();
|
|
510
|
+
}, { once: true });
|
|
511
|
+
}
|
|
512
|
+
const F2 = new X();
|
|
513
|
+
F2._write = (s, i, D2) => {
|
|
514
|
+
this._track && (this.value = this.rl?.line.replace(/\t/g, ""), this._cursor = this.rl?.cursor ?? 0, this.emit("value", this.value)), D2();
|
|
515
|
+
}, this.input.pipe(F2), this.rl = O.createInterface({ input: this.input, output: F2, tabSize: 2, prompt: "", escapeCodeTimeout: 50, terminal: true }), O.emitKeypressEvents(this.input, this.rl), this.rl.prompt(), this.opts.initialValue !== void 0 && this._track && this.rl.write(this.opts.initialValue), this.input.on("keypress", this.onKeypress), m(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
|
|
516
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u2(this.value);
|
|
517
|
+
}), this.once("cancel", () => {
|
|
518
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u2(S);
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
onKeypress(u2, t) {
|
|
523
|
+
if (this.state === "error" && (this.state = "active"), t?.name && (!this._track && B.aliases.has(t.name) && this.emit("cursor", B.aliases.get(t.name)), B.actions.has(t.name) && this.emit("cursor", t.name)), u2 && (u2.toLowerCase() === "y" || u2.toLowerCase() === "n") && this.emit("confirm", u2.toLowerCase() === "y"), u2 === " " && this.opts.placeholder && (this.value || (this.rl?.write(this.opts.placeholder), this.emit("value", this.opts.placeholder))), u2 && this.emit("key", u2.toLowerCase()), t?.name === "return") {
|
|
524
|
+
if (this.opts.validate) {
|
|
525
|
+
const F2 = this.opts.validate(this.value);
|
|
526
|
+
F2 && (this.error = F2 instanceof Error ? F2.message : F2, this.state = "error", this.rl?.write(this.value));
|
|
527
|
+
}
|
|
528
|
+
this.state !== "error" && (this.state = "submit");
|
|
529
|
+
}
|
|
530
|
+
$([u2, t?.name, t?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
|
|
531
|
+
}
|
|
532
|
+
close() {
|
|
533
|
+
this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
|
|
534
|
+
`), m(this.input, false), this.rl?.close(), this.rl = void 0, this.emit(`${this.state}`, this.value), this.unsubscribe();
|
|
535
|
+
}
|
|
536
|
+
restoreCursor() {
|
|
537
|
+
const u2 = Y(this._prevFrame, process.stdout.columns, { hard: true }).split(`
|
|
538
|
+
`).length - 1;
|
|
539
|
+
this.output.write(import_sisteransi.cursor.move(-999, u2 * -1));
|
|
540
|
+
}
|
|
541
|
+
render() {
|
|
542
|
+
const u2 = Y(this._render(this) ?? "", process.stdout.columns, { hard: true });
|
|
543
|
+
if (u2 !== this._prevFrame) {
|
|
544
|
+
if (this.state === "initial") this.output.write(import_sisteransi.cursor.hide);
|
|
545
|
+
else {
|
|
546
|
+
const t = BD(this._prevFrame, u2);
|
|
547
|
+
if (this.restoreCursor(), t && t?.length === 1) {
|
|
548
|
+
const F2 = t[0];
|
|
549
|
+
this.output.write(import_sisteransi.cursor.move(0, F2)), this.output.write(import_sisteransi.erase.lines(1));
|
|
550
|
+
const s = u2.split(`
|
|
551
|
+
`);
|
|
552
|
+
this.output.write(s[F2]), this._prevFrame = u2, this.output.write(import_sisteransi.cursor.move(0, s.length - F2 - 1));
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
if (t && t?.length > 1) {
|
|
556
|
+
const F2 = t[0];
|
|
557
|
+
this.output.write(import_sisteransi.cursor.move(0, F2)), this.output.write(import_sisteransi.erase.down());
|
|
558
|
+
const s = u2.split(`
|
|
559
|
+
`).slice(F2);
|
|
560
|
+
this.output.write(s.join(`
|
|
561
|
+
`)), this._prevFrame = u2;
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
this.output.write(import_sisteransi.erase.down());
|
|
565
|
+
}
|
|
566
|
+
this.output.write(u2), this.state === "initial" && (this.state = "active"), this._prevFrame = u2;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
var dD = class extends x {
|
|
571
|
+
get cursor() {
|
|
572
|
+
return this.value ? 0 : 1;
|
|
573
|
+
}
|
|
574
|
+
get _value() {
|
|
575
|
+
return this.cursor === 0;
|
|
576
|
+
}
|
|
577
|
+
constructor(u2) {
|
|
578
|
+
super(u2, false), this.value = !!u2.initialValue, this.on("value", () => {
|
|
579
|
+
this.value = this._value;
|
|
580
|
+
}), this.on("confirm", (t) => {
|
|
581
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = t, this.state = "submit", this.close();
|
|
582
|
+
}), this.on("cursor", () => {
|
|
583
|
+
this.value = !this.value;
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
var A;
|
|
588
|
+
A = /* @__PURE__ */ new WeakMap();
|
|
589
|
+
var kD = Object.defineProperty;
|
|
590
|
+
var $D = (e2, u2, t) => u2 in e2 ? kD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
|
|
591
|
+
var H = (e2, u2, t) => ($D(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
|
|
592
|
+
var SD = class extends x {
|
|
593
|
+
constructor(u2) {
|
|
594
|
+
super(u2, false), H(this, "options"), H(this, "cursor", 0), this.options = u2.options, this.value = [...u2.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u2.cursorAt), 0), this.on("key", (t) => {
|
|
595
|
+
t === "a" && this.toggleAll();
|
|
596
|
+
}), this.on("cursor", (t) => {
|
|
597
|
+
switch (t) {
|
|
598
|
+
case "left":
|
|
599
|
+
case "up":
|
|
600
|
+
this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
|
|
601
|
+
break;
|
|
602
|
+
case "down":
|
|
603
|
+
case "right":
|
|
604
|
+
this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
|
|
605
|
+
break;
|
|
606
|
+
case "space":
|
|
607
|
+
this.toggleValue();
|
|
608
|
+
break;
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
get _value() {
|
|
613
|
+
return this.options[this.cursor].value;
|
|
614
|
+
}
|
|
615
|
+
toggleAll() {
|
|
616
|
+
const u2 = this.value.length === this.options.length;
|
|
617
|
+
this.value = u2 ? [] : this.options.map((t) => t.value);
|
|
618
|
+
}
|
|
619
|
+
toggleValue() {
|
|
620
|
+
const u2 = this.value.includes(this._value);
|
|
621
|
+
this.value = u2 ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
var OD = Object.defineProperty;
|
|
625
|
+
var PD = (e2, u2, t) => u2 in e2 ? OD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
|
|
626
|
+
var J = (e2, u2, t) => (PD(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
|
|
627
|
+
var LD = class extends x {
|
|
628
|
+
constructor(u2) {
|
|
629
|
+
super(u2, false), J(this, "options"), J(this, "cursor", 0), this.options = u2.options, this.cursor = this.options.findIndex(({ value: t }) => t === u2.initialValue), this.cursor === -1 && (this.cursor = 0), this.changeValue(), this.on("cursor", (t) => {
|
|
630
|
+
switch (t) {
|
|
631
|
+
case "left":
|
|
632
|
+
case "up":
|
|
633
|
+
this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
|
|
634
|
+
break;
|
|
635
|
+
case "down":
|
|
636
|
+
case "right":
|
|
637
|
+
this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
this.changeValue();
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
get _value() {
|
|
644
|
+
return this.options[this.cursor];
|
|
645
|
+
}
|
|
646
|
+
changeValue() {
|
|
647
|
+
this.value = this._value.value;
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
var RD = class extends x {
|
|
651
|
+
get valueWithCursor() {
|
|
652
|
+
if (this.state === "submit") return this.value;
|
|
653
|
+
if (this.cursor >= this.value.length) return `${this.value}\u2588`;
|
|
654
|
+
const u2 = this.value.slice(0, this.cursor), [t, ...F2] = this.value.slice(this.cursor);
|
|
655
|
+
return `${u2}${import_picocolors.default.inverse(t)}${F2.join("")}`;
|
|
656
|
+
}
|
|
657
|
+
get cursor() {
|
|
658
|
+
return this._cursor;
|
|
659
|
+
}
|
|
660
|
+
constructor(u2) {
|
|
661
|
+
super(u2), this.on("finalize", () => {
|
|
662
|
+
this.value || (this.value = u2.defaultValue);
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
// node_modules/@clack/prompts/dist/index.mjs
|
|
668
|
+
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
669
|
+
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
670
|
+
import y2 from "process";
|
|
671
|
+
function ce() {
|
|
672
|
+
return y2.platform !== "win32" ? y2.env.TERM !== "linux" : !!y2.env.CI || !!y2.env.WT_SESSION || !!y2.env.TERMINUS_SUBLIME || y2.env.ConEmuTask === "{cmd::Cmder}" || y2.env.TERM_PROGRAM === "Terminus-Sublime" || y2.env.TERM_PROGRAM === "vscode" || y2.env.TERM === "xterm-256color" || y2.env.TERM === "alacritty" || y2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
673
|
+
}
|
|
674
|
+
var V2 = ce();
|
|
675
|
+
var u = (t, n) => V2 ? t : n;
|
|
676
|
+
var le = u("\u25C6", "*");
|
|
677
|
+
var L2 = u("\u25A0", "x");
|
|
678
|
+
var W2 = u("\u25B2", "x");
|
|
679
|
+
var C = u("\u25C7", "o");
|
|
680
|
+
var ue = u("\u250C", "T");
|
|
681
|
+
var o = u("\u2502", "|");
|
|
682
|
+
var d2 = u("\u2514", "\u2014");
|
|
683
|
+
var k2 = u("\u25CF", ">");
|
|
684
|
+
var P2 = u("\u25CB", " ");
|
|
685
|
+
var A2 = u("\u25FB", "[\u2022]");
|
|
686
|
+
var T = u("\u25FC", "[+]");
|
|
687
|
+
var F = u("\u25FB", "[ ]");
|
|
688
|
+
var $e = u("\u25AA", "\u2022");
|
|
689
|
+
var _2 = u("\u2500", "-");
|
|
690
|
+
var me = u("\u256E", "+");
|
|
691
|
+
var de = u("\u251C", "+");
|
|
692
|
+
var pe = u("\u256F", "+");
|
|
693
|
+
var q = u("\u25CF", "\u2022");
|
|
694
|
+
var D = u("\u25C6", "*");
|
|
695
|
+
var U = u("\u25B2", "!");
|
|
696
|
+
var K2 = u("\u25A0", "x");
|
|
697
|
+
var b2 = (t) => {
|
|
698
|
+
switch (t) {
|
|
699
|
+
case "initial":
|
|
700
|
+
case "active":
|
|
701
|
+
return import_picocolors2.default.cyan(le);
|
|
702
|
+
case "cancel":
|
|
703
|
+
return import_picocolors2.default.red(L2);
|
|
704
|
+
case "error":
|
|
705
|
+
return import_picocolors2.default.yellow(W2);
|
|
706
|
+
case "submit":
|
|
707
|
+
return import_picocolors2.default.green(C);
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
var G2 = (t) => {
|
|
711
|
+
const { cursor: n, options: r2, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
|
|
712
|
+
let l2 = 0;
|
|
713
|
+
n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
|
|
714
|
+
const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
|
|
715
|
+
return r2.slice(l2, l2 + a).map((p2, v2, f) => {
|
|
716
|
+
const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
|
|
717
|
+
return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
|
|
718
|
+
});
|
|
719
|
+
};
|
|
720
|
+
var he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
|
|
721
|
+
const n = `${import_picocolors2.default.gray(o)}
|
|
722
|
+
${b2(this.state)} ${t.message}
|
|
723
|
+
`, r2 = t.placeholder ? import_picocolors2.default.inverse(t.placeholder[0]) + import_picocolors2.default.dim(t.placeholder.slice(1)) : import_picocolors2.default.inverse(import_picocolors2.default.hidden("_")), i = this.value ? this.valueWithCursor : r2;
|
|
724
|
+
switch (this.state) {
|
|
725
|
+
case "error":
|
|
726
|
+
return `${n.trim()}
|
|
727
|
+
${import_picocolors2.default.yellow(o)} ${i}
|
|
728
|
+
${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
|
|
729
|
+
`;
|
|
730
|
+
case "submit":
|
|
731
|
+
return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(this.value || t.placeholder)}`;
|
|
732
|
+
case "cancel":
|
|
733
|
+
return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(this.value ?? ""))}${this.value?.trim() ? `
|
|
734
|
+
${import_picocolors2.default.gray(o)}` : ""}`;
|
|
735
|
+
default:
|
|
736
|
+
return `${n}${import_picocolors2.default.cyan(o)} ${i}
|
|
737
|
+
${import_picocolors2.default.cyan(d2)}
|
|
738
|
+
`;
|
|
739
|
+
}
|
|
740
|
+
} }).prompt();
|
|
741
|
+
var ye = (t) => {
|
|
742
|
+
const n = t.active ?? "Yes", r2 = t.inactive ?? "No";
|
|
743
|
+
return new dD({ active: n, inactive: r2, initialValue: t.initialValue ?? true, render() {
|
|
744
|
+
const i = `${import_picocolors2.default.gray(o)}
|
|
745
|
+
${b2(this.state)} ${t.message}
|
|
746
|
+
`, s = this.value ? n : r2;
|
|
747
|
+
switch (this.state) {
|
|
748
|
+
case "submit":
|
|
749
|
+
return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(s)}`;
|
|
750
|
+
case "cancel":
|
|
751
|
+
return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
|
|
752
|
+
${import_picocolors2.default.gray(o)}`;
|
|
753
|
+
default:
|
|
754
|
+
return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(r2)}` : `${import_picocolors2.default.green(k2)} ${r2}`}
|
|
755
|
+
${import_picocolors2.default.cyan(d2)}
|
|
756
|
+
`;
|
|
757
|
+
}
|
|
758
|
+
} }).prompt();
|
|
759
|
+
};
|
|
760
|
+
var ve = (t) => {
|
|
761
|
+
const n = (r2, i) => {
|
|
762
|
+
const s = r2.label ?? String(r2.value);
|
|
763
|
+
switch (i) {
|
|
764
|
+
case "selected":
|
|
765
|
+
return `${import_picocolors2.default.dim(s)}`;
|
|
766
|
+
case "active":
|
|
767
|
+
return `${import_picocolors2.default.green(k2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}`;
|
|
768
|
+
case "cancelled":
|
|
769
|
+
return `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}`;
|
|
770
|
+
default:
|
|
771
|
+
return `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(s)}`;
|
|
772
|
+
}
|
|
773
|
+
};
|
|
774
|
+
return new LD({ options: t.options, initialValue: t.initialValue, render() {
|
|
775
|
+
const r2 = `${import_picocolors2.default.gray(o)}
|
|
776
|
+
${b2(this.state)} ${t.message}
|
|
777
|
+
`;
|
|
778
|
+
switch (this.state) {
|
|
779
|
+
case "submit":
|
|
780
|
+
return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
|
|
781
|
+
case "cancel":
|
|
782
|
+
return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
|
|
783
|
+
${import_picocolors2.default.gray(o)}`;
|
|
784
|
+
default:
|
|
785
|
+
return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
|
|
786
|
+
${import_picocolors2.default.cyan(o)} `)}
|
|
787
|
+
${import_picocolors2.default.cyan(d2)}
|
|
788
|
+
`;
|
|
789
|
+
}
|
|
790
|
+
} }).prompt();
|
|
791
|
+
};
|
|
792
|
+
var fe = (t) => {
|
|
793
|
+
const n = (r2, i) => {
|
|
794
|
+
const s = r2.label ?? String(r2.value);
|
|
795
|
+
return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
|
|
796
|
+
};
|
|
797
|
+
return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
|
|
798
|
+
if (this.required && r2.length === 0) return `Please select at least one option.
|
|
799
|
+
${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
|
|
800
|
+
}, render() {
|
|
801
|
+
const r2 = `${import_picocolors2.default.gray(o)}
|
|
802
|
+
${b2(this.state)} ${t.message}
|
|
803
|
+
`, i = (s, c) => {
|
|
804
|
+
const a = this.value.includes(s.value);
|
|
805
|
+
return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
|
|
806
|
+
};
|
|
807
|
+
switch (this.state) {
|
|
808
|
+
case "submit":
|
|
809
|
+
return `${r2}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
|
|
810
|
+
case "cancel": {
|
|
811
|
+
const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
|
|
812
|
+
return `${r2}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
|
|
813
|
+
${import_picocolors2.default.gray(o)}` : ""}`;
|
|
814
|
+
}
|
|
815
|
+
case "error": {
|
|
816
|
+
const s = this.error.split(`
|
|
817
|
+
`).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
|
|
818
|
+
`);
|
|
819
|
+
return `${r2 + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
|
|
820
|
+
${import_picocolors2.default.yellow(o)} `)}
|
|
821
|
+
${s}
|
|
822
|
+
`;
|
|
823
|
+
}
|
|
824
|
+
default:
|
|
825
|
+
return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
|
|
826
|
+
${import_picocolors2.default.cyan(o)} `)}
|
|
827
|
+
${import_picocolors2.default.cyan(d2)}
|
|
828
|
+
`;
|
|
829
|
+
}
|
|
830
|
+
} }).prompt();
|
|
831
|
+
};
|
|
832
|
+
var Ie = (t = "") => {
|
|
833
|
+
process.stdout.write(`${import_picocolors2.default.gray(ue)} ${t}
|
|
834
|
+
`);
|
|
835
|
+
};
|
|
836
|
+
var Se = (t = "") => {
|
|
837
|
+
process.stdout.write(`${import_picocolors2.default.gray(o)}
|
|
838
|
+
${import_picocolors2.default.gray(d2)} ${t}
|
|
839
|
+
|
|
840
|
+
`);
|
|
841
|
+
};
|
|
842
|
+
var J2 = `${import_picocolors2.default.gray(o)} `;
|
|
843
|
+
|
|
844
|
+
// src/context/prompts.ts
|
|
845
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
846
|
+
function unwrap(value) {
|
|
847
|
+
if (pD(value)) throw new CancelledError();
|
|
848
|
+
return value;
|
|
849
|
+
}
|
|
850
|
+
var ClackPrompter = class {
|
|
851
|
+
interactive = true;
|
|
852
|
+
intro(version) {
|
|
853
|
+
Ie(`${import_picocolors3.default.bgCyan(import_picocolors3.default.black(" create-clientkit "))} ${import_picocolors3.default.dim(`v${version}`)}`);
|
|
854
|
+
}
|
|
855
|
+
outro(message) {
|
|
856
|
+
Se(message);
|
|
857
|
+
}
|
|
858
|
+
async projectDir(defaultValue, validate) {
|
|
859
|
+
return unwrap(
|
|
860
|
+
await he({
|
|
861
|
+
message: "Project directory",
|
|
862
|
+
placeholder: defaultValue,
|
|
863
|
+
defaultValue,
|
|
864
|
+
validate: (value) => validate(value.trim() === "" ? defaultValue : value.trim()) ?? void 0
|
|
865
|
+
})
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
async siteName(defaultValue, validate) {
|
|
869
|
+
return unwrap(
|
|
870
|
+
await he({
|
|
871
|
+
message: "Client / site name",
|
|
872
|
+
placeholder: defaultValue,
|
|
873
|
+
defaultValue,
|
|
874
|
+
validate: (value) => validate(value.trim() === "" ? defaultValue : value.trim()) ?? void 0
|
|
875
|
+
})
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
async productionUrl(validate) {
|
|
879
|
+
const answer = unwrap(
|
|
880
|
+
await he({
|
|
881
|
+
message: "Production URL",
|
|
882
|
+
placeholder: "https://example.com (optional - press Enter to skip)",
|
|
883
|
+
defaultValue: "",
|
|
884
|
+
validate: (value) => value.trim() === "" ? void 0 : validate(value.trim()) ?? void 0
|
|
885
|
+
})
|
|
886
|
+
);
|
|
887
|
+
const trimmed = answer.trim();
|
|
888
|
+
return trimmed === "" ? null : trimmed;
|
|
889
|
+
}
|
|
890
|
+
async mode(defaultValue) {
|
|
891
|
+
return unwrap(
|
|
892
|
+
await ve({
|
|
893
|
+
message: "Starting mode",
|
|
894
|
+
initialValue: defaultValue,
|
|
895
|
+
options: [
|
|
896
|
+
{
|
|
897
|
+
value: "coming-soon",
|
|
898
|
+
label: "Coming Soon",
|
|
899
|
+
hint: "a single launch page you can put live today"
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
value: "full",
|
|
903
|
+
label: "Full Starter",
|
|
904
|
+
hint: "home page and sections, coming-soon route included"
|
|
905
|
+
}
|
|
906
|
+
]
|
|
907
|
+
})
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
async setup(defaults) {
|
|
911
|
+
const initial = [];
|
|
912
|
+
if (defaults.install) initial.push("install");
|
|
913
|
+
if (defaults.git) initial.push("git");
|
|
914
|
+
const selected = unwrap(
|
|
915
|
+
await fe({
|
|
916
|
+
message: "Setup",
|
|
917
|
+
initialValues: initial,
|
|
918
|
+
required: false,
|
|
919
|
+
options: [
|
|
920
|
+
{ value: "install", label: "Install dependencies" },
|
|
921
|
+
{ value: "git", label: "Initialize Git" }
|
|
922
|
+
]
|
|
923
|
+
})
|
|
924
|
+
);
|
|
925
|
+
return { install: selected.includes("install"), git: selected.includes("git") };
|
|
926
|
+
}
|
|
927
|
+
async confirmNonEmpty(collisionCount) {
|
|
928
|
+
return unwrap(
|
|
929
|
+
await ye({
|
|
930
|
+
message: collisionCount > 0 ? `Continue and replace ${collisionCount} existing file(s)?` : "Continue and add files to this directory?",
|
|
931
|
+
// Destructive by default means "no": the user must opt in.
|
|
932
|
+
initialValue: false
|
|
933
|
+
})
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
var NonInteractivePrompter = class {
|
|
938
|
+
interactive = false;
|
|
939
|
+
#reason;
|
|
940
|
+
constructor(reason) {
|
|
941
|
+
this.#reason = reason;
|
|
942
|
+
}
|
|
943
|
+
#fail(field) {
|
|
944
|
+
throw new CliError(`Cannot ask for ${field}: ${this.#reason}`, {
|
|
945
|
+
hint: "Supply the value with a flag or in the --from config file."
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
projectDir() {
|
|
949
|
+
this.#fail("the project directory");
|
|
950
|
+
}
|
|
951
|
+
siteName() {
|
|
952
|
+
this.#fail("the site name");
|
|
953
|
+
}
|
|
954
|
+
productionUrl() {
|
|
955
|
+
this.#fail("the production URL");
|
|
956
|
+
}
|
|
957
|
+
mode() {
|
|
958
|
+
this.#fail("the starting mode");
|
|
959
|
+
}
|
|
960
|
+
setup() {
|
|
961
|
+
this.#fail("the setup options");
|
|
962
|
+
}
|
|
963
|
+
confirmNonEmpty() {
|
|
964
|
+
this.#fail("confirmation to write into a non-empty directory");
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
// src/types.ts
|
|
969
|
+
var TEMPLATE_MODES = ["coming-soon", "full"];
|
|
970
|
+
var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
971
|
+
|
|
972
|
+
// src/util/pm.ts
|
|
973
|
+
function isPackageManager(value) {
|
|
974
|
+
return PACKAGE_MANAGERS.includes(value);
|
|
975
|
+
}
|
|
976
|
+
function detectPackageManager(userAgent) {
|
|
977
|
+
if (!userAgent) return null;
|
|
978
|
+
const first = userAgent.trim().split(/\s+/)[0];
|
|
979
|
+
if (!first) return null;
|
|
980
|
+
const name = first.split("/")[0]?.toLowerCase();
|
|
981
|
+
if (!name) return null;
|
|
982
|
+
return isPackageManager(name) ? name : null;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// src/context/defaults.ts
|
|
986
|
+
var TEMPLATE_ID_PLACEHOLDER = "astro-tailwind";
|
|
987
|
+
var DEFAULTS = {
|
|
988
|
+
locale: "en",
|
|
989
|
+
/** Never invented. The generator will derive this from the developer's git config. */
|
|
990
|
+
author: null,
|
|
991
|
+
templateId: TEMPLATE_ID_PLACEHOLDER,
|
|
992
|
+
templateVersion: null,
|
|
993
|
+
mode: "coming-soon",
|
|
994
|
+
features: [],
|
|
995
|
+
packageManager: "npm",
|
|
996
|
+
install: true,
|
|
997
|
+
git: true
|
|
998
|
+
};
|
|
999
|
+
function defaultSiteDescription(siteName) {
|
|
1000
|
+
return `Official website of ${siteName}.`;
|
|
1001
|
+
}
|
|
1002
|
+
function titleCase(input) {
|
|
1003
|
+
return input.split(/[-_\s.]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// src/context/fromFile.ts
|
|
1007
|
+
import { readFileSync } from "fs";
|
|
1008
|
+
import path2 from "path";
|
|
1009
|
+
|
|
1010
|
+
// src/context/validate.ts
|
|
1011
|
+
import { readdirSync, statSync } from "fs";
|
|
1012
|
+
import { homedir } from "os";
|
|
1013
|
+
import path from "path";
|
|
1014
|
+
var MAX_PROJECT_NAME_LENGTH = 214;
|
|
1015
|
+
var MAX_TARGET_PATH_LENGTH = 200;
|
|
1016
|
+
var WINDOWS_RESERVED = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i;
|
|
1017
|
+
var RESERVED_NAMES = /* @__PURE__ */ new Set(["node_modules", "favicon.ico"]);
|
|
1018
|
+
function hasControlCharacters(value) {
|
|
1019
|
+
for (const char of value) {
|
|
1020
|
+
const code = char.codePointAt(0) ?? 0;
|
|
1021
|
+
if (code < 32 || code === 127) return true;
|
|
1022
|
+
}
|
|
1023
|
+
return false;
|
|
1024
|
+
}
|
|
1025
|
+
function validateProjectName(name) {
|
|
1026
|
+
if (name.length === 0) return "Project name cannot be empty.";
|
|
1027
|
+
if (name.trim() !== name) return "Project name cannot start or end with whitespace.";
|
|
1028
|
+
if (name.length > MAX_PROJECT_NAME_LENGTH) {
|
|
1029
|
+
return `Project name cannot be longer than ${MAX_PROJECT_NAME_LENGTH} characters.`;
|
|
1030
|
+
}
|
|
1031
|
+
if (name === "." || name === "..") return `"${name}" is not a valid project name.`;
|
|
1032
|
+
if (/[/\\]/.test(name)) return "Project name cannot contain path separators.";
|
|
1033
|
+
if (name.includes("..")) return 'Project name cannot contain "..".';
|
|
1034
|
+
if (/[<>:"|?*]/.test(name)) return 'Project name cannot contain <>:"|?* characters.';
|
|
1035
|
+
if (hasControlCharacters(name)) return "Project name cannot contain control characters.";
|
|
1036
|
+
if (/[. ]$/.test(name)) return "Project name cannot end with a dot or a space.";
|
|
1037
|
+
if (WINDOWS_RESERVED.test(name)) return `"${name}" is a reserved name on Windows.`;
|
|
1038
|
+
if (RESERVED_NAMES.has(name.toLowerCase())) return `"${name}" is a reserved name.`;
|
|
1039
|
+
if (name.startsWith(".") || name.startsWith("_")) {
|
|
1040
|
+
return "Project name cannot start with a dot or an underscore.";
|
|
1041
|
+
}
|
|
1042
|
+
if (name !== name.toLowerCase()) {
|
|
1043
|
+
return `Project name must be lowercase. Try "${sanitizeProjectName(name)}".`;
|
|
1044
|
+
}
|
|
1045
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/.test(name)) {
|
|
1046
|
+
return `Project name may only contain lowercase letters, digits, "-", "_" and ".". Try "${sanitizeProjectName(name)}".`;
|
|
1047
|
+
}
|
|
1048
|
+
return null;
|
|
1049
|
+
}
|
|
1050
|
+
function sanitizeProjectName(name) {
|
|
1051
|
+
const cleaned = name.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+/, "").replace(/-+$/, "").slice(0, MAX_PROJECT_NAME_LENGTH);
|
|
1052
|
+
return cleaned.length > 0 ? cleaned : "my-client-site";
|
|
1053
|
+
}
|
|
1054
|
+
function deriveProjectName(dirInput, cwd) {
|
|
1055
|
+
const normalised = dirInput.replace(/[\\/]+$/, "");
|
|
1056
|
+
if (normalised === "" || normalised === ".") return path.basename(cwd);
|
|
1057
|
+
return path.basename(normalised);
|
|
1058
|
+
}
|
|
1059
|
+
var realFs = {
|
|
1060
|
+
readdirSync: (p2) => readdirSync(p2),
|
|
1061
|
+
statSync: (p2) => statSync(p2)
|
|
1062
|
+
};
|
|
1063
|
+
function inspectTargetDir(absolutePath, fs = realFs) {
|
|
1064
|
+
let isDirectory;
|
|
1065
|
+
try {
|
|
1066
|
+
isDirectory = fs.statSync(absolutePath).isDirectory();
|
|
1067
|
+
} catch {
|
|
1068
|
+
return "missing";
|
|
1069
|
+
}
|
|
1070
|
+
if (!isDirectory) return "non-empty";
|
|
1071
|
+
try {
|
|
1072
|
+
const entries = fs.readdirSync(absolutePath).filter((entry) => entry !== ".git");
|
|
1073
|
+
return entries.length === 0 ? "empty" : "non-empty";
|
|
1074
|
+
} catch {
|
|
1075
|
+
return "non-empty";
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
function validateTargetDir(dirInput, options) {
|
|
1079
|
+
const home = options.home ?? homedir();
|
|
1080
|
+
const absolutePath = path.resolve(options.cwd, dirInput);
|
|
1081
|
+
const state = inspectTargetDir(absolutePath, options.fs);
|
|
1082
|
+
const fail3 = (reason, error) => ({
|
|
1083
|
+
absolutePath,
|
|
1084
|
+
state,
|
|
1085
|
+
reason,
|
|
1086
|
+
error
|
|
1087
|
+
});
|
|
1088
|
+
if (absolutePath.length > MAX_TARGET_PATH_LENGTH) {
|
|
1089
|
+
return fail3(
|
|
1090
|
+
"too-long",
|
|
1091
|
+
`Target path is ${absolutePath.length} characters long; keep it under ${MAX_TARGET_PATH_LENGTH} to stay clear of path-length limits.`
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
if (absolutePath === path.parse(absolutePath).root) {
|
|
1095
|
+
return fail3("root", "Refusing to scaffold into a filesystem root.");
|
|
1096
|
+
}
|
|
1097
|
+
if (path.resolve(home) === absolutePath) {
|
|
1098
|
+
return fail3("home", "Refusing to scaffold directly into your home directory.");
|
|
1099
|
+
}
|
|
1100
|
+
if (state === "non-empty") {
|
|
1101
|
+
return fail3("non-empty", `Directory "${absolutePath}" already exists and is not empty.`);
|
|
1102
|
+
}
|
|
1103
|
+
return { absolutePath, state, reason: "ok", error: null };
|
|
1104
|
+
}
|
|
1105
|
+
function validateSiteName(name) {
|
|
1106
|
+
const trimmed = name.trim();
|
|
1107
|
+
if (trimmed.length === 0) return "Site name cannot be empty.";
|
|
1108
|
+
if (trimmed.length > 120) return "Site name cannot be longer than 120 characters.";
|
|
1109
|
+
return null;
|
|
1110
|
+
}
|
|
1111
|
+
function validateUrl(input) {
|
|
1112
|
+
if (input === void 0 || input === null) return { value: null, error: null };
|
|
1113
|
+
const trimmed = input.trim();
|
|
1114
|
+
if (trimmed === "") return { value: null, error: null };
|
|
1115
|
+
let parsed;
|
|
1116
|
+
try {
|
|
1117
|
+
parsed = new URL(trimmed);
|
|
1118
|
+
} catch {
|
|
1119
|
+
return {
|
|
1120
|
+
value: null,
|
|
1121
|
+
error: `"${trimmed}" is not a valid URL. Include the scheme, e.g. https://example.com`
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
1125
|
+
return {
|
|
1126
|
+
value: null,
|
|
1127
|
+
error: `Production URL must use http or https, not "${parsed.protocol}".`
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
if (parsed.hostname === "") {
|
|
1131
|
+
return { value: null, error: "Production URL must include a hostname." };
|
|
1132
|
+
}
|
|
1133
|
+
if (!parsed.hostname.includes(".") && parsed.hostname !== "localhost") {
|
|
1134
|
+
return { value: null, error: `"${parsed.hostname}" does not look like a domain name.` };
|
|
1135
|
+
}
|
|
1136
|
+
const normalised = parsed.pathname === "/" && parsed.href.endsWith("/") ? parsed.href.slice(0, -1) : parsed.href;
|
|
1137
|
+
return { value: normalised, error: null };
|
|
1138
|
+
}
|
|
1139
|
+
function isPackageManagerId(value) {
|
|
1140
|
+
return PACKAGE_MANAGERS.includes(value);
|
|
1141
|
+
}
|
|
1142
|
+
function isTemplateMode(value) {
|
|
1143
|
+
return TEMPLATE_MODES.includes(value);
|
|
1144
|
+
}
|
|
1145
|
+
function validateLocale(value) {
|
|
1146
|
+
return /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/.test(value) ? null : `"${value}" is not a valid BCP-47 locale tag.`;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// src/context/fromFile.ts
|
|
1150
|
+
var TOP_LEVEL_KEYS = ["dir", "site", "template", "packageManager", "git", "install"];
|
|
1151
|
+
var SITE_KEYS = ["name", "url", "description", "locale", "author"];
|
|
1152
|
+
var TEMPLATE_KEYS = ["id", "version", "mode"];
|
|
1153
|
+
var defaultReader = (filePath) => readFileSync(filePath, "utf8");
|
|
1154
|
+
function fail(message, hint) {
|
|
1155
|
+
throw new CliError(message, hint === void 0 ? {} : { hint });
|
|
1156
|
+
}
|
|
1157
|
+
function isPlainObject(value) {
|
|
1158
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1159
|
+
}
|
|
1160
|
+
function rejectUnknownKeys(object, allowed, scope) {
|
|
1161
|
+
for (const key of Object.keys(object)) {
|
|
1162
|
+
if (!allowed.includes(key)) {
|
|
1163
|
+
fail(
|
|
1164
|
+
`Unknown key "${key}" in ${scope} of the config file.`,
|
|
1165
|
+
`Allowed keys: ${allowed.join(", ")}.`
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
function expectString(value, label2) {
|
|
1171
|
+
if (typeof value !== "string") fail(`Config file field "${label2}" must be a string.`);
|
|
1172
|
+
return value;
|
|
1173
|
+
}
|
|
1174
|
+
function expectBoolean(value, label2) {
|
|
1175
|
+
if (typeof value !== "boolean") fail(`Config file field "${label2}" must be true or false.`);
|
|
1176
|
+
return value;
|
|
1177
|
+
}
|
|
1178
|
+
function loadConfigFile(filePath, options = { cwd: process.cwd() }) {
|
|
1179
|
+
const absolute = path2.resolve(options.cwd, filePath);
|
|
1180
|
+
const read = options.readFile ?? defaultReader;
|
|
1181
|
+
let raw;
|
|
1182
|
+
try {
|
|
1183
|
+
raw = read(absolute);
|
|
1184
|
+
} catch (error) {
|
|
1185
|
+
const code = error.code;
|
|
1186
|
+
if (code === "ENOENT") {
|
|
1187
|
+
fail(`Config file not found: ${absolute}`, "Check the path passed to --from.");
|
|
1188
|
+
}
|
|
1189
|
+
if (code === "EISDIR") {
|
|
1190
|
+
fail(`--from expects a JSON file, but ${absolute} is a directory.`);
|
|
1191
|
+
}
|
|
1192
|
+
fail(`Could not read config file ${absolute}: ${error.message}`);
|
|
1193
|
+
}
|
|
1194
|
+
let parsed;
|
|
1195
|
+
try {
|
|
1196
|
+
parsed = JSON.parse(raw);
|
|
1197
|
+
} catch (error) {
|
|
1198
|
+
fail(
|
|
1199
|
+
`Config file ${absolute} is not valid JSON: ${error.message}`,
|
|
1200
|
+
"Only plain JSON is supported (no comments, no trailing commas)."
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
if (!isPlainObject(parsed)) {
|
|
1204
|
+
fail(`Config file ${absolute} must contain a JSON object at the top level.`);
|
|
1205
|
+
}
|
|
1206
|
+
rejectUnknownKeys(parsed, TOP_LEVEL_KEYS, "the top level");
|
|
1207
|
+
const input = {};
|
|
1208
|
+
if (parsed["dir"] !== void 0) {
|
|
1209
|
+
const dir = expectString(parsed["dir"], "dir");
|
|
1210
|
+
const nameError = validateProjectName(deriveProjectName(dir, options.cwd));
|
|
1211
|
+
if (nameError) fail(`Config file field "dir" is invalid: ${nameError}`);
|
|
1212
|
+
input.dir = dir;
|
|
1213
|
+
}
|
|
1214
|
+
if (parsed["site"] !== void 0) {
|
|
1215
|
+
if (!isPlainObject(parsed["site"])) fail('Config file field "site" must be an object.');
|
|
1216
|
+
const site = parsed["site"];
|
|
1217
|
+
rejectUnknownKeys(site, SITE_KEYS, '"site"');
|
|
1218
|
+
if (site["name"] !== void 0) {
|
|
1219
|
+
const name = expectString(site["name"], "site.name");
|
|
1220
|
+
const error = validateSiteName(name);
|
|
1221
|
+
if (error) fail(`Config file field "site.name" is invalid: ${error}`);
|
|
1222
|
+
input.siteName = name.trim();
|
|
1223
|
+
}
|
|
1224
|
+
if (site["url"] !== void 0) {
|
|
1225
|
+
if (site["url"] === null) {
|
|
1226
|
+
input.siteUrl = null;
|
|
1227
|
+
} else {
|
|
1228
|
+
const check = validateUrl(expectString(site["url"], "site.url"));
|
|
1229
|
+
if (check.error) fail(`Config file field "site.url" is invalid: ${check.error}`);
|
|
1230
|
+
input.siteUrl = check.value;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
if (site["description"] !== void 0) {
|
|
1234
|
+
input.siteDescription = expectString(site["description"], "site.description");
|
|
1235
|
+
}
|
|
1236
|
+
if (site["locale"] !== void 0) {
|
|
1237
|
+
const locale = expectString(site["locale"], "site.locale");
|
|
1238
|
+
const error = validateLocale(locale);
|
|
1239
|
+
if (error) fail(`Config file field "site.locale" is invalid: ${error}`);
|
|
1240
|
+
input.locale = locale;
|
|
1241
|
+
}
|
|
1242
|
+
if (site["author"] !== void 0) {
|
|
1243
|
+
input.author = site["author"] === null ? null : expectString(site["author"], "site.author");
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
if (parsed["template"] !== void 0) {
|
|
1247
|
+
if (!isPlainObject(parsed["template"])) fail('Config file field "template" must be an object.');
|
|
1248
|
+
const template = parsed["template"];
|
|
1249
|
+
rejectUnknownKeys(template, TEMPLATE_KEYS, '"template"');
|
|
1250
|
+
if (template["id"] !== void 0) {
|
|
1251
|
+
input.templateId = expectString(template["id"], "template.id");
|
|
1252
|
+
}
|
|
1253
|
+
if (template["version"] !== void 0) {
|
|
1254
|
+
input.templateVersion = template["version"] === null ? null : expectString(template["version"], "template.version");
|
|
1255
|
+
}
|
|
1256
|
+
if (template["mode"] !== void 0) {
|
|
1257
|
+
const mode = expectString(template["mode"], "template.mode");
|
|
1258
|
+
if (!isTemplateMode(mode)) {
|
|
1259
|
+
fail(`Config file field "template.mode" is invalid: unknown mode "${mode}".`);
|
|
1260
|
+
}
|
|
1261
|
+
input.mode = mode;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
if (parsed["packageManager"] !== void 0) {
|
|
1265
|
+
const pm = expectString(parsed["packageManager"], "packageManager");
|
|
1266
|
+
if (!isPackageManagerId(pm)) {
|
|
1267
|
+
fail(`Config file field "packageManager" is invalid: unknown package manager "${pm}".`);
|
|
1268
|
+
}
|
|
1269
|
+
input.packageManager = pm;
|
|
1270
|
+
}
|
|
1271
|
+
if (parsed["git"] !== void 0) input.git = expectBoolean(parsed["git"], "git");
|
|
1272
|
+
if (parsed["install"] !== void 0) input.install = expectBoolean(parsed["install"], "install");
|
|
1273
|
+
return input;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
// src/context/resolve.ts
|
|
1277
|
+
function deepFreeze(value) {
|
|
1278
|
+
if (value === null || typeof value !== "object") return value;
|
|
1279
|
+
for (const key of Object.getOwnPropertyNames(value)) {
|
|
1280
|
+
deepFreeze(value[key]);
|
|
1281
|
+
}
|
|
1282
|
+
return Object.freeze(value);
|
|
1283
|
+
}
|
|
1284
|
+
function flagsLayer(flags, cwd) {
|
|
1285
|
+
const layer = {};
|
|
1286
|
+
const dir = flags.positionals[0];
|
|
1287
|
+
if (dir !== void 0) {
|
|
1288
|
+
if (dir.trim() === "") {
|
|
1289
|
+
throw new CliError("The target directory cannot be an empty string.");
|
|
1290
|
+
}
|
|
1291
|
+
const nameError = validateProjectName(deriveProjectName(dir, cwd));
|
|
1292
|
+
if (nameError) {
|
|
1293
|
+
throw new CliError(`Invalid target directory "${dir}": ${nameError}`);
|
|
1294
|
+
}
|
|
1295
|
+
layer.dir = dir;
|
|
1296
|
+
}
|
|
1297
|
+
if (flags.template !== void 0) layer.templateId = flags.template;
|
|
1298
|
+
if (flags.name !== void 0) {
|
|
1299
|
+
const error = validateSiteName(flags.name);
|
|
1300
|
+
if (error) throw new CliError(`Invalid --name: ${error}`);
|
|
1301
|
+
layer.siteName = flags.name.trim();
|
|
1302
|
+
}
|
|
1303
|
+
if (flags.url !== void 0) {
|
|
1304
|
+
const check = validateUrl(flags.url);
|
|
1305
|
+
if (check.error) throw new CliError(`Invalid --url: ${check.error}`);
|
|
1306
|
+
layer.siteUrl = check.value;
|
|
1307
|
+
}
|
|
1308
|
+
if (flags.mode !== void 0) {
|
|
1309
|
+
if (!isTemplateMode(flags.mode)) {
|
|
1310
|
+
throw new CliError(`Unknown mode "${flags.mode}".`, {
|
|
1311
|
+
hint: `Supported values for --mode: ${TEMPLATE_MODES.join(", ")}.`
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
layer.mode = flags.mode;
|
|
1315
|
+
}
|
|
1316
|
+
if (flags.pm !== void 0) {
|
|
1317
|
+
if (!isPackageManagerId(flags.pm)) {
|
|
1318
|
+
throw new CliError(`Unknown package manager "${flags.pm}".`, {
|
|
1319
|
+
hint: "Supported values for --pm: npm, pnpm, yarn, bun."
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
layer.packageManager = flags.pm;
|
|
1323
|
+
}
|
|
1324
|
+
if (flags.noGit) layer.git = false;
|
|
1325
|
+
if (flags.noInstall) layer.install = false;
|
|
1326
|
+
return layer;
|
|
1327
|
+
}
|
|
1328
|
+
async function resolveContext(options) {
|
|
1329
|
+
const { flags, cwd, env, prompter, registry, cliVersion, now } = options;
|
|
1330
|
+
assertFlagCombinations(flags);
|
|
1331
|
+
const sources = {};
|
|
1332
|
+
const mark = (key, source) => {
|
|
1333
|
+
sources[key] = source;
|
|
1334
|
+
};
|
|
1335
|
+
const dirOptions = {
|
|
1336
|
+
cwd,
|
|
1337
|
+
...options.home === void 0 ? {} : { home: options.home },
|
|
1338
|
+
...options.fs === void 0 ? {} : { fs: options.fs }
|
|
1339
|
+
};
|
|
1340
|
+
const fileLayer = flags.from === void 0 ? {} : loadConfigFile(flags.from, {
|
|
1341
|
+
cwd,
|
|
1342
|
+
...options.readFile === void 0 ? {} : { readFile: options.readFile }
|
|
1343
|
+
});
|
|
1344
|
+
const flagLayer = flagsLayer(flags, cwd);
|
|
1345
|
+
const explicit = { ...fileLayer, ...flagLayer };
|
|
1346
|
+
const sourceOf = (key) => flagLayer[key] !== void 0 ? "flag" : "file";
|
|
1347
|
+
const templateId = explicit.templateId ?? DEFAULTS.templateId;
|
|
1348
|
+
if (!registry.has(templateId) && templateId !== TEMPLATE_ID_PLACEHOLDER) {
|
|
1349
|
+
const available = registry.list();
|
|
1350
|
+
throw new CliError(`Unknown template "${templateId}".`, {
|
|
1351
|
+
hint: available.length === 0 ? "No templates are available yet." : `Available templates: ${available.map((t) => t.id).join(", ")}.`
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
const templateDefaults = registry.defaultsFor(templateId);
|
|
1355
|
+
mark("template.id", explicit.templateId !== void 0 ? sourceOf("templateId") : "default");
|
|
1356
|
+
let dirInput;
|
|
1357
|
+
if (explicit.dir !== void 0) {
|
|
1358
|
+
dirInput = explicit.dir;
|
|
1359
|
+
mark("targetDir", sourceOf("dir"));
|
|
1360
|
+
} else if (prompter.interactive) {
|
|
1361
|
+
dirInput = await prompter.projectDir("my-client-site", (value) => {
|
|
1362
|
+
const nameError = validateProjectName(deriveProjectName(value, cwd));
|
|
1363
|
+
if (nameError) return nameError;
|
|
1364
|
+
return validateTargetDir(value, dirOptions).error;
|
|
1365
|
+
});
|
|
1366
|
+
mark("targetDir", "prompt");
|
|
1367
|
+
} else {
|
|
1368
|
+
throw new CliError("No target directory was given.", {
|
|
1369
|
+
hint: "Pass one as an argument: create-clientkit my-client-site"
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
const targetCheck = validateTargetDir(dirInput, dirOptions);
|
|
1373
|
+
if (targetCheck.error && targetCheck.reason !== "non-empty") {
|
|
1374
|
+
throw new CliError(targetCheck.error);
|
|
1375
|
+
}
|
|
1376
|
+
const projectName = deriveProjectName(dirInput, cwd);
|
|
1377
|
+
const projectNameError = validateProjectName(projectName);
|
|
1378
|
+
if (projectNameError) throw new CliError(projectNameError);
|
|
1379
|
+
mark("projectName", "derived");
|
|
1380
|
+
const siteNameDefault = titleCase(projectName);
|
|
1381
|
+
let siteName;
|
|
1382
|
+
if (explicit.siteName !== void 0) {
|
|
1383
|
+
siteName = explicit.siteName;
|
|
1384
|
+
mark("site.name", sourceOf("siteName"));
|
|
1385
|
+
} else if (prompter.interactive) {
|
|
1386
|
+
siteName = (await prompter.siteName(siteNameDefault, validateSiteName)).trim();
|
|
1387
|
+
if (siteName === "") siteName = siteNameDefault;
|
|
1388
|
+
mark("site.name", "prompt");
|
|
1389
|
+
} else {
|
|
1390
|
+
siteName = siteNameDefault;
|
|
1391
|
+
mark("site.name", "derived");
|
|
1392
|
+
}
|
|
1393
|
+
const siteNameError = validateSiteName(siteName);
|
|
1394
|
+
if (siteNameError) throw new CliError(siteNameError);
|
|
1395
|
+
let siteUrl;
|
|
1396
|
+
if (explicit.siteUrl !== void 0) {
|
|
1397
|
+
const check = validateUrl(explicit.siteUrl);
|
|
1398
|
+
if (check.error) throw new CliError(check.error);
|
|
1399
|
+
siteUrl = check.value;
|
|
1400
|
+
mark("site.url", sourceOf("siteUrl"));
|
|
1401
|
+
} else if (prompter.interactive) {
|
|
1402
|
+
const answer = await prompter.productionUrl((value) => validateUrl(value).error);
|
|
1403
|
+
siteUrl = validateUrl(answer).value;
|
|
1404
|
+
mark("site.url", "prompt");
|
|
1405
|
+
} else {
|
|
1406
|
+
siteUrl = null;
|
|
1407
|
+
mark("site.url", "default");
|
|
1408
|
+
}
|
|
1409
|
+
let mode = explicit.mode;
|
|
1410
|
+
if (mode !== void 0) {
|
|
1411
|
+
mark("template.mode", sourceOf("mode"));
|
|
1412
|
+
} else if (prompter.interactive) {
|
|
1413
|
+
mode = await prompter.mode(templateDefaults.mode ?? DEFAULTS.mode);
|
|
1414
|
+
mark("template.mode", "prompt");
|
|
1415
|
+
} else if (templateDefaults.mode !== void 0) {
|
|
1416
|
+
mode = templateDefaults.mode;
|
|
1417
|
+
mark("template.mode", "template");
|
|
1418
|
+
} else {
|
|
1419
|
+
mode = DEFAULTS.mode;
|
|
1420
|
+
mark("template.mode", "default");
|
|
1421
|
+
}
|
|
1422
|
+
if (registry.has(templateId) && !registry.supportsMode(templateId, mode)) {
|
|
1423
|
+
const supported = registry.get(templateId).supportedModes;
|
|
1424
|
+
throw new CliError(`Template "${templateId}" does not support mode "${mode}".`, {
|
|
1425
|
+
hint: `Supported modes: ${supported.join(", ")}.`
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
let install;
|
|
1429
|
+
let git;
|
|
1430
|
+
const bothExplicit = explicit.install !== void 0 && explicit.git !== void 0;
|
|
1431
|
+
if (!bothExplicit && prompter.interactive) {
|
|
1432
|
+
const answer = await prompter.setup({
|
|
1433
|
+
install: explicit.install ?? DEFAULTS.install,
|
|
1434
|
+
git: explicit.git ?? DEFAULTS.git
|
|
1435
|
+
});
|
|
1436
|
+
install = explicit.install ?? answer.install;
|
|
1437
|
+
git = explicit.git ?? answer.git;
|
|
1438
|
+
mark("install", explicit.install !== void 0 ? sourceOf("install") : "prompt");
|
|
1439
|
+
mark("git", explicit.git !== void 0 ? sourceOf("git") : "prompt");
|
|
1440
|
+
} else {
|
|
1441
|
+
install = explicit.install ?? DEFAULTS.install;
|
|
1442
|
+
git = explicit.git ?? DEFAULTS.git;
|
|
1443
|
+
mark("install", explicit.install !== void 0 ? sourceOf("install") : "default");
|
|
1444
|
+
mark("git", explicit.git !== void 0 ? sourceOf("git") : "default");
|
|
1445
|
+
}
|
|
1446
|
+
const description = explicit.siteDescription ?? templateDefaults.description ?? defaultSiteDescription(siteName);
|
|
1447
|
+
mark(
|
|
1448
|
+
"site.description",
|
|
1449
|
+
explicit.siteDescription !== void 0 ? sourceOf("siteDescription") : templateDefaults.description !== void 0 ? "template" : "default"
|
|
1450
|
+
);
|
|
1451
|
+
const locale = explicit.locale ?? templateDefaults.locale ?? DEFAULTS.locale;
|
|
1452
|
+
mark(
|
|
1453
|
+
"site.locale",
|
|
1454
|
+
explicit.locale !== void 0 ? sourceOf("locale") : templateDefaults.locale !== void 0 ? "template" : "default"
|
|
1455
|
+
);
|
|
1456
|
+
const author = explicit.author ?? DEFAULTS.author;
|
|
1457
|
+
mark("site.author", explicit.author !== void 0 ? sourceOf("author") : "default");
|
|
1458
|
+
const registryVersion = registry.has(templateId) ? registry.get(templateId).version : null;
|
|
1459
|
+
const templateVersion = explicit.templateVersion ?? registryVersion ?? DEFAULTS.templateVersion;
|
|
1460
|
+
mark(
|
|
1461
|
+
"template.version",
|
|
1462
|
+
explicit.templateVersion !== void 0 ? sourceOf("templateVersion") : registryVersion !== null ? "template" : "default"
|
|
1463
|
+
);
|
|
1464
|
+
const detected = detectPackageManager(env["npm_config_user_agent"]);
|
|
1465
|
+
const packageManager = explicit.packageManager ?? detected ?? DEFAULTS.packageManager;
|
|
1466
|
+
mark(
|
|
1467
|
+
"packageManager",
|
|
1468
|
+
explicit.packageManager !== void 0 ? sourceOf("packageManager") : detected !== null ? "derived" : "default"
|
|
1469
|
+
);
|
|
1470
|
+
mark("features", "default");
|
|
1471
|
+
const context = deepFreeze({
|
|
1472
|
+
targetDir: targetCheck.absolutePath,
|
|
1473
|
+
projectName,
|
|
1474
|
+
site: { name: siteName, url: siteUrl, description, locale, author },
|
|
1475
|
+
template: { id: templateId, version: templateVersion, mode },
|
|
1476
|
+
features: [...DEFAULTS.features],
|
|
1477
|
+
packageManager,
|
|
1478
|
+
git,
|
|
1479
|
+
install,
|
|
1480
|
+
cliVersion,
|
|
1481
|
+
generatedAt: now.toISOString()
|
|
1482
|
+
});
|
|
1483
|
+
return { context, sources: Object.freeze({ ...sources }) };
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
// src/generate/apply.ts
|
|
1487
|
+
import {
|
|
1488
|
+
copyFileSync,
|
|
1489
|
+
existsSync,
|
|
1490
|
+
mkdirSync,
|
|
1491
|
+
readdirSync as readdirSync2,
|
|
1492
|
+
renameSync,
|
|
1493
|
+
rmSync,
|
|
1494
|
+
writeFileSync
|
|
1495
|
+
} from "fs";
|
|
1496
|
+
import path3 from "path";
|
|
1497
|
+
function randomSuffix() {
|
|
1498
|
+
return Math.random().toString(36).slice(2, 8);
|
|
1499
|
+
}
|
|
1500
|
+
function apply(plan2, options = {}) {
|
|
1501
|
+
const targetDir = path3.resolve(plan2.targetDir);
|
|
1502
|
+
const parent = path3.dirname(targetDir);
|
|
1503
|
+
const stagingDir = path3.join(parent, `.${path3.basename(targetDir)}.tmp-${randomSuffix()}`);
|
|
1504
|
+
const targetExists = existsSync(targetDir);
|
|
1505
|
+
if (targetExists && !options.allowNonEmpty && !isEffectivelyEmpty(targetDir)) {
|
|
1506
|
+
throw new CliError(`Directory "${targetDir}" already exists and is not empty.`);
|
|
1507
|
+
}
|
|
1508
|
+
const written = [];
|
|
1509
|
+
const overwritten = [];
|
|
1510
|
+
try {
|
|
1511
|
+
mkdirSync(stagingDir, { recursive: true });
|
|
1512
|
+
for (const operation of plan2.operations) {
|
|
1513
|
+
const destination = path3.join(stagingDir, ...operation.path.split("/"));
|
|
1514
|
+
mkdirSync(path3.dirname(destination), { recursive: true });
|
|
1515
|
+
if (operation.type === "write") {
|
|
1516
|
+
writeFileSync(destination, operation.content, "utf8");
|
|
1517
|
+
} else {
|
|
1518
|
+
copyFileSync(operation.source, destination);
|
|
1519
|
+
}
|
|
1520
|
+
written.push(operation.path);
|
|
1521
|
+
options.onProgress?.(operation.path);
|
|
1522
|
+
}
|
|
1523
|
+
if (!targetExists) {
|
|
1524
|
+
mkdirSync(parent, { recursive: true });
|
|
1525
|
+
renameSync(stagingDir, targetDir);
|
|
1526
|
+
} else {
|
|
1527
|
+
for (const operation of plan2.operations) {
|
|
1528
|
+
const from = path3.join(stagingDir, ...operation.path.split("/"));
|
|
1529
|
+
const to = path3.join(targetDir, ...operation.path.split("/"));
|
|
1530
|
+
if (existsSync(to)) {
|
|
1531
|
+
overwritten.push(operation.path);
|
|
1532
|
+
rmSync(to, { force: true });
|
|
1533
|
+
}
|
|
1534
|
+
mkdirSync(path3.dirname(to), { recursive: true });
|
|
1535
|
+
renameSync(from, to);
|
|
1536
|
+
}
|
|
1537
|
+
rmSync(stagingDir, { recursive: true, force: true });
|
|
1538
|
+
}
|
|
1539
|
+
return { targetDir, written, overwritten };
|
|
1540
|
+
} catch (error) {
|
|
1541
|
+
rmSync(stagingDir, { recursive: true, force: true });
|
|
1542
|
+
if (error instanceof CliError) throw error;
|
|
1543
|
+
throw new CliError(`Generation failed: ${error.message}`, {
|
|
1544
|
+
cause: error,
|
|
1545
|
+
hint: "Nothing was written to the target directory."
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
function isEffectivelyEmpty(dir) {
|
|
1550
|
+
try {
|
|
1551
|
+
return readdirSync2(dir).filter((entry) => entry !== ".git").length === 0;
|
|
1552
|
+
} catch {
|
|
1553
|
+
return false;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
function findCollisions(plan2) {
|
|
1557
|
+
const targetDir = path3.resolve(plan2.targetDir);
|
|
1558
|
+
if (!existsSync(targetDir)) return [];
|
|
1559
|
+
return plan2.operations.map((operation) => operation.path).filter((relative) => existsSync(path3.join(targetDir, ...relative.split("/")))).sort();
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// src/generate/plan.ts
|
|
1563
|
+
import { readFileSync as readFileSync2, readdirSync as readdirSync3 } from "fs";
|
|
1564
|
+
import path5 from "path";
|
|
1565
|
+
|
|
1566
|
+
// src/generate/compose.ts
|
|
1567
|
+
function deepMergeJson(base, overlay, atPath = "") {
|
|
1568
|
+
if (Array.isArray(base) && Array.isArray(overlay)) {
|
|
1569
|
+
return dedupeArray([...base, ...overlay]);
|
|
1570
|
+
}
|
|
1571
|
+
if (isPlainObject2(base) && isPlainObject2(overlay)) {
|
|
1572
|
+
const result = { ...base };
|
|
1573
|
+
for (const [key, value] of Object.entries(overlay)) {
|
|
1574
|
+
result[key] = key in base ? deepMergeJson(base[key], value, joinPath(atPath, key)) : value;
|
|
1575
|
+
}
|
|
1576
|
+
return result;
|
|
1577
|
+
}
|
|
1578
|
+
if (isPlainObject2(base) !== isPlainObject2(overlay) && base !== void 0) {
|
|
1579
|
+
if (Array.isArray(base) !== Array.isArray(overlay)) {
|
|
1580
|
+
throw new CliError(
|
|
1581
|
+
`Template layers disagree about the shape of "${atPath || "<root>"}" in a merged JSON file.`,
|
|
1582
|
+
{ hint: "One layer supplies an object or array where another supplies a scalar." }
|
|
1583
|
+
);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
return overlay;
|
|
1587
|
+
}
|
|
1588
|
+
function dedupeArray(items) {
|
|
1589
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1590
|
+
const result = [];
|
|
1591
|
+
for (const item of items) {
|
|
1592
|
+
const key = typeof item === "object" && item !== null ? JSON.stringify(item) : `${typeof item}:${String(item)}`;
|
|
1593
|
+
if (seen.has(key)) continue;
|
|
1594
|
+
seen.add(key);
|
|
1595
|
+
result.push(item);
|
|
1596
|
+
}
|
|
1597
|
+
return result;
|
|
1598
|
+
}
|
|
1599
|
+
function isPlainObject2(value) {
|
|
1600
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1601
|
+
}
|
|
1602
|
+
function joinPath(base, key) {
|
|
1603
|
+
return base === "" ? key : `${base}.${key}`;
|
|
1604
|
+
}
|
|
1605
|
+
function parseJsonLayer(content, sourceLabel) {
|
|
1606
|
+
try {
|
|
1607
|
+
return JSON.parse(content);
|
|
1608
|
+
} catch (error) {
|
|
1609
|
+
throw new CliError(
|
|
1610
|
+
`Template file ${sourceLabel} is not valid JSON: ${error.message}`
|
|
1611
|
+
);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
function stringifyJson(value) {
|
|
1615
|
+
return `${JSON.stringify(value, null, 2)}
|
|
1616
|
+
`;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
// src/generate/files.ts
|
|
1620
|
+
import path4 from "path";
|
|
1621
|
+
var UNDERSCORE_PREFIXED = /* @__PURE__ */ new Set([
|
|
1622
|
+
"_gitignore",
|
|
1623
|
+
"_npmrc",
|
|
1624
|
+
"_gitattributes",
|
|
1625
|
+
"_editorconfig",
|
|
1626
|
+
"_env",
|
|
1627
|
+
"_env.example",
|
|
1628
|
+
"_package.json"
|
|
1629
|
+
]);
|
|
1630
|
+
function renameSpecialFile(basename) {
|
|
1631
|
+
if (!UNDERSCORE_PREFIXED.has(basename)) return basename;
|
|
1632
|
+
if (basename === "_package.json") return "package.json";
|
|
1633
|
+
return `.${basename.slice(1)}`;
|
|
1634
|
+
}
|
|
1635
|
+
function renameSpecialPath(relativePath) {
|
|
1636
|
+
const segments = relativePath.split("/");
|
|
1637
|
+
const last = segments.pop();
|
|
1638
|
+
if (last === void 0) return relativePath;
|
|
1639
|
+
return [...segments, renameSpecialFile(last)].join("/");
|
|
1640
|
+
}
|
|
1641
|
+
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
1642
|
+
".astro",
|
|
1643
|
+
".ts",
|
|
1644
|
+
".tsx",
|
|
1645
|
+
".js",
|
|
1646
|
+
".jsx",
|
|
1647
|
+
".mjs",
|
|
1648
|
+
".cjs",
|
|
1649
|
+
".json",
|
|
1650
|
+
".jsonc",
|
|
1651
|
+
".md",
|
|
1652
|
+
".mdx",
|
|
1653
|
+
".css",
|
|
1654
|
+
".scss",
|
|
1655
|
+
".html",
|
|
1656
|
+
".txt",
|
|
1657
|
+
".svg",
|
|
1658
|
+
".xml",
|
|
1659
|
+
".yml",
|
|
1660
|
+
".yaml",
|
|
1661
|
+
".toml"
|
|
1662
|
+
]);
|
|
1663
|
+
var TEXT_BASENAMES = /* @__PURE__ */ new Set([...UNDERSCORE_PREFIXED, ".gitignore", ".npmrc", ".editorconfig"]);
|
|
1664
|
+
function isTextFile(relativePath) {
|
|
1665
|
+
const basename = path4.basename(relativePath.split("/").join(path4.sep));
|
|
1666
|
+
if (TEXT_BASENAMES.has(basename)) return true;
|
|
1667
|
+
return TEXT_EXTENSIONS.has(path4.extname(basename).toLowerCase());
|
|
1668
|
+
}
|
|
1669
|
+
var MERGEABLE_JSON = /* @__PURE__ */ new Set(["package.json", "tsconfig.json"]);
|
|
1670
|
+
function isMergeableJson(relativePath) {
|
|
1671
|
+
return MERGEABLE_JSON.has(relativePath.split("/").pop() ?? "");
|
|
1672
|
+
}
|
|
1673
|
+
function normaliseEol(content) {
|
|
1674
|
+
return content.replace(/\r\n/g, "\n");
|
|
1675
|
+
}
|
|
1676
|
+
function toPosix(relativePath) {
|
|
1677
|
+
return relativePath.split(path4.sep).join("/");
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
// src/generate/provenance.ts
|
|
1681
|
+
var PROVENANCE_FILE = ".client-site.json";
|
|
1682
|
+
function buildProvenance(context, manifest) {
|
|
1683
|
+
return {
|
|
1684
|
+
$schema: "https://create-clientkit.dev/schema/client-site.json",
|
|
1685
|
+
cliVersion: context.cliVersion,
|
|
1686
|
+
template: {
|
|
1687
|
+
id: manifest.id,
|
|
1688
|
+
version: manifest.version,
|
|
1689
|
+
framework: manifest.framework,
|
|
1690
|
+
frameworkVersion: manifest.frameworkVersion
|
|
1691
|
+
},
|
|
1692
|
+
mode: context.template.mode,
|
|
1693
|
+
generatedAt: context.generatedAt,
|
|
1694
|
+
config: {
|
|
1695
|
+
projectName: context.projectName,
|
|
1696
|
+
siteName: context.site.name,
|
|
1697
|
+
siteUrl: context.site.url,
|
|
1698
|
+
locale: context.site.locale,
|
|
1699
|
+
packageManager: context.packageManager,
|
|
1700
|
+
features: context.features
|
|
1701
|
+
}
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
// src/templates/manifest.ts
|
|
1706
|
+
var POST_STEPS = ["install", "git-init", "format"];
|
|
1707
|
+
var KNOWN_TOKENS = [
|
|
1708
|
+
"siteName",
|
|
1709
|
+
"siteUrl",
|
|
1710
|
+
"description",
|
|
1711
|
+
"year",
|
|
1712
|
+
"projectName",
|
|
1713
|
+
"author",
|
|
1714
|
+
"locale",
|
|
1715
|
+
"mode"
|
|
1716
|
+
];
|
|
1717
|
+
var REQUIRED_KEYS = [
|
|
1718
|
+
"id",
|
|
1719
|
+
"displayName",
|
|
1720
|
+
"description",
|
|
1721
|
+
"version",
|
|
1722
|
+
"framework",
|
|
1723
|
+
"frameworkVersion",
|
|
1724
|
+
"minNode",
|
|
1725
|
+
"supportedModes",
|
|
1726
|
+
"defaults",
|
|
1727
|
+
"availableFeatures",
|
|
1728
|
+
"tokens",
|
|
1729
|
+
"postSteps",
|
|
1730
|
+
"nextSteps"
|
|
1731
|
+
];
|
|
1732
|
+
var DEFAULTS_KEYS = ["mode", "locale", "description"];
|
|
1733
|
+
function fail2(source, message, hint) {
|
|
1734
|
+
throw new CliError(`Invalid template manifest (${source}): ${message}`, {
|
|
1735
|
+
...hint === void 0 ? {} : { hint }
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
function isPlainObject3(value) {
|
|
1739
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1740
|
+
}
|
|
1741
|
+
function expectString2(value, key, source) {
|
|
1742
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
1743
|
+
fail2(source, `"${key}" must be a non-empty string.`);
|
|
1744
|
+
}
|
|
1745
|
+
return value;
|
|
1746
|
+
}
|
|
1747
|
+
function expectStringArray(value, key, source) {
|
|
1748
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
1749
|
+
fail2(source, `"${key}" must be an array of strings.`);
|
|
1750
|
+
}
|
|
1751
|
+
return value;
|
|
1752
|
+
}
|
|
1753
|
+
function parseManifest(raw, source) {
|
|
1754
|
+
if (!isPlainObject3(raw)) fail2(source, "the manifest must be a JSON object.");
|
|
1755
|
+
for (const key of REQUIRED_KEYS) {
|
|
1756
|
+
if (raw[key] === void 0) fail2(source, `missing required key "${key}".`);
|
|
1757
|
+
}
|
|
1758
|
+
for (const key of Object.keys(raw)) {
|
|
1759
|
+
if (!REQUIRED_KEYS.includes(key)) {
|
|
1760
|
+
fail2(source, `unknown key "${key}".`, `Allowed keys: ${REQUIRED_KEYS.join(", ")}.`);
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
const id = expectString2(raw["id"], "id", source);
|
|
1764
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(id)) {
|
|
1765
|
+
fail2(source, `"id" must be lowercase kebab-case, got "${id}".`);
|
|
1766
|
+
}
|
|
1767
|
+
const supportedModes = expectStringArray(raw["supportedModes"], "supportedModes", source);
|
|
1768
|
+
if (supportedModes.length === 0) fail2(source, '"supportedModes" cannot be empty.');
|
|
1769
|
+
for (const mode of supportedModes) {
|
|
1770
|
+
if (!TEMPLATE_MODES.includes(mode)) {
|
|
1771
|
+
fail2(source, `unsupported mode "${mode}" in "supportedModes".`);
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
const tokens = expectStringArray(raw["tokens"], "tokens", source);
|
|
1775
|
+
for (const token of tokens) {
|
|
1776
|
+
if (!KNOWN_TOKENS.includes(token)) {
|
|
1777
|
+
fail2(source, `unknown token "${token}".`, `Known tokens: ${KNOWN_TOKENS.join(", ")}.`);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
const postSteps = expectStringArray(raw["postSteps"], "postSteps", source);
|
|
1781
|
+
for (const step of postSteps) {
|
|
1782
|
+
if (!POST_STEPS.includes(step)) {
|
|
1783
|
+
fail2(
|
|
1784
|
+
source,
|
|
1785
|
+
`unknown post-step "${step}".`,
|
|
1786
|
+
`Templates may only request CLI-owned steps: ${POST_STEPS.join(", ")}. Arbitrary commands are not supported.`
|
|
1787
|
+
);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
const availableFeatures = expectStringArray(
|
|
1791
|
+
raw["availableFeatures"],
|
|
1792
|
+
"availableFeatures",
|
|
1793
|
+
source
|
|
1794
|
+
);
|
|
1795
|
+
if (availableFeatures.length > 0) {
|
|
1796
|
+
fail2(source, 'feature overlays are not supported in V1; "availableFeatures" must be empty.');
|
|
1797
|
+
}
|
|
1798
|
+
const nextSteps = expectStringArray(raw["nextSteps"], "nextSteps", source);
|
|
1799
|
+
const rawDefaults = raw["defaults"];
|
|
1800
|
+
if (!isPlainObject3(rawDefaults)) fail2(source, '"defaults" must be an object.');
|
|
1801
|
+
for (const key of Object.keys(rawDefaults)) {
|
|
1802
|
+
if (!DEFAULTS_KEYS.includes(key)) {
|
|
1803
|
+
fail2(source, `unknown key "${key}" in "defaults".`);
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
const defaults = {};
|
|
1807
|
+
if (rawDefaults["mode"] !== void 0) {
|
|
1808
|
+
const mode = expectString2(rawDefaults["mode"], "defaults.mode", source);
|
|
1809
|
+
if (!TEMPLATE_MODES.includes(mode)) {
|
|
1810
|
+
fail2(source, `unknown mode "${mode}" in "defaults.mode".`);
|
|
1811
|
+
}
|
|
1812
|
+
if (!supportedModes.includes(mode)) {
|
|
1813
|
+
fail2(source, `"defaults.mode" (${mode}) is not listed in "supportedModes".`);
|
|
1814
|
+
}
|
|
1815
|
+
defaults.mode = mode;
|
|
1816
|
+
}
|
|
1817
|
+
if (rawDefaults["locale"] !== void 0) {
|
|
1818
|
+
defaults.locale = expectString2(
|
|
1819
|
+
rawDefaults["locale"],
|
|
1820
|
+
"defaults.locale",
|
|
1821
|
+
source
|
|
1822
|
+
);
|
|
1823
|
+
}
|
|
1824
|
+
if (rawDefaults["description"] !== void 0) {
|
|
1825
|
+
defaults.description = expectString2(
|
|
1826
|
+
rawDefaults["description"],
|
|
1827
|
+
"defaults.description",
|
|
1828
|
+
source
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1831
|
+
return {
|
|
1832
|
+
id,
|
|
1833
|
+
displayName: expectString2(raw["displayName"], "displayName", source),
|
|
1834
|
+
description: expectString2(raw["description"], "description", source),
|
|
1835
|
+
version: expectString2(raw["version"], "version", source),
|
|
1836
|
+
framework: expectString2(raw["framework"], "framework", source),
|
|
1837
|
+
frameworkVersion: expectString2(raw["frameworkVersion"], "frameworkVersion", source),
|
|
1838
|
+
minNode: expectString2(raw["minNode"], "minNode", source),
|
|
1839
|
+
supportedModes,
|
|
1840
|
+
defaults,
|
|
1841
|
+
availableFeatures,
|
|
1842
|
+
tokens,
|
|
1843
|
+
postSteps,
|
|
1844
|
+
nextSteps
|
|
1845
|
+
};
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
// src/generate/tokens.ts
|
|
1849
|
+
var NULLABLE_TOKENS = /* @__PURE__ */ new Set(["siteUrl", "author"]);
|
|
1850
|
+
var TOKEN_PATTERN = /\{\{\s*([A-Za-z0-9_]+)\s*\}\}/g;
|
|
1851
|
+
function buildTokenValues(context, now) {
|
|
1852
|
+
return Object.freeze({
|
|
1853
|
+
siteName: context.site.name,
|
|
1854
|
+
siteUrl: context.site.url ?? "",
|
|
1855
|
+
description: context.site.description,
|
|
1856
|
+
year: String(now.getUTCFullYear()),
|
|
1857
|
+
projectName: context.projectName,
|
|
1858
|
+
author: context.site.author ?? "",
|
|
1859
|
+
locale: context.site.locale,
|
|
1860
|
+
mode: context.template.mode
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
function substituteTokens(content, values, sourceLabel) {
|
|
1864
|
+
const unknown = /* @__PURE__ */ new Set();
|
|
1865
|
+
const empty = /* @__PURE__ */ new Set();
|
|
1866
|
+
const result = content.replace(TOKEN_PATTERN, (match, rawName) => {
|
|
1867
|
+
if (!KNOWN_TOKENS.includes(rawName)) {
|
|
1868
|
+
unknown.add(rawName);
|
|
1869
|
+
return match;
|
|
1870
|
+
}
|
|
1871
|
+
const name = rawName;
|
|
1872
|
+
const value = values[name];
|
|
1873
|
+
if (value === "" && !NULLABLE_TOKENS.has(name)) {
|
|
1874
|
+
empty.add(name);
|
|
1875
|
+
return match;
|
|
1876
|
+
}
|
|
1877
|
+
return value;
|
|
1878
|
+
});
|
|
1879
|
+
if (unknown.size > 0) {
|
|
1880
|
+
throw new CliError(
|
|
1881
|
+
`Unknown token${unknown.size > 1 ? "s" : ""} ${[...unknown].map((t) => `{{${t}}}`).join(", ")} in ${sourceLabel}.`,
|
|
1882
|
+
{ hint: `Known tokens: ${KNOWN_TOKENS.map((t) => `{{${t}}}`).join(", ")}.` }
|
|
1883
|
+
);
|
|
1884
|
+
}
|
|
1885
|
+
if (empty.size > 0) {
|
|
1886
|
+
throw new CliError(
|
|
1887
|
+
`Token${empty.size > 1 ? "s" : ""} ${[...empty].map((t) => `{{${t}}}`).join(", ")} resolved to an empty value in ${sourceLabel}.`,
|
|
1888
|
+
{ hint: "Only {{siteUrl}} and {{author}} may be empty." }
|
|
1889
|
+
);
|
|
1890
|
+
}
|
|
1891
|
+
return result;
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
// src/generate/plan.ts
|
|
1895
|
+
var realPlanFs = {
|
|
1896
|
+
readDir: (dir) => readdirSync3(dir, { withFileTypes: true }).map((entry) => ({
|
|
1897
|
+
name: entry.name,
|
|
1898
|
+
isDirectory: entry.isDirectory()
|
|
1899
|
+
})),
|
|
1900
|
+
readText: (file) => readFileSync2(file, "utf8"),
|
|
1901
|
+
exists: (dir) => {
|
|
1902
|
+
try {
|
|
1903
|
+
readdirSync3(dir);
|
|
1904
|
+
return true;
|
|
1905
|
+
} catch {
|
|
1906
|
+
return false;
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
};
|
|
1910
|
+
function walkLayer(fs, layerRoot, layerName) {
|
|
1911
|
+
const files = [];
|
|
1912
|
+
const walk = (dir, prefix) => {
|
|
1913
|
+
for (const entry of fs.readDir(dir)) {
|
|
1914
|
+
const absolutePath = path5.join(dir, entry.name);
|
|
1915
|
+
const relative = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
|
|
1916
|
+
if (entry.isDirectory) {
|
|
1917
|
+
walk(absolutePath, relative);
|
|
1918
|
+
} else {
|
|
1919
|
+
files.push({ layer: layerName, absolutePath, rawRelativePath: relative });
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
};
|
|
1923
|
+
if (!fs.exists(layerRoot)) return files;
|
|
1924
|
+
walk(layerRoot, "");
|
|
1925
|
+
return files;
|
|
1926
|
+
}
|
|
1927
|
+
function substituteInJson(value, values, label2) {
|
|
1928
|
+
if (typeof value === "string") return substituteTokens(value, values, label2);
|
|
1929
|
+
if (Array.isArray(value)) return value.map((item) => substituteInJson(item, values, label2));
|
|
1930
|
+
if (typeof value === "object" && value !== null) {
|
|
1931
|
+
const result = {};
|
|
1932
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
1933
|
+
result[substituteTokens(key, values, label2)] = substituteInJson(entry, values, label2);
|
|
1934
|
+
}
|
|
1935
|
+
return result;
|
|
1936
|
+
}
|
|
1937
|
+
return value;
|
|
1938
|
+
}
|
|
1939
|
+
function plan(context, options) {
|
|
1940
|
+
const fs = options.fs ?? realPlanFs;
|
|
1941
|
+
const now = options.now ?? new Date(context.generatedAt);
|
|
1942
|
+
const manifest = options.registry.get(context.template.id);
|
|
1943
|
+
if (!manifest.supportedModes.includes(context.template.mode)) {
|
|
1944
|
+
throw new CliError(
|
|
1945
|
+
`Template "${manifest.id}" does not support mode "${context.template.mode}".`,
|
|
1946
|
+
{ hint: `Supported modes: ${manifest.supportedModes.join(", ")}.` }
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1949
|
+
const templateRoot = options.registry.rootFor(manifest.id);
|
|
1950
|
+
const layers = [
|
|
1951
|
+
{ name: "base", root: path5.join(templateRoot, "base") },
|
|
1952
|
+
{
|
|
1953
|
+
name: `modes/${context.template.mode}`,
|
|
1954
|
+
root: path5.join(templateRoot, "modes", context.template.mode)
|
|
1955
|
+
}
|
|
1956
|
+
];
|
|
1957
|
+
const byDestination = /* @__PURE__ */ new Map();
|
|
1958
|
+
for (const layer of layers) {
|
|
1959
|
+
for (const file of walkLayer(fs, layer.root, layer.name)) {
|
|
1960
|
+
const destination = renameSpecialPath(toPosix(file.rawRelativePath));
|
|
1961
|
+
const existing = byDestination.get(destination);
|
|
1962
|
+
if (existing) existing.push(file);
|
|
1963
|
+
else byDestination.set(destination, [file]);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
if (byDestination.size === 0) {
|
|
1967
|
+
throw new CliError(`Template "${manifest.id}" produced no files.`, {
|
|
1968
|
+
hint: "The template directory appears to be empty or missing from the package."
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
const values = buildTokenValues(context, now);
|
|
1972
|
+
const operations = [];
|
|
1973
|
+
for (const [destination, contributions] of byDestination) {
|
|
1974
|
+
const last = contributions[contributions.length - 1];
|
|
1975
|
+
if (last === void 0) continue;
|
|
1976
|
+
if (!isTextFile(destination)) {
|
|
1977
|
+
operations.push({
|
|
1978
|
+
type: "copy",
|
|
1979
|
+
path: destination,
|
|
1980
|
+
source: last.absolutePath,
|
|
1981
|
+
origin: last.layer
|
|
1982
|
+
});
|
|
1983
|
+
continue;
|
|
1984
|
+
}
|
|
1985
|
+
const label2 = `${last.layer}/${last.rawRelativePath}`;
|
|
1986
|
+
let content;
|
|
1987
|
+
if (isMergeableJson(destination) && contributions.length > 1) {
|
|
1988
|
+
let merged;
|
|
1989
|
+
for (const contribution of contributions) {
|
|
1990
|
+
const parsed = parseJsonLayer(
|
|
1991
|
+
fs.readText(contribution.absolutePath),
|
|
1992
|
+
`${contribution.layer}/${contribution.rawRelativePath}`
|
|
1993
|
+
);
|
|
1994
|
+
merged = merged === void 0 ? parsed : deepMergeJson(merged, parsed);
|
|
1995
|
+
}
|
|
1996
|
+
content = stringifyJson(substituteInJson(merged, values, label2));
|
|
1997
|
+
} else if (isMergeableJson(destination)) {
|
|
1998
|
+
const parsed = parseJsonLayer(fs.readText(last.absolutePath), label2);
|
|
1999
|
+
content = stringifyJson(substituteInJson(parsed, values, label2));
|
|
2000
|
+
} else {
|
|
2001
|
+
content = substituteTokens(normaliseEol(fs.readText(last.absolutePath)), values, label2);
|
|
2002
|
+
}
|
|
2003
|
+
operations.push({
|
|
2004
|
+
type: "write",
|
|
2005
|
+
path: destination,
|
|
2006
|
+
content: normaliseEol(content),
|
|
2007
|
+
origin: contributions.map((c) => c.layer).join(" + ")
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
operations.push({
|
|
2011
|
+
type: "write",
|
|
2012
|
+
path: PROVENANCE_FILE,
|
|
2013
|
+
content: stringifyJson(buildProvenance(context, manifest)),
|
|
2014
|
+
origin: "cli"
|
|
2015
|
+
});
|
|
2016
|
+
operations.sort((a, b3) => a.path.localeCompare(b3.path));
|
|
2017
|
+
return {
|
|
2018
|
+
templateId: manifest.id,
|
|
2019
|
+
templateVersion: manifest.version,
|
|
2020
|
+
mode: context.template.mode,
|
|
2021
|
+
targetDir: context.targetDir,
|
|
2022
|
+
operations
|
|
2023
|
+
};
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
// src/generate/postSteps.ts
|
|
2027
|
+
import { spawnSync } from "child_process";
|
|
2028
|
+
var INSTALL_ARGS = {
|
|
2029
|
+
npm: ["install"],
|
|
2030
|
+
pnpm: ["install"],
|
|
2031
|
+
yarn: ["install"],
|
|
2032
|
+
bun: ["install"]
|
|
2033
|
+
};
|
|
2034
|
+
var defaultRunner = (command, args, cwd) => {
|
|
2035
|
+
const result = spawnSync(command, [...args], {
|
|
2036
|
+
cwd,
|
|
2037
|
+
stdio: "pipe",
|
|
2038
|
+
encoding: "utf8",
|
|
2039
|
+
// Windows resolves npm/pnpm/yarn as .cmd shims, which spawn cannot execute
|
|
2040
|
+
// directly. Both the command and every argument here are CLI-owned
|
|
2041
|
+
// constants, never template or user input.
|
|
2042
|
+
shell: process.platform === "win32"
|
|
2043
|
+
});
|
|
2044
|
+
return { status: result.status, stderr: result.stderr ?? String(result.error ?? "") };
|
|
2045
|
+
};
|
|
2046
|
+
function runPostSteps(options) {
|
|
2047
|
+
const { context, logger, steps } = options;
|
|
2048
|
+
const run2 = options.run ?? defaultRunner;
|
|
2049
|
+
const results = [];
|
|
2050
|
+
for (const step of steps) {
|
|
2051
|
+
switch (step) {
|
|
2052
|
+
case "install": {
|
|
2053
|
+
if (!context.install) {
|
|
2054
|
+
results.push({ step, status: "skipped", detail: "disabled by --no-install" });
|
|
2055
|
+
break;
|
|
2056
|
+
}
|
|
2057
|
+
const args = INSTALL_ARGS[context.packageManager];
|
|
2058
|
+
logger.info(`Installing dependencies with ${context.packageManager}...`);
|
|
2059
|
+
const result = run2(context.packageManager, args, context.targetDir);
|
|
2060
|
+
results.push(
|
|
2061
|
+
result.status === 0 ? { step, status: "ok" } : { step, status: "failed", detail: firstLine(result.stderr) }
|
|
2062
|
+
);
|
|
2063
|
+
break;
|
|
2064
|
+
}
|
|
2065
|
+
case "git-init": {
|
|
2066
|
+
if (!context.git) {
|
|
2067
|
+
results.push({ step, status: "skipped", detail: "disabled by --no-git" });
|
|
2068
|
+
break;
|
|
2069
|
+
}
|
|
2070
|
+
const result = run2("git", ["init", "--quiet"], context.targetDir);
|
|
2071
|
+
results.push(
|
|
2072
|
+
result.status === 0 ? { step, status: "ok" } : { step, status: "failed", detail: firstLine(result.stderr) }
|
|
2073
|
+
);
|
|
2074
|
+
break;
|
|
2075
|
+
}
|
|
2076
|
+
case "format": {
|
|
2077
|
+
logger.debug('post-step "format" is a no-op in this release');
|
|
2078
|
+
results.push({ step, status: "skipped", detail: "not implemented yet" });
|
|
2079
|
+
break;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
return results;
|
|
2084
|
+
}
|
|
2085
|
+
function firstLine(text) {
|
|
2086
|
+
const line = text.trim().split("\n")[0] ?? "";
|
|
2087
|
+
return line.length > 200 ? `${line.slice(0, 200)}...` : line;
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
// src/ui/plan.ts
|
|
2091
|
+
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
2092
|
+
import path6 from "path";
|
|
2093
|
+
function label(text) {
|
|
2094
|
+
return import_picocolors4.default.dim(text.padEnd(18));
|
|
2095
|
+
}
|
|
2096
|
+
function show(value) {
|
|
2097
|
+
if (value === null) return import_picocolors4.default.dim("(not set)");
|
|
2098
|
+
if (typeof value === "boolean") return value ? import_picocolors4.default.green("yes") : import_picocolors4.default.dim("no");
|
|
2099
|
+
if (value === "") return import_picocolors4.default.dim("(empty)");
|
|
2100
|
+
return value;
|
|
2101
|
+
}
|
|
2102
|
+
function renderPlan(context, sources, options) {
|
|
2103
|
+
const lines = [];
|
|
2104
|
+
const row = (name, value, sourceKey) => {
|
|
2105
|
+
const origin = options.showSources && sources[sourceKey] ? import_picocolors4.default.dim(` [${sources[sourceKey]}]`) : "";
|
|
2106
|
+
lines.push(` ${label(name)}${show(value)}${origin}`);
|
|
2107
|
+
};
|
|
2108
|
+
lines.push(import_picocolors4.default.bold("Resolved configuration"));
|
|
2109
|
+
row("Target directory", context.targetDir, "targetDir");
|
|
2110
|
+
row("Project name", context.projectName, "projectName");
|
|
2111
|
+
row("Site name", context.site.name, "site.name");
|
|
2112
|
+
row("Production URL", context.site.url, "site.url");
|
|
2113
|
+
row("Description", context.site.description, "site.description");
|
|
2114
|
+
row("Locale", context.site.locale, "site.locale");
|
|
2115
|
+
row("Author", context.site.author, "site.author");
|
|
2116
|
+
row("Template", context.template.id, "template.id");
|
|
2117
|
+
row("Template version", context.template.version, "template.version");
|
|
2118
|
+
row("Mode", context.template.mode, "template.mode");
|
|
2119
|
+
row(
|
|
2120
|
+
"Features",
|
|
2121
|
+
context.features.length === 0 ? import_picocolors4.default.dim("none") : context.features.join(", "),
|
|
2122
|
+
"features"
|
|
2123
|
+
);
|
|
2124
|
+
row("Package manager", context.packageManager, "packageManager");
|
|
2125
|
+
row("Install deps", context.install, "install");
|
|
2126
|
+
row("Initialise git", context.git, "git");
|
|
2127
|
+
lines.push("");
|
|
2128
|
+
lines.push(import_picocolors4.default.dim(` CLI ${context.cliVersion} | resolved ${context.generatedAt}`));
|
|
2129
|
+
return lines.join("\n");
|
|
2130
|
+
}
|
|
2131
|
+
function renderDryRun(generationPlan, context, sources, options) {
|
|
2132
|
+
const lines = [];
|
|
2133
|
+
lines.push("");
|
|
2134
|
+
lines.push(import_picocolors4.default.bold(import_picocolors4.default.yellow("DRY RUN - no files will be written.")));
|
|
2135
|
+
lines.push("");
|
|
2136
|
+
lines.push(` ${label("Target")}${generationPlan.targetDir}`);
|
|
2137
|
+
lines.push(
|
|
2138
|
+
` ${label("Template")}${generationPlan.templateId} ${import_picocolors4.default.dim(`v${generationPlan.templateVersion}`)}`
|
|
2139
|
+
);
|
|
2140
|
+
lines.push(` ${label("Mode")}${generationPlan.mode}`);
|
|
2141
|
+
lines.push("");
|
|
2142
|
+
lines.push(import_picocolors4.default.bold("Files:"));
|
|
2143
|
+
for (const operation of generationPlan.operations) {
|
|
2144
|
+
const kind = operation.type === "copy" ? import_picocolors4.default.dim(" (binary)") : "";
|
|
2145
|
+
const origin = options.verbose ? import_picocolors4.default.dim(` <- ${operation.origin}`) : "";
|
|
2146
|
+
lines.push(` ${operation.path}${kind}${origin}`);
|
|
2147
|
+
}
|
|
2148
|
+
lines.push("");
|
|
2149
|
+
lines.push(`Total: ${generationPlan.operations.length} files`);
|
|
2150
|
+
lines.push("");
|
|
2151
|
+
lines.push(renderPlan(context, sources, { showSources: true }));
|
|
2152
|
+
return lines.join("\n");
|
|
2153
|
+
}
|
|
2154
|
+
var RUN_PREFIX = {
|
|
2155
|
+
npm: "npm run",
|
|
2156
|
+
pnpm: "pnpm",
|
|
2157
|
+
yarn: "yarn",
|
|
2158
|
+
bun: "bun run"
|
|
2159
|
+
};
|
|
2160
|
+
function renderNextSteps(context, manifest, postResults, cwd) {
|
|
2161
|
+
const relative = path6.relative(cwd, context.targetDir) || ".";
|
|
2162
|
+
const installed = postResults.some(
|
|
2163
|
+
(result) => result.step === "install" && result.status === "ok"
|
|
2164
|
+
);
|
|
2165
|
+
const commands = [`cd ${relative}`];
|
|
2166
|
+
if (!installed) commands.push(`${context.packageManager} install`);
|
|
2167
|
+
commands.push(`${RUN_PREFIX[context.packageManager]} dev`);
|
|
2168
|
+
const lines = [import_picocolors4.default.bold("Next steps")];
|
|
2169
|
+
for (const command of commands) lines.push(` ${import_picocolors4.default.cyan(command)}`);
|
|
2170
|
+
if (manifest.nextSteps.length > 0) {
|
|
2171
|
+
lines.push("");
|
|
2172
|
+
for (const step of manifest.nextSteps) lines.push(` ${import_picocolors4.default.dim("-")} ${step}`);
|
|
2173
|
+
}
|
|
2174
|
+
return lines.join("\n");
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
// src/util/node.ts
|
|
2178
|
+
var MIN_NODE_VERSION = "20.19.0";
|
|
2179
|
+
function parseVersion(version) {
|
|
2180
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)/.exec(version.trim());
|
|
2181
|
+
if (!match) return null;
|
|
2182
|
+
return {
|
|
2183
|
+
major: Number(match[1]),
|
|
2184
|
+
minor: Number(match[2]),
|
|
2185
|
+
patch: Number(match[3])
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
function satisfiesMinimum(current, minimum = MIN_NODE_VERSION) {
|
|
2189
|
+
const a = parseVersion(current);
|
|
2190
|
+
const b3 = parseVersion(minimum);
|
|
2191
|
+
if (!a || !b3) return true;
|
|
2192
|
+
if (a.major !== b3.major) return a.major > b3.major;
|
|
2193
|
+
if (a.minor !== b3.minor) return a.minor > b3.minor;
|
|
2194
|
+
return a.patch >= b3.patch;
|
|
2195
|
+
}
|
|
2196
|
+
function nodeVersionMessage(current, minimum = MIN_NODE_VERSION) {
|
|
2197
|
+
return `create-clientkit requires Node.js ${minimum} or newer, but found ${current.replace(/^v/, "")}.`;
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
// src/commands/create.ts
|
|
2201
|
+
function selectPrompter(flags, isTTY) {
|
|
2202
|
+
if (flags.yes) return new NonInteractivePrompter("--yes was passed, so prompts are disabled");
|
|
2203
|
+
if (!isTTY) {
|
|
2204
|
+
throw new CliError("Cannot prompt because stdin is not an interactive terminal.", {
|
|
2205
|
+
exitCode: EXIT_USAGE,
|
|
2206
|
+
hint: "Re-run with --yes, or supply the answers via flags and --from <file.json>."
|
|
2207
|
+
});
|
|
2208
|
+
}
|
|
2209
|
+
return new ClackPrompter();
|
|
2210
|
+
}
|
|
2211
|
+
function hasContent(targetDir) {
|
|
2212
|
+
try {
|
|
2213
|
+
return readdirSync4(targetDir).filter((entry) => entry !== ".git").length > 0;
|
|
2214
|
+
} catch {
|
|
2215
|
+
return false;
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
async function runCreate(options) {
|
|
2219
|
+
const { flags, logger, registry, cliVersion, cwd, env, isTTY, nodeVersion } = options;
|
|
2220
|
+
const prompter = options.prompter ?? selectPrompter(flags, isTTY);
|
|
2221
|
+
logger.debug(`prompter=${prompter.interactive ? "interactive" : "non-interactive"} tty=${isTTY}`);
|
|
2222
|
+
if (prompter instanceof ClackPrompter) prompter.intro(cliVersion);
|
|
2223
|
+
const { context, sources } = await resolveContext({
|
|
2224
|
+
flags,
|
|
2225
|
+
cwd,
|
|
2226
|
+
env,
|
|
2227
|
+
prompter,
|
|
2228
|
+
registry,
|
|
2229
|
+
cliVersion,
|
|
2230
|
+
now: /* @__PURE__ */ new Date()
|
|
2231
|
+
});
|
|
2232
|
+
const manifest = registry.get(context.template.id);
|
|
2233
|
+
const generationPlan = plan(context, { registry });
|
|
2234
|
+
logger.debug(`planned ${generationPlan.operations.length} operations`);
|
|
2235
|
+
if (flags.dryRun) {
|
|
2236
|
+
logger.print(renderDryRun(generationPlan, context, sources, { verbose: flags.debug }));
|
|
2237
|
+
return EXIT_OK;
|
|
2238
|
+
}
|
|
2239
|
+
if (!satisfiesMinimum(nodeVersion, manifest.minNode.replace(/^>=/, ""))) {
|
|
2240
|
+
logger.warn(
|
|
2241
|
+
`Template "${manifest.id}" targets Node ${manifest.minNode}, but you are running ${nodeVersion}.`
|
|
2242
|
+
);
|
|
2243
|
+
logger.hint("The project will still be generated, but installing or building it may fail.");
|
|
2244
|
+
}
|
|
2245
|
+
const collisions = findCollisions(generationPlan);
|
|
2246
|
+
let allowNonEmpty = false;
|
|
2247
|
+
if (hasContent(generationPlan.targetDir)) {
|
|
2248
|
+
if (!prompter.interactive) {
|
|
2249
|
+
throw new CliError(
|
|
2250
|
+
`Directory "${generationPlan.targetDir}" already exists and is not empty.`,
|
|
2251
|
+
{
|
|
2252
|
+
hint: "Choose an empty directory, or re-run interactively to confirm writing into this one."
|
|
2253
|
+
}
|
|
2254
|
+
);
|
|
2255
|
+
}
|
|
2256
|
+
logger.warn(`${path7.basename(generationPlan.targetDir)} already contains files.`);
|
|
2257
|
+
if (collisions.length > 0) {
|
|
2258
|
+
logger.hint(`${collisions.length} existing file(s) would be replaced:`);
|
|
2259
|
+
for (const file of collisions.slice(0, 10)) logger.hint(` ${file}`);
|
|
2260
|
+
if (collisions.length > 10) logger.hint(` ...and ${collisions.length - 10} more`);
|
|
2261
|
+
} else {
|
|
2262
|
+
logger.hint("No existing file would be replaced; new files are added alongside.");
|
|
2263
|
+
}
|
|
2264
|
+
allowNonEmpty = await prompter.confirmNonEmpty(collisions.length);
|
|
2265
|
+
if (!allowNonEmpty) {
|
|
2266
|
+
logger.info("Cancelled. Nothing was written.");
|
|
2267
|
+
return EXIT_OK;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
const result = apply(generationPlan, { allowNonEmpty });
|
|
2271
|
+
logger.success(
|
|
2272
|
+
`Created ${result.written.length} files in ${path7.relative(cwd, result.targetDir) || "."}`
|
|
2273
|
+
);
|
|
2274
|
+
if (result.overwritten.length > 0) {
|
|
2275
|
+
logger.warn(`Replaced ${result.overwritten.length} existing file(s).`);
|
|
2276
|
+
}
|
|
2277
|
+
const postResults = runPostSteps({ context, logger, steps: manifest.postSteps });
|
|
2278
|
+
for (const postResult of postResults) {
|
|
2279
|
+
if (postResult.status === "ok") {
|
|
2280
|
+
logger.success(
|
|
2281
|
+
postResult.step === "install" ? "Dependencies installed." : "Git repository initialised."
|
|
2282
|
+
);
|
|
2283
|
+
} else if (postResult.status === "failed") {
|
|
2284
|
+
logger.warn(`Post-step "${postResult.step}" failed: ${postResult.detail ?? "unknown error"}`);
|
|
2285
|
+
logger.hint("The project was generated; finish this step yourself.");
|
|
2286
|
+
} else {
|
|
2287
|
+
logger.debug(`post-step "${postResult.step}" skipped: ${postResult.detail ?? ""}`);
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
logger.print("");
|
|
2291
|
+
logger.print(renderPlan(context, sources, { showSources: flags.debug }));
|
|
2292
|
+
logger.print("");
|
|
2293
|
+
logger.print(renderNextSteps(context, manifest, postResults, cwd));
|
|
2294
|
+
return EXIT_OK;
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
// src/commands/list.ts
|
|
2298
|
+
function runList(registry, logger) {
|
|
2299
|
+
const templates = registry.list();
|
|
2300
|
+
if (templates.length === 0) {
|
|
2301
|
+
logger.print("No templates are available yet.");
|
|
2302
|
+
return EXIT_OK;
|
|
2303
|
+
}
|
|
2304
|
+
logger.print("Available templates:");
|
|
2305
|
+
for (const template of templates) {
|
|
2306
|
+
logger.print("");
|
|
2307
|
+
logger.print(` ${template.id}`);
|
|
2308
|
+
logger.print(` ${template.displayName}`);
|
|
2309
|
+
logger.print(` ${template.description}`);
|
|
2310
|
+
logger.print(` modes: ${template.modes.join(", ")}`);
|
|
2311
|
+
}
|
|
2312
|
+
return EXIT_OK;
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
// src/templates/registry.ts
|
|
2316
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, readdirSync as readdirSync5 } from "fs";
|
|
2317
|
+
import path8 from "path";
|
|
2318
|
+
import { fileURLToPath } from "url";
|
|
2319
|
+
function findTemplatesRoot(startDir) {
|
|
2320
|
+
const start = startDir ?? path8.dirname(fileURLToPath(import.meta.url));
|
|
2321
|
+
let current = start;
|
|
2322
|
+
for (let depth = 0; depth < 6; depth += 1) {
|
|
2323
|
+
const candidate = path8.join(current, "templates");
|
|
2324
|
+
if (existsSync2(path8.join(candidate, "astro-tailwind", "template.json"))) return candidate;
|
|
2325
|
+
const parent = path8.dirname(current);
|
|
2326
|
+
if (parent === current) break;
|
|
2327
|
+
current = parent;
|
|
2328
|
+
}
|
|
2329
|
+
throw new CliError("Could not locate the bundled templates directory.", {
|
|
2330
|
+
hint: "This usually means the package was installed incompletely. Try reinstalling create-clientkit."
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2333
|
+
function readManifest(templateDir) {
|
|
2334
|
+
const manifestPath = path8.join(templateDir, "template.json");
|
|
2335
|
+
let raw;
|
|
2336
|
+
try {
|
|
2337
|
+
raw = JSON.parse(readFileSync3(manifestPath, "utf8"));
|
|
2338
|
+
} catch (error) {
|
|
2339
|
+
throw new CliError(`Could not read template manifest at ${manifestPath}.`, {
|
|
2340
|
+
cause: error,
|
|
2341
|
+
hint: error.message
|
|
2342
|
+
});
|
|
2343
|
+
}
|
|
2344
|
+
const manifest = parseManifest(raw, `${path8.basename(templateDir)}/template.json`);
|
|
2345
|
+
if (manifest.id !== path8.basename(templateDir)) {
|
|
2346
|
+
throw new CliError(
|
|
2347
|
+
`Template manifest id "${manifest.id}" does not match its directory "${path8.basename(templateDir)}".`
|
|
2348
|
+
);
|
|
2349
|
+
}
|
|
2350
|
+
return manifest;
|
|
2351
|
+
}
|
|
2352
|
+
function createRegistry(templatesRoot) {
|
|
2353
|
+
const root = templatesRoot ?? findTemplatesRoot();
|
|
2354
|
+
const entries = readdirSync5(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
2355
|
+
const manifests = /* @__PURE__ */ new Map();
|
|
2356
|
+
for (const name of entries) {
|
|
2357
|
+
const dir = path8.join(root, name);
|
|
2358
|
+
if (!existsSync2(path8.join(dir, "template.json"))) continue;
|
|
2359
|
+
const manifest = readManifest(dir);
|
|
2360
|
+
manifests.set(manifest.id, manifest);
|
|
2361
|
+
}
|
|
2362
|
+
const requireTemplate = (id) => {
|
|
2363
|
+
const manifest = manifests.get(id);
|
|
2364
|
+
if (!manifest) {
|
|
2365
|
+
const available = [...manifests.keys()];
|
|
2366
|
+
throw new CliError(`Unknown template "${id}".`, {
|
|
2367
|
+
hint: available.length === 0 ? "No templates are available yet." : `Available templates: ${available.join(", ")}.`
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
return manifest;
|
|
2371
|
+
};
|
|
2372
|
+
return {
|
|
2373
|
+
list: () => [...manifests.values()].map((manifest) => ({
|
|
2374
|
+
id: manifest.id,
|
|
2375
|
+
displayName: manifest.displayName,
|
|
2376
|
+
description: manifest.description,
|
|
2377
|
+
version: manifest.version,
|
|
2378
|
+
modes: manifest.supportedModes
|
|
2379
|
+
})),
|
|
2380
|
+
has: (id) => manifests.has(id),
|
|
2381
|
+
get: requireTemplate,
|
|
2382
|
+
defaultsFor: (id) => manifests.get(id)?.defaults ?? {},
|
|
2383
|
+
rootFor: (id) => {
|
|
2384
|
+
requireTemplate(id);
|
|
2385
|
+
return path8.join(root, id);
|
|
2386
|
+
},
|
|
2387
|
+
supportsMode: (id, mode) => manifests.get(id)?.supportedModes.includes(mode) ?? false
|
|
2388
|
+
};
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
// src/ui/help.ts
|
|
2392
|
+
function helpText() {
|
|
2393
|
+
return `
|
|
2394
|
+
create-clientkit - the boring foundation of your next client website.
|
|
2395
|
+
|
|
2396
|
+
Usage
|
|
2397
|
+
npm create clientkit@latest [directory] [options]
|
|
2398
|
+
npx create-clientkit@latest [directory] [options]
|
|
2399
|
+
|
|
2400
|
+
Options
|
|
2401
|
+
-t, --template <id> Template to scaffold from
|
|
2402
|
+
--list-templates List available templates and exit
|
|
2403
|
+
--name <name> Client / site name
|
|
2404
|
+
--url <url> Production URL (omit if not decided yet)
|
|
2405
|
+
-m, --mode <mode> coming-soon | full
|
|
2406
|
+
-y, --yes Accept all defaults; never prompt
|
|
2407
|
+
--from <file> Read answers from a JSON config file
|
|
2408
|
+
--dry-run Resolve and print the plan; write nothing
|
|
2409
|
+
--no-git Skip git initialisation
|
|
2410
|
+
--no-install Skip dependency installation
|
|
2411
|
+
--pm <manager> Force a package manager (${PACKAGE_MANAGERS.join(" | ")})
|
|
2412
|
+
--debug Print diagnostics and full stack traces
|
|
2413
|
+
-h, --help Show this help
|
|
2414
|
+
-v, --version Show the version
|
|
2415
|
+
|
|
2416
|
+
Examples
|
|
2417
|
+
npm create clientkit@latest acme-website
|
|
2418
|
+
npm create clientkit@latest acme-website --yes --no-install
|
|
2419
|
+
npm create clientkit@latest --from ./agency-preset.json --dry-run
|
|
2420
|
+
|
|
2421
|
+
Note
|
|
2422
|
+
Early build: configuration is resolved and validated, but no files are
|
|
2423
|
+
generated yet.
|
|
2424
|
+
`.trimStart();
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
// src/ui/logger.ts
|
|
2428
|
+
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
2429
|
+
var Logger = class {
|
|
2430
|
+
#debugEnabled;
|
|
2431
|
+
#out;
|
|
2432
|
+
#err;
|
|
2433
|
+
constructor(options = {}) {
|
|
2434
|
+
this.#debugEnabled = options.debug ?? false;
|
|
2435
|
+
this.#out = options.streams?.out ?? process.stdout;
|
|
2436
|
+
this.#err = options.streams?.err ?? process.stderr;
|
|
2437
|
+
}
|
|
2438
|
+
get debugEnabled() {
|
|
2439
|
+
return this.#debugEnabled;
|
|
2440
|
+
}
|
|
2441
|
+
setDebug(enabled) {
|
|
2442
|
+
this.#debugEnabled = enabled;
|
|
2443
|
+
}
|
|
2444
|
+
/** Raw line to stdout, no decoration. For --help, --version, plans. */
|
|
2445
|
+
print(message = "") {
|
|
2446
|
+
this.#out.write(`${message}
|
|
2447
|
+
`);
|
|
2448
|
+
}
|
|
2449
|
+
info(message) {
|
|
2450
|
+
this.#err.write(`${import_picocolors5.default.blue("i")} ${message}
|
|
2451
|
+
`);
|
|
2452
|
+
}
|
|
2453
|
+
success(message) {
|
|
2454
|
+
this.#err.write(`${import_picocolors5.default.green("*")} ${message}
|
|
2455
|
+
`);
|
|
2456
|
+
}
|
|
2457
|
+
warn(message) {
|
|
2458
|
+
this.#err.write(`${import_picocolors5.default.yellow("!")} ${import_picocolors5.default.yellow(message)}
|
|
2459
|
+
`);
|
|
2460
|
+
}
|
|
2461
|
+
error(message) {
|
|
2462
|
+
this.#err.write(`${import_picocolors5.default.red("x")} ${import_picocolors5.default.red(message)}
|
|
2463
|
+
`);
|
|
2464
|
+
}
|
|
2465
|
+
hint(message) {
|
|
2466
|
+
this.#err.write(` ${import_picocolors5.default.dim(message)}
|
|
2467
|
+
`);
|
|
2468
|
+
}
|
|
2469
|
+
debug(message) {
|
|
2470
|
+
if (!this.#debugEnabled) return;
|
|
2471
|
+
this.#err.write(`${import_picocolors5.default.magenta("debug")} ${import_picocolors5.default.dim(message)}
|
|
2472
|
+
`);
|
|
2473
|
+
}
|
|
2474
|
+
};
|
|
2475
|
+
|
|
2476
|
+
// src/version.ts
|
|
2477
|
+
var CLI_VERSION = true ? "0.1.0" : "0.0.0-dev";
|
|
2478
|
+
|
|
2479
|
+
// src/cli.ts
|
|
2480
|
+
async function main(argv, options = {}) {
|
|
2481
|
+
const logger = options.logger ?? new Logger();
|
|
2482
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2483
|
+
const env = options.env ?? process.env;
|
|
2484
|
+
const isTTY = options.isTTY ?? Boolean(process.stdin.isTTY);
|
|
2485
|
+
const nodeVersion = options.nodeVersion ?? process.versions.node;
|
|
2486
|
+
try {
|
|
2487
|
+
const flags = parseCliArgs(argv);
|
|
2488
|
+
logger.setDebug(flags.debug);
|
|
2489
|
+
logger.debug(`argv=${JSON.stringify(argv)}`);
|
|
2490
|
+
logger.debug(`node=${nodeVersion} cwd=${cwd}`);
|
|
2491
|
+
if (!satisfiesMinimum(nodeVersion, MIN_NODE_VERSION)) {
|
|
2492
|
+
throw new CliError(nodeVersionMessage(nodeVersion, MIN_NODE_VERSION), {
|
|
2493
|
+
hint: "Upgrade Node.js, or use a version manager such as nvm or fnm."
|
|
2494
|
+
});
|
|
2495
|
+
}
|
|
2496
|
+
if (flags.help) {
|
|
2497
|
+
logger.print(helpText());
|
|
2498
|
+
return EXIT_OK;
|
|
2499
|
+
}
|
|
2500
|
+
if (flags.version) {
|
|
2501
|
+
logger.print(CLI_VERSION);
|
|
2502
|
+
return EXIT_OK;
|
|
2503
|
+
}
|
|
2504
|
+
assertFlagCombinations(flags);
|
|
2505
|
+
if (flags.listTemplates) {
|
|
2506
|
+
return runList(createRegistry(), logger);
|
|
2507
|
+
}
|
|
2508
|
+
return await runCreate({
|
|
2509
|
+
flags,
|
|
2510
|
+
logger,
|
|
2511
|
+
registry: createRegistry(),
|
|
2512
|
+
cliVersion: CLI_VERSION,
|
|
2513
|
+
cwd,
|
|
2514
|
+
env,
|
|
2515
|
+
isTTY,
|
|
2516
|
+
nodeVersion
|
|
2517
|
+
});
|
|
2518
|
+
} catch (error) {
|
|
2519
|
+
return reportError(error, logger);
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
function reportError(error, logger) {
|
|
2523
|
+
if (error instanceof CancelledError) {
|
|
2524
|
+
logger.print("");
|
|
2525
|
+
logger.info("Cancelled.");
|
|
2526
|
+
return EXIT_CANCELLED;
|
|
2527
|
+
}
|
|
2528
|
+
if (error instanceof CliError) {
|
|
2529
|
+
logger.error(error.message);
|
|
2530
|
+
if (error.hint) logger.hint(error.hint);
|
|
2531
|
+
if (logger.debugEnabled && error.stack) logger.debug(error.stack);
|
|
2532
|
+
if (logger.debugEnabled && error.cause) logger.debug(`cause: ${String(error.cause)}`);
|
|
2533
|
+
return error.exitCode;
|
|
2534
|
+
}
|
|
2535
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2536
|
+
logger.error(`Unexpected error: ${message}`);
|
|
2537
|
+
if (logger.debugEnabled) {
|
|
2538
|
+
logger.debug(error instanceof Error && error.stack ? error.stack : String(error));
|
|
2539
|
+
} else {
|
|
2540
|
+
logger.hint("Re-run with --debug for a full stack trace.");
|
|
2541
|
+
}
|
|
2542
|
+
return EXIT_ERROR;
|
|
2543
|
+
}
|
|
2544
|
+
async function run() {
|
|
2545
|
+
process.on("SIGINT", () => {
|
|
2546
|
+
process.exitCode = EXIT_CANCELLED;
|
|
2547
|
+
process.stderr.write("\n");
|
|
2548
|
+
process.exit(EXIT_CANCELLED);
|
|
2549
|
+
});
|
|
2550
|
+
process.exitCode = await main(process.argv.slice(2));
|
|
2551
|
+
}
|
|
2552
|
+
export {
|
|
2553
|
+
main,
|
|
2554
|
+
reportError,
|
|
2555
|
+
run
|
|
2556
|
+
};
|