@redocly/openapi-core 1.0.0 → 1.0.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 (275) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/__tests__/utils.ts +88 -0
  3. package/lib/config/all.js +0 -1
  4. package/lib/config/minimal.js +0 -1
  5. package/lib/config/recommended.js +0 -1
  6. package/package.json +1 -1
  7. package/src/__tests__/__snapshots__/bundle.test.ts.snap +437 -0
  8. package/src/__tests__/bundle.test.ts +236 -0
  9. package/src/__tests__/codeframes.test.ts +530 -0
  10. package/src/__tests__/fixtures/.redocly.lint-ignore.yaml +5 -0
  11. package/src/__tests__/fixtures/extension.js +24 -0
  12. package/src/__tests__/fixtures/refs/definitions.yaml +3 -0
  13. package/src/__tests__/fixtures/refs/examples.yaml +8 -0
  14. package/src/__tests__/fixtures/refs/external-request-body.yaml +13 -0
  15. package/src/__tests__/fixtures/refs/externalref.yaml +35 -0
  16. package/src/__tests__/fixtures/refs/hosted.yaml +35 -0
  17. package/src/__tests__/fixtures/refs/openapi-with-external-refs-conflicting-names.yaml +21 -0
  18. package/src/__tests__/fixtures/refs/openapi-with-external-refs.yaml +33 -0
  19. package/src/__tests__/fixtures/refs/openapi-with-url-refs.yaml +18 -0
  20. package/src/__tests__/fixtures/refs/param-b.yaml +1 -0
  21. package/src/__tests__/fixtures/refs/param-c.yaml +1 -0
  22. package/src/__tests__/fixtures/refs/rename.yaml +1 -0
  23. package/src/__tests__/fixtures/refs/requestBody.yaml +9 -0
  24. package/src/__tests__/fixtures/refs/schema-a.yaml +1 -0
  25. package/src/__tests__/fixtures/refs/simple.yaml +1 -0
  26. package/src/__tests__/fixtures/refs/vendor.schema.yaml +20 -0
  27. package/src/__tests__/fixtures/resolve/External.yaml +10 -0
  28. package/src/__tests__/fixtures/resolve/External2.yaml +4 -0
  29. package/src/__tests__/fixtures/resolve/description.md +3 -0
  30. package/src/__tests__/fixtures/resolve/externalInfo.yaml +4 -0
  31. package/src/__tests__/fixtures/resolve/externalLicense.yaml +1 -0
  32. package/src/__tests__/fixtures/resolve/openapi-with-back.yaml +13 -0
  33. package/src/__tests__/fixtures/resolve/openapi-with-md-description.yaml +5 -0
  34. package/src/__tests__/fixtures/resolve/openapi.yaml +28 -0
  35. package/src/__tests__/fixtures/resolve/schemas/type-a.yaml +10 -0
  36. package/src/__tests__/fixtures/resolve/schemas/type-b.yaml +6 -0
  37. package/src/__tests__/fixtures/resolve/transitive/a.yaml +1 -0
  38. package/src/__tests__/fixtures/resolve/transitive/components.yaml +5 -0
  39. package/src/__tests__/fixtures/resolve/transitive/schemas.yaml +3 -0
  40. package/src/__tests__/format.test.ts +76 -0
  41. package/src/__tests__/js-yaml.test.ts +73 -0
  42. package/src/__tests__/lint.test.ts +392 -0
  43. package/src/__tests__/logger-browser.test.ts +53 -0
  44. package/src/__tests__/logger.test.ts +47 -0
  45. package/src/__tests__/login.test.ts +17 -0
  46. package/src/__tests__/normalizeVisitors.test.ts +151 -0
  47. package/src/__tests__/output-browser.test.ts +18 -0
  48. package/src/__tests__/output.test.ts +15 -0
  49. package/src/__tests__/ref-utils.test.ts +120 -0
  50. package/src/__tests__/resolve-http.test.ts +77 -0
  51. package/src/__tests__/resolve.test.ts +431 -0
  52. package/src/__tests__/utils-browser.test.ts +11 -0
  53. package/src/__tests__/utils.test.ts +144 -0
  54. package/src/__tests__/walk.test.ts +1545 -0
  55. package/src/benchmark/benches/lint-with-many-rules.bench.ts +35 -0
  56. package/src/benchmark/benches/lint-with-nested-rule.bench.ts +39 -0
  57. package/src/benchmark/benches/lint-with-no-rules.bench.ts +20 -0
  58. package/src/benchmark/benches/lint-with-top-level-rule-report.bench.ts +35 -0
  59. package/src/benchmark/benches/lint-with-top-level-rule.bench.ts +32 -0
  60. package/src/benchmark/benches/rebilly.yaml +32275 -0
  61. package/src/benchmark/benches/recommended-oas3.bench.ts +22 -0
  62. package/src/benchmark/benches/resolve-with-no-external.bench.ts +23 -0
  63. package/src/benchmark/benchmark.js +311 -0
  64. package/src/benchmark/colors.js +29 -0
  65. package/src/benchmark/fork.js +83 -0
  66. package/src/benchmark/utils.ts +36 -0
  67. package/src/bundle.ts +417 -0
  68. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +164 -0
  69. package/src/config/__tests__/__snapshots__/config.test.ts.snap +144 -0
  70. package/src/config/__tests__/config-resolvers.test.ts +491 -0
  71. package/src/config/__tests__/config.test.ts +312 -0
  72. package/src/config/__tests__/fixtures/ingore-file.ts +8 -0
  73. package/src/config/__tests__/fixtures/load-redocly.yaml +2 -0
  74. package/src/config/__tests__/fixtures/plugin-config.yaml +2 -0
  75. package/src/config/__tests__/fixtures/plugin.js +56 -0
  76. package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +11 -0
  77. package/src/config/__tests__/fixtures/resolve-config/api/plugin.js +69 -0
  78. package/src/config/__tests__/fixtures/resolve-config/local-config-with-circular.yaml +7 -0
  79. package/src/config/__tests__/fixtures/resolve-config/local-config-with-custom-function.yaml +17 -0
  80. package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +18 -0
  81. package/src/config/__tests__/fixtures/resolve-config/local-config-with-wrong-custom-function.yaml +15 -0
  82. package/src/config/__tests__/fixtures/resolve-config/local-config.yaml +9 -0
  83. package/src/config/__tests__/fixtures/resolve-config/plugin.js +80 -0
  84. package/src/config/__tests__/fixtures/resolve-remote-configs/nested-remote-config.yaml +3 -0
  85. package/src/config/__tests__/fixtures/resolve-remote-configs/remote-config.yaml +4 -0
  86. package/src/config/__tests__/load.test.ts +167 -0
  87. package/src/config/__tests__/resolve-plugins.test.ts +27 -0
  88. package/src/config/__tests__/utils.test.ts +204 -0
  89. package/src/config/all.ts +74 -0
  90. package/src/config/builtIn.ts +37 -0
  91. package/src/config/config-resolvers.ts +474 -0
  92. package/src/config/config.ts +332 -0
  93. package/src/config/index.ts +7 -0
  94. package/src/config/load.ts +144 -0
  95. package/src/config/minimal.ts +61 -0
  96. package/src/config/recommended.ts +61 -0
  97. package/src/config/rules.ts +54 -0
  98. package/src/config/types.ts +231 -0
  99. package/src/config/utils.ts +349 -0
  100. package/src/decorators/__tests__/filter-in.test.ts +310 -0
  101. package/src/decorators/__tests__/filter-out.test.ts +335 -0
  102. package/src/decorators/__tests__/media-type-examples-override.test.ts +665 -0
  103. package/src/decorators/__tests__/remove-x-internal.test.ts +316 -0
  104. package/src/decorators/__tests__/resources/request.yaml +3 -0
  105. package/src/decorators/__tests__/resources/response.yaml +3 -0
  106. package/src/decorators/common/filters/filter-helper.ts +72 -0
  107. package/src/decorators/common/filters/filter-in.ts +18 -0
  108. package/src/decorators/common/filters/filter-out.ts +18 -0
  109. package/src/decorators/common/info-description-override.ts +24 -0
  110. package/src/decorators/common/info-override.ts +15 -0
  111. package/src/decorators/common/media-type-examples-override.ts +79 -0
  112. package/src/decorators/common/operation-description-override.ts +30 -0
  113. package/src/decorators/common/registry-dependencies.ts +25 -0
  114. package/src/decorators/common/remove-x-internal.ts +59 -0
  115. package/src/decorators/common/tag-description-override.ts +25 -0
  116. package/src/decorators/oas2/index.ts +20 -0
  117. package/src/decorators/oas3/index.ts +22 -0
  118. package/src/env.ts +5 -0
  119. package/src/format/codeframes.ts +216 -0
  120. package/src/format/format.ts +375 -0
  121. package/src/index.ts +71 -0
  122. package/src/js-yaml/index.ts +14 -0
  123. package/src/lint.ts +148 -0
  124. package/src/logger.ts +34 -0
  125. package/src/oas-types.ts +57 -0
  126. package/src/output.ts +7 -0
  127. package/src/redocly/__tests__/redocly-client.test.ts +146 -0
  128. package/src/redocly/index.ts +187 -0
  129. package/src/redocly/redocly-client-types.ts +10 -0
  130. package/src/redocly/registry-api-types.ts +32 -0
  131. package/src/redocly/registry-api.ts +150 -0
  132. package/src/ref-utils.ts +85 -0
  133. package/src/resolve.ts +417 -0
  134. package/src/rules/__tests__/fixtures/code-sample.php +9 -0
  135. package/src/rules/__tests__/fixtures/invalid-yaml.yaml +1 -0
  136. package/src/rules/__tests__/fixtures/ref.yaml +1 -0
  137. package/src/rules/__tests__/no-unresolved-refs.test.ts +257 -0
  138. package/src/rules/__tests__/utils.test.ts +160 -0
  139. package/src/rules/ajv.ts +102 -0
  140. package/src/rules/common/__tests__/info-license.test.ts +62 -0
  141. package/src/rules/common/__tests__/license-url.test.ts +63 -0
  142. package/src/rules/common/__tests__/no-ambiguous-paths.test.ts +96 -0
  143. package/src/rules/common/__tests__/no-enum-type-mismatch.test.ts +210 -0
  144. package/src/rules/common/__tests__/no-identical-paths.test.ts +58 -0
  145. package/src/rules/common/__tests__/no-path-trailing-slash.test.ts +85 -0
  146. package/src/rules/common/__tests__/operation-2xx-response.test.ts +192 -0
  147. package/src/rules/common/__tests__/operation-4xx-response.test.ts +231 -0
  148. package/src/rules/common/__tests__/operation-operationId-unique.test.ts +76 -0
  149. package/src/rules/common/__tests__/operation-operationId-url-safe.test.ts +45 -0
  150. package/src/rules/common/__tests__/operation-parameters-unique.test.ts +167 -0
  151. package/src/rules/common/__tests__/operation-singular-tag.test.ts +72 -0
  152. package/src/rules/common/__tests__/path-http-verbs-order.test.ts +95 -0
  153. package/src/rules/common/__tests__/path-not-include-query.test.ts +64 -0
  154. package/src/rules/common/__tests__/path-params-defined.test.ts +202 -0
  155. package/src/rules/common/__tests__/paths-kebab-case.test.ts +108 -0
  156. package/src/rules/common/__tests__/scalar-property-missing-example.test.ts +264 -0
  157. package/src/rules/common/__tests__/security-defined.test.ts +175 -0
  158. package/src/rules/common/__tests__/spec-strict-refs.test.ts +69 -0
  159. package/src/rules/common/__tests__/spec.test.ts +610 -0
  160. package/src/rules/common/__tests__/tag-description.test.ts +65 -0
  161. package/src/rules/common/__tests__/tags-alphabetical.test.ts +64 -0
  162. package/src/rules/common/assertions/__tests__/asserts.test.ts +869 -0
  163. package/src/rules/common/assertions/__tests__/index.test.ts +100 -0
  164. package/src/rules/common/assertions/__tests__/utils.test.ts +236 -0
  165. package/src/rules/common/assertions/asserts.ts +357 -0
  166. package/src/rules/common/assertions/index.ts +53 -0
  167. package/src/rules/common/assertions/utils.ts +331 -0
  168. package/src/rules/common/info-contact.ts +15 -0
  169. package/src/rules/common/info-license-url.ts +10 -0
  170. package/src/rules/common/info-license.ts +15 -0
  171. package/src/rules/common/no-ambiguous-paths.ts +50 -0
  172. package/src/rules/common/no-enum-type-mismatch.ts +52 -0
  173. package/src/rules/common/no-http-verbs-in-paths.ts +36 -0
  174. package/src/rules/common/no-identical-paths.ts +24 -0
  175. package/src/rules/common/no-invalid-parameter-examples.ts +36 -0
  176. package/src/rules/common/no-invalid-schema-examples.ts +27 -0
  177. package/src/rules/common/no-path-trailing-slash.ts +15 -0
  178. package/src/rules/common/operation-2xx-response.ts +24 -0
  179. package/src/rules/common/operation-4xx-response.ts +24 -0
  180. package/src/rules/common/operation-description.ts +13 -0
  181. package/src/rules/common/operation-operationId-unique.ts +21 -0
  182. package/src/rules/common/operation-operationId-url-safe.ts +19 -0
  183. package/src/rules/common/operation-operationId.ts +17 -0
  184. package/src/rules/common/operation-parameters-unique.ts +48 -0
  185. package/src/rules/common/operation-singular-tag.ts +17 -0
  186. package/src/rules/common/operation-summary.ts +13 -0
  187. package/src/rules/common/operation-tag-defined.ts +26 -0
  188. package/src/rules/common/parameter-description.ts +22 -0
  189. package/src/rules/common/path-declaration-must-exist.ts +15 -0
  190. package/src/rules/common/path-excludes-patterns.ts +23 -0
  191. package/src/rules/common/path-http-verbs-order.ts +30 -0
  192. package/src/rules/common/path-not-include-query.ts +17 -0
  193. package/src/rules/common/path-params-defined.ts +65 -0
  194. package/src/rules/common/path-segment-plural.ts +31 -0
  195. package/src/rules/common/paths-kebab-case.ts +19 -0
  196. package/src/rules/common/required-string-property-missing-min-length.ts +44 -0
  197. package/src/rules/common/response-contains-header.ts +35 -0
  198. package/src/rules/common/scalar-property-missing-example.ts +58 -0
  199. package/src/rules/common/security-defined.ts +65 -0
  200. package/src/rules/common/spec-strict-refs.ts +30 -0
  201. package/src/rules/common/spec.ts +175 -0
  202. package/src/rules/common/tag-description.ts +10 -0
  203. package/src/rules/common/tags-alphabetical.ts +20 -0
  204. package/src/rules/no-unresolved-refs.ts +51 -0
  205. package/src/rules/oas2/__tests__/boolean-parameter-prefixes.test.ts +110 -0
  206. package/src/rules/oas2/__tests__/response-contains-header.test.ts +174 -0
  207. package/src/rules/oas2/__tests__/response-contains-property.test.ts +155 -0
  208. package/src/rules/oas2/__tests__/spec/fixtures/description.md +1 -0
  209. package/src/rules/oas2/__tests__/spec/info.test.ts +355 -0
  210. package/src/rules/oas2/__tests__/spec/operation.test.ts +123 -0
  211. package/src/rules/oas2/__tests__/spec/paths.test.ts +245 -0
  212. package/src/rules/oas2/__tests__/spec/referenceableScalars.test.ts +35 -0
  213. package/src/rules/oas2/__tests__/spec/utils.ts +32 -0
  214. package/src/rules/oas2/boolean-parameter-prefixes.ts +26 -0
  215. package/src/rules/oas2/index.ts +91 -0
  216. package/src/rules/oas2/remove-unused-components.ts +81 -0
  217. package/src/rules/oas2/request-mime-type.ts +16 -0
  218. package/src/rules/oas2/response-contains-property.ts +36 -0
  219. package/src/rules/oas2/response-mime-type.ts +16 -0
  220. package/src/rules/oas3/__tests__/boolean-parameter-prefixes.test.ts +111 -0
  221. package/src/rules/oas3/__tests__/component-name-unique.test.ts +823 -0
  222. package/src/rules/oas3/__tests__/fixtures/common.yaml +11 -0
  223. package/src/rules/oas3/__tests__/no-empty-enum-servers.com.test.ts +205 -0
  224. package/src/rules/oas3/__tests__/no-example-value-and-externalValue.test.ts +65 -0
  225. package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +473 -0
  226. package/src/rules/oas3/__tests__/no-server-example.com.test.ts +60 -0
  227. package/src/rules/oas3/__tests__/no-server-trailing-slash.test.ts +79 -0
  228. package/src/rules/oas3/__tests__/no-unused-components.test.ts +131 -0
  229. package/src/rules/oas3/__tests__/operation-4xx-problem-details-rfc7807.test.ts +145 -0
  230. package/src/rules/oas3/__tests__/response-contains-header.test.ts +389 -0
  231. package/src/rules/oas3/__tests__/response-contains-property.test.ts +403 -0
  232. package/src/rules/oas3/__tests__/spec/callbacks.test.ts +41 -0
  233. package/src/rules/oas3/__tests__/spec/fixtures/description.md +1 -0
  234. package/src/rules/oas3/__tests__/spec/info.test.ts +391 -0
  235. package/src/rules/oas3/__tests__/spec/operation.test.ts +253 -0
  236. package/src/rules/oas3/__tests__/spec/paths.test.ts +284 -0
  237. package/src/rules/oas3/__tests__/spec/referenceableScalars.test.ts +77 -0
  238. package/src/rules/oas3/__tests__/spec/servers.test.ts +505 -0
  239. package/src/rules/oas3/__tests__/spec/spec.test.ts +298 -0
  240. package/src/rules/oas3/__tests__/spec/utils.ts +32 -0
  241. package/src/rules/oas3/__tests__/spec-components-invalid-map-name.test.ts +276 -0
  242. package/src/rules/oas3/__tests__/utils/lint-document-for-test.ts +23 -0
  243. package/src/rules/oas3/boolean-parameter-prefixes.ts +28 -0
  244. package/src/rules/oas3/component-name-unique.ts +158 -0
  245. package/src/rules/oas3/index.ts +113 -0
  246. package/src/rules/oas3/no-empty-servers.ts +22 -0
  247. package/src/rules/oas3/no-example-value-and-externalValue.ts +14 -0
  248. package/src/rules/oas3/no-invalid-media-type-examples.ts +49 -0
  249. package/src/rules/oas3/no-server-example.com.ts +14 -0
  250. package/src/rules/oas3/no-server-trailing-slash.ts +15 -0
  251. package/src/rules/oas3/no-server-variables-empty-enum.ts +66 -0
  252. package/src/rules/oas3/no-undefined-server-variable.ts +30 -0
  253. package/src/rules/oas3/no-unused-components.ts +75 -0
  254. package/src/rules/oas3/operation-4xx-problem-details-rfc7807.ts +35 -0
  255. package/src/rules/oas3/remove-unused-components.ts +95 -0
  256. package/src/rules/oas3/request-mime-type.ts +30 -0
  257. package/src/rules/oas3/response-contains-property.ts +38 -0
  258. package/src/rules/oas3/response-mime-type.ts +30 -0
  259. package/src/rules/oas3/spec-components-invalid-map-name.ts +69 -0
  260. package/src/rules/other/stats.ts +73 -0
  261. package/src/rules/utils.ts +193 -0
  262. package/src/types/config-external-schemas.ts +917 -0
  263. package/src/types/index.ts +149 -0
  264. package/src/types/oas2.ts +478 -0
  265. package/src/types/oas3.ts +597 -0
  266. package/src/types/oas3_1.ts +258 -0
  267. package/src/types/redocly-yaml.ts +1040 -0
  268. package/src/typings/common.ts +17 -0
  269. package/src/typings/openapi.ts +298 -0
  270. package/src/typings/swagger.ts +236 -0
  271. package/src/utils.ts +276 -0
  272. package/src/visitors.ts +491 -0
  273. package/src/walk.ts +439 -0
  274. package/tsconfig.json +8 -0
  275. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,245 @@
