@redocly/openapi-core 1.8.2 → 1.9.1

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.
Files changed (60) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/lib/bundle.d.ts +1 -1
  3. package/lib/config/all.js +1 -0
  4. package/lib/config/minimal.js +1 -0
  5. package/lib/config/recommended-strict.js +1 -0
  6. package/lib/config/recommended.js +1 -0
  7. package/lib/lint.d.ts +1 -0
  8. package/lib/lint.js +1 -1
  9. package/lib/oas-types.d.ts +1 -1
  10. package/lib/ref-utils.js +4 -4
  11. package/lib/resolve.js +9 -1
  12. package/lib/rules/common/no-required-schema-properties-undefined.d.ts +2 -0
  13. package/lib/rules/common/no-required-schema-properties-undefined.js +37 -0
  14. package/lib/rules/oas2/index.js +2 -0
  15. package/lib/rules/oas3/index.js +2 -0
  16. package/lib/types/index.d.ts +7 -7
  17. package/lib/types/json-schema-adapter.d.ts +3 -0
  18. package/lib/types/json-schema-adapter.js +173 -0
  19. package/lib/types/oas2.d.ts +3 -2
  20. package/lib/types/oas3.d.ts +3 -2
  21. package/lib/types/oas3_1.d.ts +3 -2
  22. package/lib/types/portal-config-schema.d.ts +5261 -52
  23. package/lib/types/portal-config-schema.js +71 -55
  24. package/lib/types/redocly-yaml.d.ts +14 -2
  25. package/lib/types/redocly-yaml.js +102 -39
  26. package/lib/types/theme-config.d.ts +819 -36
  27. package/lib/types/theme-config.js +67 -29
  28. package/lib/utils.d.ts +2 -2
  29. package/lib/visitors.js +1 -1
  30. package/lib/walk.js +7 -1
  31. package/package.json +1 -1
  32. package/src/__tests__/lint.test.ts +1218 -36
  33. package/src/__tests__/ref-utils.test.ts +22 -0
  34. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +2 -0
  35. package/src/config/__tests__/load.test.ts +13 -13
  36. package/src/config/all.ts +1 -0
  37. package/src/config/minimal.ts +1 -0
  38. package/src/config/recommended-strict.ts +1 -0
  39. package/src/config/recommended.ts +1 -0
  40. package/src/decorators/oas2/remove-unused-components.ts +3 -2
  41. package/src/decorators/oas3/remove-unused-components.ts +3 -2
  42. package/src/lint.ts +2 -1
  43. package/src/ref-utils.ts +4 -4
  44. package/src/resolve.ts +13 -1
  45. package/src/rules/common/__tests__/no-required-schema-properties-undefined.test.ts +550 -0
  46. package/src/rules/common/no-required-schema-properties-undefined.ts +53 -0
  47. package/src/rules/oas2/index.ts +2 -0
  48. package/src/rules/oas3/index.ts +2 -0
  49. package/src/types/index.ts +7 -12
  50. package/src/types/json-schema-adapter.ts +217 -0
  51. package/src/types/oas2.ts +5 -2
  52. package/src/types/oas3.ts +6 -2
  53. package/src/types/oas3_1.ts +5 -2
  54. package/src/types/portal-config-schema.ts +111 -61
  55. package/src/types/redocly-yaml.ts +119 -43
  56. package/src/types/theme-config.ts +125 -27
  57. package/src/utils.ts +2 -2
  58. package/src/visitors.ts +1 -1
  59. package/src/walk.ts +7 -1
  60. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,550 @@
