Redocly / redocly-cli

⚒️ Redocly CLI makes OpenAPI easy. Lint/validate to any standard, generate beautiful docs, and more.
https://redocly.com/docs/cli/
MIT License
952 stars 149 forks source link

Prevent `redocly bundle` from creating new schema objects in `#/components/schemas` when using `--dereferenced` option #1798

Open outdooracorn opened 2 weeks ago

outdooracorn commented 2 weeks ago

Describe the bug

The redocly bundle command is adding schema objects to the #/components/schemas section of the bundled schema, even when using the --dereferenced option is used.

Closed issue #239 seems to be similar and points to using the --dereferenced option to solve this issue.

To Reproduce Steps to reproduce the behavior:

  1. Given this redocly.yaml file
  2. And these OpenAPI files
  3. Run npx redocly bundle schema/openapi.json --dereferenced -o out/openapi.json
  4. See that PropertyValuePair and Error schema objects are added to #/components/schemas in the bundled OpenAPI document

Expected behavior

I would expect only (dereferenced versions of) the schema objects present in schemas.json to be in the #/components/schemas section of the bundled and dereference OpenAPI document.

Logs

OpenAPI description

OpenAPI v3.1 - see example repo

Redocly Version(s)

"@redocly/cli": "^1.25.11",

Node.js Version(s)

v18.20.4 and v20.12.2

OS, environment

Kubuntu 22.04

Additional context

tatomyr commented 2 weeks ago

Have you tried using the --remove-unused-components option?

outdooracorn commented 2 weeks ago

Have you tried using the --remove-unused-components option?

I have. It removes some, but not all, of the components. In this example, #/components/schemas/Statement is left.

I also don't want to remove all the components. I would like to keep #/components/schema so that it displays the schemas section in Swagger UI.

tatomyr commented 1 week ago

Ah, so you want to bundle your files, preserve the existing components, and not add the new ones? Then it's more of an enhancement rather than a bug. I'm not sure it would be an easy change. It will require modifying the internals, as the bundler currently resolves external references into the components section regardless of the --dereferenced option because the component might be used in an indirect way (e.g. in a discriminator). However, you can try using a custom plugin with a decorator to filter schemas that were only present in the original components. It should probably look like this:


const filterSchemas = () => {
  let originalSchemas;
  return {
    Components: {
      leave(components) {
        for (const key in components.schemas || {}) {
          if (originalSchemas?.[key] === undefined) {
            delete components.schemas[key];
          }
        }
      },
      NamedSchemas: {
        enter(schemas) {
          originalSchemas = schemas;
        },
      },
    },
  };
};

Please let me know if that works!

outdooracorn commented 1 week ago

Ideally, we would like to bundle the files and only dereference/inline schemas that aren't already in #/components. Said differently, keep references to components already in #/components, and dereference/inline everything else.

Thanks for the custom decorator plugin code, we will try it out.