import { toHtml } from 'hast-util-to-html' import { fromMarkdown } from 'mdast-util-from-markdown' import { mdxFromMarkdown } from 'mdast-util-mdx' import { toHast } from 'mdast-util-to-hast' import { mdxjs } from 'micromark-extension-mdxjs' import { notFound } from 'next/navigation' import { visit } from 'unist-util-visit' import { REFERENCES } from '~/content/navigation.references' import { getFlattenedSections, getFunctionsList, getTypeSpec, } from '~/features/docs/Reference.generated.singleton' import { getRefMarkdown } from '~/features/docs/Reference.mdx' import type { MethodTypes } from '~/features/docs/Reference.typeSpec' import type { AbbrevApiReferenceSection } from '~/features/docs/Reference.utils' import { BASE_PATH } from '~/lib/constants' export async function GET(request: Request) { const url = new URL(request.url) let [, , lib, maybeVersion, slug] = url.pathname.split('/') const libraryMeta = REFERENCES[lib] const isVersion = /^v\d+$/.test(maybeVersion) const version = isVersion ? maybeVersion : libraryMeta.versions[0] if (!isVersion) { slug = maybeVersion } let section: AbbrevApiReferenceSection | undefined let sectionsWithUrl: Array = [] try { const flattenedSections = (await getFlattenedSections(lib, version)) ?? [] sectionsWithUrl = flattenedSections.map((section) => { const url = new URL(request.url) url.pathname = [BASE_PATH, 'reference', lib, isVersion ? version : null, section.slug] .filter(Boolean) .join('/') return { ...section, url, } }) section = flattenedSections.find( (section) => (section.type === 'markdown' || section.type === 'function') && section.slug === slug ) } catch {} if (!section) { notFound() } const html = htmlShell( lib, isVersion ? version : null, slug, section, libraryNav(sectionsWithUrl) + (await sectionDetails(lib, isVersion ? version : null, section)) ) const response = new Response(html) response.headers.set('Content-Type', 'text/html; charset=utf-8') return response } function htmlShell( lib: string, version: string | null, slug: string, section: AbbrevApiReferenceSection, body: string ) { const libraryName = REFERENCES[lib].name let title = libraryName + ': ' + (section.title ?? '') return ( '' + '' + `${title} | Supabase Docs` + `` + `` + `` + `` + '' + '' + body + '' ) } function libraryNav(sections: Array) { return ( '' + sections .map((section) => `${section.title ?? ''}`) .join('') + '' ) } async function sectionDetails(lib: string, version: string, section: AbbrevApiReferenceSection) { const libraryName = REFERENCES[lib].name let result = '' + (libraryName + ': ' + (section.title ?? '')) + '' if (section.type === 'markdown') { result += await markdown(lib, version, section) } else { result += await functionDetails(lib, version, section) } return result } async function markdown(lib: string, version: string | null, section: AbbrevApiReferenceSection) { const dir = !!section.meta?.shared ? 'shared' : lib + (version ? '/' + version : '') let content = await getRefMarkdown(dir + '/' + section.slug) content = mdxToHtml(content) return content } async function functionDetails( lib: string, version: string | null, section: AbbrevApiReferenceSection ) { const libraryMeta = REFERENCES[lib] const fns = await getFunctionsList(lib, version ?? libraryMeta.versions[0]) const fn = fns!.find((fn) => fn.id === section.id) if (!fn) return '' let types: MethodTypes | undefined if (libraryMeta.typeSpec && '$ref' in fn) { types = await getTypeSpec(fn['$ref'] as string) } const fullDescription = [ types?.comment?.shortText, 'description' in fn && (fn.description as string), 'notes' in fn && (fn.notes as string), ] .filter((x) => typeof x === 'string') .map(mdxToHtml) .join('') const parameters = parametersToHtml(fn, types) const examples = examplesToHtml(fn) return fullDescription + parameters + examples } function mdxToHtml(markdown: string): string { const mdast = fromMarkdown(markdown, { extensions: [mdxjs()], mdastExtensions: [mdxFromMarkdown()], }) visit(mdast, 'text', (node) => { node.value = node.value.replace(/\n/g, ' ') }) if (!mdast) return '' const hast = toHast(mdast) if (!hast) return '' // @ts-ignore const html = toHtml(hast) return html } function parametersToHtml(fn: any, types: MethodTypes | undefined) { let result = 'Parameters' if ('overwriteParams' in fn || 'params' in fn) { const params = fn.overwriteParams ?? fn.params if (params.length === 0) return '' result += '' + params .map( (param) => '' + `${param.name}` + `${param.isOptional ? '(Optional)' : '(Required)'}` + `${param.description}` + '' ) .join('') + '' return result } if (!types?.params || types.params.length === 0) return '' result += '' + types.params .map( (param) => '' + `${String(param.name)}` + `${param.isOptional ? '(Optional)' : '(Required)'}` + `${param.comment?.shortText ?? ''}` + '' ) .join('') + '' return result } function examplesToHtml(fn: any) { if (!fn.examples || fn.examples.length === 0) return '' let result = 'Examples' result += fn.examples .map((example) => `${example.name ?? ''}` + mdxToHtml(example.code ?? '')) .join('') return result }
${param.description}
${param.comment?.shortText ?? ''}