create-better-fullstack 1.4.0 → 1.4.2
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.mjs +1 -1
- package/dist/index.d.mts +85 -2
- package/dist/index.mjs +1 -1
- package/dist/{src-p54ND5wJ.mjs → src-B5kV0Yns.mjs} +543 -465
- package/package.json +3 -3
|
@@ -13,6 +13,7 @@ import { ECOSYSTEM_GROUPS, EMBEDDED_TEMPLATES, EMBEDDED_TEMPLATES as EMBEDDED_TE
|
|
|
13
13
|
import gradient from "gradient-string";
|
|
14
14
|
import path$1 from "path";
|
|
15
15
|
import { writeTreeToFilesystem } from "@better-fullstack/template-generator/fs-writer";
|
|
16
|
+
import { allowedApisForFrontends, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleUILibraries, hasWebStyling, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isWebFrontend, requiresChatSdkVercelAIForSelection, splitFrontends, validateAddonCompatibility } from "@better-fullstack/types";
|
|
16
17
|
import consola, { consola as consola$1 } from "consola";
|
|
17
18
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
18
19
|
import { ConfirmPrompt, GroupMultiSelectPrompt, MultiSelectPrompt, SelectPrompt, isCancel as isCancel$1 } from "@clack/core";
|
|
@@ -74,6 +75,13 @@ const DEFAULT_CONFIG_BASE = {
|
|
|
74
75
|
serverDeploy: "none",
|
|
75
76
|
cssFramework: "tailwind",
|
|
76
77
|
uiLibrary: "shadcn-ui",
|
|
78
|
+
shadcnBase: "radix",
|
|
79
|
+
shadcnStyle: "nova",
|
|
80
|
+
shadcnIconLibrary: "lucide",
|
|
81
|
+
shadcnColorTheme: "neutral",
|
|
82
|
+
shadcnBaseColor: "neutral",
|
|
83
|
+
shadcnFont: "inter",
|
|
84
|
+
shadcnRadius: "default",
|
|
77
85
|
rustWebFramework: "none",
|
|
78
86
|
rustFrontend: "none",
|
|
79
87
|
rustOrm: "none",
|
|
@@ -107,254 +115,6 @@ function getDefaultConfig() {
|
|
|
107
115
|
};
|
|
108
116
|
}
|
|
109
117
|
const DEFAULT_CONFIG = getDefaultConfig();
|
|
110
|
-
const ADDON_COMPATIBILITY = {
|
|
111
|
-
pwa: [
|
|
112
|
-
"tanstack-router",
|
|
113
|
-
"react-router",
|
|
114
|
-
"solid",
|
|
115
|
-
"next",
|
|
116
|
-
"astro",
|
|
117
|
-
"qwik",
|
|
118
|
-
"angular",
|
|
119
|
-
"redwood",
|
|
120
|
-
"fresh"
|
|
121
|
-
],
|
|
122
|
-
tauri: [
|
|
123
|
-
"tanstack-router",
|
|
124
|
-
"react-router",
|
|
125
|
-
"nuxt",
|
|
126
|
-
"svelte",
|
|
127
|
-
"solid",
|
|
128
|
-
"next",
|
|
129
|
-
"astro",
|
|
130
|
-
"qwik",
|
|
131
|
-
"angular",
|
|
132
|
-
"redwood",
|
|
133
|
-
"fresh"
|
|
134
|
-
],
|
|
135
|
-
biome: [],
|
|
136
|
-
husky: [],
|
|
137
|
-
lefthook: [],
|
|
138
|
-
turborepo: [],
|
|
139
|
-
starlight: [],
|
|
140
|
-
ultracite: [],
|
|
141
|
-
ruler: [],
|
|
142
|
-
mcp: [],
|
|
143
|
-
skills: [],
|
|
144
|
-
oxlint: [],
|
|
145
|
-
fumadocs: [],
|
|
146
|
-
opentui: [],
|
|
147
|
-
wxt: [],
|
|
148
|
-
msw: [],
|
|
149
|
-
storybook: [
|
|
150
|
-
"tanstack-router",
|
|
151
|
-
"react-router",
|
|
152
|
-
"next",
|
|
153
|
-
"nuxt",
|
|
154
|
-
"svelte",
|
|
155
|
-
"solid"
|
|
156
|
-
],
|
|
157
|
-
none: []
|
|
158
|
-
};
|
|
159
|
-
/**
|
|
160
|
-
* UI Library compatibility rules
|
|
161
|
-
* Defines which frontends and CSS frameworks each UI library supports
|
|
162
|
-
*/
|
|
163
|
-
const UI_LIBRARY_COMPATIBILITY = {
|
|
164
|
-
"shadcn-ui": {
|
|
165
|
-
frontends: [
|
|
166
|
-
"tanstack-router",
|
|
167
|
-
"react-router",
|
|
168
|
-
"tanstack-start",
|
|
169
|
-
"next",
|
|
170
|
-
"astro"
|
|
171
|
-
],
|
|
172
|
-
cssFrameworks: ["tailwind"]
|
|
173
|
-
},
|
|
174
|
-
daisyui: {
|
|
175
|
-
frontends: [
|
|
176
|
-
"tanstack-router",
|
|
177
|
-
"react-router",
|
|
178
|
-
"tanstack-start",
|
|
179
|
-
"next",
|
|
180
|
-
"nuxt",
|
|
181
|
-
"svelte",
|
|
182
|
-
"solid",
|
|
183
|
-
"astro",
|
|
184
|
-
"qwik",
|
|
185
|
-
"angular",
|
|
186
|
-
"redwood",
|
|
187
|
-
"fresh"
|
|
188
|
-
],
|
|
189
|
-
cssFrameworks: ["tailwind"]
|
|
190
|
-
},
|
|
191
|
-
"radix-ui": {
|
|
192
|
-
frontends: [
|
|
193
|
-
"tanstack-router",
|
|
194
|
-
"react-router",
|
|
195
|
-
"tanstack-start",
|
|
196
|
-
"next",
|
|
197
|
-
"astro"
|
|
198
|
-
],
|
|
199
|
-
cssFrameworks: [
|
|
200
|
-
"tailwind",
|
|
201
|
-
"scss",
|
|
202
|
-
"less",
|
|
203
|
-
"postcss-only",
|
|
204
|
-
"none"
|
|
205
|
-
]
|
|
206
|
-
},
|
|
207
|
-
"headless-ui": {
|
|
208
|
-
frontends: [
|
|
209
|
-
"tanstack-router",
|
|
210
|
-
"react-router",
|
|
211
|
-
"tanstack-start",
|
|
212
|
-
"next",
|
|
213
|
-
"nuxt",
|
|
214
|
-
"astro"
|
|
215
|
-
],
|
|
216
|
-
cssFrameworks: [
|
|
217
|
-
"tailwind",
|
|
218
|
-
"scss",
|
|
219
|
-
"less",
|
|
220
|
-
"postcss-only",
|
|
221
|
-
"none"
|
|
222
|
-
]
|
|
223
|
-
},
|
|
224
|
-
"park-ui": {
|
|
225
|
-
frontends: [
|
|
226
|
-
"tanstack-router",
|
|
227
|
-
"react-router",
|
|
228
|
-
"tanstack-start",
|
|
229
|
-
"next",
|
|
230
|
-
"nuxt",
|
|
231
|
-
"solid",
|
|
232
|
-
"astro"
|
|
233
|
-
],
|
|
234
|
-
cssFrameworks: [
|
|
235
|
-
"tailwind",
|
|
236
|
-
"scss",
|
|
237
|
-
"less",
|
|
238
|
-
"postcss-only"
|
|
239
|
-
]
|
|
240
|
-
},
|
|
241
|
-
"chakra-ui": {
|
|
242
|
-
frontends: [
|
|
243
|
-
"tanstack-router",
|
|
244
|
-
"react-router",
|
|
245
|
-
"tanstack-start",
|
|
246
|
-
"next",
|
|
247
|
-
"astro"
|
|
248
|
-
],
|
|
249
|
-
cssFrameworks: [
|
|
250
|
-
"tailwind",
|
|
251
|
-
"scss",
|
|
252
|
-
"less",
|
|
253
|
-
"postcss-only",
|
|
254
|
-
"none"
|
|
255
|
-
]
|
|
256
|
-
},
|
|
257
|
-
nextui: {
|
|
258
|
-
frontends: [
|
|
259
|
-
"tanstack-router",
|
|
260
|
-
"react-router",
|
|
261
|
-
"tanstack-start",
|
|
262
|
-
"next",
|
|
263
|
-
"astro"
|
|
264
|
-
],
|
|
265
|
-
cssFrameworks: ["tailwind"]
|
|
266
|
-
},
|
|
267
|
-
mantine: {
|
|
268
|
-
frontends: [
|
|
269
|
-
"tanstack-router",
|
|
270
|
-
"react-router",
|
|
271
|
-
"tanstack-start",
|
|
272
|
-
"next",
|
|
273
|
-
"astro"
|
|
274
|
-
],
|
|
275
|
-
cssFrameworks: [
|
|
276
|
-
"tailwind",
|
|
277
|
-
"scss",
|
|
278
|
-
"less",
|
|
279
|
-
"postcss-only",
|
|
280
|
-
"none"
|
|
281
|
-
]
|
|
282
|
-
},
|
|
283
|
-
"base-ui": {
|
|
284
|
-
frontends: [
|
|
285
|
-
"tanstack-router",
|
|
286
|
-
"react-router",
|
|
287
|
-
"tanstack-start",
|
|
288
|
-
"next",
|
|
289
|
-
"astro"
|
|
290
|
-
],
|
|
291
|
-
cssFrameworks: [
|
|
292
|
-
"tailwind",
|
|
293
|
-
"scss",
|
|
294
|
-
"less",
|
|
295
|
-
"postcss-only",
|
|
296
|
-
"none"
|
|
297
|
-
]
|
|
298
|
-
},
|
|
299
|
-
"ark-ui": {
|
|
300
|
-
frontends: [
|
|
301
|
-
"tanstack-router",
|
|
302
|
-
"react-router",
|
|
303
|
-
"tanstack-start",
|
|
304
|
-
"next",
|
|
305
|
-
"nuxt",
|
|
306
|
-
"svelte",
|
|
307
|
-
"solid",
|
|
308
|
-
"astro"
|
|
309
|
-
],
|
|
310
|
-
cssFrameworks: [
|
|
311
|
-
"tailwind",
|
|
312
|
-
"scss",
|
|
313
|
-
"less",
|
|
314
|
-
"postcss-only",
|
|
315
|
-
"none"
|
|
316
|
-
]
|
|
317
|
-
},
|
|
318
|
-
"react-aria": {
|
|
319
|
-
frontends: [
|
|
320
|
-
"tanstack-router",
|
|
321
|
-
"react-router",
|
|
322
|
-
"tanstack-start",
|
|
323
|
-
"next",
|
|
324
|
-
"astro"
|
|
325
|
-
],
|
|
326
|
-
cssFrameworks: [
|
|
327
|
-
"tailwind",
|
|
328
|
-
"scss",
|
|
329
|
-
"less",
|
|
330
|
-
"postcss-only",
|
|
331
|
-
"none"
|
|
332
|
-
]
|
|
333
|
-
},
|
|
334
|
-
none: {
|
|
335
|
-
frontends: [
|
|
336
|
-
"tanstack-router",
|
|
337
|
-
"react-router",
|
|
338
|
-
"tanstack-start",
|
|
339
|
-
"next",
|
|
340
|
-
"nuxt",
|
|
341
|
-
"svelte",
|
|
342
|
-
"solid",
|
|
343
|
-
"astro",
|
|
344
|
-
"qwik",
|
|
345
|
-
"angular",
|
|
346
|
-
"redwood",
|
|
347
|
-
"fresh"
|
|
348
|
-
],
|
|
349
|
-
cssFrameworks: [
|
|
350
|
-
"tailwind",
|
|
351
|
-
"scss",
|
|
352
|
-
"less",
|
|
353
|
-
"postcss-only",
|
|
354
|
-
"none"
|
|
355
|
-
]
|
|
356
|
-
}
|
|
357
|
-
};
|
|
358
118
|
/**
|
|
359
119
|
* Default UI library for each frontend framework
|
|
360
120
|
* Falls back based on what's compatible
|
|
@@ -367,6 +127,7 @@ const DEFAULT_UI_LIBRARY_BY_FRONTEND = {
|
|
|
367
127
|
nuxt: "daisyui",
|
|
368
128
|
svelte: "daisyui",
|
|
369
129
|
solid: "daisyui",
|
|
130
|
+
"solid-start": "daisyui",
|
|
370
131
|
astro: "daisyui",
|
|
371
132
|
qwik: "daisyui",
|
|
372
133
|
angular: "daisyui",
|
|
@@ -719,23 +480,6 @@ var types_exports = {};
|
|
|
719
480
|
import * as import__better_fullstack_types from "@better-fullstack/types";
|
|
720
481
|
__reExport(types_exports, import__better_fullstack_types);
|
|
721
482
|
|
|
722
|
-
//#endregion
|
|
723
|
-
//#region src/utils/compatibility.ts
|
|
724
|
-
const WEB_FRAMEWORKS = [
|
|
725
|
-
"tanstack-router",
|
|
726
|
-
"react-router",
|
|
727
|
-
"tanstack-start",
|
|
728
|
-
"next",
|
|
729
|
-
"nuxt",
|
|
730
|
-
"svelte",
|
|
731
|
-
"solid",
|
|
732
|
-
"astro",
|
|
733
|
-
"qwik",
|
|
734
|
-
"angular",
|
|
735
|
-
"redwood",
|
|
736
|
-
"fresh"
|
|
737
|
-
];
|
|
738
|
-
|
|
739
483
|
//#endregion
|
|
740
484
|
//#region src/utils/context.ts
|
|
741
485
|
const cliStorage = new AsyncLocalStorage();
|
|
@@ -883,17 +627,14 @@ function constraintError(opts) {
|
|
|
883
627
|
|
|
884
628
|
//#endregion
|
|
885
629
|
//#region src/utils/compatibility-rules.ts
|
|
886
|
-
function isWebFrontend(value) {
|
|
887
|
-
return
|
|
630
|
+
function isWebFrontend$1(value) {
|
|
631
|
+
return isWebFrontend(value);
|
|
888
632
|
}
|
|
889
|
-
function splitFrontends(values = []) {
|
|
890
|
-
return
|
|
891
|
-
web: values.filter((f) => isWebFrontend(f)),
|
|
892
|
-
native: values.filter((f) => f === "native-bare" || f === "native-uniwind" || f === "native-unistyles")
|
|
893
|
-
};
|
|
633
|
+
function splitFrontends$1(values = []) {
|
|
634
|
+
return splitFrontends(values);
|
|
894
635
|
}
|
|
895
636
|
function ensureSingleWebAndNative(frontends) {
|
|
896
|
-
const { web, native } = splitFrontends(frontends);
|
|
637
|
+
const { web, native } = splitFrontends$1(frontends);
|
|
897
638
|
if (web.length > 1) invalidSelectionError({
|
|
898
639
|
message: "Only one web framework can be selected per project.",
|
|
899
640
|
provided: { frontend: web },
|
|
@@ -909,18 +650,20 @@ const FULLSTACK_FRONTENDS$1 = [
|
|
|
909
650
|
"next",
|
|
910
651
|
"tanstack-start",
|
|
911
652
|
"astro",
|
|
912
|
-
"nuxt"
|
|
653
|
+
"nuxt",
|
|
654
|
+
"svelte",
|
|
655
|
+
"solid-start"
|
|
913
656
|
];
|
|
914
657
|
function validateSelfBackendCompatibility(providedFlags, options, config) {
|
|
915
658
|
const backend = config.backend || options.backend;
|
|
916
659
|
const frontends = config.frontend || options.frontend || [];
|
|
917
660
|
if (backend === "self") {
|
|
918
|
-
const { web, native } = splitFrontends(frontends);
|
|
919
|
-
if (!(web.length === 1 && FULLSTACK_FRONTENDS$1.includes(web[0]))) exitWithError("Backend 'self' (fullstack) only supports Next.js, TanStack Start, Astro, or
|
|
661
|
+
const { web, native } = splitFrontends$1(frontends);
|
|
662
|
+
if (!(web.length === 1 && FULLSTACK_FRONTENDS$1.includes(web[0]))) exitWithError("Backend 'self' (fullstack) only supports Next.js, TanStack Start, Astro, Nuxt, SvelteKit, or SolidStart frontends. Please use --frontend next, --frontend tanstack-start, --frontend astro, --frontend nuxt, --frontend svelte, or --frontend solid-start.");
|
|
920
663
|
if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-bare, native-uniwind, native-unistyles");
|
|
921
664
|
}
|
|
922
665
|
const hasFullstackFrontend = frontends.some((f) => FULLSTACK_FRONTENDS$1.includes(f));
|
|
923
|
-
if (providedFlags.has("backend") && !hasFullstackFrontend && backend === "self") exitWithError("Backend 'self' (fullstack) only supports Next.js, TanStack Start, Astro, or
|
|
666
|
+
if (providedFlags.has("backend") && !hasFullstackFrontend && backend === "self") exitWithError("Backend 'self' (fullstack) only supports Next.js, TanStack Start, Astro, Nuxt, SvelteKit, or SolidStart frontends. Please use --frontend next, --frontend tanstack-start, --frontend astro, --frontend nuxt, --frontend svelte, --frontend solid-start, or choose a different backend.");
|
|
924
667
|
}
|
|
925
668
|
const WORKERS_COMPATIBLE_BACKENDS = [
|
|
926
669
|
"hono",
|
|
@@ -983,9 +726,10 @@ function validateApiFrontendCompatibility(api, frontends = [], astroIntegration)
|
|
|
983
726
|
const includesAngular = frontends.includes("angular");
|
|
984
727
|
const includesRedwood = frontends.includes("redwood");
|
|
985
728
|
const includesFresh = frontends.includes("fresh");
|
|
986
|
-
|
|
729
|
+
const includesSolidStart = frontends.includes("solid-start");
|
|
730
|
+
if ((includesNuxt || includesSvelte || includesSolid || includesSolidStart) && (api === "trpc" || api === "ts-rest" || api === "garph")) {
|
|
987
731
|
const apiName = api === "trpc" ? "tRPC" : api === "ts-rest" ? "ts-rest" : "garph";
|
|
988
|
-
const incompatibleFrontend = includesNuxt ? "nuxt" : includesSvelte ? "svelte" : "solid";
|
|
732
|
+
const incompatibleFrontend = includesNuxt ? "nuxt" : includesSvelte ? "svelte" : includesSolid ? "solid" : "solid-start";
|
|
989
733
|
incompatibilityError({
|
|
990
734
|
message: `${apiName} API requires React-based frontends.`,
|
|
991
735
|
provided: {
|
|
@@ -1044,36 +788,8 @@ function validateApiFrontendCompatibility(api, frontends = [], astroIntegration)
|
|
|
1044
788
|
]
|
|
1045
789
|
});
|
|
1046
790
|
}
|
|
1047
|
-
function isFrontendAllowedWithBackend(frontend, backend, auth) {
|
|
1048
|
-
|
|
1049
|
-
if (backend === "convex" && frontend === "astro") return false;
|
|
1050
|
-
if (backend === "convex" && frontend === "qwik") return false;
|
|
1051
|
-
if (backend === "convex" && frontend === "angular") return false;
|
|
1052
|
-
if (backend === "convex" && frontend === "redwood") return false;
|
|
1053
|
-
if (backend === "convex" && frontend === "fresh") return false;
|
|
1054
|
-
if (frontend === "qwik" && backend && backend !== "none") return false;
|
|
1055
|
-
if (frontend === "angular" && backend && backend !== "none") return false;
|
|
1056
|
-
if (frontend === "redwood" && backend && backend !== "none") return false;
|
|
1057
|
-
if (frontend === "fresh" && backend && backend !== "none") return false;
|
|
1058
|
-
if (auth === "clerk" && backend === "convex") {
|
|
1059
|
-
if ([
|
|
1060
|
-
"nuxt",
|
|
1061
|
-
"svelte",
|
|
1062
|
-
"solid"
|
|
1063
|
-
].includes(frontend)) return false;
|
|
1064
|
-
}
|
|
1065
|
-
if (auth === "clerk" && backend === "self") {
|
|
1066
|
-
if (!["next", "tanstack-start"].includes(frontend)) return false;
|
|
1067
|
-
}
|
|
1068
|
-
if (auth === "nextauth") {
|
|
1069
|
-
if (frontend !== "next") return false;
|
|
1070
|
-
if (backend !== "self") return false;
|
|
1071
|
-
}
|
|
1072
|
-
if (auth === "supabase-auth") {
|
|
1073
|
-
if (frontend !== "next") return false;
|
|
1074
|
-
if (backend !== "self") return false;
|
|
1075
|
-
}
|
|
1076
|
-
return true;
|
|
791
|
+
function isFrontendAllowedWithBackend$1(frontend, backend, auth) {
|
|
792
|
+
return isFrontendAllowedWithBackend(frontend, backend, auth);
|
|
1077
793
|
}
|
|
1078
794
|
function validateClerkCompatibility(auth, backend, frontends = []) {
|
|
1079
795
|
if (auth !== "clerk") return;
|
|
@@ -1081,7 +797,8 @@ function validateClerkCompatibility(auth, backend, frontends = []) {
|
|
|
1081
797
|
const incompatibleFrontends = frontends.filter((f) => [
|
|
1082
798
|
"nuxt",
|
|
1083
799
|
"svelte",
|
|
1084
|
-
"solid"
|
|
800
|
+
"solid",
|
|
801
|
+
"solid-start"
|
|
1085
802
|
].includes(f));
|
|
1086
803
|
if (incompatibleFrontends.length > 0) exitWithError(`In Better-Fullstack, Clerk + Convex is not compatible with the following frontends: ${incompatibleFrontends.join(", ")}. Please choose a different frontend or auth provider.`);
|
|
1087
804
|
return;
|
|
@@ -1097,6 +814,8 @@ function validateClerkCompatibility(auth, backend, frontends = []) {
|
|
|
1097
814
|
if (!hasNextJs && !hasTanStackStart) {
|
|
1098
815
|
if (frontends.includes("astro")) exitWithError("In Better-Fullstack, Clerk is not yet supported for Astro fullstack projects. Please use '--frontend next' or '--frontend tanstack-start' with '--backend self', or choose a different auth provider.");
|
|
1099
816
|
if (frontends.includes("nuxt")) exitWithError("In Better-Fullstack, Clerk is not yet supported for Nuxt fullstack projects. Please use '--frontend next' or '--frontend tanstack-start' with '--backend self', or choose a different auth provider.");
|
|
817
|
+
if (frontends.includes("svelte")) exitWithError("In Better-Fullstack, Clerk is not yet supported for SvelteKit fullstack projects. Please use '--frontend next' or '--frontend tanstack-start' with '--backend self', or choose a different auth provider.");
|
|
818
|
+
if (frontends.includes("solid-start")) exitWithError("In Better-Fullstack, Clerk is not yet supported for SolidStart fullstack projects. Please use '--frontend next' or '--frontend tanstack-start' with '--backend self', or choose a different auth provider.");
|
|
1100
819
|
exitWithError("In Better-Fullstack, Clerk with the 'self' backend currently requires the Next.js or TanStack Start frontend. Please use '--frontend next' or '--frontend tanstack-start', or choose a different auth provider.");
|
|
1101
820
|
}
|
|
1102
821
|
return;
|
|
@@ -1127,56 +846,17 @@ function validateAuth0Compatibility(auth, backend, frontends = []) {
|
|
|
1127
846
|
if (backend !== "self") exitWithError("In Better-Fullstack, Auth0 is currently supported only with the 'self' backend (fullstack Next.js). Please use '--backend self' or choose a different auth provider.");
|
|
1128
847
|
if (!hasNextJs) exitWithError("In Better-Fullstack, Auth0 currently requires the Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
|
|
1129
848
|
}
|
|
1130
|
-
function allowedApisForFrontends(frontends = [], astroIntegration) {
|
|
1131
|
-
|
|
1132
|
-
const includesSvelte = frontends.includes("svelte");
|
|
1133
|
-
const includesSolid = frontends.includes("solid");
|
|
1134
|
-
const includesAstro = frontends.includes("astro");
|
|
1135
|
-
const includesQwik = frontends.includes("qwik");
|
|
1136
|
-
const includesAngular = frontends.includes("angular");
|
|
1137
|
-
const includesRedwood = frontends.includes("redwood");
|
|
1138
|
-
const includesFresh = frontends.includes("fresh");
|
|
1139
|
-
const base = [
|
|
1140
|
-
"trpc",
|
|
1141
|
-
"orpc",
|
|
1142
|
-
"ts-rest",
|
|
1143
|
-
"garph",
|
|
1144
|
-
"none"
|
|
1145
|
-
];
|
|
1146
|
-
if (includesQwik) return ["none"];
|
|
1147
|
-
if (includesAngular) return ["none"];
|
|
1148
|
-
if (includesRedwood) return ["none"];
|
|
1149
|
-
if (includesFresh) return ["none"];
|
|
1150
|
-
if (includesNuxt || includesSvelte || includesSolid) return ["orpc", "none"];
|
|
1151
|
-
if (includesAstro && astroIntegration && astroIntegration !== "react") return ["orpc", "none"];
|
|
1152
|
-
return base;
|
|
1153
|
-
}
|
|
1154
|
-
function isExampleAIAllowed(backend, frontends = []) {
|
|
1155
|
-
if (frontends.includes("solid")) return false;
|
|
1156
|
-
if (backend === "convex") {
|
|
1157
|
-
const includesNuxt = frontends.includes("nuxt");
|
|
1158
|
-
const includesSvelte = frontends.includes("svelte");
|
|
1159
|
-
if (includesNuxt || includesSvelte) return false;
|
|
1160
|
-
}
|
|
1161
|
-
return true;
|
|
849
|
+
function allowedApisForFrontends$1(frontends = [], astroIntegration) {
|
|
850
|
+
return allowedApisForFrontends(frontends, astroIntegration);
|
|
1162
851
|
}
|
|
1163
|
-
function
|
|
1164
|
-
return frontends
|
|
1165
|
-
"next",
|
|
1166
|
-
"tanstack-start",
|
|
1167
|
-
"nuxt"
|
|
1168
|
-
].includes(f));
|
|
852
|
+
function isExampleAIAllowed$1(backend, frontends = []) {
|
|
853
|
+
return isExampleAIAllowed(backend, frontends);
|
|
1169
854
|
}
|
|
1170
|
-
function isExampleChatSdkAllowed(backend, frontends = [], runtime) {
|
|
1171
|
-
|
|
1172
|
-
if (backend === "self") return hasExampleChatSdkSelfFrontend(frontends);
|
|
1173
|
-
if (backend === "hono") return runtime === "node";
|
|
1174
|
-
return false;
|
|
855
|
+
function isExampleChatSdkAllowed$1(backend, frontends = [], runtime) {
|
|
856
|
+
return isExampleChatSdkAllowed(backend, frontends, runtime);
|
|
1175
857
|
}
|
|
1176
858
|
function requiresChatSdkVercelAI(backend, frontends = [], runtime) {
|
|
1177
|
-
|
|
1178
|
-
if (backend === "hono" && runtime === "node") return true;
|
|
1179
|
-
return false;
|
|
859
|
+
return requiresChatSdkVercelAIForSelection(backend, frontends, runtime);
|
|
1180
860
|
}
|
|
1181
861
|
function validateWebDeployRequiresWebFrontend(webDeploy, hasWebFrontendFlag) {
|
|
1182
862
|
if (webDeploy && webDeploy !== "none" && !hasWebFrontendFlag) exitWithError("'--web-deploy' requires a web frontend. Please select a web frontend or set '--web-deploy none'.");
|
|
@@ -1184,28 +864,16 @@ function validateWebDeployRequiresWebFrontend(webDeploy, hasWebFrontendFlag) {
|
|
|
1184
864
|
function validateServerDeployRequiresBackend(serverDeploy, backend) {
|
|
1185
865
|
if (serverDeploy && serverDeploy !== "none" && (!backend || backend === "none")) exitWithError("'--server-deploy' requires a backend. Please select a backend or set '--server-deploy none'.");
|
|
1186
866
|
}
|
|
1187
|
-
function validateAddonCompatibility(addon, frontend, _auth) {
|
|
1188
|
-
|
|
1189
|
-
if (compatibleFrontends.length > 0) {
|
|
1190
|
-
if (!frontend.some((f) => compatibleFrontends.includes(f))) return {
|
|
1191
|
-
isCompatible: false,
|
|
1192
|
-
reason: `${addon} addon requires one of these frontends: ${compatibleFrontends.join(", ")}`
|
|
1193
|
-
};
|
|
1194
|
-
}
|
|
1195
|
-
return { isCompatible: true };
|
|
867
|
+
function validateAddonCompatibility$1(addon, frontend, _auth) {
|
|
868
|
+
return validateAddonCompatibility(addon, frontend, _auth);
|
|
1196
869
|
}
|
|
1197
|
-
function getCompatibleAddons(allAddons, frontend, existingAddons = [], auth) {
|
|
1198
|
-
return allAddons
|
|
1199
|
-
if (existingAddons.includes(addon)) return false;
|
|
1200
|
-
if (addon === "none") return false;
|
|
1201
|
-
const { isCompatible } = validateAddonCompatibility(addon, frontend, auth);
|
|
1202
|
-
return isCompatible;
|
|
1203
|
-
});
|
|
870
|
+
function getCompatibleAddons$1(allAddons, frontend, existingAddons = [], auth) {
|
|
871
|
+
return getCompatibleAddons(allAddons, frontend, existingAddons, auth);
|
|
1204
872
|
}
|
|
1205
873
|
function validateAddonsAgainstFrontends(addons = [], frontends = [], auth) {
|
|
1206
874
|
for (const addon of addons) {
|
|
1207
875
|
if (addon === "none") continue;
|
|
1208
|
-
const { isCompatible, reason } = validateAddonCompatibility(addon, frontends, auth);
|
|
876
|
+
const { isCompatible, reason } = validateAddonCompatibility$1(addon, frontends, auth);
|
|
1209
877
|
if (!isCompatible) exitWithError(`Incompatible addon/frontend combination: ${reason}`);
|
|
1210
878
|
}
|
|
1211
879
|
}
|
|
@@ -1213,7 +881,7 @@ function validatePaymentsCompatibility(payments, auth, _backend, frontends = [])
|
|
|
1213
881
|
if (!payments || payments === "none") return;
|
|
1214
882
|
if (payments === "polar") {
|
|
1215
883
|
if (!auth || auth === "none" || auth !== "better-auth") exitWithError("Polar payments requires Better Auth. Please use '--auth better-auth' or choose a different payments provider.");
|
|
1216
|
-
const { web } = splitFrontends(frontends);
|
|
884
|
+
const { web } = splitFrontends$1(frontends);
|
|
1217
885
|
if (web.length === 0 && frontends.length > 0) exitWithError("Polar payments requires a web frontend or no frontend. Please select a web frontend or choose a different payments provider.");
|
|
1218
886
|
}
|
|
1219
887
|
}
|
|
@@ -1221,6 +889,7 @@ function validateExamplesCompatibility(examples, backend, frontend, runtime, ai)
|
|
|
1221
889
|
const examplesArr = examples ?? [];
|
|
1222
890
|
if (examplesArr.length === 0 || examplesArr.includes("none")) return;
|
|
1223
891
|
if (examplesArr.includes("ai") && (frontend ?? []).includes("solid")) exitWithError("The 'ai' example is not compatible with the Solid frontend.");
|
|
892
|
+
if (examplesArr.includes("ai") && (frontend ?? []).includes("solid-start")) exitWithError("The 'ai' example is not compatible with the SolidStart frontend.");
|
|
1224
893
|
if (examplesArr.includes("ai") && backend === "convex") {
|
|
1225
894
|
const frontendArr = frontend ?? [];
|
|
1226
895
|
const includesNuxt = frontendArr.includes("nuxt");
|
|
@@ -1229,7 +898,7 @@ function validateExamplesCompatibility(examples, backend, frontend, runtime, ai)
|
|
|
1229
898
|
}
|
|
1230
899
|
if (examplesArr.includes("chat-sdk")) {
|
|
1231
900
|
const frontendArr = frontend ?? [];
|
|
1232
|
-
if (!isExampleChatSdkAllowed(backend, frontendArr, runtime)) {
|
|
901
|
+
if (!isExampleChatSdkAllowed$1(backend, frontendArr, runtime)) {
|
|
1233
902
|
if (backend === "none") exitWithError("The 'chat-sdk' example requires a backend.");
|
|
1234
903
|
if (backend === "convex") exitWithError("The 'chat-sdk' example is not supported with the Convex backend in v1. Use self backend (Next.js, TanStack Start, Nuxt) or Hono with Node runtime.");
|
|
1235
904
|
if (backend === "self") exitWithError("The 'chat-sdk' example with self backend only supports Next.js, TanStack Start, or Nuxt frontends in v1.");
|
|
@@ -1244,48 +913,31 @@ function validateExamplesCompatibility(examples, backend, frontend, runtime, ai)
|
|
|
1244
913
|
*/
|
|
1245
914
|
function validateUILibraryFrontendCompatibility(uiLibrary, frontends = [], astroIntegration) {
|
|
1246
915
|
if (!uiLibrary || uiLibrary === "none") return;
|
|
1247
|
-
const
|
|
1248
|
-
if (
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
"tanstack-router",
|
|
1254
|
-
"react-router",
|
|
1255
|
-
"tanstack-start",
|
|
1256
|
-
"next"
|
|
1257
|
-
].includes(f));
|
|
1258
|
-
const supportsNonReact = compatibility.frontends.some((f) => [
|
|
1259
|
-
"nuxt",
|
|
1260
|
-
"svelte",
|
|
1261
|
-
"solid",
|
|
1262
|
-
"qwik",
|
|
1263
|
-
"angular"
|
|
1264
|
-
].includes(f));
|
|
1265
|
-
if (astroIntegration === "react") {
|
|
1266
|
-
if (supportsReact) return;
|
|
1267
|
-
}
|
|
1268
|
-
if (!supportsNonReact) {
|
|
1269
|
-
const integrationName = astroIntegration || "none";
|
|
916
|
+
const compatible = getCompatibleUILibraries(frontends, astroIntegration);
|
|
917
|
+
if (!compatible.includes(uiLibrary)) {
|
|
918
|
+
const { web } = splitFrontends$1(frontends);
|
|
919
|
+
const isAstroNonReact = web.includes("astro") && astroIntegration !== "react";
|
|
920
|
+
const supportsAstroReact = getCompatibleUILibraries(["astro"], "react").includes(uiLibrary);
|
|
921
|
+
if (isAstroNonReact && supportsAstroReact) {
|
|
1270
922
|
incompatibilityError({
|
|
1271
923
|
message: `UI library '${uiLibrary}' requires React.`,
|
|
1272
924
|
provided: {
|
|
1273
925
|
"ui-library": uiLibrary,
|
|
1274
|
-
"astro-integration":
|
|
926
|
+
"astro-integration": astroIntegration || "none"
|
|
1275
927
|
},
|
|
1276
928
|
suggestions: ["Use --astro-integration react", "Choose a different UI library (daisyui, ark-ui)"]
|
|
1277
929
|
});
|
|
930
|
+
return;
|
|
1278
931
|
}
|
|
1279
|
-
|
|
932
|
+
incompatibilityError({
|
|
933
|
+
message: `UI library '${uiLibrary}' is not compatible with the selected frontend.`,
|
|
934
|
+
provided: {
|
|
935
|
+
"ui-library": uiLibrary,
|
|
936
|
+
frontend: frontends
|
|
937
|
+
},
|
|
938
|
+
suggestions: [`Supported choices for this stack: ${compatible.join(", ")}`, "Choose a different UI library"]
|
|
939
|
+
});
|
|
1280
940
|
}
|
|
1281
|
-
if (!compatibility.frontends.includes(webFrontend)) incompatibilityError({
|
|
1282
|
-
message: `UI library '${uiLibrary}' is not compatible with '${webFrontend}'.`,
|
|
1283
|
-
provided: {
|
|
1284
|
-
"ui-library": uiLibrary,
|
|
1285
|
-
frontend: webFrontend
|
|
1286
|
-
},
|
|
1287
|
-
suggestions: [`Supported frontends: ${compatibility.frontends.join(", ")}`, "Choose a different UI library"]
|
|
1288
|
-
});
|
|
1289
941
|
}
|
|
1290
942
|
/**
|
|
1291
943
|
* Validates that a UI library is compatible with the selected CSS framework
|
|
@@ -1293,57 +945,26 @@ function validateUILibraryFrontendCompatibility(uiLibrary, frontends = [], astro
|
|
|
1293
945
|
function validateUILibraryCSSFrameworkCompatibility(uiLibrary, cssFramework) {
|
|
1294
946
|
if (!uiLibrary || uiLibrary === "none") return;
|
|
1295
947
|
if (!cssFramework) return;
|
|
1296
|
-
const
|
|
1297
|
-
if (!
|
|
948
|
+
const supported = getCompatibleCSSFrameworks(uiLibrary);
|
|
949
|
+
if (!supported.includes(cssFramework)) exitWithError(`UI library '${uiLibrary}' is not compatible with '${cssFramework}' CSS framework. Supported CSS frameworks: ${supported.join(", ")}`);
|
|
1298
950
|
}
|
|
1299
951
|
/**
|
|
1300
952
|
* Gets list of UI libraries compatible with the selected frontend(s)
|
|
1301
953
|
*/
|
|
1302
|
-
function getCompatibleUILibraries(frontends = [], astroIntegration) {
|
|
1303
|
-
|
|
1304
|
-
if (web.length === 0) return ["none"];
|
|
1305
|
-
const webFrontend = web[0];
|
|
1306
|
-
return Object.keys(UI_LIBRARY_COMPATIBILITY).filter((lib) => {
|
|
1307
|
-
if (lib === "none") return true;
|
|
1308
|
-
const compatibility = UI_LIBRARY_COMPATIBILITY[lib];
|
|
1309
|
-
if (webFrontend === "astro") {
|
|
1310
|
-
if (astroIntegration === "react") return compatibility.frontends.some((f) => [
|
|
1311
|
-
"tanstack-router",
|
|
1312
|
-
"react-router",
|
|
1313
|
-
"tanstack-start",
|
|
1314
|
-
"next",
|
|
1315
|
-
"astro"
|
|
1316
|
-
].includes(f));
|
|
1317
|
-
return compatibility.frontends.some((f) => [
|
|
1318
|
-
"nuxt",
|
|
1319
|
-
"svelte",
|
|
1320
|
-
"solid",
|
|
1321
|
-
"qwik",
|
|
1322
|
-
"angular"
|
|
1323
|
-
].includes(f));
|
|
1324
|
-
}
|
|
1325
|
-
return compatibility.frontends.includes(webFrontend);
|
|
1326
|
-
});
|
|
954
|
+
function getCompatibleUILibraries$1(frontends = [], astroIntegration) {
|
|
955
|
+
return getCompatibleUILibraries(frontends, astroIntegration);
|
|
1327
956
|
}
|
|
1328
957
|
/**
|
|
1329
958
|
* Gets list of CSS frameworks compatible with the selected UI library
|
|
1330
959
|
*/
|
|
1331
|
-
function getCompatibleCSSFrameworks(uiLibrary) {
|
|
1332
|
-
|
|
1333
|
-
"tailwind",
|
|
1334
|
-
"scss",
|
|
1335
|
-
"less",
|
|
1336
|
-
"postcss-only",
|
|
1337
|
-
"none"
|
|
1338
|
-
];
|
|
1339
|
-
return UI_LIBRARY_COMPATIBILITY[uiLibrary].cssFrameworks;
|
|
960
|
+
function getCompatibleCSSFrameworks$1(uiLibrary) {
|
|
961
|
+
return getCompatibleCSSFrameworks(uiLibrary);
|
|
1340
962
|
}
|
|
1341
963
|
/**
|
|
1342
964
|
* Checks if a frontend has web styling (excludes native-only frontends)
|
|
1343
965
|
*/
|
|
1344
|
-
function hasWebStyling(frontends = []) {
|
|
1345
|
-
|
|
1346
|
-
return web.length > 0;
|
|
966
|
+
function hasWebStyling$1(frontends = []) {
|
|
967
|
+
return hasWebStyling(frontends);
|
|
1347
968
|
}
|
|
1348
969
|
|
|
1349
970
|
//#endregion
|
|
@@ -1684,7 +1305,7 @@ async function getAddonsChoice(addons, frontends, auth) {
|
|
|
1684
1305
|
};
|
|
1685
1306
|
const frontendsArray = frontends || [];
|
|
1686
1307
|
for (const addon of allAddons) {
|
|
1687
|
-
const { isCompatible } = validateAddonCompatibility(addon, frontendsArray, auth);
|
|
1308
|
+
const { isCompatible } = validateAddonCompatibility$1(addon, frontendsArray, auth);
|
|
1688
1309
|
if (!isCompatible) continue;
|
|
1689
1310
|
const { label, hint } = getAddonDisplay(addon);
|
|
1690
1311
|
const option = {
|
|
@@ -1723,7 +1344,7 @@ async function getAddonsToAdd(frontend, existingAddons = [], auth) {
|
|
|
1723
1344
|
"AI Agents": []
|
|
1724
1345
|
};
|
|
1725
1346
|
const frontendArray = frontend || [];
|
|
1726
|
-
const compatibleAddons = getCompatibleAddons(types_exports.AddonsSchema.options.filter((addon) => addon !== "none"), frontendArray, existingAddons, auth);
|
|
1347
|
+
const compatibleAddons = getCompatibleAddons$1(types_exports.AddonsSchema.options.filter((addon) => addon !== "none"), frontendArray, existingAddons, auth);
|
|
1727
1348
|
for (const addon of compatibleAddons) {
|
|
1728
1349
|
const { label, hint } = getAddonDisplay(addon);
|
|
1729
1350
|
const option = {
|
|
@@ -3452,7 +3073,7 @@ async function getAiDocsChoice(aiDocs) {
|
|
|
3452
3073
|
//#region src/prompts/animation.ts
|
|
3453
3074
|
async function getAnimationChoice(animation, frontends) {
|
|
3454
3075
|
if (animation !== void 0) return animation;
|
|
3455
|
-
const { web } = splitFrontends(frontends);
|
|
3076
|
+
const { web } = splitFrontends$1(frontends);
|
|
3456
3077
|
if (web.length === 0) return "none";
|
|
3457
3078
|
const isReact = web.some((f) => [
|
|
3458
3079
|
"tanstack-router",
|
|
@@ -3504,7 +3125,7 @@ async function getAnimationChoice(animation, frontends) {
|
|
|
3504
3125
|
//#region src/prompts/api.ts
|
|
3505
3126
|
async function getApiChoice(Api, frontend, backend, astroIntegration) {
|
|
3506
3127
|
if (backend === "convex" || backend === "none") return "none";
|
|
3507
|
-
const allowed = allowedApisForFrontends(frontend ?? [], astroIntegration);
|
|
3128
|
+
const allowed = allowedApisForFrontends$1(frontend ?? [], astroIntegration);
|
|
3508
3129
|
if (Api) return allowed.includes(Api) ? Api : allowed[0];
|
|
3509
3130
|
const apiOptionMap = {
|
|
3510
3131
|
trpc: {
|
|
@@ -3692,11 +3313,13 @@ const FULLSTACK_FRONTENDS = [
|
|
|
3692
3313
|
"next",
|
|
3693
3314
|
"tanstack-start",
|
|
3694
3315
|
"astro",
|
|
3695
|
-
"nuxt"
|
|
3316
|
+
"nuxt",
|
|
3317
|
+
"svelte",
|
|
3318
|
+
"solid-start"
|
|
3696
3319
|
];
|
|
3697
3320
|
async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
3698
3321
|
if (backendFramework !== void 0) return backendFramework;
|
|
3699
|
-
const hasIncompatibleFrontend = frontends?.some((f) => f === "solid");
|
|
3322
|
+
const hasIncompatibleFrontend = frontends?.some((f) => f === "solid" || f === "solid-start");
|
|
3700
3323
|
const hasFullstackFrontend = frontends?.some((f) => FULLSTACK_FRONTENDS.includes(f));
|
|
3701
3324
|
const backendOptions = [];
|
|
3702
3325
|
if (hasFullstackFrontend) backendOptions.push({
|
|
@@ -3842,7 +3465,7 @@ const CSS_FRAMEWORK_OPTIONS = {
|
|
|
3842
3465
|
}
|
|
3843
3466
|
};
|
|
3844
3467
|
async function getCSSFrameworkChoice(cssFramework, uiLibrary) {
|
|
3845
|
-
const compatibleFrameworks = getCompatibleCSSFrameworks(uiLibrary);
|
|
3468
|
+
const compatibleFrameworks = getCompatibleCSSFrameworks$1(uiLibrary);
|
|
3846
3469
|
if (cssFramework !== void 0) return compatibleFrameworks.includes(cssFramework) ? cssFramework : compatibleFrameworks[0];
|
|
3847
3470
|
const selected = await navigableSelect({
|
|
3848
3471
|
message: "Select CSS framework",
|
|
@@ -4158,12 +3781,12 @@ async function getExamplesChoice(examples, frontends, backend, runtime) {
|
|
|
4158
3781
|
if (backend === "none") return [];
|
|
4159
3782
|
let response = [];
|
|
4160
3783
|
const options = [];
|
|
4161
|
-
if (isExampleAIAllowed(backend, frontends ?? [])) options.push({
|
|
3784
|
+
if (isExampleAIAllowed$1(backend, frontends ?? [])) options.push({
|
|
4162
3785
|
value: "ai",
|
|
4163
3786
|
label: "AI Chat",
|
|
4164
3787
|
hint: "A simple AI chat interface using AI SDK"
|
|
4165
3788
|
});
|
|
4166
|
-
if (isExampleChatSdkAllowed(backend, frontends ?? [], runtime)) options.push({
|
|
3789
|
+
if (isExampleChatSdkAllowed$1(backend, frontends ?? [], runtime)) options.push({
|
|
4167
3790
|
value: "chat-sdk",
|
|
4168
3791
|
label: "Chat SDK Bots",
|
|
4169
3792
|
hint: "Framework-specific Chat SDK bot example (Slack/Discord/GitHub depending on stack)"
|
|
@@ -4248,7 +3871,7 @@ async function getFileUploadChoice(fileUpload, backend) {
|
|
|
4248
3871
|
//#region src/prompts/forms.ts
|
|
4249
3872
|
async function getFormsChoice(forms, frontends) {
|
|
4250
3873
|
if (forms !== void 0) return forms;
|
|
4251
|
-
const { web } = splitFrontends(frontends);
|
|
3874
|
+
const { web } = splitFrontends$1(frontends);
|
|
4252
3875
|
if (web.length === 0) return "none";
|
|
4253
3876
|
const isReact = web.some((f) => [
|
|
4254
3877
|
"tanstack-router",
|
|
@@ -4361,6 +3984,11 @@ async function getFrontendChoice(frontendOptions, backend, auth) {
|
|
|
4361
3984
|
label: "Solid",
|
|
4362
3985
|
hint: "Simple and performant reactivity for building user interfaces"
|
|
4363
3986
|
},
|
|
3987
|
+
{
|
|
3988
|
+
value: "solid-start",
|
|
3989
|
+
label: "SolidStart",
|
|
3990
|
+
hint: "Full-stack Solid framework with SSR and API routes"
|
|
3991
|
+
},
|
|
4364
3992
|
{
|
|
4365
3993
|
value: "astro",
|
|
4366
3994
|
label: "Astro",
|
|
@@ -4391,7 +4019,7 @@ async function getFrontendChoice(frontendOptions, backend, auth) {
|
|
|
4391
4019
|
label: "Fresh",
|
|
4392
4020
|
hint: "Deno-native framework with islands architecture"
|
|
4393
4021
|
}
|
|
4394
|
-
].filter((option) => isFrontendAllowedWithBackend(option.value, backend, auth)),
|
|
4022
|
+
].filter((option) => isFrontendAllowedWithBackend$1(option.value, backend, auth)),
|
|
4395
4023
|
initialValue: DEFAULT_CONFIG.frontend[0]
|
|
4396
4024
|
});
|
|
4397
4025
|
if (isGoBack(webFramework)) shouldRestart = true;
|
|
@@ -4885,7 +4513,7 @@ async function getPackageManagerChoice(packageManager) {
|
|
|
4885
4513
|
async function getPaymentsChoice(payments, auth, backend, frontends) {
|
|
4886
4514
|
if (payments !== void 0) return payments;
|
|
4887
4515
|
if (backend === "none") return "none";
|
|
4888
|
-
const isPolarCompatible = auth === "better-auth" && backend !== "convex" && (frontends?.length === 0 || splitFrontends(frontends).web.length > 0);
|
|
4516
|
+
const isPolarCompatible = auth === "better-auth" && backend !== "convex" && (frontends?.length === 0 || splitFrontends$1(frontends).web.length > 0);
|
|
4889
4517
|
const options = [];
|
|
4890
4518
|
if (isPolarCompatible) options.push({
|
|
4891
4519
|
value: "polar",
|
|
@@ -5366,11 +4994,379 @@ async function getServerDeploymentChoice(deployment, runtime, backend, _webDeplo
|
|
|
5366
4994
|
return "none";
|
|
5367
4995
|
}
|
|
5368
4996
|
|
|
4997
|
+
//#endregion
|
|
4998
|
+
//#region src/prompts/shadcn-options.ts
|
|
4999
|
+
const BASE_OPTIONS = [{
|
|
5000
|
+
value: "radix",
|
|
5001
|
+
label: "Radix UI",
|
|
5002
|
+
hint: "Battle-tested headless primitives (130M+ monthly downloads)"
|
|
5003
|
+
}, {
|
|
5004
|
+
value: "base",
|
|
5005
|
+
label: "Base UI",
|
|
5006
|
+
hint: "MUI's headless library with cleaner APIs and native multi-select"
|
|
5007
|
+
}];
|
|
5008
|
+
const STYLE_OPTIONS = [
|
|
5009
|
+
{
|
|
5010
|
+
value: "vega",
|
|
5011
|
+
label: "Vega",
|
|
5012
|
+
hint: "Classic shadcn/ui look"
|
|
5013
|
+
},
|
|
5014
|
+
{
|
|
5015
|
+
value: "nova",
|
|
5016
|
+
label: "Nova",
|
|
5017
|
+
hint: "Compact layout with reduced padding"
|
|
5018
|
+
},
|
|
5019
|
+
{
|
|
5020
|
+
value: "maia",
|
|
5021
|
+
label: "Maia",
|
|
5022
|
+
hint: "Soft, rounded with generous spacing"
|
|
5023
|
+
},
|
|
5024
|
+
{
|
|
5025
|
+
value: "lyra",
|
|
5026
|
+
label: "Lyra",
|
|
5027
|
+
hint: "Boxy and sharp, pairs well with mono fonts"
|
|
5028
|
+
},
|
|
5029
|
+
{
|
|
5030
|
+
value: "mira",
|
|
5031
|
+
label: "Mira",
|
|
5032
|
+
hint: "Dense, made for data-heavy interfaces"
|
|
5033
|
+
}
|
|
5034
|
+
];
|
|
5035
|
+
const ICON_LIBRARY_OPTIONS = [
|
|
5036
|
+
{
|
|
5037
|
+
value: "lucide",
|
|
5038
|
+
label: "Lucide",
|
|
5039
|
+
hint: "Default icon library — clean, consistent icons"
|
|
5040
|
+
},
|
|
5041
|
+
{
|
|
5042
|
+
value: "tabler",
|
|
5043
|
+
label: "Tabler Icons",
|
|
5044
|
+
hint: "2000+ open-source SVG icons"
|
|
5045
|
+
},
|
|
5046
|
+
{
|
|
5047
|
+
value: "hugeicons",
|
|
5048
|
+
label: "HugeIcons",
|
|
5049
|
+
hint: "Modern icon set with wrapper component"
|
|
5050
|
+
},
|
|
5051
|
+
{
|
|
5052
|
+
value: "phosphor",
|
|
5053
|
+
label: "Phosphor Icons",
|
|
5054
|
+
hint: "Flexible, consistent icon family"
|
|
5055
|
+
},
|
|
5056
|
+
{
|
|
5057
|
+
value: "remixicon",
|
|
5058
|
+
label: "Remix Icon",
|
|
5059
|
+
hint: "Open-source neutral style icons"
|
|
5060
|
+
}
|
|
5061
|
+
];
|
|
5062
|
+
const COLOR_THEME_OPTIONS = [
|
|
5063
|
+
{
|
|
5064
|
+
value: "neutral",
|
|
5065
|
+
label: "Neutral",
|
|
5066
|
+
hint: "Clean and minimal"
|
|
5067
|
+
},
|
|
5068
|
+
{
|
|
5069
|
+
value: "stone",
|
|
5070
|
+
label: "Stone",
|
|
5071
|
+
hint: "Warm neutral tones"
|
|
5072
|
+
},
|
|
5073
|
+
{
|
|
5074
|
+
value: "zinc",
|
|
5075
|
+
label: "Zinc",
|
|
5076
|
+
hint: "Cool neutral tones"
|
|
5077
|
+
},
|
|
5078
|
+
{
|
|
5079
|
+
value: "gray",
|
|
5080
|
+
label: "Gray",
|
|
5081
|
+
hint: "Blue-tinted neutral"
|
|
5082
|
+
},
|
|
5083
|
+
{
|
|
5084
|
+
value: "blue",
|
|
5085
|
+
label: "Blue",
|
|
5086
|
+
hint: "Trust and reliability"
|
|
5087
|
+
},
|
|
5088
|
+
{
|
|
5089
|
+
value: "violet",
|
|
5090
|
+
label: "Violet",
|
|
5091
|
+
hint: "Creative and modern"
|
|
5092
|
+
},
|
|
5093
|
+
{
|
|
5094
|
+
value: "green",
|
|
5095
|
+
label: "Green",
|
|
5096
|
+
hint: "Growth and success"
|
|
5097
|
+
},
|
|
5098
|
+
{
|
|
5099
|
+
value: "red",
|
|
5100
|
+
label: "Red",
|
|
5101
|
+
hint: "Bold and energetic"
|
|
5102
|
+
},
|
|
5103
|
+
{
|
|
5104
|
+
value: "rose",
|
|
5105
|
+
label: "Rose",
|
|
5106
|
+
hint: "Warm and inviting"
|
|
5107
|
+
},
|
|
5108
|
+
{
|
|
5109
|
+
value: "orange",
|
|
5110
|
+
label: "Orange",
|
|
5111
|
+
hint: "Friendly and vibrant"
|
|
5112
|
+
},
|
|
5113
|
+
{
|
|
5114
|
+
value: "amber",
|
|
5115
|
+
label: "Amber",
|
|
5116
|
+
hint: "Warm and golden"
|
|
5117
|
+
},
|
|
5118
|
+
{
|
|
5119
|
+
value: "yellow",
|
|
5120
|
+
label: "Yellow",
|
|
5121
|
+
hint: "Bright and optimistic"
|
|
5122
|
+
},
|
|
5123
|
+
{
|
|
5124
|
+
value: "lime",
|
|
5125
|
+
label: "Lime",
|
|
5126
|
+
hint: "Fresh and lively"
|
|
5127
|
+
},
|
|
5128
|
+
{
|
|
5129
|
+
value: "emerald",
|
|
5130
|
+
label: "Emerald",
|
|
5131
|
+
hint: "Rich and luxurious"
|
|
5132
|
+
},
|
|
5133
|
+
{
|
|
5134
|
+
value: "teal",
|
|
5135
|
+
label: "Teal",
|
|
5136
|
+
hint: "Calm and sophisticated"
|
|
5137
|
+
},
|
|
5138
|
+
{
|
|
5139
|
+
value: "cyan",
|
|
5140
|
+
label: "Cyan",
|
|
5141
|
+
hint: "Cool and refreshing"
|
|
5142
|
+
},
|
|
5143
|
+
{
|
|
5144
|
+
value: "sky",
|
|
5145
|
+
label: "Sky",
|
|
5146
|
+
hint: "Light and airy"
|
|
5147
|
+
},
|
|
5148
|
+
{
|
|
5149
|
+
value: "indigo",
|
|
5150
|
+
label: "Indigo",
|
|
5151
|
+
hint: "Deep and focused"
|
|
5152
|
+
},
|
|
5153
|
+
{
|
|
5154
|
+
value: "purple",
|
|
5155
|
+
label: "Purple",
|
|
5156
|
+
hint: "Royal and elegant"
|
|
5157
|
+
},
|
|
5158
|
+
{
|
|
5159
|
+
value: "fuchsia",
|
|
5160
|
+
label: "Fuchsia",
|
|
5161
|
+
hint: "Playful and bold"
|
|
5162
|
+
},
|
|
5163
|
+
{
|
|
5164
|
+
value: "pink",
|
|
5165
|
+
label: "Pink",
|
|
5166
|
+
hint: "Soft and expressive"
|
|
5167
|
+
}
|
|
5168
|
+
];
|
|
5169
|
+
const BASE_COLOR_OPTIONS = [
|
|
5170
|
+
{
|
|
5171
|
+
value: "neutral",
|
|
5172
|
+
label: "Neutral",
|
|
5173
|
+
hint: "Pure neutral grays"
|
|
5174
|
+
},
|
|
5175
|
+
{
|
|
5176
|
+
value: "stone",
|
|
5177
|
+
label: "Stone",
|
|
5178
|
+
hint: "Warm-tinted grays"
|
|
5179
|
+
},
|
|
5180
|
+
{
|
|
5181
|
+
value: "zinc",
|
|
5182
|
+
label: "Zinc",
|
|
5183
|
+
hint: "Cool-tinted grays"
|
|
5184
|
+
},
|
|
5185
|
+
{
|
|
5186
|
+
value: "gray",
|
|
5187
|
+
label: "Gray",
|
|
5188
|
+
hint: "Blue-tinted grays"
|
|
5189
|
+
}
|
|
5190
|
+
];
|
|
5191
|
+
const FONT_OPTIONS = [
|
|
5192
|
+
{
|
|
5193
|
+
value: "inter",
|
|
5194
|
+
label: "Inter",
|
|
5195
|
+
hint: "Clean variable sans-serif (default)"
|
|
5196
|
+
},
|
|
5197
|
+
{
|
|
5198
|
+
value: "geist",
|
|
5199
|
+
label: "Geist",
|
|
5200
|
+
hint: "Vercel's modern typeface"
|
|
5201
|
+
},
|
|
5202
|
+
{
|
|
5203
|
+
value: "figtree",
|
|
5204
|
+
label: "Figtree",
|
|
5205
|
+
hint: "Friendly geometric sans-serif"
|
|
5206
|
+
},
|
|
5207
|
+
{
|
|
5208
|
+
value: "noto-sans",
|
|
5209
|
+
label: "Noto Sans",
|
|
5210
|
+
hint: "Google's universal typeface"
|
|
5211
|
+
},
|
|
5212
|
+
{
|
|
5213
|
+
value: "nunito-sans",
|
|
5214
|
+
label: "Nunito Sans",
|
|
5215
|
+
hint: "Rounded, balanced sans-serif"
|
|
5216
|
+
},
|
|
5217
|
+
{
|
|
5218
|
+
value: "roboto",
|
|
5219
|
+
label: "Roboto",
|
|
5220
|
+
hint: "Google's Material Design typeface"
|
|
5221
|
+
},
|
|
5222
|
+
{
|
|
5223
|
+
value: "raleway",
|
|
5224
|
+
label: "Raleway",
|
|
5225
|
+
hint: "Elegant thin-weight display font"
|
|
5226
|
+
},
|
|
5227
|
+
{
|
|
5228
|
+
value: "dm-sans",
|
|
5229
|
+
label: "DM Sans",
|
|
5230
|
+
hint: "Low-contrast geometric sans"
|
|
5231
|
+
},
|
|
5232
|
+
{
|
|
5233
|
+
value: "public-sans",
|
|
5234
|
+
label: "Public Sans",
|
|
5235
|
+
hint: "Neutral, US government typeface"
|
|
5236
|
+
},
|
|
5237
|
+
{
|
|
5238
|
+
value: "outfit",
|
|
5239
|
+
label: "Outfit",
|
|
5240
|
+
hint: "Modern geometric variable font"
|
|
5241
|
+
},
|
|
5242
|
+
{
|
|
5243
|
+
value: "jetbrains-mono",
|
|
5244
|
+
label: "JetBrains Mono",
|
|
5245
|
+
hint: "Developer-focused monospace"
|
|
5246
|
+
},
|
|
5247
|
+
{
|
|
5248
|
+
value: "geist-mono",
|
|
5249
|
+
label: "Geist Mono",
|
|
5250
|
+
hint: "Vercel's monospace typeface"
|
|
5251
|
+
}
|
|
5252
|
+
];
|
|
5253
|
+
const RADIUS_OPTIONS = [
|
|
5254
|
+
{
|
|
5255
|
+
value: "default",
|
|
5256
|
+
label: "Default",
|
|
5257
|
+
hint: "Use the style's default radius"
|
|
5258
|
+
},
|
|
5259
|
+
{
|
|
5260
|
+
value: "none",
|
|
5261
|
+
label: "None",
|
|
5262
|
+
hint: "Sharp corners (0)"
|
|
5263
|
+
},
|
|
5264
|
+
{
|
|
5265
|
+
value: "small",
|
|
5266
|
+
label: "Small",
|
|
5267
|
+
hint: "Subtle rounding (0.45rem)"
|
|
5268
|
+
},
|
|
5269
|
+
{
|
|
5270
|
+
value: "medium",
|
|
5271
|
+
label: "Medium",
|
|
5272
|
+
hint: "Moderate rounding (0.625rem)"
|
|
5273
|
+
},
|
|
5274
|
+
{
|
|
5275
|
+
value: "large",
|
|
5276
|
+
label: "Large",
|
|
5277
|
+
hint: "Generous rounding (0.875rem)"
|
|
5278
|
+
}
|
|
5279
|
+
];
|
|
5280
|
+
const SHADCN_DEFAULTS = {
|
|
5281
|
+
shadcnBase: "radix",
|
|
5282
|
+
shadcnStyle: "nova",
|
|
5283
|
+
shadcnIconLibrary: "lucide",
|
|
5284
|
+
shadcnColorTheme: "neutral",
|
|
5285
|
+
shadcnBaseColor: "neutral",
|
|
5286
|
+
shadcnFont: "inter",
|
|
5287
|
+
shadcnRadius: "default"
|
|
5288
|
+
};
|
|
5289
|
+
async function getShadcnOptions(flags) {
|
|
5290
|
+
const fallback = (key) => isSilent() ? SHADCN_DEFAULTS[key] : void 0;
|
|
5291
|
+
return {
|
|
5292
|
+
shadcnBase: flags.shadcnBase ?? fallback("shadcnBase") ?? await promptShadcnBase(),
|
|
5293
|
+
shadcnStyle: flags.shadcnStyle ?? fallback("shadcnStyle") ?? await promptShadcnStyle(),
|
|
5294
|
+
shadcnIconLibrary: flags.shadcnIconLibrary ?? fallback("shadcnIconLibrary") ?? await promptShadcnIconLibrary(),
|
|
5295
|
+
shadcnColorTheme: flags.shadcnColorTheme ?? fallback("shadcnColorTheme") ?? await promptShadcnColorTheme(),
|
|
5296
|
+
shadcnBaseColor: flags.shadcnBaseColor ?? fallback("shadcnBaseColor") ?? await promptShadcnBaseColor(),
|
|
5297
|
+
shadcnFont: flags.shadcnFont ?? fallback("shadcnFont") ?? await promptShadcnFont(),
|
|
5298
|
+
shadcnRadius: flags.shadcnRadius ?? fallback("shadcnRadius") ?? await promptShadcnRadius()
|
|
5299
|
+
};
|
|
5300
|
+
}
|
|
5301
|
+
async function promptShadcnBase() {
|
|
5302
|
+
const selected = await navigableSelect({
|
|
5303
|
+
message: "Select shadcn/ui base library",
|
|
5304
|
+
options: BASE_OPTIONS,
|
|
5305
|
+
initialValue: "radix"
|
|
5306
|
+
});
|
|
5307
|
+
if (isCancel$1(selected)) return exitCancelled("Operation cancelled");
|
|
5308
|
+
return selected;
|
|
5309
|
+
}
|
|
5310
|
+
async function promptShadcnStyle() {
|
|
5311
|
+
const selected = await navigableSelect({
|
|
5312
|
+
message: "Select shadcn/ui visual style",
|
|
5313
|
+
options: STYLE_OPTIONS,
|
|
5314
|
+
initialValue: "nova"
|
|
5315
|
+
});
|
|
5316
|
+
if (isCancel$1(selected)) return exitCancelled("Operation cancelled");
|
|
5317
|
+
return selected;
|
|
5318
|
+
}
|
|
5319
|
+
async function promptShadcnIconLibrary() {
|
|
5320
|
+
const selected = await navigableSelect({
|
|
5321
|
+
message: "Select shadcn/ui icon library",
|
|
5322
|
+
options: ICON_LIBRARY_OPTIONS,
|
|
5323
|
+
initialValue: "lucide"
|
|
5324
|
+
});
|
|
5325
|
+
if (isCancel$1(selected)) return exitCancelled("Operation cancelled");
|
|
5326
|
+
return selected;
|
|
5327
|
+
}
|
|
5328
|
+
async function promptShadcnColorTheme() {
|
|
5329
|
+
const selected = await navigableSelect({
|
|
5330
|
+
message: "Select shadcn/ui color theme",
|
|
5331
|
+
options: COLOR_THEME_OPTIONS,
|
|
5332
|
+
initialValue: "neutral"
|
|
5333
|
+
});
|
|
5334
|
+
if (isCancel$1(selected)) return exitCancelled("Operation cancelled");
|
|
5335
|
+
return selected;
|
|
5336
|
+
}
|
|
5337
|
+
async function promptShadcnBaseColor() {
|
|
5338
|
+
const selected = await navigableSelect({
|
|
5339
|
+
message: "Select shadcn/ui base neutral color",
|
|
5340
|
+
options: BASE_COLOR_OPTIONS,
|
|
5341
|
+
initialValue: "neutral"
|
|
5342
|
+
});
|
|
5343
|
+
if (isCancel$1(selected)) return exitCancelled("Operation cancelled");
|
|
5344
|
+
return selected;
|
|
5345
|
+
}
|
|
5346
|
+
async function promptShadcnFont() {
|
|
5347
|
+
const selected = await navigableSelect({
|
|
5348
|
+
message: "Select shadcn/ui font",
|
|
5349
|
+
options: FONT_OPTIONS,
|
|
5350
|
+
initialValue: "inter"
|
|
5351
|
+
});
|
|
5352
|
+
if (isCancel$1(selected)) return exitCancelled("Operation cancelled");
|
|
5353
|
+
return selected;
|
|
5354
|
+
}
|
|
5355
|
+
async function promptShadcnRadius() {
|
|
5356
|
+
const selected = await navigableSelect({
|
|
5357
|
+
message: "Select shadcn/ui border radius",
|
|
5358
|
+
options: RADIUS_OPTIONS,
|
|
5359
|
+
initialValue: "default"
|
|
5360
|
+
});
|
|
5361
|
+
if (isCancel$1(selected)) return exitCancelled("Operation cancelled");
|
|
5362
|
+
return selected;
|
|
5363
|
+
}
|
|
5364
|
+
|
|
5369
5365
|
//#endregion
|
|
5370
5366
|
//#region src/prompts/state-management.ts
|
|
5371
5367
|
async function getStateManagementChoice(stateManagement, frontends) {
|
|
5372
5368
|
if (stateManagement !== void 0) return stateManagement;
|
|
5373
|
-
const { web } = splitFrontends(frontends);
|
|
5369
|
+
const { web } = splitFrontends$1(frontends);
|
|
5374
5370
|
if (web.length === 0) return "none";
|
|
5375
5371
|
const isReact = web.some((f) => [
|
|
5376
5372
|
"tanstack-router",
|
|
@@ -5530,9 +5526,9 @@ const UI_LIBRARY_OPTIONS = {
|
|
|
5530
5526
|
}
|
|
5531
5527
|
};
|
|
5532
5528
|
async function getUILibraryChoice(uiLibrary, frontends, astroIntegration) {
|
|
5533
|
-
const { web } = splitFrontends(frontends);
|
|
5529
|
+
const { web } = splitFrontends$1(frontends);
|
|
5534
5530
|
if (web.length === 0) return "none";
|
|
5535
|
-
const compatibleLibraries = getCompatibleUILibraries(frontends, astroIntegration);
|
|
5531
|
+
const compatibleLibraries = getCompatibleUILibraries$1(frontends, astroIntegration);
|
|
5536
5532
|
if (uiLibrary !== void 0) return compatibleLibraries.includes(uiLibrary) ? uiLibrary : compatibleLibraries[0];
|
|
5537
5533
|
const options = compatibleLibraries.map((lib) => ({
|
|
5538
5534
|
value: lib,
|
|
@@ -5603,6 +5599,24 @@ async function getValidationChoice(validation) {
|
|
|
5603
5599
|
return response;
|
|
5604
5600
|
}
|
|
5605
5601
|
|
|
5602
|
+
//#endregion
|
|
5603
|
+
//#region src/utils/compatibility.ts
|
|
5604
|
+
const WEB_FRAMEWORKS = [
|
|
5605
|
+
"tanstack-router",
|
|
5606
|
+
"react-router",
|
|
5607
|
+
"tanstack-start",
|
|
5608
|
+
"next",
|
|
5609
|
+
"nuxt",
|
|
5610
|
+
"svelte",
|
|
5611
|
+
"solid",
|
|
5612
|
+
"solid-start",
|
|
5613
|
+
"astro",
|
|
5614
|
+
"qwik",
|
|
5615
|
+
"angular",
|
|
5616
|
+
"redwood",
|
|
5617
|
+
"fresh"
|
|
5618
|
+
];
|
|
5619
|
+
|
|
5606
5620
|
//#endregion
|
|
5607
5621
|
//#region src/prompts/web-deploy.ts
|
|
5608
5622
|
function hasWebFrontend(frontends) {
|
|
@@ -5653,12 +5667,24 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
5653
5667
|
},
|
|
5654
5668
|
uiLibrary: ({ results }) => {
|
|
5655
5669
|
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
5656
|
-
if (hasWebStyling(results.frontend)) return getUILibraryChoice(flags.uiLibrary, results.frontend, results.astroIntegration);
|
|
5670
|
+
if (hasWebStyling$1(results.frontend)) return getUILibraryChoice(flags.uiLibrary, results.frontend, results.astroIntegration);
|
|
5657
5671
|
return Promise.resolve("none");
|
|
5658
5672
|
},
|
|
5673
|
+
shadcnOptions: ({ results }) => {
|
|
5674
|
+
if (results.uiLibrary !== "shadcn-ui") return Promise.resolve(void 0);
|
|
5675
|
+
return getShadcnOptions({
|
|
5676
|
+
shadcnBase: flags.shadcnBase,
|
|
5677
|
+
shadcnStyle: flags.shadcnStyle,
|
|
5678
|
+
shadcnIconLibrary: flags.shadcnIconLibrary,
|
|
5679
|
+
shadcnColorTheme: flags.shadcnColorTheme,
|
|
5680
|
+
shadcnBaseColor: flags.shadcnBaseColor,
|
|
5681
|
+
shadcnFont: flags.shadcnFont,
|
|
5682
|
+
shadcnRadius: flags.shadcnRadius
|
|
5683
|
+
});
|
|
5684
|
+
},
|
|
5659
5685
|
cssFramework: ({ results }) => {
|
|
5660
5686
|
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
5661
|
-
if (hasWebStyling(results.frontend)) return getCSSFrameworkChoice(flags.cssFramework, results.uiLibrary);
|
|
5687
|
+
if (hasWebStyling$1(results.frontend)) return getCSSFrameworkChoice(flags.cssFramework, results.uiLibrary);
|
|
5662
5688
|
return Promise.resolve("none");
|
|
5663
5689
|
},
|
|
5664
5690
|
backend: ({ results }) => {
|
|
@@ -5869,6 +5895,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
5869
5895
|
frontend: result.frontend,
|
|
5870
5896
|
astroIntegration: result.astroIntegration,
|
|
5871
5897
|
uiLibrary: result.uiLibrary,
|
|
5898
|
+
...result.shadcnOptions ?? {},
|
|
5872
5899
|
cssFramework: result.cssFramework,
|
|
5873
5900
|
backend: result.backend,
|
|
5874
5901
|
runtime: result.runtime,
|
|
@@ -6097,6 +6124,15 @@ function generateReproducibleCommand(config) {
|
|
|
6097
6124
|
flags.push(`--effect ${config.effect}`);
|
|
6098
6125
|
flags.push(`--css-framework ${config.cssFramework}`);
|
|
6099
6126
|
flags.push(`--ui-library ${config.uiLibrary}`);
|
|
6127
|
+
if (config.uiLibrary === "shadcn-ui") {
|
|
6128
|
+
flags.push(`--shadcn-base ${config.shadcnBase}`);
|
|
6129
|
+
flags.push(`--shadcn-style ${config.shadcnStyle}`);
|
|
6130
|
+
flags.push(`--shadcn-icon-library ${config.shadcnIconLibrary}`);
|
|
6131
|
+
flags.push(`--shadcn-color-theme ${config.shadcnColorTheme}`);
|
|
6132
|
+
flags.push(`--shadcn-base-color ${config.shadcnBaseColor}`);
|
|
6133
|
+
flags.push(`--shadcn-font ${config.shadcnFont}`);
|
|
6134
|
+
flags.push(`--shadcn-radius ${config.shadcnRadius}`);
|
|
6135
|
+
}
|
|
6100
6136
|
flags.push(`--ai ${config.ai}`);
|
|
6101
6137
|
flags.push(`--state-management ${config.stateManagement}`);
|
|
6102
6138
|
flags.push(`--forms ${config.forms}`);
|
|
@@ -6352,6 +6388,13 @@ function processFlags(options, projectName) {
|
|
|
6352
6388
|
if (options.astroIntegration) config.astroIntegration = options.astroIntegration;
|
|
6353
6389
|
if (options.cssFramework) config.cssFramework = options.cssFramework;
|
|
6354
6390
|
if (options.uiLibrary) config.uiLibrary = options.uiLibrary;
|
|
6391
|
+
if (options.shadcnBase) config.shadcnBase = options.shadcnBase;
|
|
6392
|
+
if (options.shadcnStyle) config.shadcnStyle = options.shadcnStyle;
|
|
6393
|
+
if (options.shadcnIconLibrary) config.shadcnIconLibrary = options.shadcnIconLibrary;
|
|
6394
|
+
if (options.shadcnColorTheme) config.shadcnColorTheme = options.shadcnColorTheme;
|
|
6395
|
+
if (options.shadcnBaseColor) config.shadcnBaseColor = options.shadcnBaseColor;
|
|
6396
|
+
if (options.shadcnFont) config.shadcnFont = options.shadcnFont;
|
|
6397
|
+
if (options.shadcnRadius) config.shadcnRadius = options.shadcnRadius;
|
|
6355
6398
|
if (options.addons && options.addons.length > 0) config.addons = processArrayOption(options.addons);
|
|
6356
6399
|
if (options.examples && options.examples.length > 0) config.examples = processArrayOption(options.examples);
|
|
6357
6400
|
if (options.aiDocs !== void 0) config.aiDocs = processArrayOption(options.aiDocs);
|
|
@@ -6820,10 +6863,30 @@ function validateFrontendConstraints(config, providedFlags) {
|
|
|
6820
6863
|
ensureSingleWebAndNative(frontend);
|
|
6821
6864
|
if (providedFlags.has("api") && providedFlags.has("frontend") && config.api) validateApiFrontendCompatibility(config.api, frontend, config.astroIntegration);
|
|
6822
6865
|
}
|
|
6823
|
-
const hasWebFrontendFlag = (frontend ?? []).some((f) => isWebFrontend(f));
|
|
6866
|
+
const hasWebFrontendFlag = (frontend ?? []).some((f) => isWebFrontend$1(f));
|
|
6824
6867
|
validateWebDeployRequiresWebFrontend(config.webDeploy, hasWebFrontendFlag);
|
|
6825
6868
|
}
|
|
6826
6869
|
function validateApiConstraints(_config, _options) {}
|
|
6870
|
+
function validateShadcnConstraints(config, providedFlags) {
|
|
6871
|
+
const shadcnFlagMap = {
|
|
6872
|
+
shadcnBase: "--shadcn-base",
|
|
6873
|
+
shadcnStyle: "--shadcn-style",
|
|
6874
|
+
shadcnIconLibrary: "--shadcn-icon-library",
|
|
6875
|
+
shadcnColorTheme: "--shadcn-color-theme",
|
|
6876
|
+
shadcnBaseColor: "--shadcn-base-color",
|
|
6877
|
+
shadcnFont: "--shadcn-font",
|
|
6878
|
+
shadcnRadius: "--shadcn-radius"
|
|
6879
|
+
};
|
|
6880
|
+
const providedShadcnFlags = Object.keys(shadcnFlagMap).filter((f) => providedFlags.has(f));
|
|
6881
|
+
if (providedShadcnFlags.length > 0 && config.uiLibrary !== "shadcn-ui") incompatibilityError({
|
|
6882
|
+
message: "shadcn/ui customization flags require --ui-library shadcn-ui.",
|
|
6883
|
+
provided: {
|
|
6884
|
+
"ui-library": config.uiLibrary || "none",
|
|
6885
|
+
...Object.fromEntries(providedShadcnFlags.map((f) => [shadcnFlagMap[f], String(config[f] ?? "")]))
|
|
6886
|
+
},
|
|
6887
|
+
suggestions: ["Add --ui-library shadcn-ui to use shadcn customization flags", "Remove the --shadcn-* flags if not using shadcn/ui"]
|
|
6888
|
+
});
|
|
6889
|
+
}
|
|
6827
6890
|
function validateFullConfig(config, providedFlags, options) {
|
|
6828
6891
|
validateDatabaseOrmAuth(config, providedFlags);
|
|
6829
6892
|
validateDatabaseSetup(config, providedFlags);
|
|
@@ -6853,6 +6916,7 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
6853
6916
|
validateAuth0Compatibility(config.auth, config.backend, config.frontend ?? []);
|
|
6854
6917
|
validateUILibraryFrontendCompatibility(config.uiLibrary, config.frontend ?? [], config.astroIntegration);
|
|
6855
6918
|
validateUILibraryCSSFrameworkCompatibility(config.uiLibrary, config.cssFramework);
|
|
6919
|
+
validateShadcnConstraints(config, providedFlags);
|
|
6856
6920
|
validatePeerDependencies(config);
|
|
6857
6921
|
}
|
|
6858
6922
|
function validateConfigForProgrammaticUse(config) {
|
|
@@ -8880,6 +8944,13 @@ const router = os.router({
|
|
|
8880
8944
|
api: types_exports.APISchema.optional(),
|
|
8881
8945
|
cssFramework: types_exports.CSSFrameworkSchema.optional(),
|
|
8882
8946
|
uiLibrary: types_exports.UILibrarySchema.optional(),
|
|
8947
|
+
shadcnBase: types_exports.ShadcnBaseSchema.optional().describe("shadcn/ui headless library (radix, base)"),
|
|
8948
|
+
shadcnStyle: types_exports.ShadcnStyleSchema.optional().describe("shadcn/ui visual style (vega, nova, maia, lyra, mira)"),
|
|
8949
|
+
shadcnIconLibrary: types_exports.ShadcnIconLibrarySchema.optional().describe("shadcn/ui icon library (lucide, tabler, hugeicons, phosphor, remixicon)"),
|
|
8950
|
+
shadcnColorTheme: types_exports.ShadcnColorThemeSchema.optional().describe("shadcn/ui color theme (neutral, blue, violet, etc.)"),
|
|
8951
|
+
shadcnBaseColor: types_exports.ShadcnBaseColorSchema.optional().describe("shadcn/ui base neutral color (neutral, stone, zinc, gray)"),
|
|
8952
|
+
shadcnFont: types_exports.ShadcnFontSchema.optional().describe("shadcn/ui font (inter, geist, figtree, etc.)"),
|
|
8953
|
+
shadcnRadius: types_exports.ShadcnRadiusSchema.optional().describe("shadcn/ui border radius (default, none, small, medium, large)"),
|
|
8883
8954
|
webDeploy: types_exports.WebDeploySchema.optional(),
|
|
8884
8955
|
serverDeploy: types_exports.ServerDeploySchema.optional(),
|
|
8885
8956
|
directoryConflict: types_exports.DirectoryConflictSchema.optional(),
|
|
@@ -9098,6 +9169,13 @@ async function createVirtual(options) {
|
|
|
9098
9169
|
serverDeploy: options.serverDeploy || "none",
|
|
9099
9170
|
cssFramework: options.cssFramework || "tailwind",
|
|
9100
9171
|
uiLibrary: options.uiLibrary || "shadcn-ui",
|
|
9172
|
+
shadcnBase: options.shadcnBase ?? "radix",
|
|
9173
|
+
shadcnStyle: options.shadcnStyle ?? "nova",
|
|
9174
|
+
shadcnIconLibrary: options.shadcnIconLibrary ?? "lucide",
|
|
9175
|
+
shadcnColorTheme: options.shadcnColorTheme ?? "neutral",
|
|
9176
|
+
shadcnBaseColor: options.shadcnBaseColor ?? "neutral",
|
|
9177
|
+
shadcnFont: options.shadcnFont ?? "inter",
|
|
9178
|
+
shadcnRadius: options.shadcnRadius ?? "default",
|
|
9101
9179
|
ai: options.ai || "none",
|
|
9102
9180
|
stateManagement: options.stateManagement || "none",
|
|
9103
9181
|
forms: options.forms || "react-hook-form",
|