@redocly/openapi-core 1.0.0-beta.108 → 1.0.0-beta.110

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 (159) hide show
  1. package/README.md +2 -2
  2. package/lib/benchmark/benches/resolve-with-no-external.bench.js +1 -1
  3. package/lib/bundle.d.ts +1 -1
  4. package/lib/bundle.js +4 -4
  5. package/lib/config/all.js +3 -1
  6. package/lib/config/config-resolvers.js +22 -4
  7. package/lib/config/config.d.ts +1 -0
  8. package/lib/config/config.js +1 -0
  9. package/lib/config/load.d.ts +8 -2
  10. package/lib/config/load.js +4 -2
  11. package/lib/config/minimal.js +3 -1
  12. package/lib/config/recommended.js +3 -1
  13. package/lib/config/rules.js +1 -1
  14. package/lib/config/types.d.ts +17 -0
  15. package/lib/config/utils.d.ts +2 -2
  16. package/lib/config/utils.js +44 -6
  17. package/lib/decorators/common/registry-dependencies.js +1 -1
  18. package/lib/format/format.d.ts +1 -1
  19. package/lib/format/format.js +22 -1
  20. package/lib/lint.js +2 -2
  21. package/lib/redocly/registry-api.d.ts +0 -1
  22. package/lib/redocly/registry-api.js +5 -4
  23. package/lib/resolve.js +3 -1
  24. package/lib/rules/ajv.d.ts +1 -1
  25. package/lib/rules/ajv.js +5 -5
  26. package/lib/rules/common/assertions/asserts.d.ts +3 -5
  27. package/lib/rules/common/assertions/asserts.js +137 -97
  28. package/lib/rules/common/assertions/index.js +2 -6
  29. package/lib/rules/common/assertions/utils.d.ts +12 -6
  30. package/lib/rules/common/assertions/utils.js +33 -20
  31. package/lib/rules/common/no-ambiguous-paths.js +1 -1
  32. package/lib/rules/common/no-identical-paths.js +1 -1
  33. package/lib/rules/common/operation-2xx-response.js +1 -1
  34. package/lib/rules/common/operation-4xx-response.js +1 -1
  35. package/lib/rules/common/operation-operationId.js +1 -1
  36. package/lib/rules/common/operation-tag-defined.js +1 -1
  37. package/lib/rules/common/path-not-include-query.js +1 -1
  38. package/lib/rules/common/security-defined.d.ts +2 -0
  39. package/lib/rules/common/{operation-security-defined.js → security-defined.js} +18 -4
  40. package/lib/rules/common/spec.js +12 -1
  41. package/lib/rules/common/tags-alphabetical.js +1 -1
  42. package/lib/rules/oas2/index.d.ts +1 -1
  43. package/lib/rules/oas2/index.js +2 -2
  44. package/lib/rules/oas2/remove-unused-components.js +1 -1
  45. package/lib/rules/oas2/request-mime-type.js +1 -1
  46. package/lib/rules/oas2/response-mime-type.js +1 -1
  47. package/lib/rules/oas3/index.js +6 -2
  48. package/lib/rules/oas3/no-empty-servers.js +1 -1
  49. package/lib/rules/oas3/no-server-variables-empty-enum.js +1 -1
  50. package/lib/rules/oas3/no-unused-components.js +1 -1
  51. package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.d.ts +5 -0
  52. package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.js +36 -0
  53. package/lib/rules/oas3/remove-unused-components.js +1 -1
  54. package/lib/rules/oas3/request-mime-type.js +1 -1
  55. package/lib/rules/oas3/response-mime-type.js +1 -1
  56. package/lib/rules/oas3/spec-components-invalid-map-name.d.ts +2 -0
  57. package/lib/rules/oas3/spec-components-invalid-map-name.js +46 -0
  58. package/lib/rules/other/stats.d.ts +2 -2
  59. package/lib/rules/other/stats.js +2 -2
  60. package/lib/rules/utils.js +1 -1
  61. package/lib/types/oas2.js +5 -5
  62. package/lib/types/oas3.js +27 -20
  63. package/lib/types/oas3_1.js +3 -3
  64. package/lib/types/redocly-yaml.js +60 -54
  65. package/lib/utils.d.ts +3 -3
  66. package/lib/utils.js +5 -5
  67. package/lib/visitors.d.ts +11 -11
  68. package/lib/visitors.js +13 -1
  69. package/package.json +3 -5
  70. package/src/__tests__/__snapshots__/bundle.test.ts.snap +3 -3
  71. package/src/__tests__/fixtures/extension.js +3 -3
  72. package/src/__tests__/format.test.ts +76 -0
  73. package/src/__tests__/lint.test.ts +184 -121
  74. package/src/__tests__/resolve-http.test.ts +1 -1
  75. package/src/__tests__/resolve.test.ts +9 -9
  76. package/src/__tests__/walk.test.ts +78 -10
  77. package/src/benchmark/benches/resolve-with-no-external.bench.ts +1 -1
  78. package/src/bundle.ts +4 -4
  79. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +6 -2
  80. package/src/config/__tests__/config-resolvers.test.ts +37 -1
  81. package/src/config/__tests__/config.test.ts +5 -0
  82. package/src/config/__tests__/fixtures/plugin-config.yaml +2 -3
  83. package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +11 -12
  84. package/src/config/__tests__/fixtures/resolve-config/local-config-with-circular.yaml +7 -8
  85. package/src/config/__tests__/fixtures/resolve-config/local-config-with-custom-function.yaml +16 -0
  86. package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +18 -19
  87. package/src/config/__tests__/fixtures/resolve-config/local-config-with-wrong-custom-function.yaml +16 -0
  88. package/src/config/__tests__/fixtures/resolve-config/local-config.yaml +9 -10
  89. package/src/config/__tests__/fixtures/resolve-config/plugin.js +11 -0
  90. package/src/config/__tests__/fixtures/resolve-remote-configs/nested-remote-config.yaml +3 -4
  91. package/src/config/__tests__/fixtures/resolve-remote-configs/remote-config.yaml +4 -5
  92. package/src/config/__tests__/load.test.ts +13 -16
  93. package/src/config/__tests__/resolve-plugins.test.ts +3 -3
  94. package/src/config/__tests__/utils.test.ts +64 -4
  95. package/src/config/all.ts +3 -1
  96. package/src/config/config-resolvers.ts +30 -7
  97. package/src/config/config.ts +2 -0
  98. package/src/config/load.ts +13 -6
  99. package/src/config/minimal.ts +3 -1
  100. package/src/config/recommended.ts +3 -1
  101. package/src/config/rules.ts +2 -2
  102. package/src/config/types.ts +24 -0
  103. package/src/config/utils.ts +103 -13
  104. package/src/decorators/common/registry-dependencies.ts +1 -1
  105. package/src/format/format.ts +32 -2
  106. package/src/lint.ts +2 -2
  107. package/src/redocly/registry-api.ts +5 -4
  108. package/src/resolve.ts +3 -1
  109. package/src/rules/__tests__/utils.test.ts +1 -1
  110. package/src/rules/ajv.ts +4 -4
  111. package/src/rules/common/__tests__/no-enum-type-mismatch.test.ts +1 -0
  112. package/src/rules/common/__tests__/operation-2xx-response.test.ts +1 -1
  113. package/src/rules/common/__tests__/operation-4xx-response.test.ts +26 -3
  114. package/src/rules/common/__tests__/security-defined.test.ts +175 -0
  115. package/src/rules/common/__tests__/spec.test.ts +79 -0
  116. package/src/rules/common/assertions/__tests__/asserts.test.ts +491 -428
  117. package/src/rules/common/assertions/__tests__/utils.test.ts +2 -2
  118. package/src/rules/common/assertions/asserts.ts +155 -97
  119. package/src/rules/common/assertions/index.ts +2 -11
  120. package/src/rules/common/assertions/utils.ts +66 -36
  121. package/src/rules/common/no-ambiguous-paths.ts +1 -1
  122. package/src/rules/common/no-identical-paths.ts +1 -1
  123. package/src/rules/common/operation-2xx-response.ts +1 -1
  124. package/src/rules/common/operation-4xx-response.ts +1 -1
  125. package/src/rules/common/operation-operationId.ts +1 -1
  126. package/src/rules/common/operation-tag-defined.ts +1 -1
  127. package/src/rules/common/path-not-include-query.ts +1 -1
  128. package/src/rules/common/{operation-security-defined.ts → security-defined.ts} +19 -4
  129. package/src/rules/common/spec.ts +15 -1
  130. package/src/rules/common/tags-alphabetical.ts +1 -1
  131. package/src/rules/oas2/index.ts +2 -2
  132. package/src/rules/oas2/remove-unused-components.ts +1 -1
  133. package/src/rules/oas2/request-mime-type.ts +1 -1
  134. package/src/rules/oas2/response-mime-type.ts +1 -1
  135. package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +51 -2
  136. package/src/rules/oas3/__tests__/operation-4xx-problem-details-rfc7807.test.ts +145 -0
  137. package/src/rules/oas3/__tests__/spec/spec.test.ts +10 -0
  138. package/src/rules/oas3/__tests__/spec-components-invalid-map-name.test.ts +217 -0
  139. package/src/rules/oas3/index.ts +6 -2
  140. package/src/rules/oas3/no-empty-servers.ts +1 -1
  141. package/src/rules/oas3/no-server-variables-empty-enum.ts +1 -1
  142. package/src/rules/oas3/no-unused-components.ts +1 -1
  143. package/src/rules/oas3/operation-4xx-problem-details-rfc7807.ts +36 -0
  144. package/src/rules/oas3/remove-unused-components.ts +1 -1
  145. package/src/rules/oas3/request-mime-type.ts +1 -1
  146. package/src/rules/oas3/response-mime-type.ts +1 -1
  147. package/src/rules/oas3/spec-components-invalid-map-name.ts +53 -0
  148. package/src/rules/other/stats.ts +2 -2
  149. package/src/rules/utils.ts +2 -1
  150. package/src/types/index.ts +2 -2
  151. package/src/types/oas2.ts +5 -5
  152. package/src/types/oas3.ts +27 -20
  153. package/src/types/oas3_1.ts +3 -3
  154. package/src/types/redocly-yaml.ts +66 -38
  155. package/src/utils.ts +11 -7
  156. package/src/visitors.ts +29 -13
  157. package/tsconfig.tsbuildinfo +1 -1
  158. package/lib/rules/common/operation-security-defined.d.ts +0 -2
  159. package/src/rules/common/__tests__/operation-security-defined.test.ts +0 -69
