@redocly/openapi-core 1.0.0-beta.111 → 1.0.0-beta.113

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 (78) hide show
  1. package/lib/config/all.js +0 -1
  2. package/lib/config/config-resolvers.js +22 -18
  3. package/lib/config/config.d.ts +4 -10
  4. package/lib/config/config.js +1 -1
  5. package/lib/config/load.d.ts +1 -1
  6. package/lib/config/load.js +10 -10
  7. package/lib/config/minimal.js +0 -1
  8. package/lib/config/recommended.js +0 -1
  9. package/lib/config/rules.d.ts +6 -3
  10. package/lib/config/rules.js +3 -2
  11. package/lib/config/types.d.ts +3 -0
  12. package/lib/ref-utils.d.ts +1 -0
  13. package/lib/ref-utils.js +5 -1
  14. package/lib/resolve.js +19 -0
  15. package/lib/rules/common/assertions/asserts.d.ts +22 -5
  16. package/lib/rules/common/assertions/asserts.js +25 -0
  17. package/lib/rules/common/assertions/index.d.ts +27 -2
  18. package/lib/rules/common/assertions/index.js +6 -29
  19. package/lib/rules/common/assertions/utils.d.ts +7 -14
  20. package/lib/rules/common/assertions/utils.js +129 -97
  21. package/lib/rules/common/spec.js +6 -0
  22. package/lib/rules/oas2/index.d.ts +0 -1
  23. package/lib/rules/oas2/index.js +0 -2
  24. package/lib/rules/oas3/index.js +0 -2
  25. package/lib/rules/utils.js +3 -0
  26. package/lib/types/oas2.js +11 -7
  27. package/lib/types/oas3.js +15 -10
  28. package/lib/types/oas3_1.js +1 -0
  29. package/lib/types/redocly-yaml.js +49 -27
  30. package/lib/utils.d.ts +2 -0
  31. package/lib/utils.js +13 -1
  32. package/lib/visitors.d.ts +2 -1
  33. package/lib/visitors.js +1 -0
  34. package/lib/walk.js +7 -1
  35. package/package.json +1 -1
  36. package/src/__tests__/bundle.test.ts +46 -0
  37. package/src/__tests__/lint.test.ts +24 -5
  38. package/src/benchmark/benches/rebilly.yaml +36 -28
  39. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +1 -3
  40. package/src/config/__tests__/config-resolvers.test.ts +6 -7
  41. package/src/config/__tests__/fixtures/load-redocly.yaml +2 -0
  42. package/src/config/__tests__/fixtures/resolve-config/local-config-with-custom-function.yaml +6 -5
  43. package/src/config/__tests__/fixtures/resolve-config/local-config-with-wrong-custom-function.yaml +0 -1
  44. package/src/config/__tests__/load.test.ts +4 -1
  45. package/src/config/all.ts +0 -1
  46. package/src/config/config-resolvers.ts +44 -31
  47. package/src/config/config.ts +6 -5
  48. package/src/config/load.ts +19 -9
  49. package/src/config/minimal.ts +0 -1
  50. package/src/config/recommended.ts +0 -1
  51. package/src/config/rules.ts +11 -3
  52. package/src/config/types.ts +2 -0
  53. package/src/ref-utils.ts +4 -0
  54. package/src/resolve.ts +25 -3
  55. package/src/rules/common/__tests__/spec.test.ts +170 -0
  56. package/src/rules/common/assertions/__tests__/asserts.test.ts +7 -3
  57. package/src/rules/common/assertions/__tests__/index.test.ts +41 -20
  58. package/src/rules/common/assertions/__tests__/utils.test.ts +43 -17
  59. package/src/rules/common/assertions/asserts.ts +60 -8
  60. package/src/rules/common/assertions/index.ts +36 -46
  61. package/src/rules/common/assertions/utils.ts +204 -127
  62. package/src/rules/common/spec.ts +7 -0
  63. package/src/rules/oas2/index.ts +0 -2
  64. package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +32 -0
  65. package/src/rules/oas3/index.ts +0 -2
  66. package/src/rules/utils.ts +4 -0
  67. package/src/types/oas2.ts +11 -7
  68. package/src/types/oas3.ts +15 -10
  69. package/src/types/oas3_1.ts +1 -0
  70. package/src/types/redocly-yaml.ts +49 -29
  71. package/src/utils.ts +11 -0
  72. package/src/visitors.ts +7 -1
  73. package/src/walk.ts +8 -1
  74. package/tsconfig.tsbuildinfo +1 -1
  75. package/lib/rules/common/info-description.d.ts +0 -2
  76. package/lib/rules/common/info-description.js +0 -12
  77. package/src/rules/common/__tests__/info-description.test.ts +0 -102
  78. package/src/rules/common/info-description.ts +0 -10
