import type { Document, MDX } from 'contentlayer2/core' const isProduction = process.env.NODE_ENV === 'production' export type MDXDocument = Document & { body: MDX } export type MDXDocumentDate = MDXDocument & { date: string } export type MDXBlog = MDXDocumentDate & { tags?: string[] draft?: boolean } export type MDXAuthor = MDXDocument & { name: string } export function dateSortDesc(a: string, b: string) { if (a > b) return -1 if (a < b) return 1 return 0 } /** * Sorts a list of MDX documents by date in descending order * * @param {MDXDocumentDate[]} allBlogs * @param {string} [dateKey='date'] * @return {*} */ export function sortPosts(allBlogs: T[], dateKey: string = 'date') { return allBlogs.sort((a, b) => dateSortDesc(a[dateKey], b[dateKey])) } /** * Kept for backwards compatibility * Please use `sortPosts` instead * @deprecated * @param {MDXBlog[]} allBlogs * @return {*} */ export function sortedBlogPost(allBlogs: MDXDocumentDate[]) { return sortPosts(allBlogs) } type ConvertUndefined = OrNull<{ [K in keyof T as undefined extends T[K] ? K : never]-?: T[K] }> type OrNull = { [K in keyof T]: Exclude | null } type PickRequired = { [K in keyof T as undefined extends T[K] ? never : K]: T[K] } type ConvertPick = ConvertUndefined & PickRequired /** * A typesafe omit helper function * @example pick(content, ['title', 'description']) * * @param {Obj} obj * @param {Keys[]} keys * @return {*} {ConvertPick<{ [K in Keys]: Obj[K] }>} */ export const pick = ( obj: Obj, keys: Keys[] ): ConvertPick<{ [K in Keys]: Obj[K] }> => { return keys.reduce((acc, key) => { acc[key] = obj[key] ?? null return acc }, {} as any) } /** * A typesafe omit helper function * @example omit(content, ['body', '_raw', '_id']) * * @param {Obj} obj * @param {Keys[]} keys * @return {*} {Omit} */ export const omit = (obj: Obj, keys: Keys[]): Omit => { const result = Object.assign({}, obj) keys.forEach((key) => { delete result[key] }) return result } export type CoreContent = Omit /** * Omit body, _raw, _id from MDX document and return only the core content * * @param {T} content * @return {*} {CoreContent} */ export function coreContent(content: T): CoreContent { return omit(content, ['body', '_raw', '_id']) } /** * Omit body, _raw, _id from a list of MDX documents and returns only the core content * If `NODE_ENV` === "production", it will also filter out any documents with draft: true. * * @param {T[]} contents * @return {*} {CoreContent[]} */ export function allCoreContent(contents: T[]): CoreContent[] { if (isProduction) return contents.map((c) => coreContent(c)).filter((c) => !('draft' in c && c.draft === true)) return contents.map((c) => coreContent(c)) }