1
+ import { outdent } from 'outdent';
2
+ import { lintDocument } from '../../../lint';
3
+ import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../../../__tests__/utils';
4
+ import { BaseResolver } from '../../../resolve';
5
+
6
+ describe('no-required-schema-properties-undefined', () => {
7
+ it('should report if one or more of the required properties are undefined', async () => {
8
+ const document = parseYamlToDocument(
9
+ outdent`
10
+ openapi: 3.0.0
11
+ components:
12
+ schemas:
13
+ Pet:
14
+ type: object
15
+ required:
16
+ - name
17
+ - id
18
+ - test
19
+ properties:
20
+ id:
21
+ type: integer
22
+ format: int64
23
+ name:
24
+ type: string
25
+ example: doggie
26
+ `,
27
+ 'foobar.yaml'
28
+ );
29
+
30
+ const results = await lintDocument({
31
+ externalRefResolver: new BaseResolver(),
32
+ document,
33
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
34
+ });
35
+
36
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
37
+ [
38
+ {
39
+ "location": [
40
+ {
41
+ "pointer": "#/components/schemas/Pet/required/2",
42
+ "reportOnKey": false,
43
+ "source": "foobar.yaml",
44
+ },
45
+ ],
46
+ "message": "Required property 'test' is undefined.",
47
+ "ruleId": "no-required-schema-properties-undefined",
48
+ "severity": "error",
49
+ "suggest": [],
50
+ },
51
+ ]
52
+ `);
53
+ });
54
+
55
+ it('should report if one or more of the required properties are undefined, including allOf nested schemas', async () => {
56
+ const document = parseYamlToDocument(
57
+ outdent`
58
+ openapi: 3.0.0
59
+ components:
60
+ schemas:
61
+ Pet:
62
+ type: object
63
+ allOf:
64
+ - properties:
65
+ foo:
66
+ type: string
67
+ required:
68
+ - id
69
+ - foo
70
+ - test
71
+ properties:
72
+ id:
73
+ type: integer
74
+ format: int64
75
+ `,
76
+ 'foobar.yaml'
77
+ );
78
+
79
+ const results = await lintDocument({
80
+ externalRefResolver: new BaseResolver(),
81
+ document,
82
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
83
+ });
84
+
85
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
86
+ [
87
+ {
88
+ "location": [
89
+ {
90
+ "pointer": "#/components/schemas/Pet/required/2",
91
+ "reportOnKey": false,
92
+ "source": "foobar.yaml",
93
+ },
94
+ ],
95
+ "message": "Required property 'test' is undefined.",
96
+ "ruleId": "no-required-schema-properties-undefined",
97
+ "severity": "error",
98
+ "suggest": [],
99
+ },
100
+ ]
101
+ `);
102
+ });
103
+
104
+ it('should report if one or more of the required properties are undefined when used in schema with allOf keyword', async () => {
105
+ const document = parseYamlToDocument(
106
+ outdent`
107
+ openapi: 3.0.0
108
+ components:
109
+ schemas:
110
+ Cat:
111
+ description: A representation of a cat
112
+ allOf:
113
+ - $ref: '#/components/schemas/Pet'
114
+ - type: object
115
+ properties:
116
+ huntingSkill:
117
+ type: string
118
+ required:
119
+ - huntingSkill
120
+ - name
121
+ Pet:
122
+ type: object
123
+ required:
124
+ - photoUrls
125
+ properties:
126
+ name:
127
+ type: string
128
+ photoUrls:
129
+ type: string
130
+ `,
131
+ 'foobar.yaml'
132
+ );
133
+
134
+ const results = await lintDocument({
135
+ externalRefResolver: new BaseResolver(),
136
+ document,
137
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
138
+ });
139
+
140
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
141
+ [
142
+ {
143
+ "location": [
144
+ {
145
+ "pointer": "#/components/schemas/Cat/allOf/1/required/1",
146
+ "reportOnKey": false,
147
+ "source": "foobar.yaml",
148
+ },
149
+ ],
150
+ "message": "Required property 'name' is undefined.",
151
+ "ruleId": "no-required-schema-properties-undefined",
152
+ "severity": "error",
153
+ "suggest": [],
154
+ },
155
+ ]
156
+ `);
157
+ });
158
+
159
+ it('should not report required properties are present after resolving $refs when used in schema with allOf keyword', async () => {
160
+ const document = parseYamlToDocument(
161
+ outdent`
162
+ openapi: 3.0.0
163
+ components:
164
+ schemas:
165
+ Cat:
166
+ description: A representation of a cat
167
+ allOf:
168
+ - $ref: '#/components/schemas/Pet'
169
+ - type: object
170
+ properties:
171
+ huntingSkill:
172
+ type: string
173
+ required:
174
+ - huntingSkill
175
+ required:
176
+ - name
177
+ Pet:
178
+ type: object
179
+ required:
180
+ - photoUrls
181
+ properties:
182
+ name:
183
+ type: string
184
+ photoUrls:
185
+ type: string
186
+ `,
187
+ 'foobar.yaml'
188
+ );
189
+
190
+ const results = await lintDocument({
191
+ externalRefResolver: new BaseResolver(),
192
+ document,
193
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
194
+ });
195
+
196
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
197
+ });
198
+
199
+ it('should report with few messages if more than one of the required properties are undefined', async () => {
200
+ const document = parseYamlToDocument(
201
+ outdent`
202
+ openapi: 3.0.0
203
+ components:
204
+ schemas:
205
+ Pet:
206
+ type: object
207
+ required:
208
+ - name
209
+ - id
210
+ - test
211
+ - test2
212
+ properties:
213
+ id:
214
+ type: integer
215
+ format: int64
216
+ name:
217
+ type: string
218
+ example: doggie
219
+ `,
220
+ 'foobar.yaml'
221
+ );
222
+
223
+ const results = await lintDocument({
224
+ externalRefResolver: new BaseResolver(),
225
+ document,
226
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
227
+ });
228
+
229
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
230
+ [
231
+ {
232
+ "location": [
233
+ {
234
+ "pointer": "#/components/schemas/Pet/required/2",
235
+ "reportOnKey": false,
236
+ "source": "foobar.yaml",
237
+ },
238
+ ],
239
+ "message": "Required property 'test' is undefined.",
240
+ "ruleId": "no-required-schema-properties-undefined",
241
+ "severity": "error",
242
+ "suggest": [],
243
+ },
244
+ {
245
+ "location": [
246
+ {
247
+ "pointer": "#/components/schemas/Pet/required/3",
248
+ "reportOnKey": false,
249
+ "source": "foobar.yaml",
250
+ },
251
+ ],
252
+ "message": "Required property 'test2' is undefined.",
253
+ "ruleId": "no-required-schema-properties-undefined",
254
+ "severity": "error",
255
+ "suggest": [],
256
+ },
257
+ ]
258
+ `);
259
+ });
260
+
261
+ it('should not report if all of the required properties are present', async () => {
262
+ const document = parseYamlToDocument(
263
+ outdent`
264
+ openapi: 3.0.0
265
+ components:
266
+ schemas:
267
+ Pet:
268
+ type: object
269
+ required:
270
+ - name
271
+ - id
272
+ properties:
273
+ id:
274
+ type: integer
275
+ format: int64
276
+ name:
277
+ type: string
278
+ example: doggie
279
+ test:
280
+ type: string
281
+ example: test
282
+ `,
283
+ 'foobar.yaml'
284
+ );
285
+
286
+ const results = await lintDocument({
287
+ externalRefResolver: new BaseResolver(),
288
+ document,
289
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
290
+ });
291
+
292
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
293
+ });
294
+
295
+ it('should not cause stack overflow when there are circular references in schemas', async () => {
296
+ const document = parseYamlToDocument(
297
+ outdent`
298
+ openapi: 3.0.0
299
+ components:
300
+ schemas:
301
+ Cat:
302
+ description: A representation of a cat
303
+ allOf:
304
+ - $ref: '#/components/schemas/Pet'
305
+ - type: object
306
+ properties:
307
+ huntingSkill:
308
+ type: string
309
+ required:
310
+ - huntingSkill
311
+ required:
312
+ - name
313
+ Pet:
314
+ description: A schema of pet
315
+ allOf:
316
+ - $ref: '#/components/schemas/Cat'
317
+ - type: object
318
+ required:
319
+ - photoUrls
320
+ properties:
321
+ name:
322
+ type: string
323
+ photoUrls:
324
+ type: string
325
+ `,
326
+ 'foobar.yaml'
327
+ );
328
+
329
+ const results = await lintDocument({
330
+ externalRefResolver: new BaseResolver(),
331
+ document,
332
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
333
+ });
334
+
335
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
336
+ });
337
+
338
+ it('should report if there is any required schema that is undefined, including checking nested allOf schemas', async () => {
339
+ const document = parseYamlToDocument(
340
+ outdent`
341
+ openapi: 3.0.0
342
+ components:
343
+ schemas:
344
+ Cat:
345
+ description: A representation of a cat
346
+ allOf:
347
+ - $ref: '#/components/schemas/Pet'
348
+ - type: object
349
+ properties:
350
+ huntingSkill:
351
+ type: string
352
+ required:
353
+ - huntingSkill
354
+ required:
355
+ - test
356
+ - id
357
+ Pet:
358
+ description: A schema of pet
359
+ allOf:
360
+ - type: object
361
+ required:
362
+ - photoUrls
363
+ properties:
364
+ photoUrls:
365
+ type: string
366
+ - type: object
367
+ required:
368
+ - name
369
+ properties:
370
+ name:
371
+ type: string
372
+ id:
373
+ type: string
374
+ `,
375
+ 'foobar.yaml'
376
+ );
377
+
378
+ const results = await lintDocument({
379
+ externalRefResolver: new BaseResolver(),
380
+ document,
381
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
382
+ });
383
+
384
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
385
+ [
386
+ {
387
+ "location": [
388
+ {
389
+ "pointer": "#/components/schemas/Cat/required/0",
390
+ "reportOnKey": false,
391
+ "source": "foobar.yaml",
392
+ },
393
+ ],
394
+ "message": "Required property 'test' is undefined.",
395
+ "ruleId": "no-required-schema-properties-undefined",
396
+ "severity": "error",
397
+ "suggest": [],
398
+ },
399
+ ]
400
+ `);
401
+ });
402
+
403
+ it('should not report if required property is present in one of the nested reference schemas', async () => {
404
+ const document = parseYamlToDocument(
405
+ outdent`
406
+ openapi: 3.0.0
407
+ components:
408
+ schemas:
409
+ Animal:
410
+ type: object
411
+ properties:
412
+ commonProperty:
413
+ type: string
414
+ Mammal:
415
+ allOf:
416
+ - $ref: '#/components/schemas/Animal'
417
+ - type: object
418
+ properties:
419
+ furColor:
420
+ type: string
421
+ required:
422
+ - furColor
423
+ Carnivore:
424
+ allOf:
425
+ - $ref: '#/components/schemas/Mammal'
426
+ - type: object
427
+ properties:
428
+ diet:
429
+ type: string
430
+ required:
431
+ - diet
432
+ Tiger:
433
+ allOf:
434
+ - $ref: '#/components/schemas/Carnivore'
435
+ - type: object
436
+ properties:
437
+ stripes:
438
+ type: boolean
439
+ required:
440
+ - stripes
441
+ required:
442
+ - commonProperty
443
+ `,
444
+ 'foobar.yaml'
445
+ );
446
+
447
+ const results = await lintDocument({
448
+ externalRefResolver: new BaseResolver(),
449
+ document,
450
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
451
+ });
452
+
453
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
454
+ });
455
+
456
+ it('should report if one or more of the required properties are undefined when used in schema with anyOf keyword', async () => {
457
+ const document = parseYamlToDocument(
458
+ outdent`
459
+ openapi: 3.0.0
460
+ components:
461
+ schemas:
462
+ Cat:
463
+ description: A representation of a cat
464
+ anyOf:
465
+ - $ref: '#/components/schemas/Pet'
466
+ - type: object
467
+ properties:
468
+ huntingSkill:
469
+ type: string
470
+ required:
471
+ - huntingSkill
472
+ - name
473
+ Pet:
474
+ type: object
475
+ required:
476
+ - photoUrls
477
+ properties:
478
+ name:
479
+ type: string
480
+ photoUrls:
481
+ type: string
482
+ `,
483
+ 'foobar.yaml'
484
+ );
485
+
486
+ const results = await lintDocument({
487
+ externalRefResolver: new BaseResolver(),
488
+ document,
489
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
490
+ });
491
+
492
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
493
+ [
494
+ {
495
+ "location": [
496
+ {
497
+ "pointer": "#/components/schemas/Cat/anyOf/1/required/1",
498
+ "reportOnKey": false,
499
+ "source": "foobar.yaml",
500
+ },
501
+ ],
502
+ "message": "Required property 'name' is undefined.",
503
+ "ruleId": "no-required-schema-properties-undefined",
504
+ "severity": "error",
505
+ "suggest": [],
506
+ },
507
+ ]
508
+ `);
509
+ });
510
+
511
+ it('should report if one or more of the required properties are undefined when used in schema with allOf keyword', async () => {
512
+ const document = parseYamlToDocument(
513
+ outdent`
514
+ openapi: 3.0.0
515
+ components:
516
+ schemas:
517
+ Cat:
518
+ description: A representation of a cat
519
+ anyOf:
520
+ - $ref: '#/components/schemas/Pet'
521
+ - type: object
522
+ properties:
523
+ huntingSkill:
524
+ type: string
525
+ required:
526
+ - huntingSkill
527
+ required:
528
+ - name
529
+ Pet:
530
+ type: object
531
+ required:
532
+ - photoUrls
533
+ properties:
534
+ name:
535
+ type: string
536
+ photoUrls:
537
+ type: string
538
+ `,
539
+ 'foobar.yaml'
540
+ );
541
+
542
+ const results = await lintDocument({
543
+ externalRefResolver: new BaseResolver(),
544
+ document,
545
+ config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
546
+ });
547
+
548
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
549
+ });
550
+ });
@@ -0,0 +1,53 @@
1
+ import { Oas2Rule, Oas3Rule } from '../../visitors';
2
+ import { Oas3Schema, Oas3_1Schema } from '../../typings/openapi';
3
+ import { Oas2Schema } from 'core/src/typings/swagger';
4
+ import { UserContext } from 'core/src/walk';
5
+ import { isRef } from '../../ref-utils';
6
+
7
+ export const NoRequiredSchemaPropertiesUndefined: Oas3Rule | Oas2Rule = () => {
8
+ return {
9
+ Schema: {
10
+ enter(
11
+ schema: Oas3Schema | Oas3_1Schema | Oas2Schema,
12
+ { location, report, resolve }: UserContext
13
+ ) {
14
+ if (!schema.required) return;
15
+ const visitedSchemas: Set<Oas3Schema | Oas3_1Schema | Oas2Schema> = new Set();
16
+
17
+ const elevateProperties = (
18
+ schema: Oas3Schema | Oas3_1Schema | Oas2Schema
19
+ ): Record<string, Oas3Schema | Oas3_1Schema | Oas2Schema> => {
20
+ // Check if the schema has been visited before processing it
21
+ if (visitedSchemas.has(schema)) {
22
+ return {};
23
+ }
24
+ visitedSchemas.add(schema);
25
+
26
+ if (isRef(schema)) {
27
+ return elevateProperties(
28
+ resolve(schema).node as Oas3Schema | Oas3_1Schema | Oas2Schema
29
+ );
30
+ }
31
+
32
+ return Object.assign(
33
+ {},
34
+ schema.properties,
35
+ ...(schema.allOf?.map(elevateProperties) ?? []),
36
+ ...((schema as Oas3Schema).anyOf?.map(elevateProperties) ?? [])
37
+ );
38
+ };
39
+
40
+ const allProperties = elevateProperties(schema);
41
+
42
+ for (const [i, requiredProperty] of schema.required.entries()) {
43
+ if (!allProperties || allProperties[requiredProperty] === undefined) {
44
+ report({
45
+ message: `Required property '${requiredProperty}' is undefined.`,
46
+ location: location.child(['required', i]),
47
+ });
48
+ }
49
+ }
50
+ },
51
+ },
52
+ };
53
+ };
@@ -41,6 +41,7 @@ import { ResponseContainsProperty } from './response-contains-property';
41
41
  import { ScalarPropertyMissingExample } from '../common/scalar-property-missing-example';
