|
1 | | -import { readFileSync } from 'node:fs' |
| 1 | +import { existsSync, readFileSync } from 'node:fs' |
2 | 2 | import { glob } from 'node:fs/promises' |
3 | 3 | import { basename, dirname, relative, resolve } from 'node:path' |
4 | 4 | import { fileURLToPath } from 'node:url' |
5 | 5 |
|
6 | 6 | // Types |
| 7 | +import type { ApiData } from './generate-api' |
7 | 8 | import type { Plugin, ViteDevServer } from 'vite' |
8 | 9 |
|
9 | 10 | import { getApiNamesGrouped, toKebab } from './api-names' |
@@ -96,33 +97,88 @@ function getTitleFromPath (filePath: string): string { |
96 | 97 | .join(' ') |
97 | 98 | } |
98 | 99 |
|
| 100 | +const API_CACHE_FILE = resolve(__dirname, '../node_modules/.cache/api-cache.json') |
| 101 | + |
| 102 | +function loadApiData (): ApiData | null { |
| 103 | + if (!existsSync(API_CACHE_FILE)) return null |
| 104 | + try { |
| 105 | + return JSON.parse(readFileSync(API_CACHE_FILE, 'utf8')) as ApiData |
| 106 | + } catch { |
| 107 | + return null |
| 108 | + } |
| 109 | +} |
| 110 | + |
99 | 111 | async function generateApiSearchDocuments (startId: number): Promise<SearchDocument[]> { |
100 | 112 | const documents: SearchDocument[] = [] |
101 | 113 | const apiNames = await getApiNamesGrouped() |
| 114 | + const apiData = loadApiData() |
102 | 115 | let id = startId |
103 | 116 |
|
104 | 117 | // Add component API documents |
105 | 118 | for (const comp of apiNames.components) { |
| 119 | + const apiPath = `/api/${toKebab(comp.name)}` |
| 120 | + |
106 | 121 | documents.push({ |
107 | 122 | id: String(id++), |
108 | 123 | title: `${comp.name} API`, |
109 | 124 | category: 'API', |
110 | | - path: `/api/${toKebab(comp.name)}`, |
| 125 | + path: apiPath, |
111 | 126 | headings: ['Props', 'Events', 'Slots'], |
112 | 127 | content: `API reference for ${comp.name} component. Props, events, and slots documentation.`, |
113 | 128 | }) |
| 129 | + |
| 130 | + // Add individual entries for each sub-component (e.g. Dialog.Root, Dialog.Content) |
| 131 | + if (apiData) { |
| 132 | + for (const [name, api] of Object.entries(apiData.components)) { |
| 133 | + if (!name.startsWith(`${comp.name}.`)) continue |
| 134 | + |
| 135 | + documents.push({ |
| 136 | + id: String(id++), |
| 137 | + title: `${name} API`, |
| 138 | + category: 'API', |
| 139 | + path: apiPath, |
| 140 | + headings: ['Props', 'Events', 'Slots'], |
| 141 | + content: [ |
| 142 | + ...api.props.map(p => p.name), |
| 143 | + ...api.events.map(e => e.name), |
| 144 | + ...api.slots.map(s => s.name), |
| 145 | + ].join(' '), |
| 146 | + }) |
| 147 | + } |
| 148 | + } |
114 | 149 | } |
115 | 150 |
|
116 | 151 | // Add composable API documents |
117 | 152 | for (const comp of apiNames.composables) { |
| 153 | + const apiPath = `/api/${toKebab(comp.name)}` |
| 154 | + |
118 | 155 | documents.push({ |
119 | 156 | id: String(id++), |
120 | 157 | title: `${comp.name} API`, |
121 | 158 | category: 'API', |
122 | | - path: `/api/${toKebab(comp.name)}`, |
| 159 | + path: apiPath, |
123 | 160 | headings: ['Options', 'Properties', 'Methods'], |
124 | 161 | content: `API reference for ${comp.name} composable. Options, properties, and methods documentation.`, |
125 | 162 | }) |
| 163 | + |
| 164 | + // Add individual entries for each exported function (e.g. createTimelineContext → createTimeline API) |
| 165 | + if (apiData) { |
| 166 | + const api = apiData.composables[comp.name] |
| 167 | + if (api) { |
| 168 | + for (const fn of api.functions) { |
| 169 | + if (fn.name === comp.name) continue |
| 170 | + |
| 171 | + documents.push({ |
| 172 | + id: String(id++), |
| 173 | + title: `${fn.name} API`, |
| 174 | + category: 'API', |
| 175 | + path: apiPath, |
| 176 | + headings: ['Options', 'Properties', 'Methods'], |
| 177 | + content: fn.description ?? '', |
| 178 | + }) |
| 179 | + } |
| 180 | + } |
| 181 | + } |
126 | 182 | } |
127 | 183 |
|
128 | 184 | return documents |
|
0 commit comments