1+ import type { APIRoute , GetStaticPaths } from 'astro'
2+ import type { CollectionEntry , CollectionKey } from 'astro:content'
3+ import { getCollection } from 'astro:content'
4+ import { readFile } from 'fs/promises'
5+ import { resolve } from 'path'
6+ import { content } from '../../../../../../../content'
7+ import { kebabCase , getDefaultTab , addDemosOrDeprecated } from '../../../../../../../utils'
8+ import { createJsonResponse , createTextResponse , createIndexKey } from '../../../../../../../utils/apiHelpers'
9+ import { generateAndWriteApiIndex } from '../../../../../../../utils/apiIndex/generate'
10+
11+ export const prerender = true
12+
13+ export const getStaticPaths : GetStaticPaths = async ( ) => {
14+ // Generate index file (will be cached if already generated)
15+ const index = await generateAndWriteApiIndex ( )
16+
17+ const paths : {
18+ params : {
19+ version : string
20+ section : string
21+ page : string
22+ tab : string
23+ example : string
24+ }
25+ } [ ] = [ ]
26+
27+ // Build paths from index structure
28+ for ( const version of index . versions ) {
29+ for ( const section of index . sections [ version ] || [ ] ) {
30+ const sectionKey = createIndexKey ( version , section )
31+ for ( const page of index . pages [ sectionKey ] || [ ] ) {
32+ const pageKey = createIndexKey ( version , section , page )
33+ for ( const tab of index . tabs [ pageKey ] || [ ] ) {
34+ const tabKey = createIndexKey ( version , section , page , tab )
35+
36+ // Get all examples for this tab
37+ const examples = index . examples [ tabKey ] || [ ]
38+ for ( const example of examples ) {
39+ paths . push ( {
40+ params : {
41+ version,
42+ section,
43+ page,
44+ tab,
45+ example : example . exampleName ,
46+ } ,
47+ } )
48+ }
49+ }
50+ }
51+ }
52+ }
53+
54+ return paths
55+ }
56+
57+ function getImports ( fileContent : string ) {
58+ const importRegex = / i m p o r t .* f r o m .* [ ' " ] \. .* \/ [ \w \. \? ] * [ ' " ] / gm
59+ const matches = fileContent . match ( importRegex )
60+ return matches
61+ }
62+
63+ function getExampleFilePath ( imports : string [ ] , exampleName : string ) {
64+ const exampleImport = imports . find ( ( imp ) => imp . includes ( exampleName ) )
65+ if ( ! exampleImport ) {
66+ console . error ( 'No import path found for example' , exampleName )
67+ return null
68+ }
69+ const match = exampleImport . match ( / [ ' " ] \. .* \/ [ \w \. ] * \? / )
70+ if ( ! match ) {
71+ return null
72+ }
73+ return match [ 0 ] . replace ( / [ ' " ? ] / g, '' )
74+ }
75+
76+ async function getCollections ( version : string ) {
77+ const collectionsToFetch = content
78+ . filter ( ( entry ) => entry . version === version )
79+ . map ( ( entry ) => entry . name as CollectionKey )
80+ const collections = await Promise . all (
81+ collectionsToFetch . map ( async ( name ) => await getCollection ( name ) ) ,
82+ )
83+ return collections . flat ( ) . map ( ( { data, filePath, ...rest } ) => ( {
84+ filePath,
85+ ...rest ,
86+ data : {
87+ ...data ,
88+ tab : data . tab || data . source || getDefaultTab ( filePath ) ,
89+ } ,
90+ } ) )
91+ }
92+
93+ async function getContentEntryFilePath ( collections : CollectionEntry < 'core-docs' | 'quickstarts-docs' | 'react-component-docs' > [ ] , section : string , page : string , tab : string ) {
94+ const contentEntry = collections . find ( ( entry ) => entry . data . section === section && kebabCase ( entry . data . id ) === page && entry . data . tab === tab )
95+ if ( ! contentEntry ) {
96+ console . error ( 'No content entry found for section' , section , 'page' , page , 'tab' , tab )
97+ return null
98+ }
99+ if ( typeof contentEntry . filePath !== 'string' ) {
100+ console . error ( 'No file path found for content entry' , contentEntry . id )
101+ return null
102+ }
103+ return contentEntry . filePath
104+ }
105+
106+ export const GET : APIRoute = async ( { params } ) => {
107+ const { version, section, page, tab, example } = params
108+ if ( ! version || ! section || ! page || ! tab || ! example ) {
109+ return createJsonResponse ( { error : 'Version, section, page, tab, and example parameters are required' } , 400 )
110+ }
111+
112+ const collections = await getCollections ( version )
113+ const contentEntryFilePath = await getContentEntryFilePath ( collections , section , page , tab )
114+
115+ if ( ! contentEntryFilePath ) {
116+ return createJsonResponse ( { error : 'Content entry not found' } , 404 )
117+ }
118+
119+ const contentEntryFileContent = await readFile ( contentEntryFilePath , 'utf8' )
120+
121+ const contentEntryImports = getImports ( contentEntryFileContent )
122+ if ( ! contentEntryImports ) {
123+ return createJsonResponse ( { error : 'Content entry imports not found' } , 404 )
124+ }
125+
126+ const relativeExampleFilePath = getExampleFilePath ( contentEntryImports , example )
127+ if ( ! relativeExampleFilePath ) {
128+ return createJsonResponse ( { error : 'Example file path not found' } , 404 )
129+ }
130+
131+ const absoluteExampleFilePath = resolve ( contentEntryFilePath , '../' , relativeExampleFilePath )
132+ const exampleFileContent = await readFile ( absoluteExampleFilePath , 'utf8' )
133+
134+ return createTextResponse ( exampleFileContent )
135+ }
0 commit comments