Skip to content

Commit 573e52f

Browse files
feat(ls): add schema validation rules (#4992)
1 parent d5b16f8 commit 573e52f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1781
-19
lines changed

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ enum ApilintCodes {
6969
SCHEMA_MISSING_CORE_FIELDS,
7070
SCHEMA_NULLABLE,
7171
SCHEMA_XML,
72+
SCHEMA_ENUM_TYPE,
73+
SCHEMA_ENUM_DEFAULT_VALUE,
74+
SCHEMA_MINIMUM_VALUE,
75+
SCHEMA_MIN_LENGTH_VALUE,
76+
SCHEMA_MIN_PROPERTIES_VALUE,
77+
SCHEMA_MIN_ITEMS_VALUE,
78+
SCHEMA_READONLY_WRITEONLY,
79+
SCHEMA_READONLY_REQUIRED,
80+
SCHEMA_PATTERN_REG_EXP_ANCHORS,
81+
SCHEMA_ITEMS_REQUIRED,
7282

7383
DUPLICATE_KEYS = 14999,
7484
NOT_ALLOWED_FIELDS = 15000,
@@ -739,6 +749,8 @@ enum ApilintCodes {
739749
OPENAPI2_PARAMETER_FIELD_MIN_LENGTH_TYPE = 3101600,
740750
OPENAPI2_PARAMETER_FIELD_UNIQUE_ITEMS_TYPE = 3101700,
741751
OPENAPI2_PARAMETER_FIELD_ENUM_TYPE = 3101800,
752+
OPENAPI2_PARAMETER_FIELD_ENUM_TYPE_VALUE,
753+
OPENAPI2_PARAMETER_FIELD_ENUM_DEFAULT_VALUE,
742754
OPENAPI2_PARAMETER_FIELD_MULTIPLE_OF_TYPE = 3101900,
743755
OPENAPI2_PARAMETER_FIELD_IN_PATH_TEMPLATE = 3102000,
744756
OPENAPI2_PARAMETER_FIELD_NAME_UNIQUE = 3103000,
@@ -753,12 +765,15 @@ enum ApilintCodes {
753765
OPENAPI2_ITEMS_FIELD_MAXIMUM_TYPE = 3110500,
754766
OPENAPI2_ITEMS_FIELD_EXCLUSIVE_MAXIMUM_TYPE = 3110600,
755767
OPENAPI2_ITEMS_FIELD_MINIMUM_TYPE = 3110700,
768+
OPENAPI2_ITEMS_FIELD_MINIMUM_VALUE = 3110701,
756769
OPENAPI2_ITEMS_FIELD_EXCLUSIVE_MINIMUM_TYPE = 3110800,
757770
OPENAPI2_ITEMS_FIELD_MAX_LENGTH_TYPE = 3110900,
758771
OPENAPI2_ITEMS_FIELD_MIN_LENGTH_TYPE = 3111000,
772+
OPENAPI2_ITEMS_FIELD_MIN_LENGTH_VALUE,
759773
OPENAPI2_ITEMS_FIELD_PATTERN_TYPE = 3111100,
760774
OPENAPI2_ITEMS_FIELD_MAX_ITEMS_TYPE = 3111200,
761775
OPENAPI2_ITEMS_FIELD_MIN_ITEMS_TYPE = 3111300,
776+
OPENAPI2_ITEMS_FIELD_MIN_ITEMS_VALUE,
762777
OPENAPI2_ITEMS_FIELD_UNIQUE_ITEMS_TYPE = 3111400,
763778
OPENAPI2_ITEMS_FIELD_ENUM_TYPE = 3111500,
764779
OPENAPI2_ITEMS_FIELD_MULTIPLE_OF_TYPE = 3111600,
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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, OpenAPI30 } from '../../../openapi/target-specs.ts';
6+
7+
const enumDefaultValueLint: LinterMeta = {
8+
code: ApilintCodes.SCHEMA_ENUM_DEFAULT_VALUE,
9+
source: 'apilint',
10+
message: 'Default values must be present in enum',
11+
severity: DiagnosticSeverity.Error,
12+
linterFunction: 'apilintContainsDefaultValue',
13+
marker: 'value',
14+
target: 'enum',
15+
data: {},
16+
targetSpecs: [...OpenAPI2, ...OpenAPI30],
17+
};
18+
19+
export default enumDefaultValueLint;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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, OpenAPI30 } from '../../../openapi/target-specs.ts';
6+
7+
const enumTypeLint: LinterMeta = {
8+
code: ApilintCodes.SCHEMA_ENUM_TYPE,
9+
source: 'apilint',
10+
message: "enum value should conform to its schema's type",
11+
severity: DiagnosticSeverity.Warning,
12+
linterFunction: 'apilintArrayOfType',
13+
linterParams: ['', false, true],
14+
marker: 'value',
15+
target: 'enum',
16+
data: {},
17+
targetSpecs: [...OpenAPI2, ...OpenAPI30],
18+
};
19+
20+
export default enumTypeLint;

packages/apidom-ls/src/config/common/schema/lint/index.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import $idFormatURILint from './$id--format-uri.ts';
44
import $refValidLint from './$ref--valid.ts';
55
import $refNoSiblingsLint from './$ref--no-siblings.ts';
66
import $ref3RequestBodiesLint from './$ref-3-0--request-bodies.ts';
7+
import $refNotUsedLint from './$ref--not-used.ts';
78
import additionalItemsNonArrayLint from './additional-items--non-array.ts';
89
import additionalItemsTypeLint from './additional-items--type.ts';
910
import additionalItemsTypeOpenAPI3_1__AsyncAPI2Lint from './additional-items--type-openapi-3-1--asyncapi-2.ts';
@@ -34,7 +35,9 @@ import formatTypeLint from './format--type.ts';
3435
import ifNonThenLint from './if--non-then.ts';
3536
import ifTypeLint from './if--type.ts';
3637
import itemsNonArrayLint from './items--non-array.ts';
37-
import itemsTypeLint from './items--type.ts';
38+
import itemsRequiredLint from './items--required.ts';
39+
import itemsTypeOpenAPI31AsyncAPI2Lint from './items--type-3-1-asyncapi-2.ts';
40+
import itemsTypeOpenAPI2OpenAPI30Lint from './items--type-2-0-3-0.ts';
3841
import maxItemsNonArrayLint from './max-items--non-array.ts';
3942
import maxItemsTypeLint from './max-items--type.ts';
4043
import maxLengthNonStringLint from './max-length--non-string.ts';
@@ -82,7 +85,15 @@ import uniqueItemsNonArrayLint from './unique-items--non-array.ts';
8285
import uniqueItemsTypeLint from './unique-items--type.ts';
8386
import writeOnlyTypeLint from './write-only--type.ts';
8487
import exampleDeprecatedLint from './example--deprecated.ts';
85-
import $refNotUsedLint from './$ref--not-used.ts';
88+
import enumTypeLint from './enum--type.ts';
89+
import enumDefaultValueLint from './enum--default-value.ts';
90+
import minimumValueLint from './minimum-maximum--value.ts';
91+
import minLengthValueLint from './min-length-max-length--value.ts';
92+
import minPropertiesValueLint from './min-properties-max-properties--value.ts';
93+
import minItemsValueLint from './min-items-max-items--value.ts';
94+
import readOnlyWriteOnlyLint from './read-only-write-only-3-0.ts';
95+
import readOnlyRequiredLint from './required--read-only-2.ts';
96+
import patternValueLint from './pattern--value-2.ts';
8697

8798
const schemaLints = [
8899
allowedFieldsOpenAPI2_0Lint,
@@ -111,6 +122,8 @@ const schemaLints = [
111122
elseNonIfLint,
112123
elseTypeLint,
113124
enumUniqueLint,
125+
enumDefaultValueLint,
126+
enumTypeLint,
114127
examplesTypeLint,
115128
exclusiveMaximumTypeNumberLint,
116129
exclusiveMaximumTypeBooleanLint,
@@ -122,7 +135,9 @@ const schemaLints = [
122135
ifNonThenLint,
123136
ifTypeLint,
124137
itemsNonArrayLint,
125-
itemsTypeLint,
138+
itemsRequiredLint,
139+
itemsTypeOpenAPI31AsyncAPI2Lint,
140+
itemsTypeOpenAPI2OpenAPI30Lint,
126141
maxItemsNonArrayLint,
127142
maxItemsTypeLint,
128143
maxLengthNonStringLint,
@@ -135,6 +150,10 @@ const schemaLints = [
135150
minPropertiesNonObjectLint,
136151
minPropertiesTypeLint,
137152
minimumTypeLint,
153+
minimumValueLint,
154+
minLengthValueLint,
155+
minPropertiesValueLint,
156+
minItemsValueLint,
138157
missingCoreFieldsOpenAPI2_0Lint,
139158
missingCoreFieldsOpenAPI3_0Lint,
140159
missingCoreFieldsOpenAPI3_1Lint,
@@ -150,13 +169,16 @@ const schemaLints = [
150169
patternPropertiesKeysRegexpLint,
151170
patternPropertiesNonObjectLint,
152171
patternPropertiesTypeLint,
172+
patternValueLint,
153173
patternPropertiesValuesTypeLint,
154174
propertiesTypeLint,
155175
propertiesValuesTypeLint,
156176
propertiesValuesTypeOpenAPI3_1__AsyncAPI2Lint,
157177
propertyNamesNonObjectLint,
158178
propertyNamesTypeLint,
159179
readOnlyTypeLint,
180+
readOnlyWriteOnlyLint,
181+
readOnlyRequiredLint,
160182
requiredDefinedLint,
161183
requiredNonObjectLint,
162184
requiredTypeLint,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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, OpenAPI30 } from '../../../openapi/target-specs.ts';
6+
7+
const itemsRequiredLint: LinterMeta = {
8+
code: ApilintCodes.SCHEMA_ITEMS_REQUIRED,
9+
source: 'apilint',
10+
message: "should have an 'items' if 'type'=array",
11+
severity: DiagnosticSeverity.Error,
12+
linterFunction: 'hasRequiredField',
13+
linterParams: ['items'],
14+
marker: 'key',
15+
conditions: [
16+
{
17+
targets: [{ path: 'type' }],
18+
function: 'apilintContainsValue',
19+
params: ['array'],
20+
},
21+
{
22+
function: 'missingField',
23+
params: ['$ref'],
24+
},
25+
],
26+
data: {
27+
quickFix: [
28+
{
29+
message: "add 'items' field",
30+
action: 'addChild',
31+
snippetYaml: 'items: \n \n',
32+
snippetJson: '"items": {\n \n },\n',
33+
},
34+
],
35+
},
36+
targetSpecs: [...OpenAPI2, ...OpenAPI30],
37+
};
38+
39+
export default itemsRequiredLint;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { DiagnosticSeverity } from 'vscode-languageserver-types';
2+
3+
import ApilintCodes from '../../../codes.ts';
4+
import { LinterMeta } from '../../../../apidom-language-types.ts';
5+
import { OpenAPI30, OpenAPI2 } from '../../../openapi/target-specs.ts';
6+
7+
const itemsTypeOpenAPI2OpenAPI30Lint: LinterMeta = {
8+
code: ApilintCodes.SCHEMA_ITEMS,
9+
source: 'apilint',
10+
message: "'items' must be an object",
11+
severity: DiagnosticSeverity.Error,
12+
linterFunction: 'apilintElementOrClass',
13+
linterParams: [['schema']],
14+
marker: 'value',
15+
target: 'items',
16+
data: {},
17+
targetSpecs: [...OpenAPI2, ...OpenAPI30],
18+
};
19+
20+
export default itemsTypeOpenAPI2OpenAPI30Lint;

packages/apidom-ls/src/config/common/schema/lint/items--type.ts renamed to packages/apidom-ls/src/config/common/schema/lint/items--type-3-1-asyncapi-2.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { DiagnosticSeverity } from 'vscode-languageserver-types';
33
import ApilintCodes from '../../../codes.ts';
44
import { LinterMeta } from '../../../../apidom-language-types.ts';
55
import { AsyncAPI2 } from '../../../asyncapi/target-specs.ts';
6-
import { OpenAPI2, OpenAPI3 } from '../../../openapi/target-specs.ts';
6+
import { OpenAPI31 } from '../../../openapi/target-specs.ts';
77

8-
const itemsTypeLint: LinterMeta = {
8+
const itemsTypeOpenAPI31AsyncAPI2Lint: LinterMeta = {
99
code: ApilintCodes.SCHEMA_ITEMS,
1010
source: 'apilint',
1111
message: 'items must be a schema or array of schemas',
@@ -15,7 +15,7 @@ const itemsTypeLint: LinterMeta = {
1515
marker: 'value',
1616
target: 'items',
1717
data: {},
18-
targetSpecs: [...AsyncAPI2, ...OpenAPI2, ...OpenAPI3],
18+
targetSpecs: [...AsyncAPI2, ...OpenAPI31],
1919
};
2020

21-
export default itemsTypeLint;
21+
export default itemsTypeOpenAPI31AsyncAPI2Lint;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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, OpenAPI30 } from '../../../openapi/target-specs.ts';
6+
7+
const minItemsValueLint: LinterMeta = {
8+
code: ApilintCodes.SCHEMA_MIN_ITEMS_VALUE,
9+
source: 'apilint',
10+
message: "'minItems' must be a lower value than 'maxItems'",
11+
severity: DiagnosticSeverity.Error,
12+
linterFunction: 'apilintSchemaMinimumMaximum',
13+
linterParams: ['minItems', 'maxItems'],
14+
marker: 'value',
15+
target: 'minItems',
16+
data: {},
17+
targetSpecs: [...OpenAPI2, ...OpenAPI30],
18+
};
19+
20+
export default minItemsValueLint;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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, OpenAPI30 } from '../../../openapi/target-specs.ts';
6+
7+
const minLengthValueLint: LinterMeta = {
8+
code: ApilintCodes.SCHEMA_MIN_LENGTH_VALUE,
9+
source: 'apilint',
10+
message: "'minLength' must be a lower value than 'maxLength'",
11+
severity: DiagnosticSeverity.Error,
12+
linterFunction: 'apilintSchemaMinimumMaximum',
13+
linterParams: ['minLength', 'maxLength'],
14+
marker: 'value',
15+
target: 'minLength',
16+
data: {},
17+
targetSpecs: [...OpenAPI2, ...OpenAPI30],
18+
};
19+
20+
export default minLengthValueLint;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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, OpenAPI30 } from '../../../openapi/target-specs.ts';
6+
7+
const minPropertiesValueLint: LinterMeta = {
8+
code: ApilintCodes.SCHEMA_MIN_PROPERTIES_VALUE,
9+
source: 'apilint',
10+
message: "'minProperties' must be a lower value than 'maxProperties'",
11+
severity: DiagnosticSeverity.Error,
12+
linterFunction: 'apilintSchemaMinimumMaximum',
13+
linterParams: ['minProperties', 'maxProperties'],
14+
marker: 'value',
15+
target: 'minProperties',
16+
data: {},
17+
targetSpecs: [...OpenAPI2, ...OpenAPI30],
18+
};
19+
20+
export default minPropertiesValueLint;

0 commit comments

Comments
 (0)