diff --git a/.changeset/preserve-openapi-raw-json.md b/.changeset/preserve-openapi-raw-json.md new file mode 100644 index 00000000000..8718904d1c6 --- /dev/null +++ b/.changeset/preserve-openapi-raw-json.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +Preserve `JSON.rawJSON` values when cloning cached OpenAPI specs. diff --git a/packages/effect/src/unstable/httpapi/OpenApi.ts b/packages/effect/src/unstable/httpapi/OpenApi.ts index c7ff5bff44f..e6291722dc9 100644 --- a/packages/effect/src/unstable/httpapi/OpenApi.ts +++ b/packages/effect/src/unstable/httpapi/OpenApi.ts @@ -227,11 +227,15 @@ const compileSchemas: CompileSchemas = (asts) => ) ) +const jsonWithRawJSON = JSON as unknown as { isRawJSON?: (value: unknown) => boolean } + +const isJsonRawJSON = (value: unknown): boolean => jsonWithRawJSON.isRawJSON?.(value) === true + const cloneOpenAPISpec = (value: A): A => { if (Array.isArray(value)) { return value.map(cloneOpenAPISpec) as A } - if (value !== null && typeof value === "object") { + if (value !== null && typeof value === "object" && !isJsonRawJSON(value)) { const out: Record = {} for (const key of Object.keys(value)) { InternalRecord.assignProperty(out, key, cloneOpenAPISpec((value as Record)[key])) diff --git a/packages/effect/test/unstable/httpapi/OpenApi.test.ts b/packages/effect/test/unstable/httpapi/OpenApi.test.ts index c0de5e47d22..872730a8433 100644 --- a/packages/effect/test/unstable/httpapi/OpenApi.test.ts +++ b/packages/effect/test/unstable/httpapi/OpenApi.test.ts @@ -97,6 +97,22 @@ describe("OpenApi", () => { assert.isUndefined(third.paths["/resource"]!.get!.summary) }) + it("preserves JSON.rawJSON values when cloning cached specs", () => { + const rawJson = (JSON as unknown as { rawJSON: (value: string) => unknown }).rawJSON("9223372036854775807") + const Api = HttpApi.make("Api").annotate(OpenApi.Transform, (spec) => ({ + ...spec, + info: { + ...spec.info, + "x-raw": rawJson + } + })) + + const expected = `{"title":"Api","version":"0.0.1","x-raw":9223372036854775807}` + + assert.strictEqual(JSON.stringify(OpenApi.fromApi(Api).info), expected) + assert.strictEqual(JSON.stringify(OpenApi.fromApi(Api).info), expected) + }) + it("isolates the cached spec from external override mutations", () => { const info = { title: "Api", version: "1.0.0" } const Api = HttpApi.make("Api").annotate(OpenApi.Override, { info })