@@ -25,7 +25,7 @@ import { NoUnusedComponents } from './no-unused-components';
25
25
  import { PathNotIncludeQuery } from '../common/path-not-include-query';
26
26
  import { ParameterDescription } from '../common/parameter-description';
27
27
  import { OperationSingularTag } from '../common/operation-singular-tag';
28
- import { OperationSecurityDefined } from '../common/operation-security-defined';
28
+ import { SecurityDefined } from '../common/security-defined';
29
29
  import { NoUnresolvedRefs } from '../no-unresolved-refs';
30
30
  import { BooleanParameterPrefixes } from './boolean-parameter-prefixes';
31
31
  import { PathsKebabCase } from '../common/paths-kebab-case';
@@ -48,6 +48,8 @@ import { NoInvalidParameterExamples } from '../common/no-invalid-parameter-examp
48
48
  import { ResponseContainsHeader } from '../common/response-contains-header';
49
49
  import { ResponseContainsProperty } from './response-contains-property';
50
50
  import { ScalarPropertyMissingExample } from '../common/scalar-property-missing-example';
51
+ import { SpecComponentsInvalidMapName } from './spec-components-invalid-map-name';
52
+ import { Operation4xxProblemDetailsRfc7807 } from './operation-4xx-problem-details-rfc7807';
51
53
 