@@ -118,6 +118,10 @@ export function validateExample(
118
118
  }
119
119
  }
120
120
  } catch (e) {
121
+ if (e.message === 'discriminator: requires oneOf or anyOf composite keyword') {
122
+ return;
123
+ }
124
+
121
125
  report({
122
126
  message: `Example validation errored: ${e.message}.`,
123
127
  location: location.child('schema'),
package/src/types/oas2.ts CHANGED
@@ -16,8 +16,8 @@ const Root: NodeType = {
16
16
  parameters: 'NamedParameters',
17
17
  responses: 'NamedResponses',
18
18
  securityDefinitions: 'NamedSecuritySchemes',
19
- security: listOf('SecurityRequirement'),
20
- tags: listOf('Tag'),
19
+ security: 'SecurityRequirementList',
20
+ tags: 'TagList',
21
21
  externalDocs: 'ExternalDocs',
22
22
  },
23
23
  required: ['swagger', 'paths', 'info'],
@@ -60,7 +60,7 @@ const Paths: NodeType = {
60
60
  const PathItem: NodeType = {
61
61
  properties: {
62
62
  $ref: { type: 'string' }, // TODO: verify special $ref handling for Path Item
63
- parameters: listOf('Parameter'),
63
+ parameters: 'ParameterList',
64
64
 
65
65
  get: 'Operation',
66
66
  put: 'Operation',
@@ -81,13 +81,13 @@ const Operation: NodeType = {
81
81
  operationId: { type: 'string' },
82
82
  consumes: { type: 'array', items: { type: 'string' } },
83
83
  produces: { type: 'array', items: { type: 'string' } },
84
- parameters: listOf('Parameter'),
84
+ parameters: 'ParameterList',
85
85
  responses: 'Responses',
86
86
  schemes: { type: 'array', items: { type: 'string' } },
87
87
  deprecated: { type: 'boolean' },
88
- security: listOf('SecurityRequirement'),
89
- 'x-codeSamples': listOf('XCodeSample'),
90
- 'x-code-samples': listOf('XCodeSample'), // deprecated
88
+ security: 'SecurityRequirementList',
89
+ 'x-codeSamples': 'XCodeSampleList',
90
+ 'x-code-samples': 'XCodeSampleList', // deprecated
91
91
  'x-hideTryItPanel': { type: 'boolean' },
92
92
  },
93
93
  required: ['responses'],
@@ -371,8 +371,10 @@ const SecurityRequirement: NodeType = {
371
371
  export const Oas2Types: Record<string, NodeType> = {
372
372
  Root,
373
373
  Tag,
374
+ TagList: listOf('Tag'),
374
375
  ExternalDocs,
375
376
  SecurityRequirement,
377
+ SecurityRequirementList: listOf('SecurityRequirement'),
376
378
  Info,
377
379
  Contact,
378
380
  License,
@@ -380,6 +382,7 @@ export const Oas2Types: Record<string, NodeType> = {
380
382
  PathItem,
381
383
  Parameter,
382
384
  ParameterItems,
385
+ ParameterList: listOf('Parameter'),
383
386
  Operation,
384
387
  Examples,
385
388
  Header,
@@ -394,4 +397,5 @@ export const Oas2Types: Record<string, NodeType> = {
394
397
  NamedSecuritySchemes: mapOf('SecurityScheme'),
395
398
  SecurityScheme,
396
399
  XCodeSample,
400
+ XCodeSampleList: listOf('XCodeSample'),
397
401
  };
package/src/types/oas3.ts CHANGED
@@ -6,9 +6,9 @@ const Root: NodeType = {
6
6
  properties: {
7
7
  openapi: null,
8
8
  info: 'Info',
9
- servers: listOf('Server'),
10
- security: listOf('SecurityRequirement'),
11
- tags: listOf('Tag'),
9
+ servers: 'ServerList',
10
+ security: 'SecurityRequirementList',
11
+ tags: 'TagList',
12
12
  externalDocs: 'ExternalDocs',
13
13
  paths: 'Paths',
14
14
  components: 'Components',
@@ -102,8 +102,8 @@ const WebhooksMap: NodeType = {
102
102
  const PathItem: NodeType = {
103
103
  properties: {
104
104
  $ref: { type: 'string' }, // TODO: verify special $ref handling for Path Item
105
- servers: listOf('Server'),
106
- parameters: listOf('Parameter'),
105
+ servers: 'ServerList',
106
+ parameters: 'ParameterList',
107
107
  summary: { type: 'string' },
108
108
  description: { type: 'string' },
109
109
  get: 'Operation',
@@ -149,15 +149,15 @@ const Operation: NodeType = {
149
149
  description: { type: 'string' },
150
150
  externalDocs: 'ExternalDocs',
151
151
  operationId: { type: 'string' },
152
- parameters: listOf('Parameter'),
153
- security: listOf('SecurityRequirement'),
154
- servers: listOf('Server'),
152
+ parameters: 'ParameterList',
153
+ security: 'SecurityRequirementList',
154
+ servers: 'ServerList',
155
155
  requestBody: 'RequestBody',
156
156
  responses: 'Responses',
157
157
  deprecated: { type: 'boolean' },
158
158
  callbacks: 'CallbacksMap',
159
- 'x-codeSamples': listOf('XCodeSample'),
160
- 'x-code-samples': listOf('XCodeSample'), // deprecated
159
+ 'x-codeSamples': 'XCodeSampleList',
160
+ 'x-code-samples': 'XCodeSampleList', // deprecated
161
161
  'x-hideTryItPanel': { type: 'boolean' },
162
162
  },
163
163
  required: ['responses'],
@@ -462,17 +462,21 @@ const SecurityScheme: NodeType = {
462
462
  export const Oas3Types: Record<string, NodeType> = {
463
463
  Root,
464
464
  Tag,
465
+ TagList: listOf('Tag'),
465
466
  ExternalDocs,
466
467
  Server,
468
+ ServerList: listOf('Server'),
467
469
  ServerVariable,
468
470
  ServerVariablesMap: mapOf('ServerVariable'),
469
471
  SecurityRequirement,
472
+ SecurityRequirementList: listOf('SecurityRequirement'),
470
473
  Info,
471
474
  Contact,
472
475
  License,
473
476
  Paths,
474
477
  PathItem,
475
478
  Parameter,
479
+ ParameterList: listOf('Parameter'),
476
480
  Operation,
477
481
  Callback: mapOf('PathItem'),
478
482
  CallbacksMap: mapOf('Callback'),
@@ -511,5 +515,6 @@ export const Oas3Types: Record<string, NodeType> = {
511
515
  OAuth2Flows,
512
516
  SecurityScheme,
513
517
  XCodeSample,
518
+ XCodeSampleList: listOf('XCodeSample'),
514
519
  WebhooksMap,
515
520
  };
@@ -81,6 +81,7 @@ const Operation: NodeType = {
81
81
  const Schema: NodeType = {
82
82
  properties: {
83
83
  $id: { type: 'string' },
84
+ $anchor: { type: 'string' },
84
85
  id: { type: 'string' },
85
86
  $schema: { type: 'string' },
86
87
  definitions: 'NamedSchemas',
@@ -3,7 +3,6 @@ import { omitObjectProps, pickObjectProps, isCustomRuleId } from '../utils';
3
3
 
4
4
  const builtInRulesList = [
5
5
  'spec',
6
- 'info-description',
7
6
  'info-contact',
8
7
  'info-license',
9
8
  'info-license-url',
@@ -58,17 +57,21 @@ const builtInRulesList = [
58
57
  const nodeTypesList = [
59
58
  'Root',
60
59
  'Tag',
60
+ 'TagList',
61
61
  'ExternalDocs',
62
62
  'Server',
63
+ 'ServerList',
63
64
  'ServerVariable',
64
65
  'ServerVariablesMap',
65
66
  'SecurityRequirement',
67
+ 'SecurityRequirementList',
66
68
  'Info',
67
69
  'Contact',
68
70
  'License',
69
71
  'Paths',
70
72
  'PathItem',
71
73
  'Parameter',
74
+ 'ParameterList',
72
75
  'Operation',
73
76
  'Callback',
74
77
  'CallbacksMap',
@@ -107,6 +110,7 @@ const nodeTypesList = [
107
110
  'OAuth2Flows',
108
111
  'SecurityScheme',
109
112
  'XCodeSample',
113
+ 'XCodeSampleList',
110
114
  'WebhooksMap',
111
115
  ];
112
116
 
@@ -147,16 +151,8 @@ const ConfigRoot: NodeType = {
147
151
  properties: {
148
152
  organization: { type: 'string' },
149
153
  apis: 'ConfigApis',
150
- apiDefinitions: {
151
- type: 'object',
152
- properties: {},
153
- additionalProperties: { properties: { type: 'string' } },
154
- }, // deprecated
155
154
  ...RootConfigStyleguide.properties,
156
- styleguide: 'RootConfigStyleguide', // deprecated
157
- lint: 'RootConfigStyleguide', // deprecated
158
155
  'features.openapi': 'ConfigReferenceDocs',
159
- referenceDocs: 'ConfigReferenceDocs', // deprecated
160
156
  'features.mockServer': 'ConfigMockServer',
161
157
  region: { enum: ['us', 'eu'] },
162
158
  resolve: {
@@ -239,15 +235,9 @@ const ObjectRule: NodeType = {
239
235
  required: ['severity'],
240
236
  };
241
237
 
242
- const Assert: NodeType = {
238
+ const AssertionDefinitionSubject: NodeType = {
243
239
  properties: {
244
- subject: (value: unknown) => {
245
- if (Array.isArray(value)) {
246
- return { type: 'array', items: { enum: nodeTypesList } };
247
- } else {
248
- return { enum: nodeTypesList };
249
- }
250
- },
240
+ type: { enum: nodeTypesList },
251
241
  property: (value: unknown) => {
252
242
  if (Array.isArray(value)) {
253
243
  return { type: 'array', items: { type: 'string' } };
@@ -257,10 +247,15 @@ const Assert: NodeType = {
257
247
  return { type: 'string' };
258
248
  }
259
249
  },
260
- context: listOf('Context'),
261
- message: { type: 'string' },
262
- suggest: { type: 'array', items: { type: 'string' } },
263
- severity: { enum: ['error', 'warn', 'off'] },
250
+ filterInParentKeys: { type: 'array', items: { type: 'string' } },
251
+ filterOutParentKeys: { type: 'array', items: { type: 'string' } },
252
+ matchParentKeys: { type: 'string' },
253
+ },
254
+ required: ['type'],
255
+ };
256
+
257
+ const AssertionDefinitionAssertions: NodeType = {
258
+ properties: {
264
259
  enum: { type: 'array', items: { type: 'string' } },
265
260
  pattern: { type: 'string' },
266
261
  casing: {
@@ -280,27 +275,50 @@ const Assert: NodeType = {
280
275
  requireAny: { type: 'array', items: { type: 'string' } },
281
276
  disallowed: { type: 'array', items: { type: 'string' } },
282
277
  defined: { type: 'boolean' },
283
- undefined: { type: 'boolean' },
278
+ // undefined: { type: 'boolean' }, // TODO: Remove `undefined` assertion from codebase overall
284
279
  nonEmpty: { type: 'boolean' },
285
280
  minLength: { type: 'integer' },
286
281
  maxLength: { type: 'integer' },
287
282
  ref: (value: string | boolean) =>
288
283
  typeof value === 'string' ? { type: 'string' } : { type: 'boolean' },
284
+ const: (value: string | boolean | number) => {
285
+ if (typeof value === 'string') {
286
+ return { type: 'string' };
287
+ }
288
+ if (typeof value === 'number') {
289
+ return { type: 'number' };
290
+ }
291
+ if (typeof value === 'boolean') {
292
+ return { type: 'boolean' };
293
+ } else {
294
+ return;
295
+ }
296
+ },
289
297
  },
290
298
  additionalProperties: (_value: unknown, key: string) => {
291
299
  if (/^\w+\/\w+$/.test(key)) return { type: 'object' };
292
300
  return;
293
301
  },
294
- required: ['subject'],
295
302
  };
296
303
 
297
- const Context: NodeType = {
304
+ const AssertDefinition: NodeType = {
298
305
  properties: {
299
- type: { enum: nodeTypesList },
300
- matchParentKeys: { type: 'array', items: { type: 'string' } },
301
- excludeParentKeys: { type: 'array', items: { type: 'string' } },
306
+ subject: 'AssertionDefinitionSubject',
307
+ assertions: 'AssertionDefinitionAssertions',
302
308
  },
303
- required: ['type'],
309
+ required: ['subject', 'assertions'],
310
+ };
311
+
312
+ const Assert: NodeType = {
313
+ properties: {
314
+ subject: 'AssertionDefinitionSubject',
315
+ assertions: 'AssertionDefinitionAssertions',
316
+ where: listOf('AssertDefinition'),
317
+ message: { type: 'string' },
318
+ suggest: { type: 'array', items: { type: 'string' } },
319
+ severity: { enum: ['error', 'warn', 'off'] },
320
+ },
321
+ required: ['subject', 'assertions'],
304
322
  };
305
323
 
306
324
  const ConfigLanguage: NodeType = {
@@ -926,7 +944,7 @@ export const ConfigTypes: Record<string, NodeType> = {
926
944
  ConfigSidebarLinks,
927
945
  CommonConfigSidebarLinks,
928
946
  ConfigTheme,
929
- Context,
947
+ AssertDefinition,
930
948
  ThemeColors,
931
949
  CommonThemeColors,
932
950
  BorderThemeColors,
@@ -973,4 +991,6 @@ export const ConfigTypes: Record<string, NodeType> = {
973
991
  Sidebar,
974
992
  Heading,
975
993
  Typography,
994
+ AssertionDefinitionAssertions,
995
+ AssertionDefinitionSubject,
976
996
  };
package/src/utils.ts CHANGED
@@ -232,6 +232,11 @@ export function identity<T>(value: T): T {
232
232
  return value;
233
233
  }
234
234
 
235
+ export function keysOf<T>(obj: T) {
236
+ if (!obj) return [];
237
+ return Object.keys(obj) as (keyof T)[];
238
+ }
239
+
235
240
  export function pickDefined<T extends Record<string, unknown>>(
236
241
  obj?: T
237
242
  ): Record<string, unknown> | undefined {
@@ -244,3 +249,9 @@ export function pickDefined<T extends Record<string, unknown>>(
244
249
  }
245
250
  return res;
246
251
  }
252
+
253
+ export function nextTick() {
254
+ new Promise((resolve) => {
255
+ setTimeout(resolve);
256
+ });
257
+ }
package/src/visitors.ts CHANGED
@@ -50,6 +50,11 @@ import type { Stack } from './utils';
50
50
  import type { UserContext, ResolveResult, ProblemSeverity } from './walk';
51
51
  import type { Location } from './ref-utils';
52
52
 
53
+ export type SkipFunctionContext = Pick<
54
+ UserContext,
55
+ 'location' | 'rawNode' | 'resolve' | 'rawLocation'
56
+ >;
57
+
53
58
  export type VisitFunction<T> = (
54
59
  node: T,
55
60
  ctx: UserContext & { ignoreNextVisitorsOnNode: () => void },
@@ -59,7 +64,7 @@ export type VisitFunction<T> = (
59
64
 
60
65
  type VisitRefFunction = (node: OasRef, ctx: UserContext, resolved: ResolveResult<any>) => void;
61
66
 
62
- type SkipFunction<T> = (node: T, key: string | number) => boolean;
67
+ type SkipFunction<T> = (node: T, key: string | number, ctx: SkipFunctionContext) => boolean;
63
68
 
64
69
  type VisitObject<T> = {
65
70
  enter?: VisitFunction<T>;
@@ -210,6 +215,7 @@ const legacyTypesMap = {
210
215
  HeadersMap: 'HeaderMap',
211
216
  LinksMap: 'LinkMap',
212
217
  OAuth2Flows: 'SecuritySchemeFlows',
218
+ Responses: 'ResponsesMap',
213
219
  };
214
220
 
215
221
  type Oas3NestedVisitor = {
package/src/walk.ts CHANGED
@@ -226,7 +226,14 @@ export function walkDocument<T>(opts: {
226
226
  nextLevelTypeActivated: null,
227
227
  withParentNode: context.parent?.activatedOn?.value.node,
228
228
  skipped:
229
- (context.parent?.activatedOn?.value.skipped || skip?.(resolvedNode, key)) ?? false,
229
+ (context.parent?.activatedOn?.value.skipped ||
230
+ skip?.(resolvedNode, key, {
231
+ location,
232
+ rawLocation,
233
+ resolve,
234
+ rawNode: node,
235
+ })) ??
236
+ false,
230
237
  };
231
238
 
232
239
  context.activatedOn = pushStack<any>(context.activatedOn, activatedOn);