create-fumadocs-app 16.0.2 → 16.0.4
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/bin.d.ts +1 -0
- package/dist/bin.js +215 -0
- package/dist/chunk-BEZTHMLF.js +51 -0
- package/dist/chunk-JCFTHRDR.js +50 -0
- package/dist/chunk-UXPTMGXV.js +130 -0
- package/dist/chunk-ZWEHS3HT.js +191 -0
- package/dist/index.d.ts +63 -1
- package/dist/index.js +5 -283
- package/dist/plugins/biome.base.d.ts +45 -0
- package/dist/plugins/biome.base.js +18 -0
- package/dist/plugins/biome.d.ts +5 -0
- package/dist/plugins/biome.js +43 -0
- package/dist/plugins/biome.next.d.ts +49 -0
- package/dist/plugins/biome.next.js +18 -0
- package/dist/plugins/eslint.d.ts +5 -0
- package/dist/plugins/eslint.js +61 -0
- package/dist/plugins/next-use-src.d.ts +8 -0
- package/dist/plugins/next-use-src.js +39 -0
- package/dist/plugins/orama-cloud.d.ts +5 -0
- package/dist/plugins/orama-cloud.js +359 -0
- package/package.json +19 -8
- package/template/react-router/react-router.config.ts +3 -3
- package/template/react-router-spa/react-router.config.ts +7 -2
- package/dist/chunk-6C2B326N.js +0 -372
- package/dist/create-app.d.ts +0 -61
- package/dist/create-app.js +0 -6
- package/template/+next+biome/biome.json +0 -34
- package/template/+next+eslint/eslint.config.mjs +0 -26
- package/template/+orama-cloud/+next+fuma-docs-mdx/app/layout.tsx +0 -18
- package/template/+orama-cloud/+next+fuma-docs-mdx/app/static.json/route.ts +0 -7
- package/template/+orama-cloud/react-router/app/root.tsx +0 -76
- package/template/+orama-cloud/react-router/app/routes/static.ts +0 -5
- package/template/+orama-cloud/react-router/app/routes.ts +0 -8
- package/template/+orama-cloud/react-router-spa/app/root.tsx +0 -76
- package/template/+orama-cloud/react-router-spa/app/routes/static.ts +0 -5
- package/template/+orama-cloud/react-router-spa/app/routes.ts +0 -8
- package/template/+orama-cloud/tanstack-start/src/routes/__root.tsx +0 -51
- package/template/+orama-cloud/tanstack-start/src/routes/static[.]json.ts +0 -10
- package/template/+orama-cloud/tanstack-start/vite.config.ts +0 -27
- package/template/+orama-cloud/waku/src/components/provider.tsx +0 -8
- package/template/+orama-cloud/waku/src/pages/api/static.json.ts +0 -9
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
create,
|
|
4
|
+
getPackageManager,
|
|
5
|
+
managers
|
|
6
|
+
} from "./chunk-UXPTMGXV.js";
|
|
7
|
+
import {
|
|
8
|
+
isCI,
|
|
9
|
+
templates
|
|
10
|
+
} from "./chunk-ZWEHS3HT.js";
|
|
11
|
+
|
|
12
|
+
// src/bin.ts
|
|
13
|
+
import fs from "fs/promises";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import {
|
|
16
|
+
cancel,
|
|
17
|
+
confirm,
|
|
18
|
+
group,
|
|
19
|
+
intro,
|
|
20
|
+
isCancel,
|
|
21
|
+
outro,
|
|
22
|
+
select,
|
|
23
|
+
spinner,
|
|
24
|
+
text
|
|
25
|
+
} from "@clack/prompts";
|
|
26
|
+
import pc from "picocolors";
|
|
27
|
+
import { Option, program } from "@commander-js/extra-typings";
|
|
28
|
+
var command = program.argument("[name]", "the project name").option("--src", "(Next.js only) enable `src/` directory").option("--install", "install packages automatically").option("--no-git", "disable auto Git repository initialization").addOption(
|
|
29
|
+
new Option(
|
|
30
|
+
"--linter <name>",
|
|
31
|
+
"configure a linter/formatter, ESLint is currently Next.js only."
|
|
32
|
+
).choices(["eslint", "biome"])
|
|
33
|
+
).addOption(
|
|
34
|
+
new Option("--search <name>", "configure a search solution").choices([
|
|
35
|
+
"orama",
|
|
36
|
+
"orama-cloud"
|
|
37
|
+
])
|
|
38
|
+
).addOption(
|
|
39
|
+
new Option("--template <name>", "choose a template").choices(
|
|
40
|
+
templates.map((item) => item.value)
|
|
41
|
+
)
|
|
42
|
+
).addOption(
|
|
43
|
+
new Option("--pm <name>", "choose a package manager").choices(managers).default(getPackageManager())
|
|
44
|
+
);
|
|
45
|
+
async function main() {
|
|
46
|
+
command.parse(process.argv);
|
|
47
|
+
const defaultName = command.args[0];
|
|
48
|
+
const config = command.opts();
|
|
49
|
+
intro(pc.bgCyan(pc.bold("Create Fumadocs App")));
|
|
50
|
+
const options = await group(
|
|
51
|
+
{
|
|
52
|
+
name: async () => {
|
|
53
|
+
if (defaultName) return defaultName;
|
|
54
|
+
if (isCI) return "untitled";
|
|
55
|
+
return text({
|
|
56
|
+
message: "Project name",
|
|
57
|
+
placeholder: "my-app",
|
|
58
|
+
defaultValue: "my-app"
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
template: async () => {
|
|
62
|
+
if (config.template) return config.template;
|
|
63
|
+
if (isCI) return "+next+fuma-docs-mdx";
|
|
64
|
+
return select({
|
|
65
|
+
message: "Choose a template",
|
|
66
|
+
initialValue: "+next+fuma-docs-mdx",
|
|
67
|
+
options: templates
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
src: async ({ results }) => {
|
|
71
|
+
if (config.src !== void 0) return config.src;
|
|
72
|
+
if (isCI || !results.template?.startsWith("+next")) return false;
|
|
73
|
+
return confirm({
|
|
74
|
+
message: "Use `/src` directory?",
|
|
75
|
+
initialValue: false
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
lint: async ({ results }) => {
|
|
79
|
+
if (config.linter !== void 0) return config.linter;
|
|
80
|
+
if (isCI) return "disabled";
|
|
81
|
+
return select({
|
|
82
|
+
message: "Configure linter?",
|
|
83
|
+
options: results.template === "+next+fuma-docs-mdx" ? [
|
|
84
|
+
{
|
|
85
|
+
value: "disabled",
|
|
86
|
+
label: "Disabled"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
value: "eslint",
|
|
90
|
+
label: "ESLint"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
value: "biome",
|
|
94
|
+
label: "Biome"
|
|
95
|
+
}
|
|
96
|
+
] : [
|
|
97
|
+
{
|
|
98
|
+
value: "disabled",
|
|
99
|
+
label: "Disabled"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
value: "biome",
|
|
103
|
+
label: "Biome"
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
search: async () => {
|
|
109
|
+
if (config.search !== void 0) return config.search;
|
|
110
|
+
if (isCI) return "orama";
|
|
111
|
+
return select({
|
|
112
|
+
message: "Choose a search solution?",
|
|
113
|
+
options: [
|
|
114
|
+
{
|
|
115
|
+
value: "orama",
|
|
116
|
+
label: "Default",
|
|
117
|
+
hint: "local search powered by Orama, recommended"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
value: "orama-cloud",
|
|
121
|
+
label: "Orama Cloud",
|
|
122
|
+
hint: "3rd party search solution, signup needed"
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
installDeps: async () => {
|
|
128
|
+
if (config.install !== void 0) return config.install;
|
|
129
|
+
if (isCI) return false;
|
|
130
|
+
return confirm({
|
|
131
|
+
message: `Do you want to install packages automatically? (detected as ${config.pm})`
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
onCancel: () => {
|
|
137
|
+
cancel("Installation Stopped.");
|
|
138
|
+
process.exit(0);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
const projectName = options.name.toLowerCase().replace(/\s/, "-");
|
|
143
|
+
if (!isCI) await checkDir(projectName);
|
|
144
|
+
const info = spinner();
|
|
145
|
+
info.start(`Generating Project`);
|
|
146
|
+
const plugins = [];
|
|
147
|
+
if (options.src) {
|
|
148
|
+
const { nextUseSrc } = await import("./plugins/next-use-src.js");
|
|
149
|
+
plugins.push(nextUseSrc());
|
|
150
|
+
}
|
|
151
|
+
if (options.search === "orama-cloud") {
|
|
152
|
+
const { oramaCloud } = await import("./plugins/orama-cloud.js");
|
|
153
|
+
plugins.push(oramaCloud());
|
|
154
|
+
}
|
|
155
|
+
if (options.lint === "eslint") {
|
|
156
|
+
const { eslint } = await import("./plugins/eslint.js");
|
|
157
|
+
plugins.push(eslint());
|
|
158
|
+
}
|
|
159
|
+
if (options.lint === "biome") {
|
|
160
|
+
const { biome } = await import("./plugins/biome.js");
|
|
161
|
+
plugins.push(biome());
|
|
162
|
+
}
|
|
163
|
+
await create({
|
|
164
|
+
packageManager: config.pm,
|
|
165
|
+
template: options.template,
|
|
166
|
+
outputDir: projectName,
|
|
167
|
+
installDeps: options.installDeps,
|
|
168
|
+
initializeGit: config.git,
|
|
169
|
+
plugins,
|
|
170
|
+
log: (message) => {
|
|
171
|
+
info.message(message);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
info.stop("Project Generated");
|
|
175
|
+
outro(pc.bgGreen(pc.bold("Done")));
|
|
176
|
+
console.log(pc.bold("\nOpen the project"));
|
|
177
|
+
console.log(pc.cyan(`cd ${projectName}`));
|
|
178
|
+
console.log(pc.bold("\nRun Development Server"));
|
|
179
|
+
if (config.pm === "npm" || config.pm === "bun") {
|
|
180
|
+
console.log(pc.cyan(`${config.pm} run dev`));
|
|
181
|
+
} else {
|
|
182
|
+
console.log(pc.cyan(`${config.pm} dev`));
|
|
183
|
+
}
|
|
184
|
+
console.log(
|
|
185
|
+
pc.bold("\nYou can now open the project and start writing documents")
|
|
186
|
+
);
|
|
187
|
+
process.exit(0);
|
|
188
|
+
}
|
|
189
|
+
async function checkDir(outputDir) {
|
|
190
|
+
const destDir = await fs.readdir(outputDir).catch(() => null);
|
|
191
|
+
if (!destDir || destDir.length === 0) return;
|
|
192
|
+
const del = await confirm({
|
|
193
|
+
message: `directory ${outputDir} already exists, do you want to delete its files?`
|
|
194
|
+
});
|
|
195
|
+
if (isCancel(del)) {
|
|
196
|
+
cancel();
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
if (!del) return;
|
|
200
|
+
const info = spinner();
|
|
201
|
+
info.start(`Deleting files in ${outputDir}`);
|
|
202
|
+
await Promise.all(
|
|
203
|
+
destDir.map((item) => {
|
|
204
|
+
return fs.rm(path.join(outputDir, item), {
|
|
205
|
+
recursive: true,
|
|
206
|
+
force: true
|
|
207
|
+
});
|
|
208
|
+
})
|
|
209
|
+
);
|
|
210
|
+
info.stop(`Deleted files in ${outputDir}`);
|
|
211
|
+
}
|
|
212
|
+
main().catch((e) => {
|
|
213
|
+
console.error(e);
|
|
214
|
+
process.exit(1);
|
|
215
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/plugins/biome.next.json
|
|
2
|
+
var $schema = "https://biomejs.dev/schemas/2.2.0/schema.json";
|
|
3
|
+
var vcs = {
|
|
4
|
+
enabled: true,
|
|
5
|
+
clientKind: "git",
|
|
6
|
+
useIgnoreFile: true
|
|
7
|
+
};
|
|
8
|
+
var files = {
|
|
9
|
+
ignoreUnknown: true,
|
|
10
|
+
includes: ["**", "!node_modules", "!.next", "!dist", "!build", "!.source"]
|
|
11
|
+
};
|
|
12
|
+
var formatter = {
|
|
13
|
+
enabled: true,
|
|
14
|
+
indentStyle: "space",
|
|
15
|
+
indentWidth: 2
|
|
16
|
+
};
|
|
17
|
+
var linter = {
|
|
18
|
+
enabled: true,
|
|
19
|
+
rules: {
|
|
20
|
+
recommended: true
|
|
21
|
+
},
|
|
22
|
+
domains: {
|
|
23
|
+
next: "recommended",
|
|
24
|
+
react: "recommended"
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var assist = {
|
|
28
|
+
actions: {
|
|
29
|
+
source: {
|
|
30
|
+
organizeImports: "on"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var biome_next_default = {
|
|
35
|
+
$schema,
|
|
36
|
+
vcs,
|
|
37
|
+
files,
|
|
38
|
+
formatter,
|
|
39
|
+
linter,
|
|
40
|
+
assist
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
$schema,
|
|
45
|
+
vcs,
|
|
46
|
+
files,
|
|
47
|
+
formatter,
|
|
48
|
+
linter,
|
|
49
|
+
assist,
|
|
50
|
+
biome_next_default
|
|
51
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// src/plugins/biome.base.json
|
|
2
|
+
var $schema = "https://biomejs.dev/schemas/2.2.0/schema.json";
|
|
3
|
+
var vcs = {
|
|
4
|
+
enabled: true,
|
|
5
|
+
clientKind: "git",
|
|
6
|
+
useIgnoreFile: true
|
|
7
|
+
};
|
|
8
|
+
var files = {
|
|
9
|
+
ignoreUnknown: true,
|
|
10
|
+
includes: ["**", "!node_modules", "!.source"]
|
|
11
|
+
};
|
|
12
|
+
var formatter = {
|
|
13
|
+
enabled: true,
|
|
14
|
+
indentStyle: "space",
|
|
15
|
+
indentWidth: 2
|
|
16
|
+
};
|
|
17
|
+
var linter = {
|
|
18
|
+
enabled: true,
|
|
19
|
+
rules: {
|
|
20
|
+
recommended: true
|
|
21
|
+
},
|
|
22
|
+
domains: {
|
|
23
|
+
react: "recommended"
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var assist = {
|
|
27
|
+
actions: {
|
|
28
|
+
source: {
|
|
29
|
+
organizeImports: "on"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var biome_base_default = {
|
|
34
|
+
$schema,
|
|
35
|
+
vcs,
|
|
36
|
+
files,
|
|
37
|
+
formatter,
|
|
38
|
+
linter,
|
|
39
|
+
assist
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
$schema,
|
|
44
|
+
vcs,
|
|
45
|
+
files,
|
|
46
|
+
formatter,
|
|
47
|
+
linter,
|
|
48
|
+
assist,
|
|
49
|
+
biome_base_default
|
|
50
|
+
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {
|
|
2
|
+
copy,
|
|
3
|
+
depVersions,
|
|
4
|
+
sourceDir,
|
|
5
|
+
templates,
|
|
6
|
+
tryGitInit
|
|
7
|
+
} from "./chunk-ZWEHS3HT.js";
|
|
8
|
+
|
|
9
|
+
// src/index.ts
|
|
10
|
+
import path from "path";
|
|
11
|
+
import fs from "fs/promises";
|
|
12
|
+
|
|
13
|
+
// src/auto-install.ts
|
|
14
|
+
import { x } from "tinyexec";
|
|
15
|
+
var managers = ["npm", "yarn", "bun", "pnpm"];
|
|
16
|
+
function getPackageManager() {
|
|
17
|
+
const userAgent = process.env.npm_config_user_agent ?? "";
|
|
18
|
+
if (userAgent.startsWith("yarn")) {
|
|
19
|
+
return "yarn";
|
|
20
|
+
}
|
|
21
|
+
if (userAgent.startsWith("pnpm")) {
|
|
22
|
+
return "pnpm";
|
|
23
|
+
}
|
|
24
|
+
if (userAgent.startsWith("bun")) {
|
|
25
|
+
return "bun";
|
|
26
|
+
}
|
|
27
|
+
return "npm";
|
|
28
|
+
}
|
|
29
|
+
async function autoInstall(manager, dest) {
|
|
30
|
+
await x(manager, ["install"], {
|
|
31
|
+
throwOnError: true,
|
|
32
|
+
nodeOptions: {
|
|
33
|
+
env: {
|
|
34
|
+
...process.env,
|
|
35
|
+
NODE_ENV: "development",
|
|
36
|
+
DISABLE_OPENCOLLECTIVE: "1"
|
|
37
|
+
},
|
|
38
|
+
cwd: dest
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/index.ts
|
|
44
|
+
async function create(createOptions) {
|
|
45
|
+
const {
|
|
46
|
+
outputDir,
|
|
47
|
+
plugins = [],
|
|
48
|
+
packageManager = "npm",
|
|
49
|
+
initializeGit = false,
|
|
50
|
+
installDeps = false,
|
|
51
|
+
log = console.log
|
|
52
|
+
} = createOptions;
|
|
53
|
+
let template = templates.find(
|
|
54
|
+
(item) => item.value === createOptions.template
|
|
55
|
+
);
|
|
56
|
+
for (const plugin of plugins) {
|
|
57
|
+
template = await plugin.template?.call({ dest: outputDir }, template) ?? template;
|
|
58
|
+
}
|
|
59
|
+
const appDir = path.join(outputDir, template.appDir);
|
|
60
|
+
const projectName = path.basename(outputDir);
|
|
61
|
+
const pluginContext = {
|
|
62
|
+
template,
|
|
63
|
+
dest: outputDir,
|
|
64
|
+
log,
|
|
65
|
+
appDir
|
|
66
|
+
};
|
|
67
|
+
await copy(path.join(sourceDir, "template", template.value), outputDir, {
|
|
68
|
+
rename(file) {
|
|
69
|
+
file = file.replace("example.gitignore", ".gitignore");
|
|
70
|
+
return template.rename?.(file) ?? file;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
const packageJsonPath = path.join(outputDir, "package.json");
|
|
74
|
+
let packageJson = await initPackageJson(projectName, packageJsonPath);
|
|
75
|
+
for (const plugin of plugins) {
|
|
76
|
+
packageJson = await plugin.packageJson?.call(pluginContext, packageJson) ?? packageJson;
|
|
77
|
+
}
|
|
78
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
79
|
+
const readmePath = path.join(outputDir, "README.md");
|
|
80
|
+
let readme = `# ${projectName}
|
|
81
|
+
|
|
82
|
+
${await fs.readFile(readmePath)}`;
|
|
83
|
+
for (const plugin of plugins) {
|
|
84
|
+
readme = await plugin.readme?.call(pluginContext, readme) ?? readme;
|
|
85
|
+
}
|
|
86
|
+
await fs.writeFile(readmePath, readme);
|
|
87
|
+
for (const plugin of plugins) {
|
|
88
|
+
await plugin.afterWrite?.call(pluginContext);
|
|
89
|
+
}
|
|
90
|
+
if (installDeps) {
|
|
91
|
+
try {
|
|
92
|
+
await autoInstall(packageManager, outputDir);
|
|
93
|
+
log("Installed dependencies");
|
|
94
|
+
} catch (err) {
|
|
95
|
+
log(`Failed to install dependencies: ${err}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (initializeGit && await tryGitInit(outputDir)) {
|
|
99
|
+
log("Initialized Git repository");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function initPackageJson(projectName, packageJsonPath) {
|
|
103
|
+
function replaceWorkspaceDeps(deps = {}) {
|
|
104
|
+
for (const k in deps) {
|
|
105
|
+
if (deps[k].startsWith("workspace:") && k in depVersions) {
|
|
106
|
+
deps[k] = depVersions[k];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return deps;
|
|
110
|
+
}
|
|
111
|
+
const packageJson = JSON.parse(
|
|
112
|
+
(await fs.readFile(packageJsonPath)).toString()
|
|
113
|
+
);
|
|
114
|
+
return {
|
|
115
|
+
...packageJson,
|
|
116
|
+
name: projectName,
|
|
117
|
+
scripts: {
|
|
118
|
+
...packageJson.scripts,
|
|
119
|
+
postinstall: "fumadocs-mdx"
|
|
120
|
+
},
|
|
121
|
+
dependencies: replaceWorkspaceDeps(packageJson.dependencies),
|
|
122
|
+
devDependencies: replaceWorkspaceDeps(packageJson.devDependencies)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
managers,
|
|
128
|
+
getPackageManager,
|
|
129
|
+
create
|
|
130
|
+
};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
import path, { join } from "path";
|
|
4
|
+
import { x } from "tinyexec";
|
|
5
|
+
async function writeFile(file, content) {
|
|
6
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
7
|
+
await fs.writeFile(file, content);
|
|
8
|
+
}
|
|
9
|
+
async function copy(from, to, options = {}) {
|
|
10
|
+
const {
|
|
11
|
+
rename = (s) => s,
|
|
12
|
+
filterDir = () => true,
|
|
13
|
+
filter = () => true
|
|
14
|
+
} = options;
|
|
15
|
+
const stats = await fs.stat(from);
|
|
16
|
+
if (stats.isDirectory() && filterDir(from)) {
|
|
17
|
+
const files = await fs.readdir(from);
|
|
18
|
+
await Promise.all(
|
|
19
|
+
files.map(
|
|
20
|
+
(file) => copy(path.join(from, file), path.join(to, file), options)
|
|
21
|
+
)
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
if (stats.isFile() && filter(from)) {
|
|
25
|
+
to = rename(to);
|
|
26
|
+
await fs.mkdir(path.dirname(to), { recursive: true });
|
|
27
|
+
await fs.copyFile(from, to);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function isInGitRepository(cwd) {
|
|
31
|
+
const { exitCode } = await x("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
32
|
+
nodeOptions: { cwd }
|
|
33
|
+
});
|
|
34
|
+
return exitCode === 0;
|
|
35
|
+
}
|
|
36
|
+
async function isDefaultBranchSet(cwd) {
|
|
37
|
+
const { exitCode } = await x("git", ["config", "init.defaultBranch"], {
|
|
38
|
+
nodeOptions: { cwd }
|
|
39
|
+
});
|
|
40
|
+
return exitCode === 0;
|
|
41
|
+
}
|
|
42
|
+
async function tryGitInit(cwd) {
|
|
43
|
+
const { exitCode } = await x("git", ["--version"]);
|
|
44
|
+
if (exitCode !== 0) return false;
|
|
45
|
+
if (await isInGitRepository(cwd)) return false;
|
|
46
|
+
try {
|
|
47
|
+
await x("git", ["init"], {
|
|
48
|
+
throwOnError: true,
|
|
49
|
+
nodeOptions: { cwd }
|
|
50
|
+
});
|
|
51
|
+
if (!await isDefaultBranchSet(cwd)) {
|
|
52
|
+
await x("git", ["checkout", "-b", "main"], {
|
|
53
|
+
throwOnError: true,
|
|
54
|
+
nodeOptions: {
|
|
55
|
+
cwd
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
await x("git", ["add", "-A"], {
|
|
60
|
+
throwOnError: true,
|
|
61
|
+
nodeOptions: {
|
|
62
|
+
cwd
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
await x(
|
|
66
|
+
"git",
|
|
67
|
+
["commit", "-m", "Initial commit from Create Fumadocs App"],
|
|
68
|
+
{
|
|
69
|
+
throwOnError: true,
|
|
70
|
+
nodeOptions: {
|
|
71
|
+
cwd
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
return true;
|
|
76
|
+
} catch {
|
|
77
|
+
await fs.rmdir(join(cwd, ".git"), { recursive: true }).catch(() => null);
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function pick(obj, keys) {
|
|
82
|
+
const result = {};
|
|
83
|
+
for (const key of keys) {
|
|
84
|
+
if (key in obj) {
|
|
85
|
+
result[key] = obj[key];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/constants.ts
|
|
92
|
+
import { fileURLToPath } from "url";
|
|
93
|
+
|
|
94
|
+
// src/versions.js
|
|
95
|
+
var versions = { "fumadocs-core": "16.0.3", "fumadocs-ui": "16.0.3", "fumadocs-mdx": "13.0.1", "@fumadocs/mdx-remote": "1.4.3", "@fumadocs/content-collections": "1.2.4" };
|
|
96
|
+
|
|
97
|
+
// ../create-app-versions/package.json
|
|
98
|
+
var package_default = {
|
|
99
|
+
name: "example-versions",
|
|
100
|
+
version: "0.0.0",
|
|
101
|
+
private: true,
|
|
102
|
+
description: "Used to track dependency versions in create-fumadocs-app",
|
|
103
|
+
dependencies: {
|
|
104
|
+
"@biomejs/biome": "^2.2.6",
|
|
105
|
+
"@content-collections/core": "^0.11.1",
|
|
106
|
+
"@content-collections/mdx": "^0.2.2",
|
|
107
|
+
"@content-collections/next": "^0.2.8",
|
|
108
|
+
"@orama/core": "^1.2.13",
|
|
109
|
+
"@react-router/dev": "^7.9.4",
|
|
110
|
+
"@react-router/node": "^7.9.4",
|
|
111
|
+
"@react-router/serve": "^7.9.4",
|
|
112
|
+
"@tailwindcss/postcss": "^4.1.15",
|
|
113
|
+
"@tailwindcss/vite": "^4.1.15",
|
|
114
|
+
"@tanstack/react-router": "^1.133.21",
|
|
115
|
+
"@tanstack/react-start": "^1.133.21",
|
|
116
|
+
"@types/mdx": "^2.0.13",
|
|
117
|
+
"@types/node": "24.9.1",
|
|
118
|
+
"@types/react": "^19.2.2",
|
|
119
|
+
"@types/react-dom": "^19.2.2",
|
|
120
|
+
"@vitejs/plugin-react": "^5.0.4",
|
|
121
|
+
"gray-matter": "^4.0.3",
|
|
122
|
+
isbot: "^5.1.31",
|
|
123
|
+
"lucide-react": "^0.546.0",
|
|
124
|
+
next: "16.0.0",
|
|
125
|
+
postcss: "^8.5.6",
|
|
126
|
+
react: "^19.2.0",
|
|
127
|
+
"react-dom": "^19.2.0",
|
|
128
|
+
"react-router": "^7.9.4",
|
|
129
|
+
"react-router-devtools": "^5.1.3",
|
|
130
|
+
shiki: "^3.13.0",
|
|
131
|
+
tailwindcss: "^4.1.15",
|
|
132
|
+
tinyglobby: "^0.2.15",
|
|
133
|
+
typescript: "^5.9.3",
|
|
134
|
+
vinxi: "^0.5.8",
|
|
135
|
+
vite: "^7.1.11",
|
|
136
|
+
"vite-tsconfig-paths": "^5.1.4"
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// src/constants.ts
|
|
141
|
+
var sourceDir = fileURLToPath(new URL(`../`, import.meta.url).href);
|
|
142
|
+
var isCI = Boolean(process.env.CI);
|
|
143
|
+
var templates = [
|
|
144
|
+
{
|
|
145
|
+
value: "+next+fuma-docs-mdx",
|
|
146
|
+
label: "Next.js: Fumadocs MDX",
|
|
147
|
+
hint: "recommended",
|
|
148
|
+
appDir: "",
|
|
149
|
+
rootProviderPath: "app/layout.tsx"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
value: "waku",
|
|
153
|
+
label: "Waku: Fumadocs MDX",
|
|
154
|
+
appDir: "src",
|
|
155
|
+
rootProviderPath: "components/provider.tsx"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
value: "react-router",
|
|
159
|
+
label: "React Router: Fumadocs MDX (not RSC)",
|
|
160
|
+
appDir: "app",
|
|
161
|
+
rootProviderPath: "root.tsx"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
value: "react-router-spa",
|
|
165
|
+
label: "React Router SPA: Fumadocs MDX (not RSC)",
|
|
166
|
+
hint: "SPA mode allows you to host the site statically, compatible with a CDN.",
|
|
167
|
+
appDir: "app",
|
|
168
|
+
rootProviderPath: "root.tsx"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
value: "tanstack-start",
|
|
172
|
+
label: "Tanstack Start: Fumadocs MDX (not RSC)",
|
|
173
|
+
appDir: "src",
|
|
174
|
+
rootProviderPath: "routes/__root.tsx"
|
|
175
|
+
}
|
|
176
|
+
];
|
|
177
|
+
var depVersions = {
|
|
178
|
+
...versions,
|
|
179
|
+
...package_default.dependencies
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export {
|
|
183
|
+
writeFile,
|
|
184
|
+
copy,
|
|
185
|
+
tryGitInit,
|
|
186
|
+
pick,
|
|
187
|
+
sourceDir,
|
|
188
|
+
isCI,
|
|
189
|
+
templates,
|
|
190
|
+
depVersions
|
|
191
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,63 @@
|
|
|
1
|
-
|
|
1
|
+
type PackageManager = (typeof managers)[number];
|
|
2
|
+
declare const managers: readonly ["npm", "yarn", "bun", "pnpm"];
|
|
3
|
+
|
|
4
|
+
interface TemplateInfo {
|
|
5
|
+
value: '+next+fuma-docs-mdx' | 'waku' | 'react-router' | 'react-router-spa' | 'tanstack-start';
|
|
6
|
+
label: string;
|
|
7
|
+
appDir: string;
|
|
8
|
+
/**
|
|
9
|
+
* path to root provider, relative to `appDir``
|
|
10
|
+
*/
|
|
11
|
+
rootProviderPath: string;
|
|
12
|
+
hint?: string;
|
|
13
|
+
/**
|
|
14
|
+
* rename files when copying from template
|
|
15
|
+
*/
|
|
16
|
+
rename?: (name: string) => string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type Template = TemplateInfo['value'];
|
|
20
|
+
interface Options {
|
|
21
|
+
outputDir: string;
|
|
22
|
+
template: Template;
|
|
23
|
+
/**
|
|
24
|
+
* the package manager to use
|
|
25
|
+
*
|
|
26
|
+
* @defaultValue 'npm'
|
|
27
|
+
*/
|
|
28
|
+
packageManager?: PackageManager;
|
|
29
|
+
installDeps?: boolean;
|
|
30
|
+
initializeGit?: boolean;
|
|
31
|
+
log?: (message: string) => void;
|
|
32
|
+
plugins?: TemplatePlugin[];
|
|
33
|
+
}
|
|
34
|
+
interface TemplatePluginContext {
|
|
35
|
+
template: TemplateInfo;
|
|
36
|
+
log: (message: string) => void;
|
|
37
|
+
/**
|
|
38
|
+
* output directory
|
|
39
|
+
*/
|
|
40
|
+
dest: string;
|
|
41
|
+
/**
|
|
42
|
+
* output directory for app code (e.g. under `/src`)
|
|
43
|
+
*/
|
|
44
|
+
appDir: string;
|
|
45
|
+
}
|
|
46
|
+
type PackageJsonType = {
|
|
47
|
+
name?: string;
|
|
48
|
+
version?: string;
|
|
49
|
+
private?: boolean;
|
|
50
|
+
scripts?: Record<string, string>;
|
|
51
|
+
dependencies?: Record<string, string>;
|
|
52
|
+
devDependencies?: Record<string, string>;
|
|
53
|
+
} & Record<string, unknown>;
|
|
54
|
+
type Awaitable<T> = T | Promise<T>;
|
|
55
|
+
interface TemplatePlugin {
|
|
56
|
+
template?: (this: Pick<TemplatePluginContext, 'dest'>, info: TemplateInfo) => Awaitable<void | TemplateInfo>;
|
|
57
|
+
packageJson?: (this: TemplatePluginContext, packageJson: PackageJsonType) => Awaitable<void | PackageJsonType>;
|
|
58
|
+
afterWrite?: (this: TemplatePluginContext) => Awaitable<void>;
|
|
59
|
+
readme?: (this: TemplatePluginContext, content: string) => Awaitable<void | string>;
|
|
60
|
+
}
|
|
61
|
+
declare function create(createOptions: Options): Promise<void>;
|
|
62
|
+
|
|
63
|
+
export { type Options, type PackageJsonType, type Template, type TemplatePlugin, type TemplatePluginContext, create };
|