generated from avior/template-web-astro
118 lines
2.9 KiB
TypeScript
118 lines
2.9 KiB
TypeScript
import { objectMap, objectRemap } from '@dzeio/object-util'
|
|
import type { AstroIntegration } from 'astro'
|
|
import fs from 'fs/promises'
|
|
|
|
interface Config {
|
|
output?: string
|
|
}
|
|
|
|
/**
|
|
* get every files recursivelly in a specific directory
|
|
*
|
|
* @param path the path to search
|
|
* @returns the list of files recursivelly in the specific directory
|
|
*/
|
|
async function getFiles(path: string): Promise<Array<string>> {
|
|
path = decodeURI(path)
|
|
try {
|
|
const dir = await fs.readdir(path)
|
|
let files: Array<string> = []
|
|
for (const file of dir) {
|
|
if (file.startsWith('_')) {
|
|
continue
|
|
}
|
|
const filePath = path + '/' + file
|
|
if ((await fs.stat(filePath)).isDirectory()) {
|
|
files = files.concat(await getFiles(filePath))
|
|
} else if (file.endsWith('.ts')) {
|
|
files.push(filePath)
|
|
}
|
|
}
|
|
return files
|
|
} catch {
|
|
return []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* format the path back to an url usable by the app
|
|
*
|
|
* @param path the path to format
|
|
* @returns the path formatted as a URL
|
|
*/
|
|
function formatPath(basePath: string, path: string): string {
|
|
// remove the base path
|
|
path = path.replace(decodeURI(basePath), '')
|
|
|
|
// handle the `/` endpoint
|
|
if (path === '') {
|
|
path = '/'
|
|
}
|
|
|
|
return path
|
|
}
|
|
|
|
async function run(config?: Config) {
|
|
|
|
// get the files list
|
|
const files = await getFiles('./src/pages/api').then((ev) => ev.map((it) => formatPath('./src/pages/api', it)))
|
|
|
|
const methods = ['GET', 'POST', 'DELETE']
|
|
|
|
let content = ''
|
|
const items: Record<string, Record<string, string>> = {}
|
|
for (const entry of files) {
|
|
const file = await fs.readFile('./src/pages/api' + entry, 'utf-8')
|
|
const availableMethods: Array<string> = []
|
|
for (const method of methods) {
|
|
if (file.includes(method)) {
|
|
availableMethods.push(method)
|
|
}
|
|
}
|
|
if (availableMethods.length === 0) {
|
|
continue
|
|
}
|
|
const prefix = entry.replace(/[/.[\]-]/g, '')
|
|
content += `import type { ${availableMethods.map((it) => `${it} as ${prefix}${it}`).join((', '))} } from './pages/api${entry}'\n`
|
|
|
|
|
|
let path = entry
|
|
// remove the extension if asked
|
|
const lastDot = path.lastIndexOf('.')
|
|
path = path.slice(0, lastDot)
|
|
|
|
// remove the index from the element
|
|
if (path.endsWith('/index')) {
|
|
path = path.replace('/index', '')
|
|
}
|
|
|
|
items[path] = {
|
|
...objectRemap(availableMethods, (value) => ({ key: value as string, value: `${prefix}${value as string}` }))
|
|
}
|
|
}
|
|
|
|
content += `\ninterface APIRoutes {
|
|
${objectMap(items, (record, key) => `\t'${key}': {
|
|
${objectMap(record, (value, method) => ` ${method}: typeof ${value}`).join('\n')}
|
|
}`).join('\n')}
|
|
}`
|
|
|
|
content += '\n\nexport default APIRoutes\n'
|
|
|
|
await fs.writeFile(config?.output ?? './src/api-routes.d.ts', content)
|
|
}
|
|
|
|
/**
|
|
* launch the integration
|
|
* @returns the routng integration
|
|
*/
|
|
const integration = (config?: Config): AstroIntegration => ({
|
|
name: 'routing',
|
|
hooks: {
|
|
'astro:build:setup': () => run(config),
|
|
'astro:server:setup': () => run(config)
|
|
}
|
|
})
|
|
|
|
export default integration
|