Skip to content

Commit

Permalink
feat(apidom-ls): path template match parameter object lint
Browse files Browse the repository at this point in the history
  • Loading branch information
kowalczyk-krzysztof committed Dec 14, 2023
1 parent 30df7c8 commit 678e3c0
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 3 deletions.
34 changes: 31 additions & 3 deletions packages/apidom-ls/src/services/validation/linter-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
ObjectElement,
} from '@swagger-api/apidom-core';
import { CompletionItem } from 'vscode-languageserver-types';
import { test } from 'openapi-path-templating';
import { test, parse } from 'openapi-path-templating';

// eslint-disable-next-line import/no-cycle
import {
Expand Down Expand Up @@ -1009,9 +1009,37 @@ export const standardLinterfunctions: FunctionItem[] = [
functionName: 'apilintOpenAPIPathTemplateValid',
function: (element: Element) => {
if (isStringElement(element)) {
return true;
const parseResult = parse(toValue(element));
const parts: string[] = [];
parseResult.ast.translate(parts);

const templateExpressions = parts
.filter((part) => part[0] === 'template-expression')
.map((part) => part[1].slice(1, -1));

if (templateExpressions.length === 0) {
return true;
}

const httpVerbsWithParameters: {
[key: string]: {
parameters: {
name: string;
}[];
};
} = element.parent.toValue().value;

const allExpressionsHaveMatchingParameter = Object.values(httpVerbsWithParameters).every(
({ parameters }) => {
return templateExpressions.every((expression) =>
parameters.find(({ name }) => name === expression),
);
},
);
return allExpressionsHaveMatchingParameter;
}
return true;

return false;
},
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
openapi: 3.0.0
info:
title: Foo
version: 0.1.0
paths:
/foo/bar/{baz}/test/{foo_id}/baz/{bar_id}:
delete:
summary: Delete foo bar baz
operationId: >-
deleteFooBarBaz
parameters:
- name: foo_id
in: path
required: true
schema:
type: string
format: uuid
title: Foo Id
- name: bar_id
in: path
required: true
schema:
type: string
format: uuid
title: Bar Id
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
/test/{foo_id}/{bar_id}:
get:
summary: Get test foo bar
operationId: >-
getTestFooBar
parameters:
- name: foo_id
in: path
required: true
schema:
type: string
format: uuid
title: Foo Id
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
42 changes: 42 additions & 0 deletions packages/apidom-ls/test/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3376,6 +3376,48 @@ describe('apidom-ls-validate', function () {

assert.deepEqual(result, expected as Diagnostic[]);

languageService.terminate();
});
it('oas / yaml - every path template should be defined', async function () {
const validationContext: ValidationContext = {
comments: DiagnosticSeverity.Error,
maxNumberOfProblems: 100,
relatedInformation: false,
};

const spec = fs
.readFileSync(
path.join(__dirname, 'fixtures', 'validation', 'oas', 'path-template-all-defined.yaml'),
)
.toString();
const doc: TextDocument = TextDocument.create(
'foo://bar/path-template-all-defined.yaml',
'yaml',
0,
spec,
);

const languageService: LanguageService = getLanguageService(contextNoSchema);

const result = await languageService.doValidation(doc, validationContext);
const expected: Diagnostic[] = [
{
range: { start: { line: 5, character: 2 }, end: { line: 5, character: 43 } },
message: 'path template expressions is not matched with Parameter Object(s)',
severity: 1,
code: 3040101,
source: 'apilint',
},
{
range: { start: { line: 31, character: 2 }, end: { line: 31, character: 25 } },
message: 'path template expressions is not matched with Parameter Object(s)',
severity: 1,
code: 3040101,
source: 'apilint',
},
];
assert.deepEqual(result, expected as Diagnostic[]);

languageService.terminate();
});
});

0 comments on commit 678e3c0

Please sign in to comment.