mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 09:55:06 +03:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Include the v2 mgmt API spec in the official docs. This PR merges the v1 and v2 specs when generating the reference, with v2 taking precedence on conflicts. Fixes API-1215 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Docs now include API v2 reference: log-drain management (list/create/update/delete) and project transfer (preview/transfer). * **Documentation** * Generated API reference now merges v1 and v2 specs so both appear in the docs and section listings. * New v2 operations added to Analytics and Projects documentation sections. * **Chores** * Docs generation pipeline updated to accept and process multiple API spec inputs. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
import fs from 'fs'
|
|
import path from 'path'
|
|
|
|
function slugToTitle(slug) {
|
|
if (!slug) return ''
|
|
const prefixRegex = /^v\d+/
|
|
const title = slug.replace(prefixRegex, '').replace(/-/g, ' ').trimStart()
|
|
return title.charAt(0).toUpperCase() + title.slice(1)
|
|
}
|
|
|
|
function isValidSlug(slug) {
|
|
const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/
|
|
return slugRegex.test(slug)
|
|
}
|
|
|
|
function readJson(filePath: string) {
|
|
return JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
|
}
|
|
|
|
function extractSectionsFromOpenApi(filePaths: string[], outputPath: string) {
|
|
try {
|
|
// Merge paths from all specs, later specs override earlier ones on conflict
|
|
const mergedPaths = Object.assign({}, ...filePaths.map((p) => readJson(p).paths ?? {}))
|
|
|
|
const categories: string[] = []
|
|
const sections: Array<{
|
|
type: string
|
|
title: string
|
|
id?: string
|
|
slug?: string
|
|
items: Array<{
|
|
type: string
|
|
title: string
|
|
id: string
|
|
slug: string
|
|
}>
|
|
}> = []
|
|
|
|
for (const route in mergedPaths) {
|
|
const methods = mergedPaths[route]
|
|
for (const method in methods) {
|
|
if (methods[method]['x-internal']) {
|
|
continue
|
|
}
|
|
const tag = methods[method].tags?.[0]
|
|
const operationId = methods[method].operationId
|
|
if (!tag || !isValidSlug(operationId)) continue
|
|
if (!categories.includes(tag)) {
|
|
categories.push(tag)
|
|
sections.push({
|
|
type: 'category',
|
|
title: tag,
|
|
items: [],
|
|
})
|
|
}
|
|
const sectionCate = sections.find((i) => i.title === tag)
|
|
sectionCate?.items.push({
|
|
id: operationId,
|
|
title: slugToTitle(operationId),
|
|
slug: operationId,
|
|
type: 'operation',
|
|
})
|
|
}
|
|
}
|
|
|
|
sections.sort((a, b) => a.title.localeCompare(b.title))
|
|
sections.forEach((i) => i.items.sort((a, b) => a.title.localeCompare(b.title)))
|
|
sections.unshift({
|
|
title: 'Introduction',
|
|
id: 'introduction',
|
|
slug: 'introduction',
|
|
type: 'markdown',
|
|
items: [],
|
|
})
|
|
|
|
fs.writeFileSync(outputPath, JSON.stringify(sections, null, 2), 'utf8')
|
|
console.log(`Sections successfully generated!!!`)
|
|
} catch (error) {
|
|
console.error('Error:', error)
|
|
}
|
|
}
|
|
|
|
const args = process.argv.slice(2)
|
|
if (args.length < 2) {
|
|
console.error(
|
|
'Please provide at least one openapi file path and an output file path as arguments.'
|
|
)
|
|
process.exit(1)
|
|
}
|
|
|
|
// Last arg is output, everything before is input files
|
|
const outputFilePath = path.resolve(args[args.length - 1])
|
|
const inputFilePaths = args.slice(0, -1).map((p) => path.resolve(p))
|
|
|
|
extractSectionsFromOpenApi(inputFilePaths, outputFilePath)
|