42
42
  import { RequiredStringPropertyMissingMinLength } from '../common/required-string-property-missing-min-length';
43
43
  import { SpecStrictRefs } from '../common/spec-strict-refs';
44
+ import { NoRequiredSchemaPropertiesUndefined } from '../common/no-required-schema-properties-undefined';
44
45
 
45
46
  import type { Oas2RuleSet } from 'core/src/oas-types';
46
47
 
@@ -88,6 +89,7 @@ export const rules: Oas2RuleSet<'built-in'> = {
88
89
  'scalar-property-missing-example': ScalarPropertyMissingExample,
89
90
  'required-string-property-missing-min-length': RequiredStringPropertyMissingMinLength,
90
91
  'spec-strict-refs': SpecStrictRefs,
92
+ 'no-required-schema-properties-undefined': NoRequiredSchemaPropertiesUndefined,
91
93
  };
92
94
 
93
95
  export const preprocessors = {};
@@ -53,6 +53,7 @@ import { RequiredStringPropertyMissingMinLength } from '../common/required-strin
53
53
  import { SpecStrictRefs } from '../common/spec-strict-refs';
54
54
  import { ComponentNameUnique } from './component-name-unique';
55
55
  import { ArrayParameterSerialization } from './array-parameter-serialization';
56
+ import { NoRequiredSchemaPropertiesUndefined } from '../common/no-required-schema-properties-undefined';
56
57
 
