Skip to content

feat: add new linting rules for compositions keys oneOf, anyOf, allOf - #2369

Draft
AlbinaBlazhko17 wants to merge 6 commits into
mainfrom
feat/new-linting-rules-for-oneof-anyof-allof
Draft

feat: add new linting rules for compositions keys oneOf, anyOf, allOf#2369
AlbinaBlazhko17 wants to merge 6 commits into
mainfrom
feat/new-linting-rules-for-oneof-anyof-allof

Conversation

@AlbinaBlazhko17

@AlbinaBlazhko17 AlbinaBlazhko17 commented Oct 15, 2025

Copy link
Copy Markdown
Contributor

What/Why/How?

Added new linting rules to handle illogical use of composition keys: oneOf, anyOf, allOf.

Reference

Resolves #2326

Testing

Locally with different specs.

Screenshots (optional)

Check yourself

  • This PR follows the contributing guide
  • All new/updated code is covered by tests
  • Core code changed? - Tested with other Redocly products (internal contributions only)
  • New package installed? - Tested in different environments (browser/node)
  • Documentation update has been considered

Security

  • The security impact of the change has been considered
  • Code follows company security practices and guidelines

Note

Medium Risk
Turns on a new recommended lint rule that can emit warnings/errors on existing OpenAPI descriptions. Overlap detection is heuristic and may false-positive or miss cases, but it does not change auth or data handling.

Overview
Adds the OAS 3.x lint rule no-illogical-composition-keywords so oneOf, anyOf, and allOf must combine schemas a value can actually match.

It flags too-few members, duplicates, empty {} members, overlapping oneOf branches (using a narrow comparison of type/enum/const/properties/required/additionalProperties: false), and discriminator misuse (property not required, or inline members that cannot be selected). Single-schema allOf wrappers used for sibling keywords or discriminated subtypes are allowed.

Enabled as warn in recommended and error in recommended-strict/all (off in minimal/spec). Registers named OneOf/AnyOf/AllOf node types so built-in and configurable rules can target one composition keyword. Existing descriptions may report new problems.

Reviewed by Cursor Bugbot for commit b0c7308. Bugbot is set up for automated code reviews on this repo. Configure here.

@changeset-bot

changeset-bot Bot commented Oct 15, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3938123

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@redocly/cli Minor
@redocly/openapi-core Minor
@redocly/respect-core Minor
@redocly/client-generator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Oct 15, 2025

Copy link
Copy Markdown
Contributor
Command Mean [s] Min [s] Max [s] Relative
redocly lint packages/core/src/benchmark/benches/rebilly.yaml 1.433 ± 0.020 1.407 1.478 1.00 ± 0.02
redocly-next lint packages/core/src/benchmark/benches/rebilly.yaml 1.431 ± 0.028 1.391 1.478 1.00

@AlbinaBlazhko17
AlbinaBlazhko17 force-pushed the feat/new-linting-rules-for-oneof-anyof-allof branch 2 times, most recently from 4ee9d5e to b6216c1 Compare October 21, 2025 11:51

@tatomyr tatomyr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a quick look. I suggest to reorganise the checks, so they cover fist for oneOfs, then anyOfs, and then allOfs. Just duplicate the checks when needed.
Will have another look after you implement those changes.

