Skip to content

Commit a819278

Browse files
Merge pull request #4986 from swagger-api/feat/swg--15850--port-parameters-validation-rules
feat: add parameter validation rules
2 parents 774fd62 + 1581750 commit a819278

15 files changed

+619
-0
lines changed

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

Lines changed: 4 additions & 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,
@@ -740,6 +741,7 @@ enum ApilintCodes {
740741
OPENAPI2_PARAMETER_FIELD_ENUM_TYPE = 3101800,
741742
OPENAPI2_PARAMETER_FIELD_MULTIPLE_OF_TYPE = 3101900,
742743
OPENAPI2_PARAMETER_FIELD_IN_PATH_TEMPLATE = 3102000,
744+
OPENAPI2_PARAMETER_FIELD_NAME_UNIQUE = 3103000,
743745

744746
OPENAPI2_ITEMS = 3110000,
745747
OPENAPI2_ITEMS_FIELD_TYPE_EQUALS = 3110100,
@@ -976,6 +978,8 @@ enum ApilintCodes {
976978
OPENAPI3_0_PARAMETER_FIELD_IN_TYPE = 5150300,
977979
OPENAPI3_0_PARAMETER_FIELD_IN_REQUIRED,
978980
OPENAPI3_0_PARAMETER_FIELD_IN_EQUALS,
981+
OPENAPI3_0_PARAMETER_FIELD_IN_AUTHORIZATION,
982+
OPENAPI3_0_PARAMETER_FIELD_IN_CONTENT_TYPE,
979983
OPENAPI3_0_PARAMETER_FIELD_DESCRIPTION_TYPE = 5150400,
980984
OPENAPI3_0_PARAMETER_FIELD_REQUIRED_TYPE = 5150500,
981985
OPENAPI3_0_PARAMETER_FIELD_REQUIRED_REQUIRED,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { DiagnosticSeverity } from 'vscode-languageserver-types';
2+
3+
import { OpenAPI3 } from '../../target-specs.ts';
4+
import ApilintCodes from '../../../codes.ts';
5+
6+
const inAcceptLint = {
7+
code: ApilintCodes.OPENAPI3_0_PARAMETER_FIELD_IN_CONTENT_TYPE,
8+
source: 'apilint',
9+
message:
10+
'Header Parameter named "Accept" is ignored. The values for the "Accept" header are defined by `requestBody.content.<media-type>`',
11+
severity: DiagnosticSeverity.Warning,
12+
linterParams: ['^(?!\\b(A|a)ccept\\b).*$'],
13+
linterFunction: 'apilintValueRegex',
14+
marker: 'value',
15+
target: 'name',
16+
data: {},
17+
conditions: [
18+
{
19+
targets: [
20+
{
21+
path: 'in',
22+
},
23+
],
24+
function: 'apilintContainsValue',
25+
params: ['header'],
26+
},
27+
],
28+
targetSpecs: OpenAPI3,
29+
};
30+
31+
export default inAcceptLint;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { DiagnosticSeverity } from 'vscode-languageserver-types';
2+
3+
import { OpenAPI3 } from '../../target-specs.ts';
4+
import ApilintCodes from '../../../codes.ts';
5+
6+
const inAuthorizationLint = {
7+
code: ApilintCodes.OPENAPI3_0_PARAMETER_FIELD_IN_AUTHORIZATION,
8+
source: 'apilint',
9+
message:
10+
'Header Parameter named "Authorization" is ignored. Use the "securitySchemes" and "security" sections instead to define authorization',
11+
severity: DiagnosticSeverity.Warning,
12+
linterParams: ['^(?!\\b(A|a)uthorization\\b).*$'],
13+
linterFunction: 'apilintValueRegex',
14+
marker: 'value',
15+
target: 'name',
16+
data: {},
17+
conditions: [
18+
{
19+
targets: [
20+
{
21+
path: 'in',
22+
},
23+
],
24+
function: 'apilintContainsValue',
25+
params: ['header'],
26+
},
27+
],
28+
targetSpecs: OpenAPI3,
29+
};
30+
31+
export default inAuthorizationLint;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { DiagnosticSeverity } from 'vscode-languageserver-types';
2+
3+
import { OpenAPI3 } from '../../target-specs.ts';
4+
import ApilintCodes from '../../../codes.ts';
5+
6+
const inContentTypeLint = {
7+
code: ApilintCodes.OPENAPI3_0_PARAMETER_FIELD_IN_CONTENT_TYPE,
8+
source: 'apilint',
9+
message:
10+
'Header Parameter named "Content-Type" is ignored. The values for the "Content-Type" header are defined by `requestBody.content.<media-type>`',
11+
severity: DiagnosticSeverity.Warning,
12+
linterParams: ['^(?!\\b(C|c)ontent-(T|t)ype\\b).*$'],
13+
linterFunction: 'apilintValueRegex',
14+
marker: 'value',
15+
target: 'name',
16+
data: {},
17+
conditions: [
18+
{
19+
targets: [
20+
{
21+
path: 'in',
22+
},
23+
],
24+
function: 'apilintContainsValue',
25+
params: ['header'],
26+
},
27+
],
28+
targetSpecs: OpenAPI3,
29+
};
30+
31+
export default inContentTypeLint;
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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,18 @@ import uniqueItemsTypeLint from './unique-items--type.ts';
4242
import enumTypeLint from './enum--type.ts';
4343
import multipleOfTypeLint from './multiple-of--type.ts';
4444
import inPathTemplateLint from './in-path-template.ts';
45+
import uniqueNameLint from './unique-name.ts';
46+
import inAuthorizationLint from './in--authorization.ts';
47+
import inContentTypeLint from './in--content-type.ts';
48+
import inAcceptLint from './in--accept.ts';
49+
import inMultipleBody from './in--multiple-body.ts';
4550

4651
const lints = [
4752
nameTypeLint,
4853
nameRequiredLint,
4954
inEquals2_0Lint,
5055
inEquals3_0__3_1Lint,
56+
inAuthorizationLint,
5157
inRequiredLint,
5258
inValidLint,
5359
descriptionTypeLint,
@@ -81,13 +87,17 @@ const lints = [
8187
maxLengthTypeLint,
8288
minLengthTypeLint,
8389
uniqueItemsTypeLint,
90+
uniqueNameLint,
8491
enumTypeLint,
8592
multipleOfTypeLint,
8693
requiredFields3_0__3_1Lint,
8794
allowedFields2_0Lint,
8895
allowedFields3_0Lint,
8996
allowedFields3_1Lint,
9097
inPathTemplateLint,
98+
inContentTypeLint,
99+
inAcceptLint,
100+
inMultipleBody,
91101
];
92102

93103
export default lints;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { DiagnosticSeverity } from 'vscode-languageserver-types';
2+
3+
import ApilintCodes from '../../../codes.ts';
4+
import { LinterMeta } from '../../../../apidom-language-types.ts';
5+
import { OpenAPI2, OpenAPI3 } from '../../target-specs.ts';
6+
7+
const parametersTypeLint: LinterMeta = {
8+
code: ApilintCodes.OPENAPI2_PARAMETER_FIELD_NAME_UNIQUE,
9+
source: 'apilint',
10+
message: 'Name must be unique among all parameters',
11+
severity: DiagnosticSeverity.Error,
12+
linterFunction: 'apilintPropertyUniqueSiblingValue',
13+
linterParams: ['parameters', 'name'],
14+
marker: 'key',
15+
markerTarget: 'name',
16+
target: 'name',
17+
data: {},
18+
targetSpecs: [...OpenAPI2, ...OpenAPI3],
19+
};
20+
21+
export default parametersTypeLint;

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,30 @@ export const standardLinterfunctions: FunctionItem[] = [
795795
return true;
796796
},
797797
},
798+
{
799+
functionName: 'apilintPropertyUniqueSiblingValue',
800+
function: (element, elementOrClasses, key) => {
801+
const value = toValue(element);
802+
803+
const filterSiblingsOAS2 = (
804+
el: Element & { key?: { content?: string }; content: { value?: string } },
805+
) => isString(el) && el.key?.content === key && toValue(el.content.value) === value;
806+
807+
const filterSiblingsOAS3 = (el: Element) =>
808+
isObject(el) && el.hasKey(key) && toValue(el.get(key)) === value;
809+
810+
const elements = filter((el: Element) => {
811+
const classes: string[] = toValue(el.getMetaProperty('classes', []));
812+
813+
return (
814+
(elementOrClasses.includes(el.element) ||
815+
classes.every((v) => elementOrClasses.includes(v))) &&
816+
(filterSiblingsOAS2(el) || filterSiblingsOAS3(el))
817+
);
818+
}, element.parent?.parent?.parent);
819+
return elements.length <= 1;
820+
},
821+
},
798822
{
799823
functionName: 'apilintChannelParameterExist',
800824
function: (element: Element): boolean => {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
openapi: 3.0.0
2+
info:
3+
version: 1.0.0
4+
title: 'test'
5+
paths:
6+
/:
7+
get:
8+
responses:
9+
default:
10+
description: 'test'
11+
parameters:
12+
- in: header
13+
name: accept
14+
content:
15+
application/xml: {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
openapi: 3.0.0
2+
info:
3+
version: 1.0.0
4+
title: 'test'
5+
paths:
6+
/:
7+
get:
8+
responses:
9+
default:
10+
description: 'test'
11+
parameters:
12+
- in: header
13+
name: Authorization
14+
content:
15+
application/xml: {}

0 commit comments

Comments
 (0)