fuma-nama / fumadocs

The beautiful docs framework with Next.js. Alternative to Nextra
https://fumadocs.vercel.app
MIT License
1.92k stars 116 forks source link

`@fumari/json-schema-to-typescript` cyclic reference bug #1100

Closed ndom91 closed 15 hours ago

ndom91 commented 4 days ago

To Reproduce

Since issues are disabled on fuma-nama/json-schema-to-typescript, I'll post this here.

I'm having a similar issues to here with fumadocs-openapi@5.5.10.

The resulting OpenAPI JSON fails to be parsed and results in a maximum call stack size exceeded error when there are cyclic references like the one below:

"Butler_API_Entities_Project": {
  "type": "object",
  "properties": {
    "slug": {
      "type": "string"
    },
    "owner": {
      "type": "string"
    },
    "parent_project": {
      "$ref": "#/components/schemas/Butler_API_Entities_Project"
    },
    "name": {
      "type": "string",
      "description": "Project Name"
    },
  },
}

As you can see the parent_project property doesn't have any other fields, but the cyclic reference still rbeaks the build with the "max call stack size exceeded" error :thinking:

I'm using:

"fumadocs-core": "14.4.0",
"fumadocs-mdx": "11.1.1",
"fumadocs-openapi": "^5.5.10",
"fumadocs-twoslash": "^2.0.1",
"fumadocs-ui": "14.4.0",

There is a simliar issue in the parent repository to your fork that yuo might be aware of here.

Current vs. Expected behavior

Parse openapi spec JSON successfully

Provide environment information

Node.js v22.10.0

Operating System:
  Platform: linux
  Arch: x64
  Version: #1-NixOS SMP PREEMPT_DYNAMIC Fri Nov  1 01:02:44 UTC 2024
  Available memory (MB): 32026
  Available CPU cores: 12
Binaries:
  Node: 22.10.0
  npm: 10.9.0
  Yarn: N/A
  pnpm: 9.3.0
Relevant Packages:
  next: 15.0.3 // Latest available version is detected (15.0.3).
  eslint-config-next: N/A
  react: 18.3.1
  react-dom: 18.3.1
  typescript: N/A
Next.js Config:
  output: N/A

I've worked around it so far by just dropping self-referencing properties in the effected entities before passing the json file to fumadocs-openapi's generateFiles as input.

delete swaggerContent.components.schemas.Butler_API_Entities_Project.properties.parentProject

Which area(s) are affected? (Select all that apply)

Integrations (e.g OpenAPI, Typescript DocsGen)

Additional context

No response

fuma-nama commented 4 days ago

Didn't have much time to work on the fork, I will look into that later.

fuma-nama commented 3 days ago

Also if you don't mind, you can disable it as a temporary fix:

export const openapi = createOpenAPI({
  generateTypeScriptSchema: false,
});

As the linked issue said

fuma-nama commented 2 days ago

I cannot seem to reproduce the problem, make sure to upgrade to 5.7.4 and provide more details (e.g. the OpenAPI schema or a GitHub repo)

image

fuma-nama commented 2 days ago

Note it could also be a problem when sampling an example response.

For example, if you made parent_project a required field, it will be forced to create parent_project for every new sampled parent_project, causing a similar problem. In this case, it has to be optional.

ndom91 commented 1 day ago

I've bumped to 5.7.5 and I'm still seeing the same error (maximum call stack size exceeded).

Unfortunately the parent_project field doesn't seem to be listed as required either. For example, the whole Butler_API_Entities_Project schema:

{
  type: 'object',
  properties: {
    slug: { type: 'string' },
    owner: { type: 'string' },
    parent_project: { '$ref': '#/components/schemas/Butler_API_Entities_Project' },
    name: { type: 'string', description: 'Project Name' },
    description: { type: 'string', description: 'Project Description' },
    repository_id: { type: 'string', description: 'Repository' },
    code_repository_id: { type: 'string', description: 'Code Repository ID' },
    created_at: { type: 'string' },
    updated_at: { type: 'string' }
  },
  description: 'Butler_API_Entities_Project model'
}
fuma-nama commented 1 day ago

Could you provide a reproduction?

ndom91 commented 1 day ago

It's not a minimal reproduciton, but it's relatively small and easy to reproduce :pray:

  1. Clone our docs site - git clone https://github.com/gitbutlerapp/gitbutler-docs
  2. Check out ndom91/fumadocs-openapi-fix branch
  3. Run pnpm build

Relevant PR: https://github.com/gitbutlerapp/gitbutler-docs/pull/53

fuma-nama commented 20 hours ago

thanks for the info! I think I've found the problem now, json-schema-to-typescript relies on $ref property but Fumadocs OpenAPI always use a dereferenced schema for everything, need some refactoring but will fix that soon

ndom91 commented 20 hours ago

Awesome, thanks a lot :pray:

fuma-nama commented 16 hours ago

To fix it, you can add title to the schemas, which will work better as the latest fix will infer it from ref id, resulting a type name like interface Butler_API_Entities_Project.

image

ndom91 commented 16 hours ago

What do you mean by "add title to the schemas" exactly?

fuma-nama commented 16 hours ago
{
  type: 'object',
  title: 'Project',
  properties: {
    slug: { type: 'string' },
    owner: { type: 'string' },
    parent_project: { '$ref': '#/components/schemas/Butler_API_Entities_Project' },
    name: { type: 'string', description: 'Project Name' },
    description: { type: 'string', description: 'Project Description' },
    repository_id: { type: 'string', description: 'Repository' },
    code_repository_id: { type: 'string', description: 'Code Repository ID' },
    created_at: { type: 'string' },
    updated_at: { type: 'string' }
  },
  description: 'Butler_API_Entities_Project model'
}
ndom91 commented 15 hours ago

Ahh okay gotcha. Not sure why exactly that works, but it did the trick haha

https://gitbutler-docs-git-ndom91-fumadocs-openapi-fix-gitbutler.vercel.app/api-reference/user#get-user

fuma-nama commented 14 hours ago

Because title is used as an id to detect cyclic references when the schema is dereferenced, I am going to release the fix together with OpenAPI 3.1 support this month.