@fumadocs/cli 1.0.3 → 1.2.0

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