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

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 (240) hide show
  1. package/README.md +4 -4
  2. package/__tests__/utils.ts +5 -5
  3. package/lib/benchmark/benches/lint-with-top-level-rule-report.bench.js +0 -1
  4. package/lib/benchmark/benches/recommended-oas3.bench.js +1 -1
  5. package/lib/benchmark/utils.d.ts +2 -2
  6. package/lib/benchmark/utils.js +2 -2
  7. package/lib/bundle.d.ts +2 -2
  8. package/lib/bundle.js +7 -4
  9. package/lib/config/all.d.ts +2 -2
  10. package/lib/config/all.js +3 -3
  11. package/lib/config/builtIn.d.ts +2 -2
  12. package/lib/config/builtIn.js +2 -2
  13. package/lib/config/config-resolvers.d.ts +5 -5
  14. package/lib/config/config-resolvers.js +70 -49
  15. package/lib/config/config.d.ts +8 -10
  16. package/lib/config/config.js +10 -7
  17. package/lib/config/load.d.ts +7 -0
  18. package/lib/config/load.js +18 -10
  19. package/lib/config/minimal.d.ts +2 -2
  20. package/lib/config/minimal.js +5 -4
  21. package/lib/config/recommended.d.ts +2 -2
  22. package/lib/config/recommended.js +5 -4
  23. package/lib/config/rules.d.ts +3 -3
  24. package/lib/config/rules.js +1 -1
  25. package/lib/config/types.d.ts +23 -19
  26. package/lib/config/utils.d.ts +5 -5
  27. package/lib/config/utils.js +48 -31
  28. package/lib/decorators/common/registry-dependencies.js +1 -1
  29. package/lib/decorators/common/remove-x-internal.js +2 -2
  30. package/lib/env.d.ts +3 -0
  31. package/lib/env.js +8 -0
  32. package/lib/format/codeframes.js +16 -10
  33. package/lib/format/format.js +29 -27
  34. package/lib/index.d.ts +5 -5
  35. package/lib/index.js +4 -2
  36. package/lib/js-yaml/index.js +2 -6
  37. package/lib/lint.d.ts +2 -2
  38. package/lib/lint.js +16 -6
  39. package/lib/logger.d.ts +10 -0
  40. package/lib/logger.js +31 -0
  41. package/lib/output.d.ts +3 -0
  42. package/lib/output.js +9 -0
  43. package/lib/redocly/index.js +10 -9
  44. package/lib/redocly/registry-api-types.d.ts +28 -30
  45. package/lib/redocly/registry-api.d.ts +4 -3
  46. package/lib/redocly/registry-api.js +9 -4
  47. package/lib/ref-utils.js +2 -1
  48. package/lib/resolve.d.ts +1 -1
  49. package/lib/resolve.js +1 -1
  50. package/lib/rules/ajv.d.ts +1 -1
  51. package/lib/rules/ajv.js +7 -7
  52. package/lib/rules/common/assertions/asserts.js +4 -4
  53. package/lib/rules/common/assertions/index.js +1 -1
  54. package/lib/rules/common/info-license-url.d.ts +1 -1
  55. package/lib/rules/common/info-license-url.js +5 -10
  56. package/lib/rules/common/info-license.d.ts +2 -0
  57. package/lib/rules/common/info-license.js +17 -0
  58. package/lib/rules/common/no-enum-type-mismatch.js +1 -3
  59. package/lib/rules/common/no-invalid-parameter-examples.js +3 -3
  60. package/lib/rules/common/no-invalid-schema-examples.js +3 -3
  61. package/lib/rules/common/operation-operationId.js +1 -1
  62. package/lib/rules/common/operation-security-defined.js +1 -1
  63. package/lib/rules/common/path-not-include-query.js +1 -1
  64. package/lib/rules/common/paths-kebab-case.js +4 -1
  65. package/lib/rules/common/spec.js +3 -3
  66. package/lib/rules/oas2/index.js +4 -4
  67. package/lib/rules/oas2/remove-unused-components.js +5 -5
  68. package/lib/rules/oas3/index.js +6 -6
  69. package/lib/rules/oas3/no-empty-servers.js +1 -1
  70. package/lib/rules/oas3/no-invalid-media-type-examples.js +2 -2
  71. package/lib/rules/oas3/no-server-variables-empty-enum.d.ts +2 -0
  72. package/lib/rules/oas3/{no-servers-empty-enum.js → no-server-variables-empty-enum.js} +4 -4
  73. package/lib/rules/oas3/no-unused-components.js +1 -1
  74. package/lib/rules/oas3/remove-unused-components.js +5 -5
  75. package/lib/rules/other/stats.js +43 -14
  76. package/lib/rules/utils.d.ts +3 -2
  77. package/lib/rules/utils.js +20 -5
  78. package/lib/types/index.d.ts +2 -2
  79. package/lib/types/redocly-yaml.js +9 -8
  80. package/lib/utils.d.ts +5 -0
  81. package/lib/utils.js +22 -5
  82. package/lib/visitors.d.ts +1 -1
  83. package/lib/visitors.js +2 -2
  84. package/lib/walk.d.ts +2 -1
  85. package/lib/walk.js +6 -3
  86. package/package.json +2 -2
  87. package/src/__tests__/__snapshots__/bundle.test.ts.snap +141 -0
  88. package/src/__tests__/bundle.test.ts +68 -34
  89. package/src/__tests__/codeframes.test.ts +13 -14
  90. package/src/__tests__/js-yaml.test.ts +6 -4
  91. package/src/__tests__/lint.test.ts +74 -6
  92. package/src/__tests__/logger-browser.test.ts +53 -0
  93. package/src/__tests__/logger.test.ts +47 -0
  94. package/src/__tests__/login.test.ts +2 -2
  95. package/src/__tests__/normalizeVisitors.test.ts +4 -4
  96. package/src/__tests__/output-browser.test.ts +18 -0
  97. package/src/__tests__/output.test.ts +15 -0
  98. package/src/__tests__/ref-utils.test.ts +13 -13
  99. package/src/__tests__/resolve-http.test.ts +1 -1
  100. package/src/__tests__/resolve.test.ts +14 -11
  101. package/src/__tests__/utils-browser.test.ts +11 -0
  102. package/src/__tests__/utils.test.ts +7 -0
  103. package/src/__tests__/walk.test.ts +48 -56
  104. package/src/benchmark/benches/lint-with-many-rules.bench.ts +1 -1
  105. package/src/benchmark/benches/lint-with-nested-rule.bench.ts +1 -1
  106. package/src/benchmark/benches/lint-with-no-rules.bench.ts +1 -1
  107. package/src/benchmark/benches/lint-with-top-level-rule-report.bench.ts +1 -2
  108. package/src/benchmark/benches/lint-with-top-level-rule.bench.ts +1 -1
  109. package/src/benchmark/benches/recommended-oas3.bench.ts +3 -3
  110. package/src/benchmark/benches/resolve-with-no-external.bench.ts +1 -1
  111. package/src/benchmark/benchmark.js +9 -5
  112. package/src/benchmark/utils.ts +5 -5
  113. package/src/bundle.ts +24 -20
  114. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +7 -5
  115. package/src/config/__tests__/config-resolvers.test.ts +123 -121
  116. package/src/config/__tests__/config.test.ts +111 -76
  117. package/src/config/__tests__/fixtures/resolve-config/api/plugin.js +4 -2
  118. package/src/config/__tests__/fixtures/resolve-config/plugin.js +4 -1
  119. package/src/config/__tests__/load.test.ts +79 -1
  120. package/src/config/__tests__/resolve-plugins.test.ts +3 -3
  121. package/src/config/__tests__/utils.test.ts +83 -0
  122. package/src/config/all.ts +5 -6
  123. package/src/config/builtIn.ts +5 -5
  124. package/src/config/config-resolvers.ts +161 -96
  125. package/src/config/config.ts +15 -13
  126. package/src/config/load.ts +34 -11
  127. package/src/config/minimal.ts +7 -6
  128. package/src/config/recommended.ts +7 -6
  129. package/src/config/rules.ts +6 -6
  130. package/src/config/types.ts +28 -19
  131. package/src/config/utils.ts +78 -57
  132. package/src/decorators/__tests__/filter-out.test.ts +8 -4
  133. package/src/decorators/__tests__/remove-x-internal.test.ts +5 -5
  134. package/src/decorators/common/filters/filter-helper.ts +1 -1
  135. package/src/decorators/common/info-description-override.ts +1 -1
  136. package/src/decorators/common/operation-description-override.ts +1 -1
  137. package/src/decorators/common/registry-dependencies.ts +1 -1
  138. package/src/decorators/common/remove-x-internal.ts +4 -4
  139. package/src/decorators/common/tag-description-override.ts +1 -1
  140. package/src/env.ts +5 -0
  141. package/src/format/codeframes.ts +18 -12
  142. package/src/format/format.ts +37 -42
  143. package/src/index.ts +8 -7
  144. package/src/js-yaml/index.ts +4 -8
  145. package/src/lint.ts +22 -18
  146. package/src/logger.ts +34 -0
  147. package/src/oas-types.ts +1 -6
  148. package/src/output.ts +7 -0
  149. package/src/redocly/__tests__/redocly-client.test.ts +25 -19
  150. package/src/redocly/index.ts +12 -7
  151. package/src/redocly/registry-api-types.ts +27 -29
  152. package/src/redocly/registry-api.ts +22 -12
  153. package/src/ref-utils.ts +4 -3
  154. package/src/resolve.ts +11 -8
  155. package/src/rules/__tests__/no-unresolved-refs.test.ts +4 -4
  156. package/src/rules/__tests__/utils.test.ts +160 -0
  157. package/src/rules/ajv.ts +7 -8
  158. package/src/rules/common/__tests__/info-description.test.ts +3 -3
  159. package/src/rules/common/__tests__/info-license.test.ts +2 -2
  160. package/src/rules/common/__tests__/license-url.test.ts +2 -2
  161. package/src/rules/common/__tests__/no-ambiguous-paths.test.ts +1 -1
  162. package/src/rules/common/__tests__/no-enum-type-mismatch.test.ts +8 -8
  163. package/src/rules/common/__tests__/no-identical-paths.test.ts +1 -1
  164. package/src/rules/common/__tests__/no-path-trailing-slash.test.ts +3 -3
  165. package/src/rules/common/__tests__/operation-2xx-response.test.ts +3 -3
  166. package/src/rules/common/__tests__/operation-4xx-response.test.ts +3 -3
  167. package/src/rules/common/__tests__/operation-operationId-unique.test.ts +2 -2
  168. package/src/rules/common/__tests__/operation-operationId-url-safe.test.ts +1 -1
  169. package/src/rules/common/__tests__/operation-parameters-unique.test.ts +4 -4
  170. package/src/rules/common/__tests__/operation-security-defined.test.ts +2 -2
  171. package/src/rules/common/__tests__/operation-singular-tag.test.ts +2 -2
  172. package/src/rules/common/__tests__/path-http-verbs-order.test.ts +2 -2
  173. package/src/rules/common/__tests__/path-not-include-query.test.ts +2 -2
  174. package/src/rules/common/__tests__/path-params-defined.test.ts +3 -3
  175. package/src/rules/common/__tests__/paths-kebab-case.test.ts +15 -15
  176. package/src/rules/common/__tests__/scalar-property-missing-example.test.ts +8 -8
  177. package/src/rules/common/__tests__/spec.test.ts +2 -2
  178. package/src/rules/common/__tests__/tag-description.test.ts +2 -2
  179. package/src/rules/common/__tests__/tags-alphabetical.test.ts +2 -2
  180. package/src/rules/common/assertions/__tests__/asserts.test.ts +513 -130
  181. package/src/rules/common/assertions/asserts.ts +4 -4
  182. package/src/rules/common/assertions/index.ts +7 -7
  183. package/src/rules/common/info-license-url.ts +4 -9
  184. package/src/rules/common/info-license.ts +15 -0
  185. package/src/rules/common/no-ambiguous-paths.ts +1 -1
  186. package/src/rules/common/no-enum-type-mismatch.ts +12 -9
  187. package/src/rules/common/no-invalid-parameter-examples.ts +4 -4
  188. package/src/rules/common/no-invalid-schema-examples.ts +4 -4
  189. package/src/rules/common/operation-operationId.ts +1 -1
  190. package/src/rules/common/operation-parameters-unique.ts +2 -2
  191. package/src/rules/common/operation-security-defined.ts +1 -1
  192. package/src/rules/common/path-not-include-query.ts +1 -1
  193. package/src/rules/common/path-params-defined.ts +1 -1
  194. package/src/rules/common/paths-kebab-case.ts +4 -1
  195. package/src/rules/common/scalar-property-missing-example.ts +1 -1
  196. package/src/rules/common/spec.ts +12 -9
  197. package/src/rules/no-unresolved-refs.ts +1 -1
  198. package/src/rules/oas2/__tests__/boolean-parameter-prefixes.test.ts +3 -3
  199. package/src/rules/oas2/__tests__/spec/info.test.ts +12 -12
  200. package/src/rules/oas2/__tests__/spec/operation.test.ts +4 -4
  201. package/src/rules/oas2/__tests__/spec/paths.test.ts +10 -10
  202. package/src/rules/oas2/__tests__/spec/referenceableScalars.test.ts +6 -2
  203. package/src/rules/oas2/__tests__/spec/utils.ts +6 -6
  204. package/src/rules/oas2/index.ts +3 -3
  205. package/src/rules/oas2/remove-unused-components.ts +14 -9
  206. package/src/rules/oas3/__tests__/boolean-parameter-prefixes.test.ts +3 -3
  207. package/src/rules/oas3/__tests__/no-empty-enum-servers.com.test.ts +16 -16
  208. package/src/rules/oas3/__tests__/no-example-value-and-externalValue.test.ts +2 -2
  209. package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +13 -13
  210. package/src/rules/oas3/__tests__/no-server-example.com.test.ts +2 -2
  211. package/src/rules/oas3/__tests__/no-server-trailing-slash.test.ts +3 -3
  212. package/src/rules/oas3/__tests__/no-unused-components.test.ts +1 -1
  213. package/src/rules/oas3/__tests__/spec/callbacks.test.ts +1 -1
  214. package/src/rules/oas3/__tests__/spec/info.test.ts +12 -12
  215. package/src/rules/oas3/__tests__/spec/operation.test.ts +8 -8
  216. package/src/rules/oas3/__tests__/spec/paths.test.ts +10 -10
  217. package/src/rules/oas3/__tests__/spec/referenceableScalars.test.ts +12 -12
  218. package/src/rules/oas3/__tests__/spec/servers.test.ts +15 -15
  219. package/src/rules/oas3/__tests__/spec/spec.test.ts +6 -6
  220. package/src/rules/oas3/__tests__/spec/utils.ts +6 -6
  221. package/src/rules/oas3/index.ts +5 -5
  222. package/src/rules/oas3/no-empty-servers.ts +1 -1
  223. package/src/rules/oas3/no-invalid-media-type-examples.ts +14 -6
  224. package/src/rules/oas3/{no-servers-empty-enum.ts → no-server-variables-empty-enum.ts} +10 -11
  225. package/src/rules/oas3/no-unused-components.ts +1 -1
  226. package/src/rules/oas3/remove-unused-components.ts +21 -10
  227. package/src/rules/other/stats.ts +46 -17
  228. package/src/rules/utils.ts +20 -4
  229. package/src/types/index.ts +5 -5
  230. package/src/types/redocly-yaml.ts +9 -8
  231. package/src/typings/common.ts +9 -1
  232. package/src/typings/openapi.ts +1 -1
  233. package/src/utils.ts +26 -3
  234. package/src/visitors.ts +9 -9
  235. package/src/walk.ts +15 -11
  236. package/tsconfig.tsbuildinfo +1 -1
  237. package/lib/rules/common/license-url.d.ts +0 -2
  238. package/lib/rules/common/license-url.js +0 -12
  239. package/lib/rules/oas3/no-servers-empty-enum.d.ts +0 -2
  240. package/src/rules/common/license-url.ts +0 -10
