create-turbo-wizard 0.1.2 → 0.2.0
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 +386 -67
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -15,13 +15,38 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
17
|
|
|
18
|
+
// ../../packages/types/src/command.ts
|
|
19
|
+
function buildCommand(config) {
|
|
20
|
+
const parts = [
|
|
21
|
+
...CREATE_PREFIX[config.packageManager],
|
|
22
|
+
`--name ${config.name}`,
|
|
23
|
+
`--frontend ${config.frontend}`,
|
|
24
|
+
`--content ${config.content}`,
|
|
25
|
+
`--package-manager ${config.packageManager}`
|
|
26
|
+
];
|
|
27
|
+
config.deploy !== "node" && parts.push(`--deploy ${config.deploy}`);
|
|
28
|
+
config.modules.length && parts.push(`--modules ${config.modules.join(" ")}`);
|
|
29
|
+
config.experimental.cacheComponents && parts.push("--cache-components");
|
|
30
|
+
config.experimental.reactCompiler && parts.push("--react-compiler");
|
|
31
|
+
return parts.join(" ");
|
|
32
|
+
}
|
|
33
|
+
var CREATE_PREFIX;
|
|
34
|
+
var init_command = __esm(() => {
|
|
35
|
+
CREATE_PREFIX = {
|
|
36
|
+
npm: ["npm create turbo-wizard@latest", "--"],
|
|
37
|
+
pnpm: ["pnpm create turbo-wizard@latest"],
|
|
38
|
+
bun: ["bun create turbo-wizard@latest"]
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
|
|
18
42
|
// ../../packages/types/src/index.ts
|
|
19
43
|
import { z } from "zod";
|
|
20
44
|
function applyPreset(preset, overrides = {}) {
|
|
21
45
|
return { ...PRESET_CONFIGS[preset], ...overrides };
|
|
22
46
|
}
|
|
23
|
-
var FRONTENDS, CONTENT_SOURCES, PACKAGE_MANAGERS, MODULES, DEPLOY_TARGETS, FrontendSchema, ContentSourceSchema, PackageManagerSchema, ModuleSchema, DeployTargetSchema, ExperimentalSchema, ProjectNameSchema, WizardConfigSchema, wizardConfigJsonSchema = () => z.toJSONSchema(WizardConfigSchema), PRESETS, PRESET_CONFIGS;
|
|
47
|
+
var FRONTENDS, CONTENT_SOURCES, PACKAGE_MANAGERS, MODULES, MODULE_CATEGORIES, DEPLOY_TARGETS, FrontendSchema, ContentSourceSchema, PackageManagerSchema, ModuleSchema, DeployTargetSchema, ExperimentalSchema, ProjectNameSchema, WizardConfigSchema, wizardConfigJsonSchema = () => z.toJSONSchema(WizardConfigSchema), PRESETS, PRESET_CONFIGS;
|
|
24
48
|
var init_src = __esm(() => {
|
|
49
|
+
init_command();
|
|
25
50
|
FRONTENDS = ["astro", "next"];
|
|
26
51
|
CONTENT_SOURCES = ["sanity", "markdown", "none"];
|
|
27
52
|
PACKAGE_MANAGERS = ["pnpm", "bun", "npm"];
|
|
@@ -39,6 +64,7 @@ var init_src = __esm(() => {
|
|
|
39
64
|
"forms",
|
|
40
65
|
"llms"
|
|
41
66
|
];
|
|
67
|
+
MODULE_CATEGORIES = ["devtools", "integration", "ui", "cross-cutting"];
|
|
42
68
|
DEPLOY_TARGETS = ["node", "vercel"];
|
|
43
69
|
FrontendSchema = z.enum(FRONTENDS).describe("Web framework");
|
|
44
70
|
ContentSourceSchema = z.enum(CONTENT_SOURCES).describe("Content source");
|
|
@@ -75,7 +101,7 @@ var package_default;
|
|
|
75
101
|
var init_package = __esm(() => {
|
|
76
102
|
package_default = {
|
|
77
103
|
name: "create-turbo-wizard",
|
|
78
|
-
version: "0.
|
|
104
|
+
version: "0.2.0",
|
|
79
105
|
description: "Scaffold a Turborepo monorepo: Astro or Next.js, Sanity or Markdown, opt-in modules.",
|
|
80
106
|
keywords: [
|
|
81
107
|
"turborepo",
|
|
@@ -3886,6 +3912,10 @@ var init_astro = __esm(() => {
|
|
|
3886
3912
|
astroFrontend = {
|
|
3887
3913
|
id: "astro",
|
|
3888
3914
|
kind: "frontend",
|
|
3915
|
+
prompt: {
|
|
3916
|
+
label: "Astro",
|
|
3917
|
+
hint: "Islands architecture, zero client JS by default"
|
|
3918
|
+
},
|
|
3889
3919
|
templates: [
|
|
3890
3920
|
{
|
|
3891
3921
|
path: "apps/web/package.json",
|
|
@@ -4061,6 +4091,10 @@ var init_next = __esm(() => {
|
|
|
4061
4091
|
nextFrontend = {
|
|
4062
4092
|
id: "next",
|
|
4063
4093
|
kind: "frontend",
|
|
4094
|
+
prompt: {
|
|
4095
|
+
label: "Next.js",
|
|
4096
|
+
hint: "App Router, React Server Components, Turbopack"
|
|
4097
|
+
},
|
|
4064
4098
|
templates: [
|
|
4065
4099
|
{
|
|
4066
4100
|
path: "apps/web/package.json",
|
|
@@ -6731,6 +6765,35 @@ var init_vitest = __esm(() => {
|
|
|
6731
6765
|
};
|
|
6732
6766
|
});
|
|
6733
6767
|
|
|
6768
|
+
// ../../packages/registry/src/catalog.ts
|
|
6769
|
+
function withPrerequisites(selected) {
|
|
6770
|
+
const chosen = new Set(selected);
|
|
6771
|
+
const added = [];
|
|
6772
|
+
const queue = [...selected];
|
|
6773
|
+
for (const id of queue) {
|
|
6774
|
+
for (const required of MODULE_DESCRIPTORS[id]?.compat?.requiresModules ?? []) {
|
|
6775
|
+
if (chosen.has(required))
|
|
6776
|
+
continue;
|
|
6777
|
+
chosen.add(required);
|
|
6778
|
+
added.push([required, id]);
|
|
6779
|
+
queue.push(required);
|
|
6780
|
+
}
|
|
6781
|
+
}
|
|
6782
|
+
return { modules: MODULES.filter((id) => chosen.has(id)), added };
|
|
6783
|
+
}
|
|
6784
|
+
var entry = (id, descriptor) => ({
|
|
6785
|
+
id,
|
|
6786
|
+
label: descriptor?.prompt?.label ?? id,
|
|
6787
|
+
hint: descriptor?.prompt?.hint ?? "",
|
|
6788
|
+
category: descriptor?.category,
|
|
6789
|
+
requires: descriptor?.compat?.requiresModules ?? []
|
|
6790
|
+
}), moduleCatalog = () => MODULES.map((id) => entry(id, MODULE_DESCRIPTORS[id])), frontendCatalog = () => FRONTENDS.map((id) => entry(id, FRONTEND_DESCRIPTORS[id])), NO_CONTENT, contentCatalog = () => CONTENT_SOURCES.map((id) => id === "none" ? { id, ...NO_CONTENT, category: undefined, requires: [] } : entry(id, CONTENT_DESCRIPTORS[id]));
|
|
6791
|
+
var init_catalog = __esm(() => {
|
|
6792
|
+
init_src();
|
|
6793
|
+
init_src3();
|
|
6794
|
+
NO_CONTENT = { label: "None", hint: "No CMS and no MDX — just the frontend" };
|
|
6795
|
+
});
|
|
6796
|
+
|
|
6734
6797
|
// ../../packages/registry/src/index.ts
|
|
6735
6798
|
function buildRegistry(config2) {
|
|
6736
6799
|
const content = CONTENT_DESCRIPTORS[config2.content];
|
|
@@ -6769,6 +6832,7 @@ var init_src3 = __esm(() => {
|
|
|
6769
6832
|
init_seo();
|
|
6770
6833
|
init_ui();
|
|
6771
6834
|
init_vitest();
|
|
6835
|
+
init_catalog();
|
|
6772
6836
|
baselineDescriptors = [typescriptConfig, env, logger, biome];
|
|
6773
6837
|
FRONTEND_DESCRIPTORS = {
|
|
6774
6838
|
next: nextFrontend,
|
|
@@ -6795,40 +6859,82 @@ var init_src3 = __esm(() => {
|
|
|
6795
6859
|
});
|
|
6796
6860
|
|
|
6797
6861
|
// src/create.ts
|
|
6798
|
-
import { spawnSync } from "node:child_process";
|
|
6862
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
6799
6863
|
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
6800
6864
|
import { resolve } from "node:path";
|
|
6801
|
-
function step(label, cmd, args, cwd, stdio = "ignore") {
|
|
6865
|
+
function step(label, cmd, args, cwd, stdio = "ignore", onWarn = warn) {
|
|
6802
6866
|
const res = spawnSync(cmd, args, { cwd, stdio });
|
|
6803
6867
|
if (res.error) {
|
|
6804
|
-
|
|
6868
|
+
onWarn(`${label} skipped: ${res.error.message}`);
|
|
6805
6869
|
return false;
|
|
6806
6870
|
}
|
|
6807
6871
|
if (res.status !== 0) {
|
|
6808
|
-
|
|
6872
|
+
onWarn(`${label} failed (exit ${res.status ?? `signal ${res.signal}`})`);
|
|
6809
6873
|
return false;
|
|
6810
6874
|
}
|
|
6811
6875
|
return true;
|
|
6812
6876
|
}
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6877
|
+
function streamStep(label, cmd, args, cwd, onOutput, onWarn) {
|
|
6878
|
+
return new Promise((done) => {
|
|
6879
|
+
const child = spawn(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
6880
|
+
const emit = (chunk) => {
|
|
6881
|
+
for (const line of chunk.toString().split(/\r?\n|\r/)) {
|
|
6882
|
+
if (line.trim())
|
|
6883
|
+
onOutput(line);
|
|
6884
|
+
}
|
|
6885
|
+
};
|
|
6886
|
+
child.stdout?.on("data", emit);
|
|
6887
|
+
child.stderr?.on("data", emit);
|
|
6888
|
+
child.on("error", (error) => {
|
|
6889
|
+
onWarn(`${label} skipped: ${error.message}`);
|
|
6890
|
+
done(false);
|
|
6891
|
+
});
|
|
6892
|
+
child.on("close", (code, signal) => {
|
|
6893
|
+
if (code === 0)
|
|
6894
|
+
return done(true);
|
|
6895
|
+
onWarn(`${label} failed (exit ${code ?? `signal ${signal}`})`);
|
|
6896
|
+
done(false);
|
|
6897
|
+
});
|
|
6898
|
+
});
|
|
6899
|
+
}
|
|
6900
|
+
function planProject(config2) {
|
|
6901
|
+
return generate(config2, buildRegistry(config2));
|
|
6902
|
+
}
|
|
6903
|
+
async function writeProject(tree, config2, opts = {}) {
|
|
6904
|
+
const { onWarn = warn, onOutput } = opts;
|
|
6817
6905
|
const dir = resolve(opts.targetDir ?? config2.name);
|
|
6818
6906
|
await mkdir2(dir, { recursive: true });
|
|
6819
|
-
await writeTree(
|
|
6907
|
+
await writeTree(tree, dir);
|
|
6820
6908
|
if (opts.git) {
|
|
6821
|
-
const inited = step("git init", "git", ["init", "-q"], dir);
|
|
6822
|
-
const added = inited && step("git add", "git", ["add", "-A"], dir);
|
|
6909
|
+
const inited = step("git init", "git", ["init", "-q"], dir, "ignore", onWarn);
|
|
6910
|
+
const added = inited && step("git add", "git", ["add", "-A"], dir, "ignore", onWarn);
|
|
6823
6911
|
if (added) {
|
|
6824
|
-
|
|
6912
|
+
const args = ["commit", "-qm", "chore: scaffold with create-turbo-wizard"];
|
|
6913
|
+
step("git commit", "git", args, dir, "ignore", onWarn);
|
|
6825
6914
|
}
|
|
6826
6915
|
}
|
|
6916
|
+
let installError;
|
|
6827
6917
|
if (opts.install) {
|
|
6828
|
-
|
|
6918
|
+
const label = `${config2.packageManager} install`;
|
|
6919
|
+
const capture = (message) => {
|
|
6920
|
+
installError = message;
|
|
6921
|
+
};
|
|
6922
|
+
const ok2 = onOutput ? await streamStep(label, config2.packageManager, ["install"], dir, onOutput, capture) : step(label, config2.packageManager, ["install"], dir, "inherit", capture);
|
|
6923
|
+
if (ok2)
|
|
6924
|
+
installError = null;
|
|
6829
6925
|
}
|
|
6830
|
-
return {
|
|
6926
|
+
return { dir, fileCount: tree.size, installError };
|
|
6831
6927
|
}
|
|
6928
|
+
async function createProject(config2, opts = {}) {
|
|
6929
|
+
const res = planProject(config2);
|
|
6930
|
+
if (!res.ok)
|
|
6931
|
+
return res;
|
|
6932
|
+
const value = await writeProject(res.value, config2, opts);
|
|
6933
|
+
if (value.installError)
|
|
6934
|
+
(opts.onWarn ?? warn)(value.installError);
|
|
6935
|
+
return { ok: true, value };
|
|
6936
|
+
}
|
|
6937
|
+
var warn = (message) => console.error(`! ${message}`);
|
|
6832
6938
|
var init_create = __esm(() => {
|
|
6833
6939
|
init_src2();
|
|
6834
6940
|
init_src3();
|
|
@@ -6838,7 +6944,7 @@ var init_create = __esm(() => {
|
|
|
6838
6944
|
var exports_mcp = {};
|
|
6839
6945
|
__export(exports_mcp, {
|
|
6840
6946
|
startMcpServer: () => startMcpServer,
|
|
6841
|
-
planProject: () =>
|
|
6947
|
+
planProject: () => planProject2,
|
|
6842
6948
|
guidanceText: () => guidanceText,
|
|
6843
6949
|
createProjectFromInput: () => createProjectFromInput,
|
|
6844
6950
|
buildMcpServer: () => buildMcpServer
|
|
@@ -6846,7 +6952,7 @@ __export(exports_mcp, {
|
|
|
6846
6952
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6847
6953
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6848
6954
|
import { z as z3 } from "zod";
|
|
6849
|
-
function
|
|
6955
|
+
function planProject2(input) {
|
|
6850
6956
|
const config2 = toConfig(input);
|
|
6851
6957
|
const res = generate(config2, buildRegistry(config2));
|
|
6852
6958
|
if (!res.ok)
|
|
@@ -6864,7 +6970,7 @@ function buildMcpServer() {
|
|
|
6864
6970
|
description: "Preview the files a configuration would generate (does NOT write to disk).",
|
|
6865
6971
|
inputSchema: PlanInput
|
|
6866
6972
|
}, (input) => {
|
|
6867
|
-
const res =
|
|
6973
|
+
const res = planProject2(input);
|
|
6868
6974
|
return res.ok ? text2(res.paths.join(`
|
|
6869
6975
|
`)) : { ...text2(`Generation failed: ${res.error}`), isError: true };
|
|
6870
6976
|
});
|
|
@@ -6921,59 +7027,259 @@ var init_mcp = __esm(() => {
|
|
|
6921
7027
|
init_src();
|
|
6922
7028
|
init_package();
|
|
6923
7029
|
init_create();
|
|
7030
|
+
import { resolve as resolve2 } from "node:path";
|
|
7031
|
+
import { cancel as cancel3, confirm, isCancel, log as log3 } from "@clack/prompts";
|
|
6924
7032
|
import { initTRPC } from "@trpc/server";
|
|
6925
7033
|
import { createCli } from "trpc-cli";
|
|
6926
7034
|
import { z as z2 } from "zod";
|
|
6927
7035
|
|
|
6928
7036
|
// src/prompts.ts
|
|
7037
|
+
init_src3();
|
|
6929
7038
|
init_src();
|
|
6930
|
-
import { cancel,
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
7039
|
+
import { cancel, group, groupMultiselect, log, select, text } from "@clack/prompts";
|
|
7040
|
+
|
|
7041
|
+
// src/theme.ts
|
|
7042
|
+
import { WriteStream } from "node:tty";
|
|
7043
|
+
import { isCI, unicode } from "@clack/prompts";
|
|
7044
|
+
var resolveDepth = () => {
|
|
7045
|
+
const stream = process.stdout;
|
|
7046
|
+
if (typeof stream.getColorDepth === "function")
|
|
7047
|
+
return stream.getColorDepth();
|
|
7048
|
+
return process.env.FORCE_COLOR ? WriteStream.prototype.getColorDepth() : 1;
|
|
7049
|
+
};
|
|
7050
|
+
var depth = resolveDepth();
|
|
7051
|
+
var wrap = (open, close) => (value) => `\x1B[${open}m${value}\x1B[${close}m`;
|
|
7052
|
+
var plain = (value) => value;
|
|
7053
|
+
var scale = (rgb, x256, basic) => {
|
|
7054
|
+
if (depth >= 24)
|
|
7055
|
+
return wrap(`38;2;${rgb[0]};${rgb[1]};${rgb[2]}`, "39");
|
|
7056
|
+
if (depth >= 8)
|
|
7057
|
+
return wrap(`38;5;${x256}`, "39");
|
|
7058
|
+
if (depth >= 4)
|
|
7059
|
+
return wrap(String(basic), "39");
|
|
7060
|
+
return plain;
|
|
7061
|
+
};
|
|
7062
|
+
var effect = (open, close) => depth >= 4 ? wrap(open, close) : plain;
|
|
7063
|
+
var accent = scale([124, 140, 255], 105, 36);
|
|
7064
|
+
var accentDim = scale([74, 85, 168], 61, 34);
|
|
7065
|
+
var muted = scale([153, 161, 179], 109, 90);
|
|
7066
|
+
var success = scale([74, 222, 128], 78, 32);
|
|
7067
|
+
var warn2 = scale([251, 191, 36], 214, 33);
|
|
7068
|
+
var danger = scale([248, 113, 113], 203, 31);
|
|
7069
|
+
var bold = effect("1", "22");
|
|
7070
|
+
var dim = effect("2", "22");
|
|
7071
|
+
var badge = (value) => depth >= 24 ? `\x1B[48;2;124;140;255m\x1B[30m ${value} \x1B[39m\x1B[49m` : depth >= 8 ? `\x1B[48;5;105m\x1B[30m ${value} \x1B[39m\x1B[49m` : depth >= 4 ? `\x1B[46m\x1B[30m ${value} \x1B[39m\x1B[49m` : ` ${value} `;
|
|
7072
|
+
var WORDMARK = [
|
|
7073
|
+
"████████╗██╗ ██╗██╗███████╗",
|
|
7074
|
+
"╚══██╔══╝██║ ██║██║╚══███╔╝",
|
|
7075
|
+
" ██║ ██║ █╗ ██║██║ ███╔╝ ",
|
|
7076
|
+
" ██║ ██║███╗██║██║ ███╔╝ ",
|
|
7077
|
+
" ██║ ╚███╔███╔╝██║███████╗",
|
|
7078
|
+
" ╚═╝ ╚══╝╚══╝ ╚═╝╚══════╝"
|
|
7079
|
+
];
|
|
7080
|
+
var WORDMARK_WIDTH = 30;
|
|
7081
|
+
var TAGLINE = "scaffold a Turborepo monorepo";
|
|
7082
|
+
var shade = (row) => (row.match(/█+|[^█]+/g) ?? []).map((run) => run.startsWith("█") ? accent(run) : accentDim(run)).join("");
|
|
7083
|
+
function banner(version) {
|
|
7084
|
+
if (!process.stdout.isTTY || isCI() || !unicode)
|
|
7085
|
+
return null;
|
|
7086
|
+
const label = `v${version}`;
|
|
7087
|
+
const gap = Math.max(2, WORDMARK_WIDTH - 2 - TAGLINE.length - label.length);
|
|
7088
|
+
const width = Math.max(WORDMARK_WIDTH, 2 + TAGLINE.length + gap + label.length);
|
|
7089
|
+
if ((process.stdout.columns ?? 80) < width + 2)
|
|
7090
|
+
return null;
|
|
7091
|
+
const footer = ` ${muted(TAGLINE)}${" ".repeat(gap)}${dim(label)}`;
|
|
7092
|
+
return `
|
|
7093
|
+
${WORDMARK.map(shade).join(`
|
|
7094
|
+
`)}
|
|
7095
|
+
|
|
7096
|
+
${footer}
|
|
7097
|
+
`;
|
|
7098
|
+
}
|
|
7099
|
+
|
|
7100
|
+
// src/prompts.ts
|
|
7101
|
+
var toOption = (entry2) => ({
|
|
7102
|
+
value: entry2.id,
|
|
7103
|
+
label: entry2.label,
|
|
7104
|
+
...entry2.hint ? { hint: entry2.hint } : {}
|
|
7105
|
+
});
|
|
7106
|
+
var PACKAGE_MANAGER_HINTS = {
|
|
7107
|
+
pnpm: "Strict node_modules, workspace: protocol",
|
|
7108
|
+
bun: "Fastest install, workspace: protocol",
|
|
7109
|
+
npm: "No workspace: protocol — deps are rewritten to *"
|
|
7110
|
+
};
|
|
7111
|
+
var DEPLOY_HINTS = {
|
|
7112
|
+
node: "@astrojs/node — runs anywhere, and what `astro preview` serves",
|
|
7113
|
+
vercel: "@astrojs/vercel — required once a server route deploys to Vercel"
|
|
7114
|
+
};
|
|
7115
|
+
var CATEGORY_LABELS = {
|
|
7116
|
+
ui: "UI",
|
|
7117
|
+
integration: "Integrations",
|
|
7118
|
+
devtools: "Developer tooling",
|
|
7119
|
+
"cross-cutting": "Cross-cutting"
|
|
7120
|
+
};
|
|
7121
|
+
var moduleGroups = () => {
|
|
7122
|
+
const catalog = moduleCatalog();
|
|
7123
|
+
const groups = {};
|
|
7124
|
+
for (const category of MODULE_CATEGORIES) {
|
|
7125
|
+
const entries = catalog.filter((entry2) => entry2.category === category);
|
|
7126
|
+
if (entries.length)
|
|
7127
|
+
groups[CATEGORY_LABELS[category]] = entries.map(toOption);
|
|
6935
7128
|
}
|
|
6936
|
-
return
|
|
7129
|
+
return groups;
|
|
7130
|
+
};
|
|
7131
|
+
var bail = () => {
|
|
7132
|
+
cancel("Cancelled.");
|
|
7133
|
+
process.exit(0);
|
|
6937
7134
|
};
|
|
6938
7135
|
async function gatherConfig(flags) {
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
7136
|
+
const answers = await group({
|
|
7137
|
+
name: () => flags.name ? Promise.resolve(flags.name) : text({
|
|
7138
|
+
message: "Project name",
|
|
7139
|
+
placeholder: "my-app",
|
|
7140
|
+
defaultValue: "my-app",
|
|
7141
|
+
validate: (value) => {
|
|
7142
|
+
const parsed = ProjectNameSchema.safeParse(value || "my-app");
|
|
7143
|
+
return parsed.success ? undefined : parsed.error.issues[0]?.message;
|
|
7144
|
+
}
|
|
7145
|
+
}),
|
|
7146
|
+
frontend: () => flags.frontend ? Promise.resolve(flags.frontend) : select({
|
|
7147
|
+
message: "Frontend framework",
|
|
7148
|
+
options: frontendCatalog().map(toOption),
|
|
7149
|
+
initialValue: "next"
|
|
7150
|
+
}),
|
|
7151
|
+
content: () => flags.content ? Promise.resolve(flags.content) : select({
|
|
7152
|
+
message: "Content source",
|
|
7153
|
+
options: contentCatalog().map(toOption)
|
|
7154
|
+
}),
|
|
7155
|
+
packageManager: () => flags.packageManager ? Promise.resolve(flags.packageManager) : select({
|
|
7156
|
+
message: "Package manager",
|
|
7157
|
+
options: PACKAGE_MANAGERS.map((value) => ({
|
|
7158
|
+
value,
|
|
7159
|
+
label: value,
|
|
7160
|
+
hint: PACKAGE_MANAGER_HINTS[value]
|
|
7161
|
+
}))
|
|
7162
|
+
}),
|
|
7163
|
+
deploy: ({ results }) => flags.deploy || results.frontend !== "astro" ? Promise.resolve(flags.deploy ?? "node") : select({
|
|
7164
|
+
message: "Deploy target",
|
|
7165
|
+
options: DEPLOY_TARGETS.map((value) => ({
|
|
7166
|
+
value,
|
|
7167
|
+
label: value,
|
|
7168
|
+
hint: DEPLOY_HINTS[value]
|
|
7169
|
+
}))
|
|
7170
|
+
}),
|
|
7171
|
+
modules: () => flags.modules ? Promise.resolve(flags.modules) : groupMultiselect({
|
|
7172
|
+
message: `Modules ${muted("(space to toggle, enter to confirm)")}`,
|
|
7173
|
+
options: moduleGroups(),
|
|
7174
|
+
required: false
|
|
7175
|
+
})
|
|
7176
|
+
}, { onCancel: bail });
|
|
7177
|
+
const picked = (answers.modules ?? []).filter((id) => MODULES.includes(id));
|
|
7178
|
+
const resolved = flags.modules ? { modules: picked, added: [] } : withPrerequisites(picked);
|
|
7179
|
+
for (const [module, requiredBy] of resolved.added) {
|
|
7180
|
+
log.info(`Added ${accent(module)} — required by ${accent(requiredBy)}`);
|
|
7181
|
+
}
|
|
6967
7182
|
return WizardConfigSchema.parse({
|
|
6968
|
-
name,
|
|
6969
|
-
frontend,
|
|
6970
|
-
content,
|
|
6971
|
-
packageManager,
|
|
6972
|
-
|
|
7183
|
+
name: answers.name,
|
|
7184
|
+
frontend: answers.frontend,
|
|
7185
|
+
content: answers.content,
|
|
7186
|
+
packageManager: answers.packageManager,
|
|
7187
|
+
deploy: answers.deploy,
|
|
7188
|
+
modules: resolved.modules,
|
|
6973
7189
|
experimental: { cacheComponents: flags.cacheComponents, reactCompiler: flags.reactCompiler }
|
|
6974
7190
|
});
|
|
6975
7191
|
}
|
|
6976
7192
|
|
|
7193
|
+
// src/ui.ts
|
|
7194
|
+
init_src3();
|
|
7195
|
+
init_src();
|
|
7196
|
+
import { relative, sep } from "node:path";
|
|
7197
|
+
import { cancel as cancel2, intro, log as log2, note, outro, taskLog } from "@clack/prompts";
|
|
7198
|
+
var RAW = { format: (line) => line };
|
|
7199
|
+
function printBanner(version) {
|
|
7200
|
+
const art = banner(version);
|
|
7201
|
+
if (art)
|
|
7202
|
+
process.stdout.write(`${art}
|
|
7203
|
+
`);
|
|
7204
|
+
}
|
|
7205
|
+
function start() {
|
|
7206
|
+
intro(badge("create-turbo-wizard"));
|
|
7207
|
+
}
|
|
7208
|
+
function displayPath(dir) {
|
|
7209
|
+
const rel = relative(process.cwd(), dir);
|
|
7210
|
+
return rel && !rel.startsWith("..") && !rel.startsWith(sep) ? `./${rel}` : dir;
|
|
7211
|
+
}
|
|
7212
|
+
function shape(tree) {
|
|
7213
|
+
const nested = new Map;
|
|
7214
|
+
let rootFiles = 0;
|
|
7215
|
+
for (const path of tree.keys()) {
|
|
7216
|
+
const [top, second] = path.split("/");
|
|
7217
|
+
if (!top)
|
|
7218
|
+
continue;
|
|
7219
|
+
if (second && (top === "apps" || top === "packages")) {
|
|
7220
|
+
const names = nested.get(top) ?? new Set;
|
|
7221
|
+
names.add(second);
|
|
7222
|
+
nested.set(top, names);
|
|
7223
|
+
} else if (!second) {
|
|
7224
|
+
rootFiles += 1;
|
|
7225
|
+
}
|
|
7226
|
+
}
|
|
7227
|
+
const parts = [...nested].sort(([a], [b]) => a.localeCompare(b)).map(([top, names]) => names.size > 3 ? `${names.size} ${top}` : `${top}/{${[...names].sort().join(", ")}}`);
|
|
7228
|
+
if (rootFiles)
|
|
7229
|
+
parts.push(`${rootFiles} root files`);
|
|
7230
|
+
return parts.join(" ");
|
|
7231
|
+
}
|
|
7232
|
+
var labelOf = (entries, id) => entries.find((entry2) => entry2.id === id)?.label ?? id;
|
|
7233
|
+
var row = (label, value) => `${muted(label.padEnd(10))}${value}`;
|
|
7234
|
+
function summary(config2, tree, dir) {
|
|
7235
|
+
const stack = [
|
|
7236
|
+
labelOf(frontendCatalog(), config2.frontend),
|
|
7237
|
+
labelOf(contentCatalog(), config2.content),
|
|
7238
|
+
config2.packageManager
|
|
7239
|
+
].join(" · ");
|
|
7240
|
+
note([
|
|
7241
|
+
row("Directory", accent(displayPath(dir))),
|
|
7242
|
+
row("Stack", stack),
|
|
7243
|
+
row("Modules", config2.modules.length ? config2.modules.join(", ") : muted("none")),
|
|
7244
|
+
row("Writing", `${tree.size} files ${muted(shape(tree))}`),
|
|
7245
|
+
"",
|
|
7246
|
+
muted("Reproduce this with"),
|
|
7247
|
+
dim(buildCommand(config2))
|
|
7248
|
+
].join(`
|
|
7249
|
+
`), "Summary", RAW);
|
|
7250
|
+
}
|
|
7251
|
+
function installLog(config2) {
|
|
7252
|
+
const task = taskLog({
|
|
7253
|
+
title: `Installing dependencies with ${config2.packageManager}`,
|
|
7254
|
+
limit: 8
|
|
7255
|
+
});
|
|
7256
|
+
return {
|
|
7257
|
+
onOutput: (line) => task.message(line, { raw: true }),
|
|
7258
|
+
finish: (error) => error ? task.error(error, { showLog: true }) : task.success(`${config2.packageManager} install`)
|
|
7259
|
+
};
|
|
7260
|
+
}
|
|
7261
|
+
var runScript = (config2, script) => config2.packageManager === "npm" ? `npm run ${script}` : `${config2.packageManager} ${script}`;
|
|
7262
|
+
function nextSteps(config2, tree, dir, installed) {
|
|
7263
|
+
const commands = [`cd ${displayPath(dir)}`];
|
|
7264
|
+
if (!installed)
|
|
7265
|
+
commands.push(`${config2.packageManager} install`);
|
|
7266
|
+
commands.push(runScript(config2, "dev"));
|
|
7267
|
+
if (config2.content === "sanity")
|
|
7268
|
+
commands.push(runScript(config2, "dev:studio"));
|
|
7269
|
+
const extras = [];
|
|
7270
|
+
if (tree.has(".env.example"))
|
|
7271
|
+
extras.push(row("Env", "copy .env.example to .env and fill it in"));
|
|
7272
|
+
extras.push(row("Docs", "https://turbo-wizard.vercel.app/docs"));
|
|
7273
|
+
note([...commands.map(accent), "", ...extras].join(`
|
|
7274
|
+
`), "Next steps", RAW);
|
|
7275
|
+
outro(success(`Created ${config2.name} — ${tree.size} files`));
|
|
7276
|
+
}
|
|
7277
|
+
function fail(message) {
|
|
7278
|
+
log2.error(message);
|
|
7279
|
+
cancel2("Nothing was written.");
|
|
7280
|
+
process.exit(1);
|
|
7281
|
+
}
|
|
7282
|
+
|
|
6977
7283
|
// src/router.ts
|
|
6978
7284
|
var t = initTRPC.create();
|
|
6979
7285
|
var CreateInput = z2.object({
|
|
@@ -7004,6 +7310,8 @@ var router = t.router({
|
|
|
7004
7310
|
cacheComponents: input.cacheComponents ?? base.experimental?.cacheComponents,
|
|
7005
7311
|
reactCompiler: input.reactCompiler ?? base.experimental?.reactCompiler
|
|
7006
7312
|
};
|
|
7313
|
+
printBanner(package_default.version);
|
|
7314
|
+
start();
|
|
7007
7315
|
const interactive = !input.yes && !input.preset && Boolean(process.stdout.isTTY) && (!input.frontend || !input.name);
|
|
7008
7316
|
const config2 = interactive ? await gatherConfig(flags) : WizardConfigSchema.parse({
|
|
7009
7317
|
name: flags.name ?? "my-app",
|
|
@@ -7017,17 +7325,28 @@ var router = t.router({
|
|
|
7017
7325
|
reactCompiler: flags.reactCompiler
|
|
7018
7326
|
}
|
|
7019
7327
|
});
|
|
7020
|
-
const
|
|
7021
|
-
|
|
7328
|
+
const plan = planProject(config2);
|
|
7329
|
+
if (!plan.ok)
|
|
7330
|
+
fail(plan.error.message);
|
|
7331
|
+
const dir = resolve2(input.dir ?? config2.name);
|
|
7332
|
+
summary(config2, plan.value, dir);
|
|
7333
|
+
if (interactive) {
|
|
7334
|
+
const proceed = await confirm({ message: "Proceed with scaffolding?" });
|
|
7335
|
+
if (isCancel(proceed) || !proceed) {
|
|
7336
|
+
cancel3("Nothing was written.");
|
|
7337
|
+
process.exit(0);
|
|
7338
|
+
}
|
|
7339
|
+
}
|
|
7340
|
+
const installer = input.install ? installLog(config2) : undefined;
|
|
7341
|
+
const result = await writeProject(plan.value, config2, {
|
|
7342
|
+
targetDir: dir,
|
|
7022
7343
|
install: input.install,
|
|
7023
|
-
git: input.git
|
|
7344
|
+
git: input.git,
|
|
7345
|
+
onWarn: (message) => log3.warn(message),
|
|
7346
|
+
onOutput: installer?.onOutput
|
|
7024
7347
|
});
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
process.exit(1);
|
|
7028
|
-
}
|
|
7029
|
-
console.error(`✓ created ${config2.name} → ${res.value.dir} (${res.value.fileCount} files)`);
|
|
7030
|
-
console.error(` next: cd ${res.value.dir} && ${config2.packageManager} install`);
|
|
7348
|
+
installer?.finish(result.installError);
|
|
7349
|
+
nextSteps(config2, plan.value, result.dir, result.installError === null);
|
|
7031
7350
|
})
|
|
7032
7351
|
});
|
|
7033
7352
|
var cli = createCli({ router, name: "create-turbo-wizard", version: package_default.version });
|