/// import { defineCollection as defineNative, type BaseSchema, type SchemaContext, } from 'astro:content'; import { z, type ZodIntersection } from 'astro/zod'; export type { BaseSchema }; // Copied from Starlight because Astro core doesn't export their definitions :( // https://github.com/withastro/starlight/blob/95ace6d51c7bf631863b06ee46bbc9b6dff6828a/packages/starlight/schema.ts#L116-L123 /** Type that extends a collection's default schema with an optional, user-defined schema. */ export type ExtendedSchema = [ T, ] extends [never] ? S : T extends BaseSchema ? ZodIntersection : S; type CollectionConfig = ReturnType>; export interface CollectionExtensionOptions { extends?: E | ((context: SchemaContext) => E); } export type ExtendedCollection = ExtendedSchema extends BaseSchema ? CollectionConfig> : CollectionConfig; export type FancyCollection = ( options?: CollectionExtensionOptions ) => ExtendedCollection; /** * Define a collection from an integration that can be extended by users of the integration. * * Also known as a FancyCollection 💅 */ export function defineCollection( config: CollectionConfig ): FancyCollection { const definedConfig = defineNative(config); const fn = ( options?: CollectionExtensionOptions ): ExtendedCollection => { const fancyMarker = { [FANCY_COLLECTION_MARKER]: fn, }; if (options?.extends === undefined) return Object.assign(definedConfig as ExtendedCollection, fancyMarker); // Make TS not forget about type narrowing; const { extends: extendSchema } = options; const config = { ...definedConfig, schema: (context) => { const userSchema = typeof extendSchema === 'function' ? extendSchema(context) : extendSchema; const baseSchema = typeof definedConfig.schema === 'function' ? definedConfig.schema(context) : definedConfig.schema; return baseSchema === undefined ? userSchema : z.intersection(baseSchema, userSchema); }, } as ExtendedCollection; return Object.assign(config, fancyMarker); }; return Object.assign(fn, { [FANCY_COLLECTION_MARKER]: true, }); } const FANCY_COLLECTION_MARKER = Symbol('@inox-tools/content-utils/fancyCollection'); type DerivedCollection = { [FANCY_COLLECTION_MARKER]: FancyCollection; }; function isDerivedCollection(something: any): something is DerivedCollection { return typeof something[FANCY_COLLECTION_MARKER] === 'function'; } /** * Guard checking that a value is a FancyCollection. */ export function isFancyCollection(something: any): something is FancyCollection { return something[FANCY_COLLECTION_MARKER] === true; } /** * Extract the original FancyCollection from a value, if it was derived from one. * * If the value was not derived from a FancyCollection, return null; */ export function tryGetOriginalFancyCollection(something: any): FancyCollection | null { return isDerivedCollection(something) ? something[FANCY_COLLECTION_MARKER] : null; }