-
Notifications
You must be signed in to change notification settings - Fork 214
fix(core): fix Ajv error discriminator #2720
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f8fd185
e54fc2f
636419c
c68873f
27817b6
e6378dd
e999529
24df583
1bc5103
ae9fbf6
0063e79
c690a69
d7ca08e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@redocly/respect-core": patch | ||
| --- | ||
|
|
||
| Fix AJV validation error when using discriminator with constraint patterns allOf + not . AJV with `discriminator: true` requires discriminator properties to have `const` or `enum` directly, but valid OpenAPI schemas can use `allOf + not` patterns. The schema check now strips discriminators before AJV validation which allows full dereferenced schemas with complex constraints to validate correctly while maintaining data validation semantics. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import { removeDiscriminatorsFromSchema } from '../remove-discriminators-from-schema.js'; | ||
|
|
||
| describe('removeDiscriminatorsFromSchema', () => { | ||
| it('should return schema unchanged when no discriminator is present', () => { | ||
| const schema = { | ||
| type: 'object', | ||
| properties: { | ||
| method: { type: 'string' }, | ||
| }, | ||
| }; | ||
| expect(removeDiscriminatorsFromSchema(schema)).toEqual(schema); | ||
| }); | ||
|
|
||
| it('should remove top-level discriminator', () => { | ||
| const schema = { | ||
| oneOf: [{ properties: { method: { const: 'card' } } }], | ||
| discriminator: { propertyName: 'method' }, | ||
| }; | ||
| const result = removeDiscriminatorsFromSchema(schema); | ||
| expect(result).not.toHaveProperty('discriminator'); | ||
| expect(result.oneOf).toBeDefined(); | ||
| }); | ||
|
|
||
| it('should remove nested discriminators', () => { | ||
| const schema = { | ||
| properties: { | ||
| instrument: { | ||
| oneOf: [{ properties: { method: { const: 'card' } } }], | ||
| discriminator: { propertyName: 'method' }, | ||
| }, | ||
| }, | ||
| }; | ||
| const result = removeDiscriminatorsFromSchema(schema); | ||
| expect(result.properties.instrument).not.toHaveProperty('discriminator'); | ||
| }); | ||
|
|
||
| it('should handle allOf + not pattern (the discriminator bug case)', () => { | ||
| const schema = { | ||
| oneOf: [ | ||
| { | ||
| properties: { | ||
| method: { | ||
| allOf: [ | ||
| { enum: ['cash', 'payment-card', 'paypal', 'ach'] }, | ||
| { not: { enum: ['payment-card', 'paypal', 'ach'] } }, | ||
| ], | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| properties: { | ||
| method: { const: 'payment-card' }, | ||
| }, | ||
| }, | ||
| ], | ||
| discriminator: { propertyName: 'method' }, | ||
| }; | ||
| const result = removeDiscriminatorsFromSchema(schema); | ||
| expect(result).not.toHaveProperty('discriminator'); | ||
| expect(result.oneOf).toHaveLength(2); | ||
| expect(result.oneOf[0].properties.method.allOf).toBeDefined(); | ||
| }); | ||
|
|
||
| it('should not mutate the original schema', () => { | ||
| const schema = { | ||
| oneOf: [{ properties: { method: { const: 'card' } } }], | ||
| discriminator: { propertyName: 'method' }, | ||
| }; | ||
| removeDiscriminatorsFromSchema(schema); | ||
| expect(schema).toHaveProperty('discriminator'); | ||
|
Check failure on line 70 in packages/respect-core/src/utils/__tests__/remove-discriminators-from-schema.test.ts
|
||
| }); | ||
|
|
||
| it('should handle null and non-object values gracefully', () => { | ||
| expect(removeDiscriminatorsFromSchema(null)).toBeNull(); | ||
| expect(removeDiscriminatorsFromSchema('string')).toBe('string'); | ||
| expect(removeDiscriminatorsFromSchema(42)).toBe(42); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /** | ||
| * removes `discriminator` keywords from a fully-dereferenced schema. | ||
| */ | ||
| export function removeDiscriminatorsFromSchema(schema: any): any { | ||
| if (!schema || typeof schema !== 'object') return schema; | ||
|
|
||
| stripDiscriminators(schema); | ||
| return schema; | ||
| } | ||
|
|
||
| function stripDiscriminators(node: any): void { | ||
| if (!node || typeof node !== 'object') return; | ||
|
|
||
| if (Array.isArray(node)) { | ||
| for (const item of node) { | ||
| stripDiscriminators(item); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| if ('discriminator' in node) { | ||
| delete node.discriminator; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Strips any key named "discriminator" not just OpenAPI keywordMedium Severity
Reviewed by Cursor Bugbot for commit c690a69. Configure here. |
||
|
|
||
| for (const key of Object.keys(node)) { | ||
| stripDiscriminators(node[key]); | ||
| } | ||
| } | ||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function mutates input, failing its own non-mutation test
High Severity
removeDiscriminatorsFromSchemamutates its input in-place viadelete node.discriminatorinstripDiscriminators, but the test "should not mutate the original schema" asserts that the original object retains itsdiscriminatorproperty after the call. This test will fail. The function needs to deep-clone the schema before stripping, or the test expectation is wrong. In the current call site the mutation is masked becauseremoveWriteOnlyPropertiesalready deep-clones, but the function's contract is broken.Additional Locations (1)
packages/respect-core/src/utils/__tests__/remove-discriminators-from-schema.test.ts#L63-L71Reviewed by Cursor Bugbot for commit d7ca08e. Configure here.