Skip to content
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

feat: added rules for channel-server v3 #1031

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
57 changes: 57 additions & 0 deletions src/ruleset/v3/functions/channelServer3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { createRulesetFunction } from '@stoplight/spectral-core';
import type { IFunctionResult } from '@stoplight/spectral-core';

export const channelServers3 = createRulesetFunction<
{ servers?: Record<string, unknown>; channels?: Record<string, { servers?: Array<{ $ref: string }> }> },
null
>(
{
input: {
type: 'object',
properties: {
servers: {
type: 'object',
},
channels: {
type: 'object',
additionalProperties: {
type: 'object',
properties: {
servers: {
type: 'array',
items: {
type: 'object',
required: ['$ref'],
properties: {
$ref: { type: 'string' },
},
},
},
},
},
},
},
},
options: null,
},
(targetVal) => {
console.log('channelServers function called with:', JSON.stringify(targetVal, null, 2));
const results: IFunctionResult[] = [];
if (!targetVal.channels) return results;

Object.entries(targetVal.channels ?? {}).forEach(([channelAddress, channel]) => {
if (!channel.servers) return;

channel.servers.forEach((serverRef, index) => {
if (!serverRef.$ref.startsWith('#/servers/')) {
results.push({
message: 'Channel server must reference a server defined in the root "servers" object.',
path: ['channels', channelAddress, 'servers', index, '$ref'],
});
}
});
});
console.log('channelServers function returning results:', results);
return results;
},
);
11 changes: 11 additions & 0 deletions src/ruleset/v3/ruleset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { AsyncAPIFormats } from '../formats';
import { operationMessagesUnambiguity } from './functions/operationMessagesUnambiguity';
import { channelServers3 } from './functions/channelServers3';
import { pattern } from '@stoplight/spectral-functions';

export const v3CoreRuleset = {
Expand Down Expand Up @@ -56,6 +57,16 @@ export const v3CoreRuleset = {
match: '#\\/servers\\/', // If doesn't match, rule fails.
},
},
},
'asyncapi3-channel-servers': {
description: 'Channel servers must be defined in the root "servers" object.',
message: '{{error}}',
severity: 'error',
recommended: true,
given: '$',
then: {
function: channelServers3,
},
}
},
};
210 changes: 210 additions & 0 deletions test/ruleset/rules/v3/asyncapi3-channel-server.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import { testRule, DiagnosticSeverity } from '../../tester';

testRule('asyncapi3-channel-servers', [
{
name: 'valid case',
document: {
asyncapi: '3.0.0',
servers: {
development: {},
production: {},
},
channels: {
channel: {
servers: [{ $ref: '#/servers/development' }],
},
},
},
errors: [],
},

{
name: 'valid case - multiple servers',
document: {
asyncapi: '3.0.0',
servers: {
development: {},
production: {},
staging: {},
},
channels: {
channel: {
servers: [
{ $ref: '#/servers/development' },
{ $ref: '#/servers/production' },
],
},
},
},
errors: [],
},

{
name: 'valid case - without defined servers',
document: {
asyncapi: '3.0.0',
servers: {
development: {},
production: {},
},
channels: {
channel: {},
},
},
errors: [],
},

{
name: 'valid case - without defined servers in the root',
document: {
asyncapi: '3.0.0',
channels: {
channel: {},
},
},
errors: [],
},

{
name: 'valid case - without defined channels in the root',
document: {
asyncapi: '3.0.0',
servers: {
development: {},
production: {},
},
},
errors: [],
},

{
name: 'valid case - with empty array',
document: {
asyncapi: '3.0.0',
servers: {
development: {},
production: {},
},
channels: {
channel: {
servers: [],
},
},
},
errors: [],
},

{
name: 'invalid case - incorrect $ref',
document: {
asyncapi: '3.0.0',
servers: {
development: {},
production: {},
},
channels: {
channel: {
servers: [{ $ref: '#/components/servers/another-server' }],
},
},
},
errors: [
{
message: 'Channel server must reference a server defined in the root "servers" object.',
path: ['channels', 'channel', 'servers', '0', '$ref'],
severity: DiagnosticSeverity.Error,
},
],
},

{
name: 'invalid case - one server is correct, another one is incorrect',
document: {
asyncapi: '3.0.0',
servers: {
development: {},
production: {},
},
channels: {
channel: {
servers: [
{ $ref: '#/servers/production' },
{ $ref: '#/components/servers/another-server' },
],
},
},
},
errors: [
{
message: 'Channel server must reference a server defined in the root "servers" object.',
path: ['channels', 'channel', 'servers', '1', '$ref'],
severity: DiagnosticSeverity.Error,
},
],
},

{
name: 'invalid case - without defined servers',
document: {
asyncapi: '3.0.0',
channels: {
channel: {
servers: [{ $ref: '#/servers/production' }],
},
},
},
errors: [
{
message: 'Channel server must reference a server defined in the root "servers" object.',
path: ['channels', 'channel', 'servers', '0', '$ref'],
severity: DiagnosticSeverity.Error,
},
],
},

{
name: 'invalid case - incorrect $ref format',
document: {
asyncapi: '3.0.0',
servers: {
development: {},
production: {},
},
channels: {
channel: {
servers: [{ $ref: 'production' }],
},
},
},
errors: [
{
message: 'Channel server must reference a server defined in the root "servers" object.',
path: ['channels', 'channel', 'servers', '0', '$ref'],
severity: DiagnosticSeverity.Error,
},
],
},

{
name: 'invalid case - servers is not an array',
document: {
asyncapi: '3.0.0',
servers: {
development: {},
production: {},
},
channels: {
channel: {
servers: { $ref: '#/servers/production' },
},
},
},
errors: [
{
message: 'Channel servers must be an array of references to servers.',
path: ['channels', 'channel', 'servers'],
severity: DiagnosticSeverity.Error,
},
],
},
]);
Loading