diff --git a/apps/example-todo-app/tests/openapi-generation/openapi-generation.test.ts b/apps/example-todo-app/tests/openapi-generation/openapi-generation.test.ts index 6d4fd92ed..68c14adde 100644 --- a/apps/example-todo-app/tests/openapi-generation/openapi-generation.test.ts +++ b/apps/example-todo-app/tests/openapi-generation/openapi-generation.test.ts @@ -78,7 +78,7 @@ test("generateOpenAPI correctly parses description with front matter", async (t) routeSpec.description.trim(), "This endpoint allows you to add a new todo item to the list. Deprecated." ) - t.is(routeSpec.deprecated, "Use foobar instead.") + t.is(routeSpec['x-deprecated'], "Use foobar instead.") t.is(routeSpec["x-fern-sdk-return-value"], "foobar") - t.is(routeSpec.response_key, "foobar") + t.is(routeSpec["x-response-key"], "foobar") }) diff --git a/packages/nextlove/src/generators/generate-openapi/index.ts b/packages/nextlove/src/generators/generate-openapi/index.ts index 406536749..c356489d7 100644 --- a/packages/nextlove/src/generators/generate-openapi/index.ts +++ b/packages/nextlove/src/generators/generate-openapi/index.ts @@ -12,6 +12,7 @@ import { embedSchemaReferences } from "./embed-schema-references" import { mapMethodsToFernSdkMetadata } from "./fern-sdk-utils" import { parseFrontMatter, testFrontMatter } from "../lib/front-matter" import dedent from "dedent" +import { prefixKeysWithX } from "../utils/prefix-keys-with-x" function replaceFirstCharToLowercase(str: string) { if (str.length === 0) { @@ -210,9 +211,15 @@ export async function generateOpenAPI(opts: GenerateOpenAPIOpts) { } } + const formattedDescriptionMetadata = Object.fromEntries( + Object.entries(prefixKeysWithX(descriptionMetadata)).map( + ([key, value]) => [key.replace(/_/g, "-"), value] + ) + ) + const route: OperationObject = { ...routeSpec.openApiMetadata, - ...descriptionMetadata, + ...formattedDescriptionMetadata, summary: routePath, ...(description && { description }), responses: { diff --git a/packages/nextlove/src/generators/lib/zod-openapi.ts b/packages/nextlove/src/generators/lib/zod-openapi.ts index 3ccd7c24f..9187d2291 100644 --- a/packages/nextlove/src/generators/lib/zod-openapi.ts +++ b/packages/nextlove/src/generators/lib/zod-openapi.ts @@ -31,6 +31,7 @@ import merge from "ts-deepmerge" import { AnyZodObject, z, ZodTypeAny } from "zod" import { parseFrontMatter, testFrontMatter } from "./front-matter" import dedent from "dedent" +import { prefixKeysWithX } from "../utils/prefix-keys-with-x" type AnatineSchemaObject = SchemaObject & { hideDefinitions?: string[] } @@ -81,16 +82,16 @@ function parseDescription(zodRef: OpenApiZodAny): SchemaObject { if (!testFrontMatter(trimmedDescription)) return { description: zodRef.description } const { attributes, body } = parseFrontMatter(trimmedDescription) - const output: SchemaObject = {} + let output: SchemaObject = {} if (body.trim()) output.description = body.trim() if (typeof attributes === "object" && attributes !== null) { if ("deprecated" in attributes && attributes.deprecated) { output.deprecated = true } - for (const [key, value] of Object.entries(attributes)) { - output[`x-${key}`] = value - } + + output = prefixKeysWithX(output) } + return output } diff --git a/packages/nextlove/src/generators/utils/prefix-keys-with-x.ts b/packages/nextlove/src/generators/utils/prefix-keys-with-x.ts new file mode 100644 index 000000000..1e947fe5d --- /dev/null +++ b/packages/nextlove/src/generators/utils/prefix-keys-with-x.ts @@ -0,0 +1,9 @@ +type PrefixedObject = { + [K in keyof T as `x-${string & K}`]: T[K] +} + +export function prefixKeysWithX(obj: T): PrefixedObject { + return Object.fromEntries( + Object.entries(obj).map(([key, value]) => [`x-${key}`, value]) + ) as PrefixedObject +}