@mayrlabs/setup-project 0.1.6 → 0.1.8

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.js CHANGED
@@ -32,12 +32,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
32
  mod
33
33
  ));
34
34
 
35
- // src/index.ts
36
- var import_prompts12 = require("@clack/prompts");
37
- var import_picocolors11 = __toESM(require("picocolors"));
35
+ // src/cli/index.ts
36
+ var import_prompts16 = require("@clack/prompts");
37
+ var import_picocolors14 = __toESM(require("picocolors"));
38
38
  var import_commander = require("commander");
39
39
 
40
- // src/services/husky.ts
40
+ // src/features/husky.ts
41
41
  var import_prompts2 = require("@clack/prompts");
42
42
 
43
43
  // src/utils/pm.ts
@@ -70,7 +70,7 @@ async function installPackages(packages, dev = false) {
70
70
  await (0, import_execa.execa)(pm, [...args, ...packages]);
71
71
  }
72
72
 
73
- // src/services/husky.ts
73
+ // src/features/husky.ts
74
74
  var import_execa2 = require("execa");
75
75
  var import_fs_extra = __toESM(require("fs-extra"));
76
76
  var import_picocolors = __toESM(require("picocolors"));
@@ -80,14 +80,14 @@ var TOOL_OPTIONS = [
80
80
  { value: "husky", label: "Husky" },
81
81
  { value: "formatter", label: "Formatter (Prettier/Oxfmt)" },
82
82
  { value: "linter", label: "Linter (Eslint/Oxlint)" },
83
- { value: "lint-staged", label: "Lint-staged" },
83
+ { value: "lintStaged", label: "Lint-staged" },
84
84
  { value: "env", label: "Env Validation (@t3-oss/env)" },
85
85
  { value: "test", label: "Test Runner (Vitest/Jest)" },
86
86
  { value: "editorConfig", label: "EditorConfig" },
87
87
  { value: "license", label: "License" }
88
88
  ];
89
89
  var HUSKY_HOOK_OPTIONS = [
90
- { value: "lint-staged", label: "lint-staged" },
90
+ { value: "lintStaged", label: "lint-staged" },
91
91
  { value: "custom", label: "Custom script" },
92
92
  { value: "none", label: "None" }
93
93
  ];
@@ -177,7 +177,7 @@ async function withCancelHandling(promptFn, cancelMessage = "Operation cancelled
177
177
  }
178
178
  }
179
179
 
