@fumadocs/cli 1.1.0 → 1.2.1

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