Skip to content

Commit

Permalink
fix(ls): process schema 'null' / 'nullable' depending on spec version
Browse files Browse the repository at this point in the history
  • Loading branch information
frantuma committed Jul 25, 2023
1 parent 5127577 commit d053dca
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/apidom-ls/src/config/codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ enum ApilintCodes {
SCHEMA_EXAMPLES,
SCHEMA_EXTERNAL_DOCS,
SCHEMA_EXAMPLE_DEPRECATED,
SCHEMA_TYPE_OPENAPI_3_0,
SCHEMA_NULLABLE_NOT_RECOMMENDED,

DUPLICATE_KEYS = 14999,
NOT_ALLOWED_FIELDS = 15000,
Expand Down
10 changes: 10 additions & 0 deletions packages/apidom-ls/src/config/common/schema/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,16 @@ const completion: ApidomCompletionItem[] = [
format: CompletionFormat.QUOTED,
type: CompletionType.VALUE,
insertTextFormat: 2,
targetSpecs: [
{ namespace: 'asyncapi', version: '2.0.0' },
{ namespace: 'asyncapi', version: '2.1.0' },
{ namespace: 'asyncapi', version: '2.2.0' },
{ namespace: 'asyncapi', version: '2.3.0' },
{ namespace: 'asyncapi', version: '2.4.0' },
{ namespace: 'asyncapi', version: '2.5.0' },
{ namespace: 'asyncapi', version: '2.6.0' },
{ namespace: 'openapi', version: '3.1.0' },
],
},
{
target: 'type',
Expand Down
4 changes: 4 additions & 0 deletions packages/apidom-ls/src/config/common/schema/lint/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import minPropertiesTypeLint from './min-properties--type';
import minimumPatternLint from './minimum--pattern';
import multipleOfTypeLint from './multiple-of--type';
import notTypeLint from './not--type';
import nullableNotRecommendedLint from './nullable--not-recommended';
import oneOfTypeLint from './one-of--type';
import patternTypeLint from './pattern--type';
import patternPropertiesKeysRegexpLint from './pattern-properties--keys-regexp';
Expand All @@ -56,6 +57,7 @@ import thenNonIfLint from './then--non-if';
import thenTypeLint from './then--type';
import titleTypeLint from './title--type';
import typeTypeLint from './type--type';
import typeTypeOpenAPI3_0Lint from './type--type-openapi-3-0';
import uniqueItemsNonArrayLint from './unique-items--non-array';
import uniqueItemsTypeLint from './unique-items--type';
import writeOnlyTypeLint from './write-only--type';
Expand Down Expand Up @@ -102,6 +104,7 @@ const schemaLints = [
minimumPatternLint,
multipleOfTypeLint,
notTypeLint,
nullableNotRecommendedLint,
oneOfTypeLint,
patternTypeLint,
patternPropertiesKeysRegexpLint,
Expand All @@ -120,6 +123,7 @@ const schemaLints = [
thenTypeLint,
titleTypeLint,
typeTypeLint,
typeTypeOpenAPI3_0Lint,
uniqueItemsNonArrayLint,
uniqueItemsTypeLint,
writeOnlyTypeLint,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { DiagnosticSeverity } from 'vscode-languageserver-types';

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

const nullableNotRecommendedLint: LinterMeta = {
code: ApilintCodes.SCHEMA_NULLABLE_NOT_RECOMMENDED,
source: 'apilint',
message: 'nullable has no special meaning, if not set on purpose use `type="null"` instead',
severity: DiagnosticSeverity.Hint,
linterFunction: 'missingField',
linterParams: ['nullable'],
marker: 'key',
markerTarget: 'nullable',
targetSpecs: [
{ namespace: 'asyncapi', version: '2.0.0' },
{ namespace: 'asyncapi', version: '2.1.0' },
{ namespace: 'asyncapi', version: '2.2.0' },
{ namespace: 'asyncapi', version: '2.3.0' },
{ namespace: 'asyncapi', version: '2.4.0' },
{ namespace: 'asyncapi', version: '2.5.0' },
{ namespace: 'asyncapi', version: '2.6.0' },
{ namespace: 'openapi', version: '3.1.0' },
],
data: {
quickFix: [
{
message: 'remove nullable',
action: 'removeChild',
functionParams: ['nullable'],
target: 'parent',
},
],
},
};

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

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

// eslint-disable-next-line @typescript-eslint/naming-convention
const typeTypeOpenAPI3_0Lint: LinterMeta = {
code: ApilintCodes.SCHEMA_TYPE,
source: 'apilint',
message: 'type must be one of allowed values',
severity: DiagnosticSeverity.Error,
linterFunction: 'apilintValueOrArray',
linterParams: [['boolean', 'object', 'array', 'number', 'string', 'integer'], true],
marker: 'value',
target: 'type',
targetSpecs: [
{ namespace: 'openapi', version: '3.0.0' },
{ namespace: 'openapi', version: '3.0.1' },
{ namespace: 'openapi', version: '3.0.2' },
{ namespace: 'openapi', version: '3.0.3' },
],
data: {
quickFix: [
{
message: "update to 'boolean'",
action: 'updateValue',
functionParams: ['boolean'],
},
{
message: "update to 'object'",
action: 'updateValue',
functionParams: ['object'],
},
{
message: "update to 'array'",
action: 'updateValue',
functionParams: ['array'],
},
{
message: "update to 'number'",
action: 'updateValue',
functionParams: ['null'],
},
{
message: "update to 'string'",
action: 'updateValue',
functionParams: ['string'],
},
{
message: "update to 'integer'",
action: 'updateValue',
functionParams: ['integer'],
},
],
},
};

export default typeTypeOpenAPI3_0Lint;
10 changes: 10 additions & 0 deletions packages/apidom-ls/src/config/common/schema/lint/type--type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ const typeTypeLint: LinterMeta = {
linterParams: [['null', 'boolean', 'object', 'array', 'number', 'string', 'integer'], true],
marker: 'value',
target: 'type',
targetSpecs: [
{ namespace: 'asyncapi', version: '2.0.0' },
{ namespace: 'asyncapi', version: '2.1.0' },
{ namespace: 'asyncapi', version: '2.2.0' },
{ namespace: 'asyncapi', version: '2.3.0' },
{ namespace: 'asyncapi', version: '2.4.0' },
{ namespace: 'asyncapi', version: '2.5.0' },
{ namespace: 'asyncapi', version: '2.6.0' },
{ namespace: 'openapi', version: '3.1.0' },
],
data: {
quickFix: [
{
Expand Down
10 changes: 10 additions & 0 deletions packages/apidom-ls/test/complete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,16 @@ describe('apidom-ls-complete', function () {
kind: 12,
insertTextFormat: 2,
filterText: '[integer, string]',
targetSpecs: [
{ namespace: 'asyncapi', version: '2.0.0' },
{ namespace: 'asyncapi', version: '2.1.0' },
{ namespace: 'asyncapi', version: '2.2.0' },
{ namespace: 'asyncapi', version: '2.3.0' },
{ namespace: 'asyncapi', version: '2.4.0' },
{ namespace: 'asyncapi', version: '2.5.0' },
{ namespace: 'asyncapi', version: '2.6.0' },
{ namespace: 'openapi', version: '3.1.0' },
],
textEdit: {
range: {
start: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
openapi: 3.1.0
info:
title: test
version: 1.0.0
paths:
/a:
get:
operationId: aget
components:
schemas:
foo:
type: string
nullable: true
39 changes: 39 additions & 0 deletions packages/apidom-ls/test/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3136,4 +3136,43 @@ describe('apidom-ls-validate', function () {

languageService.terminate();
});

it('oas / yaml - test nullable hint for openapi 3.1', async function () {
const validationContext: ValidationContext = {
comments: DiagnosticSeverity.Error,
maxNumberOfProblems: 100,
relatedInformation: false,
};

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

const languageService: LanguageService = getLanguageService(contextNoSchema);

const result = await languageService.doValidation(doc, validationContext);
const expected: Diagnostic[] = [
{
range: { start: { line: 12, character: 6 }, end: { line: 12, character: 14 } },
message: 'nullable has no special meaning, if not set on purpose use `type="null"` instead',
severity: 4,
code: 10071,
source: 'apilint',
data: {
quickFix: [
{
message: 'remove nullable',
action: 'removeChild',
functionParams: ['nullable'],
target: 'parent',
},
],
},
},
];
assert.deepEqual(result, expected as Diagnostic[]);

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

0 comments on commit d053dca

Please sign in to comment.