@fumadocs/cli 0.2.1 → 1.0.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/build/index.d.ts +110 -92
- package/dist/build/index.js +250 -244
- package/dist/index.js +347 -782
- package/package.json +6 -4
- package/dist/chunk-DG6SFM2G.js +0 -19
package/dist/build/index.js
CHANGED
|
@@ -1,12 +1,97 @@
|
|
|
1
|
-
import {
|
|
2
|
-
exists
|
|
3
|
-
} from "../chunk-DG6SFM2G.js";
|
|
4
|
-
|
|
5
1
|
// src/build/index.ts
|
|
6
2
|
import * as fs3 from "fs/promises";
|
|
7
3
|
import * as path4 from "path";
|
|
8
4
|
import picocolors from "picocolors";
|
|
9
5
|
|
|
6
|
+
// src/build/shadcn.ts
|
|
7
|
+
function mapDeps(deps) {
|
|
8
|
+
return Object.entries(deps).map(([k, v]) => {
|
|
9
|
+
if (v) return `${k}@${v}`;
|
|
10
|
+
return k;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function escapeName(name) {
|
|
14
|
+
return name;
|
|
15
|
+
}
|
|
16
|
+
function toShadcnRegistry(out, baseUrl) {
|
|
17
|
+
return {
|
|
18
|
+
homepage: baseUrl,
|
|
19
|
+
name: out.name,
|
|
20
|
+
items: out.components.map((comp) => componentToShadcn(comp, baseUrl))
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function componentToShadcn(comp, baseUrl) {
|
|
24
|
+
return {
|
|
25
|
+
extends: "none",
|
|
26
|
+
type: "registry:block",
|
|
27
|
+
name: escapeName(comp.name),
|
|
28
|
+
title: comp.title ?? comp.name,
|
|
29
|
+
description: comp.description,
|
|
30
|
+
dependencies: mapDeps(comp.dependencies),
|
|
31
|
+
devDependencies: mapDeps(comp.devDependencies),
|
|
32
|
+
registryDependencies: comp.subComponents.map((comp2) => {
|
|
33
|
+
if (comp2.startsWith("https://") || comp2.startsWith("http://"))
|
|
34
|
+
return comp2;
|
|
35
|
+
return new URL(`/r/${escapeName(comp2)}.json`, baseUrl).toString();
|
|
36
|
+
}),
|
|
37
|
+
files: comp.files.map((file) => {
|
|
38
|
+
return {
|
|
39
|
+
type: {
|
|
40
|
+
components: "registry:component",
|
|
41
|
+
lib: "registry:lib",
|
|
42
|
+
css: "registry:style",
|
|
43
|
+
route: "registry:page",
|
|
44
|
+
ui: "registry:ui",
|
|
45
|
+
block: "registry:block"
|
|
46
|
+
}[file.type],
|
|
47
|
+
content: file.content,
|
|
48
|
+
path: file.path,
|
|
49
|
+
target: file.target
|
|
50
|
+
};
|
|
51
|
+
})
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/build/validate.ts
|
|
56
|
+
function validateOutput(registry) {
|
|
57
|
+
function validateComponent(comp, ctx = {}) {
|
|
58
|
+
const { stack = /* @__PURE__ */ new Map() } = ctx;
|
|
59
|
+
for (const file of comp.files) {
|
|
60
|
+
const parents = stack.get(file.path);
|
|
61
|
+
if (parents) {
|
|
62
|
+
parents.add(comp.name);
|
|
63
|
+
} else {
|
|
64
|
+
stack.set(file.path, /* @__PURE__ */ new Set([comp.name]));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for (const name of comp.subComponents) {
|
|
68
|
+
const subComp = registry.components.find((item) => item.name === name);
|
|
69
|
+
if (!subComp) {
|
|
70
|
+
console.warn(`skipped component ${name}: not found`);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
validateComponent(subComp, {
|
|
74
|
+
stack
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
for (const file of comp.files) {
|
|
78
|
+
const parents = stack.get(file.path);
|
|
79
|
+
if (!parents) continue;
|
|
80
|
+
if (parents.size <= 1) continue;
|
|
81
|
+
throw new Error(
|
|
82
|
+
`Duplicated file in same component ${Array.from(parents).join(", ")}: ${file.path}`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const compSet = /* @__PURE__ */ new Set();
|
|
87
|
+
for (const comp of registry.components) {
|
|
88
|
+
if (compSet.has(comp.name))
|
|
89
|
+
throw new Error(`duplicated component name ${comp.name}`);
|
|
90
|
+
compSet.add(comp.name);
|
|
91
|
+
validateComponent(comp);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
10
95
|
// src/build/build-registry.ts
|
|
11
96
|
import * as fs2 from "fs/promises";
|
|
12
97
|
import * as path3 from "path";
|
|
@@ -14,86 +99,51 @@ import * as path3 from "path";
|
|
|
14
99
|
// src/build/build-file.ts
|
|
15
100
|
import * as path from "path";
|
|
16
101
|
import { ts } from "ts-morph";
|
|
17
|
-
async function buildFile(
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
function process2(specifier, getSpecifiedFile) {
|
|
28
|
-
let specifiedFile = getSpecifiedFile();
|
|
29
|
-
if (!specifiedFile) return;
|
|
30
|
-
const name = specifiedFile.isInNodeModules() ? builder.resolveDep(specifier.getLiteralValue()).name : path.relative(builder.registryDir, specifiedFile.getFilePath());
|
|
31
|
-
if (name in importMap) {
|
|
32
|
-
const resolver = importMap[name];
|
|
33
|
-
if (typeof resolver === "string") {
|
|
34
|
-
specifier.setLiteralValue(resolver);
|
|
35
|
-
specifiedFile = getSpecifiedFile();
|
|
36
|
-
if (!specifiedFile) return;
|
|
37
|
-
} else if (resolver.type === "dependency") {
|
|
38
|
-
const info = builder.resolveDep(resolver.name);
|
|
39
|
-
const value2 = onReference({
|
|
40
|
-
type: "dependency",
|
|
41
|
-
name: info.name,
|
|
42
|
-
version: info.version ?? "",
|
|
43
|
-
isDev: info.type === "dev"
|
|
44
|
-
});
|
|
45
|
-
if (value2) out.imports[specifier.getLiteralValue()] = value2;
|
|
46
|
-
return;
|
|
47
|
-
} else {
|
|
48
|
-
const sub2 = builder.getComponentByName(
|
|
49
|
-
resolver.name,
|
|
50
|
-
resolver.registry
|
|
51
|
-
);
|
|
52
|
-
if (!sub2)
|
|
53
|
-
throw new Error(`Failed to resolve sub component ${resolver.name}`);
|
|
54
|
-
const value2 = onReference({
|
|
55
|
-
type: "sub-component",
|
|
56
|
-
resolved: sub2,
|
|
57
|
-
targetFile: resolver.file
|
|
58
|
-
});
|
|
59
|
-
if (value2) out.imports[specifier.getLiteralValue()] = value2;
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
102
|
+
async function buildFile(file, builder, comp, writeReference) {
|
|
103
|
+
const sourceFilePath = path.join(builder.registryDir, file.path);
|
|
104
|
+
const defaultResolve = (specifier, specified) => {
|
|
105
|
+
let filePath;
|
|
106
|
+
if (specified) {
|
|
107
|
+
filePath = specified.getFilePath();
|
|
108
|
+
} else if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
109
|
+
filePath = path.join(path.dirname(sourceFilePath), specifier);
|
|
110
|
+
} else {
|
|
111
|
+
throw new Error("Unknown specifier " + specifier);
|
|
62
112
|
}
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
const value2 = onReference({
|
|
113
|
+
if (path.relative(builder.registryDir, filePath).startsWith("../")) {
|
|
114
|
+
return {
|
|
66
115
|
type: "dependency",
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
});
|
|
71
|
-
if (value2) out.imports[specifier.getLiteralValue()] = value2;
|
|
72
|
-
return;
|
|
116
|
+
dep: builder.getDepFromSpecifier(specifier),
|
|
117
|
+
specifier
|
|
118
|
+
};
|
|
73
119
|
}
|
|
74
|
-
const sub = builder.getSubComponent(
|
|
120
|
+
const sub = builder.getSubComponent(filePath);
|
|
75
121
|
if (sub) {
|
|
76
|
-
|
|
122
|
+
return {
|
|
77
123
|
type: "sub-component",
|
|
78
124
|
resolved: {
|
|
79
125
|
type: "local",
|
|
80
|
-
component: sub
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
specifiedFile.getFilePath()
|
|
85
|
-
)
|
|
86
|
-
});
|
|
87
|
-
if (value2) out.imports[specifier.getLiteralValue()] = value2;
|
|
88
|
-
return;
|
|
126
|
+
component: sub.component,
|
|
127
|
+
file: sub.file
|
|
128
|
+
}
|
|
129
|
+
};
|
|
89
130
|
}
|
|
90
|
-
|
|
131
|
+
return {
|
|
91
132
|
type: "file",
|
|
92
|
-
file:
|
|
93
|
-
}
|
|
94
|
-
|
|
133
|
+
file: filePath
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
function process2(specifier, getSpecifiedFile) {
|
|
137
|
+
const onResolve = comp.onResolve ?? builder.registry.onResolve;
|
|
138
|
+
let resolved = defaultResolve(
|
|
139
|
+
specifier.getLiteralValue(),
|
|
140
|
+
getSpecifiedFile()
|
|
141
|
+
);
|
|
142
|
+
if (onResolve) resolved = onResolve(resolved);
|
|
143
|
+
const out = writeReference(resolved);
|
|
144
|
+
if (out) specifier.setLiteralValue(out);
|
|
95
145
|
}
|
|
96
|
-
const sourceFile = await builder.createSourceFile(
|
|
146
|
+
const sourceFile = await builder.createSourceFile(sourceFilePath);
|
|
97
147
|
for (const item of sourceFile.getImportDeclarations()) {
|
|
98
148
|
process2(
|
|
99
149
|
item.getModuleSpecifier(),
|
|
@@ -116,8 +166,12 @@ async function buildFile(inputPath, outputPath, builder, comp, onReference) {
|
|
|
116
166
|
);
|
|
117
167
|
}
|
|
118
168
|
}
|
|
119
|
-
|
|
120
|
-
|
|
169
|
+
return {
|
|
170
|
+
content: sourceFile.getFullText(),
|
|
171
|
+
type: file.type,
|
|
172
|
+
path: file.path,
|
|
173
|
+
target: file.target
|
|
174
|
+
};
|
|
121
175
|
}
|
|
122
176
|
|
|
123
177
|
// src/build/component-builder.ts
|
|
@@ -125,46 +179,47 @@ import path2 from "path";
|
|
|
125
179
|
import { Project } from "ts-morph";
|
|
126
180
|
import * as fs from "fs/promises";
|
|
127
181
|
function createComponentBuilder(registry, packageJson) {
|
|
128
|
-
const rootDir = path2.join(registry.dir, registry.rootDir);
|
|
129
182
|
const project = new Project({
|
|
130
|
-
tsConfigFilePath:
|
|
183
|
+
tsConfigFilePath: path2.join(registry.dir, registry.tsconfigPath)
|
|
131
184
|
});
|
|
132
185
|
const fileToComponent = /* @__PURE__ */ new Map();
|
|
133
186
|
for (const comp of registry.components) {
|
|
134
187
|
for (const file of comp.files) {
|
|
135
|
-
|
|
136
|
-
if (fileToComponent.has(filePath))
|
|
188
|
+
if (fileToComponent.has(file.path))
|
|
137
189
|
console.warn(
|
|
138
|
-
`the same file ${file} exists in multiple component, you should make the shared file a separate component.`
|
|
190
|
+
`the same file ${file.path} exists in multiple component, you should make the shared file a separate component.`
|
|
139
191
|
);
|
|
140
|
-
fileToComponent.set(
|
|
192
|
+
fileToComponent.set(file.path, [comp, file]);
|
|
141
193
|
}
|
|
142
194
|
}
|
|
195
|
+
const deps = {
|
|
196
|
+
...packageJson?.dependencies,
|
|
197
|
+
...registry.dependencies
|
|
198
|
+
};
|
|
199
|
+
const devDeps = {
|
|
200
|
+
...packageJson?.devDependencies,
|
|
201
|
+
...registry.devDependencies
|
|
202
|
+
};
|
|
143
203
|
return {
|
|
144
204
|
registryDir: registry.dir,
|
|
145
205
|
registry,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
206
|
+
getDepFromSpecifier(specifier) {
|
|
207
|
+
return specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
|
|
208
|
+
},
|
|
209
|
+
getDepInfo(name) {
|
|
210
|
+
if (name in deps)
|
|
149
211
|
return {
|
|
150
|
-
|
|
151
|
-
|
|
212
|
+
name,
|
|
213
|
+
type: "runtime",
|
|
214
|
+
version: deps[name]
|
|
152
215
|
};
|
|
153
|
-
if (
|
|
216
|
+
if (name in devDeps)
|
|
154
217
|
return {
|
|
218
|
+
name,
|
|
155
219
|
type: "dev",
|
|
156
|
-
version:
|
|
157
|
-
name
|
|
220
|
+
version: devDeps[name]
|
|
158
221
|
};
|
|
159
|
-
}
|
|
160
|
-
if (packageJson && name in packageJson.dependencies) {
|
|
161
|
-
return {
|
|
162
|
-
type: "runtime",
|
|
163
|
-
version: packageJson.dependencies[name],
|
|
164
|
-
name
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
return { type: "runtime", name };
|
|
222
|
+
console.warn(`dep info for ${name} cannot be found`);
|
|
168
223
|
},
|
|
169
224
|
async createSourceFile(file) {
|
|
170
225
|
const content = await fs.readFile(file);
|
|
@@ -172,64 +227,17 @@ function createComponentBuilder(registry, packageJson) {
|
|
|
172
227
|
overwrite: true
|
|
173
228
|
});
|
|
174
229
|
},
|
|
175
|
-
getComponentByName(name
|
|
176
|
-
|
|
177
|
-
const child = registry.on[registryName];
|
|
178
|
-
const comp2 = child.registry.components.find(
|
|
179
|
-
(comp3) => comp3.name === name
|
|
180
|
-
);
|
|
181
|
-
if (comp2) {
|
|
182
|
-
return {
|
|
183
|
-
type: child.type,
|
|
184
|
-
registryName,
|
|
185
|
-
component: comp2
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
const comp = registry.components.find((comp2) => comp2.name === name);
|
|
191
|
-
if (comp) {
|
|
192
|
-
return {
|
|
193
|
-
type: "local",
|
|
194
|
-
registryName,
|
|
195
|
-
component: comp
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
resolveOutputPath(file, registryName, namespace) {
|
|
200
|
-
let targetRegistry = registry;
|
|
201
|
-
if (registryName && registry.on[registryName].type === "local") {
|
|
202
|
-
targetRegistry = registry.on[registryName].registry;
|
|
203
|
-
}
|
|
204
|
-
const parsed = file.split(":", 2);
|
|
205
|
-
if (parsed.length > 1) {
|
|
206
|
-
namespace ??= parsed[0];
|
|
207
|
-
file = parsed[1];
|
|
208
|
-
}
|
|
209
|
-
if (!path2.isAbsolute(file)) {
|
|
210
|
-
file = path2.join(targetRegistry.dir, file);
|
|
211
|
-
}
|
|
212
|
-
const rootDir2 = path2.join(targetRegistry.dir, targetRegistry.rootDir);
|
|
213
|
-
if (namespace) {
|
|
214
|
-
return `${namespace}:${path2.relative(rootDir2, file)}`;
|
|
215
|
-
}
|
|
216
|
-
if (targetRegistry.namespaces)
|
|
217
|
-
for (const namespace2 in targetRegistry.namespaces) {
|
|
218
|
-
const relativePath = path2.relative(
|
|
219
|
-
path2.join(targetRegistry.dir, namespace2),
|
|
220
|
-
file
|
|
221
|
-
);
|
|
222
|
-
if (!relativePath.startsWith("../")) {
|
|
223
|
-
return `${targetRegistry.namespaces[namespace2]}:${relativePath}`;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
return path2.relative(rootDir2, file);
|
|
230
|
+
getComponentByName(name) {
|
|
231
|
+
return registry.components.find((comp) => comp.name === name);
|
|
227
232
|
},
|
|
228
233
|
getSubComponent(file) {
|
|
229
234
|
const relativeFile = path2.relative(registry.dir, file);
|
|
230
235
|
const comp = fileToComponent.get(relativeFile);
|
|
231
236
|
if (!comp) return;
|
|
232
|
-
return
|
|
237
|
+
return {
|
|
238
|
+
component: comp[0],
|
|
239
|
+
file: comp[1]
|
|
240
|
+
};
|
|
233
241
|
}
|
|
234
242
|
};
|
|
235
243
|
}
|
|
@@ -237,30 +245,16 @@ function createComponentBuilder(registry, packageJson) {
|
|
|
237
245
|
// src/build/build-registry.ts
|
|
238
246
|
async function build(registry) {
|
|
239
247
|
const output = {
|
|
248
|
+
name: registry.name,
|
|
240
249
|
index: [],
|
|
241
250
|
components: []
|
|
242
251
|
};
|
|
243
252
|
function readPackageJson() {
|
|
244
|
-
if (typeof registry.packageJson !== "string"
|
|
245
|
-
|
|
246
|
-
return fs2.readFile(
|
|
247
|
-
registry.packageJson ? path3.join(registry.dir, registry.packageJson) : path3.join(registry.dir, registry.rootDir, "package.json")
|
|
248
|
-
).then((res) => JSON.parse(res.toString())).catch(() => void 0);
|
|
253
|
+
if (typeof registry.packageJson !== "string") return registry.packageJson;
|
|
254
|
+
return fs2.readFile(path3.join(registry.dir, registry.packageJson)).then((res) => JSON.parse(res.toString())).catch(() => void 0);
|
|
249
255
|
}
|
|
250
256
|
const packageJson = await readPackageJson();
|
|
251
257
|
const builder = createComponentBuilder(registry, packageJson);
|
|
252
|
-
const buildExtendRegistries = Object.values(registry.on ?? {}).map(
|
|
253
|
-
async (schema) => {
|
|
254
|
-
if (schema.type === "remote") {
|
|
255
|
-
return schema.registry;
|
|
256
|
-
}
|
|
257
|
-
return await build(schema.registry);
|
|
258
|
-
}
|
|
259
|
-
);
|
|
260
|
-
for (const built of await Promise.all(buildExtendRegistries)) {
|
|
261
|
-
output.components.push(...built.components);
|
|
262
|
-
output.index.push(...built.index);
|
|
263
|
-
}
|
|
264
258
|
const builtComps = await Promise.all(
|
|
265
259
|
registry.components.map((component) => buildComponent(component, builder))
|
|
266
260
|
);
|
|
@@ -268,11 +262,13 @@ async function build(registry) {
|
|
|
268
262
|
if (!input.unlisted) {
|
|
269
263
|
output.index.push({
|
|
270
264
|
name: input.name,
|
|
265
|
+
title: input.title,
|
|
271
266
|
description: input.description
|
|
272
267
|
});
|
|
273
268
|
}
|
|
274
269
|
output.components.push(comp);
|
|
275
270
|
}
|
|
271
|
+
validateOutput(output);
|
|
276
272
|
return output;
|
|
277
273
|
}
|
|
278
274
|
async function buildComponent(component, builder) {
|
|
@@ -280,70 +276,48 @@ async function buildComponent(component, builder) {
|
|
|
280
276
|
const subComponents = /* @__PURE__ */ new Set();
|
|
281
277
|
const devDependencies = /* @__PURE__ */ new Map();
|
|
282
278
|
const dependencies = /* @__PURE__ */ new Map();
|
|
279
|
+
function toImportPath(file) {
|
|
280
|
+
let filePath = file.target ?? file.path;
|
|
281
|
+
if (filePath.startsWith("./")) filePath = filePath.slice(2);
|
|
282
|
+
return `@/${filePath.replaceAll(path3.sep, "/")}`;
|
|
283
|
+
}
|
|
283
284
|
async function build2(file) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if (typeof file === "string") {
|
|
287
|
-
let namespace;
|
|
288
|
-
const parsed = file.split(":", 2);
|
|
289
|
-
if (parsed.length > 1) {
|
|
290
|
-
namespace = parsed[0];
|
|
291
|
-
inputPath = path3.join(builder.registryDir, parsed[1]);
|
|
292
|
-
} else {
|
|
293
|
-
inputPath = path3.join(builder.registryDir, file);
|
|
294
|
-
}
|
|
295
|
-
outputPath = builder.resolveOutputPath(file, void 0, namespace);
|
|
296
|
-
} else {
|
|
297
|
-
inputPath = path3.join(builder.registryDir, file.in);
|
|
298
|
-
outputPath = file.out;
|
|
299
|
-
}
|
|
300
|
-
if (processedFiles.has(inputPath)) return [];
|
|
301
|
-
processedFiles.add(inputPath);
|
|
285
|
+
if (processedFiles.has(file.path)) return [];
|
|
286
|
+
processedFiles.add(file.path);
|
|
302
287
|
const queue = [];
|
|
303
|
-
const result = await buildFile(
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
queue.push(path3.relative(builder.registryDir, reference.file));
|
|
311
|
-
return builder.resolveOutputPath(reference.file);
|
|
288
|
+
const result = await buildFile(file, builder, component, (reference) => {
|
|
289
|
+
if (reference.type === "custom") return reference.specifier;
|
|
290
|
+
if (reference.type === "file") {
|
|
291
|
+
const refFile = builder.registry.onUnknownFile?.(reference.file);
|
|
292
|
+
if (refFile) {
|
|
293
|
+
queue.push(refFile);
|
|
294
|
+
return toImportPath(refFile);
|
|
312
295
|
}
|
|
313
|
-
|
|
314
|
-
|
|
296
|
+
throw new Error(
|
|
297
|
+
`Unknown file ${reference.file} referenced by ${file.path}`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
if (reference.type === "sub-component") {
|
|
301
|
+
const resolved = reference.resolved;
|
|
302
|
+
if (resolved.component.name !== component.name)
|
|
315
303
|
subComponents.add(resolved.component.name);
|
|
316
|
-
|
|
317
|
-
return reference.targetFile;
|
|
318
|
-
}
|
|
319
|
-
for (const childFile of resolved.component.files) {
|
|
320
|
-
if (typeof childFile === "string" && childFile === reference.targetFile) {
|
|
321
|
-
return builder.resolveOutputPath(
|
|
322
|
-
childFile,
|
|
323
|
-
reference.resolved.registryName
|
|
324
|
-
);
|
|
325
|
-
}
|
|
326
|
-
if (typeof childFile === "object" && childFile.in === reference.targetFile) {
|
|
327
|
-
return childFile.out;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
throw new Error(
|
|
331
|
-
`Failed to find sub component ${resolved.component.name}'s ${reference.targetFile} referenced by ${inputPath}`
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
if (reference.type === "dependency") {
|
|
335
|
-
if (reference.isDev)
|
|
336
|
-
devDependencies.set(reference.name, reference.version);
|
|
337
|
-
else dependencies.set(reference.name, reference.version);
|
|
338
|
-
}
|
|
304
|
+
return toImportPath(resolved.file);
|
|
339
305
|
}
|
|
340
|
-
|
|
306
|
+
const dep = builder.getDepInfo(reference.dep);
|
|
307
|
+
if (dep) {
|
|
308
|
+
const map = dep.type === "dev" ? devDependencies : dependencies;
|
|
309
|
+
map.set(dep.name, dep.version);
|
|
310
|
+
}
|
|
311
|
+
return reference.specifier;
|
|
312
|
+
});
|
|
341
313
|
return [result, ...(await Promise.all(queue.map(build2))).flat()];
|
|
342
314
|
}
|
|
343
315
|
return [
|
|
344
316
|
component,
|
|
345
317
|
{
|
|
346
318
|
name: component.name,
|
|
319
|
+
title: component.title,
|
|
320
|
+
description: component.description,
|
|
347
321
|
files: (await Promise.all(component.files.map(build2))).flat(),
|
|
348
322
|
subComponents: Array.from(subComponents),
|
|
349
323
|
dependencies: Object.fromEntries(dependencies),
|
|
@@ -353,40 +327,72 @@ async function buildComponent(component, builder) {
|
|
|
353
327
|
}
|
|
354
328
|
|
|
355
329
|
// src/build/index.ts
|
|
356
|
-
|
|
357
|
-
const
|
|
358
|
-
|
|
330
|
+
function combineRegistry(...items) {
|
|
331
|
+
const out = {
|
|
332
|
+
index: [],
|
|
333
|
+
components: [],
|
|
334
|
+
name: items[0].name
|
|
335
|
+
};
|
|
336
|
+
for (const item of items) {
|
|
337
|
+
out.components.push(...item.components);
|
|
338
|
+
out.index.push(...item.index);
|
|
339
|
+
}
|
|
340
|
+
validateOutput(out);
|
|
341
|
+
return out;
|
|
342
|
+
}
|
|
343
|
+
async function writeShadcnRegistry(out, options) {
|
|
344
|
+
const { dir, cleanDir = false, baseUrl } = options;
|
|
345
|
+
if (cleanDir) {
|
|
359
346
|
await fs3.rm(dir, {
|
|
360
|
-
recursive: true
|
|
347
|
+
recursive: true,
|
|
348
|
+
force: true
|
|
361
349
|
});
|
|
362
|
-
|
|
363
|
-
console.log(picocolors.bold(picocolors.greenBright("Cleaned directory")));
|
|
364
|
-
}
|
|
350
|
+
console.log(picocolors.bold(picocolors.greenBright("Cleaned directory")));
|
|
365
351
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
352
|
+
await Promise.all(
|
|
353
|
+
toShadcnRegistry(out, baseUrl).items.map(async (item) => {
|
|
354
|
+
const file = path4.join(dir, `${item.name}.json`);
|
|
355
|
+
await writeFile2(file, JSON.stringify(item, null, 2));
|
|
356
|
+
})
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
async function writeFumadocsRegistry(out, options) {
|
|
360
|
+
const { dir, cleanDir = false, log = true } = options;
|
|
361
|
+
if (cleanDir) {
|
|
362
|
+
await fs3.rm(dir, {
|
|
363
|
+
recursive: true,
|
|
364
|
+
force: true
|
|
365
|
+
});
|
|
366
|
+
console.log(picocolors.bold(picocolors.greenBright("Cleaned directory")));
|
|
374
367
|
}
|
|
375
|
-
const write = out.components.map(async (comp) => {
|
|
376
|
-
const file = path4.join(dir, `${comp.name}.json`);
|
|
377
|
-
const json = JSON.stringify(comp, null, 2);
|
|
378
|
-
await writeFile2(file, json);
|
|
379
|
-
});
|
|
380
368
|
async function writeIndex() {
|
|
381
369
|
const file = path4.join(dir, "_registry.json");
|
|
382
370
|
const json = JSON.stringify(out.index, null, 2);
|
|
383
|
-
await writeFile2(file, json);
|
|
371
|
+
await writeFile2(file, json, log);
|
|
384
372
|
}
|
|
373
|
+
const write = out.components.map(async (comp) => {
|
|
374
|
+
const file = path4.join(dir, `${comp.name}.json`);
|
|
375
|
+
const json = JSON.stringify(comp, null, 2);
|
|
376
|
+
await writeFile2(file, json, log);
|
|
377
|
+
});
|
|
385
378
|
write.push(writeIndex());
|
|
386
379
|
await Promise.all(write);
|
|
387
380
|
}
|
|
381
|
+
async function writeFile2(file, content, log = true) {
|
|
382
|
+
await fs3.mkdir(path4.dirname(file), { recursive: true });
|
|
383
|
+
await fs3.writeFile(file, content);
|
|
384
|
+
if (log) {
|
|
385
|
+
const size = (Buffer.byteLength(content) / 1024).toFixed(2);
|
|
386
|
+
console.log(
|
|
387
|
+
`${picocolors.greenBright("+")} ${path4.relative(process.cwd(), file)} ${picocolors.dim(`${size} KB`)}`
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
388
391
|
export {
|
|
389
392
|
build,
|
|
393
|
+
combineRegistry,
|
|
390
394
|
createComponentBuilder,
|
|
391
|
-
|
|
395
|
+
toShadcnRegistry,
|
|
396
|
+
writeFumadocsRegistry,
|
|
397
|
+
writeShadcnRegistry
|
|
392
398
|
};
|