Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,32 @@ import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

const componentSchemas = {
schemas: {
Dog: {
type: 'object',
properties: {
breed: { type: 'string' },
age: { type: 'integer' },
},
Dog: {
type: 'object',
properties: {
breed: { type: 'string' },
age: { type: 'integer' },
},
Cat: {
type: 'object',
properties: {
color: { type: 'string' },
livesLeft: { type: 'integer' },
},
},
Cat: {
type: 'object',
properties: {
color: { type: 'string' },
livesLeft: { type: 'integer' },
},
Bird: {
type: 'object',
properties: {
species: { type: 'string' },
wingspan: { type: 'number' },
},
},
Bird: {
type: 'object',
properties: {
species: { type: 'string' },
wingspan: { type: 'number' },
},
Fish: {
type: 'object',
properties: {
species: { type: 'string' },
waterType: { type: 'string' },
},
},
Fish: {
type: 'object',
properties: {
species: { type: 'string' },
waterType: { type: 'string' },
},
},
};
Expand All @@ -38,15 +36,17 @@ testRule('xgen-IPA-125-oneOf-must-have-discriminator', [
{
name: 'valid oneOf with discriminator and matching mapping',
document: {
components: componentSchemas,
schemas: {
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
discriminator: {
propertyName: 'type',
mapping: {
dog: '#/components/schemas/Dog',
cat: '#/components/schemas/Cat',
components: {
schemas: {
...componentSchemas,
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
discriminator: {
propertyName: 'type',
mapping: {
dog: '#/components/schemas/Dog',
cat: '#/components/schemas/Cat',
},
},
},
},
Expand All @@ -57,15 +57,17 @@ testRule('xgen-IPA-125-oneOf-must-have-discriminator', [
{
name: 'invalid oneOf with discriminator but mismatched mapping',
document: {
components: componentSchemas,
schemas: {
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
discriminator: {
propertyName: 'type',
mapping: {
dog: '#/components/schemas/Dog',
bird: '#/components/schemas/Bird',
components: {
schemas: {
...componentSchemas,
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
discriminator: {
propertyName: 'type',
mapping: {
dog: '#/components/schemas/Dog',
bird: '#/components/schemas/Bird',
},
},
},
},
Expand All @@ -76,61 +78,67 @@ testRule('xgen-IPA-125-oneOf-must-have-discriminator', [
code: 'xgen-IPA-125-oneOf-must-have-discriminator',
message:
'The discriminator mapping must match the oneOf references. Unmatched Discriminator mappings with oneOf references: #/components/schemas/Bird',
path: ['schemas', 'Animal'],
path: ['components', 'schemas', 'Animal'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'invalid oneOf without discriminator',
document: {
components: componentSchemas,
schemas: {
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
components: {
schemas: {
...componentSchemas,
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
},
},
},
},
errors: [
{
code: 'xgen-IPA-125-oneOf-must-have-discriminator',
message: 'The schema has oneOf but no discriminator property.',
path: ['schemas', 'Animal'],
path: ['components', 'schemas', 'Animal'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'invalid oneOf with non-object discriminator',
document: {
components: componentSchemas,
schemas: {
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
discriminator: "I'm a string, not an object!",
components: {
schemas: {
...componentSchemas,
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
discriminator: "I'm a string, not an object!",
},
},
},
},
errors: [
{
code: 'xgen-IPA-125-oneOf-must-have-discriminator',
message: 'Discriminator property is not an object.',
path: ['schemas', 'Animal'],
path: ['components', 'schemas', 'Animal'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'invalid oneOf with discriminator but no propertyName',
document: {
components: componentSchemas,
schemas: {
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
discriminator: {
mapping: {
dog: '#/components/schemas/Dog',
cat: '#/components/schemas/Cat',
components: {
schemas: {
...componentSchemas,
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
discriminator: {
mapping: {
dog: '#/components/schemas/Dog',
cat: '#/components/schemas/Cat',
},
},
},
},
Expand All @@ -140,20 +148,22 @@ testRule('xgen-IPA-125-oneOf-must-have-discriminator', [
{
code: 'xgen-IPA-125-oneOf-must-have-discriminator',
message: 'Discriminator has no propertyName defined.',
path: ['schemas', 'Animal'],
path: ['components', 'schemas', 'Animal'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'invalid oneOf with discriminator but no mapping',
document: {
components: componentSchemas,
schemas: {
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
discriminator: {
propertyName: 'type',
components: {
schemas: {
...componentSchemas,
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
discriminator: {
propertyName: 'type',
},
},
},
},
Expand All @@ -162,20 +172,22 @@ testRule('xgen-IPA-125-oneOf-must-have-discriminator', [
{
code: 'xgen-IPA-125-oneOf-must-have-discriminator',
message: 'Discriminator must have a mapping object.',
path: ['schemas', 'Animal'],
path: ['components', 'schemas', 'Animal'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'oneOf with discriminator exemption',
document: {
components: componentSchemas,
schemas: {
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
'x-xgen-IPA-exception': {
'xgen-IPA-125-oneOf-must-have-discriminator': 'reason for exemption',
components: {
schemas: {
...componentSchemas,
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
'x-xgen-IPA-exception': {
'xgen-IPA-125-oneOf-must-have-discriminator': 'reason for exemption',
},
},
},
},
Expand Down
117 changes: 117 additions & 0 deletions tools/spectral/ipa/__tests__/IPA125OneOfNoBaseTypes.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

const componentSchemas = {
Dog: {
type: 'object',
properties: {
breed: { type: 'string' },
age: { type: 'integer' },
},
},
Cat: {
type: 'object',
properties: {
color: { type: 'string' },
livesLeft: { type: 'integer' },
},
},
};

testRule('xgen-IPA-125-oneOf-no-base-types', [
{
name: 'valid oneOf with references only',
document: {
components: {
schemas: {
...componentSchemas,
Animal: {
oneOf: [{ $ref: '#/components/schemas/Dog' }, { $ref: '#/components/schemas/Cat' }],
},
},
},
},
errors: [],
},
{
name: 'valid oneOf with object schema',
document: {
components: {
schemas: {
...componentSchemas,
MixedObject: {
oneOf: [
{
type: 'object',
properties: {
name: { type: 'string' },
},
},
{ $ref: '#/components/schemas/Dog' },
],
},
},
},
},
errors: [],
},
{
name: 'invalid oneOf with string type',
document: {
components: {
schemas: {
...componentSchemas,
MixedType: {
oneOf: [{ type: 'string' }, { $ref: '#/components/schemas/Dog' }],
},
},
},
},
errors: [
{
code: 'xgen-IPA-125-oneOf-no-base-types',
message: 'oneOf should not contain base types like integer, number, string, or boolean.',
path: ['components', 'schemas', 'MixedType'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'invalid oneOf with multiple base types',
document: {
components: {
schemas: {
...componentSchemas,
BaseTypes: {
oneOf: [{ type: 'string' }, { type: 'integer' }, { type: 'boolean' }],
},
},
},
},
errors: [
{
code: 'xgen-IPA-125-oneOf-no-base-types',
message: 'oneOf should not contain base types like integer, number, string, or boolean.',
path: ['components', 'schemas', 'BaseTypes'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'oneOf with exception',
document: {
components: {
schemas: {
...componentSchemas,
MixedType: {
oneOf: [{ type: 'string' }, { type: 'integer' }],
'x-xgen-IPA-exception': {
'xgen-IPA-125-oneOf-no-base-types': 'reason for exemption',
},
},
},
},
},
errors: [],
},
]);
1 change: 1 addition & 0 deletions tools/spectral/ipa/ipa-spectral.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extends:
- ./rulesets/IPA-112.yaml
- ./rulesets/IPA-113.yaml
- ./rulesets/IPA-123.yaml
- ./rulesets/IPA-125.yaml

overrides:
- files:
Expand Down
Loading
Loading