@@ -1,5 +1,4 @@
1
1
  import * as path from 'path';
2
- import { blue, red } from 'colorette';
3
2
  import { isAbsoluteUrl } from '../ref-utils';
4
3
  import { BaseResolver } from '../resolve';
5
4
  import { defaultPlugin } from './builtIn';
@@ -12,28 +11,32 @@ import {
12
11
  transformConfig,
13
12
  } from './utils';
14
13
  import type {
15
- LintRawConfig,
14
+ StyleguideRawConfig,
15
+ ApiStyleguideRawConfig,
16
16
  Plugin,
17
17
  RawConfig,
18
18
  ResolvedApi,
19
- ResolvedLintConfig,
19
+ ResolvedStyleguideConfig,
20
20
  RuleConfig,
21
+ DeprecatedInRawConfig,
21
22
  } from './types';
23
+ import { isBrowser } from '../env';
22
24
  import { isNotString, isString, notUndefined, parseYaml } from '../utils';
23
25
  import { Config } from './config';
26
+ import { colorize, logger } from '../logger';
24
27
 
25
- export async function resolveConfig(rawConfig: RawConfig, configPath?: string) {
26
- if (rawConfig.lint?.extends?.some(isNotString)) {
28
+ export async function resolveConfig(rawConfig: RawConfig, configPath?: string): Promise<Config> {
29
+ if (rawConfig.styleguide?.extends?.some(isNotString)) {
27
30
  throw new Error(
28
- `Error configuration format not detected in extends value must contain strings`,
31
+ `Error configuration format not detected in extends value must contain strings`
29
32
  );
30
33
  }
31
34
 
32
35
  const resolver = new BaseResolver(getResolveConfig(rawConfig.resolve));
33
- const configExtends = rawConfig?.lint?.extends ?? ['recommended'];
34
- const recommendedFallback = !rawConfig?.lint?.extends;
35
- const lintConfig = {
36
- ...rawConfig?.lint,
36
+ const configExtends = rawConfig?.styleguide?.extends ?? ['recommended'];
37
+ const recommendedFallback = !rawConfig?.styleguide?.extends;
38
+ const styleguideConfig = {
39
+ ...rawConfig?.styleguide,
37
40
  extends: configExtends,
38
41
  recommendedFallback,
39
42
  };
@@ -41,14 +44,14 @@ export async function resolveConfig(rawConfig: RawConfig, configPath?: string) {
41
44
  const apis = await resolveApis({
42
45
  rawConfig: {
43
46
  ...rawConfig,
44
- lint: lintConfig,
47
+ styleguide: styleguideConfig,
45
48
  },
46
49
  configPath,
47
50
  resolver,
48
51
  });
49
52
 
50
- const lint = await resolveLint({
51
- lintConfig,
53
+ const styleguide = await resolveStyleguideConfig({
54
+ styleguideConfig,
52
55
  configPath,
53
56
  resolver,
54
57
  });
@@ -57,47 +60,70 @@ export async function resolveConfig(rawConfig: RawConfig, configPath?: string) {
57
60
  {
58
61
  ...rawConfig,
59
62
  apis,
60
- lint,
63
+ styleguide,
61
64
  },
62
- configPath,
65
+ configPath
63
66
  );
64
67
  }
65
68
 
66
69
  export function resolvePlugins(
67
70
  plugins: (string | Plugin)[] | null,
68
- configPath: string = '',
71
+ configPath: string = ''
69
72
  ): Plugin[] {
70
73
  if (!plugins) return [];
71
74
 
72
- // @ts-ignore
73
- const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require;
75
+ // TODO: implement or reuse Resolver approach so it will work in node and browser envs
76
+ const requireFunc = (plugin: string | Plugin): Plugin | undefined => {
77
+ if (isBrowser && isString(plugin)) {
78
+ logger.error(`Cannot load ${plugin}. Plugins aren't supported in browser yet.`);
79
+
80
+ return undefined;
81
+ }
82
+
83
+ if (isString(plugin)) {
84
+ const absoltePluginPath = path.resolve(path.dirname(configPath), plugin);
85
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
86
+ // @ts-ignore
87
+ return typeof __webpack_require__ === 'function'
88
+ ? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
89
+ // @ts-ignore
90
+ __non_webpack_require__(absoltePluginPath)
91
+ : require(absoltePluginPath);
92
+ }
93
+
94
+ return plugin;
95
+ };
74
96
 
75
97
  const seenPluginIds = new Map<string, string>();
76
98
 
77
99
  return plugins
78
100
  .map((p) => {
79
101
  if (isString(p) && isAbsoluteUrl(p)) {
80
- throw new Error(red(`We don't support remote plugins yet.`));
102
+ throw new Error(colorize.red(`We don't support remote plugins yet.`));
81
103
  }
82
104
 
83
105
  // TODO: resolve npm packages similar to eslint
84
- const pluginModule = isString(p)
85
- ? (requireFunc(path.resolve(path.dirname(configPath), p)) as Plugin)
86
- : p;
106
+ const pluginModule = requireFunc(p);
107
+
108
+ if (!pluginModule) {
109
+ return;
110
+ }
87
111
 
88
112
  const id = pluginModule.id;
89
113
  if (typeof id !== 'string') {
90
- throw new Error(red(`Plugin must define \`id\` property in ${blue(p.toString())}.`));
114
+ throw new Error(
115
+ colorize.red(`Plugin must define \`id\` property in ${colorize.blue(p.toString())}.`)
116
+ );
91
117
  }
92
118
 
93
119
  if (seenPluginIds.has(id)) {
94
120
  const pluginPath = seenPluginIds.get(id)!;
95
121
  throw new Error(
96
- red(
97
- `Plugin "id" must be unique. Plugin ${blue(p.toString())} uses id "${blue(
98
- id,
99
- )}" already seen in ${blue(pluginPath)}`,
100
- ),
122
+ colorize.red(
123
+ `Plugin "id" must be unique. Plugin ${colorize.blue(
124
+ p.toString()
125
+ )} uses id "${colorize.blue(id)}" already seen in ${colorize.blue(pluginPath)}`
126
+ )
101
127
  );
102
128
  }
103
129
 
@@ -124,7 +150,7 @@ export function resolvePlugins(
124
150
  if (pluginModule.preprocessors) {
125
151
  if (!pluginModule.preprocessors.oas3 && !pluginModule.preprocessors.oas2) {
126
152
  throw new Error(
127
- `Plugin \`preprocessors\` must have \`oas3\` or \`oas2\` preprocessors "${p}.`,
153
+ `Plugin \`preprocessors\` must have \`oas3\` or \`oas2\` preprocessors "${p}.`
128
154
  );
129
155
  }
130
156
  plugin.preprocessors = {};
@@ -163,45 +189,48 @@ export async function resolveApis({
163
189
  configPath?: string;
164
190
  resolver?: BaseResolver;
165
191
  }): Promise<Record<string, ResolvedApi>> {
166
- const { apis = {}, lint: lintConfig = {} } = rawConfig;
167
- let resolvedApis: Record<string, ResolvedApi> = {};
192
+ const { apis = {}, styleguide: styleguideConfig = {} } = rawConfig;
193
+ const resolvedApis: Record<string, ResolvedApi> = {};
168
194
  for (const [apiName, apiContent] of Object.entries(apis || {})) {
169
- if (apiContent.lint?.extends?.some(isNotString)) {
195
+ if (apiContent.styleguide?.extends?.some(isNotString)) {
170
196
  throw new Error(
171
- `Error configuration format not detected in extends value must contain strings`,
197
+ `Error configuration format not detected in extends value must contain strings`
172
198
  );
173
199
  }
174
- const rawLintConfig = getMergedLintRawConfig(lintConfig, apiContent.lint);
175
- const apiLint = await resolveLint({
176
- lintConfig: rawLintConfig,
200
+ const rawStyleguideConfig = getMergedRawStyleguideConfig(
201
+ styleguideConfig,
202
+ apiContent.styleguide
203
+ );
204
+ const resolvedApiConfig = await resolveStyleguideConfig({
205
+ styleguideConfig: rawStyleguideConfig,
177
206
  configPath,
178
207
  resolver,
179
208
  });
180
- resolvedApis[apiName] = { ...apiContent, lint: apiLint };
209
+ resolvedApis[apiName] = { ...apiContent, styleguide: resolvedApiConfig };
181
210
  }
182
211
  return resolvedApis;
183
212
  }
184
213
 
185
- async function resolveAndMergeNestedLint(
214
+ async function resolveAndMergeNestedStyleguideConfig(
186
215
  {
187
- lintConfig,
216
+ styleguideConfig,
188
217
  configPath = '',
189
218
  resolver = new BaseResolver(),
190
219
  }: {
191
- lintConfig?: LintRawConfig;
220
+ styleguideConfig?: StyleguideRawConfig;
192
221
  configPath?: string;
193
222
  resolver?: BaseResolver;
194
223
  },
195
224
  parentConfigPaths: string[] = [],
196
- extendPaths: string[] = [],
197
- ): Promise<ResolvedLintConfig> {
225
+ extendPaths: string[] = []
226
+ ): Promise<ResolvedStyleguideConfig> {
198
227
  if (parentConfigPaths.includes(configPath)) {
199
228
  throw new Error(`Circular dependency in config file: "${configPath}"`);
200
229
  }
201
230
  const plugins = getUniquePlugins(
202
- resolvePlugins([...(lintConfig?.plugins || []), defaultPlugin], configPath),
231
+ resolvePlugins([...(styleguideConfig?.plugins || []), defaultPlugin], configPath)
203
232
  );
204
- const pluginPaths = lintConfig?.plugins
233
+ const pluginPaths = styleguideConfig?.plugins
205
234
  ?.filter(isString)
206
235
  .map((p) => path.resolve(path.dirname(configPath), p));
207
236
 
@@ -209,8 +238,8 @@ async function resolveAndMergeNestedLint(
209
238
  ? configPath
210
239
  : configPath && path.resolve(configPath);
211
240
 
212
- const extendConfigs: ResolvedLintConfig[] = await Promise.all(
213
- lintConfig?.extends?.map(async (presetItem) => {
241
+ const extendConfigs: ResolvedStyleguideConfig[] = await Promise.all(
242
+ styleguideConfig?.extends?.map(async (presetItem) => {
214
243
  if (!isAbsoluteUrl(presetItem) && !path.extname(presetItem)) {
215
244
  return resolvePreset(presetItem, plugins);
216
245
  }
@@ -219,23 +248,23 @@ async function resolveAndMergeNestedLint(
219
248
  : isAbsoluteUrl(configPath)
220
249
  ? new URL(presetItem, configPath).href
221
250
  : path.resolve(path.dirname(configPath), presetItem);
222
- const extendedLintConfig = await loadExtendLintConfig(pathItem, resolver);
223
- return await resolveAndMergeNestedLint(
251
+ const extendedStyleguideConfig = await loadExtendStyleguideConfig(pathItem, resolver);
252
+ return await resolveAndMergeNestedStyleguideConfig(
224
253
  {
225
- lintConfig: extendedLintConfig,
254
+ styleguideConfig: extendedStyleguideConfig,
226
255
  configPath: pathItem,
227
256
  resolver: resolver,
228
257
  },
229
258
  [...parentConfigPaths, resolvedConfigPath],
230
- extendPaths,
259
+ extendPaths
231
260
  );
232
- }) || [],
261
+ }) || []
233
262
  );
234
263
 
235
- const { plugins: mergedPlugins = [], ...lint } = mergeExtends([
264
+ const { plugins: mergedPlugins = [], ...styleguide } = mergeExtends([
236
265
  ...extendConfigs,
237
266
  {
238
- ...lintConfig,
267
+ ...styleguideConfig,
239
268
  plugins,
240
269
  extends: undefined,
241
270
  extendPaths: [...parentConfigPaths, resolvedConfigPath],
@@ -244,91 +273,127 @@ async function resolveAndMergeNestedLint(
244
273
  ]);
245
274
 
246
275
  return {
247
- ...lint,
248
- extendPaths: lint.extendPaths?.filter((path) => path && !isAbsoluteUrl(path)),
276
+ ...styleguide,
277
+ extendPaths: styleguide.extendPaths?.filter((path) => path && !isAbsoluteUrl(path)),
249
278
  plugins: getUniquePlugins(mergedPlugins),
250
- recommendedFallback: lintConfig?.recommendedFallback,
251
- doNotResolveExamples: lintConfig?.doNotResolveExamples,
279
+ recommendedFallback: styleguideConfig?.recommendedFallback,
280
+ doNotResolveExamples: styleguideConfig?.doNotResolveExamples,
252
281
  };
253
282
  }
254
283
 
255
- export async function resolveLint(
256
- lintOpts: {
257
- lintConfig?: LintRawConfig;
284
+ export async function resolveStyleguideConfig(
285
+ opts: {
286
+ styleguideConfig?: StyleguideRawConfig;
258
287
  configPath?: string;
259
288
  resolver?: BaseResolver;
260
289
  },
261
290
  parentConfigPaths: string[] = [],
262
- extendPaths: string[] = [],
263
- ): Promise<ResolvedLintConfig> {
264
- const resolvedLint = await resolveAndMergeNestedLint(lintOpts, parentConfigPaths, extendPaths);
291
+ extendPaths: string[] = []
292
+ ): Promise<ResolvedStyleguideConfig> {
293
+ const resolvedStyleguideConfig = await resolveAndMergeNestedStyleguideConfig(
294
+ opts,
295
+ parentConfigPaths,
296
+ extendPaths
297
+ );
265
298
 
266
299
  return {
267
- ...resolvedLint,
268
- rules: resolvedLint.rules && groupLintAssertionRules(resolvedLint.rules),
300
+ ...resolvedStyleguideConfig,
301
+ rules:
302
+ resolvedStyleguideConfig.rules &&
303
+ groupStyleguideAssertionRules(resolvedStyleguideConfig.rules),
269
304
  };
270
305
  }
271
306
 
272
- export function resolvePreset(presetName: string, plugins: Plugin[]): ResolvedLintConfig {
307
+ export function resolvePreset(presetName: string, plugins: Plugin[]): ResolvedStyleguideConfig {
273
308
  const { pluginId, configName } = parsePresetName(presetName);
274
309
  const plugin = plugins.find((p) => p.id === pluginId);
275
310
  if (!plugin) {
276
- throw new Error(`Invalid config ${red(presetName)}: plugin ${pluginId} is not included.`);
311
+ throw new Error(
312
+ `Invalid config ${colorize.red(presetName)}: plugin ${pluginId} is not included.`
313
+ );
277
314
  }
278
315
 
279
- const preset = plugin.configs?.[configName]! as ResolvedLintConfig;
316
+ const preset = plugin.configs?.[configName];
280
317
  if (!preset) {
281
318
  throw new Error(
282
319
  pluginId
283
- ? `Invalid config ${red(
284
- presetName,
320
+ ? `Invalid config ${colorize.red(
321
+ presetName
285
322
  )}: plugin ${pluginId} doesn't export config with name ${configName}.`
286
- : `Invalid config ${red(presetName)}: there is no such built-in config.`,
323
+ : `Invalid config ${colorize.red(presetName)}: there is no such built-in config.`
287
324
  );
288
325
  }
289
326
  return preset;
290
327
  }
291
328
 
292
- async function loadExtendLintConfig(
329
+ async function loadExtendStyleguideConfig(
293
330
  filePath: string,
294
- resolver: BaseResolver,
295
- ): Promise<LintRawConfig> {
331
+ resolver: BaseResolver
332
+ ): Promise<StyleguideRawConfig> {
296
333
  try {
297
334
  const fileSource = await resolver.loadExternalRef(filePath);
298
- const rawConfig = transformConfig(parseYaml(fileSource.body) as RawConfig);
299
- if (!rawConfig.lint) {
300
- throw new Error(`Lint configuration format not detected: "${filePath}"`);
335
+ const rawConfig = transformConfig(
336
+ parseYaml(fileSource.body) as RawConfig & DeprecatedInRawConfig
337
+ );
338
+ if (!rawConfig.styleguide) {
339
+ throw new Error(`Styleguide configuration format not detected: "${filePath}"`);
301
340
  }
302
341
 
303
- return rawConfig.lint;
342
+ return rawConfig.styleguide;
304
343
  } catch (error) {
305
344
  throw new Error(`Failed to load "${filePath}": ${error.message}`);
306
345
  }
307
346
  }
308
347
 
309
- function getMergedLintRawConfig(configLint: LintRawConfig, apiLint?: LintRawConfig) {
348
+ function getMergedRawStyleguideConfig(
349
+ rootStyleguideConfig: StyleguideRawConfig,
350
+ apiStyleguideConfig?: ApiStyleguideRawConfig
351
+ ) {
310
352
  const resultLint = {
311
- ...configLint,
312
- ...apiLint,
313
- rules: { ...configLint?.rules, ...apiLint?.rules },
314
- oas2Rules: { ...configLint?.oas2Rules, ...apiLint?.oas2Rules },
315
- oas3_0Rules: { ...configLint?.oas3_0Rules, ...apiLint?.oas3_0Rules },
316
- oas3_1Rules: { ...configLint?.oas3_1Rules, ...apiLint?.oas3_1Rules },
317
- preprocessors: { ...configLint?.preprocessors, ...apiLint?.preprocessors },
318
- oas2Preprocessors: { ...configLint?.oas2Preprocessors, ...apiLint?.oas2Preprocessors },
319
- oas3_0Preprocessors: { ...configLint?.oas3_0Preprocessors, ...apiLint?.oas3_0Preprocessors },
320
- oas3_1Preprocessors: { ...configLint?.oas3_1Preprocessors, ...apiLint?.oas3_1Preprocessors },
321
- decorators: { ...configLint?.decorators, ...apiLint?.decorators },
322
- oas2Decorators: { ...configLint?.oas2Decorators, ...apiLint?.oas2Decorators },
323
- oas3_0Decorators: { ...configLint?.oas3_0Decorators, ...apiLint?.oas3_0Decorators },
324
- oas3_1Decorators: { ...configLint?.oas3_1Decorators, ...apiLint?.oas3_1Decorators },
325
- recommendedFallback: apiLint?.extends ? false : configLint.recommendedFallback,
353
+ ...rootStyleguideConfig,
354
+ ...apiStyleguideConfig,
355
+ rules: { ...rootStyleguideConfig?.rules, ...apiStyleguideConfig?.rules },
356
+ oas2Rules: { ...rootStyleguideConfig?.oas2Rules, ...apiStyleguideConfig?.oas2Rules },
357
+ oas3_0Rules: { ...rootStyleguideConfig?.oas3_0Rules, ...apiStyleguideConfig?.oas3_0Rules },
358
+ oas3_1Rules: { ...rootStyleguideConfig?.oas3_1Rules, ...apiStyleguideConfig?.oas3_1Rules },
359
+ preprocessors: {
360
+ ...rootStyleguideConfig?.preprocessors,
361
+ ...apiStyleguideConfig?.preprocessors,
362
+ },
363
+ oas2Preprocessors: {
364
+ ...rootStyleguideConfig?.oas2Preprocessors,
365
+ ...apiStyleguideConfig?.oas2Preprocessors,
366
+ },
367
+ oas3_0Preprocessors: {
368
+ ...rootStyleguideConfig?.oas3_0Preprocessors,
369
+ ...apiStyleguideConfig?.oas3_0Preprocessors,
370
+ },
371
+ oas3_1Preprocessors: {
372
+ ...rootStyleguideConfig?.oas3_1Preprocessors,
373
+ ...apiStyleguideConfig?.oas3_1Preprocessors,
374
+ },
375
+ decorators: { ...rootStyleguideConfig?.decorators, ...apiStyleguideConfig?.decorators },
376
+ oas2Decorators: {
377
+ ...rootStyleguideConfig?.oas2Decorators,
378
+ ...apiStyleguideConfig?.oas2Decorators,
379
+ },
380
+ oas3_0Decorators: {
381
+ ...rootStyleguideConfig?.oas3_0Decorators,
382
+ ...apiStyleguideConfig?.oas3_0Decorators,
383
+ },
384
+ oas3_1Decorators: {
385
+ ...rootStyleguideConfig?.oas3_1Decorators,
386
+ ...apiStyleguideConfig?.oas3_1Decorators,
387
+ },
388
+ recommendedFallback: apiStyleguideConfig?.extends
389
+ ? false
390
+ : rootStyleguideConfig.recommendedFallback,
326
391
  };
327
392
  return resultLint;
328
393
  }
329
394
 
330
- function groupLintAssertionRules(
331
- rules: Record<string, RuleConfig> | undefined,
395
+ function groupStyleguideAssertionRules(
396
+ rules: Record<string, RuleConfig> | undefined
332
397
  ): Record<string, RuleConfig> | undefined {
333
398
  if (!rules) {
334
399
  return rules;
@@ -4,6 +4,7 @@ import { parseYaml, stringifyYaml } from '../js-yaml';
4
4
  import { slash, doesYamlFileExist } from '../utils';
5
5
  import { NormalizedProblem } from '../walk';
6
6
  import { OasVersion, OasMajorVersion, Oas2RuleSet, Oas3RuleSet } from '../oas-types';
7
+ import { env } from '../env';
7
8
 
8
9
  import type { NodeType } from '../types';
9
10
  import type {
@@ -14,14 +15,11 @@ import type {
14
15
  ResolveConfig,
15
16
  ResolvedApi,
16
17
  ResolvedConfig,
17
- ResolvedLintConfig,
18
+ ResolvedStyleguideConfig,
18
19
  RuleConfig,
19
20
  } from './types';
20
21
  import { getResolveConfig } from './utils';
21
22
 
22
- // Alias environment here so this file can work in browser environments too.
23
- export const env = typeof process !== 'undefined' ? process.env || {} : {};
24
-
25
23
  export const IGNORE_FILE = '.redocly.lint-ignore.yaml';
26
24
  const IGNORE_BANNER =
27
25
  `# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.\n` +
@@ -59,7 +57,7 @@ function getIgnoreFilePath(configFile?: string): string | undefined {
59
57
  export const DOMAINS = getDomains();
60
58
  export const AVAILABLE_REGIONS = Object.keys(DOMAINS) as Region[];
61
59
 
62
- export class LintConfig {
60
+ export class StyleguideConfig {
63
61
  plugins: Plugin[];
64
62
  ignore: Record<string, Record<string, Set<string>>> = {};
65
63
  doNotResolveExamples: boolean;
@@ -75,7 +73,7 @@ export class LintConfig {
75
73
  extendPaths: string[];
76
74
  pluginPaths: string[];
77
75
 
78
- constructor(public rawConfig: ResolvedLintConfig, public configFile?: string) {
76
+ constructor(public rawConfig: ResolvedStyleguideConfig, public configFile?: string) {
79
77
  this.plugins = rawConfig.plugins || [];
80
78
  this.doNotResolveExamples = !!rawConfig.doNotResolveExamples;
81
79
 
@@ -172,9 +170,11 @@ export class LintConfig {
172
170
  case OasVersion.Version3_1:
173
171
  if (!plugin.typeExtension.oas3) continue;
174
172
  extendedTypes = plugin.typeExtension.oas3(extendedTypes, version);
173
+ break;
175
174
  case OasVersion.Version2:
176
175
  if (!plugin.typeExtension.oas2) continue;
177
176
  extendedTypes = plugin.typeExtension.oas2(extendedTypes, version);
177
+ break;
178
178
  default:
179
179
  throw new Error('Not implemented');
180
180
  }
@@ -192,7 +192,7 @@ export class LintConfig {
192
192
  severity: settings,
193
193
  };
194
194
  } else {
195
- return { severity: 'error' as 'error', ...settings };
195
+ return { severity: 'error', ...settings };
196
196
  }
197
197
  }
198
198
 
@@ -203,10 +203,10 @@ export class LintConfig {
203
203
  const settings = this.preprocessors[oasVersion][ruleId] || 'off';
204
204
  if (typeof settings === 'string') {
205
205
  return {
206
- severity: settings === 'on' ? ('error' as 'error') : settings,
206
+ severity: settings === 'on' ? 'error' : settings,
207
207
  };
208
208
  } else {
209
- return { severity: 'error' as 'error', ...settings };
209
+ return { severity: 'error', ...settings };
210
210
  }
211
211
  }
212
212
 
@@ -216,10 +216,10 @@ export class LintConfig {
216
216
  const settings = this.decorators[oasVersion][ruleId] || 'off';
217
217
  if (typeof settings === 'string') {
218
218
  return {
219
- severity: settings === 'on' ? ('error' as 'error') : settings,
219
+ severity: settings === 'on' ? 'error' : settings,
220
220
  };
221
221
  } else {
222
- return { severity: 'error' as 'error', ...settings };
222
+ return { severity: 'error', ...settings };
223
223
  }
224
224
  }
225
225
 
@@ -250,12 +250,14 @@ export class LintConfig {
250
250
  getRulesForOasVersion(version: OasMajorVersion) {
251
251
  switch (version) {
252
252
  case OasMajorVersion.Version3:
253
+ // eslint-disable-next-line no-case-declarations
253
254
  const oas3Rules: Oas3RuleSet[] = []; // default ruleset
254
255
  this.plugins.forEach((p) => p.preprocessors?.oas3 && oas3Rules.push(p.preprocessors.oas3));
255
256
  this.plugins.forEach((p) => p.rules?.oas3 && oas3Rules.push(p.rules.oas3));
256
257
  this.plugins.forEach((p) => p.decorators?.oas3 && oas3Rules.push(p.decorators.oas3));
257
258
  return oas3Rules;
258
259
  case OasMajorVersion.Version2:
260
+ // eslint-disable-next-line no-case-declarations
259
261
  const oas2Rules: Oas2RuleSet[] = []; // default ruleset
260
262
  this.plugins.forEach((p) => p.preprocessors?.oas2 && oas2Rules.push(p.preprocessors.oas2));
261
263
  this.plugins.forEach((p) => p.rules?.oas2 && oas2Rules.push(p.rules.oas2));
@@ -297,7 +299,7 @@ export class LintConfig {
297
299
 
298
300
  export class Config {
299
301
  apis: Record<string, ResolvedApi>;
300
- lint: LintConfig;
302
+ styleguide: StyleguideConfig;
301
303
  resolve: ResolveConfig;
302
304
  licenseKey?: string;
303
305
  region?: Region;
@@ -306,7 +308,7 @@ export class Config {
306
308
  organization?: string;
307
309
  constructor(public rawConfig: ResolvedConfig, public configFile?: string) {
308
310
  this.apis = rawConfig.apis || {};
309
- this.lint = new LintConfig(rawConfig.lint || {}, configFile);
311
+ this.styleguide = new StyleguideConfig(rawConfig.styleguide || {}, configFile);
310
312
  this['features.openapi'] = rawConfig['features.openapi'] || {};
311
313
  this['features.mockServer'] = rawConfig['features.mockServer'] || {};
312
314
  this.resolve = getResolveConfig(rawConfig?.resolve);
@@ -2,33 +2,34 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { RedoclyClient } from '../redocly';
4
4
  import { isEmptyObject, loadYaml, doesYamlFileExist } from '../utils';
5
+ import { parseYaml } from '../js-yaml';
5
6
  import { Config, DOMAINS } from './config';
6
7
  import { transformConfig } from './utils';
7
8
  import { resolveConfig } from './config-resolvers';
8
9
 
9
- import type { RawConfig, Region } from './types';
10
+ import type { DeprecatedInRawConfig, RawConfig, Region } from './types';
11
+ import { RegionalTokenWithValidity } from '../redocly/redocly-client-types';
10
12
 
11
13
  async function addConfigMetadata({
12
14
  rawConfig,
13
15
  customExtends,
14
16
  configPath,
17
+ tokens,
15
18
  }: {
16
19
  rawConfig: RawConfig;
17
20
  customExtends?: string[];
18
21
  configPath?: string;
22
+ tokens?: RegionalTokenWithValidity[];
19
23
  }): Promise<Config> {
20
24
  if (customExtends !== undefined) {
21
- rawConfig.lint = rawConfig.lint || {};
22
- rawConfig.lint.extends = customExtends;
25
+ rawConfig.styleguide = rawConfig.styleguide || {};
26
+ rawConfig.styleguide.extends = customExtends;
23
27
  } else if (isEmptyObject(rawConfig)) {
24
28
  // TODO: check if we can add recommended here. add message here?
25
- // rawConfig.lint = { extends: ['recommended'], recommendedFallback: true };
29
+ // rawConfig.styleguide = { extends: ['recommended'], recommendedFallback: true };
26
30
  }
27
31
 
28
- const redoclyClient = new RedoclyClient();
29
- const tokens = await redoclyClient.getTokens();
30
-
31
- if (tokens.length) {
32
+ if (tokens?.length) {
32
33
  if (!rawConfig.resolve) rawConfig.resolve = {};
33
34
  if (!rawConfig.resolve.http) rawConfig.resolve.http = {};
34
35
  rawConfig.resolve.http.headers = [...(rawConfig.resolve.http.headers ?? [])];
@@ -69,10 +70,15 @@ export async function loadConfig(
69
70
  if (typeof processRawConfig === 'function') {
70
71
  await processRawConfig(rawConfig);
71
72
  }
72
- return await addConfigMetadata({
73
+
74
+ const redoclyClient = new RedoclyClient();
75
+ const tokens = await redoclyClient.getTokens();
76
+
77
+ return addConfigMetadata({
73
78
  rawConfig,
74
79
  customExtends,
75
80
  configPath,
81
+ tokens,
76
82
  });
77
83
  }
78
84
 
@@ -93,12 +99,29 @@ export function findConfig(dir?: string): string | undefined {
93
99
  return existingConfigFiles[0];
94
100
  }
95
101
 
96
- export async function getConfig(configPath: string | undefined = findConfig()) {
102
+ export async function getConfig(configPath: string | undefined = findConfig()): Promise<RawConfig> {
97
103
  if (!configPath || !doesYamlFileExist(configPath)) return {};
98
104
  try {
99
- const rawConfig = ((await loadYaml(configPath)) || {}) as RawConfig;
105
+ const rawConfig = (await loadYaml<RawConfig & DeprecatedInRawConfig>(configPath)) || {};
100
106
  return transformConfig(rawConfig);
101
107
  } catch (e) {
102
108
  throw new Error(`Error parsing config file at '${configPath}': ${e.message}`);
103
109
  }
104
110
  }
111
+
112
+ type CreateConfigOptions = {
113
+ extends?: string[];
114
+ tokens?: RegionalTokenWithValidity[];
115
+ };
116
+
117
+ export async function createConfig(
118
+ config: string | RawConfig,
119
+ options?: CreateConfigOptions
120
+ ): Promise<Config> {
121
+ return addConfigMetadata({
122
+ rawConfig: transformConfig(
123
+ typeof config === 'string' ? (parseYaml(config) as RawConfig) : config
124
+ ),
125
+ ...options,
126
+ });
127
+ }