UNPKG

@astrojs/starlight

Version:

Build beautiful, high-performance documentation websites with Astro

164 lines (151 loc) 6.4 kB
import type { AstroBuiltinAttributes } from 'astro'; import type { HTMLAttributes } from 'astro/types'; import { z } from 'astro/zod'; import { I18nBadgeConfigSchema } from './badge'; import { stripLeadingAndTrailingSlashes } from '../utils/path'; const SidebarBaseSchema = z.object({ /** The visible label for this item in the sidebar. */ label: z.string(), /** Translations of the `label` for each supported language. */ translations: z.record(z.string(), z.string()).default({}), /** Adds a badge to the item */ badge: I18nBadgeConfigSchema(), }); const SidebarGroupSchema = z.object({ ...SidebarBaseSchema.shape, /** * Explicitly prevent custom attributes on groups as the final type for supported sidebar item * is a non-discriminated union where TypeScript will not perform excess property checks. * This means that a user could define a sidebar group with custom attributes, not getting a * TypeScript error, and only have it fail at runtime. * @see https://github.com/microsoft/TypeScript/issues/20863 */ attrs: z.never().optional(), /** Whether this item should be collapsed by default. */ collapsed: z.boolean().default(false), }); // HTML attributes that can be added to an anchor element, validated as // `Record<string, string | number | boolean | undefined>` but typed as `HTMLAttributes<'a'>` // for user convenience. const linkHTMLAttributesSchema = z.record( z.string(), z.union([z.string(), z.number(), z.boolean(), z.undefined(), z.null()]) ) as z.ZodType<LinkHTMLAttributes, LinkHTMLAttributes>; export type LinkHTMLAttributes = Omit< HTMLAttributes<'a'>, keyof AstroBuiltinAttributes | 'children' >; export const SidebarLinkItemHTMLAttributesSchema = () => linkHTMLAttributesSchema.default({}); const SidebarLinkItemSchema = z.strictObject({ ...SidebarBaseSchema.shape, /** The link to this item’s content. Can be a relative link to local files or the full URL of an external page. */ link: z.string(), /** HTML attributes to add to the link item. */ attrs: SidebarLinkItemHTMLAttributesSchema(), }); export type SidebarLinkItem = z.infer<typeof SidebarLinkItemSchema>; const AutoSidebarEntriesSchema = z .object({ /** * Explicitly prevent autogenerated groups which are no longer supported as the final type for * supported sidebar item is a non-discriminated union where TypeScript will not perform excess * property checks. This means that a user could define a sidebar group with an autogenerated * property, not getting a TypeScript error, and only have it fail at runtime. * @see https://github.com/microsoft/TypeScript/issues/20863 */ label: z.custom<never>().optional(), /** Enable autogenerating entries from a specific docs directory. */ autogenerate: z.object({ /** The directory to generate sidebar items for. */ directory: z.string().transform(stripLeadingAndTrailingSlashes), /** Whether the autogenerated subgroups should be collapsed by default. Default: `false`. */ collapsed: z.boolean().optional(), /** HTML attributes to add to the autogenerated link items. */ attrs: SidebarLinkItemHTMLAttributesSchema(), // TODO: not supported by Docusaurus but would be good to have /** How many directories deep to include from this directory in the sidebar. Default: `Infinity`. */ // depth: z.number().optional(), }), }) .strict() .superRefine((config, ctx) => { if (!('label' in config)) return; // TODO: Remove this error message in a future release once most users have migrated ctx.addIssue({ code: 'custom', message: `Found an \`autogenerate\` object with a \`label\`. Support for autogenerated sidebar groups was removed in Starlight v0.39.0.\n` + `You should instead create a group with the desired \`label\` and an \`items\` array containing the autogenerate config:\n\n` + `{\n` + ` label: '${config.label}',\n` + ` items: [{ autogenerate: ${JSON.stringify( config.autogenerate, // Hide empty attrs object that is automatically added by the schema default value. (key, value: unknown) => key === 'attrs' && typeof value === 'object' && value !== null && Object.keys(value).length === 0 ? undefined : value, ' ' ).replace(/\n\s*/g, ' ')} }]\n` + `}`, }); }); export type AutoSidebarEntries = z.infer<typeof AutoSidebarEntriesSchema>; type ManualSidebarGroupInput = z.input<typeof SidebarGroupSchema> & { /** Array of links and subcategories to display in this category. */ items: Array< | z.input<typeof SidebarLinkItemSchema> | z.input<typeof AutoSidebarEntriesSchema> | z.input<typeof InternalSidebarLinkItemSchema> | z.input<typeof InternalSidebarLinkItemShorthandSchema> | ManualSidebarGroupInput >; }; type ManualSidebarGroupOutput = z.output<typeof SidebarGroupSchema> & { /** Array of links and subcategories to display in this category. */ items: Array< | z.output<typeof SidebarLinkItemSchema> | z.output<typeof AutoSidebarEntriesSchema> | z.output<typeof InternalSidebarLinkItemSchema> | z.output<typeof InternalSidebarLinkItemShorthandSchema> | ManualSidebarGroupOutput >; }; const ManualSidebarGroupSchema: z.ZodType<ManualSidebarGroupOutput, ManualSidebarGroupInput> = z.strictObject({ ...SidebarGroupSchema.shape, /** Array of links and subcategories to display in this category. */ items: z.lazy(() => z .union([ SidebarLinkItemSchema, ManualSidebarGroupSchema, AutoSidebarEntriesSchema, InternalSidebarLinkItemSchema, InternalSidebarLinkItemShorthandSchema, ]) .array() ), }); const InternalSidebarLinkItemSchema = z.object({ ...SidebarBaseSchema.partial({ label: true }).shape, /** The link to this item’s content. Must be a slug of a Content Collection entry. */ slug: z.string(), /** HTML attributes to add to the link item. */ attrs: SidebarLinkItemHTMLAttributesSchema(), }); const InternalSidebarLinkItemShorthandSchema = z .string() .transform((slug) => InternalSidebarLinkItemSchema.parse({ slug })); export type InternalSidebarLinkItem = z.output<typeof InternalSidebarLinkItemSchema>; export const SidebarItemSchema = z.union([ SidebarLinkItemSchema, ManualSidebarGroupSchema, AutoSidebarEntriesSchema, InternalSidebarLinkItemSchema, InternalSidebarLinkItemShorthandSchema, ]); export type SidebarItem = z.infer<typeof SidebarItemSchema>;