mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-07-09 06:55:07 +00:00
* feat(shadcn): add view command * test(shadcn): add tests for view command * feat(shadcn): allow shadow config in view command * chore: changeset * test(shadcn): skip view * test(shadcn): update view port number * feat(shadcn): add list command * fix * feat(shadcn): implement search command * fix: tests * fix * chore: update changesets
218 lines
5.1 KiB
TypeScript
218 lines
5.1 KiB
TypeScript
import path from "path"
|
|
import { buildUrlAndHeadersForRegistryItem } from "@/src/registry/builder"
|
|
import { configWithDefaults } from "@/src/registry/config"
|
|
import { BASE_COLORS } from "@/src/registry/constants"
|
|
import {
|
|
clearRegistryContext,
|
|
setRegistryHeaders,
|
|
} from "@/src/registry/context"
|
|
import {
|
|
RegistryNotFoundError,
|
|
RegistryParseError,
|
|
} from "@/src/registry/errors"
|
|
import { fetchRegistry } from "@/src/registry/fetcher"
|
|
import {
|
|
fetchRegistryItems,
|
|
resolveRegistryTree,
|
|
} from "@/src/registry/resolver"
|
|
import {
|
|
iconsSchema,
|
|
registryBaseColorSchema,
|
|
registryIndexSchema,
|
|
registryItemSchema,
|
|
registrySchema,
|
|
stylesSchema,
|
|
} from "@/src/schema"
|
|
import { Config } from "@/src/utils/get-config"
|
|
import { handleError } from "@/src/utils/handle-error"
|
|
import { logger } from "@/src/utils/logger"
|
|
import { z } from "zod"
|
|
|
|
// Schema for validating registry names
|
|
const registryNameSchema = z
|
|
.string()
|
|
.regex(
|
|
/^@[a-zA-Z0-9][a-zA-Z0-9-_]*$/,
|
|
"Registry name must start with @ followed by alphanumeric characters, hyphens, or underscores"
|
|
)
|
|
|
|
export async function getRegistry(
|
|
name: `@${string}`,
|
|
config?: Partial<Config>
|
|
) {
|
|
// Validate the registry name using Zod schema
|
|
try {
|
|
registryNameSchema.parse(name.split("/")[0])
|
|
} catch (error) {
|
|
throw new RegistryParseError(name, error)
|
|
}
|
|
|
|
if (!name.endsWith("/registry")) {
|
|
name = `${name}/registry`
|
|
}
|
|
|
|
const urlAndHeaders = buildUrlAndHeadersForRegistryItem(
|
|
name,
|
|
configWithDefaults(config)
|
|
)
|
|
|
|
if (!urlAndHeaders?.url) {
|
|
throw new RegistryNotFoundError(name)
|
|
}
|
|
|
|
// Set headers in context if provided
|
|
if (urlAndHeaders.headers && Object.keys(urlAndHeaders.headers).length > 0) {
|
|
setRegistryHeaders({
|
|
[urlAndHeaders.url]: urlAndHeaders.headers,
|
|
})
|
|
}
|
|
|
|
const [result] = await fetchRegistry([urlAndHeaders.url])
|
|
|
|
try {
|
|
return registrySchema.parse(result)
|
|
} catch (error) {
|
|
throw new RegistryParseError(name, error)
|
|
}
|
|
}
|
|
|
|
export async function getRegistryItems(
|
|
items: string[],
|
|
config?: Partial<Config>,
|
|
options: { useCache?: boolean } = {}
|
|
) {
|
|
clearRegistryContext()
|
|
|
|
return fetchRegistryItems(items, configWithDefaults(config), options)
|
|
}
|
|
|
|
export async function resolveRegistryItems(
|
|
items: string[],
|
|
config?: Partial<Config>,
|
|
options: { useCache?: boolean } = {}
|
|
) {
|
|
clearRegistryContext()
|
|
return resolveRegistryTree(items, configWithDefaults(config), options)
|
|
}
|
|
|
|
export async function getShadcnRegistryIndex() {
|
|
try {
|
|
const [result] = await fetchRegistry(["index.json"])
|
|
|
|
return registryIndexSchema.parse(result)
|
|
} catch (error) {
|
|
logger.error("\n")
|
|
handleError(error)
|
|
}
|
|
}
|
|
|
|
export async function getRegistryStyles() {
|
|
try {
|
|
const [result] = await fetchRegistry(["styles/index.json"])
|
|
|
|
return stylesSchema.parse(result)
|
|
} catch (error) {
|
|
logger.error("\n")
|
|
handleError(error)
|
|
return []
|
|
}
|
|
}
|
|
|
|
export async function getRegistryIcons() {
|
|
try {
|
|
const [result] = await fetchRegistry(["icons/index.json"])
|
|
return iconsSchema.parse(result)
|
|
} catch (error) {
|
|
handleError(error)
|
|
return {}
|
|
}
|
|
}
|
|
|
|
export async function getRegistryBaseColors() {
|
|
return BASE_COLORS
|
|
}
|
|
|
|
export async function getRegistryBaseColor(baseColor: string) {
|
|
try {
|
|
const [result] = await fetchRegistry([`colors/${baseColor}.json`])
|
|
|
|
return registryBaseColorSchema.parse(result)
|
|
} catch (error) {
|
|
handleError(error)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @deprecated This function is deprecated and will be removed in a future version.
|
|
*/
|
|
export async function resolveTree(
|
|
index: z.infer<typeof registryIndexSchema>,
|
|
names: string[]
|
|
) {
|
|
const tree: z.infer<typeof registryIndexSchema> = []
|
|
|
|
for (const name of names) {
|
|
const entry = index.find((entry) => entry.name === name)
|
|
|
|
if (!entry) {
|
|
continue
|
|
}
|
|
|
|
tree.push(entry)
|
|
|
|
if (entry.registryDependencies) {
|
|
const dependencies = await resolveTree(index, entry.registryDependencies)
|
|
tree.push(...dependencies)
|
|
}
|
|
}
|
|
|
|
return tree.filter(
|
|
(component, index, self) =>
|
|
self.findIndex((c) => c.name === component.name) === index
|
|
)
|
|
}
|
|
|
|
/**
|
|
* @deprecated This function is deprecated and will be removed in a future version.
|
|
*/
|
|
export async function fetchTree(
|
|
style: string,
|
|
tree: z.infer<typeof registryIndexSchema>
|
|
) {
|
|
try {
|
|
const paths = tree.map((item) => `styles/${style}/${item.name}.json`)
|
|
const results = await fetchRegistry(paths)
|
|
return results.map((result) => registryItemSchema.parse(result))
|
|
} catch (error) {
|
|
handleError(error)
|
|
return []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @deprecated This function is deprecated and will be removed in a future version.
|
|
*/
|
|
export async function getItemTargetPath(
|
|
config: Config,
|
|
item: Pick<z.infer<typeof registryItemSchema>, "type">,
|
|
override?: string
|
|
) {
|
|
if (override) {
|
|
return override
|
|
}
|
|
|
|
if (item.type === "registry:ui") {
|
|
return config.resolvedPaths.ui ?? config.resolvedPaths.components
|
|
}
|
|
|
|
const [parent, type] = item.type?.split(":") ?? []
|
|
if (!(parent in config.resolvedPaths)) {
|
|
return null
|
|
}
|
|
|
|
return path.join(
|
|
config.resolvedPaths[parent as keyof typeof config.resolvedPaths],
|
|
type
|
|
)
|
|
}
|