mirror of
https://github.com/Drop-OSS/drop-api-autogen.git
synced 2026-01-30 20:55:17 +01:00
158 lines
3.8 KiB
TypeScript
158 lines
3.8 KiB
TypeScript
import * as ts from "typescript";
|
|
import type { Route, RouteMetadata } from ".";
|
|
import prettier from "prettier";
|
|
|
|
function encouragePrettierLinebreaks(rawType: string) {
|
|
return rawType.startsWith("{")
|
|
? rawType.slice(0, 1) + "\n" + rawType.slice(1)
|
|
: rawType;
|
|
}
|
|
|
|
async function renderType(metadata: RouteMetadata, type: ts.Type) {
|
|
const expandedType = metadata.checker.typeToTypeNode(
|
|
type,
|
|
metadata.sourceFile,
|
|
ts.NodeBuilderFlags.NoTruncation | ts.NodeBuilderFlags.InTypeAlias
|
|
);
|
|
|
|
const rawType = metadata.checker.typeToString(
|
|
type,
|
|
undefined,
|
|
ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.InTypeAlias
|
|
);
|
|
|
|
const newLinedType = encouragePrettierLinebreaks(rawType);
|
|
const pretty = await prettier.format(`type Body = ${newLinedType}`, {
|
|
parser: "typescript",
|
|
});
|
|
|
|
return pretty;
|
|
}
|
|
|
|
export default async function generateDocsPage(
|
|
route: Route,
|
|
metadata: RouteMetadata
|
|
) {
|
|
// ===== Body =====
|
|
let bodyText = "";
|
|
if (metadata.body) {
|
|
bodyText = `
|
|
## Request Body
|
|
|
|
${metadata.bodyComment ?? ""}
|
|
|
|
Request type: \`application/json\`. Body type (TypeScript definition):
|
|
|
|
|
|
`.trimStart();
|
|
bodyText += "```typescript\n";
|
|
|
|
bodyText += await renderType(metadata, metadata.body);
|
|
bodyText += "\n```";
|
|
} else if (metadata.bodyComment) {
|
|
bodyText = `
|
|
## Request Body
|
|
|
|
${metadata.bodyComment ?? ""}`;
|
|
}
|
|
|
|
// ===== Route Params =====
|
|
let paramTable = "";
|
|
if (metadata.routeParams) {
|
|
paramTable =
|
|
"## Route Parameters \n\n| Name | Type | About |\n| ---- | ---- | ---- |\n";
|
|
for (const [name, data] of Object.entries(metadata.routeParams)) {
|
|
paramTable += `| ${name} | ${data.type} | ${data.comment}`;
|
|
}
|
|
}
|
|
|
|
let queryTable = "";
|
|
if (metadata.query) {
|
|
const queryProperties = metadata.query.getProperties();
|
|
if (queryProperties.length > 0) {
|
|
queryTable =
|
|
"## Query Parameters\n\n| Name | Parser |\n| ---- | ---- |\n";
|
|
for (const property of queryProperties) {
|
|
queryTable += `| ${property.escapedName} | ${property.declarations?.at(0)?.getLastToken()?.getText()?.slice(1, -1) ?? "string"} |\n`;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ===== ACLs =====
|
|
let routeAuthentication = "";
|
|
if (metadata.acls && metadata.acls.length > 0) {
|
|
routeAuthentication = `
|
|
|
|
Any of the following ACLs on a \`${metadata.aclMode}\` token are required to access this route:
|
|
${metadata.acls.map((e) => ` - \`${e}\``).join("\n")}
|
|
|
|
`.trimStart();
|
|
}
|
|
// If ACL is checked, but no specific ones are required
|
|
// Means authenticated, but only sessions
|
|
else if (metadata.acls) {
|
|
routeAuthentication = `Only \`${metadata.aclMode}\` **sessions** can access this route, not API tokens.`;
|
|
}
|
|
|
|
// ===== Client Warning =====
|
|
let clientWarning = "";
|
|
if (metadata.clientRoute) {
|
|
clientWarning =
|
|
"**This is a client route. It is not accessible through API tokens.**";
|
|
}
|
|
|
|
// ===== Response ======
|
|
let responseText = "";
|
|
if (metadata.response) {
|
|
responseText = `
|
|
## Response Body
|
|
|
|
${metadata.responseComment ?? ""}
|
|
|
|
${metadata.responseTag ? `This endpoint returns '${metadata.responseTag}'` : ""}
|
|
|
|
Response definition:
|
|
|
|
`.trimStart();
|
|
responseText += "```typescript\n";
|
|
|
|
responseText += await renderType(metadata, metadata.response);
|
|
responseText += "\n```";
|
|
} else if (metadata.responseComment) {
|
|
responseText = `
|
|
## Response Body
|
|
${metadata.responseComment}`.trim();
|
|
}
|
|
|
|
const deprecatedElement = `::deprecated\n::`;
|
|
|
|
const rawText = `
|
|
---
|
|
metaUrl: ${route.urlPath}
|
|
---
|
|
# ${route.method} \`${route.urlPath}\`
|
|
|
|
${metadata.deprecated ? deprecatedElement : ""}
|
|
|
|
## About this route
|
|
${metadata.routeDescription ?? "*No description provided.*"}
|
|
|
|
${routeAuthentication}
|
|
|
|
${clientWarning}
|
|
|
|
${queryTable}
|
|
|
|
${paramTable}
|
|
|
|
${bodyText}
|
|
|
|
${responseText}
|
|
|
|
`;
|
|
|
|
// Just for my sanity
|
|
const formatted = await prettier.format(rawText, { parser: "markdown" });
|
|
return formatted;
|
|
}
|