create-krispya 0.4.8 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -30
- package/dist/chunks/index.cjs +2360 -0
- package/dist/chunks/index.mjs +2346 -0
- package/dist/cli.cjs +816 -195
- package/dist/cli.mjs +818 -197
- package/dist/index.cjs +10 -1714
- package/dist/index.d.cts +84 -79
- package/dist/index.d.mts +84 -79
- package/dist/index.d.ts +84 -79
- package/dist/index.mjs +2 -1707
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
|
|
4
4
|
const module$1 = require('module');
|
|
5
5
|
const process$1 = require('process');
|
|
6
|
-
const index = require('./index.cjs');
|
|
7
6
|
const path = require('path');
|
|
8
7
|
const promises = require('fs/promises');
|
|
8
|
+
const fs = require('fs');
|
|
9
9
|
const commander = require('commander');
|
|
10
10
|
const p = require('@clack/prompts');
|
|
11
11
|
const color = require('chalk');
|
|
12
12
|
const undici = require('undici');
|
|
13
13
|
const child_process = require('child_process');
|
|
14
|
+
const index = require('./chunks/index.cjs');
|
|
14
15
|
const Conf = require('conf');
|
|
15
16
|
|
|
16
17
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -32,70 +33,31 @@ const p__namespace = /*#__PURE__*/_interopNamespaceCompat(p);
|
|
|
32
33
|
const color__default = /*#__PURE__*/_interopDefaultCompat(color);
|
|
33
34
|
const Conf__default = /*#__PURE__*/_interopDefaultCompat(Conf);
|
|
34
35
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
36
|
+
const editorNames = {
|
|
37
|
+
cursor: "Cursor",
|
|
38
|
+
code: "VS Code",
|
|
39
|
+
webstorm: "WebStorm",
|
|
40
|
+
skip: "Skip"
|
|
41
|
+
};
|
|
42
|
+
function openInEditor(editor, path, reuseWindow) {
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
const isWindows = process.platform === "win32";
|
|
45
|
+
const useReuseFlag = reuseWindow && (editor === "cursor" || editor === "code");
|
|
46
|
+
const args = useReuseFlag ? ["-r", path] : [path];
|
|
47
|
+
const child = isWindows ? child_process.spawn(`${editor} ${useReuseFlag ? "-r " : ""}"${path}"`, {
|
|
48
|
+
detached: true,
|
|
49
|
+
stdio: "ignore",
|
|
50
|
+
shell: true
|
|
51
|
+
}) : child_process.spawn(editor, args, {
|
|
52
|
+
detached: true,
|
|
53
|
+
stdio: "ignore"
|
|
54
|
+
});
|
|
55
|
+
child.on("error", reject);
|
|
56
|
+
child.unref();
|
|
57
|
+
setTimeout(resolve, 100);
|
|
58
|
+
});
|
|
52
59
|
}
|
|
53
60
|
|
|
54
|
-
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href)));
|
|
55
|
-
const pkg = require$1("../package.json");
|
|
56
|
-
function getDefaultProjectName(template) {
|
|
57
|
-
const base = index.getBaseTemplate(template);
|
|
58
|
-
switch (base) {
|
|
59
|
-
case "vanilla":
|
|
60
|
-
return `vanilla-${index.generateRandomName()}`;
|
|
61
|
-
case "react":
|
|
62
|
-
return `react-${index.generateRandomName()}`;
|
|
63
|
-
case "r3f":
|
|
64
|
-
return `react-three-${index.generateRandomName()}`;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function getDefaultOptions(template, name, projectType = "app", libraryBundler) {
|
|
68
|
-
const baseTemplate = index.getBaseTemplate(template);
|
|
69
|
-
const base = {
|
|
70
|
-
name,
|
|
71
|
-
template,
|
|
72
|
-
projectType,
|
|
73
|
-
libraryBundler: projectType === "library" ? libraryBundler ?? "unbuild" : void 0,
|
|
74
|
-
packageManager: "pnpm",
|
|
75
|
-
pnpmManageVersions: true,
|
|
76
|
-
nodeVersion: "latest",
|
|
77
|
-
linter: "oxlint",
|
|
78
|
-
formatter: "oxfmt"
|
|
79
|
-
};
|
|
80
|
-
if (baseTemplate === "r3f") {
|
|
81
|
-
return {
|
|
82
|
-
...base,
|
|
83
|
-
drei: {},
|
|
84
|
-
handle: {},
|
|
85
|
-
leva: {},
|
|
86
|
-
postprocessing: {},
|
|
87
|
-
rapier: {},
|
|
88
|
-
xr: {},
|
|
89
|
-
uikit: {},
|
|
90
|
-
offscreen: {},
|
|
91
|
-
zustand: {},
|
|
92
|
-
koota: {},
|
|
93
|
-
triplex: {},
|
|
94
|
-
viverse: {}
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
return base;
|
|
98
|
-
}
|
|
99
61
|
function formatConfigSummary(options) {
|
|
100
62
|
const lines = [];
|
|
101
63
|
const VALUE_COL = 27;
|
|
@@ -109,6 +71,12 @@ function formatConfigSummary(options) {
|
|
|
109
71
|
return lang === "typescript" ? "TypeScript" : lang === "javascript" ? "JavaScript" : lang;
|
|
110
72
|
};
|
|
111
73
|
const projectType = options.projectType ?? "app";
|
|
74
|
+
const baseTemplate = options.template ? index.getBaseTemplate(options.template) : "vanilla";
|
|
75
|
+
if (baseTemplate === "react") {
|
|
76
|
+
lines.push(formatRow("Framework", "React"));
|
|
77
|
+
} else if (baseTemplate === "r3f") {
|
|
78
|
+
lines.push(formatRow("Framework", "React Three Fiber"));
|
|
79
|
+
}
|
|
112
80
|
const language = options.template ? index.getLanguageFromTemplate(options.template) : "typescript";
|
|
113
81
|
lines.push(formatRow("Language", formatLanguage(language)));
|
|
114
82
|
if (projectType === "library") {
|
|
@@ -128,7 +96,8 @@ function formatConfigSummary(options) {
|
|
|
128
96
|
if (options.formatter) {
|
|
129
97
|
lines.push(formatRow("Formatter", options.formatter));
|
|
130
98
|
}
|
|
131
|
-
|
|
99
|
+
const testing = options.testing ?? (projectType === "library" ? "vitest" : "none");
|
|
100
|
+
lines.push(formatRow("Testing", testing));
|
|
132
101
|
if (options.template && index.getBaseTemplate(options.template) === "r3f") {
|
|
133
102
|
const integrationNames = [
|
|
134
103
|
options.drei && "drei",
|
|
@@ -155,7 +124,123 @@ function formatConfigSummary(options) {
|
|
|
155
124
|
}
|
|
156
125
|
return lines.join("\n");
|
|
157
126
|
}
|
|
158
|
-
|
|
127
|
+
function formatMonorepoConfigSummary(options) {
|
|
128
|
+
const lines = [];
|
|
129
|
+
const VALUE_COL = 27;
|
|
130
|
+
const formatRow = (label, value, indent = "") => {
|
|
131
|
+
const fullLabel = indent + label;
|
|
132
|
+
const dotCount = Math.max(1, VALUE_COL - fullLabel.length - 1);
|
|
133
|
+
const dots = color__default.gray(".".repeat(dotCount));
|
|
134
|
+
return `${indent}${label} ${dots} ${value}`;
|
|
135
|
+
};
|
|
136
|
+
lines.push(formatRow("Node version", options.nodeVersion || "latest"));
|
|
137
|
+
lines.push(formatRow("Package manager", options.packageManager || "pnpm"));
|
|
138
|
+
if (options.packageManager === "pnpm") {
|
|
139
|
+
const versionManaged = options.pnpmManageVersions ? "yes" : "no";
|
|
140
|
+
lines.push(formatRow("\u21B3 Version managed", versionManaged, ""));
|
|
141
|
+
}
|
|
142
|
+
lines.push(formatRow("Linter", options.linter));
|
|
143
|
+
lines.push(formatRow("Formatter", options.formatter));
|
|
144
|
+
return lines.join("\n");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const config = new Conf__default({
|
|
148
|
+
projectName: "create-krispya"
|
|
149
|
+
});
|
|
150
|
+
function getPreferredEditor() {
|
|
151
|
+
return config.get("preferredEditor");
|
|
152
|
+
}
|
|
153
|
+
function setPreferredEditor(editor) {
|
|
154
|
+
config.set("preferredEditor", editor);
|
|
155
|
+
}
|
|
156
|
+
function getReuseWindow() {
|
|
157
|
+
return config.get("reuseWindow") ?? false;
|
|
158
|
+
}
|
|
159
|
+
function setReuseWindow(reuse) {
|
|
160
|
+
config.set("reuseWindow", reuse);
|
|
161
|
+
}
|
|
162
|
+
function clearConfig() {
|
|
163
|
+
config.clear();
|
|
164
|
+
}
|
|
165
|
+
function getConfigPath() {
|
|
166
|
+
return config.path;
|
|
167
|
+
}
|
|
168
|
+
function getCustomTemplates() {
|
|
169
|
+
return config.get("customTemplates") ?? {};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function getDefaultOptions(template, name, projectType = "app", libraryBundler, integrations, inheritedTooling) {
|
|
173
|
+
const baseTemplate = index.getBaseTemplate(template);
|
|
174
|
+
const base = {
|
|
175
|
+
name,
|
|
176
|
+
template,
|
|
177
|
+
projectType,
|
|
178
|
+
libraryBundler: projectType === "library" ? libraryBundler ?? "unbuild" : void 0,
|
|
179
|
+
packageManager: "pnpm",
|
|
180
|
+
pnpmManageVersions: true,
|
|
181
|
+
nodeVersion: "latest",
|
|
182
|
+
linter: inheritedTooling?.linter ?? "oxlint",
|
|
183
|
+
formatter: inheritedTooling?.formatter ?? "oxfmt",
|
|
184
|
+
// Libraries get vitest by default, apps don't
|
|
185
|
+
testing: projectType === "library" ? "vitest" : "none"
|
|
186
|
+
};
|
|
187
|
+
if (baseTemplate === "r3f" && integrations) {
|
|
188
|
+
return {
|
|
189
|
+
...base,
|
|
190
|
+
drei: integrations.includes("drei") ? {} : void 0,
|
|
191
|
+
handle: integrations.includes("handle") ? {} : void 0,
|
|
192
|
+
leva: integrations.includes("leva") ? {} : void 0,
|
|
193
|
+
postprocessing: integrations.includes("postprocessing") ? {} : void 0,
|
|
194
|
+
rapier: integrations.includes("rapier") ? {} : void 0,
|
|
195
|
+
xr: integrations.includes("xr") ? {} : void 0,
|
|
196
|
+
uikit: integrations.includes("uikit") ? {} : void 0,
|
|
197
|
+
offscreen: integrations.includes("offscreen") ? {} : void 0,
|
|
198
|
+
zustand: integrations.includes("zustand") ? {} : void 0,
|
|
199
|
+
koota: integrations.includes("koota") ? {} : void 0,
|
|
200
|
+
triplex: integrations.includes("triplex") ? {} : void 0,
|
|
201
|
+
viverse: integrations.includes("viverse") ? {} : void 0
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return base;
|
|
205
|
+
}
|
|
206
|
+
function getDefaultProjectName(template) {
|
|
207
|
+
const base = index.getBaseTemplate(template);
|
|
208
|
+
switch (base) {
|
|
209
|
+
case "vanilla":
|
|
210
|
+
return `vanilla-${index.generateRandomName()}`;
|
|
211
|
+
case "react":
|
|
212
|
+
return `react-${index.generateRandomName()}`;
|
|
213
|
+
case "r3f":
|
|
214
|
+
return `react-three-${index.generateRandomName()}`;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async function promptForR3fIntegrations() {
|
|
218
|
+
const selected = await p__namespace.multiselect({
|
|
219
|
+
message: "R3F integrations",
|
|
220
|
+
options: [
|
|
221
|
+
{ value: "drei", label: "Drei" },
|
|
222
|
+
{ value: "handle", label: "Handle" },
|
|
223
|
+
{ value: "leva", label: "Leva" },
|
|
224
|
+
{ value: "postprocessing", label: "Postprocessing" },
|
|
225
|
+
{ value: "rapier", label: "Rapier" },
|
|
226
|
+
{ value: "xr", label: "XR" },
|
|
227
|
+
{ value: "uikit", label: "UIKit" },
|
|
228
|
+
{ value: "offscreen", label: "Offscreen" },
|
|
229
|
+
{ value: "zustand", label: "Zustand" },
|
|
230
|
+
{ value: "koota", label: "Koota" },
|
|
231
|
+
{ value: "triplex", label: "Triplex" },
|
|
232
|
+
{ value: "viverse", label: "Viverse" }
|
|
233
|
+
],
|
|
234
|
+
initialValues: ["drei"],
|
|
235
|
+
required: false
|
|
236
|
+
});
|
|
237
|
+
if (p__namespace.isCancel(selected)) {
|
|
238
|
+
p__namespace.cancel("Operation cancelled.");
|
|
239
|
+
process.exit(0);
|
|
240
|
+
}
|
|
241
|
+
return selected;
|
|
242
|
+
}
|
|
243
|
+
async function promptForCustomization(template, name, projectType, integrations, inheritedTooling) {
|
|
159
244
|
let libraryBundler;
|
|
160
245
|
if (projectType === "library") {
|
|
161
246
|
const bundler = await p__namespace.select({
|
|
@@ -227,29 +312,49 @@ async function promptForCustomization(template, name, projectType) {
|
|
|
227
312
|
}
|
|
228
313
|
pnpmManageVersions = managePnpm;
|
|
229
314
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
315
|
+
let linter = inheritedTooling?.linter ?? "oxlint";
|
|
316
|
+
let formatter = inheritedTooling?.formatter ?? "oxfmt";
|
|
317
|
+
if (!inheritedTooling?.linter) {
|
|
318
|
+
const linterChoice = await p__namespace.select({
|
|
319
|
+
message: "Linter",
|
|
320
|
+
options: [
|
|
321
|
+
{ value: "oxlint", label: "Oxlint", hint: "fast, from OXC" },
|
|
322
|
+
{ value: "eslint", label: "ESLint", hint: "classic" },
|
|
323
|
+
{ value: "biome", label: "Biome", hint: "all-in-one" }
|
|
324
|
+
],
|
|
325
|
+
initialValue: "oxlint"
|
|
326
|
+
});
|
|
327
|
+
if (p__namespace.isCancel(linterChoice)) {
|
|
328
|
+
p__namespace.cancel("Operation cancelled.");
|
|
329
|
+
process.exit(0);
|
|
330
|
+
}
|
|
331
|
+
linter = linterChoice;
|
|
242
332
|
}
|
|
243
|
-
|
|
244
|
-
|
|
333
|
+
if (!inheritedTooling?.formatter) {
|
|
334
|
+
const formatterChoice = await p__namespace.select({
|
|
335
|
+
message: "Formatter",
|
|
336
|
+
options: [
|
|
337
|
+
{ value: "oxfmt", label: "Oxfmt", hint: "fast, Prettier-compatible" },
|
|
338
|
+
{ value: "prettier", label: "Prettier", hint: "classic" },
|
|
339
|
+
{ value: "biome", label: "Biome", hint: "all-in-one" }
|
|
340
|
+
],
|
|
341
|
+
initialValue: "oxfmt"
|
|
342
|
+
});
|
|
343
|
+
if (p__namespace.isCancel(formatterChoice)) {
|
|
344
|
+
p__namespace.cancel("Operation cancelled.");
|
|
345
|
+
process.exit(0);
|
|
346
|
+
}
|
|
347
|
+
formatter = formatterChoice;
|
|
348
|
+
}
|
|
349
|
+
const testing = await p__namespace.select({
|
|
350
|
+
message: "Testing",
|
|
245
351
|
options: [
|
|
246
|
-
{ value: "
|
|
247
|
-
{ value: "
|
|
248
|
-
{ value: "biome", label: "Biome", hint: "all-in-one" }
|
|
352
|
+
{ value: "vitest", label: "Vitest", hint: "fast, Vite-native" },
|
|
353
|
+
{ value: "none", label: "None" }
|
|
249
354
|
],
|
|
250
|
-
initialValue: "
|
|
355
|
+
initialValue: projectType === "library" ? "vitest" : "none"
|
|
251
356
|
});
|
|
252
|
-
if (p__namespace.isCancel(
|
|
357
|
+
if (p__namespace.isCancel(testing)) {
|
|
253
358
|
p__namespace.cancel("Operation cancelled.");
|
|
254
359
|
process.exit(0);
|
|
255
360
|
}
|
|
@@ -267,47 +372,7 @@ async function promptForCustomization(template, name, projectType) {
|
|
|
267
372
|
}
|
|
268
373
|
const baseTemplate = index.getBaseTemplate(template);
|
|
269
374
|
const finalTemplate = language === "javascript" ? `${baseTemplate}-js` : baseTemplate;
|
|
270
|
-
|
|
271
|
-
if (baseTemplate === "r3f") {
|
|
272
|
-
const selected = await p__namespace.multiselect({
|
|
273
|
-
message: "R3F integrations",
|
|
274
|
-
options: [
|
|
275
|
-
{ value: "drei", label: "Drei" },
|
|
276
|
-
{ value: "handle", label: "Handle" },
|
|
277
|
-
{ value: "leva", label: "Leva" },
|
|
278
|
-
{ value: "postprocessing", label: "Postprocessing" },
|
|
279
|
-
{ value: "rapier", label: "Rapier" },
|
|
280
|
-
{ value: "xr", label: "XR" },
|
|
281
|
-
{ value: "uikit", label: "UIKit" },
|
|
282
|
-
{ value: "offscreen", label: "Offscreen" },
|
|
283
|
-
{ value: "zustand", label: "Zustand" },
|
|
284
|
-
{ value: "koota", label: "Koota" },
|
|
285
|
-
{ value: "triplex", label: "Triplex" },
|
|
286
|
-
{ value: "viverse", label: "Viverse" }
|
|
287
|
-
],
|
|
288
|
-
initialValues: [
|
|
289
|
-
"drei",
|
|
290
|
-
"handle",
|
|
291
|
-
"leva",
|
|
292
|
-
"postprocessing",
|
|
293
|
-
"rapier",
|
|
294
|
-
"xr",
|
|
295
|
-
"uikit",
|
|
296
|
-
"offscreen",
|
|
297
|
-
"zustand",
|
|
298
|
-
"koota",
|
|
299
|
-
"triplex",
|
|
300
|
-
"viverse"
|
|
301
|
-
],
|
|
302
|
-
required: false
|
|
303
|
-
});
|
|
304
|
-
if (p__namespace.isCancel(selected)) {
|
|
305
|
-
p__namespace.cancel("Operation cancelled.");
|
|
306
|
-
process.exit(0);
|
|
307
|
-
}
|
|
308
|
-
integrations = selected;
|
|
309
|
-
}
|
|
310
|
-
return {
|
|
375
|
+
const base = {
|
|
311
376
|
name,
|
|
312
377
|
template: finalTemplate,
|
|
313
378
|
projectType,
|
|
@@ -317,7 +382,11 @@ async function promptForCustomization(template, name, projectType) {
|
|
|
317
382
|
pnpmManageVersions,
|
|
318
383
|
linter,
|
|
319
384
|
formatter,
|
|
320
|
-
|
|
385
|
+
testing
|
|
386
|
+
};
|
|
387
|
+
if (baseTemplate === "r3f" && integrations) {
|
|
388
|
+
return {
|
|
389
|
+
...base,
|
|
321
390
|
drei: integrations.includes("drei") ? {} : void 0,
|
|
322
391
|
handle: integrations.includes("handle") ? {} : void 0,
|
|
323
392
|
leva: integrations.includes("leva") ? {} : void 0,
|
|
@@ -330,9 +399,140 @@ async function promptForCustomization(template, name, projectType) {
|
|
|
330
399
|
koota: integrations.includes("koota") ? {} : void 0,
|
|
331
400
|
triplex: integrations.includes("triplex") ? {} : void 0,
|
|
332
401
|
viverse: integrations.includes("viverse") ? {} : void 0
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
return base;
|
|
405
|
+
}
|
|
406
|
+
async function promptForInitialPackage() {
|
|
407
|
+
const choice = await p__namespace.select({
|
|
408
|
+
message: "Add an initial package?",
|
|
409
|
+
options: [
|
|
410
|
+
{ value: "app", label: "Application" },
|
|
411
|
+
{ value: "library", label: "Library" },
|
|
412
|
+
{ value: "skip", label: "Skip" }
|
|
413
|
+
],
|
|
414
|
+
initialValue: "app"
|
|
415
|
+
});
|
|
416
|
+
if (p__namespace.isCancel(choice)) {
|
|
417
|
+
p__namespace.cancel("Operation cancelled.");
|
|
418
|
+
process.exit(0);
|
|
419
|
+
}
|
|
420
|
+
return choice;
|
|
421
|
+
}
|
|
422
|
+
function getDefaultMonorepoOptions(name) {
|
|
423
|
+
return {
|
|
424
|
+
name,
|
|
425
|
+
projectType: "monorepo",
|
|
426
|
+
packageManager: "pnpm",
|
|
427
|
+
pnpmManageVersions: true,
|
|
428
|
+
nodeVersion: "latest",
|
|
429
|
+
linter: "oxlint",
|
|
430
|
+
formatter: "oxfmt"
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
async function promptForMonorepoCustomization(name) {
|
|
434
|
+
const nodeVersion = await p__namespace.text({
|
|
435
|
+
message: "Node.js version",
|
|
436
|
+
placeholder: "latest",
|
|
437
|
+
defaultValue: "latest",
|
|
438
|
+
validate: (value) => {
|
|
439
|
+
if (!value.length) return "Required";
|
|
440
|
+
if (value !== "latest" && !/^\d+(\.\d+(\.\d+)?)?$/.test(value)) {
|
|
441
|
+
return 'Must be "latest" or a valid semver (e.g., "22" or "22.13.0")';
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
if (p__namespace.isCancel(nodeVersion)) {
|
|
446
|
+
p__namespace.cancel("Operation cancelled.");
|
|
447
|
+
process.exit(0);
|
|
448
|
+
}
|
|
449
|
+
const packageManager = await p__namespace.select({
|
|
450
|
+
message: "Package manager",
|
|
451
|
+
options: [
|
|
452
|
+
{ value: "pnpm", label: "pnpm" },
|
|
453
|
+
{ value: "npm", label: "npm" },
|
|
454
|
+
{ value: "yarn", label: "yarn" }
|
|
455
|
+
],
|
|
456
|
+
initialValue: "pnpm"
|
|
457
|
+
});
|
|
458
|
+
if (p__namespace.isCancel(packageManager)) {
|
|
459
|
+
p__namespace.cancel("Operation cancelled.");
|
|
460
|
+
process.exit(0);
|
|
461
|
+
}
|
|
462
|
+
let pnpmManageVersions = true;
|
|
463
|
+
if (packageManager === "pnpm") {
|
|
464
|
+
const managePnpm = await p__namespace.confirm({
|
|
465
|
+
message: "Enable manage-package-manager-versions?",
|
|
466
|
+
initialValue: true
|
|
467
|
+
});
|
|
468
|
+
if (p__namespace.isCancel(managePnpm)) {
|
|
469
|
+
p__namespace.cancel("Operation cancelled.");
|
|
470
|
+
process.exit(0);
|
|
333
471
|
}
|
|
472
|
+
pnpmManageVersions = managePnpm;
|
|
473
|
+
}
|
|
474
|
+
const linter = await p__namespace.select({
|
|
475
|
+
message: "Linter",
|
|
476
|
+
options: [
|
|
477
|
+
{ value: "oxlint", label: "Oxlint", hint: "fast, from OXC" },
|
|
478
|
+
{ value: "eslint", label: "ESLint", hint: "classic" },
|
|
479
|
+
{ value: "biome", label: "Biome", hint: "all-in-one" }
|
|
480
|
+
],
|
|
481
|
+
initialValue: "oxlint"
|
|
482
|
+
});
|
|
483
|
+
if (p__namespace.isCancel(linter)) {
|
|
484
|
+
p__namespace.cancel("Operation cancelled.");
|
|
485
|
+
process.exit(0);
|
|
486
|
+
}
|
|
487
|
+
const formatter = await p__namespace.select({
|
|
488
|
+
message: "Formatter",
|
|
489
|
+
options: [
|
|
490
|
+
{ value: "oxfmt", label: "Oxfmt", hint: "fast, Prettier-compatible" },
|
|
491
|
+
{ value: "prettier", label: "Prettier", hint: "classic" },
|
|
492
|
+
{ value: "biome", label: "Biome", hint: "all-in-one" }
|
|
493
|
+
],
|
|
494
|
+
initialValue: "oxfmt"
|
|
495
|
+
});
|
|
496
|
+
if (p__namespace.isCancel(formatter)) {
|
|
497
|
+
p__namespace.cancel("Operation cancelled.");
|
|
498
|
+
process.exit(0);
|
|
499
|
+
}
|
|
500
|
+
return {
|
|
501
|
+
name,
|
|
502
|
+
projectType: "monorepo",
|
|
503
|
+
nodeVersion,
|
|
504
|
+
packageManager,
|
|
505
|
+
pnpmManageVersions,
|
|
506
|
+
linter,
|
|
507
|
+
formatter
|
|
334
508
|
};
|
|
335
509
|
}
|
|
510
|
+
async function promptForMonorepo(workspaceName) {
|
|
511
|
+
const defaultOptions = getDefaultMonorepoOptions(workspaceName);
|
|
512
|
+
p__namespace.note(
|
|
513
|
+
formatMonorepoConfigSummary({
|
|
514
|
+
name: defaultOptions.name,
|
|
515
|
+
nodeVersion: defaultOptions.nodeVersion ?? "latest",
|
|
516
|
+
packageManager: defaultOptions.packageManager ?? "pnpm",
|
|
517
|
+
pnpmManageVersions: defaultOptions.pnpmManageVersions,
|
|
518
|
+
linter: defaultOptions.linter ?? "oxlint",
|
|
519
|
+
formatter: defaultOptions.formatter ?? "oxfmt"
|
|
520
|
+
}),
|
|
521
|
+
"Workspace Configuration"
|
|
522
|
+
);
|
|
523
|
+
const proceed = await p__namespace.confirm({
|
|
524
|
+
message: "Proceed with these settings?",
|
|
525
|
+
initialValue: true
|
|
526
|
+
});
|
|
527
|
+
if (p__namespace.isCancel(proceed)) {
|
|
528
|
+
p__namespace.cancel("Operation cancelled.");
|
|
529
|
+
process.exit(0);
|
|
530
|
+
}
|
|
531
|
+
if (proceed) {
|
|
532
|
+
return defaultOptions;
|
|
533
|
+
}
|
|
534
|
+
return promptForMonorepoCustomization(workspaceName);
|
|
535
|
+
}
|
|
336
536
|
async function promptForOptions(name) {
|
|
337
537
|
let projectName = name;
|
|
338
538
|
if (!projectName) {
|
|
@@ -354,7 +554,8 @@ async function promptForOptions(name) {
|
|
|
354
554
|
message: "Project type",
|
|
355
555
|
options: [
|
|
356
556
|
{ value: "app", label: "Application" },
|
|
357
|
-
{ value: "library", label: "Library" }
|
|
557
|
+
{ value: "library", label: "Library" },
|
|
558
|
+
{ value: "monorepo", label: "Monorepo" }
|
|
358
559
|
],
|
|
359
560
|
initialValue: "app"
|
|
360
561
|
});
|
|
@@ -362,91 +563,408 @@ async function promptForOptions(name) {
|
|
|
362
563
|
p__namespace.cancel("Operation cancelled.");
|
|
363
564
|
process.exit(0);
|
|
364
565
|
}
|
|
365
|
-
|
|
566
|
+
if (projectType === "monorepo") {
|
|
567
|
+
return promptForMonorepo(projectName);
|
|
568
|
+
}
|
|
569
|
+
return promptForPackageOptions(projectName, projectType);
|
|
570
|
+
}
|
|
571
|
+
function customTemplateToOptions(customTemplate, name, projectType) {
|
|
572
|
+
const baseTemplate = customTemplate.baseTemplate;
|
|
573
|
+
const template = baseTemplate;
|
|
574
|
+
const base = {
|
|
575
|
+
name,
|
|
576
|
+
template,
|
|
577
|
+
projectType,
|
|
578
|
+
packageManager: "pnpm",
|
|
579
|
+
pnpmManageVersions: true,
|
|
580
|
+
nodeVersion: "latest",
|
|
581
|
+
linter: customTemplate.linter,
|
|
582
|
+
formatter: customTemplate.formatter,
|
|
583
|
+
testing: customTemplate.testing
|
|
584
|
+
};
|
|
585
|
+
if (baseTemplate === "r3f" && customTemplate.integrations) {
|
|
586
|
+
const integrations = customTemplate.integrations;
|
|
587
|
+
return {
|
|
588
|
+
...base,
|
|
589
|
+
drei: integrations.includes("drei") ? {} : void 0,
|
|
590
|
+
handle: integrations.includes("handle") ? {} : void 0,
|
|
591
|
+
leva: integrations.includes("leva") ? {} : void 0,
|
|
592
|
+
postprocessing: integrations.includes("postprocessing") ? {} : void 0,
|
|
593
|
+
rapier: integrations.includes("rapier") ? {} : void 0,
|
|
594
|
+
xr: integrations.includes("xr") ? {} : void 0,
|
|
595
|
+
uikit: integrations.includes("uikit") ? {} : void 0,
|
|
596
|
+
offscreen: integrations.includes("offscreen") ? {} : void 0,
|
|
597
|
+
zustand: integrations.includes("zustand") ? {} : void 0,
|
|
598
|
+
koota: integrations.includes("koota") ? {} : void 0,
|
|
599
|
+
triplex: integrations.includes("triplex") ? {} : void 0,
|
|
600
|
+
viverse: integrations.includes("viverse") ? {} : void 0
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
return base;
|
|
604
|
+
}
|
|
605
|
+
async function promptForPackageOptions(projectName, projectType, inheritedTooling) {
|
|
606
|
+
const builtInOptions = [
|
|
607
|
+
{ value: "vanilla", label: "Vanilla" },
|
|
608
|
+
{ value: "react", label: "React" },
|
|
609
|
+
{ value: "r3f", label: "React Three Fiber" }
|
|
610
|
+
];
|
|
611
|
+
const customTemplates = getCustomTemplates();
|
|
612
|
+
const customOptions = Object.keys(customTemplates).map((name) => ({
|
|
613
|
+
value: `custom:${name}`,
|
|
614
|
+
label: name,
|
|
615
|
+
hint: "saved template"
|
|
616
|
+
}));
|
|
617
|
+
const allOptions = [...builtInOptions, ...customOptions];
|
|
618
|
+
const templateSelection = await p__namespace.select({
|
|
366
619
|
message: "Select a template",
|
|
367
|
-
options:
|
|
368
|
-
{ value: "vanilla", label: "Vanilla" },
|
|
369
|
-
{ value: "react", label: "React" },
|
|
370
|
-
{ value: "r3f", label: "React Three Fiber" }
|
|
371
|
-
],
|
|
620
|
+
options: allOptions,
|
|
372
621
|
initialValue: "vanilla"
|
|
373
622
|
});
|
|
374
|
-
if (p__namespace.isCancel(
|
|
623
|
+
if (p__namespace.isCancel(templateSelection)) {
|
|
375
624
|
p__namespace.cancel("Operation cancelled.");
|
|
376
625
|
process.exit(0);
|
|
377
626
|
}
|
|
627
|
+
const selection = templateSelection;
|
|
628
|
+
if (selection.startsWith("custom:")) {
|
|
629
|
+
const customName = selection.slice(7);
|
|
630
|
+
const customTemplate = customTemplates[customName];
|
|
631
|
+
const defaultOptions2 = customTemplateToOptions(customTemplate, projectName, projectType);
|
|
632
|
+
if (inheritedTooling?.linter) {
|
|
633
|
+
defaultOptions2.linter = inheritedTooling.linter;
|
|
634
|
+
}
|
|
635
|
+
if (inheritedTooling?.formatter) {
|
|
636
|
+
defaultOptions2.formatter = inheritedTooling.formatter;
|
|
637
|
+
}
|
|
638
|
+
const configTitle2 = inheritedTooling ? `Template: ${customName} (using workspace tooling)` : `Template: ${customName}`;
|
|
639
|
+
p__namespace.note(formatConfigSummary(defaultOptions2), configTitle2);
|
|
640
|
+
const proceed2 = await p__namespace.confirm({
|
|
641
|
+
message: "Proceed with these settings?",
|
|
642
|
+
initialValue: true
|
|
643
|
+
});
|
|
644
|
+
if (p__namespace.isCancel(proceed2)) {
|
|
645
|
+
p__namespace.cancel("Operation cancelled.");
|
|
646
|
+
process.exit(0);
|
|
647
|
+
}
|
|
648
|
+
if (proceed2) {
|
|
649
|
+
return defaultOptions2;
|
|
650
|
+
}
|
|
651
|
+
return promptForCustomization(
|
|
652
|
+
customTemplate.baseTemplate,
|
|
653
|
+
projectName,
|
|
654
|
+
projectType,
|
|
655
|
+
customTemplate.integrations,
|
|
656
|
+
inheritedTooling
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
const template = selection;
|
|
660
|
+
const baseTemplate = index.getBaseTemplate(template);
|
|
661
|
+
let integrations;
|
|
662
|
+
if (baseTemplate === "r3f") {
|
|
663
|
+
integrations = await promptForR3fIntegrations();
|
|
664
|
+
}
|
|
378
665
|
const defaultOptions = getDefaultOptions(
|
|
379
666
|
template,
|
|
380
667
|
projectName,
|
|
381
|
-
projectType
|
|
668
|
+
projectType,
|
|
669
|
+
void 0,
|
|
670
|
+
integrations,
|
|
671
|
+
inheritedTooling
|
|
382
672
|
);
|
|
383
|
-
|
|
384
|
-
|
|
673
|
+
const configTitle = inheritedTooling ? "Template Configuration (using workspace tooling)" : "Template Configuration";
|
|
674
|
+
p__namespace.note(formatConfigSummary(defaultOptions), configTitle);
|
|
675
|
+
const proceed = await p__namespace.confirm({
|
|
385
676
|
message: "Proceed with these settings?",
|
|
386
|
-
|
|
387
|
-
{ value: "confirm", label: "Yes, create project" },
|
|
388
|
-
{ value: "customize", label: "No, let me customize" }
|
|
389
|
-
],
|
|
390
|
-
initialValue: "confirm"
|
|
677
|
+
initialValue: true
|
|
391
678
|
});
|
|
392
|
-
if (p__namespace.isCancel(
|
|
679
|
+
if (p__namespace.isCancel(proceed)) {
|
|
393
680
|
p__namespace.cancel("Operation cancelled.");
|
|
394
681
|
process.exit(0);
|
|
395
682
|
}
|
|
396
|
-
if (
|
|
683
|
+
if (proceed) {
|
|
397
684
|
return defaultOptions;
|
|
398
685
|
}
|
|
399
|
-
return promptForCustomization(
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
686
|
+
return promptForCustomization(template, projectName, projectType, integrations, inheritedTooling);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href)));
|
|
690
|
+
const pkg = require$1("../package.json");
|
|
691
|
+
async function detectMonorepoRoot() {
|
|
692
|
+
let currentDir = process$1.cwd();
|
|
693
|
+
const root = path.resolve("/");
|
|
694
|
+
while (currentDir !== root) {
|
|
695
|
+
const workspaceFile = path.join(currentDir, "pnpm-workspace.yaml");
|
|
696
|
+
try {
|
|
697
|
+
await promises.access(workspaceFile, fs.constants.F_OK);
|
|
698
|
+
const content = await promises.readFile(workspaceFile, "utf-8");
|
|
699
|
+
if (content.includes("packages:")) {
|
|
700
|
+
return currentDir;
|
|
701
|
+
}
|
|
702
|
+
} catch {
|
|
703
|
+
}
|
|
704
|
+
currentDir = path.dirname(currentDir);
|
|
705
|
+
}
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
async function detectWorkspaceTooling(monorepoRoot) {
|
|
709
|
+
try {
|
|
710
|
+
const pkgPath = path.join(monorepoRoot, "package.json");
|
|
711
|
+
const content = await promises.readFile(pkgPath, "utf-8");
|
|
712
|
+
const pkg2 = JSON.parse(content);
|
|
713
|
+
const devDeps = pkg2.devDependencies ?? {};
|
|
714
|
+
const linter = devDeps.oxlint ? "oxlint" : devDeps.eslint ? "eslint" : devDeps["@biomejs/biome"] ? "biome" : void 0;
|
|
715
|
+
const formatter = devDeps.oxfmt ? "oxfmt" : devDeps.prettier ? "prettier" : devDeps["@biomejs/biome"] ? "biome" : void 0;
|
|
716
|
+
return { linter, formatter };
|
|
717
|
+
} catch {
|
|
718
|
+
return {};
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
async function getMonorepoScope(monorepoRoot) {
|
|
722
|
+
try {
|
|
723
|
+
const pkgPath = path.join(monorepoRoot, "package.json");
|
|
724
|
+
const content = await promises.readFile(pkgPath, "utf-8");
|
|
725
|
+
const pkg2 = JSON.parse(content);
|
|
726
|
+
if (pkg2.name) {
|
|
727
|
+
return pkg2.name.replace(/^@/, "").replace(/\/.*$/, "");
|
|
728
|
+
}
|
|
729
|
+
} catch {
|
|
730
|
+
}
|
|
731
|
+
return monorepoRoot.split(/[/\\]/).pop() ?? "workspace";
|
|
732
|
+
}
|
|
733
|
+
async function getWorkspacePackages(monorepoRoot) {
|
|
734
|
+
const packagesDir = path.join(monorepoRoot, "packages");
|
|
735
|
+
const packages = [];
|
|
736
|
+
try {
|
|
737
|
+
const { readdir } = await import('fs/promises');
|
|
738
|
+
const entries = await readdir(packagesDir, { withFileTypes: true });
|
|
739
|
+
for (const entry of entries) {
|
|
740
|
+
if (entry.isDirectory()) {
|
|
741
|
+
try {
|
|
742
|
+
const pkgJsonPath = path.join(packagesDir, entry.name, "package.json");
|
|
743
|
+
const content = await promises.readFile(pkgJsonPath, "utf-8");
|
|
744
|
+
const pkg2 = JSON.parse(content);
|
|
745
|
+
if (pkg2.name) {
|
|
746
|
+
packages.push({ name: pkg2.name, path: `packages/${entry.name}` });
|
|
747
|
+
}
|
|
748
|
+
} catch {
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
} catch {
|
|
753
|
+
}
|
|
754
|
+
return packages;
|
|
755
|
+
}
|
|
756
|
+
async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedTooling, scope) {
|
|
757
|
+
const packageType = await promptForInitialPackage();
|
|
758
|
+
if (packageType === "skip") {
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
const packageNameInput = await p__namespace.text({
|
|
762
|
+
message: "Package name?",
|
|
763
|
+
placeholder: `Scoped to @${scope}/`,
|
|
764
|
+
validate: (value) => {
|
|
765
|
+
if (!value.length) return "Package name is required";
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
if (p__namespace.isCancel(packageNameInput)) {
|
|
769
|
+
return false;
|
|
770
|
+
}
|
|
771
|
+
const shortName = packageNameInput;
|
|
772
|
+
const scopedName = `@${scope}/${shortName}`;
|
|
773
|
+
const targetDir = packageType === "app" ? "apps" : "packages";
|
|
774
|
+
const packagePath = path.join(targetDir, shortName);
|
|
775
|
+
const workspaceRoot = "../..";
|
|
776
|
+
const packageOptions = await promptForPackageOptions(
|
|
777
|
+
scopedName,
|
|
778
|
+
packageType,
|
|
779
|
+
inheritedTooling
|
|
403
780
|
);
|
|
781
|
+
packageOptions.workspaceRoot = workspaceRoot;
|
|
782
|
+
packageOptions.name = scopedName;
|
|
783
|
+
if (packageManager === "pnpm") {
|
|
784
|
+
packageOptions.pnpmVersion = await index.getLatestPnpmVersion();
|
|
785
|
+
}
|
|
786
|
+
const nodeVersion = packageOptions.nodeVersion ?? "latest";
|
|
787
|
+
if (nodeVersion === "latest") {
|
|
788
|
+
packageOptions.nodeVersion = await index.getLatestNodeVersion();
|
|
789
|
+
}
|
|
790
|
+
const versions = {};
|
|
791
|
+
const versionPromises = [];
|
|
792
|
+
const pkgIsLibrary = packageOptions.projectType === "library";
|
|
793
|
+
const pkgTesting = packageOptions.testing ?? (pkgIsLibrary ? "vitest" : "none");
|
|
794
|
+
if (pkgTesting === "vitest") {
|
|
795
|
+
versionPromises.push(
|
|
796
|
+
index.getLatestNpmVersion("vitest", "4.0.0").then((v) => {
|
|
797
|
+
versions.vitest = v;
|
|
798
|
+
})
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
if (!pkgIsLibrary) {
|
|
802
|
+
versionPromises.push(
|
|
803
|
+
index.getLatestNpmVersion("vite", "6.3.4").then((v) => {
|
|
804
|
+
versions.vite = v;
|
|
805
|
+
})
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
const linter = packageOptions.linter ?? "oxlint";
|
|
809
|
+
if (linter === "eslint") {
|
|
810
|
+
versionPromises.push(
|
|
811
|
+
index.getLatestNpmVersion("eslint", "9.17.0").then((v) => {
|
|
812
|
+
versions.eslint = v;
|
|
813
|
+
})
|
|
814
|
+
);
|
|
815
|
+
} else if (linter === "oxlint") {
|
|
816
|
+
versionPromises.push(
|
|
817
|
+
index.getLatestNpmVersion("oxlint", "0.16.0").then((v) => {
|
|
818
|
+
versions.oxlint = v;
|
|
819
|
+
})
|
|
820
|
+
);
|
|
821
|
+
} else if (linter === "biome") {
|
|
822
|
+
versionPromises.push(
|
|
823
|
+
index.getLatestNpmVersion("@biomejs/biome", "1.9.4").then((v) => {
|
|
824
|
+
versions.biome = v;
|
|
825
|
+
})
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
const formatter = packageOptions.formatter ?? "oxfmt";
|
|
829
|
+
if (formatter === "prettier") {
|
|
830
|
+
versionPromises.push(
|
|
831
|
+
index.getLatestNpmVersion("prettier", "3.4.2").then((v) => {
|
|
832
|
+
versions.prettier = v;
|
|
833
|
+
})
|
|
834
|
+
);
|
|
835
|
+
} else if (formatter === "oxfmt") {
|
|
836
|
+
versionPromises.push(
|
|
837
|
+
index.getLatestNpmVersion("oxfmt", "0.1.0").then((v) => {
|
|
838
|
+
versions.oxfmt = v;
|
|
839
|
+
})
|
|
840
|
+
);
|
|
841
|
+
} else if (formatter === "biome" && linter !== "biome") {
|
|
842
|
+
versionPromises.push(
|
|
843
|
+
index.getLatestNpmVersion("@biomejs/biome", "1.9.4").then((v) => {
|
|
844
|
+
versions.biome = v;
|
|
845
|
+
})
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
await Promise.all(versionPromises);
|
|
849
|
+
packageOptions.versions = versions;
|
|
850
|
+
if (packageType === "app") {
|
|
851
|
+
const workspacePackages = await getWorkspacePackages(monorepoRoot);
|
|
852
|
+
if (workspacePackages.length > 0) {
|
|
853
|
+
const selectedDeps = await p__namespace.multiselect({
|
|
854
|
+
message: "Add workspace dependencies?",
|
|
855
|
+
options: workspacePackages.map((pkg2) => ({
|
|
856
|
+
value: pkg2.name,
|
|
857
|
+
label: pkg2.name.replace(/^@[^/]+\//, "")
|
|
858
|
+
})),
|
|
859
|
+
required: false
|
|
860
|
+
});
|
|
861
|
+
if (!p__namespace.isCancel(selectedDeps) && selectedDeps.length > 0) {
|
|
862
|
+
packageOptions.workspaceDependencies = selectedDeps;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
const basePath = path.join(monorepoRoot, packagePath);
|
|
867
|
+
const s = p__namespace.spinner();
|
|
868
|
+
s.start("Creating package...");
|
|
869
|
+
try {
|
|
870
|
+
const files = index.generate(packageOptions);
|
|
871
|
+
const filePaths = Object.keys(files).sort();
|
|
872
|
+
for (const filePath of filePaths) {
|
|
873
|
+
const fullFilePath = path.join(basePath, filePath);
|
|
874
|
+
await promises.mkdir(path.dirname(fullFilePath), { recursive: true });
|
|
875
|
+
const file = files[filePath];
|
|
876
|
+
if (file.type === "text") {
|
|
877
|
+
await promises.writeFile(fullFilePath, file.content);
|
|
878
|
+
} else {
|
|
879
|
+
const response = await undici.fetch(file.url);
|
|
880
|
+
await promises.writeFile(fullFilePath, response.body);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
s.stop(color__default.green.inverse(` \u2713 Package created at ${packagePath}! `));
|
|
884
|
+
const addAnother = await p__namespace.select({
|
|
885
|
+
message: "Add another package?",
|
|
886
|
+
options: [
|
|
887
|
+
{ value: "no", label: "No, I'm done" },
|
|
888
|
+
{ value: "yes", label: "Yes, add another" }
|
|
889
|
+
],
|
|
890
|
+
initialValue: "no"
|
|
891
|
+
});
|
|
892
|
+
return !p__namespace.isCancel(addAnother) && addAnother === "yes";
|
|
893
|
+
} catch (error) {
|
|
894
|
+
s.stop("Failed to create package");
|
|
895
|
+
p__namespace.log.error(String(error));
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
404
898
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const isWindows = process.platform === "win32";
|
|
413
|
-
const useReuseFlag = reuseWindow && (editor === "cursor" || editor === "code");
|
|
414
|
-
const args = useReuseFlag ? ["-r", path] : [path];
|
|
415
|
-
const child = isWindows ? child_process.spawn(`${editor} ${useReuseFlag ? "-r " : ""}"${path}"`, {
|
|
416
|
-
detached: true,
|
|
417
|
-
stdio: "ignore",
|
|
418
|
-
shell: true
|
|
419
|
-
}) : child_process.spawn(editor, args, {
|
|
420
|
-
detached: true,
|
|
421
|
-
stdio: "ignore"
|
|
899
|
+
async function promptAndOpenEditor(basePath) {
|
|
900
|
+
const savedEditor = getPreferredEditor();
|
|
901
|
+
let selectedEditor;
|
|
902
|
+
if (savedEditor && savedEditor !== "skip") {
|
|
903
|
+
const useDefault = await p__namespace.confirm({
|
|
904
|
+
message: `Open in editor? ${color__default.dim(`(${editorNames[savedEditor]})`)}`,
|
|
905
|
+
initialValue: true
|
|
422
906
|
});
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
907
|
+
if (p__namespace.isCancel(useDefault)) {
|
|
908
|
+
selectedEditor = void 0;
|
|
909
|
+
} else if (useDefault) {
|
|
910
|
+
selectedEditor = savedEditor;
|
|
911
|
+
} else {
|
|
912
|
+
selectedEditor = "skip";
|
|
913
|
+
}
|
|
914
|
+
} else {
|
|
915
|
+
const openEditor = await p__namespace.select({
|
|
916
|
+
message: "Open project in editor?",
|
|
917
|
+
options: [
|
|
918
|
+
{ value: "skip", label: "Skip" },
|
|
919
|
+
{ value: "cursor", label: "Cursor" },
|
|
920
|
+
{ value: "code", label: "VS Code" },
|
|
921
|
+
{ value: "webstorm", label: "WebStorm" }
|
|
922
|
+
],
|
|
923
|
+
initialValue: "skip"
|
|
924
|
+
});
|
|
925
|
+
if (!p__namespace.isCancel(openEditor)) {
|
|
926
|
+
selectedEditor = openEditor;
|
|
927
|
+
const saveChoice = await p__namespace.confirm({
|
|
928
|
+
message: `Save ${editorNames[selectedEditor] ?? "Skip"} as default editor?`,
|
|
929
|
+
initialValue: true
|
|
930
|
+
});
|
|
931
|
+
if (!p__namespace.isCancel(saveChoice) && saveChoice) {
|
|
932
|
+
setPreferredEditor(selectedEditor);
|
|
933
|
+
if (selectedEditor === "cursor" || selectedEditor === "code") {
|
|
934
|
+
const reuseChoice = await p__namespace.confirm({
|
|
935
|
+
message: "Reuse current window when opening projects?",
|
|
936
|
+
initialValue: false
|
|
937
|
+
});
|
|
938
|
+
if (!p__namespace.isCancel(reuseChoice)) {
|
|
939
|
+
setReuseWindow(reuseChoice);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
if (selectedEditor && selectedEditor !== "skip") {
|
|
946
|
+
try {
|
|
947
|
+
await openInEditor(
|
|
948
|
+
selectedEditor,
|
|
949
|
+
basePath,
|
|
950
|
+
getReuseWindow()
|
|
951
|
+
);
|
|
952
|
+
p__namespace.log.success(`Opening in ${editorNames[selectedEditor]}...`);
|
|
953
|
+
} catch {
|
|
954
|
+
p__namespace.log.warn(
|
|
955
|
+
`Could not open ${editorNames[selectedEditor]}. Make sure the CLI command is in your PATH.`
|
|
956
|
+
);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
427
959
|
}
|
|
428
960
|
async function main() {
|
|
429
|
-
const program = new commander.Command().name("create-krispya").description(
|
|
430
|
-
"CLI for creating Vanilla, React, and React Three Fiber projects"
|
|
431
|
-
).argument("[name]", "name for the project").option(
|
|
432
|
-
"--type <type>",
|
|
433
|
-
"project type: app or library (default: app)"
|
|
434
|
-
).option(
|
|
961
|
+
const program = new commander.Command().name("create-krispya").description("CLI for creating Vanilla, React, and React Three Fiber projects").argument("[name]", "name for the project").option("--type <type>", "project type: app or library (default: app)").option(
|
|
435
962
|
"--bundler <bundler>",
|
|
436
963
|
"library bundler: unbuild or tsdown (default: unbuild, only for libraries)"
|
|
437
964
|
).option(
|
|
438
965
|
"--template <type>",
|
|
439
966
|
"project template: vanilla, vanilla-js, react, react-js, r3f, r3f-js (default: vanilla)"
|
|
440
|
-
).option(
|
|
441
|
-
"--linter <type>",
|
|
442
|
-
"linter: eslint, oxlint, or biome (default: oxlint)"
|
|
443
|
-
).option(
|
|
444
|
-
"--formatter <type>",
|
|
445
|
-
"formatter: prettier, oxfmt, or biome (default: oxfmt)"
|
|
446
|
-
).option("--drei", "add @react-three/drei (r3f only)").option("--handle", "add @react-three/handle (r3f only)").option("--leva", "add leva (r3f only)").option("--postprocessing", "add @react-three/postprocessing (r3f only)").option("--rapier", "add @react-three/rapier (r3f only)").option("--xr", "add @react-three/xr (r3f only)").option("--uikit", "add @react-three/uikit (r3f only)").option("--offscreen", "add @react-three/offscreen (r3f only)").option("--zustand", "add zustand (r3f only)").option("--koota", "add koota (r3f only)").option("--triplex", "set up triplex development environment (r3f only)").option("--viverse", "set up viverse deployment (r3f only)").option(
|
|
447
|
-
"--package-manager <manager>",
|
|
448
|
-
"specify package manager (e.g. npm, yarn, pnpm)"
|
|
449
|
-
).option(
|
|
967
|
+
).option("--linter <type>", "linter: eslint, oxlint, or biome (default: oxlint)").option("--formatter <type>", "formatter: prettier, oxfmt, or biome (default: oxfmt)").option("--drei", "add @react-three/drei (r3f only)").option("--handle", "add @react-three/handle (r3f only)").option("--leva", "add leva (r3f only)").option("--postprocessing", "add @react-three/postprocessing (r3f only)").option("--rapier", "add @react-three/rapier (r3f only)").option("--xr", "add @react-three/xr (r3f only)").option("--uikit", "add @react-three/uikit (r3f only)").option("--offscreen", "add @react-three/offscreen (r3f only)").option("--zustand", "add zustand (r3f only)").option("--koota", "add koota (r3f only)").option("--triplex", "set up triplex development environment (r3f only)").option("--viverse", "set up viverse deployment (r3f only)").option("--package-manager <manager>", "specify package manager (e.g. npm, yarn, pnpm)").option(
|
|
450
968
|
"--pnpm-manage-versions",
|
|
451
969
|
"enable manage-package-manager-versions in pnpm-workspace.yaml (default: true)"
|
|
452
970
|
).option(
|
|
@@ -455,14 +973,55 @@ async function main() {
|
|
|
455
973
|
).option(
|
|
456
974
|
"--node-version <version>",
|
|
457
975
|
'set Node.js version for engines.node field (default: "latest")'
|
|
458
|
-
).option("-y, --yes", "Skip prompts and use default values").option("--clear-config", "Clear saved preferences (e.g. editor choice)").action(async (name, options) => {
|
|
976
|
+
).option("-y, --yes", "Skip prompts and use default values").option("--clear-config", "Clear saved preferences (e.g. editor choice)").option("--config-path", "Print the path to the config file").action(async (name, options) => {
|
|
459
977
|
if (options.clearConfig) {
|
|
460
978
|
clearConfig();
|
|
461
979
|
console.log("Configuration cleared.");
|
|
462
980
|
process.exit(0);
|
|
463
981
|
}
|
|
982
|
+
if (options.configPath) {
|
|
983
|
+
console.log(getConfigPath());
|
|
984
|
+
process.exit(0);
|
|
985
|
+
}
|
|
464
986
|
console.clear();
|
|
465
987
|
p__namespace.intro(color__default.bgCyan(color__default.black(` create-krispya v${pkg.version} `)));
|
|
988
|
+
const monorepoRoot = await detectMonorepoRoot();
|
|
989
|
+
if (monorepoRoot && Object.keys(options).length === 0) {
|
|
990
|
+
const choice = await p__namespace.select({
|
|
991
|
+
message: "Detected monorepo workspace",
|
|
992
|
+
options: [
|
|
993
|
+
{ value: "add", label: "Add new package to this workspace" },
|
|
994
|
+
{ value: "standalone", label: "Create standalone project" }
|
|
995
|
+
],
|
|
996
|
+
initialValue: "add"
|
|
997
|
+
});
|
|
998
|
+
if (p__namespace.isCancel(choice)) {
|
|
999
|
+
p__namespace.cancel("Operation cancelled.");
|
|
1000
|
+
process.exit(0);
|
|
1001
|
+
}
|
|
1002
|
+
if (choice === "add") {
|
|
1003
|
+
const inheritedTooling = await detectWorkspaceTooling(monorepoRoot);
|
|
1004
|
+
if (inheritedTooling.linter || inheritedTooling.formatter) {
|
|
1005
|
+
const toolingInfo = [
|
|
1006
|
+
inheritedTooling.linter && `linter: ${inheritedTooling.linter}`,
|
|
1007
|
+
inheritedTooling.formatter && `formatter: ${inheritedTooling.formatter}`
|
|
1008
|
+
].filter(Boolean).join(", ");
|
|
1009
|
+
p__namespace.log.info(`Using workspace tooling (${toolingInfo})`);
|
|
1010
|
+
}
|
|
1011
|
+
const scope = await getMonorepoScope(monorepoRoot);
|
|
1012
|
+
let addMore = true;
|
|
1013
|
+
while (addMore) {
|
|
1014
|
+
addMore = await createPackageInWorkspace(monorepoRoot, "pnpm", inheritedTooling, scope);
|
|
1015
|
+
}
|
|
1016
|
+
p__namespace.note(
|
|
1017
|
+
[`cd ${monorepoRoot}`, "pnpm install", "pnpm run dev"].join("\n"),
|
|
1018
|
+
"Next steps"
|
|
1019
|
+
);
|
|
1020
|
+
await promptAndOpenEditor(monorepoRoot);
|
|
1021
|
+
p__namespace.outro(color__default.green("Happy coding! \u2728"));
|
|
1022
|
+
process.exit(0);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
466
1025
|
let generateOptions;
|
|
467
1026
|
if (Object.keys(options).length > 0) {
|
|
468
1027
|
const template = options.template ?? "vanilla";
|
|
@@ -497,6 +1056,63 @@ async function main() {
|
|
|
497
1056
|
} else {
|
|
498
1057
|
generateOptions = await promptForOptions(name);
|
|
499
1058
|
}
|
|
1059
|
+
if (generateOptions.projectType === "monorepo") {
|
|
1060
|
+
const { generateMonorepo } = await import('./chunks/index.cjs').then(function (n) { return n.monorepo; });
|
|
1061
|
+
const packageManager2 = generateOptions.packageManager || "pnpm";
|
|
1062
|
+
if (packageManager2 === "pnpm") {
|
|
1063
|
+
generateOptions.pnpmVersion = await index.getLatestPnpmVersion();
|
|
1064
|
+
}
|
|
1065
|
+
const nodeVersion2 = generateOptions.nodeVersion ?? "latest";
|
|
1066
|
+
if (nodeVersion2 === "latest") {
|
|
1067
|
+
generateOptions.nodeVersion = await index.getLatestNodeVersion();
|
|
1068
|
+
}
|
|
1069
|
+
const basePath2 = path.join(process$1.cwd(), generateOptions.name);
|
|
1070
|
+
const s2 = p__namespace.spinner();
|
|
1071
|
+
s2.start("Creating monorepo workspace...");
|
|
1072
|
+
try {
|
|
1073
|
+
const { files } = generateMonorepo({
|
|
1074
|
+
name: generateOptions.name,
|
|
1075
|
+
linter: generateOptions.linter ?? "oxlint",
|
|
1076
|
+
formatter: generateOptions.formatter ?? "oxfmt",
|
|
1077
|
+
packageManager: packageManager2,
|
|
1078
|
+
pnpmVersion: generateOptions.pnpmVersion,
|
|
1079
|
+
pnpmManageVersions: generateOptions.pnpmManageVersions,
|
|
1080
|
+
nodeVersion: generateOptions.nodeVersion
|
|
1081
|
+
});
|
|
1082
|
+
const filePaths = Object.keys(files).sort();
|
|
1083
|
+
for (const filePath of filePaths) {
|
|
1084
|
+
const fullFilePath = path.join(basePath2, filePath);
|
|
1085
|
+
await promises.mkdir(path.dirname(fullFilePath), { recursive: true });
|
|
1086
|
+
const file = files[filePath];
|
|
1087
|
+
if (file.type === "text") {
|
|
1088
|
+
await promises.writeFile(fullFilePath, file.content);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
s2.stop(color__default.green.inverse(" \u2713 Monorepo workspace created! "));
|
|
1092
|
+
const newMonorepoTooling = {
|
|
1093
|
+
linter: generateOptions.linter,
|
|
1094
|
+
formatter: generateOptions.formatter
|
|
1095
|
+
};
|
|
1096
|
+
const scope = generateOptions.name;
|
|
1097
|
+
let addMore = true;
|
|
1098
|
+
while (addMore) {
|
|
1099
|
+
addMore = await createPackageInWorkspace(basePath2, packageManager2, newMonorepoTooling, scope);
|
|
1100
|
+
}
|
|
1101
|
+
const nextSteps = [
|
|
1102
|
+
`cd ${generateOptions.name}`,
|
|
1103
|
+
`${packageManager2} install`,
|
|
1104
|
+
`${packageManager2} run dev`
|
|
1105
|
+
].join("\n");
|
|
1106
|
+
p__namespace.note(nextSteps, "Next steps");
|
|
1107
|
+
await promptAndOpenEditor(basePath2);
|
|
1108
|
+
p__namespace.outro(color__default.green("Happy coding! \u2728"));
|
|
1109
|
+
process.exit(0);
|
|
1110
|
+
} catch (error) {
|
|
1111
|
+
s2.stop("Failed to create monorepo workspace");
|
|
1112
|
+
p__namespace.log.error(String(error));
|
|
1113
|
+
process.exit(1);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
500
1116
|
const base = generateOptions.template ? index.getBaseTemplate(generateOptions.template) : "vanilla";
|
|
501
1117
|
const defaultFallbackName = base === "vanilla" ? "vanilla-app" : base === "react" ? "react-app" : "react-three-app";
|
|
502
1118
|
generateOptions.name ??= defaultFallbackName;
|
|
@@ -509,12 +1125,17 @@ async function main() {
|
|
|
509
1125
|
generateOptions.nodeVersion = await index.getLatestNodeVersion();
|
|
510
1126
|
}
|
|
511
1127
|
const versions = {};
|
|
512
|
-
const versionPromises = [
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
1128
|
+
const versionPromises = [];
|
|
1129
|
+
const isLibrary = generateOptions.projectType === "library";
|
|
1130
|
+
const testing = generateOptions.testing ?? (isLibrary ? "vitest" : "none");
|
|
1131
|
+
if (testing === "vitest") {
|
|
1132
|
+
versionPromises.push(
|
|
1133
|
+
index.getLatestNpmVersion("vitest", "4.0.0").then((v) => {
|
|
1134
|
+
versions.vitest = v;
|
|
1135
|
+
})
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
if (!isLibrary) {
|
|
518
1139
|
versionPromises.push(
|
|
519
1140
|
index.getLatestNpmVersion("vite", "6.3.4").then((v) => {
|
|
520
1141
|
versions.vite = v;
|
|
@@ -580,9 +1201,9 @@ async function main() {
|
|
|
580
1201
|
await promises.writeFile(fullFilePath, response.body);
|
|
581
1202
|
}
|
|
582
1203
|
}
|
|
583
|
-
s.stop("Project created!");
|
|
584
|
-
const
|
|
585
|
-
const nextSteps =
|
|
1204
|
+
s.stop(color__default.green.inverse(" \u2713 Project created! "));
|
|
1205
|
+
const isLibrary2 = generateOptions.projectType === "library";
|
|
1206
|
+
const nextSteps = isLibrary2 ? [
|
|
586
1207
|
`cd ${generateOptions.name}`,
|
|
587
1208
|
`${packageManager} install`,
|
|
588
1209
|
`${packageManager} run build`
|