Files
medusa-store/www/apps/api-reference/app/api/algolia/route.ts
Shahed Nasser bb87db8342 docs: prep for v2 documentation (#6710)
This PR includes documentation that preps for v2 docs (but doesn't introduce new docs).

_Note: The number of file changes in the PR is due to find-and-replace within the `references` which is unavoidable. Let me know if I should move it to another PR._

## Changes

- Change Medusa version in base OAS used for v2.
- Fix to docblock generator related to not catching all path parameters.
- Added typedoc plugin that generates ER Diagrams, which will be used specifically for data model references in commerce modules.
- Changed OAS tool to output references in `www/apps/api-reference/specs-v2` directory when the `--v2` option is used.
- Added a version switcher to the API reference to switch between V1 and V2. This switcher is enabled by an environment variable, so it won't be visible/usable at the moment.
- Upgraded docusaurus to v3.0.1
- Added new Vale rules to ensure correct spelling of Medusa Admin and module names.
- Added new components to the `docs-ui` package that will be used in future documentation changes.
2024-03-18 07:47:35 +00:00

153 lines
4.5 KiB
TypeScript

import OpenAPIParser from "@readme/openapi-parser"
import algoliasearch from "algoliasearch"
import type { ExpandedDocument, Operation } from "../../../types/openapi"
import path from "path"
import getPathsOfTag from "../../../utils/get-paths-of-tag"
import getSectionId from "../../../utils/get-section-id"
import { NextResponse } from "next/server"
import { JSDOM } from "jsdom"
import getUrl from "../../../utils/get-url"
import { capitalize } from "docs-ui"
export async function GET() {
const algoliaClient = algoliasearch(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID || "",
process.env.ALGOLIA_WRITE_API_KEY || ""
)
const index = algoliaClient.initIndex(
process.env.NEXT_PUBLIC_API_ALGOLIA_INDEX_NAME || ""
)
// retrieve tags and their operations to index them
const indices: Record<string, any>[] = []
for (const area of ["store", "admin"]) {
const defaultIndexData = {
version: ["current"],
lang: "en",
_tags: ["api", area],
}
// find and parse static headers from pages
const dom = await JSDOM.fromURL(getUrl(area))
const headers = dom.window.document.querySelectorAll("h2")
headers.forEach((header) => {
if (!header.textContent) {
return
}
const objectID = getSectionId([header.textContent])
const url = getUrl(area, objectID)
indices.push({
objectID: getObjectId(area, `${objectID}-mdx-section`),
hierarchy: getHierarchy(area, [header.textContent]),
type: `content`,
content: header.textContent,
url,
url_without_variables: url,
url_without_anchor: url,
...defaultIndexData,
})
})
// find and index tag and operations
const baseSpecs = (await OpenAPIParser.parse(
path.join(process.cwd(), `specs/${area}/openapi.yaml`)
)) as ExpandedDocument
await Promise.all(
baseSpecs.tags?.map(async (tag) => {
const tagName = getSectionId([tag.name])
const url = getUrl(area, tagName)
indices.push({
objectID: getObjectId(area, tagName),
hierarchy: getHierarchy(area, [tag.name]),
type: "lvl1",
content: null,
url,
url_without_variables: url,
url_without_anchor: url,
...defaultIndexData,
})
const paths = await getPathsOfTag(tagName, area)
Object.values(paths.paths).forEach((path) => {
Object.values(path).forEach((op) => {
const operation = op as Operation
const operationName = getSectionId([
tag.name,
operation.operationId,
])
const url = getUrl(area, operationName)
indices.push({
objectID: getObjectId(area, operationName),
hierarchy: getHierarchy(area, [tag.name, operation.summary]),
type: "content",
content: operation.summary,
content_camel: operation.summary,
url,
url_without_variables: url,
url_without_anchor: url,
...defaultIndexData,
})
// index its description
const operationDescriptionId = getSectionId([
tag.name,
operation.operationId,
operation.description.substring(
0,
Math.min(20, operation.description.length)
),
])
indices.push({
objectID: getObjectId(area, operationDescriptionId),
hierarchy: getHierarchy(area, [
tag.name,
operation.summary,
operation.description,
]),
type: "content",
content: operation.description,
content_camel: operation.description,
url,
url_without_variables: url,
url_without_anchor: url,
...defaultIndexData,
})
})
})
}) || []
)
}
if (indices.length) {
await index.saveObjects(indices, {
autoGenerateObjectIDIfNotExist: true,
})
}
return NextResponse.json({
message: "done",
})
}
function getObjectId(area: string, objectName: string): string {
return `${area}_${objectName}`
}
function getHierarchy(area: string, levels: string[]): Record<string, string> {
const heirarchy: Record<string, string> = {
lvl0: `${capitalize(area)} API Reference`,
}
let counter = 1
levels.forEach((level) => {
heirarchy[`lvl${counter}`] = level
counter++
})
return heirarchy
}
export const dynamic = "force-dynamic"