@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
@@ -6,13 +6,18 @@ import { isPlainObject } from '../../utils';
6
6
 
7
7
  export const OasSpec: Oas3Rule | Oas2Rule = () => {
8
8
  return {
9
- any(node: any, { report, type, location, key, resolve, ignoreNextVisitorsOnNode }) {
9
+ any(
10
+ node: any,
11
+ { report, type, location, rawLocation, key, resolve, ignoreNextVisitorsOnNode }
12
+ ) {
10
13
  const nodeType = oasTypeOf(node);
14
+ const refLocation = rawLocation !== location ? rawLocation : undefined;
11
15
 
12
16
  if (type.items) {
13
17
  if (nodeType !== 'array') {
14
18
  report({
15
19
  message: `Expected type \`${type.name}\` (array) but got \`${nodeType}\``,
20
+ from: refLocation,
16
21
  });
17
22
  ignoreNextVisitorsOnNode();
18
23
  }
@@ -20,6 +25,7 @@ export const OasSpec: Oas3Rule | Oas2Rule = () => {
20
25
  } else if (nodeType !== 'object') {
21
26
  report({
22
27
  message: `Expected type \`${type.name}\` (object) but got \`${nodeType}\``,
28
+ from: refLocation,
23
29
  });
24
30
  ignoreNextVisitorsOnNode();
25
31
  return;
@@ -32,6 +38,7 @@ export const OasSpec: Oas3Rule | Oas2Rule = () => {
32
38
  if (!(node as object).hasOwnProperty(propName)) {
33
39
  report({
34
40
  message: `The field \`${propName}\` must be present on this level.`,
41
+ from: refLocation,
35
42
  location: [{ reportOnKey: true }],
36
43
  });
37
44
  }
@@ -49,6 +56,7 @@ export const OasSpec: Oas3Rule | Oas2Rule = () => {
49
56
  }
50
57
  report({
51
58
  message: `The field \`${propName}\` is not allowed here.`,
59
+ from: refLocation,
52
60
  location: location.child([propName]).key(),
53
61
  });
54
62
  }
@@ -67,6 +75,7 @@ export const OasSpec: Oas3Rule | Oas2Rule = () => {
67
75
  message: `Must contain at least one of the following fields: ${type.requiredOneOf?.join(
68
76
  ', '
69
77
  )}.`,
78
+ from: refLocation,
70
79
  location: [{ reportOnKey: true }],
71
80
  });
72
81
  }
@@ -91,6 +100,7 @@ export const OasSpec: Oas3Rule | Oas2Rule = () => {
91
100
  report({
92
101
  message: `Property \`${propName}\` is not expected here.`,
93
102
  suggest: getSuggest(propName, Object.keys(type.properties)),
103
+ from: refLocation,
94
104
  location: propLocation.key(),
95
105
  });
96
106
  continue;
@@ -111,12 +121,14 @@ export const OasSpec: Oas3Rule | Oas2Rule = () => {
111
121
  message: `\`${propName}\` can be one of the following only: ${propSchema.enum
112
122
  .map((i) => `"${i}"`)
113
123
  .join(', ')}.`,
124
+ from: refLocation,
114
125
  suggest: getSuggest(propValue, propSchema.enum),
115
126
  });
116
127
  }
117
128
  } else if (propSchema.type && !matchesJsonSchemaType(propValue, propSchema.type, false)) {
118
129
  report({
119
130
  message: `Expected type \`${propSchema.type}\` but got \`${propValueType}\`.`,
131
+ from: refLocation,
120
132
  location: propLocation,
121
133
  });
122
134
  } else if (propValueType === 'array' && propSchema.items?.type) {
@@ -126,6 +138,7 @@ export const OasSpec: Oas3Rule | Oas2Rule = () => {
126
138
  if (!matchesJsonSchemaType(item, itemsType, false)) {
127
139
  report({
128
140
  message: `Expected type \`${itemsType}\` but got \`${oasTypeOf(item)}\`.`,
141
+ from: refLocation,
129
142
  location: propLocation.child([i]),
130
143
  });
131
144
  }
@@ -136,6 +149,7 @@ export const OasSpec: Oas3Rule | Oas2Rule = () => {
136
149
  if (propSchema.minimum > node[propName]) {
137
150
  report({
138
151
  message: `The value of the ${propName} field must be greater than or equal to ${propSchema.minimum}`,
152
+ from: refLocation,
139
153
  location: location.child([propName]),
140
154
  });
141
155
  }
@@ -5,7 +5,7 @@ import { UserContext } from '../../walk';
5
5
 
6
6
  export const TagsAlphabetical: Oas3Rule | Oas2Rule = () => {
7
7
  return {
8
- DefinitionRoot(root: Oas2Definition | Oas3Definition, { report, location }: UserContext) {
8
+ Root(root: Oas2Definition | Oas3Definition, { report, location }: UserContext) {
9
9
  if (!root.tags) return;
10
10
  for (let i = 0; i < root.tags.length - 1; i++) {
11
11
  if (root.tags[i].name > root.tags[i + 1].name) {
@@ -25,7 +25,7 @@ import { OperationDescription } from '../common/operation-description';
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 { PathHttpVerbsOrder } from '../common/path-http-verbs-order';
31
31
  import { NoIdenticalPaths } from '../common/no-identical-paths';
@@ -71,7 +71,7 @@ export const rules = {
71
71
  'path-params-defined': PathParamsDefined as Oas2Rule,
72
72
  'parameter-description': ParameterDescription as Oas2Rule,
73
73
  'operation-singular-tag': OperationSingularTag as Oas2Rule,
74
- 'operation-security-defined': OperationSecurityDefined as Oas2Rule,
74
+ 'security-defined': SecurityDefined as Oas2Rule,
75
75
  'no-unresolved-refs': NoUnresolvedRefs as Oas2Rule,
76
76
  'no-identical-paths': NoIdenticalPaths as Oas2Rule,
77
77
  'no-ambiguous-paths': NoAmbiguousPaths as Oas2Rule,
@@ -34,7 +34,7 @@ export const RemoveUnusedComponents: Oas2Rule = () => {
34
34
  }
35
35
  },
36
36
  },
37
- DefinitionRoot: {
37
+ Root: {
38
38
  leave(root, ctx) {
39
39
  const data = ctx.getVisitorData() as { removedCount: number };
40
40
  data.removedCount = 0;
@@ -5,7 +5,7 @@ import { validateMimeType } from '../../utils';
5
5
 
6
6
  export const RequestMimeType: Oas2Rule = ({ allowedValues }) => {
7
7
  return {
8
- DefinitionRoot(root: Oas2Definition, ctx: UserContext) {
8
+ Root(root: Oas2Definition, ctx: UserContext) {
9
9
  validateMimeType({ type: 'consumes', value: root }, ctx, allowedValues);
10
10
  },
11
11
  Operation: {
@@ -5,7 +5,7 @@ import { validateMimeType } from '../../utils';
5
5
 
6
6
  export const ResponseMimeType: Oas2Rule = ({ allowedValues }) => {
7
7
  return {
8
- DefinitionRoot(root: Oas2Definition, ctx: UserContext) {
8
+ Root(root: Oas2Definition, ctx: UserContext) {
9
9
  validateMimeType({ type: 'produces', value: root }, ctx, allowedValues);
10
10
  },
11
11
  Operation: {
@@ -128,7 +128,7 @@ describe('no-invalid-media-type-examples', () => {
128
128
  "source": "foobar.yaml",
129
129
  },
130
130
  ],
131
- "message": "Example value must conform to the schema: must NOT have additional properties \`c\`.",
131
+ "message": "Example value must conform to the schema: must NOT have unevaluated properties \`c\`.",
132
132
  "ruleId": "no-invalid-media-type-examples",
133
133
  "severity": "error",
134
134
  "suggest": Array [],
@@ -137,7 +137,7 @@ describe('no-invalid-media-type-examples', () => {
137
137
  `);
138
138
  });
139
139
 
140
- it('should not on invalid example with allowAdditionalProperties', async () => {
140
+ it('should not report on valid example with allowAdditionalProperties', async () => {
141
141
  const document = parseYamlToDocument(
142
142
  outdent`
143
143
  openapi: 3.0.0
@@ -177,6 +177,55 @@ describe('no-invalid-media-type-examples', () => {
177
177
  expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
178
178
  });
179
179
 
180
+ it('should not report on valid example with allowAdditionalProperties and allOf and $ref', async () => {
181
+ const document = parseYamlToDocument(
182
+ outdent`
183
+ openapi: 3.0.0
184
+ components:
185
+ schemas:
186
+ C:
187
+ properties:
188
+ c:
189
+ type: string
190
+ paths:
191
+ /pet:
192
+ get:
193
+ responses:
194
+ 200:
195
+ content:
196
+ application/json:
197
+ example:
198
+ a: "string"
199
+ b: 13
200
+ c: "string"
201
+ schema:
202
+ type: object
203
+ allOf:
204
+ - $ref: '#/components/schemas/C'
205
+ properties:
206
+ a:
207
+ type: string
208
+ b:
209
+ type: number
210
+
211
+ `,
212
+ 'foobar.yaml'
213
+ );
214
+
215
+ const results = await lintDocument({
216
+ externalRefResolver: new BaseResolver(),
217
+ document,
218
+ config: await makeConfig({
219
+ 'no-invalid-media-type-examples': {
220
+ severity: 'error',
221
+ allowAdditionalProperties: false,
222
+ },
223
+ }),
224
+ });
225
+
226
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
227
+ });
228
+
180
229
  it('should not on invalid examples', async () => {
181
230
  const document = parseYamlToDocument(
182
231
  outdent`
@@ -0,0 +1,145 @@
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('Oas3 operation-4xx-problem-details-rfc7807', () => {
7
+ it('should report `4xx` must have content type `application/problem+json` ', async () => {
8
+ const document = parseYamlToDocument(
9
+ outdent`
10
+ openapi: "3.0.0"
11
+ paths:
12
+ /pets:
13
+ get:
14
+ summary: List all pets
15
+ operationId: listPets
16
+ responses:
17
+ '400':
18
+ description: Test
19
+ content:
20
+ application/json:
21
+ schema:
22
+ type: object
23
+ properties:
24
+ type:
25
+ type: string
26
+ title:
27
+ type: string
28
+ `,
29
+ 'foobar.yaml'
30
+ );
31
+
32
+ const results = await lintDocument({
33
+ externalRefResolver: new BaseResolver(),
34
+ document,
35
+ config: await makeConfig({ 'operation-4xx-problem-details-rfc7807': 'error' }),
36
+ });
37
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
38
+ Array [
39
+ Object {
40
+ "location": Array [
41
+ Object {
42
+ "pointer": "#/paths/~1pets/get/responses/400",
43
+ "reportOnKey": true,
44
+ "source": "foobar.yaml",
45
+ },
46
+ ],
47
+ "message": "Response \`4xx\` must have content-type \`application/problem+json\`.",
48
+ "ruleId": "operation-4xx-problem-details-rfc7807",
49
+ "severity": "error",
50
+ "suggest": Array [],
51
+ },
52
+ ]
53
+ `);
54
+ });
55
+
56
+ it('should report `application/problem+json` must have `type` property', async () => {
57
+ const document = parseYamlToDocument(
58
+ outdent`
59
+ openapi: "3.0.0"
60
+ paths:
61
+ /pets:
62
+ get:
63
+ summary: List all pets
64
+ operationId: listPets
65
+ responses:
66
+ '400':
67
+ description: Test
68
+ content:
69
+ application/problem+json:
70
+ schema:
71
+ type: object
72
+ properties:
73
+ title:
74
+ type: string
75
+ `,
76
+ 'foobar.yaml'
77
+ );
78
+
79
+ const results = await lintDocument({
80
+ externalRefResolver: new BaseResolver(),
81
+ document,
82
+ config: await makeConfig({ 'operation-4xx-problem-details-rfc7807': 'error' }),
83
+ });
84
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
85
+ Array [
86
+ Object {
87
+ "location": Array [
88
+ Object {
89
+ "pointer": "#/paths/~1pets/get/responses/400/content/application~1problem+json/schema/properties/type",
90
+ "reportOnKey": true,
91
+ "source": "foobar.yaml",
92
+ },
93
+ ],
94
+ "message": "SchemaProperties object should contain \`type\` field.",
95
+ "ruleId": "operation-4xx-problem-details-rfc7807",
96
+ "severity": "error",
97
+ "suggest": Array [],
98
+ },
99
+ ]
100
+ `);
101
+ });
102
+
103
+ it('should report `application/problem+json` must have `schema` property', async () => {
104
+ const document = parseYamlToDocument(
105
+ outdent`
106
+ openapi: "3.0.0"
107
+ paths:
108
+ /pets:
109
+ get:
110
+ summary: List all pets
111
+ operationId: listPets
112
+ responses:
113
+ '400':
114
+ description: Test
115
+ content:
116
+ application/problem+json:
117
+ example: asd
118
+ `,
119
+ 'foobar.yaml'
120
+ );
121
+
122
+ const results = await lintDocument({
123
+ externalRefResolver: new BaseResolver(),
124
+ document,
125
+ config: await makeConfig({ 'operation-4xx-problem-details-rfc7807': 'error' }),
126
+ });
127
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
128
+ Array [
129
+ Object {
130
+ "location": Array [
131
+ Object {
132
+ "pointer": "#/paths/~1pets/get/responses/400/content/application~1problem+json/schema",
133
+ "reportOnKey": true,
134
+ "source": "foobar.yaml",
135
+ },
136
+ ],
137
+ "message": "MediaType object should contain \`schema\` field.",
138
+ "ruleId": "operation-4xx-problem-details-rfc7807",
139
+ "severity": "error",
140
+ "suggest": Array [],
141
+ },
142
+ ]
143
+ `);
144
+ });
145
+ });
@@ -47,6 +47,7 @@ describe('Oas3 Structural visitor basic', () => {
47
47
  expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
48
48
  Array [
49
49
  Object {
50
+ "from": undefined,
50
51
  "location": Array [
51
52
  Object {
52
53
  "pointer": "#/info/contact/url",
@@ -60,6 +61,7 @@ describe('Oas3 Structural visitor basic', () => {
60
61
  "suggest": Array [],
61
62
  },
62
63
  Object {
64
+ "from": undefined,
63
65
  "location": Array [
64
66
  Object {
65
67
  "pointer": "#/info/contact/email",
@@ -73,6 +75,7 @@ describe('Oas3 Structural visitor basic', () => {
73
75
  "suggest": Array [],
74
76
  },
75
77
  Object {
78
+ "from": undefined,
76
79
  "location": Array [
77
80
  Object {
78
81
  "pointer": "#/info/license",
@@ -103,6 +106,7 @@ describe('Oas3 Structural visitor basic', () => {
103
106
  "suggest": Array [],
104
107
  },
105
108
  Object {
109
+ "from": undefined,
106
110
  "location": Array [
107
111
  Object {
108
112
  "pointer": "#/servers/0/variables/a/enum/0",
@@ -116,6 +120,7 @@ describe('Oas3 Structural visitor basic', () => {
116
120
  "suggest": Array [],
117
121
  },
118
122
  Object {
123
+ "from": undefined,
119
124
  "location": Array [
120
125
  Object {
121
126
  "pointer": "#/tags/0",
@@ -129,6 +134,7 @@ describe('Oas3 Structural visitor basic', () => {
129
134
  "suggest": Array [],
130
135
  },
131
136
  Object {
137
+ "from": undefined,
132
138
  "location": Array [
133
139
  Object {
134
140
  "pointer": "#/tags/1",
@@ -175,6 +181,7 @@ describe('Oas3 Structural visitor basic', () => {
175
181
  expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
176
182
  Array [
177
183
  Object {
184
+ "from": undefined,
178
185
  "location": Array [
179
186
  Object {
180
187
  "pointer": "#/components1",
@@ -203,6 +210,7 @@ describe('Oas3 Structural visitor basic', () => {
203
210
  "suggest": Array [],
204
211
  },
205
212
  Object {
213
+ "from": undefined,
206
214
  "location": Array [
207
215
  Object {
208
216
  "pointer": "#/info/contact/test",
@@ -244,6 +252,7 @@ describe('Oas3 Structural visitor basic', () => {
244
252
  expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
245
253
  Array [
246
254
  Object {
255
+ "from": undefined,
247
256
  "location": Array [
248
257
  Object {
249
258
  "pointer": "#/",
@@ -270,6 +279,7 @@ describe('Oas3 Structural visitor basic', () => {
270
279
  "suggest": Array [],
271
280
  },
272
281
  Object {
282
+ "from": undefined,
273
283
  "location": Array [
274
284
  Object {
275
285
  "pointer": "#/info",
@@ -0,0 +1,217 @@
1
+ import { makeConfig, parseYamlToDocument } from '../../../../__tests__/utils';
2
+ import { outdent } from 'outdent';
3
+ import { lintDocument } from '../../../lint';
4
+ import { BaseResolver } from '../../../resolve';
5
+
6
+ describe('Oas3 spec-components-invalid-map-name', () => {
7
+ it('should report about invalid keys inside components', async () => {
8
+ const document = parseYamlToDocument(outdent`
9
+ openapi: 3.0.0
10
+ info:
11
+ version: 3.0.0
12
+ components:
13
+ parameters:
14
+ my Param:
15
+ name: param
16
+ description: param
17
+ in: path
18
+ examples:
19
+ invalid identifier:
20
+ description: 'Some description'
21
+ value: 21
22
+ responses:
23
+ 400 status:
24
+ description: bad request
25
+ schemas:
26
+ first schema:
27
+ type: integer
28
+ format: int64
29
+ `);
30
+ const results = await lintDocument({
31
+ externalRefResolver: new BaseResolver(),
32
+ document,
33
+ config: await makeConfig({
34
+ 'spec-components-invalid-map-name': 'error',
35
+ }),
36
+ });
37
+
38
+ expect(results).toMatchInlineSnapshot(`
39
+ Array [
40
+ Object {
41
+ "location": Array [
42
+ Object {
43
+ "pointer": "#/components/parameters/my Param",
44
+ "reportOnKey": true,
45
+ "source": Source {
46
+ "absoluteRef": "",
47
+ "body": "openapi: 3.0.0
48
+ info:
49
+ version: 3.0.0
50
+ components:
51
+ parameters:
52
+ my Param:
53
+ name: param
54
+ description: param
55
+ in: path
56
+ examples:
57
+ invalid identifier:
58
+ description: 'Some description'
59
+ value: 21
60
+ responses:
61
+ 400 status:
62
+ description: bad request
63
+ schemas:
64
+ first schema:
65
+ type: integer
66
+ format: int64 ",
67
+ "mimeType": undefined,
68
+ },
69
+ },
70
+ ],
71
+ "message": "The map key in parameters \\"my Param\\" does not match the regular expression \\"^[a-zA-Z0-9\\\\.\\\\-_]+$\\"",
72
+ "ruleId": "spec-components-invalid-map-name",
73
+ "severity": "error",
74
+ "suggest": Array [],
75
+ },
76
+ Object {
77
+ "location": Array [
78
+ Object {
79
+ "pointer": "#/components/schemas/first schema",
80
+ "reportOnKey": true,
81
+ "source": Source {
82
+ "absoluteRef": "",
83
+ "body": "openapi: 3.0.0
84
+ info:
85
+ version: 3.0.0
86
+ components:
87
+ parameters:
88
+ my Param:
89
+ name: param
90
+ description: param
91
+ in: path
92
+ examples:
93
+ invalid identifier:
94
+ description: 'Some description'
95
+ value: 21
96
+ responses:
97
+ 400 status:
98
+ description: bad request
99
+ schemas:
100
+ first schema:
101
+ type: integer
102
+ format: int64 ",
103
+ "mimeType": undefined,
104
+ },
105
+ },
106
+ ],
107
+ "message": "The map key in schemas \\"first schema\\" does not match the regular expression \\"^[a-zA-Z0-9\\\\.\\\\-_]+$\\"",
108
+ "ruleId": "spec-components-invalid-map-name",
109
+ "severity": "error",
110
+ "suggest": Array [],
111
+ },
112
+ Object {
113
+ "location": Array [
114
+ Object {
115
+ "pointer": "#/components/responses/400 status",
116
+ "reportOnKey": true,
117
+ "source": Source {
118
+ "absoluteRef": "",
119
+ "body": "openapi: 3.0.0
120
+ info:
121
+ version: 3.0.0
122
+ components:
123
+ parameters:
124
+ my Param:
125
+ name: param
126
+ description: param
127
+ in: path
128
+ examples:
129
+ invalid identifier:
130
+ description: 'Some description'
131
+ value: 21
132
+ responses:
133
+ 400 status:
134
+ description: bad request
135
+ schemas:
136
+ first schema:
137
+ type: integer
138
+ format: int64 ",
139
+ "mimeType": undefined,
140
+ },
141
+ },
142
+ ],
143
+ "message": "The map key in responses \\"400 status\\" does not match the regular expression \\"^[a-zA-Z0-9\\\\.\\\\-_]+$\\"",
144
+ "ruleId": "spec-components-invalid-map-name",
145
+ "severity": "error",
146
+ "suggest": Array [],
147
+ },
148
+ Object {
149
+ "location": Array [
150
+ Object {
151
+ "pointer": "#/components/examples/invalid identifier",
152
+ "reportOnKey": true,
153
+ "source": Source {
154
+ "absoluteRef": "",
155
+ "body": "openapi: 3.0.0
156
+ info:
157
+ version: 3.0.0
158
+ components:
159
+ parameters:
160
+ my Param:
161
+ name: param
162
+ description: param
163
+ in: path
164
+ examples:
165
+ invalid identifier:
166
+ description: 'Some description'
167
+ value: 21
168
+ responses:
169
+ 400 status:
170
+ description: bad request
171
+ schemas:
172
+ first schema:
173
+ type: integer
174
+ format: int64 ",
175
+ "mimeType": undefined,
176
+ },
177
+ },
178
+ ],
179
+ "message": "The map key in examples \\"invalid identifier\\" does not match the regular expression \\"^[a-zA-Z0-9\\\\.\\\\-_]+$\\"",
180
+ "ruleId": "spec-components-invalid-map-name",
181
+ "severity": "error",
182
+ "suggest": Array [],
183
+ },
184
+ ]
185
+ `);
186
+ });
187
+
188
+ it('should not report a key of the example does not match the regular expression', async () => {
189
+ const document = parseYamlToDocument(outdent`
190
+ openapi: 3.0.0
191
+ info:
192
+ version: 3.0.0
193
+ paths:
194
+ /store/subscribe:
195
+ post:
196
+ parameters:
197
+ - name: petId
198
+ in: path
199
+ schema:
200
+ type: integer
201
+ format: int64
202
+ examples:
203
+ valid-identifier-1.key:
204
+ description: 'Some description'
205
+ value: 21
206
+ `);
207
+ const results = await lintDocument({
208
+ externalRefResolver: new BaseResolver(),
209
+ document,
210
+ config: await makeConfig({
211
+ 'spec-components-invalid-map-name': 'error',
212
+ }),
213
+ });
214
+
215
+ expect(results).toMatchInlineSnapshot(`Array []`);
216
+ });
217
+ });