diff --git a/packages/cli/src/commands/registry/build.ts b/packages/cli/src/commands/registry/build.ts index 0de9e2ae7d..49f9e7c32c 100644 --- a/packages/cli/src/commands/registry/build.ts +++ b/packages/cli/src/commands/registry/build.ts @@ -162,7 +162,8 @@ async function runBuild(options: BuildOptions) { const dependencies = new Set(item.dependencies); const devDependencies = new Set(item.devDependencies); - const registryDependencies = new Set(item.registryDependencies); + + const registryDependencies = new Set(item.registryDependencies.map(transformLocal)); const predefinedDeps = dependencies.size > 0 && devDependencies.size > 0; if (!predefinedDeps) { @@ -210,3 +211,23 @@ async function runBuild(options: BuildOptions) { await p.tasks(tasks); } + +/** + * Transforms registryDependencies that start with `local:` into a path + * relative to the current registry-item's json file. + * + * ``` + * "local:stepper" + *``` + * transforms into: + * ``` + * "./stepper.json" + * ``` + */ +function transformLocal(registryDep: string) { + if (registryDep.startsWith("local:")) { + const LOCAL_REGEX = /^local:(.*)/; + return registryDep.replace(LOCAL_REGEX, "./$1.json"); + } + return registryDep; +} diff --git a/packages/cli/src/commands/update/index.ts b/packages/cli/src/commands/update/index.ts index 26220f0b19..1881fb7fa0 100644 --- a/packages/cli/src/commands/update/index.ts +++ b/packages/cli/src/commands/update/index.ts @@ -153,7 +153,6 @@ async function runUpdate(cwd: string, config: cliConfig.Config, options: UpdateO const tasks: p.Task[] = []; const resolvedItems = await registry.resolveRegistryItems({ - baseUrl: registryUrl, registryIndex: registryIndex, items: selectedComponents.map((comp) => comp.name), }); diff --git a/packages/cli/src/utils/add-registry-items.ts b/packages/cli/src/utils/add-registry-items.ts index 14841afc6b..21ab266efd 100644 --- a/packages/cli/src/utils/add-registry-items.ts +++ b/packages/cli/src/utils/add-registry-items.ts @@ -30,7 +30,6 @@ export async function addRegistryItems(opts: AddRegistryItemsProps) { const registryIndex = await registry.getRegistryIndex(registryUrl); const resolvedItems = await registry.resolveRegistryItems({ - baseUrl: registryUrl, items: Array.from(selectedItems), registryIndex, }); diff --git a/packages/cli/src/utils/registry/index.ts b/packages/cli/src/utils/registry/index.ts index acf2653be5..d2e8bc7427 100644 --- a/packages/cli/src/utils/registry/index.ts +++ b/packages/cli/src/utils/registry/index.ts @@ -47,46 +47,50 @@ export async function getRegistryBaseColor(baseUrl: string, baseColor: string) { } type ResolveRegistryItemsProps = { - baseUrl: string; registryIndex: schemas.RegistryIndex; items: string[]; - includeRegDeps?: boolean; + parentUrl?: URL; }; type ResolvedRegistryItem = schemas.RegistryItem | schemas.RegistryIndexItem; export async function resolveRegistryItems({ registryIndex, - baseUrl, items, - includeRegDeps = true, + parentUrl, }: ResolveRegistryItemsProps): Promise { const resolvedItems: ResolvedRegistryItem[] = []; for (const item of items) { + let remoteUrl: URL | undefined; let resolvedItem: ResolvedRegistryItem | undefined = registryIndex.find( (entry) => entry.name === item ); - // the `item` doesn't exist in the `index`, so it _must_ be a remote item (in other words, it's a URL) + /** + * The `item` doesn't exist in the registry's `index`, so it can be one of two things: + * 1. a remote registry item (URL) + * 2. a `local:registryDep` of a _remote_ item (relative path from that item to the dep) + */ if (!resolvedItem) { - const url = item; - if (!isUrl(url)) { + const isRelative = item.startsWith("./") || item.startsWith("../"); + if (isUrl(item) || (parentUrl && isRelative)) { + remoteUrl = new URL(item, parentUrl); + const [result] = await fetchRegistry([remoteUrl]); + resolvedItem = schemas.registryItemSchema.parse(result); + } else { throw error( - `Component item '${item}' does not exist in the registry, nor is it a valid URL.` + `Registry item '${item}' does not exist in the registry, nor is it a valid URL or a relative path to a registry dependency.` ); } - - const [result] = await fetchRegistry([url]); - resolvedItem = schemas.registryItemSchema.parse(result); } resolvedItems.push(resolvedItem); - if (includeRegDeps && resolvedItem.registryDependencies?.length) { + if (resolvedItem.registryDependencies?.length) { const registryDeps = await resolveRegistryItems({ - baseUrl, registryIndex: registryIndex, items: resolvedItem.registryDependencies, + parentUrl: remoteUrl, }); resolvedItems.push(...registryDeps); } diff --git a/registry-template/registry.json b/registry-template/registry.json index 64341bf370..8f0a254b1c 100644 --- a/registry-template/registry.json +++ b/registry-template/registry.json @@ -25,7 +25,7 @@ "registryDependencies": ["button", "input", "label", "textarea", "card"], "files": [ { - "path": "registry/blocks/example-form/example-form.svelte", + "path": "src/lib/registry/blocks/example-form/example-form.svelte", "type": "registry:component" } ] @@ -84,15 +84,15 @@ "files": [ { "path": "src/lib/registry/ui/stepper/stepper.svelte", - "type": "registry:component" + "type": "registry:file" }, { "path": "src/lib/registry/ui/stepper/stepper-item.svelte", - "type": "registry:component" + "type": "registry:file" }, { "path": "src/lib/registry/ui/stepper/index.ts", - "type": "registry:lib" + "type": "registry:file" } ] }, diff --git a/sites/docs/src/content/registry/registry-item-json.md b/sites/docs/src/content/registry/registry-item-json.md index 7583f78f94..fdd976b1b1 100644 --- a/sites/docs/src/content/registry/registry-item-json.md +++ b/sites/docs/src/content/registry/registry-item-json.md @@ -136,23 +136,62 @@ Use `@version` to specify the version of your registry item. ### registryDependencies -Used for registry dependencies. Can be names or URLs. Use the name of the item to reference shadcn/ui components and urls to reference other registries. +Defines other registry items that this item depends on. -- For `shadcn-svelte` registry items such as `button`, `input`, `select`, etc use the name eg. `['button', 'input', 'select']`. -- For custom registry items use the URL of the registry item eg. `['https://example.com/r/hello-world.json']`. +Each entry may be one of the following: + +#### shadcn-svelte Registry Item + +The name of a shadcn-svelte registry item (e.g., `'button'`, `'input'`, `'select'`), which will resolve to that item in the shadcn-svelte registry. ```json title="registry-item.json" showLineNumbers { - "registryDependencies": [ - "button", - "input", - "select", - "https://example.com/r/editor.json" + "registryDependencies": ["button", "input", "select"] +} +``` + +#### Remote URL + +A full URL to a custom registry item (e.g. `https://example.com/r/hello-world.json`) + +```json title="registry-item.json" showLineNumbers +{ + "registryDependencies": ["https://example.com/r/hello-world.json"] +} +``` + +#### Local alias (when building with the CLI) + +If you're defining the item in `registry.json` and using the CLI to build the registry, you can use a name prefixed with `local:` (e.g. `local:stepper`) to reference an item in the current registry. The CLI will convert this to a relative path (e.g. `./stepper.json`) in the output `registry-item.json` file. + +```json title="registry.json" showLineNumbers +{ + "items": [ + { + "name": "hello-world", + "registryDependencies": ["local:stepper"] + } ] } ``` -Note: The CLI will automatically resolve remote registry dependencies. +Which the CLI will convert to the following in the output `registry-item.json` file: + +```json title="registry-item.json" showLineNumbers +{ + "registryDependencies": ["./stepper.json"] +} +``` + +#### Relative Path + +If you're not using the CLI and defining the item directly in its `registry-item.json` file, you can specify a relative path, which is relative to the current item, to reference another item in the registry (e.g. `./stepper.json`). + +```json title="registry-item.json" showLineNumbers +{ + "registryDependencies": ["./stepper.json"] +} +``` ### files diff --git a/sites/docs/src/content/registry/registry-json.md b/sites/docs/src/content/registry/registry-json.md index 07ff048dab..38d0c23b3b 100644 --- a/sites/docs/src/content/registry/registry-json.md +++ b/sites/docs/src/content/registry/registry-json.md @@ -22,7 +22,7 @@ The `registry.json` schema is used to define your custom component registry. "description": "A simple hello world component.", "files": [ { - "path": "registry/hello-world/hello-world.svelte", + "path": "src/lib/registry/blocks/hello-world/hello-world.svelte", "type": "registry:component" } ] @@ -79,7 +79,7 @@ The `items` in your registry. Each item must implement the [registry-item schema "description": "A simple hello world component.", "files": [ { - "path": "registry/hello-world/hello-world.svelte", + "path": "src/lib/registry/blocks/hello-world/hello-world.svelte", "type": "registry:component" } ]