@redocly/openapi-core 1.0.0-beta.124 → 1.0.0-beta.126

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { Assertion, Assertions } from '../.';
1
+ import { Assertions } from '../.';
2
2
 
3
3
  const opts = {
4
4
  '0': {
@@ -1,5 +1,8 @@
1
1
  import { Assertion, AssertionDefinition } from '..';
2
- import { isOrdered, buildVisitorObject, getIntersectionLength } from '../utils';
2
+ import { AssertionContext } from '../../../../config';
3
+ import { Location } from '../../../../ref-utils';
4
+ import { Source } from '../../../../resolve';
5
+ import { isOrdered, buildVisitorObject, getIntersectionLength, runAssertion } from '../utils';
3
6
 
4
7
  describe('Oas3 assertions', () => {
5
8
  describe('Utils', () => {
@@ -111,5 +114,123 @@ describe('Oas3 assertions', () => {
111
114
  `);
112
115
  });
113
116
  });
117
+
118
+ describe('runAssertion', () => {
119
+ const baseLocation = new Location(jest.fn() as any as Source, 'pointer');
120
+ const rawLocation = new Location(jest.fn() as any as Source, 'raw-pointer');
121
+ // { $ref: 'text' }, true, {...assertionProperties, rawValue: { $ref: 'text' }}
122
+
123
+ const ctxStub = {
124
+ location: baseLocation,
125
+ node: {
126
+ property: 'test',
127
+ },
128
+ rawNode: {
129
+ property: 'test',
130
+ },
131
+ rawLocation: rawLocation,
132
+ } as AssertionContext;
133
+
134
+ it('should catch error cause property should be not defined with assertionProperty', () => {
135
+ const result = runAssertion({
136
+ assert: {
137
+ name: 'defined',
138
+ conditions: false,
139
+ runsOnKeys: true,
140
+ runsOnValues: false,
141
+ },
142
+ ctx: ctxStub,
143
+ assertionProperty: 'property',
144
+ });
145
+
146
+ const expectedLocation = new Location(jest.fn() as any as Source, 'pointer/property');
147
+
148
+ expect(JSON.stringify(result)).toEqual(
149
+ JSON.stringify([
150
+ {
151
+ message: 'Should be not defined',
152
+ location: expectedLocation,
153
+ },
154
+ ])
155
+ );
156
+ });
157
+
158
+ it('should pass cause property defined', () => {
159
+ const result = runAssertion({
160
+ assert: {
161
+ name: 'defined',
162
+ conditions: true,
163
+ runsOnKeys: true,
164
+ runsOnValues: false,
165
+ },
166
+ ctx: ctxStub,
167
+ assertionProperty: 'property',
168
+ });
169
+
170
+ expect(result).toEqual([]);
171
+ });
172
+
173
+ it('should failure cause property does not passed', () => {
174
+ const result = runAssertion({
175
+ assert: {
176
+ name: 'defined',
177
+ conditions: false,
178
+ runsOnKeys: true,
179
+ runsOnValues: false,
180
+ },
181
+ ctx: ctxStub,
182
+ });
183
+
184
+ expect(result).toEqual([
185
+ {
186
+ message: 'Should be not defined',
187
+ location: baseLocation,
188
+ },
189
+ ]);
190
+ });
191
+
192
+ it('should pass with ref assertion cause it is defined', () => {
193
+ const result = runAssertion({
194
+ assert: {
195
+ name: 'ref',
196
+ conditions: true,
197
+ runsOnKeys: true,
198
+ runsOnValues: false,
199
+ },
200
+ ctx: {
201
+ ...ctxStub,
202
+ rawNode: {
203
+ $ref: 'test',
204
+ },
205
+ },
206
+ });
207
+
208
+ expect(result).toEqual([]);
209
+ });
210
+
211
+ it('should failure with ref assertion cause it is defined', () => {
212
+ const result = runAssertion({
213
+ assert: {
214
+ name: 'ref',
215
+ conditions: false,
216
+ runsOnKeys: true,
217
+ runsOnValues: false,
218
+ },
219
+ ctx: {
220
+ ...ctxStub,
221
+ rawNode: {
222
+ $ref: 'test',
223
+ },
224
+ },
225
+ });
226
+
227
+ expect(result).toEqual([
228
+ {
229
+ message: 'should not use $ref',
230
+ location: rawLocation,
231
+ },
232
+ ]);
233
+ });
234
+ });
114
235
  });
115
236
  });
@@ -1,4 +1,4 @@
1
- import { AssertResult, CustomFunction } from 'core/src/config/types';
1
+ import { AssertionContext, AssertResult, CustomFunction } from 'core/src/config/types';
2
2
  import { Location } from '../../../ref-utils';
3
3
  import { isPlainObject, isString as runOnValue, isTruthy } from '../../../utils';
4
4
  import {
@@ -9,12 +9,9 @@ import {
9
9
  regexFromString,
10
10
  } from './utils';
11
11
 
12
- export type AssertionFn = (
13
- value: any,
14
- condition: any,
15
- baseLocation: Location,
16
- rawValue?: any
17
- ) => AssertResult[];
12
+ export type AssertionFnContext = AssertionContext & { baseLocation: Location; rawValue?: any };
13
+
14
+ export type AssertionFn = (value: any, condition: any, ctx: AssertionFnContext) => AssertResult[];
18
15
 
19
16
  export type Asserts = {
20
17
  pattern: AssertionFn;
@@ -69,7 +66,7 @@ export const runOnValuesSet = new Set<keyof Asserts>([
69
66
  ]);
70
67
 
71
68
  export const asserts: Asserts = {
72
- pattern: (value: string | string[], condition: string, baseLocation: Location) => {
69
+ pattern: (value: string | string[], condition: string, { baseLocation }: AssertionFnContext) => {
73
70
  if (typeof value === 'undefined' || isPlainObject(value)) return []; // property doesn't exist or is an object, no need to lint it with this assert
74
71
  const values = Array.isArray(value) ? value : [value];
75
72
  const regex = regexFromString(condition);
@@ -84,7 +81,11 @@ export const asserts: Asserts = {
84
81
  )
85
82
  .filter(isTruthy);
86
83
  },
87
- notPattern: (value: string | string[], condition: string, baseLocation: Location) => {
84
+ notPattern: (
85
+ value: string | string[],
86
+ condition: string,
87
+ { baseLocation }: AssertionFnContext
88
+ ) => {
88
89
  if (typeof value === 'undefined' || isPlainObject(value)) return []; // property doesn't exist or is an object, no need to lint it with this assert
89
90
  const values = Array.isArray(value) ? value : [value];
90
91
  const regex = regexFromString(condition);
@@ -99,7 +100,7 @@ export const asserts: Asserts = {
99
100
  )
100
101
  .filter(isTruthy);
101
102
  },
102
- enum: (value: string | string[], condition: string[], baseLocation: Location) => {
103
+ enum: (value: string | string[], condition: string[], { baseLocation }: AssertionFnContext) => {
103
104
  if (typeof value === 'undefined' || isPlainObject(value)) return []; // property doesn't exist or is an object, no need to lint it with this assert
104
105
  const values = Array.isArray(value) ? value : [value];
105
106
  return values
@@ -112,7 +113,11 @@ export const asserts: Asserts = {
112
113
  )
113
114
  .filter(isTruthy);
114
115
  },
115
- defined: (value: string | undefined, condition: boolean = true, baseLocation: Location) => {
116
+ defined: (
117
+ value: string | undefined,
118
+ condition: boolean = true,
119
+ { baseLocation }: AssertionFnContext
120
+ ) => {
116
121
  const isDefined = typeof value !== 'undefined';
117
122
  const isValid = condition ? isDefined : !isDefined;
118
123
  return isValid
@@ -124,7 +129,7 @@ export const asserts: Asserts = {
124
129
  },
125
130
  ];
126
131
  },
127
- required: (value: string[], keys: string[], baseLocation: Location) => {
132
+ required: (value: string[], keys: string[], { baseLocation }: AssertionFnContext) => {
128
133
  return keys
129
134
  .map(
130
135
  (requiredKey) =>
@@ -135,7 +140,11 @@ export const asserts: Asserts = {
135
140
  )
136
141
  .filter(isTruthy);
137
142
  },
138
- disallowed: (value: string | string[], condition: string[], baseLocation: Location) => {
143
+ disallowed: (
144
+ value: string | string[],
145
+ condition: string[],
146
+ { baseLocation }: AssertionFnContext
147
+ ) => {
139
148
  if (typeof value === 'undefined' || isPlainObject(value)) return []; // property doesn't exist or is an object, no need to lint it with this assert
140
149
  const values = Array.isArray(value) ? value : [value];
141
150
  return values
@@ -151,7 +160,7 @@ export const asserts: Asserts = {
151
160
  const: (
152
161
  value: string | number | boolean | string[] | number[],
153
162
  condition: string | number | boolean,
154
- baseLocation: Location
163
+ { baseLocation }: AssertionFnContext
155
164
  ) => {
156
165
  if (typeof value === 'undefined') return [];
157
166
 
@@ -176,7 +185,7 @@ export const asserts: Asserts = {
176
185
  : [];
177
186
  }
178
187
  },
179
- undefined: (value: unknown, condition: boolean = true, baseLocation: Location) => {
188
+ undefined: (value: unknown, condition: boolean = true, { baseLocation }: AssertionFnContext) => {
180
189
  const isUndefined = typeof value === 'undefined';
181
190
  const isValid = condition ? isUndefined : !isUndefined;
182
191
  return isValid
@@ -191,7 +200,7 @@ export const asserts: Asserts = {
191
200
  nonEmpty: (
192
201
  value: string | undefined | null,
193
202
  condition: boolean = true,
194
- baseLocation: Location
203
+ { baseLocation }: AssertionFnContext
195
204
  ) => {
196
205
  const isEmpty = typeof value === 'undefined' || value === null || value === '';
197
206
  const isValid = condition ? !isEmpty : isEmpty;
@@ -204,15 +213,25 @@ export const asserts: Asserts = {
204
213
  },
205
214
  ];
206
215
  },
207
- minLength: (value: string | any[], condition: number, baseLocation: Location) => {
216
+ minLength: (value: string | any[], condition: number, { baseLocation }: AssertionFnContext) => {
208
217
  if (typeof value === 'undefined' || value.length >= condition) return []; // property doesn't exist, no need to lint it with this assert
209
- return [{ message: `Should have at least ${condition} characters`, location: baseLocation }];
218
+ return [
219
+ {
220
+ message: `Should have at least ${condition} characters`,
221
+ location: baseLocation,
222
+ },
223
+ ];
210
224
  },
211
- maxLength: (value: string | any[], condition: number, baseLocation: Location) => {
225
+ maxLength: (value: string | any[], condition: number, { baseLocation }: AssertionFnContext) => {
212
226
  if (typeof value === 'undefined' || value.length <= condition) return []; // property doesn't exist, no need to lint it with this assert
213
- return [{ message: `Should have at most ${condition} characters`, location: baseLocation }];
227
+ return [
228
+ {
229
+ message: `Should have at most ${condition} characters`,
230
+ location: baseLocation,
231
+ },
232
+ ];
214
233
  },
215
- casing: (value: string | string[], condition: string, baseLocation: Location) => {
234
+ casing: (value: string | string[], condition: string, { baseLocation }: AssertionFnContext) => {
216
235
  if (typeof value === 'undefined' || isPlainObject(value)) return []; // property doesn't exist or is an object, no need to lint it with this assert
217
236
  const values = Array.isArray(value) ? value : [value];
218
237
  const casingRegexes: Record<string, RegExp> = {
@@ -237,7 +256,7 @@ export const asserts: Asserts = {
237
256
  sortOrder: (
238
257
  value: unknown[],
239
258
  condition: OrderOptions | OrderDirection,
240
- baseLocation: Location
259
+ { baseLocation }: AssertionFnContext
241
260
  ) => {
242
261
  const direction = (condition as OrderOptions).direction || (condition as OrderDirection);
243
262
  const property = (condition as OrderOptions).property;
@@ -260,7 +279,11 @@ export const asserts: Asserts = {
260
279
  },
261
280
  ];
262
281
  },
263
- mutuallyExclusive: (value: string[], condition: string[], baseLocation: Location) => {
282
+ mutuallyExclusive: (
283
+ value: string[],
284
+ condition: string[],
285
+ { baseLocation }: AssertionFnContext
286
+ ) => {
264
287
  if (getIntersectionLength(value, condition) < 2) return [];
265
288
  return [
266
289
  {
@@ -269,7 +292,11 @@ export const asserts: Asserts = {
269
292
  },
270
293
  ];
271
294
  },
272
- mutuallyRequired: (value: string[], condition: string[], baseLocation: Location) => {
295
+ mutuallyRequired: (
296
+ value: string[],
297
+ condition: string[],
298
+ { baseLocation }: AssertionFnContext
299
+ ) => {
273
300
  const isValid =
274
301
  getIntersectionLength(value, condition) > 0
275
302
  ? getIntersectionLength(value, condition) === condition.length
@@ -283,7 +310,7 @@ export const asserts: Asserts = {
283
310
  },
284
311
  ];
285
312
  },
286
- requireAny: (value: string[], condition: string[], baseLocation: Location) => {
313
+ requireAny: (value: string[], condition: string[], { baseLocation }: AssertionFnContext) => {
287
314
  return getIntersectionLength(value, condition) >= 1
288
315
  ? []
289
316
  : [
@@ -293,7 +320,11 @@ export const asserts: Asserts = {
293
320
  },
294
321
  ];
295
322
  },
296
- ref: (_value: unknown, condition: string | boolean, baseLocation: Location, rawValue: any) => {
323
+ ref: (
324
+ _value: unknown,
325
+ condition: string | boolean,
326
+ { baseLocation, rawValue }: AssertionFnContext
327
+ ) => {
297
328
  if (typeof rawValue === 'undefined') return []; // property doesn't exist, no need to lint it with this assert
298
329
  const hasRef = rawValue.hasOwnProperty('$ref');
299
330
  if (typeof condition === 'boolean') {
@@ -321,6 +352,6 @@ export const asserts: Asserts = {
321
352
  };
322
353
 
323
354
  export function buildAssertCustomFunction(fn: CustomFunction): AssertionFn {
324
- return (value: string[], options: any, baseLocation: Location) =>
325
- fn.call(null, value, options, baseLocation);
355
+ return (value: string[], options: any, ctx: AssertionFnContext) =>
356
+ fn.call(null, value, options, ctx);
326
357
  }
@@ -1,8 +1,8 @@
1
1
  import { asserts, runOnKeysSet, runOnValuesSet, Asserts } from './asserts';
2
2
  import { colorize } from '../../../logger';
3
- import { isRef, Location } from '../../../ref-utils';
3
+ import { isRef } from '../../../ref-utils';
4
4
  import { isTruthy, keysOf, isString } from '../../../utils';
5
- import type { AssertResult } from '../../../config';
5
+ import type { AssertionContext, AssertResult } from '../../../config';
6
6
  import type { Assertion, AssertionDefinition, AssertionLocators } from '.';
7
7
  import type {
8
8
  Oas2Visitor,
@@ -10,6 +10,7 @@ import type {
10
10
  SkipFunctionContext,
11
11
  VisitFunction,
12
12
  } from '../../../visitors';
13
+ import { UserContext } from 'core/src/walk';
13
14
 
14
15
  export type OrderDirection = 'asc' | 'desc';
15
16
 
@@ -25,8 +26,10 @@ export type AssertToApply = {
25
26
  runsOnValues: boolean;
26
27
  };
27
28
 
28
- type AssertionContext = SkipFunctionContext & {
29
- node: any;
29
+ type RunAssertionParams = {
30
+ ctx: AssertionContext;
31
+ assert: AssertToApply;
32
+ assertionProperty?: string;
30
33
  };
31
34
 
32
35
  const assertionMessageTemplates = {
@@ -96,35 +99,27 @@ function getAssertionProperties({ subject }: AssertionDefinition): string[] {
96
99
  function applyAssertions(
97
100
  assertionDefinition: AssertionDefinition,
98
101
  asserts: AssertToApply[],
99
- { rawLocation, rawNode, resolve, location, node }: AssertionContext
102
+ ctx: AssertionContext
100
103
  ): AssertResult[] {
101
104
  const properties = getAssertionProperties(assertionDefinition);
102
105
  const assertResults: Array<AssertResult[]> = [];
103
106
 
104
107
  for (const assert of asserts) {
105
- const currentLocation = assert.name === 'ref' ? rawLocation : location;
106
-
107
108
  if (properties.length) {
108
109
  for (const property of properties) {
109
- // we can have resolvable scalar so need to resolve value here.
110
- const value = isRef(node[property]) ? resolve(node[property])?.node : node[property];
111
110
  assertResults.push(
112
111
  runAssertion({
113
- values: value,
114
- rawValues: rawNode[property],
115
112
  assert,
116
- location: currentLocation.child(property),
113
+ ctx,
114
+ assertionProperty: property,
117
115
  })
118
116
  );
119
117
  }
120
118
  } else {
121
- const value = Array.isArray(node) ? node : Object.keys(node);
122
119
  assertResults.push(
123
120
  runAssertion({
124
- values: value,
125
- rawValues: rawNode,
126
121
  assert,
127
- location: currentLocation,
122
+ ctx,
128
123
  })
129
124
  );
130
125
  }
@@ -139,7 +134,7 @@ export function buildVisitorObject(
139
134
  ): Oas2Visitor | Oas3Visitor {
140
135
  const targetVisitorLocatorPredicates = getPredicatesFromLocators(assertion.subject);
141
136
  const targetVisitorSkipFunction = targetVisitorLocatorPredicates.length
142
- ? (node: any, key: string | number) =>
137
+ ? (_: any, key: string | number) =>
143
138
  !targetVisitorLocatorPredicates.every((predicate) => predicate(key))
144
139
  : undefined;
145
140
  const targetVisitor: Oas2Visitor | Oas3Visitor = {
@@ -169,19 +164,9 @@ export function buildVisitorObject(
169
164
  const locatorPredicates = getPredicatesFromLocators(assertionDefinitionNode.subject);
170
165
  const assertsToApply = getAssertsToApply(assertionDefinitionNode);
171
166
 
172
- const skipFunction = (
173
- node: unknown,
174
- key: string | number,
175
- { location, rawLocation, resolve, rawNode }: SkipFunctionContext
176
- ): boolean =>
167
+ const skipFunction = (node: unknown, key: string | number, ctx: SkipFunctionContext): boolean =>
177
168
  !locatorPredicates.every((predicate) => predicate(key)) ||
178
- !!applyAssertions(assertionDefinitionNode, assertsToApply, {
179
- location,
180
- node,
181
- rawLocation,
182
- rawNode,
183
- resolve,
184
- }).length;
169
+ !!applyAssertions(assertionDefinitionNode, assertsToApply, { ...ctx, node }).length;
185
170
 
186
171
  const nodeVisitor = {
187
172
  ...((locatorPredicates.length || assertsToApply.length) && { skip: skipFunction }),
@@ -215,7 +200,7 @@ export function buildVisitorObject(
215
200
  }
216
201
 
217
202
  export function buildSubjectVisitor(assertId: string, assertion: Assertion): VisitFunction<any> {
218
- return (node: any, { report, location, rawLocation, resolve, rawNode }) => {
203
+ return (node: any, ctx: UserContext) => {
219
204
  const properties = getAssertionProperties(assertion);
220
205
 
221
206
  const defaultMessage = `${colorize.blue(assertId)} failed because the ${colorize.blue(
@@ -225,10 +210,7 @@ export function buildSubjectVisitor(assertId: string, assertion: Assertion): Vis
225
210
  }`.replace(/ +/g, ' ');
226
211
 
227
212
  const problems = applyAssertions(assertion, getAssertsToApply(assertion), {
228
- rawLocation,
229
- rawNode,
230
- resolve,
231
- location,
213
+ ...ctx,
232
214
  node,
233
215
  });
234
216
 
@@ -236,9 +218,9 @@ export function buildSubjectVisitor(assertId: string, assertion: Assertion): Vis
236
218
  for (const problemGroup of groupProblemsByPointer(problems)) {
237
219
  const message = assertion.message || defaultMessage;
238
220
  const problemMessage = getProblemsMessage(problemGroup);
239
- report({
221
+ ctx.report({
240
222
  message: message.replace(assertionMessageTemplates.problems, problemMessage),
241
- location: getProblemsLocation(problemGroup) || location,
223
+ location: getProblemsLocation(problemGroup) || ctx.location,
242
224
  forceSeverity: assertion.severity || 'error',
243
225
  suggest: assertion.suggest || [],
244
226
  ruleId: assertId,
@@ -312,15 +294,35 @@ export function isOrdered(value: any[], options: OrderOptions | OrderDirection):
312
294
  return true;
313
295
  }
314
296
 
315
- type RunAssertionParams = {
316
- values: string | string[];
317
- rawValues: any;
318
- assert: AssertToApply;
319
- location: Location;
320
- };
297
+ export function runAssertion({
298
+ assert,
299
+ ctx,
300
+ assertionProperty,
301
+ }: RunAssertionParams): AssertResult[] {
302
+ const currentLocation = assert.name === 'ref' ? ctx.rawLocation : ctx.location;
303
+
304
+ if (assertionProperty) {
305
+ const values = isRef(ctx.node[assertionProperty])
306
+ ? ctx.resolve(ctx.node[assertionProperty])?.node
307
+ : ctx.node[assertionProperty];
308
+ const rawValues = ctx.rawNode[assertionProperty];
309
+
310
+ const location = currentLocation.child(assertionProperty);
311
+
312
+ return asserts[assert.name](values, assert.conditions, {
313
+ ...ctx,
314
+ baseLocation: location,
315
+ rawValue: rawValues,
316
+ });
317
+ } else {
318
+ const value = Array.isArray(ctx.node) ? ctx.node : Object.keys(ctx.node);
321
319
 
322
- function runAssertion({ values, rawValues, assert, location }: RunAssertionParams): AssertResult[] {
323
- return asserts[assert.name](values, assert.conditions, location, rawValues);
320
+ return asserts[assert.name](value, assert.conditions, {
321
+ ...ctx,
322
+ rawValue: ctx.rawNode,
323
+ baseLocation: currentLocation,
324
+ });
325
+ }
324
326
  }
325
327
 
326
328
  export function regexFromString(input: string): RegExp | null {
@@ -0,0 +1,44 @@
1
+ import { UserContext } from '../../walk';
2
+ import { Oas3Schema, Oas3_1Schema } from '../../typings/openapi';
3
+ import { Oas2Schema } from 'core/src/typings/swagger';
4
+ import { Oas3Rule } from 'core/src/visitors';
5
+
6
+ export const RequiredStringPropertyMissingMinLength: Oas3Rule = () => {
7
+ let skipSchemaProperties: boolean;
8
+ let requiredPropertiesSet: Set<string>;
9
+
10
+ return {
11
+ Schema: {
12
+ enter(schema: Oas3Schema | Oas3_1Schema | Oas2Schema) {
13
+ if (!schema?.required) {
14
+ skipSchemaProperties = true;
15
+ return;
16
+ }
17
+ requiredPropertiesSet = new Set(schema.required);
18
+ skipSchemaProperties = false;
19
+ },
20
+
21
+ SchemaProperties: {
22
+ skip() {
23
+ return skipSchemaProperties;
24
+ },
25
+
26
+ Schema: {
27
+ enter(
28
+ schema: Oas3Schema | Oas3_1Schema | Oas2Schema,
29
+ { key, location, report }: UserContext
30
+ ) {
31
+ if (requiredPropertiesSet.has(key as string) && schema.type === 'string') {
32
+ if (!schema?.minLength) {
33
+ report({
34
+ message: 'Property minLength is required.',
35
+ location: location.key(),
36
+ });
37
+ }
38
+ }
39
+ },
40
+ },
41
+ },
42
+ },
43
+ };
44
+ };
@@ -39,6 +39,7 @@ import { PathSegmentPlural } from '../common/path-segment-plural';
39
39
  import { ResponseContainsHeader } from '../common/response-contains-header';
40
40
  import { ResponseContainsProperty } from './response-contains-property';
41
41
  import { ScalarPropertyMissingExample } from '../common/scalar-property-missing-example';
42
+ import { RequiredStringPropertyMissingMinLength } from '../common/required-string-property-missing-min-length';
42
43
 
43
44
  export const rules = {
44
45
  spec: OasSpec as Oas2Rule,
@@ -82,6 +83,7 @@ export const rules = {
82
83
  'response-contains-header': ResponseContainsHeader as Oas2Rule,
83
84
  'response-contains-property': ResponseContainsProperty as Oas2Rule,
84
85
  'scalar-property-missing-example': ScalarPropertyMissingExample,
86
+ 'required-string-property-missing-min-length': RequiredStringPropertyMissingMinLength,
85
87
  };
86
88
 
87
89
  export const preprocessors = {};
@@ -49,6 +49,7 @@ import { ResponseContainsProperty } from './response-contains-property';
49
49
  import { ScalarPropertyMissingExample } from '../common/scalar-property-missing-example';
50
50
  import { SpecComponentsInvalidMapName } from './spec-components-invalid-map-name';
51
51
  import { Operation4xxProblemDetailsRfc7807 } from './operation-4xx-problem-details-rfc7807';
52
+ import { RequiredStringPropertyMissingMinLength } from '../common/required-string-property-missing-min-length';
52
53
 
53
54
  export const rules = {
54
55
  spec: OasSpec,
@@ -102,6 +103,7 @@ export const rules = {
102
103
  'response-contains-property': ResponseContainsProperty,
103
104
  'scalar-property-missing-example': ScalarPropertyMissingExample,
104
105
  'spec-components-invalid-map-name': SpecComponentsInvalidMapName,
106
+ 'required-string-property-missing-min-length': RequiredStringPropertyMissingMinLength,
105
107
  } as Oas3RuleSet;
106
108
 
107
109
  export const preprocessors = {};
@@ -53,6 +53,7 @@ const builtInRulesList = [
53
53
  'response-contains-property',
54
54
  'scalar-property-missing-example',
55
55
  'spec-components-invalid-map-name',
56
+ 'required-string-property-missing-min-length',
56
57
  ];
57
58
  const nodeTypesList = [
58
59
  'any',