57
58
  export const rules: Oas3RuleSet<'built-in'> = {
58
59
  spec: Spec,
@@ -110,6 +111,7 @@ export const rules: Oas3RuleSet<'built-in'> = {
110
111
  'spec-strict-refs': SpecStrictRefs,
111
112
  'component-name-unique': ComponentNameUnique,
112
113
  'array-parameter-serialization': ArrayParameterSerialization,
114
+ 'no-required-schema-properties-undefined': NoRequiredSchemaPropertiesUndefined,
113
115
  };
114
116
 
115
117
  export const preprocessors = {};
@@ -21,31 +21,28 @@ export type NormalizedScalarSchema = {
21
21
  export type NodeType = {
22
22
  properties: Record<string, PropType | ResolveTypeFn>;
23
23
  additionalProperties?: PropType | ResolveTypeFn;
24
- items?: string;
24
+ items?: PropType | ResolveTypeFn;
25
25
  required?: string[] | ((value: any, key: string | number | undefined) => string[]);
26
26
  requiredOneOf?: string[];
27
27
  allowed?: (value: any) => string[] | undefined;
28
28
  extensionsPrefix?: string;
29
29
  };
30
- type PropType = string | NodeType | ScalarSchema | undefined | null;
31
- type ResolveTypeFn = (value: any, key: string) => string | PropType;
30
+ export type PropType = string | NodeType | ScalarSchema | undefined | null;
31
+ export type ResolveTypeFn = (value: any, key: string) => string | PropType;
32
32
 
33
33
  export type NormalizedNodeType = {
34
34
  name: string;
35
35
  properties: Record<string, NormalizedPropType | NormalizedResolveTypeFn>;
36
36
  additionalProperties?: NormalizedPropType | NormalizedResolveTypeFn;
37
- items?: NormalizedNodeType;
37
+ items?: NormalizedPropType | NormalizedResolveTypeFn;
38
38
  required?: string[] | ((value: any, key: string | number | undefined) => string[]);
39
39
  requiredOneOf?: string[];
40
40
  allowed?: (value: any) => string[] | undefined;
41
41
  extensionsPrefix?: string;
42
42
  };
43
43
 
44
- type NormalizedPropType = NormalizedNodeType | NormalizedScalarSchema | undefined | null;
45
- type NormalizedResolveTypeFn = (
46
- value: any,
47
- key: string
48
- ) => NormalizedNodeType | NormalizedScalarSchema | undefined | null;
44
+ type NormalizedPropType = NormalizedNodeType | NormalizedScalarSchema | null | undefined;
45
+ type NormalizedResolveTypeFn = (value: any, key: string) => NormalizedPropType;
49
46
 
50
47
  export function listOf(typeName: string) {
51
48
  return {
@@ -142,8 +139,6 @@ export function normalizeTypes(
142
139
  }
143
140
  }
144
141
 
145
- export function isNamedType(
146
- t: NormalizedNodeType | NormalizedScalarSchema | null | undefined
147
- ): t is NormalizedNodeType {
142
+ export function isNamedType(t: NormalizedPropType): t is NormalizedNodeType {
148
143
  return typeof t?.name === 'string';
149
144
  }