160 lines
3.6 KiB
TypeScript
160 lines
3.6 KiB
TypeScript
import type { Config } from '@/src/utils/get-config'
|
|
import type { registryItemWithContentSchema } from '@/src/utils/registry/schema'
|
|
import type * as z from 'zod'
|
|
import process from 'node:process'
|
|
import {
|
|
registryBaseColorSchema,
|
|
registryIndexSchema,
|
|
registryWithContentSchema,
|
|
stylesSchema,
|
|
} from '@/src/utils/registry/schema'
|
|
import consola from 'consola'
|
|
import { ofetch } from 'ofetch'
|
|
import path from 'pathe'
|
|
import { ProxyAgent } from 'undici'
|
|
|
|
const baseUrl = process.env.COMPONENTS_REGISTRY_URL ?? 'https://www.shadcn-vue.com'
|
|
const agent = process.env.https_proxy
|
|
? new ProxyAgent(process.env.https_proxy)
|
|
: undefined
|
|
|
|
export async function getRegistryIndex() {
|
|
try {
|
|
const [result] = await fetchRegistry(['index.json'])
|
|
|
|
return registryIndexSchema.parse(result)
|
|
}
|
|
catch (error) {
|
|
throw new Error('Failed to fetch components from registry.')
|
|
}
|
|
}
|
|
|
|
export async function getRegistryStyles() {
|
|
try {
|
|
const [result] = await fetchRegistry(['styles/index.json'])
|
|
|
|
return stylesSchema.parse(result)
|
|
}
|
|
catch (error) {
|
|
throw new Error('Failed to fetch styles from registry.')
|
|
}
|
|
}
|
|
|
|
export function getRegistryBaseColors() {
|
|
return [
|
|
{
|
|
name: 'slate',
|
|
label: 'Slate',
|
|
},
|
|
{
|
|
name: 'gray',
|
|
label: 'Gray',
|
|
},
|
|
{
|
|
name: 'zinc',
|
|
label: 'Zinc',
|
|
},
|
|
{
|
|
name: 'neutral',
|
|
label: 'Neutral',
|
|
},
|
|
{
|
|
name: 'stone',
|
|
label: 'Stone',
|
|
},
|
|
]
|
|
}
|
|
|
|
export async function getRegistryBaseColor(baseColor: string) {
|
|
try {
|
|
const [result] = await fetchRegistry([`colors/${baseColor}.json`])
|
|
|
|
return registryBaseColorSchema.parse(result)
|
|
}
|
|
catch (error) {
|
|
throw new Error('Failed to fetch base color from registry.')
|
|
}
|
|
}
|
|
|
|
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,
|
|
)
|
|
}
|
|
|
|
export async function fetchTree(
|
|
style: string,
|
|
tree: z.infer<typeof registryIndexSchema>,
|
|
) {
|
|
try {
|
|
const paths = tree.map(item => `styles/${style}/${item.name}.json`)
|
|
const result = await fetchRegistry(paths)
|
|
|
|
return registryWithContentSchema.parse(result)
|
|
}
|
|
catch (error) {
|
|
throw new Error('Failed to fetch tree from registry.')
|
|
}
|
|
}
|
|
|
|
export function getItemTargetPath(
|
|
config: Config,
|
|
item: Pick<z.infer<typeof registryItemWithContentSchema>, 'type'>,
|
|
override?: string,
|
|
) {
|
|
// Allow overrides for all items but ui.
|
|
if (override)
|
|
return override
|
|
|
|
if (item.type === 'components:ui' && config.aliases.ui)
|
|
return config.resolvedPaths.ui
|
|
|
|
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,
|
|
)
|
|
}
|
|
|
|
async function fetchRegistry(paths: string[]) {
|
|
try {
|
|
const results = await Promise.all(
|
|
paths.map(async (path) => {
|
|
const response = await ofetch(`${baseUrl}/registry/${path}`, {
|
|
dispatcher: agent,
|
|
})
|
|
|
|
return response
|
|
}),
|
|
)
|
|
return results
|
|
}
|
|
catch (error) {
|
|
consola.error(error)
|
|
throw new Error(`Failed to fetch registry from ${baseUrl}.`)
|
|
}
|
|
}
|