@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
package/src/bundle.ts ADDED
@@ -0,0 +1,417 @@
1
+ import isEqual = require('lodash.isequal');
2
+ import { BaseResolver, resolveDocument, Document, ResolvedRefMap, makeRefId } from './resolve';
3
+ import { Oas3Rule, normalizeVisitors, Oas3Visitor, Oas2Visitor } from './visitors';
4
+ import { Oas3Types } from './types/oas3';
5
+ import { Oas2Types } from './types/oas2';
6
+ import { Oas3_1Types } from './types/oas3_1';
7
+ import { NormalizedNodeType, normalizeTypes, NodeType } from './types';
8
+ import { WalkContext, walkDocument, UserContext, ResolveResult, NormalizedProblem } from './walk';
9
+ import { detectOpenAPI, openAPIMajor, OasMajorVersion } from './oas-types';
10
+ import { isAbsoluteUrl, isRef, Location, refBaseName } from './ref-utils';
11
+ import { initRules } from './config/rules';
12
+ import { reportUnresolvedRef } from './rules/no-unresolved-refs';
13
+ import { isPlainObject, isTruthy } from './utils';
14
+ import { OasRef } from './typings/openapi';
15
+ import { isRedoclyRegistryURL } from './redocly';
16
+ import { RemoveUnusedComponents as RemoveUnusedComponentsOas2 } from './rules/oas2/remove-unused-components';
17
+ import { RemoveUnusedComponents as RemoveUnusedComponentsOas3 } from './rules/oas3/remove-unused-components';
18
+
19
+ import type { Config, StyleguideConfig } from './config';
20
+
21
+ export type Oas3RuleSet = Record<string, Oas3Rule>;
22
+
23
+ export enum OasVersion {
24
+ Version2 = 'oas2',
25
+ Version3_0 = 'oas3_0',
26
+ Version3_1 = 'oas3_1',
27
+ }
28
+
29
+ export async function bundle(opts: {
30
+ ref?: string;
31
+ doc?: Document;
32
+ externalRefResolver?: BaseResolver;
33
+ config: Config;
34
+ dereference?: boolean;
35
+ base?: string;
36
+ skipRedoclyRegistryRefs?: boolean;
37
+ removeUnusedComponents?: boolean;
38
+ keepUrlRefs?: boolean;
39
+ }) {
40
+ const {
41
+ ref,
42
+ doc,
43
+ externalRefResolver = new BaseResolver(opts.config.resolve),
44
+ base = null,
45
+ } = opts;
46
+ if (!(ref || doc)) {
47
+ throw new Error('Document or reference is required.\n');
48
+ }
49
+
50
+ const document =
51
+ doc !== undefined ? doc : await externalRefResolver.resolveDocument(base, ref!, true);
52
+
53
+ if (document instanceof Error) {
54
+ throw document;
55
+ }
56
+
57
+ return bundleDocument({
58
+ document,
59
+ ...opts,
60
+ config: opts.config.styleguide,
61
+ externalRefResolver,
62
+ });
63
+ }
64
+
65
+ type BundleContext = WalkContext;
66
+
67
+ export type BundleResult = {
68
+ bundle: Document;
69
+ problems: NormalizedProblem[];
70
+ fileDependencies: Set<string>;
71
+ rootType: NormalizedNodeType;
72
+ refTypes?: Map<string, NormalizedNodeType>;
73
+ visitorsData: Record<string, Record<string, unknown>>;
74
+ };
75
+
76
+ export async function bundleDocument(opts: {
77
+ document: Document;
78
+ config: StyleguideConfig;
79
+ customTypes?: Record<string, NodeType>;
80
+ externalRefResolver: BaseResolver;
81
+ dereference?: boolean;
82
+ skipRedoclyRegistryRefs?: boolean;
83
+ removeUnusedComponents?: boolean;
84
+ keepUrlRefs?: boolean;
85
+ }): Promise<BundleResult> {
86
+ const {
87
+ document,
88
+ config,
89
+ customTypes,
90
+ externalRefResolver,
91
+ dereference = false,
92
+ skipRedoclyRegistryRefs = false,
93
+ removeUnusedComponents = false,
94
+ keepUrlRefs = false,
95
+ } = opts;
96
+ const oasVersion = detectOpenAPI(document.parsed);
97
+ const oasMajorVersion = openAPIMajor(oasVersion);
98
+ const rules = config.getRulesForOasVersion(oasMajorVersion);
99
+ const types = normalizeTypes(
100
+ config.extendTypes(
101
+ customTypes ?? oasMajorVersion === OasMajorVersion.Version3
102
+ ? oasVersion === OasVersion.Version3_1
103
+ ? Oas3_1Types
104
+ : Oas3Types
105
+ : Oas2Types,
106
+ oasVersion
107
+ ),
108
+ config
109
+ );
110
+
111
+ const preprocessors = initRules(rules as any, config, 'preprocessors', oasVersion);
112
+ const decorators = initRules(rules as any, config, 'decorators', oasVersion);
113
+
114
+ const ctx: BundleContext = {
115
+ problems: [],
116
+ oasVersion: oasVersion,
117
+ refTypes: new Map<string, NormalizedNodeType>(),
118
+ visitorsData: {},
119
+ };
120
+
121
+ if (removeUnusedComponents) {
122
+ decorators.push({
123
+ severity: 'error',
124
+ ruleId: 'remove-unused-components',
125
+ visitor:
126
+ oasMajorVersion === OasMajorVersion.Version2
127
+ ? RemoveUnusedComponentsOas2({})
128
+ : RemoveUnusedComponentsOas3({}),
129
+ });
130
+ }
131
+
132
+ let resolvedRefMap = await resolveDocument({
133
+ rootDocument: document,
134
+ rootType: types.Root,
135
+ externalRefResolver,
136
+ });
137
+
138
+ if (preprocessors.length > 0) {
139
+ // Make additional pass to resolve refs defined in preprocessors.
140
+ walkDocument({
141
+ document,
142
+ rootType: types.Root as NormalizedNodeType,
143
+ normalizedVisitors: normalizeVisitors(preprocessors, types),
144
+ resolvedRefMap,
145
+ ctx,
146
+ });
147
+ resolvedRefMap = await resolveDocument({
148
+ rootDocument: document,
149
+ rootType: types.Root,
150
+ externalRefResolver,
151
+ });
152
+ }
153
+
154
+ const bundleVisitor = normalizeVisitors(
155
+ [
156
+ {
157
+ severity: 'error',
158
+ ruleId: 'bundler',
159
+ visitor: makeBundleVisitor(
160
+ oasMajorVersion,
161
+ dereference,
162
+ skipRedoclyRegistryRefs,
163
+ document,
164
+ resolvedRefMap,
165
+ keepUrlRefs
166
+ ),
167
+ },
168
+ ...decorators,
169
+ ],
170
+ types
171
+ );
172
+
173
+ walkDocument({
174
+ document,
175
+ rootType: types.Root as NormalizedNodeType,
176
+ normalizedVisitors: bundleVisitor,
177
+ resolvedRefMap,
178
+ ctx,
179
+ });
180
+
181
+ return {
182
+ bundle: document,
183
+ problems: ctx.problems.map((problem) => config.addProblemToIgnore(problem)),
184
+ fileDependencies: externalRefResolver.getFiles(),
185
+ rootType: types.Root,
186
+ refTypes: ctx.refTypes,
187
+ visitorsData: ctx.visitorsData,
188
+ };
189
+ }
190
+
191
+ export function mapTypeToComponent(typeName: string, version: OasMajorVersion) {
192
+ switch (version) {
193
+ case OasMajorVersion.Version3:
194
+ switch (typeName) {
195
+ case 'Schema':
196
+ return 'schemas';
197
+ case 'Parameter':
198
+ return 'parameters';
199
+ case 'Response':
200
+ return 'responses';
201
+ case 'Example':
202
+ return 'examples';
203
+ case 'RequestBody':
204
+ return 'requestBodies';
205
+ case 'Header':
206
+ return 'headers';
207
+ case 'SecuritySchema':
208
+ return 'securitySchemes';
209
+ case 'Link':
210
+ return 'links';
211
+ case 'Callback':
212
+ return 'callbacks';
213
+ default:
214
+ return null;
215
+ }
216
+ case OasMajorVersion.Version2:
217
+ switch (typeName) {
218
+ case 'Schema':
219
+ return 'definitions';
220
+ case 'Parameter':
221
+ return 'parameters';
222
+ case 'Response':
223
+ return 'responses';
224
+ default:
225
+ return null;
226
+ }
227
+ }
228
+ }
229
+
230
+ // function oas3Move
231
+
232
+ function makeBundleVisitor(
233
+ version: OasMajorVersion,
234
+ dereference: boolean,
235
+ skipRedoclyRegistryRefs: boolean,
236
+ rootDocument: Document,
237
+ resolvedRefMap: ResolvedRefMap,
238
+ keepUrlRefs: boolean
239
+ ) {
240
+ let components: Record<string, Record<string, any>>;
241
+ let rootLocation: Location;
242
+
243
+ const visitor: Oas3Visitor | Oas2Visitor = {
244
+ ref: {
245
+ leave(node, ctx, resolved) {
246
+ if (!resolved.location || resolved.node === undefined) {
247
+ reportUnresolvedRef(resolved, ctx.report, ctx.location);
248
+ return;
249
+ }
250
+ if (
251
+ resolved.location.source === rootDocument.source &&
252
+ resolved.location.source === ctx.location.source &&
253
+ ctx.type.name !== 'scalar' &&
254
+ !dereference
255
+ ) {
256
+ return;
257
+ }
258
+
259
+ // do not bundle registry URL before push, otherwise we can't record dependencies
260
+ if (skipRedoclyRegistryRefs && isRedoclyRegistryURL(node.$ref)) {
261
+ return;
262
+ }
263
+
264
+ if (keepUrlRefs && isAbsoluteUrl(node.$ref)) {
265
+ return;
266
+ }
267
+
268
+ const componentType = mapTypeToComponent(ctx.type.name, version);
269
+ if (!componentType) {
270
+ replaceRef(node, resolved, ctx);
271
+ } else {
272
+ if (dereference) {
273
+ saveComponent(componentType, resolved, ctx);
274
+ replaceRef(node, resolved, ctx);
275
+ } else {
276
+ node.$ref = saveComponent(componentType, resolved, ctx);
277
+ resolveBundledComponent(node, resolved, ctx);
278
+ }
279
+ }
280
+ },
281
+ },
282
+ Root: {
283
+ enter(root: any, ctx: any) {
284
+ rootLocation = ctx.location;
285
+ if (version === OasMajorVersion.Version3) {
286
+ components = root.components = root.components || {};
287
+ } else if (version === OasMajorVersion.Version2) {
288
+ components = root;
289
+ }
290
+ },
291
+ },
292
+ };
293
+
294
+ if (version === OasMajorVersion.Version3) {
295
+ visitor.DiscriminatorMapping = {
296
+ leave(mapping: Record<string, string>, ctx: any) {
297
+ for (const name of Object.keys(mapping)) {
298
+ const $ref = mapping[name];
299
+ const resolved = ctx.resolve({ $ref });
300
+ if (!resolved.location || resolved.node === undefined) {
301
+ reportUnresolvedRef(resolved, ctx.report, ctx.location.child(name));
302
+ return;
303
+ }
304
+
305
+ const componentType = mapTypeToComponent('Schema', version)!;
306
+ if (dereference) {
307
+ saveComponent(componentType, resolved, ctx);
308
+ } else {
309
+ mapping[name] = saveComponent(componentType, resolved, ctx);
310
+ }
311
+ }
312
+ },
313
+ };
314
+ }
315
+
316
+ function resolveBundledComponent(node: OasRef, resolved: ResolveResult<any>, ctx: UserContext) {
317
+ const newRefId = makeRefId(ctx.location.source.absoluteRef, node.$ref);
318
+ resolvedRefMap.set(newRefId, {
319
+ document: rootDocument,
320
+ isRemote: false,
321
+ node: resolved.node,
322
+ nodePointer: node.$ref,
323
+ resolved: true,
324
+ });
325
+ }
326
+
327
+ function replaceRef(ref: OasRef, resolved: ResolveResult<any>, ctx: UserContext) {
328
+ if (!isPlainObject(resolved.node)) {
329
+ ctx.parent[ctx.key] = resolved.node;
330
+ } else {
331
+ // TODO: why $ref isn't optional in OasRef?
332
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
333
+ // @ts-ignore
334
+ delete ref.$ref;
335
+ const obj = Object.assign({}, resolved.node, ref);
336
+ Object.assign(ref, obj); // assign ref itself again so ref fields take precedence
337
+ }
338
+ }
339
+
340
+ function saveComponent(
341
+ componentType: string,
342
+ target: { node: any; location: Location },
343
+ ctx: UserContext
344
+ ) {
345
+ components[componentType] = components[componentType] || {};
346
+ const name = getComponentName(target, componentType, ctx);
347
+ components[componentType][name] = target.node;
348
+ if (version === OasMajorVersion.Version3) {
349
+ return `#/components/${componentType}/${name}`;
350
+ } else {
351
+ return `#/${componentType}/${name}`;
352
+ }
353
+ }
354
+
355
+ function isEqualOrEqualRef(
356
+ node: any,
357
+ target: { node: any; location: Location },
358
+ ctx: UserContext
359
+ ) {
360
+ if (
361
+ isRef(node) &&
362
+ ctx.resolve(node, rootLocation.absolutePointer).location?.absolutePointer ===
363
+ target.location.absolutePointer
364
+ ) {
365
+ return true;
366
+ }
367
+
368
+ return isEqual(node, target.node);
369
+ }
370
+
371
+ function getComponentName(
372
+ target: { node: any; location: Location },
373
+ componentType: string,
374
+ ctx: UserContext
375
+ ) {
376
+ const [fileRef, pointer] = [target.location.source.absoluteRef, target.location.pointer];
377
+ const componentsGroup = components[componentType];
378
+
379
+ let name = '';
380
+
381
+ const refParts = pointer.slice(2).split('/').filter(isTruthy); // slice(2) removes "#/"
382
+ while (refParts.length > 0) {
383
+ name = refParts.pop() + (name ? `-${name}` : '');
384
+ if (
385
+ !componentsGroup ||
386
+ !componentsGroup[name] ||
387
+ isEqualOrEqualRef(componentsGroup[name], target, ctx)
388
+ ) {
389
+ return name;
390
+ }
391
+ }
392
+
393
+ name = refBaseName(fileRef) + (name ? `_${name}` : '');
394
+ if (!componentsGroup[name] || isEqualOrEqualRef(componentsGroup[name], target, ctx)) {
395
+ return name;
396
+ }
397
+
398
+ const prevName = name;
399
+ let serialId = 2;
400
+ while (componentsGroup[name] && !isEqualOrEqualRef(componentsGroup[name], target, ctx)) {
401
+ name = `${prevName}-${serialId}`;
402
+ serialId++;
403
+ }
404
+
405
+ if (!componentsGroup[name]) {
406
+ ctx.report({
407
+ message: `Two schemas are referenced with the same name but different content. Renamed ${prevName} to ${name}.`,
408
+ location: ctx.location,
409
+ forceSeverity: 'warn',
410
+ });
411
+ }
412
+
413
+ return name;
414
+ }
415
+
416
+ return visitor;
417
+ }
@@ -0,0 +1,164 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`resolveConfig should ignore minimal from the root and read local file 1`] = `
4
+ Object {
5
+ "decorators": Object {},
6
+ "doNotResolveExamples": undefined,
7
+ "oas2Decorators": Object {},
8
+ "oas2Preprocessors": Object {},
9
+ "oas2Rules": Object {},
10
+ "oas3_0Decorators": Object {},
11
+ "oas3_0Preprocessors": Object {},
12
+ "oas3_0Rules": Object {
13
+ "no-empty-servers": "error",
14
+ "no-example-value-and-externalValue": "error",
15
+ "no-invalid-media-type-examples": "error",
16
+ "no-server-example.com": "warn",
17
+ "no-server-trailing-slash": "error",
18
+ "no-server-variables-empty-enum": "error",
19
+ "no-undefined-server-variable": "error",
20
+ "no-unused-components": "warn",
21
+ "spec-components-invalid-map-name": "error",
22
+ },
23
+ "oas3_1Decorators": Object {},
24
+ "oas3_1Preprocessors": Object {},
25
+ "oas3_1Rules": Object {
26
+ "no-empty-servers": "error",
27
+ "no-example-value-and-externalValue": "error",
28
+ "no-invalid-media-type-examples": "error",
29
+ "no-server-example.com": "warn",
30
+ "no-server-trailing-slash": "error",
31
+ "no-server-variables-empty-enum": "error",
32
+ "no-undefined-server-variable": "error",
33
+ "no-unused-components": "warn",
34
+ "spec-components-invalid-map-name": "error",
35
+ },
36
+ "preprocessors": Object {},
37
+ "recommendedFallback": false,
38
+ "rules": Object {
39
+ "boolean-parameter-prefixes": "error",
40
+ "component-name-unique": "off",
41
+ "info-contact": "off",
42
+ "info-license": "warn",
43
+ "info-license-url": "warn",
44
+ "local/operation-id-not-test": "error",
45
+ "no-ambiguous-paths": "warn",
46
+ "no-enum-type-mismatch": "error",
47
+ "no-identical-paths": "error",
48
+ "no-invalid-media-type-examples": "error",
49
+ "no-path-trailing-slash": "error",
50
+ "no-unresolved-refs": "error",
51
+ "operation-2xx-response": "warn",
52
+ "operation-4xx-response": "error",
53
+ "operation-description": "error",
54
+ "operation-operationId": "warn",
55
+ "operation-operationId-unique": "error",
56
+ "operation-operationId-url-safe": "error",
57
+ "operation-parameters-unique": "error",
58
+ "operation-singular-tag": "off",
59
+ "operation-summary": "error",
60
+ "operation-tag-defined": "off",
61
+ "parameter-description": "off",
62
+ "path-declaration-must-exist": "error",
63
+ "path-http-verbs-order": "error",
64
+ "path-not-include-query": "error",
65
+ "path-parameters-defined": "error",
66
+ "paths-kebab-case": "off",
67
+ "security-defined": "error",
68
+ "spec": "error",
69
+ "spec-strict-refs": "off",
70
+ "tag-description": "warn",
71
+ "tags-alphabetical": "off",
72
+ },
73
+ }
74
+ `;
75
+
76
+ exports[`resolveStyleguideConfig should resolve extends with local file config which contains path to nested config 1`] = `
77
+ Object {
78
+ "decorators": Object {},
79
+ "doNotResolveExamples": undefined,
80
+ "oas2Decorators": Object {},
81
+ "oas2Preprocessors": Object {},
82
+ "oas2Rules": Object {},
83
+ "oas3_0Decorators": Object {},
84
+ "oas3_0Preprocessors": Object {},
85
+ "oas3_0Rules": Object {
86
+ "no-empty-servers": "error",
87
+ "no-example-value-and-externalValue": "error",
88
+ "no-invalid-media-type-examples": "warn",
89
+ "no-server-example.com": "warn",
90
+ "no-server-trailing-slash": "error",
91
+ "no-server-variables-empty-enum": "error",
92
+ "no-undefined-server-variable": "error",
93
+ "no-unused-components": "warn",
94
+ "spec-components-invalid-map-name": "error",
95
+ },
96
+ "oas3_1Decorators": Object {},
97
+ "oas3_1Preprocessors": Object {},
98
+ "oas3_1Rules": Object {
99
+ "no-empty-servers": "error",
100
+ "no-example-value-and-externalValue": "error",
101
+ "no-invalid-media-type-examples": "warn",
102
+ "no-server-example.com": "warn",
103
+ "no-server-trailing-slash": "error",
104
+ "no-server-variables-empty-enum": "error",
105
+ "no-undefined-server-variable": "error",
106
+ "no-unused-components": "warn",
107
+ "spec-components-invalid-map-name": "error",
108
+ },
109
+ "preprocessors": Object {},
110
+ "recommendedFallback": undefined,
111
+ "rules": Object {
112
+ "assertions": Array [
113
+ Object {
114
+ "assertionId": "rule/path-item-get-defined",
115
+ "defined": true,
116
+ "message": "Every path item must have a GET operation.",
117
+ "property": "get",
118
+ "subject": "PathItem",
119
+ },
120
+ Object {
121
+ "assertionId": "rule/tag-description",
122
+ "message": "Tag description must be at least 13 characters and end with a full stop.",
123
+ "minLength": 13,
124
+ "pattern": "/\\\\.$/",
125
+ "property": "description",
126
+ "severity": "error",
127
+ "subject": "Tag",
128
+ },
129
+ ],
130
+ "boolean-parameter-prefixes": "error",
131
+ "component-name-unique": "off",
132
+ "info-contact": "off",
133
+ "info-license": "warn",
134
+ "info-license-url": "warn",
135
+ "local/operation-id-not-test": "error",
136
+ "no-ambiguous-paths": "warn",
137
+ "no-enum-type-mismatch": "error",
138
+ "no-identical-paths": "error",
139
+ "no-invalid-media-type-examples": "warn",
140
+ "no-path-trailing-slash": "error",
141
+ "no-unresolved-refs": "error",
142
+ "operation-2xx-response": "error",
143
+ "operation-4xx-response": "off",
144
+ "operation-description": "off",
145
+ "operation-operationId": "warn",
146
+ "operation-operationId-unique": "error",
147
+ "operation-operationId-url-safe": "error",
148
+ "operation-parameters-unique": "error",
149
+ "operation-singular-tag": "off",
150
+ "operation-summary": "error",
151
+ "operation-tag-defined": "off",
152
+ "parameter-description": "off",
153
+ "path-declaration-must-exist": "error",
154
+ "path-not-include-query": "error",
155
+ "path-parameters-defined": "error",
156
+ "paths-kebab-case": "off",
157
+ "security-defined": "error",
158
+ "spec": "error",
159
+ "spec-strict-refs": "off",
160
+ "tag-description": "warn",
161
+ "tags-alphabetical": "off",
162
+ },
163
+ }
164
+ `;