Skip to content

Commit 9a38571

Browse files
feat: add reference requestbodies rule
1 parent c485955 commit 9a38571

File tree

6 files changed

+118
-0
lines changed

6 files changed

+118
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,7 @@ enum ApilintCodes {
10711071
OPENAPI3_0_REFERENCE = 5260000,
10721072
OPENAPI3_0_REFERENCE_FIELD_$REF_FORMAT_URI = 5260100,
10731073
OPENAPI3_0_REFERENCE_FIELD_$REF_NO_SIBLINGS,
1074+
OPENAPI3_0_REFERENCE_FIELD_$REF_REQUEST_BODIES = 5260200,
10741075

10751076
OPENAPI3_0_LINK = 5270000,
10761077
OPENAPI3_0_LINK_FIELD_OPERATION_REF_FORMAT_URI = 5270100,
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 { OpenAPI3 } from '../../target-specs.ts';
6+
7+
const $ref3RequestBodiesLint: LinterMeta = {
8+
code: ApilintCodes.OPENAPI3_0_REFERENCE_FIELD_$REF_REQUEST_BODIES,
9+
source: 'apilint',
10+
message:
11+
'requestBody schema $refs must point to a position where a Schema Object can be legally placed',
12+
severity: DiagnosticSeverity.Error,
13+
linterFunction: 'parentExistFields',
14+
linterParams: [['requestBody']],
15+
marker: 'value',
16+
target: '$ref',
17+
data: {},
18+
targetSpecs: OpenAPI3,
19+
};
20+
21+
export default $ref3RequestBodiesLint;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import $ref2_0__3_0NoSiblingsLint from './$ref-2-0--3-0--no-siblings.ts';
33
import $ref3_1AllowedSiblingsLint from './$ref-3-1--allowed-siblings.ts';
44
import description3_1TypeLint from './description-3-1--type.ts';
55
import summary3_1TypeLint from './summary-3-1--type.ts';
6+
import $ref3RequestBodiesLint from './$ref-3-0--request-bodies.ts';
67

78
const lints = [
89
$refFormatURILint,
910
$ref2_0__3_0NoSiblingsLint,
1011
$ref3_1AllowedSiblingsLint,
12+
$ref3RequestBodiesLint,
1113
description3_1TypeLint,
1214
summary3_1TypeLint,
1315
];

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,20 @@ export const standardLinterfunctions: FunctionItem[] = [
176176
return true;
177177
},
178178
},
179+
{
180+
functionName: 'parentExistFields',
181+
function: (element: Element, keys: string[]): boolean => {
182+
const parent = element?.parent?.parent?.parent?.parent;
183+
if (parent && isObject(parent)) {
184+
for (const key of keys) {
185+
if (!parent.hasKey(key)) {
186+
return false;
187+
}
188+
}
189+
}
190+
return true;
191+
},
192+
},
179193
{
180194
functionName: 'existAnyOfFields',
181195
function: (element: Element, keys: string[], allowEmpty: boolean): boolean => {
@@ -421,6 +435,24 @@ export const standardLinterfunctions: FunctionItem[] = [
421435
return true;
422436
},
423437
},
438+
{
439+
functionName: 'apilintParentHasKey',
440+
function: (element: Element, elementsOrClasses: string[]): boolean => {
441+
if (element && !isObject(element)) {
442+
return false;
443+
}
444+
if (element && isObject(element)) {
445+
if (
446+
element.findElements((e) => !apilintElementOrClass(e, elementsOrClasses), {
447+
recursive: false,
448+
}).length > 0
449+
) {
450+
return false;
451+
}
452+
}
453+
return true;
454+
},
455+
},
424456
{
425457
functionName: 'apilintArray',
426458
function: (element: Element): boolean => {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
openapi: 3.0.0
2+
info:
3+
version: 1.0.0
4+
title: 'test'
5+
paths:
6+
/:
7+
post:
8+
responses:
9+
default:
10+
description: 'test'
11+
operationId: myId
12+
requestBody:
13+
content:
14+
application/json:
15+
schema:
16+
$ref: '#/components/requestBodies/MyBody/content/application~1json/schema'
17+
components:
18+
requestBodies:
19+
MyBody:
20+
content:
21+
application/json:
22+
schema:
23+
type: string

packages/apidom-ls/test/validate.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3032,6 +3032,45 @@ describe('apidom-ls-validate', function () {
30323032
languageService.terminate();
30333033
});
30343034

3035+
it('oas 3.0 / yaml - requestBody $refs must point to a position where can be legally placed', async function () {
3036+
const validationContext: ValidationContext = {
3037+
comments: DiagnosticSeverity.Error,
3038+
maxNumberOfProblems: 100,
3039+
relatedInformation: false,
3040+
};
3041+
3042+
const spec = fs
3043+
.readFileSync(
3044+
path.join(__dirname, 'fixtures', 'validation', 'oas', 'ref-request-bodies.yaml'),
3045+
)
3046+
.toString();
3047+
const doc: TextDocument = TextDocument.create(
3048+
'foo://bar/ref-request-bodies.yaml',
3049+
'yaml',
3050+
0,
3051+
spec,
3052+
);
3053+
3054+
const languageService: LanguageService = getLanguageService(contextNoSchema);
3055+
3056+
const result = await languageService.doValidation(doc, validationContext);
3057+
result[0].code = 'test';
3058+
const expected: Diagnostic[] = [
3059+
{
3060+
range: { start: { line: 15, character: 20 }, end: { line: 15, character: 88 } },
3061+
message:
3062+
'requestBody schema $refs must point to a position where a Schema Object can be legally placed',
3063+
severity: 1,
3064+
code: 'test',
3065+
source: 'apilint',
3066+
data: {},
3067+
},
3068+
];
3069+
assert.deepEqual(result, expected as Diagnostic[]);
3070+
3071+
languageService.terminate();
3072+
});
3073+
30353074
it('oas / yaml - test editor issue 3626 / inidrect ref', async function () {
30363075
const validationContext: ValidationContext = {
30373076
comments: DiagnosticSeverity.Error,

0 commit comments

Comments
 (0)