create-esa-stack 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +23 -476
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -367,9 +367,6 @@ function hD(e, u) {
|
|
|
367
367
|
return s;
|
|
368
368
|
}
|
|
369
369
|
var V = Symbol("clack:cancel");
|
|
370
|
-
function lD(e) {
|
|
371
|
-
return e === V;
|
|
372
|
-
}
|
|
373
370
|
function v(e, u) {
|
|
374
371
|
e.isTTY && e.setRawMode(u);
|
|
375
372
|
}
|
|
@@ -458,24 +455,6 @@ class x {
|
|
|
458
455
|
}
|
|
459
456
|
}
|
|
460
457
|
}
|
|
461
|
-
|
|
462
|
-
class BD extends x {
|
|
463
|
-
get cursor() {
|
|
464
|
-
return this.value ? 0 : 1;
|
|
465
|
-
}
|
|
466
|
-
get _value() {
|
|
467
|
-
return this.cursor === 0;
|
|
468
|
-
}
|
|
469
|
-
constructor(u) {
|
|
470
|
-
super(u, false), this.value = !!u.initialValue, this.on("value", () => {
|
|
471
|
-
this.value = this._value;
|
|
472
|
-
}), this.on("confirm", (F) => {
|
|
473
|
-
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = F, this.state = "submit", this.close();
|
|
474
|
-
}), this.on("cursor", () => {
|
|
475
|
-
this.value = !this.value;
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
458
|
var TD = Object.defineProperty;
|
|
480
459
|
var jD = (e, u, F) => (u in e) ? TD(e, u, { enumerable: true, configurable: true, writable: true, value: F }) : e[u] = F;
|
|
481
460
|
var MD = (e, u, F) => (jD(e, typeof u != "symbol" ? u + "" : u, F), F);
|
|
@@ -584,38 +563,6 @@ ${import_picocolors2.default.cyan($2)}
|
|
|
584
563
|
`;
|
|
585
564
|
}
|
|
586
565
|
} }).prompt();
|
|
587
|
-
var ce = (s) => {
|
|
588
|
-
const n = s.active ?? "Yes", t = s.inactive ?? "No";
|
|
589
|
-
return new BD({ active: n, inactive: t, initialValue: s.initialValue ?? true, render() {
|
|
590
|
-
const i = `${import_picocolors2.default.gray(a2)}
|
|
591
|
-
${y2(this.state)} ${s.message}
|
|
592
|
-
`, r2 = this.value ? n : t;
|
|
593
|
-
switch (this.state) {
|
|
594
|
-
case "submit":
|
|
595
|
-
return `${i}${import_picocolors2.default.gray(a2)} ${import_picocolors2.default.dim(r2)}`;
|
|
596
|
-
case "cancel":
|
|
597
|
-
return `${i}${import_picocolors2.default.gray(a2)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(r2))}
|
|
598
|
-
${import_picocolors2.default.gray(a2)}`;
|
|
599
|
-
default:
|
|
600
|
-
return `${i}${import_picocolors2.default.cyan(a2)} ${this.value ? `${import_picocolors2.default.green(I2)} ${n}` : `${import_picocolors2.default.dim(T2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(T2)} ${import_picocolors2.default.dim(t)}` : `${import_picocolors2.default.green(I2)} ${t}`}
|
|
601
|
-
${import_picocolors2.default.cyan($2)}
|
|
602
|
-
`;
|
|
603
|
-
}
|
|
604
|
-
} }).prompt();
|
|
605
|
-
};
|
|
606
|
-
var R2 = (s) => s.replace(ye(), "");
|
|
607
|
-
var me = (s = "", n = "") => {
|
|
608
|
-
const t = `
|
|
609
|
-
${s}
|
|
610
|
-
`.split(`
|
|
611
|
-
`), i = R2(n).length, r2 = Math.max(t.reduce((c2, l2) => (l2 = R2(l2), l2.length > c2 ? l2.length : c2), 0), i) + 2, o = t.map((c2) => `${import_picocolors2.default.gray(a2)} ${import_picocolors2.default.dim(c2)}${" ".repeat(r2 - R2(c2).length)}${import_picocolors2.default.gray(a2)}`).join(`
|
|
612
|
-
`);
|
|
613
|
-
process.stdout.write(`${import_picocolors2.default.gray(a2)}
|
|
614
|
-
${import_picocolors2.default.green(M2)} ${import_picocolors2.default.reset(n)} ${import_picocolors2.default.gray(G.repeat(Math.max(r2 - i - 1, 1)) + H)}
|
|
615
|
-
${o}
|
|
616
|
-
${import_picocolors2.default.gray(ee + G.repeat(r2 + 2) + te)}
|
|
617
|
-
`);
|
|
618
|
-
};
|
|
619
566
|
var he = (s = "") => {
|
|
620
567
|
process.stdout.write(`${import_picocolors2.default.gray($2)} ${import_picocolors2.default.red(s)}
|
|
621
568
|
|
|
@@ -631,29 +578,6 @@ ${import_picocolors2.default.gray($2)} ${s}
|
|
|
631
578
|
|
|
632
579
|
`);
|
|
633
580
|
};
|
|
634
|
-
var v2 = { message: (s = "", { symbol: n = import_picocolors2.default.gray(a2) } = {}) => {
|
|
635
|
-
const t = [`${import_picocolors2.default.gray(a2)}`];
|
|
636
|
-
if (s) {
|
|
637
|
-
const [i, ...r2] = s.split(`
|
|
638
|
-
`);
|
|
639
|
-
t.push(`${n} ${i}`, ...r2.map((o) => `${import_picocolors2.default.gray(a2)} ${o}`));
|
|
640
|
-
}
|
|
641
|
-
process.stdout.write(`${t.join(`
|
|
642
|
-
`)}
|
|
643
|
-
`);
|
|
644
|
-
}, info: (s) => {
|
|
645
|
-
v2.message(s, { symbol: import_picocolors2.default.blue(se) });
|
|
646
|
-
}, success: (s) => {
|
|
647
|
-
v2.message(s, { symbol: import_picocolors2.default.green(re) });
|
|
648
|
-
}, step: (s) => {
|
|
649
|
-
v2.message(s, { symbol: import_picocolors2.default.green(M2) });
|
|
650
|
-
}, warn: (s) => {
|
|
651
|
-
v2.message(s, { symbol: import_picocolors2.default.yellow(ie) });
|
|
652
|
-
}, warning: (s) => {
|
|
653
|
-
v2.warn(s);
|
|
654
|
-
}, error: (s) => {
|
|
655
|
-
v2.message(s, { symbol: import_picocolors2.default.red(ne) });
|
|
656
|
-
} };
|
|
657
581
|
var _2 = () => {
|
|
658
582
|
const s = C ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], n = C ? 80 : 120;
|
|
659
583
|
let t, i, r2 = false, o = "";
|
|
@@ -682,414 +606,37 @@ var _2 = () => {
|
|
|
682
606
|
o = g2 ?? o;
|
|
683
607
|
} };
|
|
684
608
|
};
|
|
685
|
-
function ye() {
|
|
686
|
-
const s = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
|
|
687
|
-
return new RegExp(s, "g");
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
// src/utils/process.ts
|
|
691
|
-
import { spawn } from "child_process";
|
|
692
|
-
async function executeCommand(command, args, options = {}) {
|
|
693
|
-
return new Promise((resolve) => {
|
|
694
|
-
const child = spawn(command, args, {
|
|
695
|
-
cwd: options.cwd || process.cwd(),
|
|
696
|
-
env: { ...process.env, ...options.env },
|
|
697
|
-
stdio: "inherit"
|
|
698
|
-
});
|
|
699
|
-
let output = "";
|
|
700
|
-
let errorOutput = "";
|
|
701
|
-
child.on("close", (code) => {
|
|
702
|
-
resolve({
|
|
703
|
-
success: code === 0,
|
|
704
|
-
code,
|
|
705
|
-
output,
|
|
706
|
-
error: errorOutput || undefined
|
|
707
|
-
});
|
|
708
|
-
});
|
|
709
|
-
child.on("error", (error) => {
|
|
710
|
-
resolve({
|
|
711
|
-
success: false,
|
|
712
|
-
code: null,
|
|
713
|
-
output,
|
|
714
|
-
error: error.message
|
|
715
|
-
});
|
|
716
|
-
});
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
async function runCreateNextApp(projectName, options = {}) {
|
|
720
|
-
const args = [
|
|
721
|
-
"create-next-app@latest",
|
|
722
|
-
projectName,
|
|
723
|
-
"--ts",
|
|
724
|
-
"--tailwind",
|
|
725
|
-
"--biome",
|
|
726
|
-
"--react-compiler",
|
|
727
|
-
"--app",
|
|
728
|
-
"--use-pnpm",
|
|
729
|
-
"--turbopack",
|
|
730
|
-
"--yes"
|
|
731
|
-
];
|
|
732
|
-
return executeCommand("npx", args, options);
|
|
733
|
-
}
|
|
734
609
|
|
|
735
|
-
// src/
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
if (result.success) {
|
|
742
|
-
s.stop(`✓ Project created successfully!`);
|
|
743
|
-
return true;
|
|
744
|
-
} else {
|
|
745
|
-
s.stop(`✗ Failed to create project`);
|
|
746
|
-
if (result.error) {
|
|
747
|
-
v2.error(result.error);
|
|
748
|
-
}
|
|
749
|
-
return false;
|
|
750
|
-
}
|
|
751
|
-
} catch (error) {
|
|
752
|
-
s.stop(`✗ Failed to create project`);
|
|
753
|
-
v2.error(error instanceof Error ? error.message : "Unknown error occurred");
|
|
754
|
-
return false;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
// src/generators/react-query.ts
|
|
759
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
760
|
-
import { join } from "path";
|
|
761
|
-
async function setupReactQuery(config) {
|
|
762
|
-
const s = _2();
|
|
763
|
-
s.start("Setting up @tanstack/react-query...");
|
|
764
|
-
try {
|
|
765
|
-
const projectPath = config.projectPath;
|
|
766
|
-
s.message("Installing @tanstack/react-query...");
|
|
767
|
-
const installResult = await executeCommand("pnpm", ["add", "@tanstack/react-query"], { cwd: projectPath });
|
|
768
|
-
if (!installResult.success) {
|
|
769
|
-
s.stop("✗ Failed to install @tanstack/react-query");
|
|
770
|
-
return false;
|
|
771
|
-
}
|
|
772
|
-
s.message("Creating RootProviders component...");
|
|
773
|
-
const providersDir = join(projectPath, "src", "components", "templates", "RootProviders");
|
|
774
|
-
if (!existsSync(providersDir)) {
|
|
775
|
-
mkdirSync(providersDir, { recursive: true });
|
|
776
|
-
}
|
|
777
|
-
const providersPath = join(providersDir, "RootProviders.component.tsx");
|
|
778
|
-
const providersTemplate = `'use client'
|
|
779
|
-
|
|
780
|
-
// Since QueryClientProvider relies on useContext under the hood, we have to put 'use client' on top
|
|
781
|
-
import {
|
|
782
|
-
isServer,
|
|
783
|
-
QueryClient,
|
|
784
|
-
QueryClientProvider,
|
|
785
|
-
} from '@tanstack/react-query'
|
|
786
|
-
import { useState } from 'react'
|
|
787
|
-
|
|
788
|
-
function makeQueryClient() {
|
|
789
|
-
return new QueryClient({
|
|
790
|
-
defaultOptions: {
|
|
791
|
-
queries: {
|
|
792
|
-
// With SSR, we usually want to set some default staleTime
|
|
793
|
-
// above 0 to avoid refetching immediately on the client
|
|
794
|
-
staleTime: 60 * 1000,
|
|
795
|
-
},
|
|
796
|
-
},
|
|
797
|
-
})
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
let browserQueryClient: QueryClient | undefined = undefined
|
|
801
|
-
|
|
802
|
-
function getQueryClient() {
|
|
803
|
-
if (isServer) {
|
|
804
|
-
// Server: always make a new query client
|
|
805
|
-
return makeQueryClient()
|
|
806
|
-
} else {
|
|
807
|
-
// Browser: make a new query client if we don't already have one
|
|
808
|
-
// This is very important, so we don't re-make a new client if React
|
|
809
|
-
// suspends during the initial render. This may not be needed if we
|
|
810
|
-
// have a suspense boundary BELOW the creation of the query client
|
|
811
|
-
if (!browserQueryClient) browserQueryClient = makeQueryClient()
|
|
812
|
-
return browserQueryClient
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
export default function RootProviders({ children }: { children: React.ReactNode }) {
|
|
817
|
-
// NOTE: Avoid useState when initializing the query client if you don't
|
|
818
|
-
// have a suspense boundary between this and the code that may
|
|
819
|
-
// suspend because React will throw away the client on the initial
|
|
820
|
-
// render if it suspends and there is no boundary
|
|
821
|
-
const queryClient = getQueryClient()
|
|
822
|
-
|
|
823
|
-
return (
|
|
824
|
-
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
825
|
-
)
|
|
826
|
-
}
|
|
827
|
-
`;
|
|
828
|
-
writeFileSync(providersPath, providersTemplate);
|
|
829
|
-
s.message("Updating root layout...");
|
|
830
|
-
const layoutPath = join(projectPath, "src", "app", "layout.tsx");
|
|
831
|
-
if (existsSync(layoutPath)) {
|
|
832
|
-
let layoutContent = readFileSync(layoutPath, "utf-8");
|
|
833
|
-
const importStatement = `import RootProviders from "@/components/templates/RootProviders/RootProviders.component";
|
|
834
|
-
`;
|
|
835
|
-
if (!layoutContent.includes("RootProviders")) {
|
|
836
|
-
const importRegex = /(import.*from.*;\n)+/;
|
|
837
|
-
layoutContent = layoutContent.replace(importRegex, (match) => match + importStatement);
|
|
838
|
-
layoutContent = layoutContent.replace(/(<body[^>]*>)([\s\S]*?)(<\/body>)/, (match, openTag, content, closeTag) => {
|
|
839
|
-
if (content.includes("<RootProviders>")) {
|
|
840
|
-
return match;
|
|
841
|
-
}
|
|
842
|
-
return `${openTag}
|
|
843
|
-
<RootProviders>${content}</RootProviders>
|
|
844
|
-
${closeTag}`;
|
|
845
|
-
});
|
|
846
|
-
writeFileSync(layoutPath, layoutContent);
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
s.stop("✓ React Query setup complete!");
|
|
850
|
-
return true;
|
|
851
|
-
} catch (error) {
|
|
852
|
-
s.stop("✗ Failed to set up React Query");
|
|
853
|
-
v2.error(error instanceof Error ? error.message : "Unknown error occurred");
|
|
854
|
-
return false;
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
// src/generators/resend.ts
|
|
859
|
-
async function setupResend(config) {
|
|
860
|
-
const s = _2();
|
|
861
|
-
s.start("Setting up Resend...");
|
|
862
|
-
try {
|
|
863
|
-
const projectPath = config.projectPath;
|
|
864
|
-
s.message("Installing resend package...");
|
|
865
|
-
const result = await executeCommand("pnpm", ["add", "resend"], { cwd: projectPath });
|
|
866
|
-
if (result.success) {
|
|
867
|
-
s.stop("✓ Resend setup complete!");
|
|
868
|
-
return true;
|
|
869
|
-
} else {
|
|
870
|
-
s.stop("✗ Failed to install Resend");
|
|
871
|
-
if (result.error) {
|
|
872
|
-
v2.error(result.error);
|
|
873
|
-
}
|
|
874
|
-
return false;
|
|
875
|
-
}
|
|
876
|
-
} catch (error) {
|
|
877
|
-
s.stop("✗ Failed to set up Resend");
|
|
878
|
-
v2.error(error instanceof Error ? error.message : "Unknown error occurred");
|
|
879
|
-
return false;
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
// src/generators/shadcn.ts
|
|
884
|
-
async function setupShadcn(config) {
|
|
885
|
-
const s = _2();
|
|
886
|
-
s.start("Setting up shadcn/ui...");
|
|
887
|
-
try {
|
|
888
|
-
const projectPath = config.projectPath;
|
|
889
|
-
s.message("Running shadcn init...");
|
|
890
|
-
const result = await executeCommand("pnpm", ["dlx", "shadcn@latest", "init", "-y"], { cwd: projectPath });
|
|
891
|
-
if (result.success) {
|
|
892
|
-
s.stop("✓ shadcn/ui setup complete!");
|
|
893
|
-
return true;
|
|
894
|
-
} else {
|
|
895
|
-
s.stop("✗ Failed to set up shadcn/ui");
|
|
896
|
-
if (result.error) {
|
|
897
|
-
v2.error(result.error);
|
|
898
|
-
}
|
|
899
|
-
return false;
|
|
900
|
-
}
|
|
901
|
-
} catch (error) {
|
|
902
|
-
s.stop("✗ Failed to set up shadcn/ui");
|
|
903
|
-
v2.error(error instanceof Error ? error.message : "Unknown error occurred");
|
|
904
|
-
return false;
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
// src/utils/file-system.ts
|
|
909
|
-
import { join as join2, resolve } from "path";
|
|
910
|
-
function resolvePath(path) {
|
|
911
|
-
return resolve(process.cwd(), path);
|
|
912
|
-
}
|
|
913
|
-
function getProjectPath(projectName, targetDir) {
|
|
914
|
-
if (targetDir) {
|
|
915
|
-
return resolvePath(join2(targetDir, projectName));
|
|
916
|
-
}
|
|
917
|
-
return resolvePath(projectName);
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
// src/utils/validators.ts
|
|
921
|
-
import { existsSync as existsSync2 } from "fs";
|
|
922
|
-
function isValidProjectName(name) {
|
|
923
|
-
const validNameRegex = /^(?![@._])[a-z0-9-_]+$/;
|
|
924
|
-
if (!name || name.length === 0) {
|
|
925
|
-
return false;
|
|
926
|
-
}
|
|
927
|
-
if (name.length > 214) {
|
|
928
|
-
return false;
|
|
929
|
-
}
|
|
930
|
-
return validNameRegex.test(name);
|
|
931
|
-
}
|
|
932
|
-
function getProjectNameValidationMessage(name) {
|
|
933
|
-
if (!name || name.length === 0) {
|
|
934
|
-
return "Project name cannot be empty";
|
|
935
|
-
}
|
|
936
|
-
if (name.length > 214) {
|
|
937
|
-
return "Project name must be 214 characters or less";
|
|
938
|
-
}
|
|
939
|
-
if (name.startsWith(".") || name.startsWith("_")) {
|
|
940
|
-
return "Project name cannot start with . or _";
|
|
941
|
-
}
|
|
942
|
-
if (!/^[a-z0-9-_]+$/.test(name)) {
|
|
943
|
-
return "Project name can only contain lowercase letters, numbers, hyphens, and underscores";
|
|
944
|
-
}
|
|
945
|
-
return "Invalid project name";
|
|
946
|
-
}
|
|
947
|
-
function directoryExists(path) {
|
|
948
|
-
return existsSync2(path);
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
// src/prompts.ts
|
|
952
|
-
async function promptForProjectConfig() {
|
|
953
|
-
console.log("");
|
|
954
|
-
pe("\uD83D\uDE80 Create ESA Stack");
|
|
610
|
+
// src/cli.ts
|
|
611
|
+
import { execSync } from "node:child_process";
|
|
612
|
+
import { existsSync } from "node:fs";
|
|
613
|
+
import { join } from "node:path";
|
|
614
|
+
async function main() {
|
|
615
|
+
pe("Welcome to ESA Stack Generator");
|
|
955
616
|
const projectName = await ae({
|
|
956
|
-
message: "What is your project
|
|
957
|
-
placeholder: "my-
|
|
958
|
-
validate
|
|
959
|
-
if (
|
|
960
|
-
return
|
|
961
|
-
|
|
617
|
+
message: "What is the name of your project?",
|
|
618
|
+
placeholder: "my-app",
|
|
619
|
+
validate(value) {
|
|
620
|
+
if (value.length === 0)
|
|
621
|
+
return "Project name is required";
|
|
622
|
+
if (existsSync(join(process.cwd(), value)))
|
|
623
|
+
return "Directory already exists";
|
|
962
624
|
}
|
|
963
625
|
});
|
|
964
|
-
if (
|
|
965
|
-
he("Operation cancelled");
|
|
966
|
-
|
|
967
|
-
}
|
|
968
|
-
const projectPath = getProjectPath(projectName);
|
|
969
|
-
if (directoryExists(projectPath)) {
|
|
970
|
-
const shouldContinue = await ce({
|
|
971
|
-
message: `Directory "${projectName}" already exists. Continue anyway?`,
|
|
972
|
-
initialValue: false
|
|
973
|
-
});
|
|
974
|
-
if (lD(shouldContinue) || !shouldContinue) {
|
|
975
|
-
he("Operation cancelled");
|
|
976
|
-
return null;
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
console.log("");
|
|
980
|
-
me("Select optional integrations to add to your project", "Optional Integrations");
|
|
981
|
-
const reactQuery = await ce({
|
|
982
|
-
message: "Add @tanstack/react-query for data fetching?",
|
|
983
|
-
initialValue: true
|
|
984
|
-
});
|
|
985
|
-
if (lD(reactQuery)) {
|
|
986
|
-
he("Operation cancelled");
|
|
987
|
-
return null;
|
|
988
|
-
}
|
|
989
|
-
const shadcn = await ce({
|
|
990
|
-
message: "Add shadcn/ui component library?",
|
|
991
|
-
initialValue: true
|
|
992
|
-
});
|
|
993
|
-
if (lD(shadcn)) {
|
|
994
|
-
he("Operation cancelled");
|
|
995
|
-
return null;
|
|
996
|
-
}
|
|
997
|
-
const resend = await ce({
|
|
998
|
-
message: "Add Resend for email API?",
|
|
999
|
-
initialValue: false
|
|
1000
|
-
});
|
|
1001
|
-
if (lD(resend)) {
|
|
1002
|
-
he("Operation cancelled");
|
|
1003
|
-
return null;
|
|
626
|
+
if (typeof projectName === "symbol") {
|
|
627
|
+
he("Operation cancelled.");
|
|
628
|
+
process.exit(0);
|
|
1004
629
|
}
|
|
1005
|
-
const integrations = {
|
|
1006
|
-
reactQuery,
|
|
1007
|
-
shadcn,
|
|
1008
|
-
resend
|
|
1009
|
-
};
|
|
1010
630
|
const s = _2();
|
|
1011
|
-
s.start("
|
|
1012
|
-
|
|
1013
|
-
s.stop("Configuration ready!");
|
|
1014
|
-
const integrationsText = [
|
|
1015
|
-
integrations.reactQuery && " ✓ @tanstack/react-query",
|
|
1016
|
-
integrations.shadcn && " ✓ shadcn/ui",
|
|
1017
|
-
integrations.resend && " ✓ resend"
|
|
1018
|
-
].filter(Boolean).join(`
|
|
1019
|
-
`);
|
|
1020
|
-
console.log("");
|
|
1021
|
-
me(`Project: ${projectName}
|
|
1022
|
-
Path: ${projectPath}
|
|
1023
|
-
|
|
1024
|
-
Default Tech Stack:
|
|
1025
|
-
✓ Next.js (App Router)
|
|
1026
|
-
✓ TypeScript
|
|
1027
|
-
✓ Tailwind CSS
|
|
1028
|
-
✓ Biome.js
|
|
1029
|
-
✓ React Compiler
|
|
1030
|
-
✓ Turbopack
|
|
1031
|
-
✓ pnpm${integrationsText ? `
|
|
1032
|
-
|
|
1033
|
-
Optional Integrations:
|
|
1034
|
-
${integrationsText}` : ""}`, "Configuration");
|
|
1035
|
-
const shouldProceed = await ce({
|
|
1036
|
-
message: "Create project with this configuration?",
|
|
1037
|
-
initialValue: true
|
|
1038
|
-
});
|
|
1039
|
-
if (lD(shouldProceed) || !shouldProceed) {
|
|
1040
|
-
he("Operation cancelled");
|
|
1041
|
-
return null;
|
|
1042
|
-
}
|
|
1043
|
-
return {
|
|
1044
|
-
projectName,
|
|
1045
|
-
projectPath,
|
|
1046
|
-
integrations
|
|
1047
|
-
};
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
// src/cli.ts
|
|
1051
|
-
async function main() {
|
|
631
|
+
s.start("Scaffolding project...");
|
|
632
|
+
const command = `npx create-next-app@latest ${projectName} --biome --ts --tailwind --react-compiler --app --src-dir --import-alias "@/*" --use-pnpm --turbopack --skip-install --yes`;
|
|
1052
633
|
try {
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
}
|
|
1057
|
-
const success = await generateNextJsProject(config);
|
|
1058
|
-
if (!success) {
|
|
1059
|
-
ge("❌ Project creation failed");
|
|
1060
|
-
process.exit(1);
|
|
1061
|
-
}
|
|
1062
|
-
if (config.integrations.reactQuery) {
|
|
1063
|
-
const reactQuerySuccess = await setupReactQuery(config);
|
|
1064
|
-
if (!reactQuerySuccess) {
|
|
1065
|
-
v2.warn("React Query setup failed, but project was created successfully");
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
if (config.integrations.shadcn) {
|
|
1069
|
-
const shadcnSuccess = await setupShadcn(config);
|
|
1070
|
-
if (!shadcnSuccess) {
|
|
1071
|
-
v2.warn("shadcn/ui setup failed, but project was created successfully");
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
if (config.integrations.resend) {
|
|
1075
|
-
const resendSuccess = await setupResend(config);
|
|
1076
|
-
if (!resendSuccess) {
|
|
1077
|
-
v2.warn("Resend setup failed, but project was created successfully");
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
console.log("");
|
|
1081
|
-
ge("\uD83C\uDF89 Project created successfully!");
|
|
1082
|
-
const nextSteps = [
|
|
1083
|
-
`cd ${config.projectName}`,
|
|
1084
|
-
config.integrations.reactQuery ? "# React Query is ready to use!" : "",
|
|
1085
|
-
"pnpm dev"
|
|
1086
|
-
].filter(Boolean).join(`
|
|
1087
|
-
`);
|
|
1088
|
-
console.log("");
|
|
1089
|
-
me(nextSteps, "Next steps");
|
|
1090
|
-
process.exit(0);
|
|
634
|
+
s.stop("Starting scaffolding...");
|
|
635
|
+
execSync(command, { stdio: "inherit" });
|
|
636
|
+
ge(`Successfully created ${projectName}!`);
|
|
1091
637
|
} catch (error) {
|
|
1092
|
-
|
|
638
|
+
s.stop("Failed to scaffold project.");
|
|
639
|
+
console.error(error);
|
|
1093
640
|
process.exit(1);
|
|
1094
641
|
}
|
|
1095
642
|
}
|