@redocly/openapi-core 1.0.0 → 1.0.2

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 +9 -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,257 @@
1
+ import path = require('path');
2
+ import { outdent } from 'outdent';
3
+ import { lintDocument } from '../../lint';
4
+ import { BaseResolver } from '../../resolve';
5
+ import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../../__tests__/utils';
6
+
7
+ describe('oas3 boolean-parameter-prefixes', () => {
8
+ it('should report on unresolved $ref', async () => {
9
+ const document = parseYamlToDocument(
10
+ outdent`
11
+ openapi: 3.0.0
12
+ paths:
13
+ '/test':
14
+ put:
15
+ requestBody:
16
+ $ref: 'invalid.yaml'
17
+ `,
18
+ path.join(__dirname, 'foobar.yaml')
19
+ );
20
+
21
+ const results = await lintDocument({
22
+ externalRefResolver: new BaseResolver(),
23
+ document,
24
+ config: await makeConfig({
25
+ 'no-unresolved-refs': 'error',
26
+ }),
27
+ });
28
+
29
+ expect(replaceSourceWithRef(results, __dirname)).toMatchInlineSnapshot(`
30
+ Array [
31
+ Object {
32
+ "location": Array [
33
+ Object {
34
+ "pointer": "#/paths/~1test/put/requestBody",
35
+ "reportOnKey": false,
36
+ "source": "foobar.yaml",
37
+ },
38
+ ],
39
+ "message": "Can't resolve $ref: ENOENT: no such file or directory 'invalid.yaml'",
40
+ "ruleId": "no-unresolved-refs",
41
+ "severity": "error",
42
+ "suggest": Array [],
43
+ },
44
+ ]
45
+ `);
46
+ });
47
+
48
+ it('should report on unresolved $ref yaml error', async () => {
49
+ const document = parseYamlToDocument(
50
+ outdent`
51
+ openapi: 3.0.0
52
+ paths:
53
+ '/test':
54
+ put:
55
+ requestBody:
56
+ $ref: 'fixtures/invalid-yaml.yaml'
57
+ `,
58
+ path.join(__dirname, 'foobar.yaml')
59
+ );
60
+
61
+ const results = await lintDocument({
62
+ externalRefResolver: new BaseResolver(),
63
+ document,
64
+ config: await makeConfig({
65
+ 'no-unresolved-refs': 'error',
66
+ }),
67
+ });
68
+
69
+ expect(replaceSourceWithRef(results, __dirname)).toMatchInlineSnapshot(`
70
+ Array [
71
+ Object {
72
+ "location": Array [
73
+ Object {
74
+ "pointer": undefined,
75
+ "reportOnKey": false,
76
+ "source": "fixtures/invalid-yaml.yaml",
77
+ "start": Object {
78
+ "col": 1,
79
+ "line": 2,
80
+ },
81
+ },
82
+ ],
83
+ "message": "Failed to parse: unexpected end of the stream within a single quoted scalar in \\"fixtures/invalid-yaml.yaml\\" (2:1)",
84
+ "ruleId": "no-unresolved-refs",
85
+ "severity": "error",
86
+ "suggest": Array [],
87
+ },
88
+ Object {
89
+ "location": Array [
90
+ Object {
91
+ "pointer": "#/paths/~1test/put/requestBody",
92
+ "reportOnKey": false,
93
+ "source": "foobar.yaml",
94
+ },
95
+ ],
96
+ "message": "Can't resolve $ref: unexpected end of the stream within a single quoted scalar in \\"fixtures/invalid-yaml.yaml\\" (2:1)",
97
+ "ruleId": "no-unresolved-refs",
98
+ "severity": "error",
99
+ "suggest": Array [],
100
+ },
101
+ ]
102
+ `);
103
+ });
104
+
105
+ it('should report on unresolved $ref yaml error', async () => {
106
+ const document = parseYamlToDocument(
107
+ outdent`
108
+ openapi: 3.0.0
109
+ paths:
110
+ '/test':
111
+ put:
112
+ requestBody:
113
+ $ref: 'fixtures/ref.yaml'
114
+ `,
115
+ path.join(__dirname, 'foobar.yaml')
116
+ );
117
+
118
+ const results = await lintDocument({
119
+ externalRefResolver: new BaseResolver(),
120
+ document,
121
+ config: await makeConfig({
122
+ 'no-unresolved-refs': 'error',
123
+ }),
124
+ });
125
+
126
+ expect(replaceSourceWithRef(results, __dirname)).toMatchInlineSnapshot(`Array []`);
127
+ });
128
+
129
+ it('should report on unresolved localr ref', async () => {
130
+ const document = parseYamlToDocument(
131
+ outdent`
132
+ openapi: 3.0.0
133
+ paths:
134
+ '/test':
135
+ put:
136
+ requestBody:
137
+ $ref: '#/components/requestBodies/a'
138
+ `,
139
+ path.join(__dirname, 'foobar.yaml')
140
+ );
141
+
142
+ const results = await lintDocument({
143
+ externalRefResolver: new BaseResolver(),
144
+ document,
145
+ config: await makeConfig({
146
+ 'no-unresolved-refs': 'error',
147
+ }),
148
+ });
149
+
150
+ expect(replaceSourceWithRef(results, __dirname)).toMatchInlineSnapshot(`
151
+ Array [
152
+ Object {
153
+ "location": Array [
154
+ Object {
155
+ "pointer": "#/paths/~1test/put/requestBody",
156
+ "reportOnKey": false,
157
+ "source": "foobar.yaml",
158
+ },
159
+ ],
160
+ "message": "Can't resolve $ref",
161
+ "ruleId": "no-unresolved-refs",
162
+ "severity": "error",
163
+ "suggest": Array [],
164
+ },
165
+ ]
166
+ `);
167
+ });
168
+
169
+ it('should not report on refs inside specification extensions', async () => {
170
+ const document = parseYamlToDocument(
171
+ outdent`
172
+ openapi: 3.0.0
173
+ components:
174
+ requestBodies:
175
+ a:
176
+ content:
177
+ application/json:
178
+ schema:
179
+ type: object
180
+ x-webhooks:
181
+ test:
182
+ put:
183
+ requestBody:
184
+ $ref: '#/components/requestBodies/a'
185
+ `,
186
+ path.join(__dirname, 'foobar.yaml')
187
+ );
188
+
189
+ const results = await lintDocument({
190
+ externalRefResolver: new BaseResolver(),
191
+ document,
192
+ config: await makeConfig({
193
+ 'no-unresolved-refs': 'error',
194
+ }),
195
+ });
196
+
197
+ expect(replaceSourceWithRef(results, __dirname)).toMatchInlineSnapshot(`Array []`);
198
+ });
199
+
200
+ it('should not report on nested refs inside specification extensions', async () => {
201
+ const document = parseYamlToDocument(
202
+ outdent`
203
+ openapi: 3.0.0
204
+ x-test:
205
+ prop:
206
+ $ref: 'fixtures/ref.yaml'
207
+ paths:
208
+ '/test':
209
+ get:
210
+ x-codeSamples:
211
+ - lang: PHP
212
+ source:
213
+ $ref: 'fixtures/code-sample.php'
214
+ `,
215
+ path.join(__dirname, 'foobar.yaml')
216
+ );
217
+
218
+ const results = await lintDocument({
219
+ externalRefResolver: new BaseResolver(),
220
+ document,
221
+ config: await makeConfig({
222
+ 'no-unresolved-refs': 'error',
223
+ }),
224
+ });
225
+
226
+ expect(replaceSourceWithRef(results, __dirname)).toMatchInlineSnapshot(`Array []`);
227
+ });
228
+
229
+ it('should not report on nested refs inside specification extensions for 3.1', async () => {
230
+ const document = parseYamlToDocument(
231
+ outdent`
232
+ openapi: 3.1.0
233
+ x-test:
234
+ prop:
235
+ $ref: 'fixtures/ref.yaml'
236
+ paths:
237
+ '/test':
238
+ get:
239
+ x-codeSamples:
240
+ - lang: PHP
241
+ source:
242
+ $ref: 'fixtures/code-sample.php'
243
+ `,
244
+ path.join(__dirname, 'foobar.yaml')
245
+ );
246
+
247
+ const results = await lintDocument({
248
+ externalRefResolver: new BaseResolver(),
249
+ document,
250
+ config: await makeConfig({
251
+ 'no-unresolved-refs': 'error',
252
+ }),
253
+ });
254
+
255
+ expect(replaceSourceWithRef(results, __dirname)).toMatchInlineSnapshot(`Array []`);
256
+ });
257
+ });
@@ -0,0 +1,160 @@
1
+ import {
2
+ fieldNonEmpty,
3
+ matchesJsonSchemaType,
4
+ missingRequiredField,
5
+ oasTypeOf,
6
+ getAdditionalPropertiesOption,
7
+ } from '../utils';
8
+
9
+ describe('field-non-empty', () => {
10
+ it('should match expected message', () => {
11
+ const message = fieldNonEmpty('Car', 'color');
12
+ expect(message).toBe('Car object `color` must be non-empty string.');
13
+ });
14
+ });
15
+
16
+ describe('matches-json-schema-type', () => {
17
+ it('should report true on a null value with nullable type', () => {
18
+ const results = matchesJsonSchemaType(null, 'string', true);
19
+ expect(results).toBe(true);
20
+ });
21
+
22
+ it('should report true on a value and type integer', () => {
23
+ const results = matchesJsonSchemaType(123, 'integer', false);
24
+ expect(results).toBe(true);
25
+ });
26
+
27
+ it('should report false when the value is not integer and type is integer', () => {
28
+ const results = matchesJsonSchemaType(3.14, 'integer', false);
29
+ expect(results).toBe(false);
30
+ });
31
+
32
+ it('should report true when the value is a number and type is number', () => {
33
+ const results = matchesJsonSchemaType(3.14, 'number', false);
34
+ expect(results).toBe(true);
35
+ });
36
+
37
+ it('should report true when the value is an integer and type is number', () => {
38
+ const results = matchesJsonSchemaType(3, 'number', false);
39
+ expect(results).toBe(true);
40
+ });
41
+
42
+ it('should report true when the value is true and type is boolean', () => {
43
+ const results = matchesJsonSchemaType(true, 'boolean', false);
44
+ expect(results).toBe(true);
45
+ });
46
+
47
+ it('should report true when the value is false and type is boolean', () => {
48
+ const results = matchesJsonSchemaType(false, 'boolean', false);
49
+ expect(results).toBe(true);
50
+ });
51
+
52
+ it('should report true when the value is a string and type is boolean', () => {
53
+ const results = matchesJsonSchemaType('test', 'boolean', false);
54
+ expect(results).toBe(false);
55
+ });
56
+
57
+ it('should report true on an array value with array type', () => {
58
+ const results = matchesJsonSchemaType(['foo', 'bar'], 'array', false);
59
+ expect(results).toBe(true);
60
+ });
61
+
62
+ it('should report false on an array value with object type', () => {
63
+ const results = matchesJsonSchemaType(['foo', 'bar'], 'object', false);
64
+ expect(results).toBe(false);
65
+ });
66
+
67
+ it('should report true on an object value with object type', () => {
68
+ const car = { type: 'Fiat', model: '500', color: 'white' };
69
+ const results = matchesJsonSchemaType(car, 'object', true);
70
+ expect(results).toBe(true);
71
+ });
72
+
73
+ it('should report false on an object value with array type', () => {
74
+ const car = { type: 'Fiat', model: '500', color: 'white' };
75
+ const results = matchesJsonSchemaType(car, 'array', true);
76
+ expect(results).toBe(false);
77
+ });
78
+ });
79
+
80
+ describe('missing-required-field', () => {
81
+ it('should match expected message for missing required field', () => {
82
+ const message = missingRequiredField('Car', 'color');
83
+ expect(message).toBe('Car object should contain `color` field.');
84
+ });
85
+ });
86
+
87
+ describe('oas-type-of', () => {
88
+ it('should report the correct oas type for a string', () => {
89
+ const results = oasTypeOf('word');
90
+ expect(results).toBe('string');
91
+ });
92
+
93
+ it('should report the correct oas type for an integer', () => {
94
+ const results = oasTypeOf(123);
95
+ expect(results).toBe('integer');
96
+ });
97
+
98
+ it('should report the correct oas type for a number', () => {
99
+ const results = oasTypeOf(3.14);
100
+ expect(results).toBe('number');
101
+ });
102
+
103
+ it('should report the correct oas type for a null value', () => {
104
+ const results = oasTypeOf(null);
105
+ expect(results).toBe('null');
106
+ });
107
+
108
+ it('should report the correct oas type for a true boolean', () => {
109
+ const results = oasTypeOf(true);
110
+ expect(results).toBe('boolean');
111
+ });
112
+
113
+ it('should report the correct oas type for a false boolean', () => {
114
+ const results = oasTypeOf(false);
115
+ expect(results).toBe('boolean');
116
+ });
117
+
118
+ it('should report the correct oas type for an array', () => {
119
+ const results = oasTypeOf(['foo', 'bar']);
120
+ expect(results).toBe('array');
121
+ });
122
+
123
+ it('should report the correct oas type for an object', () => {
124
+ const car = { type: 'Fiat', model: '500', color: 'white' };
125
+ const results = oasTypeOf(car);
126
+ expect(results).toBe('object');
127
+ });
128
+ });
129
+
130
+ describe('get-additional-properties-option', () => {
131
+ it('should return actual option', () => {
132
+ const options = {
133
+ allowAdditionalProperties: true,
134
+ };
135
+ expect(getAdditionalPropertiesOption(options)).toBeTruthy();
136
+ });
137
+
138
+ it('should reverse option', () => {
139
+ const options = {
140
+ disallowAdditionalProperties: true,
141
+ };
142
+ expect(getAdditionalPropertiesOption(options)).toBeFalsy();
143
+ });
144
+
145
+ it('should throw error with message', () => {
146
+ const options = {
147
+ allowAdditionalProperties: true,
148
+ disallowAdditionalProperties: false,
149
+ };
150
+
151
+ try {
152
+ getAdditionalPropertiesOption(options);
153
+ } catch (error) {
154
+ expect(error).toBeInstanceOf(Error);
155
+ expect(error.message).toEqual(
156
+ "Do not use 'disallowAdditionalProperties' field. Use 'allowAdditionalProperties' instead. \n"
157
+ );
158
+ }
159
+ });
160
+ });
@@ -0,0 +1,102 @@
1
+ import Ajv, { ValidateFunction, ErrorObject } from '@redocly/ajv/dist/2020';
2
+ import { Location, escapePointer } from '../ref-utils';
3
+ import { ResolveFn } from '../walk';
4
+
5
+ let ajvInstance: Ajv | null = null;
6
+
7
+ export function releaseAjvInstance() {
8
+ ajvInstance = null;
9
+ }
10
+
11
+ function getAjv(resolve: ResolveFn, allowAdditionalProperties: boolean) {
12
+ if (!ajvInstance) {
13
+ ajvInstance = new Ajv({
14
+ schemaId: '$id',
15
+ meta: true,
16
+ allErrors: true,
17
+ strictSchema: false,
18
+ inlineRefs: false,
19
+ validateSchema: false,
20
+ discriminator: true,
21
+ allowUnionTypes: true,
22
+ validateFormats: false, // TODO: fix it
23
+ defaultUnevaluatedProperties: allowAdditionalProperties,
24
+ loadSchemaSync(base: string, $ref: string) {
25
+ const resolvedRef = resolve({ $ref }, base.split('#')[0]);
26
+ if (!resolvedRef || !resolvedRef.location) return false;
27
+ return { $id: resolvedRef.location.absolutePointer, ...resolvedRef.node };
28
+ },
29
+ logger: false,
30
+ });
31
+ }
32
+ return ajvInstance;
33
+ }
34
+
35
+ function getAjvValidator(
36
+ schema: any,
37
+ loc: Location,
38
+ resolve: ResolveFn,
39
+ allowAdditionalProperties: boolean
40
+ ): ValidateFunction | undefined {
41
+ const ajv = getAjv(resolve, allowAdditionalProperties);
42
+
43
+ if (!ajv.getSchema(loc.absolutePointer)) {
44
+ ajv.addSchema({ $id: loc.absolutePointer, ...schema }, loc.absolutePointer);
45
+ }
46
+
47
+ return ajv.getSchema(loc.absolutePointer);
48
+ }
49
+
50
+ export function validateJsonSchema(
51
+ data: any,
52
+ schema: any,
53
+ schemaLoc: Location,
54
+ instancePath: string,
55
+ resolve: ResolveFn,
56
+ allowAdditionalProperties: boolean
57
+ ): { valid: boolean; errors: (ErrorObject & { suggest?: string[] })[] } {
58
+ const validate = getAjvValidator(schema, schemaLoc, resolve, allowAdditionalProperties);
59
+ if (!validate) return { valid: true, errors: [] }; // unresolved refs are reported
60
+
61
+ const valid = validate(data, {
62
+ instancePath,
63
+ parentData: { fake: {} },
64
+ parentDataProperty: 'fake',
65
+ rootData: {},
66
+ dynamicAnchors: {},
67
+ });
68
+
69
+ return {
70
+ valid: !!valid,
71
+ errors: (validate.errors || []).map(beatifyErrorMessage),
72
+ };
73
+
74
+ function beatifyErrorMessage(error: ErrorObject) {
75
+ let message = error.message;
76
+ const suggest = error.keyword === 'enum' ? error.params.allowedValues : undefined;
77
+ if (suggest) {
78
+ message += ` ${suggest.map((e: any) => `"${e}"`).join(', ')}`;
79
+ }
80
+
81
+ if (error.keyword === 'type') {
82
+ message = `type ${message}`;
83
+ }
84
+
85
+ const relativePath = error.instancePath.substring(instancePath.length + 1);
86
+ const propName = relativePath.substring(relativePath.lastIndexOf('/') + 1);
87
+ if (propName) {
88
+ message = `\`${propName}\` property ${message}`;
89
+ }
90
+ if (error.keyword === 'additionalProperties' || error.keyword === 'unevaluatedProperties') {
91
+ const property = error.params.additionalProperty || error.params.unevaluatedProperty;
92
+ message = `${message} \`${property}\``;
93
+ error.instancePath += '/' + escapePointer(property);
94
+ }
95
+
96
+ return {
97
+ ...error,
98
+ message,
99
+ suggest,
100
+ };
101
+ }
102
+ }
@@ -0,0 +1,62 @@
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 info-license', () => {
7
+ it('should report on info with no license', async () => {
8
+ const document = parseYamlToDocument(
9
+ outdent`
10
+ openapi: 3.0.0
11
+ info:
12
+ version: '1.0'
13
+ `,
14
+ 'foobar.yaml'
15
+ );
16
+
17
+ const results = await lintDocument({
18
+ externalRefResolver: new BaseResolver(),
19
+ document,
20
+ config: await makeConfig({ 'info-license': 'error' }),
21
+ });
22
+
23
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
24
+ Array [
25
+ Object {
26
+ "location": Array [
27
+ Object {
28
+ "pointer": "#/info",
29
+ "reportOnKey": true,
30
+ "source": "foobar.yaml",
31
+ },
32
+ ],
33
+ "message": "Info object should contain \`license\` field.",
34
+ "ruleId": "info-license",
35
+ "severity": "error",
36
+ "suggest": Array [],
37
+ },
38
+ ]
39
+ `);
40
+ });
41
+
42
+ it('should not report on info with license', async () => {
43
+ const document = parseYamlToDocument(
44
+ outdent`
45
+ openapi: 3.0.0
46
+ info:
47
+ license:
48
+ name: MIT
49
+ url: google.com
50
+ `,
51
+ 'foobar.yaml'
52
+ );
53
+
54
+ const results = await lintDocument({
55
+ externalRefResolver: new BaseResolver(),
56
+ document,
57
+ config: await makeConfig({ 'info-license': 'error' }),
58
+ });
59
+
60
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
61
+ });
62
+ });
@@ -0,0 +1,63 @@
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 license-url', () => {
7
+ it('should report on info.license with no url', async () => {
8
+ const document = parseYamlToDocument(
9
+ outdent`
10
+ openapi: 3.0.0
11
+ info:
12
+ license:
13
+ name: MIT
14
+ `,
15
+ 'foobar.yaml'
16
+ );
17
+
18
+ const results = await lintDocument({
19
+ externalRefResolver: new BaseResolver(),
20
+ document,
21
+ config: await makeConfig({ 'info-license-url': 'error' }),
22
+ });
23
+
24
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
25
+ Array [
26
+ Object {
27
+ "location": Array [
28
+ Object {
29
+ "pointer": "#/info/license/url",
30
+ "reportOnKey": true,
31
+ "source": "foobar.yaml",
32
+ },
33
+ ],
34
+ "message": "License object should contain \`url\` field.",
35
+ "ruleId": "info-license-url",
36
+ "severity": "error",
37
+ "suggest": Array [],
38
+ },
39
+ ]
40
+ `);
41
+ });
42
+
43
+ it('should not report on info.license with url', async () => {
44
+ const document = parseYamlToDocument(
45
+ outdent`
46
+ openapi: 3.0.0
47
+ info:
48
+ license:
49
+ name: MIT
50
+ url: google.com
51
+ `,
52
+ 'foobar.yaml'
53
+ );
54
+
55
+ const results = await lintDocument({
56
+ externalRefResolver: new BaseResolver(),
57
+ document,
58
+ config: await makeConfig({ 'info-license-url': 'error' }),
59
+ });
60
+
61
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
62
+ });
63
+ });