180
- // src/services/husky.ts
180
+ // src/features/husky.ts
181
181
  async function promptHusky(config2) {
182
182
  import_prompts2.log.message(import_picocolors.default.bgMagenta(import_picocolors.default.black(" Husky Configuration ")));
183
183
  const hookType = await withCancelHandling(
@@ -188,7 +188,7 @@ async function promptHusky(config2) {
188
188
  );
189
189
  const huskyConfig = config2.get("husky");
190
190
  huskyConfig.options = { hookType };
191
- if (hookType === "lint-staged") {
191
+ if (hookType === "lintStaged") {
192
192
  config2.enableTool("lintStaged");
193
193
  } else if (hookType === "custom") {
194
194
  const script = await withCancelHandling(
@@ -214,7 +214,7 @@ async function installHusky(config2) {
214
214
  const husky = config2.get("husky");
215
215
  const hookType = husky.options.hookType;
216
216
  const customScript = husky.options.customScript;
217
- if (hookType === "lint-staged") {
217
+ if (hookType === "lintStaged") {
218
218
  await import_fs_extra.default.outputFile(".husky/pre-commit", "npx lint-staged\n", {
219
219
  mode: 493
220
220
  });
@@ -226,15 +226,1347 @@ async function installHusky(config2) {
226
226
  }
227
227
  }
228
228
 
229
- // src/services/formatter.ts
230
- var import_prompts3 = require("@clack/prompts");
229
+ // src/features/formatter.ts
230
+ var import_prompts5 = require("@clack/prompts");
231
+ var import_picocolors3 = __toESM(require("picocolors"));
232
+
233
+ // src/features/formatter/prettier.ts
234
+ var import_fs_extra3 = __toESM(require("fs-extra"));
235
+
236
+ // src/utils/config-file.ts
231
237
  var import_fs_extra2 = __toESM(require("fs-extra"));
238
+ var import_prompts3 = require("@clack/prompts");
239
+ var import_node_path = __toESM(require("path"));
240
+ async function resolveConfigFile(toolName, candidates) {
241
+ for (const file of candidates) {
242
+ if (await import_fs_extra2.default.pathExists(file)) return file;
243
+ }
244
+ const response = await withCancelHandling(
245
+ async () => (0, import_prompts3.select)({
246
+ message: `Where do you want to store the ${toolName} config?`,
247
+ options: candidates.map((c) => ({ value: c, label: c })),
248
+ initialValue: candidates[0]
249
+ })
250
+ );
251
+ return response;
252
+ }
253
+ async function writeConfig(filePath, config2) {
254
+ const ext = import_node_path.default.extname(filePath);
255
+ if (ext === ".json" || ext === "") {
256
+ await import_fs_extra2.default.writeJson(filePath, config2, { spaces: 2 });
257
+ } else if (ext === ".js" || ext === ".cjs") {
258
+ const content = `module.exports = ${JSON.stringify(config2, null, 2)};`;
259
+ await import_fs_extra2.default.writeFile(filePath, content);
260
+ } else if (ext === ".mjs") {
261
+ const content = `export default ${JSON.stringify(config2, null, 2)};`;
262
+ await import_fs_extra2.default.writeFile(filePath, content);
263
+ } else {
264
+ await import_fs_extra2.default.writeJson(filePath, config2, { spaces: 2 });
265
+ }
266
+ }
267
+
268
+ // src/features/formatter/prettier.ts
269
+ async function installPrettier() {
270
+ await installPackages(["prettier"], true);
271
+ const configFile = await resolveConfigFile("Prettier", [
272
+ ".prettierrc",
273
+ ".prettierrc.json",
274
+ "prettier.config.js",
275
+ ".prettierrc.js"
276
+ ]);
277
+ if (!await import_fs_extra3.default.pathExists(configFile)) {
278
+ await writeConfig(configFile, {
279
+ semi: true,
280
+ singleQuote: false,
281
+ tabWidth: 2,
282
+ trailingComma: "es5",
283
+ printWidth: 80,
284
+ plugins: []
285
+ });
286
+ }
287
+ if (!await import_fs_extra3.default.pathExists(".prettierignore")) {
288
+ await import_fs_extra3.default.writeFile(
289
+ ".prettierignore",
290
+ `node_modules
291
+ dist
292
+ coverage
293
+ .next
294
+ .nuxt
295
+ build
296
+ .astro
297
+ .output
298
+ `
299
+ );
300
+ }
301
+ }
302
+ async function configurePrettierPlugins(plugins) {
303
+ const configFile = await resolveConfigFile("Prettier", [
304
+ ".prettierrc",
305
+ ".prettierrc.json",
306
+ "prettier.config.js",
307
+ ".prettierrc.js"
308
+ ]);
309
+ let currentConfig = {};
310
+ if (await import_fs_extra3.default.pathExists(configFile)) {
311
+ try {
312
+ if (configFile.endsWith(".js") || configFile.endsWith(".cjs")) {
313
+ return;
314
+ }
315
+ currentConfig = await import_fs_extra3.default.readJson(configFile);
316
+ } catch (e) {
317
+ }
318
+ }
319
+ const existingPlugins = currentConfig.plugins || [];
320
+ const newPlugins = [.../* @__PURE__ */ new Set([...existingPlugins, ...plugins])];
321
+ currentConfig.plugins = newPlugins;
322
+ await writeConfig(configFile, currentConfig);
323
+ }
324
+
325
+ // src/features/formatter/oxfmt.ts
326
+ async function installOxfmt() {
327
+ await installPackages(["oxfmt@latest"], true);
328
+ }
329
+
330
+ // src/constants/plugins.ts
331
+ var ESLINT_PLUGINS = [
332
+ // Code Quality
333
+ {
334
+ value: "depend",
335
+ label: "depend",
336
+ package: "eslint-plugin-depend",
337
+ hint: "Detect junk dependencies"
338
+ },
339
+ {
340
+ value: "github",
341
+ label: "github",
342
+ package: "eslint-plugin-github",
343
+ hint: "GitHub's ESLint rules"
344
+ },
345
+ {
346
+ value: "sonarjs",
347
+ label: "sonarjs",
348
+ package: "eslint-plugin-sonarjs",
349
+ hint: "Detect bugs and suspicious patterns"
350
+ },
351
+ {
352
+ value: "unicorn",
353
+ label: "unicorn",
354
+ package: "eslint-plugin-unicorn",
355
+ hint: "Various awesome ESLint rules"
356
+ },
357
+ {
358
+ value: "mysticatea",
359
+ label: "mysticatea",
360
+ package: "@mysticatea/eslint-plugin",
361
+ hint: "Misc rules"
362
+ },
363
+ {
364
+ value: "brettz9",
365
+ label: "brettz9",
366
+ package: "@brettz9/eslint-plugin",
367
+ hint: "Misc rules without personal config"
368
+ },
369
+ {
370
+ value: "de-morgan",
371
+ label: "de-morgan",
372
+ package: "eslint-plugin-de-morgan",
373
+ hint: "Transform logical expressions"
374
+ },
375
+ {
376
+ value: "code-complete",
377
+ label: "code-complete",
378
+ package: "eslint-plugin-code-complete",
379
+ hint: "Clean, maintainable software design"
380
+ },
381
+ // Compatibility
382
+ {
383
+ value: "compat",
384
+ label: "compat",
385
+ package: "eslint-plugin-compat",
386
+ hint: "Browser compatibility checking"
387
+ },
388
+ {
389
+ value: "es-compat",
390
+ label: "es-compat",
391
+ package: "eslint-plugin-es-compat",
392
+ hint: "Disable unsupported ES features"
393
+ },
394
+ {
395
+ value: "es-x",
396
+ label: "es-x",
397
+ package: "eslint-plugin-es-x",
398
+ hint: "Disable specific ES versions"
399
+ },
400
+ {
401
+ value: "es5",
402
+ label: "es5",
403
+ package: "eslint-plugin-es5",
404
+ hint: "Forbid ES2015+ usage"
405
+ },
406
+ {
407
+ value: "ie11",
408
+ label: "ie11",
409
+ package: "eslint-plugin-ie11",
410
+ hint: "Detect unsupported ES6 features in IE11"
411
+ },
412
+ // CSS in JS
413
+ {
414
+ value: "css-modules",
415
+ label: "css-modules",
416
+ package: "eslint-plugin-css-modules",
417
+ hint: "Lint css modules"
418
+ },
419
+ {
420
+ value: "emotion",
421
+ label: "emotion",
422
+ package: "@emotion/eslint-plugin",
423
+ hint: "Rules for emotion"
424
+ },
425
+ {
426
+ value: "better-styled-components",
427
+ label: "better-styled-components",
428
+ package: "eslint-plugin-better-styled-components",
429
+ hint: "Auto fixable rules for styled components"
430
+ },
431
+ {
432
+ value: "styled-components-a11y",
433
+ label: "styled-components-a11y",
434
+ package: "eslint-plugin-styled-components-a11y",
435
+ hint: "A11y for Styled Components"
436
+ },
437
+ {
438
+ value: "vanilla-extract",
439
+ label: "vanilla-extract",
440
+ package: "@vanilla-extract/eslint-plugin",
441
+ hint: "Enforce CSS property ordering"
442
+ },
443
+ // Deprecation
444
+ {
445
+ value: "deprecate",
446
+ label: "deprecate",
447
+ package: "eslint-plugin-deprecate",
448
+ hint: "Mark functions/modules as deprecated"
449
+ },
450
+ {
451
+ value: "disable",
452
+ label: "disable",
453
+ package: "eslint-plugin-disable",
454
+ hint: "Disable plugins using patterns"
455
+ },
456
+ // Embedded
457
+ {
458
+ value: "html",
459
+ label: "html",
460
+ package: "eslint-plugin-html",
461
+ hint: "Linting JS inside HTML"
462
+ },
463
+ {
464
+ value: "markdown",
465
+ label: "markdown",
466
+ package: "eslint-plugin-markdown",
467
+ hint: "Linting JS inside Markdown"
468
+ },
469
+ // Frameworks
470
+ {
471
+ value: "angular",
472
+ label: "angular",
473
+ package: "@angular-eslint/eslint-plugin",
474
+ hint: "Linting for Angular"
475
+ },
476
+ {
477
+ value: "angularjs",
478
+ label: "angularjs",
479
+ package: "eslint-plugin-angular",
480
+ hint: "Linting for AngularJS"
481
+ },
482
+ {
483
+ value: "astro",
484
+ label: "astro",
485
+ package: "eslint-plugin-astro",
486
+ hint: "Linting for Astro"
487
+ },
488
+ {
489
+ value: "backbone",
490
+ label: "backbone",
491
+ package: "eslint-plugin-backbone",
492
+ hint: "Linting for Backbone"
493
+ },
494
+ {
495
+ value: "ember",
496
+ label: "ember",
497
+ package: "eslint-plugin-ember",
498
+ hint: "Linting for Ember"
499
+ },
500
+ {
501
+ value: "hapi",
502
+ label: "hapi",
503
+ package: "eslint-plugin-hapi",
504
+ hint: "Linting for Hapi"
505
+ },
506
+ {
507
+ value: "meteor",
508
+ label: "meteor",
509
+ package: "eslint-plugin-meteor",
510
+ hint: "Linting for Meteor"
511
+ },
512
+ {
513
+ value: "jsx-a11y",
514
+ label: "jsx-a11y",
515
+ package: "eslint-plugin-jsx-a11y",
516
+ hint: "Accessibility rules on JSX"
517
+ },
518
+ {
519
+ value: "react",
520
+ label: "react",
521
+ package: "eslint-plugin-react",
522
+ hint: "Linting for React/JSX"
523
+ },
524
+ {
525
+ value: "react-hooks",
526
+ label: "react-hooks",
527
+ package: "eslint-plugin-react-hooks",
528
+ hint: "Linting for React Hooks"
529
+ },
530
+ {
531
+ value: "react-native",
532
+ label: "react-native",
533
+ package: "eslint-plugin-react-native",
534
+ hint: "React Native specific rules"
535
+ },
536
+ {
537
+ value: "react-redux",
538
+ label: "react-redux",
539
+ package: "eslint-plugin-react-redux",
540
+ hint: "React-Redux specific rules"
541
+ },
542
+ {
543
+ value: "react-refresh",
544
+ label: "react-refresh",
545
+ package: "eslint-plugin-react-refresh",
546
+ hint: "Improve HMR with Vite"
547
+ },
548
+ {
549
+ value: "solid",
550
+ label: "solid",
551
+ package: "eslint-plugin-solid",
552
+ hint: "Linting for Solid"
553
+ },
554
+ {
555
+ value: "svelte",
556
+ label: "svelte",
557
+ package: "eslint-plugin-svelte",
558
+ hint: "Linting for Svelte"
559
+ },
560
+ {
561
+ value: "vuejs",
562
+ label: "vuejs",
563
+ package: "eslint-plugin-vue",
564
+ hint: "Linting for VueJS"
565
+ },
566
+ {
567
+ value: "vue-scoped-css",
568
+ label: "vue-scoped-css",
569
+ package: "eslint-plugin-vue-scoped-css",
570
+ hint: "Scoped CSS in VueJS"
571
+ },
572
+ // Languages and Environments
573
+ {
574
+ value: "babel",
575
+ label: "babel",
576
+ package: "@babel/eslint-plugin",
577
+ hint: "Babel features"
578
+ },
579
+ {
580
+ value: "flowtype",
581
+ label: "flowtype",
582
+ package: "eslint-plugin-flowtype",
583
+ hint: "Flow type linting"
584
+ },
585
+ {
586
+ value: "flowtype-errors",
587
+ label: "flowtype-errors",
588
+ package: "eslint-plugin-flowtype-errors",
589
+ hint: "Run Flow as plugin"
590
+ },
591
+ {
592
+ value: "html-eslint",
593
+ label: "html-eslint",
594
+ package: "@html-eslint/eslint-plugin",
595
+ hint: "Linting for HTML"
596
+ },
597
+ {
598
+ value: "json",
599
+ label: "json",
600
+ package: "eslint-plugin-json",
601
+ hint: "Lint JSON files"
602
+ },
603
+ {
604
+ value: "json-format",
605
+ label: "json-format",
606
+ package: "eslint-plugin-json-format",
607
+ hint: "Lint/Format/Fix JSON"
608
+ },
609
+ {
610
+ value: "jsonc",
611
+ label: "jsonc",
612
+ package: "eslint-plugin-jsonc",
613
+ hint: "JSON with comments"
614
+ },
615
+ {
616
+ value: "json-schema-validator",
617
+ label: "json-schema-validator",
618
+ package: "eslint-plugin-json-schema-validator",
619
+ hint: "Validate data using JSON Schema"
620
+ },
621
+ {
622
+ value: "package-json",
623
+ label: "package-json",
624
+ package: "eslint-plugin-package-json",
625
+ hint: "Rules for package.json"
626
+ },
627
+ {
628
+ value: "mdx",
629
+ label: "mdx",
630
+ package: "eslint-plugin-mdx",
631
+ hint: "Lint MDX"
632
+ },
633
+ { value: "n", label: "n", package: "eslint-plugin-n", hint: "Node.js rules" },
634
+ {
635
+ value: "sql",
636
+ label: "sql",
637
+ package: "eslint-plugin-sql",
638
+ hint: "SQL linting"
639
+ },
640
+ {
641
+ value: "toml",
642
+ label: "toml",
643
+ package: "eslint-plugin-toml",
644
+ hint: "Lint TOML"
645
+ },
646
+ {
647
+ value: "typescript",
648
+ label: "typescript",
649
+ package: "@typescript-eslint/eslint-plugin",
650
+ hint: "Lint TypeScript"
651
+ },
652
+ {
653
+ value: "erasable-syntax-only",
654
+ label: "erasable-syntax-only",
655
+ package: "eslint-plugin-erasable-syntax-only",
656
+ hint: "Enforce TS erasableSyntaxOnly"
657
+ },
658
+ {
659
+ value: "expect-type",
660
+ label: "expect-type",
661
+ package: "eslint-plugin-expect-type",
662
+ hint: "Type assertions"
663
+ },
664
+ {
665
+ value: "yaml",
666
+ label: "yaml",
667
+ package: "eslint-plugin-yml",
668
+ hint: "Lint YAML"
669
+ },
670
+ // Libraries
671
+ {
672
+ value: "graphql",
673
+ label: "graphql",
674
+ package: "@graphql-eslint/eslint-plugin",
675
+ hint: "Validate GraphQL operations/schema"
676
+ },
677
+ {
678
+ value: "graphql-schema",
679
+ label: "graphql-schema",
680
+ package: "eslint-plugin-graphql",
681
+ hint: "Check GraphQL queries against schema"
682
+ },
683
+ {
684
+ value: "type-graphql",
685
+ label: "type-graphql",
686
+ package: "eslint-plugin-type-graphql",
687
+ hint: "Lint TypeGraphQL"
688
+ },
689
+ {
690
+ value: "jquery",
691
+ label: "jquery",
692
+ package: "eslint-plugin-no-jquery",
693
+ hint: "Lint jQuery (deprecated features)"
694
+ },
695
+ {
696
+ value: "jsdoc",
697
+ label: "jsdoc",
698
+ package: "eslint-plugin-jsdoc",
699
+ hint: "Lint JSDoc comments"
700
+ },
701
+ {
702
+ value: "lodash",
703
+ label: "lodash",
704
+ package: "eslint-plugin-lodash",
705
+ hint: "Lodash rules"
706
+ },
707
+ {
708
+ value: "lodash-fp",
709
+ label: "lodash-fp",
710
+ package: "eslint-plugin-lodash-fp",
711
+ hint: "Lodash/fp rules"
712
+ },
713
+ {
714
+ value: "lodash-template",
715
+ label: "lodash-template",
716
+ package: "eslint-plugin-lodash-template",
717
+ hint: "Lodash template rules"
718
+ },
719
+ {
720
+ value: "microtemplates",
721
+ label: "microtemplates",
722
+ package: "eslint-plugin-microtemplates",
723
+ hint: "Microtemplates rules"
724
+ },
725
+ {
726
+ value: "mongodb",
727
+ label: "mongodb",
728
+ package: "eslint-plugin-mongodb",
729
+ hint: "MongoDB driver rules"
730
+ },
731
+ {
732
+ value: "ramda",
733
+ label: "ramda",
734
+ package: "eslint-plugin-ramda",
735
+ hint: "Ramda rules"
736
+ },
737
+ {
738
+ value: "requirejs",
739
+ label: "requirejs",
740
+ package: "eslint-plugin-requirejs",
741
+ hint: "RequireJS rules"
742
+ },
743
+ {
744
+ value: "tailwindcss",
745
+ label: "tailwindcss",
746
+ package: "eslint-plugin-tailwindcss",
747
+ hint: "Tailwind CSS rules"
748
+ },
749
+ {
750
+ value: "better-tailwindcss",
751
+ label: "better-tailwindcss",
752
+ package: "eslint-plugin-better-tailwindcss",
753
+ hint: "Improve readability/best practices"
754
+ },
755
+ // Misc
756
+ {
757
+ value: "diff",
758
+ label: "diff",
759
+ package: "eslint-plugin-diff",
760
+ hint: "Lint changed lines only"
761
+ },
762
+ {
763
+ value: "misc",
764
+ label: "misc",
765
+ package: "eslint-plugin-misc",
766
+ hint: "Miscellaneous rules"
767
+ },
768
+ {
769
+ value: "notice",
770
+ label: "notice",
771
+ package: "eslint-plugin-notice",
772
+ hint: "Check top of files"
773
+ },
774
+ {
775
+ value: "only-error",
776
+ label: "only-error",
777
+ package: "eslint-plugin-only-error",
778
+ hint: "Convert all rules to errors"
779
+ },
780
+ {
781
+ value: "only-warn",
782
+ label: "only-warn",
783
+ package: "eslint-plugin-only-warn",
784
+ hint: "Convert all rules to warnings"
785
+ },
786
+ {
787
+ value: "putout",
788
+ label: "putout",
789
+ package: "eslint-plugin-putout",
790
+ hint: "Integrate PutOut linter"
791
+ },
792
+ {
793
+ value: "typelint",
794
+ label: "typelint",
795
+ package: "eslint-plugin-typelint",
796
+ hint: "Introduce types based on schemas"
797
+ },
798
+ {
799
+ value: "woke",
800
+ label: "woke",
801
+ package: "eslint-plugin-woke",
802
+ hint: "Catch insensitive words"
803
+ },
804
+ // Practices and Specific ES Features
805
+ {
806
+ value: "array-func",
807
+ label: "array-func",
808
+ package: "eslint-plugin-array-func",
809
+ hint: "Avoid redundancy with array methods"
810
+ },
811
+ {
812
+ value: "proper-arrows",
813
+ label: "proper-arrows",
814
+ package: "eslint-plugin-proper-arrows",
815
+ hint: "Ensure proper arrow function definitions"
816
+ },
817
+ {
818
+ value: "boundaries",
819
+ label: "boundaries",
820
+ package: "eslint-plugin-boundaries",
821
+ hint: "Enforce architecture boundaries"
822
+ },
823
+ {
824
+ value: "eslint-comments",
825
+ label: "eslint-comments",
826
+ package: "eslint-plugin-eslint-comments",
827
+ hint: "Best practices for ESLint directives"
828
+ },
829
+ {
830
+ value: "error-cause",
831
+ label: "error-cause",
832
+ package: "eslint-plugin-error-cause",
833
+ hint: "Preserve error context"
834
+ },
835
+ {
836
+ value: "hexagonal-architecture",
837
+ label: "hexagonal-architecture",
838
+ package: "eslint-plugin-hexagonal-architecture",
839
+ hint: "Hexagonal architecture best practices"
840
+ },
841
+ {
842
+ value: "signature-design",
843
+ label: "signature-design",
844
+ package: "eslint-plugin-signature-design",
845
+ hint: "Enforce object-based signatures"
846
+ },
847
+ {
848
+ value: "write-good-comments",
849
+ label: "write-good-comments",
850
+ package: "eslint-plugin-write-good-comments",
851
+ hint: "Enforce good comment style"
852
+ },
853
+ {
854
+ value: "exception-handling",
855
+ label: "exception-handling",
856
+ package: "eslint-plugin-exception-handling",
857
+ hint: "Lint unhandled exceptions"
858
+ },
859
+ {
860
+ value: "fp",
861
+ label: "fp",
862
+ package: "eslint-plugin-fp",
863
+ hint: "Functional programming rules"
864
+ },
865
+ {
866
+ value: "functional",
867
+ label: "functional",
868
+ package: "eslint-plugin-functional",
869
+ hint: "Disable mutation, promote FP"
870
+ },
871
+ {
872
+ value: "mutate",
873
+ label: "mutate",
874
+ package: "eslint-plugin-mutate",
875
+ hint: "Prevent accidental mutations"
876
+ },
877
+ {
878
+ value: "immutable",
879
+ label: "immutable",
880
+ package: "eslint-plugin-immutable",
881
+ hint: "Disable all mutation"
882
+ },
883
+ {
884
+ value: "import",
885
+ label: "import",
886
+ package: "eslint-plugin-import",
887
+ hint: "Lint import/export syntax"
888
+ },
889
+ {
890
+ value: "import-x",
891
+ label: "import-x",
892
+ package: "eslint-plugin-import-x",
893
+ hint: "Lightweight fork of eslint-plugin-import"
894
+ },
895
+ {
896
+ value: "math",
897
+ label: "math",
898
+ package: "eslint-plugin-math",
899
+ hint: "Math object rules"
900
+ },
901
+ {
902
+ value: "new-with-error",
903
+ label: "new-with-error",
904
+ package: "eslint-plugin-new-with-error",
905
+ hint: "Require new with Error"
906
+ },
907
+ {
908
+ value: "no-argument-spread",
909
+ label: "no-argument-spread",
910
+ package: "eslint-plugin-no-argument-spread",
911
+ hint: "Lint against spread arguments"
912
+ },
913
+ {
914
+ value: "no-comments",
915
+ label: "no-comments",
916
+ package: "eslint-plugin-no-comments",
917
+ hint: "Prevent leaking comments"
918
+ },
919
+ {
920
+ value: "no-constructor-bind",
921
+ label: "no-constructor-bind",
922
+ package: "eslint-plugin-no-constructor-bind",
923
+ hint: "Encourage class properties"
924
+ },
925
+ {
926
+ value: "no-inferred-method-name",
927
+ label: "no-inferred-method-name",
928
+ package: "eslint-plugin-no-inferred-method-name",
929
+ hint: "Check inferred method names"
930
+ },
931
+ {
932
+ value: "no-loops",
933
+ label: "no-loops",
934
+ package: "eslint-plugin-no-loops",
935
+ hint: "Disallow loops"
936
+ },
937
+ {
938
+ value: "query",
939
+ label: "query",
940
+ package: "eslint-plugin-query",
941
+ hint: "Show queried syntax content"
942
+ },
943
+ {
944
+ value: "no-use-extend-native",
945
+ label: "no-use-extend-native",
946
+ package: "eslint-plugin-no-use-extend-native",
947
+ hint: "Prevent using extended native objects"
948
+ },
949
+ {
950
+ value: "promise",
951
+ label: "promise",
952
+ package: "eslint-plugin-promise",
953
+ hint: "Promise best practices"
954
+ },
955
+ {
956
+ value: "pure",
957
+ label: "pure",
958
+ package: "eslint-plugin-pure",
959
+ hint: "Enforce pure functions"
960
+ },
961
+ {
962
+ value: "redos",
963
+ label: "redos",
964
+ package: "eslint-plugin-redos",
965
+ hint: "Find ReDoS vulnerabilities"
966
+ },
967
+ {
968
+ value: "redos-detector",
969
+ label: "redos-detector",
970
+ package: "eslint-plugin-redos-detector",
971
+ hint: "Find ReDoS vulnerabilities"
972
+ },
973
+ {
974
+ value: "regexp",
975
+ label: "regexp",
976
+ package: "eslint-plugin-regexp",
977
+ hint: "Find regexp mistakes"
978
+ },
979
+ {
980
+ value: "sort-keys-fix",
981
+ label: "sort-keys-fix",
982
+ package: "eslint-plugin-sort-keys-fix",
983
+ hint: "Fixer for sort-keys"
984
+ },
985
+ {
986
+ value: "this",
987
+ label: "this",
988
+ package: "eslint-plugin-this",
989
+ hint: "Disallow this"
990
+ },
991
+ {
992
+ value: "toplevel",
993
+ label: "toplevel",
994
+ package: "eslint-plugin-toplevel",
995
+ hint: "Disallow side effects at top level"
996
+ },
997
+ // Performance
998
+ {
999
+ value: "dom",
1000
+ label: "dom",
1001
+ package: "eslint-plugin-dom",
1002
+ hint: "DOM performance"
1003
+ },
1004
+ {
1005
+ value: "optimize-regex",
1006
+ label: "optimize-regex",
1007
+ package: "eslint-plugin-optimize-regex",
1008
+ hint: "Optimize regex literals"
1009
+ },
1010
+ {
1011
+ value: "perf-standard",
1012
+ label: "perf-standard",
1013
+ package: "eslint-plugin-perf-standard",
1014
+ hint: "Performance standard rules"
1015
+ },
1016
+ // Security
1017
+ {
1018
+ value: "no-secrets",
1019
+ label: "no-secrets",
1020
+ package: "eslint-plugin-no-secrets",
1021
+ hint: "Detect potential secrets"
1022
+ },
1023
+ {
1024
+ value: "no-unsanitized",
1025
+ label: "no-unsanitized",
1026
+ package: "eslint-plugin-no-unsanitized",
1027
+ hint: "Checks for innerHTML etc"
1028
+ },
1029
+ {
1030
+ value: "pii",
1031
+ label: "pii",
1032
+ package: "eslint-plugin-pii",
1033
+ hint: "Enforce PII compliance"
1034
+ },
1035
+ {
1036
+ value: "pg",
1037
+ label: "pg",
1038
+ package: "eslint-plugin-pg",
1039
+ hint: "PostgreSQL security"
1040
+ },
1041
+ {
1042
+ value: "security",
1043
+ label: "security",
1044
+ package: "eslint-plugin-security",
1045
+ hint: "Node Security rules"
1046
+ },
1047
+ {
1048
+ value: "xss",
1049
+ label: "xss",
1050
+ package: "eslint-plugin-xss",
1051
+ hint: "Detect XSS issues"
1052
+ },
1053
+ // Style
1054
+ {
1055
+ value: "stylistic",
1056
+ label: "stylistic",
1057
+ package: "@stylistic/eslint-plugin",
1058
+ hint: "Formatting and stylistic rules"
1059
+ },
1060
+ {
1061
+ value: "const-case",
1062
+ label: "const-case",
1063
+ package: "eslint-plugin-const-case",
1064
+ hint: "Enforce capitalization of constants"
1065
+ },
1066
+ {
1067
+ value: "editorconfig",
1068
+ label: "editorconfig",
1069
+ package: "eslint-plugin-editorconfig",
1070
+ hint: "Derive rules from .editorconfig"
1071
+ },
1072
+ {
1073
+ value: "simple-import-sort",
1074
+ label: "simple-import-sort",
1075
+ package: "eslint-plugin-simple-import-sort",
1076
+ hint: "Easy import sorting"
1077
+ },
1078
+ {
1079
+ value: "perfectionist",
1080
+ label: "perfectionist",
1081
+ package: "eslint-plugin-perfectionist",
1082
+ hint: "Sort objects, imports, etc."
1083
+ },
1084
+ {
1085
+ value: "split-and-sort-imports",
1086
+ label: "split-and-sort-imports",
1087
+ package: "eslint-plugin-split-and-sort-imports",
1088
+ hint: "Split and sort imports"
1089
+ },
1090
+ {
1091
+ value: "switch-case",
1092
+ label: "switch-case",
1093
+ package: "eslint-plugin-switch-case",
1094
+ hint: "Switch-case specific rules"
1095
+ },
1096
+ {
1097
+ value: "padding",
1098
+ label: "padding",
1099
+ package: "eslint-plugin-padding",
1100
+ hint: "Padding between statements"
1101
+ },
1102
+ {
1103
+ value: "paths",
1104
+ label: "paths",
1105
+ package: "eslint-plugin-paths",
1106
+ hint: "Use paths from tsconfig/jsconfig"
1107
+ },
1108
+ {
1109
+ value: "no-relative-imports",
1110
+ label: "no-relative-imports",
1111
+ package: "@gitbutler/no-relative-imports",
1112
+ hint: "Auto fix relative paths"
1113
+ },
1114
+ // Testing Tools
1115
+ {
1116
+ value: "ava",
1117
+ label: "ava",
1118
+ package: "eslint-plugin-ava",
1119
+ hint: "AVA rules"
1120
+ },
1121
+ {
1122
+ value: "chai-expect",
1123
+ label: "chai-expect",
1124
+ package: "eslint-plugin-chai-expect",
1125
+ hint: "Chai expect practices"
1126
+ },
1127
+ {
1128
+ value: "chai-friendly",
1129
+ label: "chai-friendly",
1130
+ package: "eslint-plugin-chai-friendly",
1131
+ hint: "Chai unused expressions"
1132
+ },
1133
+ {
1134
+ value: "chai-expect-keywords",
1135
+ label: "chai-expect-keywords",
1136
+ package: "eslint-plugin-chai-expect-keywords",
1137
+ hint: "Permitted keywords"
1138
+ },
1139
+ {
1140
+ value: "chai-as-promised",
1141
+ label: "chai-as-promised",
1142
+ package: "eslint-plugin-chai-as-promised",
1143
+ hint: "Chai as promised"
1144
+ },
1145
+ {
1146
+ value: "chai-assert-bdd",
1147
+ label: "chai-assert-bdd",
1148
+ package: "eslint-plugin-chai-assert-bdd",
1149
+ hint: "Chai globals"
1150
+ },
1151
+ {
1152
+ value: "cucumber",
1153
+ label: "cucumber",
1154
+ package: "eslint-plugin-cucumber",
1155
+ hint: "Cucumber rules"
1156
+ },
1157
+ {
1158
+ value: "cypress",
1159
+ label: "cypress",
1160
+ package: "eslint-plugin-cypress",
1161
+ hint: "Cypress rules"
1162
+ },
1163
+ {
1164
+ value: "jasmine",
1165
+ label: "jasmine",
1166
+ package: "eslint-plugin-jasmine",
1167
+ hint: "Jasmine rules"
1168
+ },
1169
+ {
1170
+ value: "jest",
1171
+ label: "jest",
1172
+ package: "eslint-plugin-jest",
1173
+ hint: "Jest practices"
1174
+ },
1175
+ {
1176
+ value: "jest-formatting",
1177
+ label: "jest-formatting",
1178
+ package: "eslint-plugin-jest-formatting",
1179
+ hint: "Jest formatting"
1180
+ },
1181
+ {
1182
+ value: "jest-async",
1183
+ label: "jest-async",
1184
+ package: "eslint-plugin-jest-async",
1185
+ hint: "Jest async rules"
1186
+ },
1187
+ {
1188
+ value: "jest-dom",
1189
+ label: "jest-dom",
1190
+ package: "eslint-plugin-jest-dom",
1191
+ hint: "Jest-DOM rules"
1192
+ },
1193
+ {
1194
+ value: "mocha",
1195
+ label: "mocha",
1196
+ package: "eslint-plugin-mocha",
1197
+ hint: "Mocha practices"
1198
+ },
1199
+ {
1200
+ value: "mocha-cleanup",
1201
+ label: "mocha-cleanup",
1202
+ package: "eslint-plugin-mocha-cleanup",
1203
+ hint: "Mocha cleanup"
1204
+ },
1205
+ {
1206
+ value: "playwright",
1207
+ label: "playwright",
1208
+ package: "eslint-plugin-playwright",
1209
+ hint: "Playwright rules"
1210
+ },
1211
+ {
1212
+ value: "qunit",
1213
+ label: "qunit",
1214
+ package: "eslint-plugin-qunit",
1215
+ hint: "QUnit rules"
1216
+ },
1217
+ {
1218
+ value: "testcafe-community",
1219
+ label: "testcafe-community",
1220
+ package: "eslint-plugin-testcafe-community",
1221
+ hint: "TestCafe rules"
1222
+ },
1223
+ {
1224
+ value: "testing-library",
1225
+ label: "testing-library",
1226
+ package: "eslint-plugin-testing-library",
1227
+ hint: "Testing Library rules"
1228
+ }
1229
+ ];
1230
+ var PRETTIER_PLUGINS = [
1231
+ // Official
1232
+ {
1233
+ value: "php",
1234
+ label: "php",
1235
+ package: "@prettier/plugin-php",
1236
+ hint: "Prettier for PHP"
1237
+ },
1238
+ {
1239
+ value: "pug",
1240
+ label: "pug",
1241
+ package: "@prettier/plugin-pug",
1242
+ hint: "Prettier for Pug"
1243
+ },
1244
+ {
1245
+ value: "ruby",
1246
+ label: "ruby",
1247
+ package: "@prettier/plugin-ruby",
1248
+ hint: "Prettier for Ruby"
1249
+ },
1250
+ {
1251
+ value: "xml",
1252
+ label: "xml",
1253
+ package: "@prettier/plugin-xml",
1254
+ hint: "Prettier for XML"
1255
+ },
1256
+ // Community
1257
+ {
1258
+ value: "apex",
1259
+ label: "apex",
1260
+ package: "prettier-plugin-apex",
1261
+ hint: "Prettier for Apex"
1262
+ },
1263
+ {
1264
+ value: "astro",
1265
+ label: "astro",
1266
+ package: "prettier-plugin-astro",
1267
+ hint: "Prettier for Astro"
1268
+ },
1269
+ {
1270
+ value: "bigcommerce",
1271
+ label: "bigcommerce",
1272
+ package: "prettier-plugin-bigcommerce-stencil",
1273
+ hint: "Prettier for BigCommerce"
1274
+ },
1275
+ {
1276
+ value: "elm",
1277
+ label: "elm",
1278
+ package: "prettier-plugin-elm",
1279
+ hint: "Prettier for Elm"
1280
+ },
1281
+ {
1282
+ value: "erb",
1283
+ label: "erb",
1284
+ package: "prettier-plugin-erb",
1285
+ hint: "Prettier for ERB"
1286
+ },
1287
+ {
1288
+ value: "gherkin",
1289
+ label: "gherkin",
1290
+ package: "prettier-plugin-gherkin",
1291
+ hint: "Prettier for Gherkin"
1292
+ },
1293
+ {
1294
+ value: "glsl",
1295
+ label: "glsl",
1296
+ package: "prettier-plugin-glsl",
1297
+ hint: "Prettier for GLSL"
1298
+ },
1299
+ {
1300
+ value: "go-template",
1301
+ label: "go-template",
1302
+ package: "prettier-plugin-go-template",
1303
+ hint: "Prettier for Go Templates"
1304
+ },
1305
+ {
1306
+ value: "hugo",
1307
+ label: "hugo",
1308
+ package: "prettier-plugin-hugo-post",
1309
+ hint: "Prettier for Hugo"
1310
+ },
1311
+ {
1312
+ value: "java",
1313
+ label: "java",
1314
+ package: "prettier-plugin-java",
1315
+ hint: "Prettier for Java"
1316
+ },
1317
+ {
1318
+ value: "jinja",
1319
+ label: "jinja",
1320
+ package: "prettier-plugin-jinja-template",
1321
+ hint: "Prettier for Jinja"
1322
+ },
1323
+ {
1324
+ value: "jsonata",
1325
+ label: "jsonata",
1326
+ package: "prettier-plugin-jsonata",
1327
+ hint: "Prettier for JSONata"
1328
+ },
1329
+ {
1330
+ value: "kotlin",
1331
+ label: "kotlin",
1332
+ package: "prettier-plugin-kotlin",
1333
+ hint: "Prettier for Kotlin"
1334
+ },
1335
+ {
1336
+ value: "marko",
1337
+ label: "marko",
1338
+ package: "prettier-plugin-marko",
1339
+ hint: "Prettier for Marko"
1340
+ },
1341
+ {
1342
+ value: "motoko",
1343
+ label: "motoko",
1344
+ package: "prettier-plugin-motoko",
1345
+ hint: "Prettier for Motoko"
1346
+ },
1347
+ {
1348
+ value: "nginx",
1349
+ label: "nginx",
1350
+ package: "prettier-plugin-nginx",
1351
+ hint: "Prettier for Nginx"
1352
+ },
1353
+ {
1354
+ value: "prisma",
1355
+ label: "prisma",
1356
+ package: "prettier-plugin-prisma",
1357
+ hint: "Prettier for Prisma"
1358
+ },
1359
+ {
1360
+ value: "properties",
1361
+ label: "properties",
1362
+ package: "prettier-plugin-properties",
1363
+ hint: "Prettier for Properties"
1364
+ },
1365
+ {
1366
+ value: "rust",
1367
+ label: "rust",
1368
+ package: "prettier-plugin-rust",
1369
+ hint: "Prettier for Rust"
1370
+ },
1371
+ {
1372
+ value: "sh",
1373
+ label: "sh",
1374
+ package: "prettier-plugin-sh",
1375
+ hint: "Prettier for Shell"
1376
+ },
1377
+ {
1378
+ value: "sql",
1379
+ label: "sql",
1380
+ package: "prettier-plugin-sql",
1381
+ hint: "Prettier for SQL"
1382
+ },
1383
+ {
1384
+ value: "sql-cst",
1385
+ label: "sql-cst",
1386
+ package: "prettier-plugin-sql-cst",
1387
+ hint: "Prettier for SQL (CST)"
1388
+ },
1389
+ {
1390
+ value: "solidity",
1391
+ label: "solidity",
1392
+ package: "prettier-plugin-solidity",
1393
+ hint: "Prettier for Solidity"
1394
+ },
1395
+ {
1396
+ value: "svelte",
1397
+ label: "svelte",
1398
+ package: "prettier-plugin-svelte",
1399
+ hint: "Prettier for Svelte"
1400
+ },
1401
+ {
1402
+ value: "toml",
1403
+ label: "toml",
1404
+ package: "prettier-plugin-toml",
1405
+ hint: "Prettier for TOML"
1406
+ },
1407
+ {
1408
+ value: "xquery",
1409
+ label: "xquery",
1410
+ package: "prettier-plugin-xquery",
1411
+ hint: "Prettier for XQuery"
1412
+ },
1413
+ // Existing
1414
+ {
1415
+ value: "tailwindcss",
1416
+ label: "tailwindcss",
1417
+ package: "prettier-plugin-tailwindcss",
1418
+ hint: "Prettier for Tailwind CSS"
1419
+ },
1420
+ {
1421
+ value: "organize-imports",
1422
+ label: "organize-imports",
1423
+ package: "prettier-plugin-organize-imports",
1424
+ hint: "Organize imports"
1425
+ },
1426
+ {
1427
+ value: "sort-imports",
1428
+ label: "sort-imports",
1429
+ package: "@trivago/prettier-plugin-sort-imports",
1430
+ hint: "Sort imports"
1431
+ },
1432
+ {
1433
+ value: "pkg",
1434
+ label: "pkg",
1435
+ package: "prettier-plugin-pkg",
1436
+ hint: "Format package.json"
1437
+ }
1438
+ ];
1439
+ var PLUGINS = {
1440
+ eslint: ESLINT_PLUGINS,
1441
+ prettier: PRETTIER_PLUGINS
1442
+ };
1443
+ var PLUGINABLE_TOOLS = Object.keys(PLUGINS);
1444
+
1445
+ // src/features/linter/eslint.ts
1446
+ var import_fs_extra4 = __toESM(require("fs-extra"));
1447
+ async function installEslint() {
1448
+ const packages = ["eslint", "globals", "@eslint/js", "typescript-eslint"];
1449
+ await installPackages(packages, true);
1450
+ const configFile = await resolveConfigFile("ESLint", [
1451
+ "eslint.config.mjs",
1452
+ "eslint.config.js",
1453
+ "eslint.config.cjs"
1454
+ ]);
1455
+ if (!await import_fs_extra4.default.pathExists(configFile)) {
1456
+ await import_fs_extra4.default.writeFile(
1457
+ configFile,
1458
+ `import globals from "globals";
1459
+ import pluginJs from "@eslint/js";
1460
+ import tseslint from "typescript-eslint";
1461
+
1462
+
1463
+ export default [
1464
+ {files: ["**/*.{js,mjs,cjs,ts}"]},
1465
+ {languageOptions: { globals: globals.browser }},
1466
+ pluginJs.configs.recommended,
1467
+ ...tseslint.configs.recommended,
1468
+ ];`
1469
+ );
1470
+ }
1471
+ }
1472
+ async function configureEslintPlugins(plugins) {
1473
+ const configFile = await resolveConfigFile("ESLint", [
1474
+ "eslint.config.mjs",
1475
+ "eslint.config.js",
1476
+ "eslint.config.cjs"
1477
+ ]);
1478
+ if (!await import_fs_extra4.default.pathExists(configFile)) {
1479
+ return;
1480
+ }
1481
+ let configContent = await import_fs_extra4.default.readFile(configFile, "utf-8");
1482
+ const newImports = [];
1483
+ const newPluginConfigs = [];
1484
+ for (const pluginName of plugins) {
1485
+ const pluginDef = PLUGINS.eslint.find((p) => p.value === pluginName);
1486
+ const packageName = pluginDef?.package || `eslint-plugin-${pluginName}`;
1487
+ const safeVarName = pluginName.replace(/[^a-zA-Z0-9]/g, "") + "Plugin";
1488
+ if (!configContent.includes(`import ${safeVarName}`)) {
1489
+ newImports.push(`import ${safeVarName} from "${packageName}";`);
1490
+ }
1491
+ const shorPluginName = pluginName.replace(/^eslint-plugin-/, "");
1492
+ newPluginConfigs.push(`"${shorPluginName}": ${safeVarName}`);
1493
+ }
1494
+ if (newImports.length > 0) {
1495
+ const lastImportIndex = configContent.lastIndexOf("import ");
1496
+ const endOfLastImport = configContent.indexOf("\n", lastImportIndex) + 1;
1497
+ configContent = configContent.slice(0, endOfLastImport) + newImports.join("\n") + "\n" + configContent.slice(endOfLastImport);
1498
+ }
1499
+ if (newPluginConfigs.length > 0) {
1500
+ const exportDefaultStart = configContent.indexOf("export default [");
1501
+ if (exportDefaultStart !== -1) {
1502
+ const pluginsBlock = `
1503
+ {
1504
+ plugins: {
1505
+ ${newPluginConfigs.join(",\n ")}
1506
+ }
1507
+ },`;
1508
+ const insertPos = exportDefaultStart + "export default [".length;
1509
+ configContent = configContent.slice(0, insertPos) + pluginsBlock + configContent.slice(insertPos);
1510
+ }
1511
+ }
1512
+ await import_fs_extra4.default.writeFile(configFile, configContent);
1513
+ }
1514
+
1515
+ // src/steps/install-plugin.ts
1516
+ var import_prompts4 = require("@clack/prompts");
232
1517
  var import_picocolors2 = __toESM(require("picocolors"));
1518
+ async function installPlugins(tool) {
1519
+ const pluginsList = PLUGINS[tool];
1520
+ const selectedPlugins = await withCancelHandling(
1521
+ async () => (0, import_prompts4.multiselect)({
1522
+ message: `Select ${tool} plugins to install:`,
1523
+ options: pluginsList,
1524
+ required: true
1525
+ })
1526
+ );
1527
+ if (selectedPlugins.length === 0) {
1528
+ (0, import_prompts4.outro)(import_picocolors2.default.yellow("No plugins selected."));
1529
+ return;
1530
+ }
1531
+ const packagesToInstall = selectedPlugins.map((val) => {
1532
+ const p = pluginsList.find((opt) => opt.value === val);
1533
+ return p ? p.package : val;
1534
+ });
1535
+ (0, import_prompts4.outro)(
1536
+ import_picocolors2.default.blue(`Installing ${packagesToInstall.length} plugins for ${tool}...`)
1537
+ );
1538
+ await installPackages(packagesToInstall, true);
1539
+ await configurePlugins(tool, selectedPlugins);
1540
+ }
1541
+ async function configurePlugins(tool, plugins) {
1542
+ const shouldConfigure = await withCancelHandling(
1543
+ async () => (0, import_prompts4.confirm)({
1544
+ message: `Do you want to configure the selected plugins in your ${tool} config file?`,
1545
+ initialValue: true
1546
+ })
1547
+ );
1548
+ if (!shouldConfigure) {
1549
+ (0, import_prompts4.outro)(import_picocolors2.default.yellow("Skipping configuration."));
1550
+ return;
1551
+ }
1552
+ switch (tool) {
1553
+ case "prettier":
1554
+ await configurePrettierPlugins(plugins);
1555
+ (0, import_prompts4.outro)(import_picocolors2.default.green("Prettier plugins configured in .prettierrc"));
1556
+ break;
1557
+ case "eslint":
1558
+ await configureEslintPlugins(plugins);
1559
+ (0, import_prompts4.outro)(import_picocolors2.default.green("ESLint plugins configured in .eslintrc.json"));
1560
+ break;
1561
+ }
1562
+ }
1563
+
1564
+ // src/features/formatter.ts
233
1565
  async function promptFormatter(config2) {
234
1566
  const formatterConfig = config2.get("formatter");
235
- import_prompts3.log.message(import_picocolors2.default.bgBlue(import_picocolors2.default.black(" Formatter Configuration ")));
1567
+ import_prompts5.log.message(import_picocolors3.default.bgBlue(import_picocolors3.default.white(" Formatter Configuration ")));
236
1568
  const formatter = await withCancelHandling(
237
- async () => (0, import_prompts3.select)({
1569
+ async () => (0, import_prompts5.select)({
238
1570
  message: "Select a formatter:",
239
1571
  options: FORMATTER_OPTIONS,
240
1572
  initialValue: formatterConfig.options.choice
@@ -243,31 +1575,37 @@ async function promptFormatter(config2) {
243
1575
  formatterConfig.options = { choice: formatter };
244
1576
  }
245
1577
  async function installFormatter(config2) {
246
- const choice = config2.get("formatter").options.choice;
247
- if (choice === "prettier") {
248
- await installPackages(["prettier"], true);
249
- const configContent = {
250
- semi: true,
251
- singleQuote: true,
252
- trailingComma: "all",
253
- printWidth: 80,
254
- tabWidth: 2
255
- };
256
- await import_fs_extra2.default.writeJson(".prettierrc", configContent, { spaces: 2 });
257
- } else if (choice === "oxfmt") {
258
- await installPackages(["oxfmt"], true);
259
- }
1578
+ const formatter = config2.get("formatter").options.choice;
1579
+ if (!formatter) return;
1580
+ import_prompts5.log.message(import_picocolors3.default.white(import_picocolors3.default.bgBlack(` Installing ${formatter}... `)));
1581
+ if (formatter === "prettier") await installPrettier();
1582
+ else if (formatter === "oxfmt") await installOxfmt();
1583
+ if (!PLUGINABLE_TOOLS.includes(formatter)) return;
1584
+ const shouldConfigure = await withCancelHandling(
1585
+ async () => (0, import_prompts5.confirm)({
1586
+ message: `Do you want to install plugins for ${formatter}?`,
1587
+ initialValue: true
1588
+ })
1589
+ );
1590
+ if (!shouldConfigure) return;
1591
+ await installPlugins(formatter);
260
1592
  }
261
1593
 
262
- // src/services/linter.ts
263
- var import_prompts4 = require("@clack/prompts");
264
- var import_fs_extra3 = __toESM(require("fs-extra"));
265
- var import_picocolors3 = __toESM(require("picocolors"));
1594
+ // src/features/linter.ts
1595
+ var import_prompts6 = require("@clack/prompts");
1596
+ var import_picocolors4 = __toESM(require("picocolors"));
1597
+
1598
+ // src/features/linter/oxlint.ts
1599
+ async function installOxlint() {
1600
+ await installPackages(["oxlint@latest"], true);
1601
+ }
1602
+
1603
+ // src/features/linter.ts
266
1604
  async function promptLinter(config2) {
267
1605
  const linterConfig = config2.get("linter");
268
- import_prompts4.log.message(import_picocolors3.default.bgYellow(import_picocolors3.default.black(" Linter Configuration ")));
1606
+ import_prompts6.log.message(import_picocolors4.default.bgYellow(import_picocolors4.default.black(" Linter Configuration ")));
269
1607
  const linter = await withCancelHandling(
270
- async () => (0, import_prompts4.select)({
1608
+ async () => (0, import_prompts6.select)({
271
1609
  message: "Select a linter:",
272
1610
  options: LINTER_OPTIONS,
273
1611
  initialValue: linterConfig.options.choice
@@ -276,41 +1614,36 @@ async function promptLinter(config2) {
276
1614
  linterConfig.options = { choice: linter };
277
1615
  }
278
1616
  async function installLinter(config2) {
279
- const choice = config2.get("linter").options.choice;
280
- if (choice === "eslint") {
281
- await installPackages(["eslint"], true);
282
- const configContent = {
283
- extends: ["eslint:recommended"],
284
- env: {
285
- node: true,
286
- es2021: true
287
- },
288
- parserOptions: {
289
- ecmaVersion: "latest",
290
- sourceType: "module"
291
- }
292
- };
293
- await import_fs_extra3.default.writeJson(".eslintrc.json", configContent, { spaces: 2 });
294
- } else if (choice === "oxlint") {
295
- await installPackages(["oxlint"], true);
296
- }
1617
+ const linter = config2.get("linter").options.choice;
1618
+ if (!linter) return;
1619
+ import_prompts6.log.message(import_picocolors4.default.white(import_picocolors4.default.bgBlack(` Installing ${linter}... `)));
1620
+ if (linter === "eslint") await installEslint();
1621
+ else if (linter === "oxlint") await installOxlint();
1622
+ if (!PLUGINABLE_TOOLS.includes(linter)) return;
1623
+ const shouldConfigure = await withCancelHandling(
1624
+ async () => (0, import_prompts6.confirm)({
1625
+ message: `Do you want to install plugins for ${linter}?`,
1626
+ initialValue: true
1627
+ })
1628
+ );
1629
+ if (!shouldConfigure) return;
1630
+ await installPlugins(linter);
297
1631
  }
298
1632
 
299
- // src/services/lint-staged.ts
300
- var import_prompts5 = require("@clack/prompts");
301
- var import_fs_extra4 = __toESM(require("fs-extra"));
302
- var import_picocolors4 = __toESM(require("picocolors"));
1633
+ // src/features/lint-staged.ts
1634
+ var import_prompts7 = require("@clack/prompts");
1635
+ var import_picocolors5 = __toESM(require("picocolors"));
303
1636
  async function promptLintStaged(config2) {
304
- import_prompts5.log.message(import_picocolors4.default.bgGreen(import_picocolors4.default.black(" Lint-staged Configuration ")));
1637
+ import_prompts7.log.message(import_picocolors5.default.bgGreen(import_picocolors5.default.black(" Lint-staged Configuration ")));
305
1638
  const lintExtensions = await withCancelHandling(
306
- async () => (0, import_prompts5.multiselect)({
1639
+ async () => (0, import_prompts7.multiselect)({
307
1640
  message: "Select extensions to lint:",
308
1641
  options: LINT_STAGED_EXTENSIONS,
309
1642
  required: false
310
1643
  })
311
1644
  );
312
1645
  const formatExtensions = await withCancelHandling(
313
- async () => (0, import_prompts5.multiselect)({
1646
+ async () => (0, import_prompts7.multiselect)({
314
1647
  message: "Select extensions to format:",
315
1648
  options: LINT_STAGED_EXTENSIONS,
316
1649
  required: false
@@ -331,6 +1664,13 @@ async function promptLintStaged(config2) {
331
1664
  }
332
1665
  async function installLintStaged(config2) {
333
1666
  await installPackages(["lint-staged"], true);
1667
+ const configFile = await resolveConfigFile("Lint-Staged", [
1668
+ ".lintstagedrc",
1669
+ ".lintstagedrc.json",
1670
+ "lint-staged.config.js",
1671
+ ".lintstagedrc.js",
1672
+ ".lintstagedrc.mjs"
1673
+ ]);
334
1674
  const lintStagedConfig = {};
335
1675
  const lintStagedOptions = config2.get("lintStaged").options;
336
1676
  const lintExts = lintStagedOptions?.lintExtensions || [];
@@ -353,37 +1693,37 @@ async function installLintStaged(config2) {
353
1693
  lintStagedConfig[glob] = ["prettier --write"];
354
1694
  }
355
1695
  }
356
- await import_fs_extra4.default.writeJson(".lintstagedrc", lintStagedConfig, { spaces: 2 });
1696
+ await writeConfig(configFile, lintStagedConfig);
357
1697
  }
358
1698
 
359
- // src/services/env.ts
360
- var import_prompts6 = require("@clack/prompts");
1699
+ // src/features/env.ts
1700
+ var import_prompts8 = require("@clack/prompts");
361
1701
  var import_fs_extra5 = __toESM(require("fs-extra"));
362
1702
  var import_path = __toESM(require("path"));
363
- var import_picocolors5 = __toESM(require("picocolors"));
1703
+ var import_picocolors6 = __toESM(require("picocolors"));
364
1704
  async function promptEnv(config2) {
365
- import_prompts6.log.message(import_picocolors5.default.bgCyan(import_picocolors5.default.black(" Env Validation Configuration ")));
1705
+ import_prompts8.log.message(import_picocolors6.default.bgCyan(import_picocolors6.default.black(" Env Validation Configuration ")));
366
1706
  const variant = await withCancelHandling(
367
- async () => (0, import_prompts6.select)({
1707
+ async () => (0, import_prompts8.select)({
368
1708
  message: "Which @t3-oss/env variant?",
369
1709
  options: ENV_VARIANT_OPTIONS
370
1710
  })
371
1711
  );
372
1712
  const validator = await withCancelHandling(
373
- async () => (0, import_prompts6.select)({
1713
+ async () => (0, import_prompts8.select)({
374
1714
  message: "Which validator?",
375
1715
  options: ENV_VALIDATOR_OPTIONS
376
1716
  })
377
1717
  );
378
1718
  const installPresets = await withCancelHandling(
379
- async () => (0, import_prompts6.confirm)({
1719
+ async () => (0, import_prompts8.confirm)({
380
1720
  message: "Install presets?"
381
1721
  })
382
1722
  );
383
1723
  let presets;
384
1724
  if (installPresets) {
385
1725
  presets = await withCancelHandling(
386
- async () => (0, import_prompts6.multiselect)({
1726
+ async () => (0, import_prompts8.multiselect)({
387
1727
  message: "Select preset to extend:",
388
1728
  options: ENV_PRESET_OPTIONS,
389
1729
  required: false
@@ -391,13 +1731,13 @@ async function promptEnv(config2) {
391
1731
  );
392
1732
  }
393
1733
  const split = await withCancelHandling(
394
- async () => (0, import_prompts6.select)({
1734
+ async () => (0, import_prompts8.select)({
395
1735
  message: "Split or Joined env files?",
396
1736
  options: ENV_SPLIT_OPTIONS
397
1737
  })
398
1738
  );
399
1739
  const location = await withCancelHandling(
400
- async () => (0, import_prompts6.text)({
1740
+ async () => (0, import_prompts8.text)({
401
1741
  message: "Where should the environment files be created?",
402
1742
  initialValue: config2.get("env").options.location || "src/lib",
403
1743
  placeholder: "src/lib"
@@ -415,7 +1755,7 @@ async function promptEnv(config2) {
415
1755
  async function installEnv(config2) {
416
1756
  const envOptions = config2.get("env").options;
417
1757
  const { variant, validator, location, presets, split } = envOptions;
418
- await installPackages([variant, validator], true);
1758
+ await installPackages([variant, validator], false);
419
1759
  await import_fs_extra5.default.ensureDir(location);
420
1760
  const presetImport = presets && presets.length > 0 ? `// Presets: ${presets.join(", ")}
421
1761
  ` : "";
@@ -468,14 +1808,14 @@ export const env = createEnv({
468
1808
  }
469
1809
  }
470
1810
 
471
- // src/services/test.ts
472
- var import_prompts7 = require("@clack/prompts");
1811
+ // src/features/test.ts
1812
+ var import_prompts9 = require("@clack/prompts");
473
1813
  var import_fs_extra6 = __toESM(require("fs-extra"));
474
- var import_picocolors6 = __toESM(require("picocolors"));
1814
+ var import_picocolors7 = __toESM(require("picocolors"));
475
1815
  async function promptTest(config2) {
476
- import_prompts7.log.message(import_picocolors6.default.bgRed(import_picocolors6.default.black(" Test Runner Configuration ")));
1816
+ import_prompts9.log.message(import_picocolors7.default.bgRed(import_picocolors7.default.white(" Test Runner Configuration ")));
477
1817
  const runner = await withCancelHandling(
478
- async () => (0, import_prompts7.select)({
1818
+ async () => (0, import_prompts9.select)({
479
1819
  message: "Select a test runner:",
480
1820
  options: TEST_RUNNER_OPTIONS
481
1821
  })
@@ -517,15 +1857,15 @@ module.exports = {
517
1857
  }
518
1858
  }
519
1859
 
520
- // src/services/editor-config.ts
521
- var import_prompts8 = require("@clack/prompts");
1860
+ // src/features/editor-config.ts
1861
+ var import_prompts10 = require("@clack/prompts");
522
1862
  var import_fs_extra7 = __toESM(require("fs-extra"));
523
- var import_picocolors7 = __toESM(require("picocolors"));
1863
+ var import_picocolors8 = __toESM(require("picocolors"));
524
1864
  async function promptEditorConfig(config2) {
525
- import_prompts8.log.message(import_picocolors7.default.bgWhite(import_picocolors7.default.black(" EditorConfig Configuration ")));
1865
+ import_prompts10.log.message(import_picocolors8.default.bgWhite(import_picocolors8.default.black(" EditorConfig Configuration ")));
526
1866
  const currentPreset = config2.get("editorConfig").options.preset;
527
1867
  const preset = await withCancelHandling(
528
- async () => (0, import_prompts8.select)({
1868
+ async () => (0, import_prompts10.select)({
529
1869
  message: "Select EditorConfig preset:",
530
1870
  options: EDITOR_CONFIG_OPTIONS,
531
1871
  initialValue: currentPreset
@@ -546,37 +1886,37 @@ async function installEditorConfig(config2) {
546
1886
  await import_fs_extra7.default.outputFile(".editorconfig", content);
547
1887
  }
548
1888
 
549
- // src/services/license.ts
550
- var import_prompts9 = require("@clack/prompts");
1889
+ // src/features/license.ts
1890
+ var import_prompts11 = require("@clack/prompts");
551
1891
  var import_fs_extra8 = __toESM(require("fs-extra"));
552
1892
  var import_path2 = __toESM(require("path"));
553
- var import_picocolors8 = __toESM(require("picocolors"));
1893
+ var import_picocolors9 = __toESM(require("picocolors"));
554
1894
  async function promptLicense(config2) {
555
- import_prompts9.log.message(import_picocolors8.default.bgGreen(import_picocolors8.default.black(" License Configuration ")));
1895
+ import_prompts11.log.message(import_picocolors9.default.bgGreen(import_picocolors9.default.black(" License Configuration ")));
556
1896
  const licenseOptions = config2.get("license").options;
557
1897
  licenseOptions.name = await withCancelHandling(
558
- async () => (0, import_prompts9.text)({
1898
+ async () => (0, import_prompts11.text)({
559
1899
  message: "License Holder Name:",
560
1900
  placeholder: "John Doe",
561
1901
  initialValue: licenseOptions.name
562
1902
  })
563
1903
  );
564
1904
  licenseOptions.email = await withCancelHandling(
565
- async () => (0, import_prompts9.text)({
1905
+ async () => (0, import_prompts11.text)({
566
1906
  message: "License Holder Email:",
567
1907
  placeholder: "john@example.com",
568
1908
  initialValue: licenseOptions.email
569
1909
  })
570
1910
  );
571
1911
  licenseOptions.website = await withCancelHandling(
572
- async () => (0, import_prompts9.text)({
1912
+ async () => (0, import_prompts11.text)({
573
1913
  message: "License Holder Website:",
574
1914
  placeholder: "https://example.com",
575
1915
  initialValue: licenseOptions.website
576
1916
  })
577
1917
  );
578
1918
  licenseOptions.type = await withCancelHandling(
579
- async () => (0, import_prompts9.select)({
1919
+ async () => (0, import_prompts11.select)({
580
1920
  message: "Select License Type:",
581
1921
  options: LICENSE_TYPE_OPTIONS
582
1922
  })
@@ -611,8 +1951,8 @@ Licensed under ${type}`;
611
1951
  }
612
1952
  }
613
1953
 
614
- // src/config/config.ts
615
- var import_picocolors9 = __toESM(require("picocolors"));
1954
+ // src/core/config.ts
1955
+ var import_picocolors10 = __toESM(require("picocolors"));
616
1956
  var Config = class {
617
1957
  data;
618
1958
  constructor() {
@@ -641,7 +1981,7 @@ var Config = class {
641
1981
  installPresets: false,
642
1982
  presets: [],
643
1983
  split: "split",
644
- location: "src/env"
1984
+ location: "src/lib"
645
1985
  }
646
1986
  },
647
1987
  test: {
@@ -666,47 +2006,47 @@ var Config = class {
666
2006
  }
667
2007
  get summary() {
668
2008
  const lines = [];
669
- lines.push(import_picocolors9.default.bold("The following actions will be performed:"));
2009
+ lines.push(import_picocolors10.default.bold("The following actions will be performed:"));
670
2010
  lines.push("");
671
2011
  if (this.data.husky.selected) {
672
- lines.push(import_picocolors9.default.magenta(`\u2022 Install and configure Husky`));
2012
+ lines.push(import_picocolors10.default.magenta(`\u2022 Install and configure Husky`));
673
2013
  if (this.data.husky.options.hookType === "custom") {
674
- lines.push(import_picocolors9.default.dim(` - Custom hook script`));
2014
+ lines.push(import_picocolors10.default.dim(` - Custom hook script`));
675
2015
  }
676
2016
  }
677
2017
  if (this.data.formatter.selected) {
678
2018
  const choice = this.data.formatter.options.choice;
679
- lines.push(import_picocolors9.default.blue(`\u2022 Install and configure ${choice || "Formatter"}`));
2019
+ lines.push(import_picocolors10.default.blue(`\u2022 Install and configure ${choice || "Formatter"}`));
680
2020
  }
681
2021
  if (this.data.linter.selected) {
682
2022
  const choice = this.data.linter.options.choice;
683
- lines.push(import_picocolors9.default.yellow(`\u2022 Install and configure ${choice || "Linter"}`));
2023
+ lines.push(import_picocolors10.default.yellow(`\u2022 Install and configure ${choice || "Linter"}`));
684
2024
  }
685
2025
  if (this.data.lintStaged.selected) {
686
- lines.push(import_picocolors9.default.green(`\u2022 Install and configure Lint-staged`));
2026
+ lines.push(import_picocolors10.default.green(`\u2022 Install and configure Lint-staged`));
687
2027
  const lintExts = this.data.lintStaged.options.lintExtensions.join(", ");
688
2028
  const formatExts = this.data.lintStaged.options.formatExtensions.join(", ");
689
- if (lintExts) lines.push(import_picocolors9.default.dim(` - Lint: ${lintExts}`));
690
- if (formatExts) lines.push(import_picocolors9.default.dim(` - Format: ${formatExts}`));
2029
+ if (lintExts) lines.push(import_picocolors10.default.dim(` - Lint: ${lintExts}`));
2030
+ if (formatExts) lines.push(import_picocolors10.default.dim(` - Format: ${formatExts}`));
691
2031
  }
692
2032
  if (this.data.env.selected) {
693
- lines.push(import_picocolors9.default.cyan(`\u2022 Install and configure Env Validation`));
694
- lines.push(import_picocolors9.default.dim(` - Variant: ${this.data.env.options.variant}`));
695
- lines.push(import_picocolors9.default.dim(` - Validator: ${this.data.env.options.validator}`));
2033
+ lines.push(import_picocolors10.default.cyan(`\u2022 Install and configure Env Validation`));
2034
+ lines.push(import_picocolors10.default.dim(` - Variant: ${this.data.env.options.variant}`));
2035
+ lines.push(import_picocolors10.default.dim(` - Validator: ${this.data.env.options.validator}`));
696
2036
  }
697
2037
  if (this.data.test.selected) {
698
2038
  const runner = this.data.test.options.runner;
699
- lines.push(import_picocolors9.default.red(`\u2022 Install and configure Test Runner (${runner})`));
2039
+ lines.push(import_picocolors10.default.red(`\u2022 Install and configure Test Runner (${runner})`));
700
2040
  }
701
2041
  if (this.data.editorConfig.selected) {
702
2042
  const preset = this.data.editorConfig.options.preset;
703
- lines.push(import_picocolors9.default.white(`\u2022 Create .editorconfig (${preset})`));
2043
+ lines.push(import_picocolors10.default.white(`\u2022 Create .editorconfig (${preset})`));
704
2044
  }
705
2045
  if (this.data.license.selected) {
706
2046
  const type = this.data.license.options.type;
707
2047
  const name = this.data.license.options.name;
708
- lines.push(import_picocolors9.default.green(`\u2022 Create LICENSE (${type})`));
709
- lines.push(import_picocolors9.default.dim(` - Holder: ${name}`));
2048
+ lines.push(import_picocolors10.default.green(`\u2022 Create LICENSE (${type})`));
2049
+ lines.push(import_picocolors10.default.dim(` - Holder: ${name}`));
710
2050
  }
711
2051
  return lines.join("\n");
712
2052
  }
@@ -714,9 +2054,9 @@ var Config = class {
714
2054
  var config = new Config();
715
2055
 
716
2056
  // src/steps/execution.ts
717
- var import_prompts10 = require("@clack/prompts");
2057
+ var import_prompts12 = require("@clack/prompts");
718
2058
  async function execution(config2) {
719
- const s = (0, import_prompts10.spinner)();
2059
+ const s = (0, import_prompts12.spinner)();
720
2060
  if (config2.get("husky").selected) {
721
2061
  s.start("Setting up Husky...");
722
2062
  await installHusky(config2);
@@ -814,15 +2154,15 @@ async function commitChanges(message) {
814
2154
  }
815
2155
 
816
2156
  // src/steps/git-check.ts
817
- var import_prompts11 = require("@clack/prompts");
2157
+ var import_prompts13 = require("@clack/prompts");
818
2158
  async function gitCheck() {
819
2159
  if (await isGitRepository()) {
820
2160
  if (await isGitDirty()) {
821
- const shouldCommit = await (0, import_prompts11.confirm)({
2161
+ const shouldCommit = await (0, import_prompts13.confirm)({
822
2162
  message: "Your working directory is dirty. Would you like to commit changes before proceeding?"
823
2163
  });
824
2164
  if (shouldCommit) {
825
- const message = await (0, import_prompts11.text)({
2165
+ const message = await (0, import_prompts13.text)({
826
2166
  message: "Enter commit message:",
827
2167
  placeholder: "wip: pre-setup commit",
828
2168
  validate(value) {
@@ -830,7 +2170,7 @@ async function gitCheck() {
830
2170
  }
831
2171
  });
832
2172
  if (typeof message === "string") {
833
- const s = (0, import_prompts11.spinner)();
2173
+ const s = (0, import_prompts13.spinner)();
834
2174
  s.start("Committing changes...");
835
2175
  await commitChanges(message);
836
2176
  s.stop("Changes committed.");
@@ -841,13 +2181,13 @@ async function gitCheck() {
841
2181
  }
842
2182
 
843
2183
  // src/utils/display.ts
844
- var import_picocolors10 = __toESM(require("picocolors"));
2184
+ var import_picocolors11 = __toESM(require("picocolors"));
845
2185
  var import_figlet = __toESM(require("figlet"));
846
2186
 
847
2187
  // package.json
848
2188
  var package_default = {
849
2189
  name: "@mayrlabs/setup-project",
850
- version: "0.1.6",
2190
+ version: "0.1.8",
851
2191
  description: "Interactive CLI to setup project tools",
852
2192
  private: false,
853
2193
  publishConfig: {
@@ -889,7 +2229,8 @@ var package_default = {
889
2229
  main: "dist/index.js",
890
2230
  scripts: {
891
2231
  build: "tsup",
892
- demo: "tsx src/index.ts",
2232
+ demo: "tsx src/cli/index.ts",
2233
+ test: "vitest",
893
2234
  prepublishOnly: "npm run build"
894
2235
  },
895
2236
  dependencies: {
@@ -905,9 +2246,11 @@ var package_default = {
905
2246
  "@types/figlet": "^1.7.0",
906
2247
  "@types/fs-extra": "^11.0.4",
907
2248
  "@types/node": "^20.11.16",
2249
+ "@vitest/coverage-v8": "^4.0.18",
908
2250
  tsup: "^8.5.1",
909
2251
  tsx: "^4.21.0",
910
- typescript: "^5.3.3"
2252
+ typescript: "^5.3.3",
2253
+ vitest: "^4.0.18"
911
2254
  }
912
2255
  };
913
2256
 
@@ -915,7 +2258,7 @@ var package_default = {
915
2258
  function introScreen() {
916
2259
  console.log();
917
2260
  console.log(
918
- import_picocolors10.default.cyan(
2261
+ import_picocolors11.default.cyan(
919
2262
  import_figlet.default.textSync("MayR\nLabs", {
920
2263
  font: "Graceful",
921
2264
  horizontalLayout: "default",
@@ -925,39 +2268,41 @@ function introScreen() {
925
2268
  })
926
2269
  )
927
2270
  );
928
- console.log(import_picocolors10.default.cyan(`@mayrlabs/setup-project v${package_default.version}`));
2271
+ console.log(import_picocolors11.default.cyan(`${package_default.name} - v${package_default.version}`));
929
2272
  console.log();
930
2273
  }
931
2274
  function showAbout() {
932
2275
  introScreen();
933
- console.log(import_picocolors10.default.bold("About:"));
2276
+ console.log(import_picocolors11.default.bold("About:"));
934
2277
  console.log(
935
2278
  " Interactive CLI to setup project tools like Husky, Prettier, ESLint, etc."
936
2279
  );
937
2280
  console.log("");
938
- console.log(import_picocolors10.default.bold("How to use:"));
2281
+ console.log(import_picocolors11.default.bold("How to use:"));
939
2282
  console.log(
940
2283
  " Run 'npx @mayrlabs/setup-project' and follow the interactive prompts."
941
2284
  );
942
2285
  console.log("");
943
2286
  }
944
2287
  function showVisit() {
945
- console.log(import_picocolors10.default.bold("Project Homepage:"));
946
- console.log(import_picocolors10.default.underline(import_picocolors10.default.cyan(package_default.homepage)));
2288
+ console.log(import_picocolors11.default.bold("Project Homepage:"));
2289
+ console.log(import_picocolors11.default.underline(import_picocolors11.default.cyan(package_default.homepage)));
947
2290
  console.log("");
948
2291
  }
949
2292
  function showManual() {
950
2293
  introScreen();
951
- console.log(import_picocolors10.default.bold("Usage:"));
2294
+ console.log(import_picocolors11.default.bold("Usage:"));
952
2295
  console.log(" npx @mayrlabs/setup-project [command] [options]");
953
2296
  console.log("");
954
- console.log(import_picocolors10.default.bold("Commands:"));
2297
+ console.log(import_picocolors11.default.bold("Commands:"));
955
2298
  console.log(" about Show project details");
956
2299
  console.log(" version Show version information");
957
2300
  console.log(" visit Visit project homepage");
958
2301
  console.log(" help Show this help message");
2302
+ console.log(" configure [tool] Configure a specific tool");
2303
+ console.log(" plugin [tool] Manage plugins for tools");
959
2304
  console.log("");
960
- console.log(import_picocolors10.default.bold("Options:"));
2305
+ console.log(import_picocolors11.default.bold("Options:"));
961
2306
  console.log(" -a, --about Show project details");
962
2307
  console.log(" -v, --version Show version information");
963
2308
  console.log(" -V, --visit Visit project homepage");
@@ -965,16 +2310,109 @@ function showManual() {
965
2310
  console.log("");
966
2311
  }
967
2312
 
968
- // src/index.ts
2313
+ // src/cli/commands/configure.ts
2314
+ var import_prompts14 = require("@clack/prompts");
2315
+ var import_picocolors12 = __toESM(require("picocolors"));
2316
+ async function configure(toolName) {
2317
+ introScreen();
2318
+ (0, import_prompts14.intro)(import_picocolors12.default.inverse(import_picocolors12.default.bold(import_picocolors12.default.blue(" Configuration Mode "))));
2319
+ await gitCheck();
2320
+ let selectedTool;
2321
+ if (toolName) {
2322
+ const tool = TOOL_OPTIONS.find((t) => t.value === toolName);
2323
+ if (tool) {
2324
+ selectedTool = tool.value;
2325
+ } else {
2326
+ console.log(
2327
+ import_picocolors12.default.yellow(`Tool '${toolName}' not found or not configurable.`)
2328
+ );
2329
+ }
2330
+ }
2331
+ if (!selectedTool) {
2332
+ const selection = await withCancelHandling(
2333
+ async () => (0, import_prompts14.select)({
2334
+ message: "Select a tool to configure:",
2335
+ options: TOOL_OPTIONS
2336
+ })
2337
+ );
2338
+ selectedTool = selection;
2339
+ }
2340
+ config.enableTool(selectedTool);
2341
+ try {
2342
+ switch (selectedTool) {
2343
+ case "husky":
2344
+ await promptHusky(config);
2345
+ await installHusky(config);
2346
+ break;
2347
+ case "formatter":
2348
+ await promptFormatter(config);
2349
+ await installFormatter(config);
2350
+ break;
2351
+ case "linter":
2352
+ await promptLinter(config);
2353
+ await installLinter(config);
2354
+ break;
2355
+ case "lintStaged":
2356
+ await promptLintStaged(config);
2357
+ await installLintStaged(config);
2358
+ break;
2359
+ case "env":
2360
+ await promptEnv(config);
2361
+ await installEnv(config);
2362
+ break;
2363
+ case "test":
2364
+ await promptTest(config);
2365
+ await installTest(config);
2366
+ break;
2367
+ case "editorConfig":
2368
+ await promptEditorConfig(config);
2369
+ await installEditorConfig(config);
2370
+ break;
2371
+ case "license":
2372
+ await promptLicense(config);
2373
+ await installLicense(config);
2374
+ break;
2375
+ }
2376
+ (0, import_prompts14.outro)(import_picocolors12.default.green(`${selectedTool} configured successfully!`));
2377
+ } catch (error) {
2378
+ (0, import_prompts14.outro)(import_picocolors12.default.red(`Failed to configure ${selectedTool}.`));
2379
+ console.error(error);
2380
+ process.exit(1);
2381
+ }
2382
+ }
2383
+
2384
+ // src/cli/commands/plugin.ts
2385
+ var import_prompts15 = require("@clack/prompts");
2386
+ var import_picocolors13 = __toESM(require("picocolors"));
2387
+ async function plugin(toolName) {
2388
+ introScreen();
2389
+ (0, import_prompts15.intro)(import_picocolors13.default.inverse(import_picocolors13.default.bold(import_picocolors13.default.magenta(" Plugin Manager "))));
2390
+ await gitCheck();
2391
+ if (!toolName) {
2392
+ toolName = await withCancelHandling(
2393
+ async () => (0, import_prompts15.select)({
2394
+ message: "Select a tool to add plugins to:",
2395
+ options: [
2396
+ { value: "eslint", label: "ESLint" },
2397
+ { value: "prettier", label: "Prettier" }
2398
+ ]
2399
+ })
2400
+ );
2401
+ }
2402
+ await installPlugins(toolName);
2403
+ (0, import_prompts15.outro)(import_picocolors13.default.green("Plugins installed successfully!"));
2404
+ }
2405
+
2406
+ // src/cli/index.ts
969
2407
  async function main() {
970
2408
  try {
971
2409
  introScreen();
972
- (0, import_prompts12.intro)(
973
- import_picocolors11.default.inverse(import_picocolors11.default.bold(import_picocolors11.default.cyan(" Welcome to the Project Setup Wizard ")))
2410
+ (0, import_prompts16.intro)(
2411
+ import_picocolors14.default.inverse(import_picocolors14.default.bold(import_picocolors14.default.cyan(" Welcome to the Project Setup Wizard ")))
974
2412
  );
975
2413
  await gitCheck();
976
2414
  const tools = await withCancelHandling(
977
- async () => (0, import_prompts12.multiselect)({
2415
+ async () => (0, import_prompts16.multiselect)({
978
2416
  message: "Select tools to configure:",
979
2417
  options: TOOL_OPTIONS,
980
2418
  required: false
@@ -989,21 +2427,21 @@ async function main() {
989
2427
  if (config.get("test").selected) await promptTest(config);
990
2428
  if (config.get("editorConfig").selected) await promptEditorConfig(config);
991
2429
  if (config.get("license").selected) await promptLicense(config);
992
- (0, import_prompts12.note)(config.summary, "Configuration Summary");
2430
+ (0, import_prompts16.note)(config.summary, "Configuration Summary");
993
2431
  const proceed = await withCancelHandling(
994
- async () => (0, import_prompts12.confirm)({
2432
+ async () => (0, import_prompts16.confirm)({
995
2433
  message: "Do you want to proceed with the installation?"
996
2434
  })
997
2435
  );
998
2436
  if (!proceed) {
999
- (0, import_prompts12.outro)(import_picocolors11.default.yellow("Installation cancelled."));
2437
+ (0, import_prompts16.outro)(import_picocolors14.default.yellow("Installation cancelled."));
1000
2438
  process.exit(0);
1001
2439
  }
1002
2440
  await execution(config);
1003
- (0, import_prompts12.outro)(import_picocolors11.default.green("Setup complete!"));
2441
+ (0, import_prompts16.outro)(import_picocolors14.default.green("Setup complete!"));
1004
2442
  } catch (error) {
1005
2443
  const logPath = await logError(error);
1006
- (0, import_prompts12.outro)(import_picocolors11.default.red(`
2444
+ (0, import_prompts16.outro)(import_picocolors14.default.red(`
1007
2445
  Something went wrong!
1008
2446
  Error log saved to: ${logPath}`));
1009
2447
  process.exit(1);
@@ -1027,6 +2465,14 @@ import_commander.program.command("help").action(() => {
1027
2465
  showManual();
1028
2466
  process.exit(0);
1029
2467
  });
2468
+ import_commander.program.command("configure [tool]").description("Configure a specific tool").action(async (tool) => {
2469
+ await configure(tool);
2470
+ process.exit(0);
2471
+ });
2472
+ import_commander.program.command("plugin [tool]").description("Manage plugins for tools").action(async (tool) => {
2473
+ await plugin(tool);
2474
+ process.exit(0);
2475
+ });
1030
2476
  import_commander.program.action(async (options) => {
1031
2477
  if (options.about) {
1032
2478
  showAbout();