Skip to content

Commit f2c2bbd

Browse files
feat: migrate multiple body rule
1 parent 028ab12 commit f2c2bbd

File tree

6 files changed

+122
-3
lines changed

6 files changed

+122
-3
lines changed

packages/apidom-ls/src/config/codes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,7 @@ enum ApilintCodes {
717717
OPENAPI2_PARAMETER_FIELD_IN_EQUALS = 3100200,
718718
OPENAPI2_PARAMETER_FIELD_IN_REQUIRED,
719719
OPENAPI2_PARAMETER_FIELD_IN_VALID,
720+
OPENAPI2_PARAMETER_FIELD_IN_MULTIPLE_BODY,
720721
OPENAPI2_PARAMETER_FIELD_DESCRIPTION_TYPE = 3100300,
721722
OPENAPI2_PARAMETER_FIELD_REQUIRED_TYPE = 3100400,
722723
OPENAPI2_PARAMETER_FIELD_REQUIRED_REQUIRED,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { DiagnosticSeverity } from 'vscode-languageserver-types';
2+
3+
import { OpenAPI2 } from '../../target-specs.ts';
4+
import ApilintCodes from '../../../codes.ts';
5+
6+
const inMultipleBody = {
7+
code: ApilintCodes.OPENAPI2_PARAMETER_FIELD_IN_MULTIPLE_BODY,
8+
source: 'apilint',
9+
message: 'Multiple body parameters are not allowed',
10+
severity: DiagnosticSeverity.Error,
11+
linterFunction: 'apilintPropertyUniqueSiblingValue',
12+
linterParams: [['parameters'], 'in'],
13+
marker: 'key',
14+
markerTarget: 'in',
15+
target: 'in',
16+
conditions: [
17+
{
18+
targets: [{ path: 'in' }],
19+
function: 'apilintContainsValue',
20+
params: ['body'],
21+
},
22+
],
23+
data: {},
24+
targetSpecs: OpenAPI2,
25+
};
26+
27+
export default inMultipleBody;

packages/apidom-ls/src/config/openapi/parameter/lint/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import uniqueNameLint from './unique-name.ts';
4646
import inAuthorizationLint from './in--authorization.ts';
4747
import inContentTypeLint from './in--content-type.ts';
4848
import inAcceptLint from './in--accept.ts';
49+
import inMultipleBody from './in--multiple-body.ts';
4950

5051
const lints = [
5152
nameTypeLint,
@@ -96,6 +97,7 @@ const lints = [
9697
inPathTemplateLint,
9798
inContentTypeLint,
9899
inAcceptLint,
100+
inMultipleBody,
99101
];
100102

101103
export default lints;

packages/apidom-ls/src/services/validation/linter-functions.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -799,15 +799,22 @@ export const standardLinterfunctions: FunctionItem[] = [
799799
functionName: 'apilintPropertyUniqueSiblingValue',
800800
function: (element, elementOrClasses, key) => {
801801
const value = toValue(element);
802+
803+
const filterSiblingsOAS2 = (el: Element) =>
804+
isString(el) &&
805+
(el.parent.key as { content?: string })?.content === key &&
806+
el.content === value;
807+
808+
const filterSiblingsOAS3 = (el: Element) =>
809+
isObject(el) && el.hasKey(key) && toValue(el.get(key)) === value;
810+
802811
const elements = filter((el) => {
803812
const classes: string[] = toValue(el.getMetaProperty('classes', []));
804813

805814
return (
806815
(elementOrClasses.includes(el.element) ||
807816
classes.every((v) => elementOrClasses.includes(v))) &&
808-
isObject(el) &&
809-
el.hasKey(key) &&
810-
toValue(el.get(key)) === value
817+
(filterSiblingsOAS2(el) || filterSiblingsOAS3(el))
811818
);
812819
}, element.parent?.parent?.parent);
813820
return elements.length <= 1;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
swagger: '2.0'
2+
info:
3+
title: 'test'
4+
version: 1.0.0
5+
paths:
6+
/:
7+
get:
8+
responses:
9+
default:
10+
description: 'test'
11+
consumes:
12+
- multipart/form-data
13+
parameters:
14+
- in: body
15+
name: Else1
16+
schema: {}
17+
- in: body
18+
name: Else2
19+
schema: {}

packages/apidom-ls/test/validate.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3861,6 +3861,69 @@ describe('apidom-ls-validate', function () {
38613861
languageService.terminate();
38623862
});
38633863

3864+
it('oas 2.0 / yaml - Multiple body parameters are not allowed', async function () {
3865+
const validationContext: ValidationContext = {
3866+
comments: DiagnosticSeverity.Error,
3867+
maxNumberOfProblems: 100,
3868+
relatedInformation: false,
3869+
};
3870+
3871+
const spec = fs
3872+
.readFileSync(
3873+
path.join(__dirname, 'fixtures', 'validation', 'oas', 'parameter-in-multiple-body.yaml'),
3874+
)
3875+
.toString();
3876+
const doc: TextDocument = TextDocument.create(
3877+
'foo://bar/parameter-in-multiple-body.yaml',
3878+
'yaml',
3879+
0,
3880+
spec,
3881+
);
3882+
3883+
const languageService: LanguageService = getLanguageService(contextNoSchema);
3884+
3885+
const result = await languageService.doValidation(doc, validationContext);
3886+
const expected: Diagnostic[] = [
3887+
{
3888+
code: 3100203,
3889+
data: {},
3890+
message: 'Multiple body parameters are not allowed',
3891+
range: {
3892+
end: {
3893+
character: 12,
3894+
line: 13,
3895+
},
3896+
start: {
3897+
character: 10,
3898+
line: 13,
3899+
},
3900+
},
3901+
severity: 1,
3902+
source: 'apilint',
3903+
},
3904+
{
3905+
code: 3100203,
3906+
data: {},
3907+
message: 'Multiple body parameters are not allowed',
3908+
range: {
3909+
end: {
3910+
character: 12,
3911+
line: 16,
3912+
},
3913+
start: {
3914+
character: 10,
3915+
line: 16,
3916+
},
3917+
},
3918+
severity: 1,
3919+
source: 'apilint',
3920+
},
3921+
];
3922+
assert.deepEqual(result, expected as Diagnostic[]);
3923+
3924+
languageService.terminate();
3925+
});
3926+
38643927
it('oas 3.1 / yaml - parameter object should be defined within path template', async function () {
38653928
const validationContext: ValidationContext = {
38663929
comments: DiagnosticSeverity.Error,

0 commit comments

Comments
 (0)