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
941 stars 148 forks source link

Add option `--prefix-components-with-filepath` to `join` #1575

Open uncaught opened 5 months ago

uncaught commented 5 months ago

Is your feature request related to a problem? Please describe.

This is a follow-up to #1566:

When you have nested component references, the names of the components can quickly collide.

Currently the only options are:

Describe the solution you'd like

I would like to get a new option in, lets call it --prefix-components-with-filepath that has three values:

Technically, the file paths of each component name should be resolved to their realpath, and then cut off starting at the root until uniqueness of the prefix is compromised. This should avoid confusion when different folder depths are involved.

So imagine in all my join sources I'm referencing these components:

The resulting component names would be as follow:

tatomyr commented 5 months ago

@uncaught there's one more possible option you can try to work around that: writing a custom decorator to remove duplicated components in the joined file. You may start with something like the following and improve is as you need:

module.exports = {
  id: "my-local-plugin",
  decorators: {
    oas3: {
      'remove-duplicated-schemas': () => {
        const refs = {};
        const schemasToDelete = [];
        return {
          ref: {
            enter(ref, ctx) {
              if (!ref.$ref.startsWith("#/components/schemas/")) {
                // Ignore refs that are not pointing to a schema inside the current file
                return;
              }
              const stringifiedSchema = JSON.stringify(ctx.resolve(ref).node);
              if (refs[stringifiedSchema]) {
                const [_, schemaName] = ref.$ref.split("#/components/schemas/");
                schemasToDelete.push(schemaName);
                ref.$ref = refs[stringifiedSchema];
              } else {
                refs[stringifiedSchema] = ref.$ref;
              }
            },
          },
          NamedSchemas: {
            leave(namedSchemas) {
              for (const schemaName of schemasToDelete) {
                delete namedSchemas[schemaName];
              }
            },
          },
        };
      },
    },
  },
};

The command then will look like this: redocly join RouteA.yml RouteB.yml --prefix-components-with-info-prop title -o joined.yaml && redocly bundle joined.yaml.

lornajane commented 5 months ago

Thank you @uncaught for the feature request, we will certainly consider it. And thank you @tatomyr for adding the workaround that can be used with the current version of the tool - I'm sure this will help someone!