Comment on lines +33 to +34
// Helper function to get the composition keyword and schemas
const compositionData = (() => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use correct naming so you don't need the comments, e.g.:

Suggested change
// Helper function to get the composition keyword and schemas
const compositionData = (() => {
const getSchemaCompositionData = (() => {

or something similar.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, wait, it's an IIFE? Then it's a bit of overengineering. You can do simply this:

const oneOfs = schema.oneOf

if you prefer to have a separate variable, and then just do every needed check. Don't be afraid to repeat yourself.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about using a separate variable for every composition keyword, but in that case, i need to duplicate checks (duplicated schemas, length of schemas) for every composition keyword and the only difference will be in the warning message. So, the purpose of the IIFE is to return the schema and string, and after that to easily retrieve them in the report message and checks.

Comment thread packages/core/src/rules/oas3/no-illogical-composition-keywords.ts Outdated
Comment thread packages/core/src/rules/oas3/no-illogical-composition-keywords.ts Outdated
// Helper function to get the composition keyword and schemas
const compositionData = (() => {
if (schema.oneOf && Array.isArray(schema.oneOf)) {
return { keyword: 'oneOf' as const, schemas: schema.oneOf };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, your schema could contain oneOf and allOf simultaneously. The code doesn't handle this case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This functionality at all doesn't resolve all nested composition keywords, because we consider, that every composition keyword is a new scope of validation.

Comment thread packages/core/src/rules/oas3/no-illogical-composition-keywords.ts Outdated

const { keyword, schemas } = compositionData;

// Check for minimum schema count (oneOf and anyOf require at least 2)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need comments like this as the intention should be clear enough from the condition and the report message.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you are right. I just left all comments to simplify the review of PR, i will remove it after finalizing the functionality.

Comment thread packages/core/src/rules/oas3/no-illogical-composition-keywords.ts Outdated
return null;
})();

if (!compositionData) return;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates the skip() functianality.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it is duplication, because it doesn't see proper type, even we check in skip method.

Comment thread packages/core/src/rules/oas3/no-illogical-composition-keywords.ts Outdated
@github-actions

github-actions Bot commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 77.96% (🎯 77%) 11926 / 15296
🔵 Statements 78.03% (🎯 77%) 12786 / 16385
🔵 Functions 82.69% (🎯 81%) 2442 / 2953
🔵 Branches 71.54% (🎯 71%) 8811 / 12316
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/core/src/visitors.ts 92.94% 88.88% 90% 92.5% 593, 631, 634, 655, 687, 701
packages/core/src/config/all.ts 100% 100% 100% 100%
packages/core/src/config/minimal.ts 100% 100% 100% 100%
packages/core/src/config/recommended-strict.ts 100% 100% 100% 100%
packages/core/src/config/recommended.ts 100% 100% 100% 100%
packages/core/src/config/spec.ts 100% 100% 100% 100%
packages/core/src/rules/oas3/index.ts 100% 100% 100% 100%
packages/core/src/rules/oas3/no-illogical-composition-keywords.ts 96.03% 92.22% 100% 99.37% 68, 87, 105, 212, 308, 311, 312, 470
packages/core/src/types/index.ts 97.29% 88.46% 100% 97.29% 140
packages/core/src/types/oas3.ts 82.19% 50% 77.77% 82.19% 615, 820-844
packages/core/src/types/oas3_1.ts 41.86% 17.85% 37.5% 41.86% 159-169, 176, 182, 228-280
packages/core/src/types/redocly-yaml.ts 89.21% 77.35% 92.85% 88.88% 479, 511, 517, 561-568, 570, 708-718, 728-744
Generated in workflow #11434 for commit 3938123 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Performance Benchmark (Lower is Faster)

CLI Version Bundle Lint Check Config
cli-latest ▓ 1.00x (Fastest) ▓ 1.00x (Fastest) ▓ 1.00x (Fastest)
cli-next ▓ 1.00x ± 0 ▓ 1.01x ± 0.01 ▓ 1.01x ± 0.01

@AlbinaBlazhko17
AlbinaBlazhko17 force-pushed the feat/new-linting-rules-for-oneof-anyof-allof branch from 65712c8 to 556e9a3 Compare August 20, 2026 17:06
@AlbinaBlazhko17 AlbinaBlazhko17 changed the title feat: new linting rules for compositions keys oneOf, anyOf, allOf feat: add new linting rules for compositions keys oneOf, anyOf, allOf Aug 20, 2026
@AlbinaBlazhko17

Copy link
Copy Markdown
Contributor Author

@cursor review

Comment thread packages/core/src/rules/oas3/no-illogical-composition-keywords.ts
Comment thread packages/core/src/rules/oas3/no-illogical-composition-keywords.ts
@AlbinaBlazhko17

Copy link
Copy Markdown
Contributor Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit b0c7308. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New linting rules for oneOf/anyOf/allOf

2 participants