@fumadocs/cli 1.3.3 → 1.3.5
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/config.d.ts +53 -2
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +9 -6
- package/dist/config.js.map +1 -1
- package/dist/index.js +87 -157
- package/dist/index.js.map +1 -1
- package/dist/installer-zD4jTQWp.js +128 -0
- package/dist/installer-zD4jTQWp.js.map +1 -0
- package/dist/registry/installer.d.ts +13 -0
- package/dist/registry/installer.d.ts.map +1 -0
- package/dist/registry/installer.js +2 -0
- package/package.json +7 -15
- package/dist/build/index.d.ts +0 -148
- package/dist/build/index.d.ts.map +0 -1
- package/dist/build/index.js +0 -289
- package/dist/build/index.js.map +0 -1
- package/dist/client-C2A4Jf2w.js +0 -102
- package/dist/client-C2A4Jf2w.js.map +0 -1
- package/dist/config-Bx-m6awG.d.ts +0 -53
- package/dist/config-Bx-m6awG.d.ts.map +0 -1
- package/dist/fs-C3j4H046.js +0 -18
- package/dist/fs-C3j4H046.js.map +0 -1
- package/dist/import-CSbSteB3.js +0 -124
- package/dist/import-CSbSteB3.js.map +0 -1
- package/dist/installer-BWoLnsXE.js +0 -673
- package/dist/installer-BWoLnsXE.js.map +0 -1
- package/dist/registry/client.d.ts +0 -112
- package/dist/registry/client.d.ts.map +0 -1
- package/dist/registry/client.js +0 -2
- package/dist/registry/installer/index.d.ts +0 -96
- package/dist/registry/installer/index.d.ts.map +0 -1
- package/dist/registry/installer/index.js +0 -2
- package/dist/registry/macros/route-handler.d.ts +0 -21
- package/dist/registry/macros/route-handler.d.ts.map +0 -1
- package/dist/registry/macros/route-handler.js +0 -11
- package/dist/registry/macros/route-handler.js.map +0 -1
- package/dist/registry/schema.d.ts +0 -2
- package/dist/registry/schema.js +0 -50
- package/dist/registry/schema.js.map +0 -1
- package/dist/schema-BAaUX4uu.d.ts +0 -77
- package/dist/schema-BAaUX4uu.d.ts.map +0 -1
- package/dist/types-79PW0lgM.d.ts +0 -6
- package/dist/types-79PW0lgM.d.ts.map +0 -1
package/dist/config.d.ts
CHANGED
|
@@ -1,2 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/config.d.ts
|
|
4
|
+
declare const frameworks: readonly ["next", "waku", "react-router", "tanstack-start"];
|
|
5
|
+
type Framework = (typeof frameworks)[number];
|
|
6
|
+
declare function createConfigSchema(cwd?: any): z.ZodObject<{
|
|
7
|
+
$schema: z.ZodOptional<z.ZodDefault<z.ZodString>>;
|
|
8
|
+
aliases: z.ZodDefault<z.ZodObject<{
|
|
9
|
+
uiDir: z.ZodDefault<z.ZodString>;
|
|
10
|
+
componentsDir: z.ZodDefault<z.ZodString>;
|
|
11
|
+
layoutDir: z.ZodDefault<z.ZodString>;
|
|
12
|
+
cssDir: z.ZodDefault<z.ZodString>;
|
|
13
|
+
libDir: z.ZodDefault<z.ZodString>;
|
|
14
|
+
}, z.core.$strip>>;
|
|
15
|
+
baseDir: z.ZodDefault<z.ZodString>;
|
|
16
|
+
uiLibrary: z.ZodDefault<z.ZodEnum<{
|
|
17
|
+
"radix-ui": "radix-ui";
|
|
18
|
+
"base-ui": "base-ui";
|
|
19
|
+
}>>;
|
|
20
|
+
framework: z.ZodDefault<z.ZodLiteral<"next" | "waku" | "react-router" | "tanstack-start">>;
|
|
21
|
+
commands: z.ZodDefault<z.ZodObject<{
|
|
22
|
+
format: z.ZodOptional<z.ZodString>;
|
|
23
|
+
}, z.core.$strip>>;
|
|
24
|
+
}, z.core.$strip>;
|
|
25
|
+
type ConfigSchema = ReturnType<typeof createConfigSchema>;
|
|
26
|
+
type ConfigInput = z.input<ConfigSchema>;
|
|
27
|
+
type LoadedConfig = z.output<ConfigSchema>;
|
|
28
|
+
declare function createOrLoadConfig(file?: string): Promise<LoadedConfig>;
|
|
29
|
+
/**
|
|
30
|
+
* Write new config, skip if a config already exists
|
|
31
|
+
*
|
|
32
|
+
* @returns the created config, `undefined` if not created
|
|
33
|
+
*/
|
|
34
|
+
declare function initConfig(file?: string): Promise<LoadedConfig | undefined>;
|
|
35
|
+
declare function getDefaultConfig(cwd?: string): Promise<{
|
|
36
|
+
aliases: {
|
|
37
|
+
uiDir: string;
|
|
38
|
+
componentsDir: string;
|
|
39
|
+
layoutDir: string;
|
|
40
|
+
cssDir: string;
|
|
41
|
+
libDir: string;
|
|
42
|
+
};
|
|
43
|
+
baseDir: string;
|
|
44
|
+
uiLibrary: "radix-ui" | "base-ui";
|
|
45
|
+
framework: "next" | "waku" | "react-router" | "tanstack-start";
|
|
46
|
+
commands: {
|
|
47
|
+
format?: string | undefined;
|
|
48
|
+
};
|
|
49
|
+
$schema?: string | undefined;
|
|
50
|
+
}>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { ConfigInput, Framework, LoadedConfig, createConfigSchema, createOrLoadConfig, getDefaultConfig, initConfig };
|
|
53
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","names":[],"sources":["../src/config.ts"],"mappings":";;;cAKM,UAAA;AAAA,KACM,SAAA,WAAoB,UAAA;AAAA,iBAEhB,kBAAA,CAAmB,GAAA,SAAmB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;KA2DjD,YAAA,GAAe,UAAA,QAAkB,kBAAA;AAAA,KAE1B,WAAA,GAAc,CAAA,CAAE,KAAA,CAAM,YAAA;AAAA,KACtB,YAAA,GAAe,CAAA,CAAE,MAAA,CAAO,YAAA;AAAA,iBAEd,kBAAA,CAAmB,IAAA,YAAsB,OAAA,CAAQ,YAAA;;;;;;iBAejD,UAAA,CAAW,IAAA,YAAsB,OAAA,CAAQ,YAAA;AAAA,iBAezC,gBAAA,CAAiB,GAAA,YAAY,OAAA"}
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
4
5
|
//#region src/config.ts
|
|
5
6
|
const frameworks = [
|
|
6
7
|
"next",
|
|
@@ -8,7 +9,9 @@ const frameworks = [
|
|
|
8
9
|
"react-router",
|
|
9
10
|
"tanstack-start"
|
|
10
11
|
];
|
|
11
|
-
function createConfigSchema() {
|
|
12
|
+
function createConfigSchema(cwd = process.cwd()) {
|
|
13
|
+
const srcDir = path.resolve(cwd, "src");
|
|
14
|
+
const packageJsonPath = path.resolve(cwd, "package.json");
|
|
12
15
|
const defaultAliases = {
|
|
13
16
|
uiDir: "./components/ui",
|
|
14
17
|
componentsDir: "./components",
|
|
@@ -25,15 +28,15 @@ function createConfigSchema() {
|
|
|
25
28
|
cssDir: z.string().default(defaultAliases.componentsDir),
|
|
26
29
|
libDir: z.string().default(defaultAliases.libDir)
|
|
27
30
|
}).default(defaultAliases),
|
|
28
|
-
baseDir: z.string().default(() => existsSync(
|
|
31
|
+
baseDir: z.string().default(() => existsSync(srcDir) ? "src" : ""),
|
|
29
32
|
uiLibrary: z.enum(["radix-ui", "base-ui"]).default("radix-ui"),
|
|
30
33
|
framework: z.literal(frameworks).default(() => {
|
|
31
|
-
return detectFrameworkFromPackageJson() ?? "next";
|
|
34
|
+
return detectFrameworkFromPackageJson(packageJsonPath) ?? "next";
|
|
32
35
|
}),
|
|
33
36
|
commands: z.object({ format: z.string().optional() }).default({})
|
|
34
37
|
});
|
|
35
38
|
}
|
|
36
|
-
function detectFrameworkFromPackageJson(pkgPath
|
|
39
|
+
function detectFrameworkFromPackageJson(pkgPath) {
|
|
37
40
|
try {
|
|
38
41
|
const pkgRaw = readFileSync(pkgPath, "utf-8");
|
|
39
42
|
const pkg = JSON.parse(pkgRaw);
|
|
@@ -66,8 +69,8 @@ async function initConfig(file = "./cli.json") {
|
|
|
66
69
|
await fs.writeFile(file, JSON.stringify(defaultConfig, null, 2));
|
|
67
70
|
return defaultConfig;
|
|
68
71
|
}
|
|
69
|
-
async function getDefaultConfig() {
|
|
70
|
-
return createConfigSchema().parse({});
|
|
72
|
+
async function getDefaultConfig(cwd) {
|
|
73
|
+
return createConfigSchema(cwd).parse({});
|
|
71
74
|
}
|
|
72
75
|
//#endregion
|
|
73
76
|
export { createConfigSchema, createOrLoadConfig, getDefaultConfig, initConfig };
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport { z } from 'zod';\nimport { existsSync, readFileSync } from 'node:fs';\n\nconst frameworks = ['next', 'waku', 'react-router', 'tanstack-start'] as const;\nexport type Framework = (typeof frameworks)[number];\n\nexport function createConfigSchema() {\n const defaultAliases = {\n uiDir: './components/ui',\n componentsDir: './components',\n layoutDir: './layouts',\n cssDir: './styles',\n libDir: './lib',\n };\n\n return z.object({\n $schema: z.string().default('node_modules/@fumadocs/cli/dist/schema.json').optional(),\n aliases: z\n .object({\n uiDir: z.string().default(defaultAliases.uiDir),\n componentsDir: z.string().default(defaultAliases.uiDir),\n layoutDir: z.string().default(defaultAliases.layoutDir),\n cssDir: z.string().default(defaultAliases.componentsDir),\n libDir: z.string().default(defaultAliases.libDir),\n })\n .default(defaultAliases),\n\n baseDir: z.string().default(() => (existsSync(
|
|
1
|
+
{"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport { z } from 'zod';\nimport { existsSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\n\nconst frameworks = ['next', 'waku', 'react-router', 'tanstack-start'] as const;\nexport type Framework = (typeof frameworks)[number];\n\nexport function createConfigSchema(cwd = process.cwd()) {\n const srcDir = path.resolve(cwd, 'src');\n const packageJsonPath = path.resolve(cwd, 'package.json');\n const defaultAliases = {\n uiDir: './components/ui',\n componentsDir: './components',\n layoutDir: './layouts',\n cssDir: './styles',\n libDir: './lib',\n };\n\n return z.object({\n $schema: z.string().default('node_modules/@fumadocs/cli/dist/schema.json').optional(),\n aliases: z\n .object({\n uiDir: z.string().default(defaultAliases.uiDir),\n componentsDir: z.string().default(defaultAliases.uiDir),\n layoutDir: z.string().default(defaultAliases.layoutDir),\n cssDir: z.string().default(defaultAliases.componentsDir),\n libDir: z.string().default(defaultAliases.libDir),\n })\n .default(defaultAliases),\n\n baseDir: z.string().default(() => (existsSync(srcDir) ? 'src' : '')),\n uiLibrary: z.enum(['radix-ui', 'base-ui']).default('radix-ui'),\n framework: z.literal(frameworks).default(() => {\n return detectFrameworkFromPackageJson(packageJsonPath) ?? 'next';\n }),\n\n commands: z\n .object({\n /**\n * command to format output code automatically\n */\n format: z.string().optional(),\n })\n .default({}),\n });\n}\n\nfunction detectFrameworkFromPackageJson(pkgPath: string): Framework | undefined {\n try {\n const pkgRaw = readFileSync(pkgPath, 'utf-8');\n const pkg = JSON.parse(pkgRaw);\n\n const deps = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n\n if (deps['next']) return 'next';\n if (deps['waku']) return 'waku';\n if (deps['react-router'] || deps['react-router-dom']) return 'react-router';\n if (deps['@tanstack/react-start']) return 'tanstack-start';\n } catch {\n return;\n }\n}\n\ntype ConfigSchema = ReturnType<typeof createConfigSchema>;\n\nexport type ConfigInput = z.input<ConfigSchema>;\nexport type LoadedConfig = z.output<ConfigSchema>;\n\nexport async function createOrLoadConfig(file = './cli.json'): Promise<LoadedConfig> {\n const inited = await initConfig(file);\n if (inited) return inited;\n\n const content = (await fs.readFile(file)).toString();\n const configSchema = createConfigSchema();\n\n return configSchema.parse(JSON.parse(content));\n}\n\n/**\n * Write new config, skip if a config already exists\n *\n * @returns the created config, `undefined` if not created\n */\nexport async function initConfig(file = './cli.json'): Promise<LoadedConfig | undefined> {\n if (\n await fs\n .stat(file)\n .then(() => true)\n .catch(() => false)\n ) {\n return;\n }\n\n const defaultConfig = await getDefaultConfig();\n await fs.writeFile(file, JSON.stringify(defaultConfig, null, 2));\n return defaultConfig;\n}\n\nexport async function getDefaultConfig(cwd?: string) {\n return createConfigSchema(cwd).parse({} satisfies ConfigInput);\n}\n"],"mappings":";;;;;AAKA,MAAM,aAAa;CAAC;CAAQ;CAAQ;CAAgB;CAAiB;AAGrE,SAAgB,mBAAmB,MAAM,QAAQ,KAAK,EAAE;CACtD,MAAM,SAAS,KAAK,QAAQ,KAAK,MAAM;CACvC,MAAM,kBAAkB,KAAK,QAAQ,KAAK,eAAe;CACzD,MAAM,iBAAiB;EACrB,OAAO;EACP,eAAe;EACf,WAAW;EACX,QAAQ;EACR,QAAQ;EACT;AAED,QAAO,EAAE,OAAO;EACd,SAAS,EAAE,QAAQ,CAAC,QAAQ,8CAA8C,CAAC,UAAU;EACrF,SAAS,EACN,OAAO;GACN,OAAO,EAAE,QAAQ,CAAC,QAAQ,eAAe,MAAM;GAC/C,eAAe,EAAE,QAAQ,CAAC,QAAQ,eAAe,MAAM;GACvD,WAAW,EAAE,QAAQ,CAAC,QAAQ,eAAe,UAAU;GACvD,QAAQ,EAAE,QAAQ,CAAC,QAAQ,eAAe,cAAc;GACxD,QAAQ,EAAE,QAAQ,CAAC,QAAQ,eAAe,OAAO;GAClD,CAAC,CACD,QAAQ,eAAe;EAE1B,SAAS,EAAE,QAAQ,CAAC,cAAe,WAAW,OAAO,GAAG,QAAQ,GAAI;EACpE,WAAW,EAAE,KAAK,CAAC,YAAY,UAAU,CAAC,CAAC,QAAQ,WAAW;EAC9D,WAAW,EAAE,QAAQ,WAAW,CAAC,cAAc;AAC7C,UAAO,+BAA+B,gBAAgB,IAAI;IAC1D;EAEF,UAAU,EACP,OAAO,EAIN,QAAQ,EAAE,QAAQ,CAAC,UAAU,EAC9B,CAAC,CACD,QAAQ,EAAE,CAAC;EACf,CAAC;;AAGJ,SAAS,+BAA+B,SAAwC;AAC9E,KAAI;EACF,MAAM,SAAS,aAAa,SAAS,QAAQ;EAC7C,MAAM,MAAM,KAAK,MAAM,OAAO;EAE9B,MAAM,OAAO;GACX,GAAG,IAAI;GACP,GAAG,IAAI;GACR;AAED,MAAI,KAAK,QAAS,QAAO;AACzB,MAAI,KAAK,QAAS,QAAO;AACzB,MAAI,KAAK,mBAAmB,KAAK,oBAAqB,QAAO;AAC7D,MAAI,KAAK,yBAA0B,QAAO;SACpC;AACN;;;AASJ,eAAsB,mBAAmB,OAAO,cAAqC;CACnF,MAAM,SAAS,MAAM,WAAW,KAAK;AACrC,KAAI,OAAQ,QAAO;CAEnB,MAAM,WAAW,MAAM,GAAG,SAAS,KAAK,EAAE,UAAU;AAGpD,QAFqB,oBAAoB,CAErB,MAAM,KAAK,MAAM,QAAQ,CAAC;;;;;;;AAQhD,eAAsB,WAAW,OAAO,cAAiD;AACvF,KACE,MAAM,GACH,KAAK,KAAK,CACV,WAAW,KAAK,CAChB,YAAY,MAAM,CAErB;CAGF,MAAM,gBAAgB,MAAM,kBAAkB;AAC9C,OAAM,GAAG,UAAU,MAAM,KAAK,UAAU,eAAe,MAAM,EAAE,CAAC;AAChE,QAAO;;AAGT,eAAsB,iBAAiB,KAAc;AACnD,QAAO,mBAAmB,IAAI,CAAC,MAAM,EAAE,CAAuB"}
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createOrLoadConfig, initConfig } from "./config.js";
|
|
3
|
-
import {
|
|
4
|
-
import { t as ComponentInstaller } from "./installer-BWoLnsXE.js";
|
|
5
|
-
import { t as exists } from "./fs-C3j4H046.js";
|
|
3
|
+
import { t as FumadocsComponentInstaller } from "./installer-zD4jTQWp.js";
|
|
6
4
|
import fs from "node:fs/promises";
|
|
7
5
|
import path from "node:path";
|
|
8
6
|
import { Command } from "commander";
|
|
9
7
|
import picocolors from "picocolors";
|
|
10
8
|
import { x } from "tinyexec";
|
|
11
|
-
import { autocompleteMultiselect,
|
|
12
|
-
import { detect } from "package-manager-detector";
|
|
9
|
+
import { autocompleteMultiselect, cancel, group, intro, isCancel, log, outro, select, spinner } from "@clack/prompts";
|
|
13
10
|
import { exec } from "node:child_process";
|
|
14
11
|
import { promisify } from "node:util";
|
|
12
|
+
import { HttpRegistryConnector, LocalRegistryConnector } from "fuma-cli/registry/connector";
|
|
15
13
|
//#region src/commands/file-tree.ts
|
|
16
14
|
const scanned = [
|
|
17
15
|
"file",
|
|
@@ -63,7 +61,7 @@ async function runTree(args) {
|
|
|
63
61
|
}
|
|
64
62
|
//#endregion
|
|
65
63
|
//#region package.json
|
|
66
|
-
var version = "1.3.
|
|
64
|
+
var version = "1.3.5";
|
|
67
65
|
//#endregion
|
|
68
66
|
//#region src/commands/shared.ts
|
|
69
67
|
const UIRegistries = {
|
|
@@ -71,146 +69,13 @@ const UIRegistries = {
|
|
|
71
69
|
"radix-ui": "fumadocs/radix-ui"
|
|
72
70
|
};
|
|
73
71
|
//#endregion
|
|
74
|
-
//#region src/registry/plugins/preserve.ts
|
|
75
|
-
/**
|
|
76
|
-
* keep references to `fumadocs-ui/layouts/*` components as original, unless the user is installing them directly.
|
|
77
|
-
*/
|
|
78
|
-
function pluginPreserveLayouts() {
|
|
79
|
-
const layoutNames = [
|
|
80
|
-
"layouts/home",
|
|
81
|
-
"layouts/flux",
|
|
82
|
-
"layouts/notebook",
|
|
83
|
-
"layouts/docs",
|
|
84
|
-
"layouts/shared"
|
|
85
|
-
];
|
|
86
|
-
const layoutComps = {
|
|
87
|
-
"@/<dir>/home/index.tsx": "layouts/home",
|
|
88
|
-
"@/<dir>/shared/index.tsx": "layouts/shared",
|
|
89
|
-
"@/<dir>/shared/client.tsx": "layouts/shared",
|
|
90
|
-
"@/<dir>/notebook/index.tsx": "layouts/notebook",
|
|
91
|
-
"@/<dir>/notebook/client.tsx": "layouts/notebook",
|
|
92
|
-
"@/<dir>/notebook/page/index.tsx": "layouts/notebook/page",
|
|
93
|
-
"@/<dir>/notebook/page/client.tsx": "layouts/notebook/page",
|
|
94
|
-
"@/<dir>/docs/index.tsx": "layouts/docs",
|
|
95
|
-
"@/<dir>/docs/client.tsx": "layouts/docs",
|
|
96
|
-
"@/<dir>/docs/page/index.tsx": "layouts/docs/page",
|
|
97
|
-
"@/<dir>/docs/page/client.tsx": "layouts/docs/page",
|
|
98
|
-
"@/<dir>/flux/index.tsx": "layouts/flux",
|
|
99
|
-
"@/<dir>/flux/page/index.tsx": "layouts/flux/page",
|
|
100
|
-
"@/<dir>/flux/page/client.tsx": "layouts/flux/page"
|
|
101
|
-
};
|
|
102
|
-
const layoutNameSet = new Set(layoutNames);
|
|
103
|
-
return {
|
|
104
|
-
beforeInstall(comp, { stack }) {
|
|
105
|
-
if (layoutNameSet.has(stack[0].name)) return;
|
|
106
|
-
return {
|
|
107
|
-
...comp,
|
|
108
|
-
$subComponents: comp.$subComponents.filter((child) => !layoutNameSet.has(child.name))
|
|
109
|
-
};
|
|
110
|
-
},
|
|
111
|
-
transformImport(specifier, { stack }) {
|
|
112
|
-
if (layoutNameSet.has(stack[0].name) || !(specifier in layoutComps)) return specifier;
|
|
113
|
-
return `fumadocs-ui/${layoutComps[specifier]}`;
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
//#endregion
|
|
118
|
-
//#region src/commands/add.ts
|
|
119
|
-
async function add(input, client) {
|
|
120
|
-
const config = client.config;
|
|
121
|
-
let target;
|
|
122
|
-
const installer = new ComponentInstaller(client, { plugins: [pluginPreserveLayouts()] });
|
|
123
|
-
const registry = UIRegistries[config.uiLibrary];
|
|
124
|
-
if (input.length === 0) {
|
|
125
|
-
const spin = spinner();
|
|
126
|
-
spin.start("fetching registry");
|
|
127
|
-
const info = await client.fetchRegistryInfo();
|
|
128
|
-
const options = [];
|
|
129
|
-
for (const item of info.indexes) options.push({
|
|
130
|
-
label: item.title ?? item.name,
|
|
131
|
-
value: item.name,
|
|
132
|
-
hint: item.description
|
|
133
|
-
});
|
|
134
|
-
const { indexes } = await client.createLinkedRegistryClient(registry).fetchRegistryInfo();
|
|
135
|
-
for (const item of indexes) options.push({
|
|
136
|
-
label: item.title ?? item.name,
|
|
137
|
-
value: `${registry}/${item.name}`,
|
|
138
|
-
hint: item.description
|
|
139
|
-
});
|
|
140
|
-
spin.stop(picocolors.bold(picocolors.greenBright("registry fetched")));
|
|
141
|
-
const value = await autocompleteMultiselect({
|
|
142
|
-
message: "Select components to install",
|
|
143
|
-
options
|
|
144
|
-
});
|
|
145
|
-
if (isCancel(value)) {
|
|
146
|
-
outro("Ended");
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
target = value;
|
|
150
|
-
} else target = await Promise.all(input.map(async (item) => await client.hasComponent(item) ? item : `${registry}/${item}`));
|
|
151
|
-
await install(target, installer);
|
|
152
|
-
}
|
|
153
|
-
async function install(target, installer) {
|
|
154
|
-
for (const name of target) {
|
|
155
|
-
const spin = spinner();
|
|
156
|
-
spin.start(picocolors.bold(picocolors.cyanBright(`Installing ${name}`)));
|
|
157
|
-
try {
|
|
158
|
-
await installer.install(name, {
|
|
159
|
-
onWarn(message) {
|
|
160
|
-
spin.message(message);
|
|
161
|
-
},
|
|
162
|
-
async confirmFileOverride(options) {
|
|
163
|
-
spin.clear();
|
|
164
|
-
const value = await confirm({
|
|
165
|
-
message: `Do you want to override ${options.path}?`,
|
|
166
|
-
initialValue: false
|
|
167
|
-
});
|
|
168
|
-
if (isCancel(value)) {
|
|
169
|
-
outro("Installation terminated");
|
|
170
|
-
process.exit(0);
|
|
171
|
-
}
|
|
172
|
-
spin.start(picocolors.bold(picocolors.cyanBright(`Installing ${name}`)));
|
|
173
|
-
return value;
|
|
174
|
-
},
|
|
175
|
-
onFileDownloaded(options) {
|
|
176
|
-
spin.message(options.path);
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
spin.stop(picocolors.bold(picocolors.greenBright(`${name} installed`)));
|
|
180
|
-
} catch (e) {
|
|
181
|
-
spin.error(e instanceof Error ? e.message : String(e));
|
|
182
|
-
process.exit(-1);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
const deps = await installer.deps();
|
|
186
|
-
if (deps.hasRequired()) {
|
|
187
|
-
log.message();
|
|
188
|
-
box([...deps.dependencies, ...deps.devDependencies].join("\n"), "New Dependencies");
|
|
189
|
-
const pm = (await detect())?.name ?? "npm";
|
|
190
|
-
const value = await confirm({ message: `Do you want to install with ${pm}?` });
|
|
191
|
-
if (isCancel(value)) {
|
|
192
|
-
outro("Installation terminated");
|
|
193
|
-
process.exit(0);
|
|
194
|
-
}
|
|
195
|
-
if (value) {
|
|
196
|
-
const spin = spinner({ errorMessage: "Failed to install dependencies" });
|
|
197
|
-
spin.start("Installing dependencies");
|
|
198
|
-
await deps.installRequired(pm);
|
|
199
|
-
spin.stop("Dependencies installed");
|
|
200
|
-
} else await deps.writeRequired();
|
|
201
|
-
}
|
|
202
|
-
await installer.onEnd();
|
|
203
|
-
outro(picocolors.bold(picocolors.greenBright("Successful")));
|
|
204
|
-
}
|
|
205
|
-
//#endregion
|
|
206
72
|
//#region src/commands/customise.ts
|
|
207
|
-
async function customise(
|
|
73
|
+
async function customise(config, connector) {
|
|
208
74
|
intro(picocolors.bgBlack(picocolors.whiteBright("Customise Fumadocs UI")));
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
const
|
|
212
|
-
const
|
|
213
|
-
const target = (await group({
|
|
75
|
+
const installer = new FumadocsComponentInstaller(connector, config);
|
|
76
|
+
const subRegistry = UIRegistries[config.uiLibrary];
|
|
77
|
+
const info = await connector.fetchRegistryInfo(subRegistry);
|
|
78
|
+
const targetInfo = (await group({
|
|
214
79
|
layout: () => select({
|
|
215
80
|
message: "What do you want to customise?",
|
|
216
81
|
options: [
|
|
@@ -218,7 +83,10 @@ async function customise(client) {
|
|
|
218
83
|
label: "Docs Layout",
|
|
219
84
|
value: {
|
|
220
85
|
id: "docs",
|
|
221
|
-
|
|
86
|
+
targets: [{
|
|
87
|
+
subRegistry,
|
|
88
|
+
name: "layouts/docs"
|
|
89
|
+
}],
|
|
222
90
|
print() {
|
|
223
91
|
printLayout(["fumadocs-ui/layouts/docs", "@/layouts/docs"], ["fumadocs-ui/layouts/docs/page", "@/layouts/docs/page"]);
|
|
224
92
|
}
|
|
@@ -229,7 +97,10 @@ async function customise(client) {
|
|
|
229
97
|
label: "Notebook Layout",
|
|
230
98
|
value: {
|
|
231
99
|
id: "notebook",
|
|
232
|
-
|
|
100
|
+
targets: [{
|
|
101
|
+
subRegistry,
|
|
102
|
+
name: "layouts/notebook"
|
|
103
|
+
}],
|
|
233
104
|
print() {
|
|
234
105
|
printLayout(["fumadocs-ui/layouts/notebook", "@/layouts/notebook"], ["fumadocs-ui/layouts/notebook/page", "@/layouts/notebook/page"]);
|
|
235
106
|
}
|
|
@@ -240,7 +111,10 @@ async function customise(client) {
|
|
|
240
111
|
label: "Flux Layout",
|
|
241
112
|
value: {
|
|
242
113
|
id: "flux",
|
|
243
|
-
|
|
114
|
+
targets: [{
|
|
115
|
+
subRegistry,
|
|
116
|
+
name: "layouts/flux"
|
|
117
|
+
}],
|
|
244
118
|
print() {
|
|
245
119
|
printLayout(["fumadocs-ui/layouts/flux", "@/layouts/flux"], ["fumadocs-ui/layouts/flux/page", "@/layouts/flux/page"]);
|
|
246
120
|
}
|
|
@@ -251,7 +125,10 @@ async function customise(client) {
|
|
|
251
125
|
label: "Home Layout",
|
|
252
126
|
value: {
|
|
253
127
|
id: "home",
|
|
254
|
-
|
|
128
|
+
targets: [{
|
|
129
|
+
subRegistry,
|
|
130
|
+
name: "layouts/home"
|
|
131
|
+
}],
|
|
255
132
|
print() {
|
|
256
133
|
printLayout(["fumadocs-ui/layouts/home", `@/layouts/home`]);
|
|
257
134
|
}
|
|
@@ -276,7 +153,7 @@ async function customise(client) {
|
|
|
276
153
|
hint: "for those who want to build their own UI from ground up",
|
|
277
154
|
value: {
|
|
278
155
|
id: "docs-min",
|
|
279
|
-
|
|
156
|
+
targets: [{ name: "layouts/docs-min" }],
|
|
280
157
|
print() {
|
|
281
158
|
printLayout(["fumadocs-ui/layouts/docs", "@/layouts/docs"], ["fumadocs-ui/layouts/docs/page", "@/layouts/docs/page"]);
|
|
282
159
|
}
|
|
@@ -293,7 +170,10 @@ async function customise(client) {
|
|
|
293
170
|
hint: "only replace a part of layout's page, useful for adjusting details",
|
|
294
171
|
value: {
|
|
295
172
|
id: index.name,
|
|
296
|
-
|
|
173
|
+
targets: [{
|
|
174
|
+
subRegistry,
|
|
175
|
+
name: index.name
|
|
176
|
+
}],
|
|
297
177
|
print() {
|
|
298
178
|
printSlot({
|
|
299
179
|
at: `@/layouts/${selected.id}/page/slots/${name}`,
|
|
@@ -310,7 +190,10 @@ async function customise(client) {
|
|
|
310
190
|
hint: "only replace a part of layout, useful for adjusting details",
|
|
311
191
|
value: {
|
|
312
192
|
id: index.name,
|
|
313
|
-
|
|
193
|
+
targets: [{
|
|
194
|
+
subRegistry,
|
|
195
|
+
name: index.name
|
|
196
|
+
}],
|
|
314
197
|
print() {
|
|
315
198
|
printSlot({
|
|
316
199
|
at: `@/layouts/${selected.id}/slots/${name}`,
|
|
@@ -329,8 +212,8 @@ async function customise(client) {
|
|
|
329
212
|
cancel("Installation Stopped.");
|
|
330
213
|
process.exit(0);
|
|
331
214
|
} })).target;
|
|
332
|
-
await
|
|
333
|
-
|
|
215
|
+
for (const target of targetInfo.targets) await installer.installInteractive(target.name, target.subRegistry);
|
|
216
|
+
targetInfo.print?.();
|
|
334
217
|
outro(picocolors.bold("Have fun!"));
|
|
335
218
|
}
|
|
336
219
|
function printLayout(...maps) {
|
|
@@ -499,6 +382,52 @@ return (
|
|
|
499
382
|
}
|
|
500
383
|
}
|
|
501
384
|
//#endregion
|
|
385
|
+
//#region src/commands/add.ts
|
|
386
|
+
async function add(input, connector, config) {
|
|
387
|
+
let targets;
|
|
388
|
+
const installer = new FumadocsComponentInstaller(connector, config);
|
|
389
|
+
const subRegistry = UIRegistries[config.uiLibrary];
|
|
390
|
+
if (input.length === 0) {
|
|
391
|
+
const spin = spinner();
|
|
392
|
+
spin.start("fetching registry");
|
|
393
|
+
async function scan(subRegistry) {
|
|
394
|
+
return (await connector.fetchRegistryInfo(subRegistry)).indexes.map((item) => ({
|
|
395
|
+
label: item.title ?? item.name,
|
|
396
|
+
value: {
|
|
397
|
+
name: item.name,
|
|
398
|
+
subRegistry
|
|
399
|
+
},
|
|
400
|
+
hint: item.description
|
|
401
|
+
}));
|
|
402
|
+
}
|
|
403
|
+
spin.stop(picocolors.bold(picocolors.greenBright("registry fetched")));
|
|
404
|
+
const value = await autocompleteMultiselect({
|
|
405
|
+
message: "Select components to install",
|
|
406
|
+
options: [...await scan(), ...await scan(subRegistry)]
|
|
407
|
+
});
|
|
408
|
+
if (isCancel(value)) {
|
|
409
|
+
outro("Ended");
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
targets = value;
|
|
413
|
+
} else targets = await Promise.all(input.map(async (item) => await connector.hasComponent(item) ? { name: item } : {
|
|
414
|
+
subRegistry,
|
|
415
|
+
name: item
|
|
416
|
+
}));
|
|
417
|
+
for (const target of targets) await installer.installInteractive(target.name, target.subRegistry);
|
|
418
|
+
outro(picocolors.bold(picocolors.greenBright("Successful")));
|
|
419
|
+
}
|
|
420
|
+
//#endregion
|
|
421
|
+
//#region src/utils/fs.ts
|
|
422
|
+
async function exists(pathLike) {
|
|
423
|
+
try {
|
|
424
|
+
await fs.access(pathLike);
|
|
425
|
+
return true;
|
|
426
|
+
} catch {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
//#endregion
|
|
502
431
|
//#region src/commands/export-epub.ts
|
|
503
432
|
const execAsync = promisify(exec);
|
|
504
433
|
async function readPackageJson(cwd) {
|
|
@@ -692,14 +621,15 @@ program.name("fumadocs").description("CLI to setup Fumadocs, init a config").ver
|
|
|
692
621
|
else console.log(picocolors.redBright("A config file already exists."));
|
|
693
622
|
});
|
|
694
623
|
program.command("customise").alias("customize").description("simple way to customise layouts with Fumadocs UI").option("--dir <string>", "the root url or directory to resolve registry").action(async (options) => {
|
|
695
|
-
await customise(
|
|
624
|
+
await customise(await createOrLoadConfig(options.config), createClientFromDir(options.dir));
|
|
696
625
|
});
|
|
697
626
|
const dirShortcuts = {
|
|
698
627
|
":preview": "https://preview.fumadocs.dev/registry",
|
|
699
628
|
":dev": "http://localhost:3000/registry"
|
|
700
629
|
};
|
|
701
630
|
program.command("add").description("add a new component to your docs").argument("[components...]", "components to download").option("--dir <string>", "the root url or directory to resolve registry").action(async (input, options) => {
|
|
702
|
-
|
|
631
|
+
const config = await createOrLoadConfig(options.config);
|
|
632
|
+
await add(input, createClientFromDir(options.dir), config);
|
|
703
633
|
});
|
|
704
634
|
program.command("export").description("export documentation to various formats").command("epub").description("export documentation to EPUB format (run after production build)").requiredOption("--framework <name>", "React framework: next, tanstack-start, react-router, waku").option("--output <path>", "output file path", "docs.epub").option("--scaffold-only", "only scaffold the EPUB route, do not copy").action(async (options) => {
|
|
705
635
|
await exportEpub({
|
|
@@ -727,9 +657,9 @@ program.command("tree").argument("[json_or_args]", "JSON output of `tree` comman
|
|
|
727
657
|
await fs.writeFile(output, out);
|
|
728
658
|
} else console.log(out);
|
|
729
659
|
});
|
|
730
|
-
function createClientFromDir(dir = "https://fumadocs.dev/registry"
|
|
660
|
+
function createClientFromDir(dir = "https://fumadocs.dev/registry") {
|
|
731
661
|
if (dir in dirShortcuts) dir = dirShortcuts[dir];
|
|
732
|
-
return dir.startsWith("http://") || dir.startsWith("https://") ? new
|
|
662
|
+
return dir.startsWith("http://") || dir.startsWith("https://") ? new HttpRegistryConnector(dir) : new LocalRegistryConnector(dir);
|
|
733
663
|
}
|
|
734
664
|
program.parse();
|
|
735
665
|
//#endregion
|