-
-
Notifications
You must be signed in to change notification settings - Fork 218
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
13d8ed5
commit d9a6cad
Showing
7 changed files
with
257 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 76 additions & 21 deletions
97
packages/rulesets/src/asyncapi/__tests__/asyncapi-operation-operationId.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,94 @@ | ||
import { DiagnosticSeverity } from '@stoplight/types'; | ||
import produce from 'immer'; | ||
import testRule from './__helpers__/tester'; | ||
|
||
const document = { | ||
asyncapi: '2.0.0', | ||
channels: { | ||
one: { | ||
publish: { | ||
operationId: 'onePubId', | ||
}, | ||
subscribe: { | ||
operationId: 'oneSubId', | ||
testRule('asyncapi-operation-operationId', [ | ||
{ | ||
name: 'valid case', | ||
document: { | ||
asyncapi: '2.4.0', | ||
channels: { | ||
one: { | ||
publish: { | ||
operationId: 'firstId', | ||
}, | ||
subscribe: { | ||
operationId: 'secondId', | ||
}, | ||
}, | ||
}, | ||
}, | ||
errors: [], | ||
}, | ||
}; | ||
|
||
testRule('asyncapi-operation-operationId', [ | ||
{ | ||
name: 'valid case', | ||
document, | ||
name: 'valid case (with traits)', | ||
document: { | ||
asyncapi: '2.4.0', | ||
channels: { | ||
one: { | ||
publish: { | ||
traits: [ | ||
{}, | ||
{ | ||
operationId: 'firstId', | ||
}, | ||
], | ||
}, | ||
subscribe: { | ||
operationId: 'secondId', | ||
}, | ||
}, | ||
}, | ||
}, | ||
errors: [], | ||
}, | ||
|
||
...['publish', 'subscribe'].map(property => ({ | ||
name: `channels.{channel}.${property}.operationId property is missing`, | ||
document: produce(document, draft => { | ||
delete draft.channels.one[property].operationId; | ||
}), | ||
{ | ||
name: 'invalid case', | ||
document: { | ||
asyncapi: '2.4.0', | ||
channels: { | ||
one: { | ||
publish: {}, | ||
subscribe: {}, | ||
}, | ||
}, | ||
}, | ||
errors: [ | ||
{ | ||
message: 'Operation should have a "operationId" field defined.', | ||
path: ['channels', 'one', 'publish'], | ||
severity: DiagnosticSeverity.Warning, | ||
}, | ||
{ | ||
message: 'Operation should have a "operationId" field defined.', | ||
path: ['channels', 'one', 'subscribe'], | ||
severity: DiagnosticSeverity.Warning, | ||
}, | ||
], | ||
}, | ||
|
||
{ | ||
name: 'invalid case (with traits)', | ||
document: { | ||
asyncapi: '2.4.0', | ||
channels: { | ||
one: { | ||
publish: { | ||
traits: [{}, {}], | ||
}, | ||
subscribe: { | ||
operationId: 'secondId', | ||
}, | ||
}, | ||
}, | ||
}, | ||
errors: [ | ||
{ | ||
message: 'Operation should have a "operationId" field defined.', | ||
path: ['channels', 'one', property], | ||
path: ['channels', 'one', 'publish'], | ||
severity: DiagnosticSeverity.Warning, | ||
}, | ||
], | ||
})), | ||
}, | ||
]); |
34 changes: 34 additions & 0 deletions
34
packages/rulesets/src/asyncapi/functions/asyncApi2CheckId.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { createRulesetFunction } from '@stoplight/spectral-core'; | ||
import { truthy } from '@stoplight/spectral-functions'; | ||
import { mergeTraits } from './utils/mergeTraits'; | ||
|
||
import type { MaybeHaveTraits } from './utils/mergeTraits'; | ||
|
||
export default createRulesetFunction<MaybeHaveTraits, { idField: 'operationId' | 'messageId' }>( | ||
{ | ||
input: { | ||
type: 'object', | ||
properties: { | ||
traits: { | ||
type: 'array', | ||
items: { | ||
type: 'object', | ||
}, | ||
}, | ||
}, | ||
}, | ||
options: { | ||
type: 'object', | ||
properties: { | ||
idField: { | ||
type: 'string', | ||
enum: ['operationId', 'messageId'], | ||
}, | ||
}, | ||
}, | ||
}, | ||
function asyncApi2CheckId(targetVal, options, ctx) { | ||
const mergedValue = mergeTraits(targetVal); | ||
return truthy(mergedValue[options.idField], null, ctx); | ||
}, | ||
); |
32 changes: 32 additions & 0 deletions
32
packages/rulesets/src/asyncapi/functions/utils/__tests__/mergeTraits.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { mergeTraits } from '../mergeTraits'; | ||
|
||
describe('mergeTraits', () => { | ||
test('should merge one trait', () => { | ||
const result = mergeTraits({ payload: {}, traits: [{ payload: { someKey: 'someValue' } }] }); | ||
expect(result.payload).toEqual({ someKey: 'someValue' }); | ||
}); | ||
|
||
test('should merge two or more traits', () => { | ||
const result = mergeTraits({ | ||
payload: {}, | ||
traits: [ | ||
{ payload: { someKey1: 'someValue1' } }, | ||
{ payload: { someKey2: 'someValue2' } }, | ||
{ payload: { someKey3: 'someValue3' } }, | ||
], | ||
}); | ||
expect(result.payload).toEqual({ someKey1: 'someValue1', someKey2: 'someValue2', someKey3: 'someValue3' }); | ||
}); | ||
|
||
test('should override fields', () => { | ||
const result = mergeTraits({ | ||
payload: { someKey: 'someValue' }, | ||
traits: [ | ||
{ payload: { someKey: 'someValue1' } }, | ||
{ payload: { someKey: 'someValue2' } }, | ||
{ payload: { someKey: 'someValue3' } }, | ||
], | ||
}); | ||
expect(result.payload).toEqual({ someKey: 'someValue3' }); | ||
}); | ||
}); |
36 changes: 36 additions & 0 deletions
36
packages/rulesets/src/asyncapi/functions/utils/mergeTraits.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { isPlainObject } from '@stoplight/json'; | ||
|
||
export type MaybeHaveTraits = { traits?: any[] } & Record<string, any>; | ||
|
||
export function mergeTraits<T extends MaybeHaveTraits>(data: T): T { | ||
if (Array.isArray(data.traits)) { | ||
data = { ...data }; // shallow copy | ||
for (const trait of data.traits as T[]) { | ||
for (const key in trait) { | ||
data[key] = merge(data[key], trait[key]); | ||
} | ||
} | ||
} | ||
return data; | ||
} | ||
|
||
function merge<T>(origin: unknown, patch: unknown): T { | ||
// If the patch is not an object, it replaces the origin. | ||
if (!isPlainObject(patch)) { | ||
return patch as T; | ||
} | ||
|
||
const result = !isPlainObject(origin) | ||
? {} // Non objects are being replaced. | ||
: Object.assign({}, origin); // Make sure we never modify the origin. | ||
|
||
Object.keys(patch).forEach(key => { | ||
const patchVal = patch[key]; | ||
if (patchVal === null) { | ||
delete result[key]; | ||
} else { | ||
result[key] = merge(result[key], patchVal); | ||
} | ||
}); | ||
return result as T; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters