openapi-ts / openapi-typescript

Generate TypeScript types from OpenAPI 3 specs

Home Page:https://openapi-ts.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Transform only transforms referenced schemas

LucaSchwan opened this issue · comments

Description

I'm using a small script with a transform function like in the example to transform schemas of type: string, format: binary to Blobs. However this only happens when it is within a schema that is referenced, not when I specify the schema in place.

Name Version
openapi-typescript ^7.0.0-next.8
Node.js 21.7.1
OS + version nixos unstable (24.05)

Reproduction

I have created this simple spec.yml, which has one post route with the schema defined in place and one with the schema in a reference.

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Schema issue
  license:
    name: MIT
    url: https://opensource.org/license/mit
servers:
  - url: something.com
paths:
  /api/file-no-schema:
    post:
      security: []
      summary: "no schema"
      operationId: noSchema
      requestBody:
        content:
          application/json:
            schema:
              type: string
              format: binary
      responses:
        200:
          description: "s3 url of the uploaded image"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FileReturn"
        400:
          description: "bad request"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        default:
          description: "unknown error"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /api/file-with-schema:
    post:
      security: []
      summary: "with schema"
      operationId: withSchema
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/File"
      responses:
        200:
          description: "s3 url of the uploaded image"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FileReturn"
        400:
          description: "bad request"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        default:
          description: "unknown error"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
components:
  schemas:
    File:
      type: string
      format: binary
    FileReturn:
      properties:
        s3Url:
          type: string
    Error:
      required:
        - code
        - message
      properties:
        code:
          type: integer
          format: int32
        message:
          type: string

and I'm transforming it with this script:

import fs from "node:fs";
import openapiTS, { astToString } from "openapi-typescript";
import ts from "typescript";

const BLOB = ts.factory.createIdentifier("Blob"); // `Blob`
const NULL = ts.factory.createLiteralTypeNode(ts.factory.createNull()); // `null`

let openapiPath = "../spec.yml";

console.log(`⌛Loading openapi schema from ${openapiPath}`);
console.log("✨Transforming binary data to file");
const ast = await openapiTS(new URL(openapiPath, import.meta.url), {
  transform(schemaObject, metadata) {
    if (schemaObject.format === "binary") {
      return schemaObject.nullable
        ? ts.factory.createUnionTypeNode([BLOB, NULL])
        : BLOB;
    }
  },
});

let contents = `/**
 * This file was auto-generated by openapi-typescript.
 * Do not make direct changes to the file.
 */

`;

contents += astToString(ast);

let path = "./generated/v1.d.ts";

console.log(`🖊️Writing schema to ${path}`);
fs.writeFileSync(path, contents);

Expected result

I'd expect the request Body of the noSchema endpoint:

...
        requestBody?: {
            content: {
                "application/json": string;
            };
        };
...

to not be of type string, but of type Blob, just like the generated type of the File schema:

...
    schemas: {
        /** Format: binary */
        File: Blob;
...

Checklist

I digged through the code a bit and I think I found where this issue comes from. Thes only place where transform is called seems to be here. This only happens if the schema object has includes the "properties", "additionalProperties", or "$defs". And then it only calls transform for for every one of those properties, while I think the transform should also be called for the schemaObject itself. I'm trying this out currently. But I'm not sure how to handle the optional yet.