@mayrlabs/setup-project 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -65,34 +65,152 @@ var init_pm = __esm({
65
65
  }
66
66
  });
67
67
 
68
- // src/services/husky.ts
69
- import { select, text } from "@clack/prompts";
70
- import { execa as execa2 } from "execa";
71
- import fs from "fs-extra";
72
- async function promptHusky(config) {
73
- const hookType = await select({
74
- message: "What pre-commit hook would you like to use?",
75
- options: [
68
+ // src/constants/options.ts
69
+ var TOOL_OPTIONS, HUSKY_HOOK_OPTIONS, FORMATTER_OPTIONS, LINTER_OPTIONS, LINT_STAGED_EXTENSIONS, ENV_VARIANT_OPTIONS, ENV_VALIDATOR_OPTIONS, ENV_PRESET_OPTIONS, ENV_SPLIT_OPTIONS, TEST_RUNNER_OPTIONS, EDITOR_CONFIG_OPTIONS, LICENSE_TYPE_OPTIONS;
70
+ var init_options = __esm({
71
+ "src/constants/options.ts"() {
72
+ "use strict";
73
+ init_esm_shims();
74
+ TOOL_OPTIONS = [
75
+ { value: "husky", label: "Husky" },
76
+ { value: "formatter", label: "Formatter (Prettier/Oxfmt)" },
77
+ { value: "linter", label: "Linter (Eslint/Oxlint)" },
78
+ { value: "lint-staged", label: "Lint-staged" },
79
+ { value: "env", label: "Env Validation (@t3-oss/env)" },
80
+ { value: "test", label: "Test Runner (Vitest/Jest)" },
81
+ { value: "editorConfig", label: "EditorConfig" },
82
+ { value: "license", label: "License" }
83
+ ];
84
+ HUSKY_HOOK_OPTIONS = [
76
85
  { value: "lint-staged", label: "lint-staged" },
77
86
  { value: "custom", label: "Custom script" },
78
87
  { value: "none", label: "None" }
79
- ]
80
- });
81
- config.huskyHookType = hookType;
88
+ ];
89
+ FORMATTER_OPTIONS = [
90
+ { value: "prettier", label: "Prettier" },
91
+ { value: "oxfmt", label: "Oxfmt" }
92
+ ];
93
+ LINTER_OPTIONS = [
94
+ { value: "eslint", label: "ESLint" },
95
+ { value: "oxlint", label: "Oxlint" }
96
+ ];
97
+ LINT_STAGED_EXTENSIONS = [
98
+ { value: "js", label: "js" },
99
+ { value: "ts", label: "ts" },
100
+ { value: "jsx", label: "jsx" },
101
+ { value: "tsx", label: "tsx" },
102
+ { value: "html", label: "html" },
103
+ { value: "vue", label: "vue" },
104
+ { value: "svelte", label: "svelte" },
105
+ { value: "css", label: "css" },
106
+ { value: "scss", label: "scss" },
107
+ { value: "json", label: "json" },
108
+ { value: "yaml", label: "yaml" },
109
+ { value: "md", label: "md" }
110
+ ];
111
+ ENV_VARIANT_OPTIONS = [
112
+ { value: "@t3-oss/env-nextjs", label: "Next.js" },
113
+ { value: "@t3-oss/env-nuxt", label: "Nuxt" },
114
+ { value: "@t3-oss/env-core", label: "Core" }
115
+ ];
116
+ ENV_VALIDATOR_OPTIONS = [
117
+ { value: "zod", label: "Zod" },
118
+ { value: "valibot", label: "Valibot" },
119
+ { value: "arktype", label: "Arktype" }
120
+ ];
121
+ ENV_PRESET_OPTIONS = [
122
+ { value: "netlify", label: "Netlify" },
123
+ { value: "vercel", label: "Vercel" },
124
+ { value: "neonVercel", label: "Neon (Vercel)" },
125
+ { value: "supabaseVercel", label: "Supabase (Vercel)" },
126
+ { value: "uploadThing", label: "UploadThing" },
127
+ { value: "render", label: "Render" },
128
+ { value: "railway", label: "Railway" },
129
+ { value: "fly.io", label: "Fly.io" },
130
+ { value: "upstashRedis", label: "Upstash Redis" },
131
+ { value: "coolify", label: "Coolify" },
132
+ { value: "vite", label: "Vite" },
133
+ { value: "wxt", label: "WXT" }
134
+ ];
135
+ ENV_SPLIT_OPTIONS = [
136
+ { value: "split", label: "Split (env/server.ts, env/client.ts)" },
137
+ { value: "joined", label: "Joined (env.ts)" }
138
+ ];
139
+ TEST_RUNNER_OPTIONS = [
140
+ { value: "vitest", label: "Vitest" },
141
+ { value: "jest", label: "Jest" }
142
+ ];
143
+ EDITOR_CONFIG_OPTIONS = [
144
+ { value: "default", label: "Default (Spaces 2)" },
145
+ { value: "spaces4", label: "Spaces 4" },
146
+ { value: "tabs", label: "Tabs" }
147
+ ];
148
+ LICENSE_TYPE_OPTIONS = [
149
+ { value: "MIT", label: "MIT" },
150
+ { value: "ISC", label: "ISC" },
151
+ { value: "Apache-2.0", label: "Apache 2.0" },
152
+ { value: "UNLICENSED", label: "UNLICENSED" }
153
+ ];
154
+ }
155
+ });
156
+
157
+ // src/utils/handle-cancel.ts
158
+ import { cancel, isCancel, confirm } from "@clack/prompts";
159
+ async function withCancelHandling(promptFn, cancelMessage = "Operation cancelled.") {
160
+ while (true) {
161
+ const response = await promptFn();
162
+ if (isCancel(response)) {
163
+ const shouldCancel = await confirm({
164
+ message: "Do you really want to cancel options selection?"
165
+ });
166
+ if (isCancel(shouldCancel) || shouldCancel) {
167
+ cancel(cancelMessage);
168
+ process.exit(0);
169
+ }
170
+ continue;
171
+ } else {
172
+ return response;
173
+ }
174
+ }
175
+ }
176
+ var init_handle_cancel = __esm({
177
+ "src/utils/handle-cancel.ts"() {
178
+ "use strict";
179
+ init_esm_shims();
180
+ }
181
+ });
182
+
183
+ // src/services/husky.ts
184
+ import { select, log, text } from "@clack/prompts";
185
+ import { execa as execa2 } from "execa";
186
+ import fs from "fs-extra";
187
+ import pc from "picocolors";
188
+ async function promptHusky(config2) {
189
+ log.message(pc.bgMagenta(pc.black(" Husky Configuration ")));
190
+ const hookType = await withCancelHandling(
191
+ async () => select({
192
+ message: "What pre-commit hook would you like to use?",
193
+ options: HUSKY_HOOK_OPTIONS
194
+ })
195
+ );
196
+ const huskyConfig = config2.get("husky");
197
+ huskyConfig.options = { hookType };
82
198
  if (hookType === "lint-staged") {
83
- config.lintStaged = true;
199
+ config2.enableTool("lintStaged");
84
200
  } else if (hookType === "custom") {
85
- const script = await text({
86
- message: "Enter your custom pre-commit script:",
87
- placeholder: "npm test",
88
- validate(value) {
89
- if (value.length === 0) return "Value is required!";
90
- }
91
- });
92
- config.huskyCustomScript = script;
201
+ const script = await withCancelHandling(
202
+ async () => text({
203
+ message: "Enter your custom pre-commit script:",
204
+ placeholder: huskyConfig.options.customScript,
205
+ validate(value) {
206
+ if (value.length === 0) return "Value is required!";
207
+ }
208
+ })
209
+ );
210
+ huskyConfig.options.customScript = script;
93
211
  }
94
212
  }
95
- async function installHusky(config) {
213
+ async function installHusky(config2) {
96
214
  await installPackages(["husky"], true);
97
215
  try {
98
216
  await execa2("npx", ["husky", "init"]);
@@ -100,12 +218,15 @@ async function installHusky(config) {
100
218
  await execa2("npm", ["pkg", "set", "scripts.prepare=husky"]);
101
219
  await execa2("npm", ["run", "prepare"]);
102
220
  }
103
- if (config.huskyHookType === "lint-staged") {
221
+ const husky = config2.get("husky");
222
+ const hookType = husky.options.hookType;
223
+ const customScript = husky.options.customScript;
224
+ if (hookType === "lint-staged") {
104
225
  await fs.outputFile(".husky/pre-commit", "npx lint-staged\n", {
105
226
  mode: 493
106
227
  });
107
- } else if (config.huskyHookType === "custom" && config.huskyCustomScript) {
108
- await fs.outputFile(".husky/pre-commit", `${config.huskyCustomScript}
228
+ } else if (hookType === "custom" && customScript) {
229
+ await fs.outputFile(".husky/pre-commit", `${customScript}
109
230
  `, {
110
231
  mode: 493
111
232
  });
@@ -116,26 +237,30 @@ var init_husky = __esm({
116
237
  "use strict";
117
238
  init_esm_shims();
118
239
  init_pm();
240
+ init_options();
241
+ init_handle_cancel();
119
242
  }
120
243
  });
121
244
 
122
245
  // src/services/formatter.ts
123
- import { select as select2 } from "@clack/prompts";
246
+ import { select as select2, log as log2 } from "@clack/prompts";
124
247
  import fs2 from "fs-extra";
125
- async function promptFormatter(config) {
126
- if (!config.formatterChoice) {
127
- const formatter = await select2({
248
+ import pc2 from "picocolors";
249
+ async function promptFormatter(config2) {
250
+ const formatterConfig = config2.get("formatter");
251
+ log2.message(pc2.bgBlue(pc2.black(" Formatter Configuration ")));
252
+ const formatter = await withCancelHandling(
253
+ async () => select2({
128
254
  message: "Select a formatter:",
129
- options: [
130
- { value: "prettier", label: "Prettier" },
131
- { value: "oxfmt", label: "Oxfmt" }
132
- ]
133
- });
134
- config.formatterChoice = formatter;
135
- }
255
+ options: FORMATTER_OPTIONS,
256
+ initialValue: formatterConfig.options.choice
257
+ })
258
+ );
259
+ formatterConfig.options = { choice: formatter };
136
260
  }
137
- async function installFormatter(config) {
138
- if (config.formatterChoice === "prettier") {
261
+ async function installFormatter(config2) {
262
+ const choice = config2.get("formatter").options.choice;
263
+ if (choice === "prettier") {
139
264
  await installPackages(["prettier"], true);
140
265
  const configContent = {
141
266
  semi: true,
@@ -145,7 +270,7 @@ async function installFormatter(config) {
145
270
  tabWidth: 2
146
271
  };
147
272
  await fs2.writeJson(".prettierrc", configContent, { spaces: 2 });
148
- } else if (config.formatterChoice === "oxfmt") {
273
+ } else if (choice === "oxfmt") {
149
274
  await installPackages(["oxfmt"], true);
150
275
  }
151
276
  }
@@ -154,26 +279,30 @@ var init_formatter = __esm({
154
279
  "use strict";
155
280
  init_esm_shims();
156
281
  init_pm();
282
+ init_options();
283
+ init_handle_cancel();
157
284
  }
158
285
  });
159
286
 
160
287
  // src/services/linter.ts
161
- import { select as select3 } from "@clack/prompts";
288
+ import { select as select3, log as log3 } from "@clack/prompts";
162
289
  import fs3 from "fs-extra";
163
- async function promptLinter(config) {
164
- if (!config.linterChoice) {
165
- const linter = await select3({
290
+ import pc3 from "picocolors";
291
+ async function promptLinter(config2) {
292
+ const linterConfig = config2.get("linter");
293
+ log3.message(pc3.bgYellow(pc3.black(" Linter Configuration ")));
294
+ const linter = await withCancelHandling(
295
+ async () => select3({
166
296
  message: "Select a linter:",
167
- options: [
168
- { value: "eslint", label: "ESLint" },
169
- { value: "oxlint", label: "Oxlint" }
170
- ]
171
- });
172
- config.linterChoice = linter;
173
- }
297
+ options: LINTER_OPTIONS,
298
+ initialValue: linterConfig.options.choice
299
+ })
300
+ );
301
+ linterConfig.options = { choice: linter };
174
302
  }
175
- async function installLinter(config) {
176
- if (config.linterChoice === "eslint") {
303
+ async function installLinter(config2) {
304
+ const choice = config2.get("linter").options.choice;
305
+ if (choice === "eslint") {
177
306
  await installPackages(["eslint"], true);
178
307
  const configContent = {
179
308
  extends: ["eslint:recommended"],
@@ -187,7 +316,7 @@ async function installLinter(config) {
187
316
  }
188
317
  };
189
318
  await fs3.writeJson(".eslintrc.json", configContent, { spaces: 2 });
190
- } else if (config.linterChoice === "oxlint") {
319
+ } else if (choice === "oxlint") {
191
320
  await installPackages(["oxlint"], true);
192
321
  }
193
322
  }
@@ -196,73 +325,63 @@ var init_linter = __esm({
196
325
  "use strict";
197
326
  init_esm_shims();
198
327
  init_pm();
328
+ init_options();
329
+ init_handle_cancel();
199
330
  }
200
331
  });
201
332
 
202
333
  // src/services/lint-staged.ts
203
- import { multiselect } from "@clack/prompts";
334
+ import { multiselect, log as log4 } from "@clack/prompts";
204
335
  import fs4 from "fs-extra";
205
- async function promptLintStaged(config) {
206
- const lintExtensions = await multiselect({
207
- message: "Select extensions to lint:",
208
- options: [
209
- { value: "js", label: "js" },
210
- { value: "ts", label: "ts" },
211
- { value: "jsx", label: "jsx" },
212
- { value: "tsx", label: "tsx" },
213
- { value: "html", label: "html" },
214
- { value: "vue", label: "vue" },
215
- { value: "svelte", label: "svelte" }
216
- ],
217
- required: false
218
- });
219
- const formatExtensions = await multiselect({
220
- message: "Select extensions to format:",
221
- options: [
222
- { value: "md", label: "md" },
223
- { value: "css", label: "css" },
224
- { value: "scss", label: "scss" },
225
- { value: "json", label: "json" },
226
- { value: "yaml", label: "yaml" },
227
- { value: "html", label: "html" },
228
- { value: "js", label: "js" },
229
- { value: "ts", label: "ts" },
230
- { value: "jsx", label: "jsx" },
231
- { value: "tsx", label: "tsx" },
232
- { value: "vue", label: "vue" },
233
- { value: "svelte", label: "svelte" }
234
- ],
235
- required: false
236
- });
237
- config.lintStagedLintExtensions = lintExtensions;
238
- config.lintStagedFormatExtensions = formatExtensions;
239
- if (lintExtensions.length > 0 && !config.linterChoice) {
240
- await promptLinter(config);
241
- config.linter = true;
242
- }
243
- if (formatExtensions.length > 0 && !config.formatterChoice) {
244
- await promptFormatter(config);
245
- config.formatter = true;
336
+ import pc4 from "picocolors";
337
+ async function promptLintStaged(config2) {
338
+ log4.message(pc4.bgGreen(pc4.black(" Lint-staged Configuration ")));
339
+ const lintExtensions = await withCancelHandling(
340
+ async () => multiselect({
341
+ message: "Select extensions to lint:",
342
+ options: LINT_STAGED_EXTENSIONS,
343
+ required: false
344
+ })
345
+ );
346
+ const formatExtensions = await withCancelHandling(
347
+ async () => multiselect({
348
+ message: "Select extensions to format:",
349
+ options: LINT_STAGED_EXTENSIONS,
350
+ required: false
351
+ })
352
+ );
353
+ config2.get("lintStaged").options = {
354
+ lintExtensions,
355
+ formatExtensions
356
+ };
357
+ if (lintExtensions.length > 0 && !config2.get("linter").selected) {
358
+ await promptLinter(config2);
359
+ config2.enableTool("linter");
360
+ }
361
+ if (formatExtensions.length > 0 && !config2.get("formatter").selected) {
362
+ await promptFormatter(config2);
363
+ config2.enableTool("formatter");
246
364
  }
247
365
  }
248
- async function installLintStaged(config) {
366
+ async function installLintStaged(config2) {
249
367
  await installPackages(["lint-staged"], true);
250
368
  const lintStagedConfig = {};
251
- const lintExts = config.lintStagedLintExtensions || [];
252
- const formatExts = config.lintStagedFormatExtensions || [];
369
+ const lintStagedOptions = config2.get("lintStaged").options;
370
+ const lintExts = lintStagedOptions?.lintExtensions || [];
371
+ const formatExts = lintStagedOptions?.formatExtensions || [];
253
372
  if (lintExts.length > 0) {
254
- await installLinter(config);
373
+ await installLinter(config2);
255
374
  const glob = `*.{${lintExts.join(",")}}`;
256
- if (config.linterChoice === "oxlint") {
375
+ if (config2.get("linter").options.choice === "oxlint") {
257
376
  lintStagedConfig[glob] = ["npx oxlint --fix"];
258
377
  } else {
259
378
  lintStagedConfig[glob] = ["eslint --fix"];
260
379
  }
261
380
  }
262
381
  if (formatExts.length > 0) {
263
- await installFormatter(config);
382
+ await installFormatter(config2);
264
383
  const glob = `*.{${formatExts.join(",")}}`;
265
- if (config.formatterChoice === "oxfmt") {
384
+ if (config2.get("formatter").options.choice === "oxfmt") {
266
385
  lintStagedConfig[glob] = ["npx oxfmt"];
267
386
  } else {
268
387
  lintStagedConfig[glob] = ["prettier --write"];
@@ -277,89 +396,81 @@ var init_lint_staged = __esm({
277
396
  init_pm();
278
397
  init_formatter();
279
398
  init_linter();
399
+ init_options();
400
+ init_handle_cancel();
280
401
  }
281
402
  });
282
403
 
283
404
  // src/services/env.ts
284
- import { select as select5, confirm, text as text2, multiselect as multiselect2 } from "@clack/prompts";
405
+ import { select as select4, confirm as confirm2, text as text2, multiselect as multiselect2, log as log5 } from "@clack/prompts";
285
406
  import fs5 from "fs-extra";
286
407
  import path2 from "path";
287
- async function promptEnv(config) {
288
- const variant = await select5({
289
- message: "Which @t3-oss/env variant?",
290
- options: [
291
- { value: "@t3-oss/env-nextjs", label: "Next.js" },
292
- { value: "@t3-oss/env-nuxt", label: "Nuxt" },
293
- { value: "@t3-oss/env-core", label: "Core" }
294
- ]
295
- });
296
- config.envVariant = variant;
297
- const validator = await select5({
298
- message: "Which validator?",
299
- options: [
300
- { value: "zod", label: "Zod" },
301
- { value: "valibot", label: "Valibot" },
302
- { value: "arktype", label: "Arktype" }
303
- ]
304
- });
305
- config.envValidator = validator;
306
- const installPresets = await confirm({
307
- message: "Install presets?"
308
- });
309
- config.envInstallPresets = installPresets;
408
+ import pc5 from "picocolors";
409
+ async function promptEnv(config2) {
410
+ log5.message(pc5.bgCyan(pc5.black(" Env Validation Configuration ")));
411
+ const variant = await withCancelHandling(
412
+ async () => select4({
413
+ message: "Which @t3-oss/env variant?",
414
+ options: ENV_VARIANT_OPTIONS
415
+ })
416
+ );
417
+ const validator = await withCancelHandling(
418
+ async () => select4({
419
+ message: "Which validator?",
420
+ options: ENV_VALIDATOR_OPTIONS
421
+ })
422
+ );
423
+ const installPresets = await withCancelHandling(
424
+ async () => confirm2({
425
+ message: "Install presets?"
426
+ })
427
+ );
428
+ let presets;
310
429
  if (installPresets) {
311
- const presets = await multiselect2({
312
- message: "Select preset to extend:",
313
- options: [
314
- { value: "netlify", label: "Netlify" },
315
- { value: "vercel", label: "Vercel" },
316
- { value: "neonVercel", label: "Neon (Vercel)" },
317
- { value: "supabaseVercel", label: "Supabase (Vercel)" },
318
- { value: "uploadThing", label: "UploadThing" },
319
- { value: "render", label: "Render" },
320
- { value: "railway", label: "Railway" },
321
- { value: "fly.io", label: "Fly.io" },
322
- { value: "upstashRedis", label: "Upstash Redis" },
323
- { value: "coolify", label: "Coolify" },
324
- { value: "vite", label: "Vite" },
325
- { value: "wxt", label: "WXT" }
326
- ],
327
- required: false
328
- });
329
- config.envPresets = presets;
430
+ presets = await withCancelHandling(
431
+ async () => multiselect2({
432
+ message: "Select preset to extend:",
433
+ options: ENV_PRESET_OPTIONS,
434
+ required: false
435
+ })
436
+ );
330
437
  }
331
- const split = await select5({
332
- message: "Split or Joined env files?",
333
- options: [
334
- { value: "split", label: "Split (env/server.ts, env/client.ts)" },
335
- { value: "joined", label: "Joined (env.ts)" }
336
- ]
337
- });
338
- config.envSplit = split;
339
- const location = await text2({
340
- message: "Where should the environment files be created?",
341
- initialValue: "src/lib",
342
- placeholder: "src/lib"
343
- });
344
- config.envLocation = location;
438
+ const split = await withCancelHandling(
439
+ async () => select4({
440
+ message: "Split or Joined env files?",
441
+ options: ENV_SPLIT_OPTIONS
442
+ })
443
+ );
444
+ const location = await withCancelHandling(
445
+ async () => text2({
446
+ message: "Where should the environment files be created?",
447
+ initialValue: config2.get("env").options.location || "src/lib",
448
+ placeholder: "src/lib"
449
+ })
450
+ );
451
+ config2.get("env").options = {
452
+ variant,
453
+ validator,
454
+ installPresets,
455
+ presets: presets || [],
456
+ split,
457
+ location
458
+ };
345
459
  }
346
- async function installEnv(config) {
347
- await installPackages([config.envVariant, config.envValidator], true);
348
- if (config.envInstallPresets) {
349
- const presetPackage = `@t3-oss/env-core/presets-${config.envValidator}`;
350
- await installPackages([presetPackage], true);
351
- }
352
- const targetDir = config.envLocation;
353
- await fs5.ensureDir(targetDir);
354
- const presetImport = config.envPresets && config.envPresets.length > 0 ? `// Presets: ${config.envPresets.join(", ")}
460
+ async function installEnv(config2) {
461
+ const envOptions = config2.get("env").options;
462
+ const { variant, validator, location, presets, split } = envOptions;
463
+ await installPackages([variant, validator], true);
464
+ await fs5.ensureDir(location);
465
+ const presetImport = presets && presets.length > 0 ? `// Presets: ${presets.join(", ")}
355
466
  ` : "";
356
- const content = `import { createEnv } from "${config.envVariant}";
357
- import { ${config.envValidator} } from "${config.envValidator}";
467
+ const content = `import { createEnv } from "${variant}";
468
+ import { ${validator} } from "${validator}";
358
469
 
359
470
  ${presetImport}`;
360
- if (config.envSplit === "split") {
471
+ if (split === "split") {
361
472
  await fs5.outputFile(
362
- path2.join(targetDir, "env/server.ts"),
473
+ path2.join(location, "env/server.ts"),
363
474
  `${content}
364
475
  // Server env definition
365
476
  export const env = createEnv({
@@ -370,7 +481,7 @@ export const env = createEnv({
370
481
  });`
371
482
  );
372
483
  await fs5.outputFile(
373
- path2.join(targetDir, "env/client.ts"),
484
+ path2.join(location, "env/client.ts"),
374
485
  `${content}
375
486
  // Client env definition
376
487
  export const env = createEnv({
@@ -384,7 +495,7 @@ export const env = createEnv({
384
495
  );
385
496
  } else {
386
497
  await fs5.outputFile(
387
- path2.join(targetDir, "env.ts"),
498
+ path2.join(location, "env.ts"),
388
499
  `${content}
389
500
  // Joined env definition
390
501
  export const env = createEnv({
@@ -406,24 +517,28 @@ var init_env = __esm({
406
517
  "use strict";
407
518
  init_esm_shims();
408
519
  init_pm();
520
+ init_options();
521
+ init_handle_cancel();
409
522
  }
410
523
  });
411
524
 
412
525
  // src/services/test.ts
413
- import { select as select6 } from "@clack/prompts";
526
+ import { select as select5, log as log6 } from "@clack/prompts";
414
527
  import fs6 from "fs-extra";
415
- async function promptTest(config) {
416
- const runner = await select6({
417
- message: "Select a test runner:",
418
- options: [
419
- { value: "vitest", label: "Vitest" },
420
- { value: "jest", label: "Jest" }
421
- ]
422
- });
423
- config.testRunner = runner;
528
+ import pc6 from "picocolors";
529
+ async function promptTest(config2) {
530
+ log6.message(pc6.bgRed(pc6.black(" Test Runner Configuration ")));
531
+ const runner = await withCancelHandling(
532
+ async () => select5({
533
+ message: "Select a test runner:",
534
+ options: TEST_RUNNER_OPTIONS
535
+ })
536
+ );
537
+ config2.get("test").options = { runner };
424
538
  }
425
- async function installTest(config) {
426
- if (config.testRunner === "vitest") {
539
+ async function installTest(config2) {
540
+ const runner = config2.get("test").options.runner;
541
+ if (runner === "vitest") {
427
542
  await installPackages(["vitest"], true);
428
543
  const configFile = "vitest.config.ts";
429
544
  if (!await fs6.pathExists(configFile)) {
@@ -439,7 +554,7 @@ export default defineConfig({
439
554
  `
440
555
  );
441
556
  }
442
- } else if (config.testRunner === "jest") {
557
+ } else if (runner === "jest") {
443
558
  await installPackages(["jest", "ts-jest", "@types/jest"], true);
444
559
  const configFile = "jest.config.js";
445
560
  if (!await fs6.pathExists(configFile)) {
@@ -460,30 +575,35 @@ var init_test = __esm({
460
575
  "use strict";
461
576
  init_esm_shims();
462
577
  init_pm();
578
+ init_options();
579
+ init_handle_cancel();
463
580
  }
464
581
  });
465
582
 
466
583
  // src/services/editor-config.ts
467
- import { select as select7 } from "@clack/prompts";
584
+ import { select as select6, log as log7 } from "@clack/prompts";
468
585
  import fs7 from "fs-extra";
469
- async function promptEditorConfig(config) {
470
- const preset = await select7({
471
- message: "Select EditorConfig preset:",
472
- options: [
473
- { value: "default", label: "Default (Spaces 2)" },
474
- { value: "spaces4", label: "Spaces 4" },
475
- { value: "tabs", label: "Tabs" }
476
- ]
477
- });
478
- config.editorConfigPreset = preset;
586
+ import pc7 from "picocolors";
587
+ async function promptEditorConfig(config2) {
588
+ log7.message(pc7.bgWhite(pc7.black(" EditorConfig Configuration ")));
589
+ const currentPreset = config2.get("editorConfig").options.preset;
590
+ const preset = await withCancelHandling(
591
+ async () => select6({
592
+ message: "Select EditorConfig preset:",
593
+ options: EDITOR_CONFIG_OPTIONS,
594
+ initialValue: currentPreset
595
+ })
596
+ );
597
+ config2.get("editorConfig").options = { preset };
479
598
  }
480
- async function installEditorConfig(config) {
599
+ async function installEditorConfig(config2) {
481
600
  let content = "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n";
482
- if (config.editorConfigPreset === "default" || config.editorConfigPreset === "spaces2") {
601
+ const preset = config2.get("editorConfig").options.preset;
602
+ if (preset === "default") {
483
603
  content += "indent_style = space\nindent_size = 2\n";
484
- } else if (config.editorConfigPreset === "spaces4") {
604
+ } else if (preset === "spaces4") {
485
605
  content += "indent_style = space\nindent_size = 4\n";
486
- } else if (config.editorConfigPreset === "tabs") {
606
+ } else if (preset === "tabs") {
487
607
  content += "indent_style = tab\n";
488
608
  }
489
609
  await fs7.outputFile(".editorconfig", content);
@@ -492,70 +612,71 @@ var init_editor_config = __esm({
492
612
  "src/services/editor-config.ts"() {
493
613
  "use strict";
494
614
  init_esm_shims();
615
+ init_options();
616
+ init_handle_cancel();
495
617
  }
496
618
  });
497
619
 
498
620
  // src/services/license.ts
499
- import { text as text3, select as select8 } from "@clack/prompts";
621
+ import { text as text3, select as select7, log as log8 } from "@clack/prompts";
500
622
  import fs8 from "fs-extra";
501
623
  import path3 from "path";
502
- async function promptLicense(config) {
503
- const name = await text3({
504
- message: "License Holder Name:",
505
- placeholder: "John Doe",
506
- initialValue: config.authorName || ""
507
- });
508
- config.licenseName = name;
509
- const email = await text3({
510
- message: "License Holder Email:",
511
- placeholder: "john@example.com"
512
- });
513
- config.licenseEmail = email;
514
- const website = await text3({
515
- message: "License Holder Website:",
516
- placeholder: "https://example.com"
517
- });
518
- config.licenseWebsite = website;
519
- const type = await select8({
520
- message: "Select License Type:",
521
- options: [
522
- { value: "MIT", label: "MIT" },
523
- { value: "ISC", label: "ISC" },
524
- { value: "Apache-2.0", label: "Apache 2.0" },
525
- { value: "UNLICENSED", label: "UNLICENSED" }
526
- ]
527
- });
528
- config.licenseType = type;
624
+ import pc8 from "picocolors";
625
+ async function promptLicense(config2) {
626
+ log8.message(pc8.bgGreen(pc8.black(" License Configuration ")));
627
+ const licenseOptions = config2.get("license").options;
628
+ licenseOptions.name = await withCancelHandling(
629
+ async () => text3({
630
+ message: "License Holder Name:",
631
+ placeholder: "John Doe",
632
+ initialValue: licenseOptions.name
633
+ })
634
+ );
635
+ licenseOptions.email = await withCancelHandling(
636
+ async () => text3({
637
+ message: "License Holder Email:",
638
+ placeholder: "john@example.com",
639
+ initialValue: licenseOptions.email
640
+ })
641
+ );
642
+ licenseOptions.website = await withCancelHandling(
643
+ async () => text3({
644
+ message: "License Holder Website:",
645
+ placeholder: "https://example.com",
646
+ initialValue: licenseOptions.website
647
+ })
648
+ );
649
+ licenseOptions.type = await withCancelHandling(
650
+ async () => select7({
651
+ message: "Select License Type:",
652
+ options: LICENSE_TYPE_OPTIONS
653
+ })
654
+ );
529
655
  }
530
- async function installLicense(config) {
531
- if (config.licenseType !== "UNLICENSED") {
656
+ async function installLicense(config2) {
657
+ const licenseOptions = config2.get("license").options;
658
+ const { type, name, email, website } = licenseOptions;
659
+ if (type !== "UNLICENSED") {
532
660
  const year = (/* @__PURE__ */ new Date()).getFullYear().toString();
533
- const templatePath = path3.join(
534
- __dirname,
535
- "licenses",
536
- `${config.licenseType}.txt`
537
- );
661
+ const templatePath = path3.join(__dirname, "licenses", `${type}.txt`);
538
662
  if (await fs8.pathExists(templatePath)) {
539
663
  let licenseContent = await fs8.readFile(templatePath, "utf-8");
540
664
  licenseContent = licenseContent.replace(/{YEAR}/g, year);
541
- licenseContent = licenseContent.replace(/{HOLDER}/g, config.licenseName);
542
- licenseContent = licenseContent.replace(/{EMAIL}/g, config.licenseEmail);
543
- licenseContent = licenseContent.replace(
544
- /{WEBSITE}/g,
545
- config.licenseWebsite
546
- );
665
+ licenseContent = licenseContent.replace(/{HOLDER}/g, name || "");
666
+ licenseContent = licenseContent.replace(/{EMAIL}/g, email || "");
667
+ licenseContent = licenseContent.replace(/{WEBSITE}/g, website || "");
547
668
  await fs8.outputFile("LICENSE", licenseContent);
548
669
  } else {
549
- const simpleContent = `Copyright (c) ${year} ${config.licenseName}
550
- Licensed under ${config.licenseType}`;
670
+ const simpleContent = `Copyright (c) ${year} ${name}
671
+ Licensed under ${type}`;
551
672
  await fs8.outputFile("LICENSE", simpleContent);
552
673
  }
553
674
  }
554
675
  if (await fs8.pathExists("package.json")) {
555
676
  const pkg = await fs8.readJson("package.json");
556
- pkg.license = config.licenseType;
557
- if (config.licenseName) {
558
- pkg.author = `${config.licenseName} <${config.licenseEmail}> (${config.licenseWebsite})`;
677
+ pkg.license = type;
678
+ if (name) {
679
+ pkg.author = { name, email, url: website };
559
680
  }
560
681
  await fs8.writeJson("package.json", pkg, { spaces: 2 });
561
682
  }
@@ -564,6 +685,215 @@ var init_license = __esm({
564
685
  "src/services/license.ts"() {
565
686
  "use strict";
566
687
  init_esm_shims();
688
+ init_options();
689
+ init_handle_cancel();
690
+ }
691
+ });
692
+
693
+ // src/config/config.ts
694
+ import pc9 from "picocolors";
695
+ var Config, config;
696
+ var init_config = __esm({
697
+ "src/config/config.ts"() {
698
+ "use strict";
699
+ init_esm_shims();
700
+ Config = class {
701
+ data;
702
+ constructor() {
703
+ this.data = {
704
+ husky: {
705
+ selected: false,
706
+ options: { hookType: "none", customScript: "npm run test" }
707
+ },
708
+ formatter: {
709
+ selected: false,
710
+ options: { choice: "prettier" }
711
+ },
712
+ linter: {
713
+ selected: false,
714
+ options: { choice: "eslint" }
715
+ },
716
+ lintStaged: {
717
+ selected: false,
718
+ options: { lintExtensions: [], formatExtensions: [] }
719
+ },
720
+ env: {
721
+ selected: false,
722
+ options: {
723
+ variant: "@t3-oss/env-nextjs",
724
+ validator: "zod",
725
+ installPresets: false,
726
+ presets: [],
727
+ split: "split",
728
+ location: "src/env"
729
+ }
730
+ },
731
+ test: {
732
+ selected: false,
733
+ options: { runner: "vitest" }
734
+ },
735
+ editorConfig: {
736
+ selected: false,
737
+ options: { preset: "default" }
738
+ },
739
+ license: {
740
+ selected: false,
741
+ options: { name: "", email: "", website: "", type: "MIT" }
742
+ }
743
+ };
744
+ }
745
+ get(tool) {
746
+ return this.data[tool];
747
+ }
748
+ enableTool(tool) {
749
+ this.data[tool].selected = true;
750
+ }
751
+ get summary() {
752
+ const lines = [];
753
+ lines.push(pc9.bold("The following actions will be performed:"));
754
+ lines.push("");
755
+ if (this.data.husky.selected) {
756
+ lines.push(pc9.magenta(`\u2022 Install and configure Husky`));
757
+ if (this.data.husky.options.hookType === "custom") {
758
+ lines.push(pc9.dim(` - Custom hook script`));
759
+ }
760
+ }
761
+ if (this.data.formatter.selected) {
762
+ const choice = this.data.formatter.options.choice;
763
+ lines.push(pc9.blue(`\u2022 Install and configure ${choice || "Formatter"}`));
764
+ }
765
+ if (this.data.linter.selected) {
766
+ const choice = this.data.linter.options.choice;
767
+ lines.push(pc9.yellow(`\u2022 Install and configure ${choice || "Linter"}`));
768
+ }
769
+ if (this.data.lintStaged.selected) {
770
+ lines.push(pc9.green(`\u2022 Install and configure Lint-staged`));
771
+ const lintExts = this.data.lintStaged.options.lintExtensions.join(", ");
772
+ const formatExts = this.data.lintStaged.options.formatExtensions.join(", ");
773
+ if (lintExts) lines.push(pc9.dim(` - Lint: ${lintExts}`));
774
+ if (formatExts) lines.push(pc9.dim(` - Format: ${formatExts}`));
775
+ }
776
+ if (this.data.env.selected) {
777
+ lines.push(pc9.cyan(`\u2022 Install and configure Env Validation`));
778
+ lines.push(pc9.dim(` - Variant: ${this.data.env.options.variant}`));
779
+ lines.push(pc9.dim(` - Validator: ${this.data.env.options.validator}`));
780
+ }
781
+ if (this.data.test.selected) {
782
+ const runner = this.data.test.options.runner;
783
+ lines.push(pc9.red(`\u2022 Install and configure Test Runner (${runner})`));
784
+ }
785
+ if (this.data.editorConfig.selected) {
786
+ const preset = this.data.editorConfig.options.preset;
787
+ lines.push(pc9.white(`\u2022 Create .editorconfig (${preset})`));
788
+ }
789
+ if (this.data.license.selected) {
790
+ const type = this.data.license.options.type;
791
+ const name = this.data.license.options.name;
792
+ lines.push(pc9.green(`\u2022 Create LICENSE (${type})`));
793
+ lines.push(pc9.dim(` - Holder: ${name}`));
794
+ }
795
+ return lines.join("\n");
796
+ }
797
+ };
798
+ config = new Config();
799
+ }
800
+ });
801
+
802
+ // src/steps/execution.ts
803
+ import { spinner } from "@clack/prompts";
804
+ async function execution(config2) {
805
+ const s = spinner();
806
+ if (config2.get("husky").selected) {
807
+ s.start("Setting up Husky...");
808
+ await installHusky(config2);
809
+ s.stop("Husky setup complete.");
810
+ }
811
+ if (config2.get("formatter").selected) {
812
+ const choice = config2.get("formatter").options.choice;
813
+ s.start(`Setting up ${choice}...`);
814
+ await installFormatter(config2);
815
+ s.stop(`${choice} setup complete.`);
816
+ }
817
+ if (config2.get("linter").selected) {
818
+ const choice = config2.get("linter").options.choice;
819
+ s.start(`Setting up ${choice}...`);
820
+ await installLinter(config2);
821
+ s.stop(`${choice} setup complete.`);
822
+ }
823
+ if (config2.get("lintStaged").selected) {
824
+ s.start("Setting up Lint-staged...");
825
+ await installLintStaged(config2);
826
+ s.stop("Lint-staged setup complete.");
827
+ }
828
+ if (config2.get("env").selected) {
829
+ s.start("Setting up Env Validation...");
830
+ await installEnv(config2);
831
+ s.stop("Env Validation setup complete.");
832
+ }
833
+ if (config2.get("test").selected) {
834
+ const runner = config2.get("test").options.runner;
835
+ s.start(`Setting up ${runner}...`);
836
+ await installTest(config2);
837
+ s.stop(`${runner} setup complete.`);
838
+ }
839
+ if (config2.get("editorConfig").selected) {
840
+ s.start("Creating .editorconfig...");
841
+ await installEditorConfig(config2);
842
+ s.stop(".editorconfig created.");
843
+ }
844
+ if (config2.get("license").selected) {
845
+ s.start("Creating LICENSE...");
846
+ await installLicense(config2);
847
+ s.stop("LICENSE created.");
848
+ }
849
+ }
850
+ var init_execution = __esm({
851
+ "src/steps/execution.ts"() {
852
+ "use strict";
853
+ init_esm_shims();
854
+ init_husky();
855
+ init_formatter();
856
+ init_linter();
857
+ init_lint_staged();
858
+ init_env();
859
+ init_test();
860
+ init_editor_config();
861
+ init_license();
862
+ }
863
+ });
864
+
865
+ // src/utils/logger.ts
866
+ import fs9 from "fs-extra";
867
+ import path4 from "path";
868
+ async function logError(error) {
869
+ try {
870
+ await fs9.ensureDir(ERRORS_DIR);
871
+ const gitignorePath = path4.join(LOG_DIR, ".gitignore");
872
+ if (!await fs9.pathExists(gitignorePath)) {
873
+ await fs9.outputFile(gitignorePath, "*\n");
874
+ }
875
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
876
+ const logFile = path4.join(ERRORS_DIR, `log-${timestamp}.txt`);
877
+ const errorMessage = error instanceof Error ? error.stack || error.message : String(error);
878
+ const logContent = `Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}
879
+
880
+ Error:
881
+ ${errorMessage}
882
+ `;
883
+ await fs9.outputFile(logFile, logContent);
884
+ return logFile;
885
+ } catch (e) {
886
+ console.error("Failed to log error:", e);
887
+ return "";
888
+ }
889
+ }
890
+ var LOG_DIR, ERRORS_DIR;
891
+ var init_logger = __esm({
892
+ "src/utils/logger.ts"() {
893
+ "use strict";
894
+ init_esm_shims();
895
+ LOG_DIR = ".mayrlabs/setup-project";
896
+ ERRORS_DIR = path4.join(LOG_DIR, "errors");
567
897
  }
568
898
  });
569
899
 
@@ -596,13 +926,47 @@ var init_git = __esm({
596
926
  }
597
927
  });
598
928
 
929
+ // src/steps/git-check.ts
930
+ import { confirm as confirm3, spinner as spinner2, text as text4 } from "@clack/prompts";
931
+ async function gitCheck() {
932
+ if (await isGitRepository()) {
933
+ if (await isGitDirty()) {
934
+ const shouldCommit = await confirm3({
935
+ message: "Your working directory is dirty. Would you like to commit changes before proceeding?"
936
+ });
937
+ if (shouldCommit) {
938
+ const message = await text4({
939
+ message: "Enter commit message:",
940
+ placeholder: "wip: pre-setup commit",
941
+ validate(value) {
942
+ if (value.length === 0) return "Commit message is required";
943
+ }
944
+ });
945
+ if (typeof message === "string") {
946
+ const s = spinner2();
947
+ s.start("Committing changes...");
948
+ await commitChanges(message);
949
+ s.stop("Changes committed.");
950
+ }
951
+ }
952
+ }
953
+ }
954
+ }
955
+ var init_git_check = __esm({
956
+ "src/steps/git-check.ts"() {
957
+ "use strict";
958
+ init_esm_shims();
959
+ init_git();
960
+ }
961
+ });
962
+
599
963
  // package.json
600
964
  var package_default;
601
965
  var init_package = __esm({
602
966
  "package.json"() {
603
967
  package_default = {
604
968
  name: "@mayrlabs/setup-project",
605
- version: "0.1.4",
969
+ version: "0.1.6",
606
970
  description: "Interactive CLI to setup project tools",
607
971
  private: false,
608
972
  publishConfig: {
@@ -651,67 +1015,89 @@ var init_package = __esm({
651
1015
  "@clack/prompts": "^0.7.0",
652
1016
  commander: "^11.1.0",
653
1017
  execa: "^8.0.1",
1018
+ figlet: "^1.10.0",
654
1019
  "fs-extra": "^11.2.0",
655
1020
  picocolors: "^1.0.0",
656
1021
  zod: "^3.22.4"
657
1022
  },
658
1023
  devDependencies: {
1024
+ "@types/figlet": "^1.7.0",
659
1025
  "@types/fs-extra": "^11.0.4",
660
1026
  "@types/node": "^20.11.16",
661
1027
  tsup: "^8.5.1",
1028
+ tsx: "^4.21.0",
662
1029
  typescript: "^5.3.3"
663
1030
  }
664
1031
  };
665
1032
  }
666
1033
  });
667
1034
 
668
- // src/utils/logger.ts
669
- import fs9 from "fs-extra";
670
- import path4 from "path";
671
- async function logError(error) {
672
- try {
673
- await fs9.ensureDir(ERRORS_DIR);
674
- const gitignorePath = path4.join(LOG_DIR, ".gitignore");
675
- if (!await fs9.pathExists(gitignorePath)) {
676
- await fs9.outputFile(gitignorePath, "*\n");
677
- }
678
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
679
- const logFile = path4.join(ERRORS_DIR, `log-${timestamp}.txt`);
680
- const errorMessage = error instanceof Error ? error.stack || error.message : String(error);
681
- const logContent = `Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}
682
-
683
- Error:
684
- ${errorMessage}
685
- `;
686
- await fs9.outputFile(logFile, logContent);
687
- return logFile;
688
- } catch (e) {
689
- console.error("Failed to log error:", e);
690
- return "";
691
- }
1035
+ // src/utils/display.ts
1036
+ import pc10 from "picocolors";
1037
+ import figlet from "figlet";
1038
+ function introScreen() {
1039
+ console.log();
1040
+ console.log(
1041
+ pc10.cyan(
1042
+ figlet.textSync("MayR\nLabs", {
1043
+ font: "Graceful",
1044
+ horizontalLayout: "default",
1045
+ verticalLayout: "default",
1046
+ width: 80,
1047
+ whitespaceBreak: true
1048
+ })
1049
+ )
1050
+ );
1051
+ console.log(pc10.cyan(`@mayrlabs/setup-project v${package_default.version}`));
1052
+ console.log();
692
1053
  }
693
- var LOG_DIR, ERRORS_DIR;
694
- var init_logger = __esm({
695
- "src/utils/logger.ts"() {
1054
+ function showAbout() {
1055
+ introScreen();
1056
+ console.log(pc10.bold("About:"));
1057
+ console.log(
1058
+ " Interactive CLI to setup project tools like Husky, Prettier, ESLint, etc."
1059
+ );
1060
+ console.log("");
1061
+ console.log(pc10.bold("How to use:"));
1062
+ console.log(
1063
+ " Run 'npx @mayrlabs/setup-project' and follow the interactive prompts."
1064
+ );
1065
+ console.log("");
1066
+ }
1067
+ function showVisit() {
1068
+ console.log(pc10.bold("Project Homepage:"));
1069
+ console.log(pc10.underline(pc10.cyan(package_default.homepage)));
1070
+ console.log("");
1071
+ }
1072
+ function showManual() {
1073
+ introScreen();
1074
+ console.log(pc10.bold("Usage:"));
1075
+ console.log(" npx @mayrlabs/setup-project [command] [options]");
1076
+ console.log("");
1077
+ console.log(pc10.bold("Commands:"));
1078
+ console.log(" about Show project details");
1079
+ console.log(" version Show version information");
1080
+ console.log(" visit Visit project homepage");
1081
+ console.log(" help Show this help message");
1082
+ console.log("");
1083
+ console.log(pc10.bold("Options:"));
1084
+ console.log(" -a, --about Show project details");
1085
+ console.log(" -v, --version Show version information");
1086
+ console.log(" -V, --visit Visit project homepage");
1087
+ console.log(" -h, --help Show this help message");
1088
+ console.log("");
1089
+ }
1090
+ var init_display = __esm({
1091
+ "src/utils/display.ts"() {
696
1092
  "use strict";
697
1093
  init_esm_shims();
698
- LOG_DIR = ".mayrlabs/setup-project";
699
- ERRORS_DIR = path4.join(LOG_DIR, "errors");
1094
+ init_package();
700
1095
  }
701
1096
  });
702
1097
 
703
1098
  // src/index.ts
704
- import {
705
- intro,
706
- outro,
707
- multiselect as multiselect3,
708
- isCancel,
709
- cancel,
710
- note,
711
- confirm as confirm2,
712
- spinner
713
- } from "@clack/prompts";
714
- import pc from "picocolors";
1099
+ import { outro, multiselect as multiselect3, note, confirm as confirm4, intro } from "@clack/prompts";
1100
+ import pc11 from "picocolors";
715
1101
  import { program } from "commander";
716
1102
  var require_index = __commonJS({
717
1103
  "src/index.ts"() {
@@ -724,148 +1110,93 @@ var require_index = __commonJS({
724
1110
  init_test();
725
1111
  init_editor_config();
726
1112
  init_license();
727
- init_git();
728
- init_package();
1113
+ init_config();
1114
+ init_handle_cancel();
1115
+ init_options();
1116
+ init_execution();
729
1117
  init_logger();
1118
+ init_git_check();
1119
+ init_display();
730
1120
  async function main() {
731
1121
  try {
732
- intro(pc.bgCyan(pc.black(" @mayrlabs/setup-project ")));
733
- if (await isGitRepository()) {
734
- if (await isGitDirty()) {
735
- const shouldCommit = await confirm2({
736
- message: "Your working directory is dirty. Would you like to commit changes before proceeding?"
737
- });
738
- if (shouldCommit) {
739
- const message = await import("@clack/prompts").then(
740
- (m) => m.text({
741
- message: "Enter commit message:",
742
- placeholder: "wip: pre-setup commit",
743
- validate(value) {
744
- if (value.length === 0) return "Commit message is required";
745
- }
746
- })
747
- );
748
- if (typeof message === "string") {
749
- const s2 = spinner();
750
- s2.start("Committing changes...");
751
- await commitChanges(message);
752
- s2.stop("Changes committed.");
753
- }
754
- }
755
- }
756
- }
757
- const tools = await multiselect3({
758
- message: "Select tools to configure:",
759
- options: [
760
- { value: "husky", label: "Husky" },
761
- { value: "formatter", label: "Formatter (Prettier/Oxfmt)" },
762
- { value: "linter", label: "Linter (Eslint/Oxlint)" },
763
- { value: "lint-staged", label: "Lint-staged" },
764
- { value: "env", label: "Env Validation (@t3-oss/env)" },
765
- { value: "test", label: "Test Runner (Vitest/Jest)" },
766
- { value: "editorConfig", label: "EditorConfig" },
767
- { value: "license", label: "License" }
768
- ],
769
- required: false
770
- });
771
- if (isCancel(tools)) {
772
- cancel("Operation cancelled.");
773
- process.exit(0);
774
- }
775
- const selectedTools = tools;
776
- const config = {
777
- husky: selectedTools.includes("husky"),
778
- formatter: selectedTools.includes("formatter"),
779
- linter: selectedTools.includes("linter"),
780
- lintStaged: selectedTools.includes("lint-staged"),
781
- env: selectedTools.includes("env"),
782
- test: selectedTools.includes("test"),
783
- editorConfig: selectedTools.includes("editorConfig"),
784
- license: selectedTools.includes("license")
785
- };
786
- if (config.husky) await promptHusky(config);
787
- if (config.formatter) await promptFormatter(config);
788
- if (config.linter) await promptLinter(config);
789
- if (config.lintStaged) await promptLintStaged(config);
790
- if (config.env) await promptEnv(config);
791
- if (config.test) await promptTest(config);
792
- if (config.editorConfig) await promptEditorConfig(config);
793
- if (config.license) await promptLicense(config);
794
- let summary = "The following actions will be performed:\n\n";
795
- if (config.husky) summary += "- Install and configure Husky\n";
796
- if (config.formatter)
797
- summary += `- Install and configure ${config.formatterChoice}
798
- `;
799
- if (config.linter)
800
- summary += `- Install and configure ${config.linterChoice}
801
- `;
802
- if (config.lintStaged) summary += "- Install and configure Lint-staged\n";
803
- if (config.env) summary += "- Install and configure @t3-oss/env\n";
804
- if (config.test)
805
- summary += `- Install and configure ${config.testRunner}
806
- `;
807
- if (config.editorConfig) summary += "- Create .editorconfig\n";
808
- if (config.license) summary += `- Create LICENSE (${config.licenseType})
809
- `;
810
- note(summary, "Configuration Summary");
811
- const proceed = await confirm2({
812
- message: "Do you want to proceed with the installation?"
813
- });
814
- if (!proceed || isCancel(proceed)) {
815
- cancel("Installation cancelled. Configuration saved.");
1122
+ introScreen();
1123
+ intro(
1124
+ pc11.inverse(pc11.bold(pc11.cyan(" Welcome to the Project Setup Wizard ")))
1125
+ );
1126
+ await gitCheck();
1127
+ const tools = await withCancelHandling(
1128
+ async () => multiselect3({
1129
+ message: "Select tools to configure:",
1130
+ options: TOOL_OPTIONS,
1131
+ required: false
1132
+ })
1133
+ );
1134
+ tools.forEach((tool) => config.enableTool(tool));
1135
+ if (config.get("husky").selected) await promptHusky(config);
1136
+ if (config.get("formatter").selected) await promptFormatter(config);
1137
+ if (config.get("linter").selected) await promptLinter(config);
1138
+ if (config.get("lintStaged").selected) await promptLintStaged(config);
1139
+ if (config.get("env").selected) await promptEnv(config);
1140
+ if (config.get("test").selected) await promptTest(config);
1141
+ if (config.get("editorConfig").selected) await promptEditorConfig(config);
1142
+ if (config.get("license").selected) await promptLicense(config);
1143
+ note(config.summary, "Configuration Summary");
1144
+ const proceed = await withCancelHandling(
1145
+ async () => confirm4({
1146
+ message: "Do you want to proceed with the installation?"
1147
+ })
1148
+ );
1149
+ if (!proceed) {
1150
+ outro(pc11.yellow("Installation cancelled."));
816
1151
  process.exit(0);
817
1152
  }
818
- const s = spinner();
819
- if (config.husky) {
820
- s.start("Setting up Husky...");
821
- await installHusky(config);
822
- s.stop("Husky setup complete.");
823
- }
824
- if (config.formatter) {
825
- s.start(`Setting up ${config.formatterChoice}...`);
826
- await installFormatter(config);
827
- s.stop(`${config.formatterChoice} setup complete.`);
828
- }
829
- if (config.linter) {
830
- s.start(`Setting up ${config.linterChoice}...`);
831
- await installLinter(config);
832
- s.stop(`${config.linterChoice} setup complete.`);
833
- }
834
- if (config.lintStaged) {
835
- s.start("Setting up Lint-staged...");
836
- await installLintStaged(config);
837
- s.stop("Lint-staged setup complete.");
838
- }
839
- if (config.env) {
840
- s.start("Setting up Env Validation...");
841
- await installEnv(config);
842
- s.stop("Env Validation setup complete.");
843
- }
844
- if (config.test) {
845
- s.start(`Setting up ${config.testRunner}...`);
846
- await installTest(config);
847
- s.stop(`${config.testRunner} setup complete.`);
848
- }
849
- if (config.editorConfig) {
850
- s.start("Creating .editorconfig...");
851
- await installEditorConfig(config);
852
- s.stop(".editorconfig created.");
853
- }
854
- if (config.license) {
855
- s.start("Creating LICENSE...");
856
- await installLicense(config);
857
- s.stop("LICENSE created.");
858
- }
859
- outro(pc.green("Setup complete!"));
1153
+ await execution(config);
1154
+ outro(pc11.green("Setup complete!"));
860
1155
  } catch (error) {
861
1156
  const logPath = await logError(error);
862
- outro(pc.red(`
1157
+ outro(pc11.red(`
863
1158
  Something went wrong!
864
1159
  Error log saved to: ${logPath}`));
865
1160
  process.exit(1);
866
1161
  }
867
1162
  }
868
- program.name("setup-project").description("Interactive setup for common project tools").version(package_default.version).action(main);
1163
+ program.helpOption(false);
1164
+ program.name("setup-project").description("Interactive setup for common project tools").option("-a, --about", "Show project details").option("-v, --version", "Show version info").option("-V, --visit", "Visit project homepage").option("-h, --help", "Show help");
1165
+ program.command("about").action(() => {
1166
+ showAbout();
1167
+ process.exit(0);
1168
+ });
1169
+ program.command("version").action(() => {
1170
+ introScreen();
1171
+ process.exit(0);
1172
+ });
1173
+ program.command("visit").action(() => {
1174
+ showVisit();
1175
+ process.exit(0);
1176
+ });
1177
+ program.command("help").action(() => {
1178
+ showManual();
1179
+ process.exit(0);
1180
+ });
1181
+ program.action(async (options) => {
1182
+ if (options.about) {
1183
+ showAbout();
1184
+ process.exit(0);
1185
+ }
1186
+ if (options.version) {
1187
+ introScreen();
1188
+ process.exit(0);
1189
+ }
1190
+ if (options.visit) {
1191
+ showVisit();
1192
+ process.exit(0);
1193
+ }
1194
+ if (options.help) {
1195
+ showManual();
1196
+ process.exit(0);
1197
+ }
1198
+ await main();
1199
+ });
869
1200
  program.parse();
870
1201
  }
871
1202
  });