52
54
  export const rules = {
53
55
  spec: OasSpec,
@@ -57,6 +59,7 @@ export const rules = {
57
59
  'info-license-url': InfoLicenseUrl,
58
60
  'operation-2xx-response': Operation2xxResponse,
59
61
  'operation-4xx-response': Operation4xxResponse,
62
+ 'operation-4xx-problem-details-rfc7807': Operation4xxProblemDetailsRfc7807,
60
63
  assertions: Assertions,
61
64
  'operation-operationId-unique': OperationIdUnique,
62
65
  'operation-parameters-unique': OperationParametersUnique,
@@ -80,7 +83,7 @@ export const rules = {
80
83
  'path-params-defined': PathParamsDefined,
81
84
  'parameter-description': ParameterDescription,
82
85
  'operation-singular-tag': OperationSingularTag,
83
- 'operation-security-defined': OperationSecurityDefined,
86
+ 'security-defined': SecurityDefined,
84
87
  'no-unresolved-refs': NoUnresolvedRefs,
85
88
  'paths-kebab-case': PathsKebabCase,
86
89
  'boolean-parameter-prefixes': BooleanParameterPrefixes,
@@ -100,6 +103,7 @@ export const rules = {
100
103
  'response-contains-header': ResponseContainsHeader,
101
104
  'response-contains-property': ResponseContainsProperty,
102
105
  'scalar-property-missing-example': ScalarPropertyMissingExample,
106
+ 'spec-components-invalid-map-name': SpecComponentsInvalidMapName,
103
107
  } as Oas3RuleSet;
104
108
 
105
109
  export const preprocessors = {};
@@ -2,7 +2,7 @@ import { Oas3Rule } from '../../visitors';
2
2
 
3
3
  export const NoEmptyServers: Oas3Rule = () => {
4
4
  return {
5
- DefinitionRoot(root, { report, location }) {
5
+ Root(root, { report, location }) {
6
6
  if (!root.hasOwnProperty('servers')) {
7
7
  report({
8
8
  message: 'Servers must be present.',
@@ -8,7 +8,7 @@ enum enumError {
8
8
 
9
9
  export const NoServerVariablesEmptyEnum: Oas3Rule = () => {
10
10
  return {
11
- DefinitionRoot(root, { report, location }) {
11
+ Root(root, { report, location }) {
12
12
  if (!root.servers || root.servers.length === 0) return;
13
13
 
14
14
  const invalidVariables: enumError[] = [];
@@ -26,7 +26,7 @@ export const NoUnusedComponents: Oas3Rule = () => {
26
26
  });
27
27
  }
28
28
  },
29
- DefinitionRoot: {
29
+ Root: {
30
30
  leave(_, { report }) {
31
31
  components.forEach((usageInfo) => {
32
32
  if (!usageInfo.used) {
@@ -0,0 +1,36 @@
1
+ import { Oas3MediaType, Oas3Response, Oas3Schema } from 'core/src/typings/openapi';
2
+ import { Oas3Rule } from '../../visitors';
3
+ import { UserContext } from '../../walk';
4
+ import { validateDefinedAndNonEmpty } from '../utils';
5
+
6
+ /**
7
+ * Validation according rfc7807 - https://datatracker.ietf.org/doc/html/rfc7807
8
+ */
9
+ export const Operation4xxProblemDetailsRfc7807: Oas3Rule = () => {
10
+ return {
11
+ Response: {
12
+ skip(_response: Oas3Response, key: string | number) {
13
+ return !/4[Xx0-9]{2}/.test(`${key}`);
14
+ },
15
+ enter(response: Oas3Response, { report, location }: UserContext) {
16
+ if (!response.content || !response.content['application/problem+json'])
17
+ report({
18
+ message: 'Response `4xx` must have content-type `application/problem+json`.',
19
+ location: location.key(),
20
+ });
21
+ },
22
+ MediaType: {
23
+ skip(_response: Oas3MediaType, key: string | number) {
24
+ return key !== 'application/problem+json';
25
+ },
26
+ enter(media: Oas3MediaType, ctx: UserContext) {
27
+ validateDefinedAndNonEmpty('schema', media, ctx);
28
+ },
29
+ SchemaProperties(schema: Oas3Schema, ctx: UserContext) {
30
+ validateDefinedAndNonEmpty('type', schema, ctx);
31
+ validateDefinedAndNonEmpty('title', schema, ctx);
32
+ },
33
+ },
34
+ },
35
+ };
36
+ };
@@ -38,7 +38,7 @@ export const RemoveUnusedComponents: Oas3Rule = () => {
38
38
  }
39
39
  },
40
40
  },
41
- DefinitionRoot: {
41
+ Root: {
42
42
  leave(root, ctx) {
43
43
  const data = ctx.getVisitorData() as { removedCount: number };
44
44
  data.removedCount = 0;
@@ -5,7 +5,7 @@ import { validateMimeTypeOAS3 } from '../../utils';
5
5
 
6
6
  export const RequestMimeType: Oas3Rule = ({ allowedValues }) => {
7
7
  return {
8
- PathMap: {
8
+ PathsMap: {
9
9
  RequestBody: {
10
10
  leave(requestBody: Oas3RequestBody, ctx: UserContext) {
11
11
  validateMimeTypeOAS3({ type: 'consumes', value: requestBody }, ctx, allowedValues);
@@ -5,7 +5,7 @@ import { validateMimeTypeOAS3 } from '../../utils';
5
5
 
6
6
  export const ResponseMimeType: Oas3Rule = ({ allowedValues }) => {
7
7
  return {
8
- PathMap: {
8
+ PathsMap: {
9
9
  Response: {
10
10
  leave(response: Oas3Response, ctx: UserContext) {
11
11
  validateMimeTypeOAS3({ type: 'produces', value: response }, ctx, allowedValues);
@@ -0,0 +1,53 @@
1
+ import { Oas3Rule } from '../../visitors';
2
+ import { Problem, UserContext } from '../../walk';
3
+ import { Location } from '../../ref-utils';
4
+
5
+ export const SpecComponentsInvalidMapName: Oas3Rule = () => {
6
+ const KEYS_REGEX = '^[a-zA-Z0-9\\.\\-_]+$';
7
+
8
+ function validateKey(
9
+ key: string | number,
10
+ report: (problem: Problem) => void,
11
+ location: Location,
12
+ component: string
13
+ ) {
14
+ if (!new RegExp(KEYS_REGEX).test(key as string)) {
15
+ report({
16
+ message: `The map key in ${component} "${key}" does not match the regular expression "${KEYS_REGEX}"`,
17
+ location: location.key(),
18
+ });
19
+ }
20
+ }
21
+
22
+ return {
23
+ Components: {
24
+ Parameter(_node, { key, report, location }: UserContext) {
25
+ validateKey(key, report, location, 'parameters');
26
+ },
27
+ Response(_node, { key, report, location }: UserContext) {
28
+ validateKey(key, report, location, 'responses');
29
+ },
30
+ Schema(_node, { key, report, location }: UserContext) {
31
+ validateKey(key, report, location, 'schemas');
32
+ },
33
+ Example(_node, { key, report, location }: UserContext) {
34
+ validateKey(key, report, location, 'examples');
35
+ },
36
+ RequestBody(_node, { key, report, location }: UserContext) {
37
+ validateKey(key, report, location, 'requestBodies');
38
+ },
39
+ Header(_node, { key, report, location }: UserContext) {
40
+ validateKey(key, report, location, 'headers');
41
+ },
42
+ SecurityScheme(_node, { key, report, location }: UserContext) {
43
+ validateKey(key, report, location, 'securitySchemas');
44
+ },
45
+ Link(_node, { key, report, location }: UserContext) {
46
+ validateKey(key, report, location, 'links');
47
+ },
48
+ Callback(_node, { key, report, location }: UserContext) {
49
+ validateKey(key, report, location, 'callbacks');
50
+ },
51
+ },
52
+ };
53
+ };
@@ -24,7 +24,7 @@ export const Stats = (statsAccumulator: StatsAccumulator) => {
24
24
  statsAccumulator.links.items!.add(link.operationId);
25
25
  },
26
26
  },
27
- DefinitionRoot: {
27
+ Root: {
28
28
  leave() {
29
29
  statsAccumulator.parameters.total = statsAccumulator.parameters.items!.size;
30
30
  statsAccumulator.refs.total = statsAccumulator.refs.items!.size;
@@ -41,7 +41,7 @@ export const Stats = (statsAccumulator: StatsAccumulator) => {
41
41
  },
42
42
  },
43
43
  },
44
- PathMap: {
44
+ PathsMap: {
45
45
  PathItem: {
46
46
  leave() {
47
47
  statsAccumulator.pathItems.total++;
@@ -109,7 +109,8 @@ export function validateExample(
109
109
  message: `Example value must conform to the schema: ${error.message}.`,
110
110
  location: {
111
111
  ...new Location(dataLoc.source, error.instancePath),
112
- reportOnKey: error.keyword === 'additionalProperties',
112
+ reportOnKey:
113
+ error.keyword === 'unevaluatedProperties' || error.keyword === 'additionalProperties',
113
114
  },
114
115
  from: location,
115
116
  suggest: error.suggest,
@@ -73,7 +73,7 @@ export function normalizeTypes(
73
73
  normalizedTypes[typeName] = {
74
74
  ...types[typeName],
75
75
  name: typeName,
76
- } as any;
76
+ } as NormalizedNodeType;
77
77
  }
78
78
 
79
79
  for (const type of Object.values(normalizedTypes)) {
@@ -81,7 +81,7 @@ export function normalizeTypes(
81
81
  }
82
82
  return normalizedTypes;
83
83
 
84
- function normalizeType(type: any) {
84
+ function normalizeType(type: NormalizedNodeType) {
85
85
  if (type.additionalProperties) {
86
86
  type.additionalProperties = resolveType(type.additionalProperties);
87
87
  }
package/src/types/oas2.ts CHANGED
@@ -2,7 +2,7 @@ import { NodeType, listOf, mapOf } from '.';
2
2
 
3
3
  const responseCodeRegexp = /^[0-9][0-9Xx]{2}$/;
4
4
 
5
- const DefinitionRoot: NodeType = {
5
+ const Root: NodeType = {
6
6
  properties: {
7
7
  swagger: { type: 'string' },
8
8
  info: 'Info',
@@ -11,7 +11,7 @@ const DefinitionRoot: NodeType = {
11
11
  schemes: { type: 'array', items: { type: 'string' } },
12
12
  consumes: { type: 'array', items: { type: 'string' } },
13
13
  produces: { type: 'array', items: { type: 'string' } },
14
- paths: 'PathMap',
14
+ paths: 'PathsMap',
15
15
  definitions: 'NamedSchemas',
16
16
  parameters: 'NamedParameters',
17
17
  responses: 'NamedResponses',
@@ -51,7 +51,7 @@ const License: NodeType = {
51
51
  required: ['name'],
52
52
  };
53
53
 
54
- const PathMap: NodeType = {
54
+ const PathsMap: NodeType = {
55
55
  properties: {},
56
56
  additionalProperties: (_value: any, key: string) =>
57
57
  key.startsWith('/') ? 'PathItem' : undefined,
@@ -369,14 +369,14 @@ const SecurityRequirement: NodeType = {
369
369
  };
370
370
 
371
371
  export const Oas2Types: Record<string, NodeType> = {
372
- DefinitionRoot,
372
+ Root,
373
373
  Tag,
374
374
  ExternalDocs,
375
375
  SecurityRequirement,
376
376
  Info,
377
377
  Contact,
378
378
  License,
379
- PathMap,
379
+ PathsMap,
380
380
  PathItem,
381
381
  Parameter,
382
382
  ParameterItems,
package/src/types/oas3.ts CHANGED
@@ -2,7 +2,7 @@ import { NodeType, listOf, mapOf } from '.';
2
2
  import { isMappingRef } from '../ref-utils';
3
3
  const responseCodeRegexp = /^[0-9][0-9Xx]{2}$/;
4
4
 
5
- const DefinitionRoot: NodeType = {
5
+ const Root: NodeType = {
6
6
  properties: {
7
7
  openapi: null,
8
8
  info: 'Info',
@@ -10,7 +10,7 @@ const DefinitionRoot: NodeType = {
10
10
  security: listOf('SecurityRequirement'),
11
11
  tags: listOf('Tag'),
12
12
  externalDocs: 'ExternalDocs',
13
- paths: 'PathMap',
13
+ paths: 'PathsMap',
14
14
  components: 'Components',
15
15
  'x-webhooks': 'WebhooksMap',
16
16
  },
@@ -38,7 +38,7 @@ const Server: NodeType = {
38
38
  properties: {
39
39
  url: { type: 'string' },
40
40
  description: { type: 'string' },
41
- variables: mapOf('ServerVariable'),
41
+ variables: 'ServerVariablesMap',
42
42
  },
43
43
  required: ['url'],
44
44
  };
@@ -88,7 +88,7 @@ const License: NodeType = {
88
88
  required: ['name'],
89
89
  };
90
90
 
91
- const PathMap: NodeType = {
91
+ const PathsMap: NodeType = {
92
92
  properties: {},
93
93
  additionalProperties: (_value: any, key: string) =>
94
94
  key.startsWith('/') ? 'PathItem' : undefined,
@@ -132,8 +132,8 @@ const Parameter: NodeType = {
132
132
  allowReserved: { type: 'boolean' },
133
133
  schema: 'Schema',
134
134
  example: { isExample: true },
135
- examples: mapOf('Example'),
136
- content: 'MediaTypeMap',
135
+ examples: 'ExamplesMap',
136
+ content: 'MediaTypesMap',
137
137
  },
138
138
  required: ['name', 'in'],
139
139
  requiredOneOf: ['schema', 'content'],
@@ -155,7 +155,7 @@ const Operation: NodeType = {
155
155
  requestBody: 'RequestBody',
156
156
  responses: 'ResponsesMap',
157
157
  deprecated: { type: 'boolean' },
158
- callbacks: mapOf('Callback'),
158
+ callbacks: 'CallbacksMap',
159
159
  'x-codeSamples': listOf('XCodeSample'),
160
160
  'x-code-samples': listOf('XCodeSample'), // deprecated
161
161
  'x-hideTryItPanel': { type: 'boolean' },
@@ -175,12 +175,12 @@ const RequestBody: NodeType = {
175
175
  properties: {
176
176
  description: { type: 'string' },
177
177
  required: { type: 'boolean' },
178
- content: 'MediaTypeMap',
178
+ content: 'MediaTypesMap',
179
179
  },
180
180
  required: ['content'],
181
181
  };
182
182
 
183
- const MediaTypeMap: NodeType = {
183
+ const MediaTypesMap: NodeType = {
184
184
  properties: {},
185
185
  additionalProperties: 'MediaType',
186
186
  };
@@ -189,8 +189,8 @@ const MediaType: NodeType = {
189
189
  properties: {
190
190
  schema: 'Schema',
191
191
  example: { isExample: true },
192
- examples: mapOf('Example'),
193
- encoding: mapOf('Encoding'),
192
+ examples: 'ExamplesMap',
193
+ encoding: 'EncodingsMap',
194
194
  },
195
195
  };
196
196
 
@@ -206,7 +206,7 @@ const Example: NodeType = {
206
206
  const Encoding: NodeType = {
207
207
  properties: {
208
208
  contentType: { type: 'string' },
209
- headers: mapOf('Header'),
209
+ headers: 'HeadersMap',
210
210
  style: {
211
211
  enum: ['form', 'simple', 'label', 'matrix', 'spaceDelimited', 'pipeDelimited', 'deepObject'],
212
212
  },
@@ -228,9 +228,10 @@ const Header: NodeType = {
228
228
  allowReserved: { type: 'boolean' },
229
229
  schema: 'Schema',
230
230
  example: { isExample: true },
231
- examples: mapOf('Example'),
232
- content: 'MediaTypeMap',
231
+ examples: 'ExamplesMap',
232
+ content: 'MediaTypesMap',
233
233
  },
234
+ requiredOneOf: ['schema', 'content'],
234
235
  };
235
236
 
236
237
  const ResponsesMap: NodeType = {
@@ -242,9 +243,9 @@ const ResponsesMap: NodeType = {
242
243
  const Response: NodeType = {
243
244
  properties: {
244
245
  description: { type: 'string' },
245
- headers: mapOf('Header'),
246
- content: 'MediaTypeMap',
247
- links: mapOf('Link'),
246
+ headers: 'HeadersMap',
247
+ content: 'MediaTypesMap',
248
+ links: 'LinksMap',
248
249
  },
249
250
  required: ['description'],
250
251
  };
@@ -459,26 +460,31 @@ const SecurityScheme: NodeType = {
459
460
  };
460
461
 
461
462
  export const Oas3Types: Record<string, NodeType> = {
462
- DefinitionRoot,
463
+ Root,
463
464
  Tag,
464
465
  ExternalDocs,
465
466
  Server,
466
467
  ServerVariable,
468
+ ServerVariablesMap: mapOf('ServerVariable'),
467
469
  SecurityRequirement,
468
470
  Info,
469
471
  Contact,
470
472
  License,
471
- PathMap,
473
+ PathsMap,
472
474
  PathItem,
473
475
  Parameter,
474
476
  Operation,
475
477
  Callback: mapOf('PathItem'),
478
+ CallbacksMap: mapOf('Callback'),
476
479
  RequestBody,
477
- MediaTypeMap,
480
+ MediaTypesMap,
478
481
  MediaType,
479
482
  Example,
483
+ ExamplesMap: mapOf('Example'),
480
484
  Encoding,
485
+ EncodingsMap: mapOf('Encoding'),
481
486
  Header,
487
+ HeadersMap: mapOf('Header'),
482
488
  ResponsesMap,
483
489
  Response,
484
490
  Link,
@@ -488,6 +494,7 @@ export const Oas3Types: Record<string, NodeType> = {
488
494
  DiscriminatorMapping,
489
495
  Discriminator,
490
496
  Components,
497
+ LinksMap: mapOf('Link'),
491
498
  NamedSchemas: mapOf('Schema'),
492
499
  NamedResponses: mapOf('Response'),
493
500
  NamedParameters: mapOf('Parameter'),
@@ -1,7 +1,7 @@
1
1
  import { NodeType, listOf, mapOf } from '.';
2
2
  import { Oas3Types } from './oas3';
3
3
 
4
- const DefinitionRoot: NodeType = {
4
+ const Root: NodeType = {
5
5
  properties: {
6
6
  openapi: null,
7
7
  info: 'Info',
@@ -9,7 +9,7 @@ const DefinitionRoot: NodeType = {
9
9
  security: listOf('SecurityRequirement'),
10
10
  tags: listOf('Tag'),
11
11
  externalDocs: 'ExternalDocs',
12
- paths: 'PathMap',
12
+ paths: 'PathsMap',
13
13
  webhooks: 'WebhooksMap',
14
14
  components: 'Components',
15
15
  jsonSchemaDialect: { type: 'string' },
@@ -241,7 +241,7 @@ const SecurityScheme: NodeType = {
241
241
  export const Oas3_1Types: Record<string, NodeType> = {
242
242
  ...Oas3Types,
243
243
  Info,
244
- DefinitionRoot,
244
+ Root,
245
245
  Schema,
246
246
  License,
247
247
  Components,
@@ -1,5 +1,6 @@
1
1
  import { NodeType, listOf } from '.';
2
2
  import { omitObjectProps, pickObjectProps, isCustomRuleId } from '../utils';
3
+
3
4
  const builtInRulesList = [
4
5
  'spec',
5
6
  'info-description',
@@ -8,6 +9,7 @@ const builtInRulesList = [
8
9
  'info-license-url',
9
10
  'operation-2xx-response',
10
11
  'operation-4xx-response',
12
+ 'operation-4xx-problem-details-rfc7807',
11
13
  'assertions',
12
14
  'operation-operationId-unique',
13
15
  'operation-parameters-unique',
@@ -31,7 +33,7 @@ const builtInRulesList = [
31
33
  'path-params-defined',
32
34
  'parameter-description',
33
35
  'operation-singular-tag',
34
- 'operation-security-defined',
36
+ 'security-defined',
35
37
  'no-unresolved-refs',
36
38
  'paths-kebab-case',
37
39
  'boolean-parameter-prefixes',
@@ -51,31 +53,38 @@ const builtInRulesList = [
51
53
  'response-contains-header',
52
54
  'response-contains-property',
53
55
  'scalar-property-missing-example',
56
+ 'spec-components-invalid-map-name',
54
57
  ];
55
58
  const nodeTypesList = [
56
- 'DefinitionRoot',
59
+ 'Root',
57
60
  'Tag',
58
61
  'ExternalDocs',
59
62
  'Server',
60
63
  'ServerVariable',
64
+ 'ServerVariablesMap',
61
65
  'SecurityRequirement',
62
66
  'Info',
63
67
  'Contact',
64
68
  'License',
65
- 'PathMap',
69
+ 'PathsMap',
66
70
  'PathItem',
67
71
  'Parameter',
68
72
  'Operation',
69
73
  'Callback',
74
+ 'CallbacksMap',
70
75
  'RequestBody',
71
- 'MediaTypeMap',
76
+ 'MediaTypesMap',
72
77
  'MediaType',
73
78
  'Example',
79
+ 'ExamplesMap',
74
80
  'Encoding',
81
+ 'EncodingsMap',
75
82
  'Header',
83
+ 'HeadersMap',
76
84
  'ResponsesMap',
77
85
  'Response',
78
86
  'Link',
87
+ 'LinksMap',
79
88
  'Schema',
80
89
  'Xml',
81
90
  'SchemaProperties',
@@ -101,6 +110,39 @@ const nodeTypesList = [
101
110
  'WebhooksMap',
102
111
  ];
103
112
 
113
+ const ConfigStyleguide: NodeType = {
114
+ properties: {
115
+ extends: {
116
+ type: 'array',
117
+ items: {
118
+ type: 'string',
119
+ },
120
+ },
121
+ rules: 'Rules',
122
+ oas2Rules: 'Rules',
123
+ oas3_0Rules: 'Rules',
124
+ oas3_1Rules: 'Rules',
125
+ preprocessors: { type: 'object' },
126
+ oas2Preprocessors: { type: 'object' },
127
+ oas3_0Preprocessors: { type: 'object' },
128
+ oas3_1Preprocessors: { type: 'object' },
129
+ decorators: { type: 'object' },
130
+ oas2Decorators: { type: 'object' },
131
+ oas3_0Decorators: { type: 'object' },
132
+ oas3_1Decorators: { type: 'object' },
133
+ },
134
+ };
135
+
136
+ const RootConfigStyleguide: NodeType = {
137
+ properties: {
138
+ plugins: {
139
+ type: 'array',
140
+ items: { type: 'string' },
141
+ },
142
+ ...ConfigStyleguide.properties,
143
+ },
144
+ };
145
+
104
146
  const ConfigRoot: NodeType = {
105
147
  properties: {
106
148
  organization: { type: 'string' },
@@ -110,7 +152,8 @@ const ConfigRoot: NodeType = {
110
152
  properties: {},
111
153
  additionalProperties: { properties: { type: 'string' } },
112
154
  }, // deprecated
113
- styleguide: 'RootConfigStyleguide',
155
+ ...RootConfigStyleguide.properties,
156
+ styleguide: 'RootConfigStyleguide', // deprecated
114
157
  lint: 'RootConfigStyleguide', // deprecated
115
158
  'features.openapi': 'ConfigReferenceDocs',
116
159
  referenceDocs: 'ConfigReferenceDocs', // deprecated
@@ -119,6 +162,13 @@ const ConfigRoot: NodeType = {
119
162
  resolve: {
120
163
  properties: {
121
164
  http: 'ConfigHTTP',
165
+ doNotResolveExamples: { type: 'boolean' },
166
+ },
167
+ },
168
+ files: {
169
+ type: 'array',
170
+ items: {
171
+ type: 'string',
122
172
  },
123
173
  },
124
174
  },
@@ -138,55 +188,29 @@ const ConfigApisProperties: NodeType = {
138
188
  type: 'string',
139
189
  },
140
190
  },
141
- styleguide: 'ConfigStyleguide',
191
+ lint: 'ConfigStyleguide', // deprecated
192
+ styleguide: 'ConfigStyleguide', // deprecated
193
+ ...ConfigStyleguide.properties,
142
194
  'features.openapi': 'ConfigReferenceDocs',
143
195
  'features.mockServer': 'ConfigMockServer',
144
- },
145
- required: ['root'],
146
- };
147
-
148
- const ConfigHTTP: NodeType = {
149
- properties: {
150
- headers: {
196
+ files: {
151
197
  type: 'array',
152
198
  items: {
153
199
  type: 'string',
154
200
  },
155
201
  },
156
202
  },
203
+ required: ['root'],
157
204
  };
158
205
 
159
- const ConfigStyleguide: NodeType = {
206
+ const ConfigHTTP: NodeType = {
160
207
  properties: {
161
- extends: {
208
+ headers: {
162
209
  type: 'array',
163
210
  items: {
164
211
  type: 'string',
165
212
  },
166
213
  },
167
- doNotResolveExamples: { type: 'boolean' },
168
- rules: 'Rules',
169
- oas2Rules: 'Rules',
170
- oas3_0Rules: 'Rules',
171
- oas3_1Rules: 'Rules',
172
- preprocessors: { type: 'object' },
173
- oas2Preprocessors: { type: 'object' },
174
- oas3_0Preprocessors: { type: 'object' },
175
- oas3_1Preprocessors: { type: 'object' },
176
- decorators: { type: 'object' },
177
- oas2Decorators: { type: 'object' },
178
- oas3_0Decorators: { type: 'object' },
179
- oas3_1Decorators: { type: 'object' },
180
- },
181
- };
182
-
183
- const RootConfigStyleguide: NodeType = {
184
- properties: {
185
- plugins: {
186
- type: 'array',
187
- items: { type: 'string' },
188
- },
189
- ...ConfigStyleguide.properties,
190
214
  },
191
215
  };
192
216
 
@@ -263,6 +287,10 @@ const Assert: NodeType = {
263
287
  ref: (value: string | boolean) =>
264
288
  typeof value === 'string' ? { type: 'string' } : { type: 'boolean' },
265
289
  },
290
+ additionalProperties: (_value: unknown, key: string) => {
291
+ if (/^\w+\/\w+$/.test(key)) return { type: 'object' };
292
+ return;
293
+ },
266
294
  required: ['subject'],
267
295
  };
268
296