1
+ import { outdent } from 'outdent';
2
+ import { lintDoc } from './utils';
3
+
4
+ describe('OpenAPI Schema', () => {
5
+ it('should not report if Path object is valid ', async () => {
6
+ const source = outdent`
7
+ swagger: '2.0'
8
+ info:
9
+ title: Test
10
+ version: '1.0'
11
+
12
+ paths:
13
+ '/ping':
14
+ get:
15
+ responses:
16
+ '200':
17
+ description: example description
18
+ `;
19
+
20
+ expect(
21
+ await lintDoc(source, {
22
+ spec: 'error',
23
+ })
24
+ ).toMatchInlineSnapshot(`Array []`);
25
+ });
26
+
27
+ it('should not report if Path object is empty ', async () => {
28
+ const source = outdent`
29
+ swagger: '2.0'
30
+ info:
31
+ title: Test
32
+ version: '1.0'
33
+
34
+ paths: {}
35
+ `;
36
+
37
+ expect(
38
+ await lintDoc(source, {
39
+ spec: 'error',
40
+ })
41
+ ).toMatchInlineSnapshot(`Array []`);
42
+ });
43
+
44
+ it('should report if Path object is not present ', async () => {
45
+ const source = outdent`
46
+ swagger: '2.0'
47
+ info:
48
+ title: Test
49
+ version: '1.0'
50
+ `;
51
+
52
+ expect(
53
+ await lintDoc(source, {
54
+ spec: 'error',
55
+ })
56
+ ).toMatchInlineSnapshot(`
57
+ Array [
58
+ Object {
59
+ "location": "#/",
60
+ "message": "The field \`paths\` must be present on this level.",
61
+ },
62
+ ]
63
+ `);
64
+ });
65
+
66
+ it('should not report if Path object is empty ', async () => {
67
+ const source = outdent`
68
+ swagger: '2.0'
69
+ info:
70
+ title: Test
71
+ version: '1.0'
72
+
73
+ paths: {}
74
+ `;
75
+
76
+ expect(
77
+ await lintDoc(source, {
78
+ spec: 'error',
79
+ })
80
+ ).toMatchInlineSnapshot(`Array []`);
81
+ });
82
+
83
+ //Check: no error
84
+ it('should report if the field name is not begin with a forward slash (/) ', async () => {
85
+ const source = outdent`
86
+ swagger: '2.0'
87
+ info:
88
+ title: Test
89
+ version: '1.0'
90
+
91
+ paths:
92
+ 'ping':
93
+ get:
94
+ responses:
95
+ '200':
96
+ description: example description
97
+ `;
98
+
99
+ expect(
100
+ await lintDoc(source, {
101
+ spec: 'error',
102
+ })
103
+ ).toMatchInlineSnapshot(`
104
+ Array [
105
+ Object {
106
+ "location": "#/paths/ping",
107
+ "message": "Property \`ping\` is not expected here.",
108
+ },
109
+ ]
110
+ `);
111
+ });
112
+
113
+ it('should report if paths are considered identical and invalid', async () => {
114
+ const source = outdent`
115
+ swagger: '2.0'
116
+ info:
117
+ title: Test
118
+ version: '1.0'
119
+
120
+ paths:
121
+ /pets/{petId}:
122
+ get:
123
+ responses:
124
+ '200':
125
+ description: example description
126
+ /pets/{name}:
127
+ get:
128
+ responses:
129
+ '200':
130
+ description: example description
131
+ `;
132
+
133
+ expect(
134
+ await lintDoc(source, {
135
+ 'paths-identical': 'error',
136
+ })
137
+ ).toMatchInlineSnapshot(`Array []`);
138
+ });
139
+
140
+ it('should not report valid matching URLs', async () => {
141
+ const source = outdent`
142
+ swagger: '2.0'
143
+ info:
144
+ title: Test
145
+ version: '1.0'
146
+
147
+ paths:
148
+ '/pets/{petId}':
149
+ get:
150
+ responses:
151
+ '200':
152
+ description: example description
153
+ '/pets/mine':
154
+ get:
155
+ responses:
156
+ '200':
157
+ description: example description
158
+ `;
159
+
160
+ expect(
161
+ await lintDoc(source, {
162
+ spec: 'error',
163
+ })
164
+ ).toMatchInlineSnapshot(`Array []`);
165
+ });
166
+
167
+ it('should not report in case of ambiguous matching ', async () => {
168
+ const source = outdent`
169
+ swagger: '2.0'
170
+ info:
171
+ title: Test
172
+ version: '1.0'
173
+
174
+ paths:
175
+ '/{entity}/me':
176
+ get:
177
+ responses:
178
+ '200':
179
+ description: example description
180
+ '/books/{id}':
181
+ get:
182
+ responses:
183
+ '200':
184
+ description: example description
185
+ `;
186
+
187
+ expect(
188
+ await lintDoc(source, {
189
+ spec: 'error',
190
+ })
191
+ ).toMatchInlineSnapshot(`Array []`);
192
+ });
193
+
194
+ it('should not report if Path Item is empty ', async () => {
195
+ const source = outdent`
196
+ swagger: '2.0'
197
+ info:
198
+ title: Test
199
+ version: '1.0'
200
+
201
+ paths:
202
+ '/ping': {}
203
+ `;
204
+
205
+ expect(
206
+ await lintDoc(source, {
207
+ spec: 'error',
208
+ })
209
+ ).toMatchInlineSnapshot(`Array []`);
210
+ });
211
+
212
+ it('should not report of a valid Parameter Object', async () => {
213
+ const source = outdent`
214
+ swagger: '2.0'
215
+ info:
216
+ title: Test
217
+ version: '1.0'
218
+
219
+ paths:
220
+ /pet:
221
+ parameters:
222
+ - name: Accept-Language
223
+ in: header
224
+ description: "test"
225
+ required: false
226
+ type: string
227
+ default: en-AU
228
+ post:
229
+ tags:
230
+ - pet
231
+ summary: Add a new pet to the store
232
+ description: Add new pet to the store inventory.
233
+ operationId: addPet
234
+ responses:
235
+ '405':
236
+ description: Invalid input
237
+ `;
238
+
239
+ expect(
240
+ await lintDoc(source, {
241
+ spec: 'error',
242
+ })
243
+ ).toMatchInlineSnapshot(`Array []`);
244
+ });
245
+ });
@@ -0,0 +1,35 @@
1
+ import { outdent } from 'outdent';
2
+ import {
3
+ parseYamlToDocument,
4
+ replaceSourceWithRef,
5
+ makeConfig,
6
+ } from '../../../../../__tests__/utils';
7
+ import { lintDocument } from '../../../../lint';
8
+ import { BaseResolver } from '../../../../resolve';
9
+
10
+ describe('Referenceable scalars', () => {
11
+ it('should not report $ref description', async () => {
12
+ const document = parseYamlToDocument(
13
+ outdent`
14
+ swagger: '2.0'
15
+ info:
16
+ title: Test
17
+ version: '1.0'
18
+ description:
19
+ $ref: fixtures/description.md
20
+ paths: {}
21
+ `,
22
+ __dirname + '/foobar.yaml'
23
+ );
24
+
25
+ const results = await lintDocument({
26
+ externalRefResolver: new BaseResolver(),
27
+ document,
28
+ config: await makeConfig({
29
+ spec: 'error',
30
+ }),
31
+ });
32
+
33
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
34
+ });
35
+ });
@@ -0,0 +1,32 @@
1
+ import { StyleguideConfig, RuleConfig, resolveStyleguideConfig } from '../../../../config';
2
+ import { parseYamlToDocument } from '../../../../../__tests__/utils';
3
+ import { lintDocument } from '../../../../lint';
4
+ import { BaseResolver } from '../../../../resolve';
5
+
6
+ export async function lintDoc(
7
+ source: string,
8
+ rules: Record<string, RuleConfig> = { spec: 'error' }
9
+ ) {
10
+ const document = parseYamlToDocument(source, 'foobar.yaml');
11
+
12
+ const results = await lintDocument({
13
+ externalRefResolver: new BaseResolver(),
14
+ document,
15
+ config: new StyleguideConfig(
16
+ await resolveStyleguideConfig({
17
+ styleguideConfig: {
18
+ plugins: [],
19
+ extends: [],
20
+ rules,
21
+ },
22
+ })
23
+ ),
24
+ });
25
+
26
+ return results.map((res) => {
27
+ return {
28
+ message: res.message,
29
+ location: res.location[0].pointer || '',
30
+ };
31
+ });
32
+ }
@@ -0,0 +1,26 @@
1
+ import { Oas2Rule } from '../../visitors';
2
+
3
+ export type BooleanParameterPrefixesOptions = {
4
+ prefixes?: string[];
5
+ };
6
+
7
+ export const BooleanParameterPrefixes: Oas2Rule = (options: BooleanParameterPrefixesOptions) => {
8
+ const prefixes = options.prefixes || ['is', 'has'];
9
+ const regexp = new RegExp(`^(${prefixes.join('|')})[A-Z-_]`);
10
+ const wrappedPrefixes = prefixes.map((p) => `\`${p}\``);
11
+ const prefixesString =
12
+ wrappedPrefixes.length === 1
13
+ ? wrappedPrefixes[0]
14
+ : wrappedPrefixes.slice(0, -1).join(', ') + ' or ' + wrappedPrefixes[prefixes.length - 1];
15
+
16
+ return {
17
+ Parameter(param, { report, location }) {
18
+ if (param.type === 'boolean' && !regexp.test(param.name)) {
19
+ report({
20
+ message: `Boolean parameter \`${param.name}\` should have ${prefixesString} prefix.`,
21
+ location: location.child('name'),
22
+ });
23
+ }
24
+ },
25
+ };
26
+ };
@@ -0,0 +1,91 @@
1
+ import { Oas2Rule } from '../../visitors';
2
+ import { OasSpec } from '../common/spec';
3
+ import { NoInvalidSchemaExamples } from '../common/no-invalid-schema-examples';
4
+ import { NoInvalidParameterExamples } from '../common/no-invalid-parameter-examples';
5
+ import { InfoContact } from '../common/info-contact';
6
+ import { InfoLicense } from '../common/info-license';
7
+ import { InfoLicenseUrl } from '../common/info-license-url';
8
+ import { BooleanParameterPrefixes } from './boolean-parameter-prefixes';
9
+ import { TagDescription } from '../common/tag-description';
10
+ import { TagsAlphabetical } from '../common/tags-alphabetical';
11
+ import { PathsKebabCase } from '../common/paths-kebab-case';
12
+ import { NoEnumTypeMismatch } from '../common/no-enum-type-mismatch';
13
+ import { NoPathTrailingSlash } from '../common/no-path-trailing-slash';
14
+ import { Operation2xxResponse } from '../common/operation-2xx-response';
15
+ import { Operation4xxResponse } from '../common/operation-4xx-response';
16
+ import { Assertions } from '../common/assertions';
17
+ import { OperationIdUnique } from '../common/operation-operationId-unique';
18
+ import { OperationParametersUnique } from '../common/operation-parameters-unique';
19
+ import { PathParamsDefined } from '../common/path-params-defined';
20
+ import { OperationTagDefined } from '../common/operation-tag-defined';
21
+ import { PathDeclarationMustExist } from '../common/path-declaration-must-exist';
22
+ import { OperationIdUrlSafe } from '../common/operation-operationId-url-safe';
23
+ import { OperationDescription } from '../common/operation-description';
24
+ import { PathNotIncludeQuery } from '../common/path-not-include-query';
25
+ import { ParameterDescription } from '../common/parameter-description';
26
+ import { OperationSingularTag } from '../common/operation-singular-tag';
27
+ import { SecurityDefined } from '../common/security-defined';
28
+ import { NoUnresolvedRefs } from '../no-unresolved-refs';
29
+ import { PathHttpVerbsOrder } from '../common/path-http-verbs-order';
30
+ import { NoIdenticalPaths } from '../common/no-identical-paths';
31
+ import { OperationOperationId } from '../common/operation-operationId';
32
+ import { OperationSummary } from '../common/operation-summary';
33
+ import { NoAmbiguousPaths } from '../common/no-ambiguous-paths';
34
+ import { NoHttpVerbsInPaths } from '../common/no-http-verbs-in-paths';
35
+ import { PathExcludesPatterns } from '../common/path-excludes-patterns';
36
+ import { RequestMimeType } from './request-mime-type';
37
+ import { ResponseMimeType } from './response-mime-type';
38
+ import { PathSegmentPlural } from '../common/path-segment-plural';
39
+ import { ResponseContainsHeader } from '../common/response-contains-header';
40
+ import { ResponseContainsProperty } from './response-contains-property';
41
+ import { ScalarPropertyMissingExample } from '../common/scalar-property-missing-example';
42
+ import { RequiredStringPropertyMissingMinLength } from '../common/required-string-property-missing-min-length';
43
+ import { SpecStrictRefs } from '../common/spec-strict-refs';
44
+
45
+ export const rules = {
46
+ spec: OasSpec as Oas2Rule,
47
+ 'no-invalid-schema-examples': NoInvalidSchemaExamples,
48
+ 'no-invalid-parameter-examples': NoInvalidParameterExamples,
49
+ 'info-contact': InfoContact as Oas2Rule,
50
+ 'info-license': InfoLicense as Oas2Rule,
51
+ 'info-license-url': InfoLicenseUrl as Oas2Rule,
52
+ 'tag-description': TagDescription as Oas2Rule,
53
+ 'tags-alphabetical': TagsAlphabetical as Oas2Rule,
54
+ 'paths-kebab-case': PathsKebabCase as Oas2Rule,
55
+ 'no-enum-type-mismatch': NoEnumTypeMismatch as Oas2Rule,
56
+ 'boolean-parameter-prefixes': BooleanParameterPrefixes as Oas2Rule,
57
+ 'no-path-trailing-slash': NoPathTrailingSlash as Oas2Rule,
58
+ 'operation-2xx-response': Operation2xxResponse as Oas2Rule,
59
+ 'operation-4xx-response': Operation4xxResponse as Oas2Rule,
60
+ assertions: Assertions as Oas2Rule,
61
+ 'operation-operationId-unique': OperationIdUnique as Oas2Rule,
62
+ 'operation-parameters-unique': OperationParametersUnique as Oas2Rule,
63
+ 'path-parameters-defined': PathParamsDefined as Oas2Rule,
64
+ 'operation-tag-defined': OperationTagDefined as Oas2Rule,
65
+ 'path-declaration-must-exist': PathDeclarationMustExist as Oas2Rule,
66
+ 'operation-operationId-url-safe': OperationIdUrlSafe as Oas2Rule,
67
+ 'operation-operationId': OperationOperationId as Oas2Rule,
68
+ 'operation-summary': OperationSummary as Oas2Rule,
69
+ 'operation-description': OperationDescription as Oas2Rule,
70
+ 'path-not-include-query': PathNotIncludeQuery as Oas2Rule,
71
+ 'path-params-defined': PathParamsDefined as Oas2Rule,
72
+ 'parameter-description': ParameterDescription as Oas2Rule,
73
+ 'operation-singular-tag': OperationSingularTag as Oas2Rule,
74
+ 'security-defined': SecurityDefined as Oas2Rule,
75
+ 'no-unresolved-refs': NoUnresolvedRefs as Oas2Rule,
76
+ 'no-identical-paths': NoIdenticalPaths as Oas2Rule,
77
+ 'no-ambiguous-paths': NoAmbiguousPaths as Oas2Rule,
78
+ 'path-http-verbs-order': PathHttpVerbsOrder as Oas2Rule,
79
+ 'no-http-verbs-in-paths': NoHttpVerbsInPaths as Oas2Rule,
80
+ 'path-excludes-patterns': PathExcludesPatterns as Oas2Rule,
81
+ 'request-mime-type': RequestMimeType as Oas2Rule,
82
+ 'response-mime-type': ResponseMimeType as Oas2Rule,
83
+ 'path-segment-plural': PathSegmentPlural as Oas2Rule,
84
+ 'response-contains-header': ResponseContainsHeader as Oas2Rule,
85
+ 'response-contains-property': ResponseContainsProperty as Oas2Rule,
86
+ 'scalar-property-missing-example': ScalarPropertyMissingExample,
87
+ 'required-string-property-missing-min-length': RequiredStringPropertyMissingMinLength,
88
+ 'spec-strict-refs': SpecStrictRefs,
89
+ };
90
+
91
+ export const preprocessors = {};
@@ -0,0 +1,81 @@
1
+ import { Oas2Rule } from '../../visitors';
2
+ import { Location } from '../../ref-utils';
3
+ import { Oas2Components } from '../../typings/swagger';
4
+ import { isEmptyObject } from '../../utils';
5
+
6
+ export const RemoveUnusedComponents: Oas2Rule = () => {
7
+ const components = new Map<
8
+ string,
9
+ { used: boolean; componentType?: keyof Oas2Components; name: string }
10
+ >();
11
+
12
+ function registerComponent(
13
+ location: Location,
14
+ componentType: keyof Oas2Components,
15
+ name: string
16
+ ): void {
17
+ components.set(location.absolutePointer, {
18
+ used: components.get(location.absolutePointer)?.used || false,
19
+ componentType,
20
+ name,
21
+ });
22
+ }
23
+
24
+ return {
25
+ ref: {
26
+ leave(ref, { type, resolve, key }) {
27
+ if (['Schema', 'Parameter', 'Response', 'SecurityScheme'].includes(type.name)) {
28
+ const resolvedRef = resolve(ref);
29
+ if (!resolvedRef.location) return;
30
+ components.set(resolvedRef.location.absolutePointer, {
31
+ used: true,
32
+ name: key.toString(),
33
+ });
34
+ }
35
+ },
36
+ },
37
+ Root: {
38
+ leave(root, ctx) {
39
+ const data = ctx.getVisitorData() as { removedCount: number };
40
+ data.removedCount = 0;
41
+
42
+ const rootComponents = new Set<keyof Oas2Components>();
43
+ components.forEach((usageInfo) => {
44
+ const { used, name, componentType } = usageInfo;
45
+ if (!used && componentType) {
46
+ rootComponents.add(componentType);
47
+ delete root[componentType]![name];
48
+ data.removedCount++;
49
+ }
50
+ });
51
+ for (const component of rootComponents) {
52
+ if (isEmptyObject(root[component])) {
53
+ delete root[component];
54
+ }
55
+ }
56
+ },
57
+ },
58
+ NamedSchemas: {
59
+ Schema(schema, { location, key }) {
60
+ if (!schema.allOf) {
61
+ registerComponent(location, 'definitions', key.toString());
62
+ }
63
+ },
64
+ },
65
+ NamedParameters: {
66
+ Parameter(_parameter, { location, key }) {
67
+ registerComponent(location, 'parameters', key.toString());
68
+ },
69
+ },
70
+ NamedResponses: {
71
+ Response(_response, { location, key }) {
72
+ registerComponent(location, 'responses', key.toString());
73
+ },
74
+ },
75
+ NamedSecuritySchemes: {
76
+ SecurityScheme(_securityScheme, { location, key }) {
77
+ registerComponent(location, 'securityDefinitions', key.toString());
78
+ },
79
+ },
80
+ };
81
+ };
@@ -0,0 +1,16 @@
1
+ import type { Oas2Rule } from '../../visitors';
2
+ import type { UserContext } from '../../walk';
3
+ import { validateMimeType } from '../../utils';
4
+
5
+ export const RequestMimeType: Oas2Rule = ({ allowedValues }) => {
6
+ return {
7
+ Root(root, ctx: UserContext) {
8
+ validateMimeType({ type: 'consumes', value: root }, ctx, allowedValues);
9
+ },
10
+ Operation: {
11
+ leave(operation, ctx: UserContext) {
12
+ validateMimeType({ type: 'consumes', value: operation }, ctx, allowedValues);
13
+ },
14
+ },
15
+ };
16
+ };
@@ -0,0 +1,36 @@
1
+ import { Oas2Rule } from '../../visitors';
2
+ import { UserContext } from '../../walk';
3
+ import { getMatchingStatusCodeRange } from '../../utils';
4
+
5
+ export const ResponseContainsProperty: Oas2Rule = (options) => {
6
+ const names: Record<string, string[]> = options.names || {};
7
+ let key: string | number;
8
+ return {
9
+ Operation: {
10
+ Response: {
11
+ skip: (_response, key) => {
12
+ return `${key}` === '204';
13
+ },
14
+ enter: (_response, ctx: UserContext) => {
15
+ key = ctx.key;
16
+ },
17
+ Schema(schema, { report, location }) {
18
+ if (schema.type !== 'object') return;
19
+ const expectedProperties =
20
+ names[key] ||
21
+ names[getMatchingStatusCodeRange(key)] ||
22
+ names[getMatchingStatusCodeRange(key).toLowerCase()] ||
23
+ [];
24
+ for (const expectedProperty of expectedProperties) {
25
+ if (!schema.properties?.[expectedProperty]) {
26
+ report({
27
+ message: `Response object must contain a top-level "${expectedProperty}" property.`,
28
+ location: location.child('properties').key(),
29
+ });
30
+ }
31
+ }
32
+ },
33
+ },
34
+ },
35
+ };
36
+ };
@@ -0,0 +1,16 @@
1
+ import type { Oas2Rule } from '../../visitors';
2
+ import type { UserContext } from '../../walk';
3
+ import { validateMimeType } from '../../utils';
4
+
5
+ export const ResponseMimeType: Oas2Rule = ({ allowedValues }) => {
6
+ return {
7
+ Root(root, ctx: UserContext) {
8
+ validateMimeType({ type: 'produces', value: root }, ctx, allowedValues);
9
+ },
10
+ Operation: {
11
+ leave(operation, ctx: UserContext) {
12
+ validateMimeType({ type: 'produces', value: operation }, ctx, allowedValues);
13
+ },
14
+ },
15
+ };
16
+ };
@@ -0,0 +1,111 @@
1
+ import { outdent } from 'outdent';
2
+ import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../../../__tests__/utils';
3
+ import { lintDocument } from '../../../lint';
4
+ import { BaseResolver } from '../../../resolve';
5
+
6
+ describe('oas3 boolean-parameter-prefixes', () => {
7
+ it('should report on boolean param without prefix', async () => {
8
+ const document = parseYamlToDocument(
9
+ outdent`
10
+ openapi: 3.0.0
11
+ paths:
12
+ '/test':
13
+ parameters:
14
+ - name: a
15
+ in: path
16
+ schema:
17
+ type: boolean
18
+ `,
19
+ 'foobar.yaml'
20
+ );
21
+
22
+ const results = await lintDocument({
23
+ externalRefResolver: new BaseResolver(),
24
+ document,
25
+ config: await makeConfig({ 'boolean-parameter-prefixes': 'error' }),
26
+ });
27
+
28
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
29
+ Array [
30
+ Object {
31
+ "location": Array [
32
+ Object {
33
+ "pointer": "#/paths/~1test/parameters/0/name",
34
+ "reportOnKey": false,
35
+ "source": "foobar.yaml",
36
+ },
37
+ ],
38
+ "message": "Boolean parameter \`a\` should have \`is\` or \`has\` prefix.",
39
+ "ruleId": "boolean-parameter-prefixes",
40
+ "severity": "error",
41
+ "suggest": Array [],
42
+ },
43
+ ]
44
+ `);
45
+ });
46
+
47
+ it('should not report on boolean param with prefix', async () => {
48
+ const document = parseYamlToDocument(
49
+ outdent`
50
+ openapi: 3.0.0
51
+ paths:
52
+ '/test':
53
+ parameters:
54
+ - name: hasA
55
+ in: path
56
+ schema:
57
+ type: boolean
58
+ - name: isA
59
+ in: path
60
+ schema:
61
+ type: boolean
62
+ - name: has_a
63
+ in: path
64
+ schema:
65
+ type: boolean
66
+ - name: is-a
67
+ in: path
68
+ schema:
69
+ type: boolean
70
+ `,
71
+ 'foobar.yaml'
72
+ );
73
+
74
+ const results = await lintDocument({
75
+ externalRefResolver: new BaseResolver(),
76
+ document,
77
+ config: await makeConfig({ 'boolean-parameter-prefixes': 'error' }),
78
+ });
79
+
80
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
81
+ });
82
+
83
+ it('should not report on boolean param with custom prefix', async () => {
84
+ const document = parseYamlToDocument(
85
+ outdent`
86
+ openapi: 3.0.0
87
+ paths:
88
+ '/test':
89
+ parameters:
90
+ - name: should-a
91
+ in: query
92
+ schema:
93
+ type: boolean
94
+ `,
95
+ 'foobar.yaml'
96
+ );
97
+
98
+ const results = await lintDocument({
99
+ externalRefResolver: new BaseResolver(),
100
+ document,
101
+ config: await makeConfig({
102
+ 'boolean-parameter-prefixes': {
103
+ severity: 'error',
104
+ prefixes: ['should'],
105
+ },
106
+ }),
107
+ });
108
+
109
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
110
+ });
111
+ });