Skip to content

Commit

Permalink
feat: allow linting OpenAPI path templates (#3532)
Browse files Browse the repository at this point in the history
Refs #3517
  • Loading branch information
char0n authored Dec 13, 2023
1 parent ab11beb commit b0b03a2
Show file tree
Hide file tree
Showing 22 changed files with 1,011 additions and 28 deletions.
17 changes: 17 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/apidom-ls/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
"@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.87.0",
"@swagger-api/apidom-reference": "^0.87.0",
"@types/ramda": "~0.29.6",
"openapi-path-templating": "^1.2.0",
"ramda": "~0.29.1",
"ramda-adjunct": "^4.1.1",
"vscode-languageserver-protocol": "^3.17.2",
Expand Down
7 changes: 5 additions & 2 deletions packages/apidom-ls/src/config/codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,10 @@ enum ApilintCodes {

OPENAPI2_INFO = 3030000,

OPENAPI2_PATH_TEMPLATE = 3040000,
OPENAPI2_PATH_TEMPLATE_VALUE_WELL_FORMED = 3040100,
OPENAPI2_PATH_TEMPLATE_VALUE_VALID,

OPENAPI3_0 = 5000000,

OPENAPI3_0_OPENAPI_VALUE_PATTERN_3_0_0 = 5000100,
Expand Down Expand Up @@ -723,8 +727,7 @@ enum ApilintCodes {
OPENAPI3_O_SERVER_VARIABLE_FIELD_DESCRIPTION_TYPE = 5080300,

OPENAPI3_0_PATHS = 5090000,
OPENAPI3_0_PATHS_KEYS_PATTERN,
OPENAPI3_0_PATHS_VALUES_PATTERN,
OPENAPI3_0_PATHS_VALUES_TYPE,

OPENAPI_3_0_SECURITY_REQUIREMENT = 5100000,
OPENAPI_3_0_SECURITY_REQUIREMENT_KEYS_DEFINED,
Expand Down
2 changes: 2 additions & 0 deletions packages/apidom-ls/src/config/openapi/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import serverVariableMeta from './server-variable/meta';
import swaggerMeta from './swagger/meta';
import tagMeta from './tag/meta';
import xmlMeta from './xml/meta';
import pathTemplateMeta from './path-template/meta';
import schemaMeta from '../common/schema/meta';
import ApilintCodes from '../codes';

Expand Down Expand Up @@ -83,4 +84,5 @@ export default {
tag: tagMeta,
xml: xmlMeta,
schema: schemaMeta,
'path-template': pathTemplateMeta,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import valueWellFormedLint from './value--well-formed';
import valueValidLint from './value--valid';

const lints = [valueWellFormedLint, valueValidLint];

export default lints;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { DiagnosticSeverity } from 'vscode-languageserver-types';

import ApilintCodes from '../../../codes';
import { LinterMeta } from '../../../../apidom-language-types';
import { OpenAPI } from '../../target-specs';

const valueValidLint: LinterMeta = {
code: ApilintCodes.OPENAPI2_PATH_TEMPLATE_VALUE_VALID,
source: 'apilint',
message: 'path template expressions is not matched with Parameter Object(s)',
severity: DiagnosticSeverity.Error,
linterFunction: 'apilintOpenAPIPathTemplateValid',
marker: 'value',
targetSpecs: OpenAPI,
conditions: [
{
function: 'apilintOpenAPIPathTemplateWellFormed',
params: [true],
},
],
};

export default valueValidLint;
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { DiagnosticSeverity } from 'vscode-languageserver-types';

import ApilintCodes from '../../../codes';
import { LinterMeta } from '../../../../apidom-language-types';
import { OpenAPI } from '../../target-specs';

const valueWellFormedLint: LinterMeta = {
code: ApilintCodes.OPENAPI2_PATH_TEMPLATE_VALUE_WELL_FORMED,
source: 'apilint',
message: "'path' must begin with '/' and be relative to an individual endpoint",
severity: DiagnosticSeverity.Error,
linterFunction: 'apilintOpenAPIPathTemplateWellFormed',
linterParams: [false],
marker: 'value',
targetSpecs: OpenAPI,
};

export default valueWellFormedLint;
8 changes: 8 additions & 0 deletions packages/apidom-ls/src/config/openapi/path-template/meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import lint from './lint';
import { FormatMeta } from '../../../apidom-language-types';

const meta: FormatMeta = {
lint,
};

export default meta;
3 changes: 1 addition & 2 deletions packages/apidom-ls/src/config/openapi/paths/lint/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import keysPatternLint from './keys--pattern';
import valuesTypeLint from './values--type';

const lints = [valuesTypeLint, keysPatternLint];
const lints = [valuesTypeLint];

export default lints;
19 changes: 0 additions & 19 deletions packages/apidom-ls/src/config/openapi/paths/lint/keys--pattern.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { LinterMeta } from '../../../../apidom-language-types';
import { OpenAPI3 } from '../../target-specs';

const valuesTypeLint: LinterMeta = {
code: ApilintCodes.OPENAPI3_0_PATHS_VALUES_PATTERN,
code: ApilintCodes.OPENAPI3_0_PATHS_VALUES_TYPE,
source: 'apilint',
message: 'Paths Object values must be of Path Item Object shape',
severity: DiagnosticSeverity.Error,
Expand Down
21 changes: 21 additions & 0 deletions packages/apidom-ls/src/services/validation/linter-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import {
Element,
ArrayElement,
MemberElement,
isStringElement,
filter,
toValue,
ArraySlice,
ObjectElement,
} from '@swagger-api/apidom-core';
import { CompletionItem } from 'vscode-languageserver-types';
import { test } from 'openapi-path-templating';

// eslint-disable-next-line import/no-cycle
import {
Expand Down Expand Up @@ -993,4 +995,23 @@ export const standardLinterfunctions: FunctionItem[] = [
return true;
},
},
{
functionName: 'apilintOpenAPIPathTemplateWellFormed',
function: (element: Element, strict = false) => {
if (isStringElement(element)) {
const pathTemplate = toValue(element);
return test(pathTemplate, { strict });
}
return true;
},
},
{
functionName: 'apilintOpenAPIPathTemplateValid',
function: (element: Element) => {
if (isStringElement(element)) {
return true;
}
return true;
},
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,43 @@ exports[`given OpenAPI 3.1 definition should decorate with API Design Systems St
"content": {
"key": {
"element": "string",
"meta": {
"classes": {
"element": "array",
"content": [
{
"element": "string",
"content": "openapi-path-template"
},
{
"element": "string",
"content": "path-template"
}
]
}
},
"content": "/path1"
},
"value": {
"element": "pathItem",
"meta": {
"path": {
"element": "string",
"meta": {
"classes": {
"element": "array",
"content": [
{
"element": "string",
"content": "openapi-path-template"
},
{
"element": "string",
"content": "path-template"
}
]
}
},
"content": "/path1"
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import stampit from 'stampit';
import { test, always } from 'ramda';
import { T as stubTrue, always } from 'ramda';
import { ObjectElement, StringElement, cloneDeep } from '@swagger-api/apidom-core';

import PathsElement from '../../../../elements/Paths';
Expand All @@ -10,7 +10,7 @@ import { isPathItemElement } from '../../../../predicates';

const PathsVisitor = stampit(PatternedFieldsVisitor, FallbackVisitor, {
props: {
fieldPatternPredicate: test(/^\/(?<path>.*)$/),
fieldPatternPredicate: stubTrue,
specPath: always(['document', 'objects', 'PathItem']),
canSupportSpecificationExtensions: true,
},
Expand All @@ -26,6 +26,8 @@ const PathsVisitor = stampit(PatternedFieldsVisitor, FallbackVisitor, {
this.element
.filter(isPathItemElement)
.forEach((pathItemElement: PathItemElement, key: StringElement) => {
key.classes.push('openapi-path-template');
key.classes.push('path-template');
pathItemElement.setMetaProperty('path', cloneDeep(key));
});

Expand Down
Loading

0 comments on commit b0b03a2

Please sign in to comment.