@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,7 +1,7 @@
1
- import { gray, red, options as colorOptions } from 'colorette';
2
1
  import * as yamlAst from 'yaml-ast-parser';
3
2
  import { unescapePointer } from '../ref-utils';
4
3
  import { LineColLocationObject, Loc, LocationObject } from '../walk';
4
+ import { colorize, colorOptions } from '../logger';
5
5
 
6
6
  type YAMLMapping = yamlAst.YAMLMapping & { kind: yamlAst.Kind.MAPPING };
7
7
  type YAMLMap = yamlAst.YamlMap & { kind: yamlAst.Kind.MAP };
@@ -36,17 +36,23 @@ export function getCodeframe(location: LineColLocationObject, color: boolean) {
36
36
  if (skipLines > 0 && i >= endLineNum - skipLines) break;
37
37
  const line = lines[i - 1] || '';
38
38
  if (line !== '') currentPad = padSize(line);
39
- let startIdx = i === startLineNum ? start.col - 1 : currentPad;
40
- let endIdx = i === endLineNum ? end.col - 1 : line.length;
39
+ const startIdx = i === startLineNum ? start.col - 1 : currentPad;
40
+ const endIdx = i === endLineNum ? end.col - 1 : line.length;
41
41
 
42
- prefixedLines.push([`${i}`, markLine(line, startIdx, endIdx, red)]);
42
+ prefixedLines.push([`${i}`, markLine(line, startIdx, endIdx, colorize.red)]);
43
43
  if (!color) prefixedLines.push(['', underlineLine(line, startIdx, endIdx)]);
44
44
  }
45
45
 
46
46
  if (skipLines > 0) {
47
- prefixedLines.push([`…`, `${whitespace(currentPad)}${gray(`< ${skipLines} more lines >`)}`]);
47
+ prefixedLines.push([
48
+ `…`,
49
+ `${whitespace(currentPad)}${colorize.gray(`< ${skipLines} more lines >`)}`,
50
+ ]);
48
51
  // print last line
49
- prefixedLines.push([`${endLineNum}`, markLine(lines[endLineNum - 1], -1, end.col - 1, red)]);
52
+ prefixedLines.push([
53
+ `${endLineNum}`,
54
+ markLine(lines[endLineNum - 1], -1, end.col - 1, colorize.red),
55
+ ]);
50
56
 
51
57
  if (!color) prefixedLines.push(['', underlineLine(lines[endLineNum - 1], -1, end.col - 1)]);
52
58
  }
@@ -63,7 +69,7 @@ export function getCodeframe(location: LineColLocationObject, color: boolean) {
63
69
  line: string,
64
70
  startIdx: number = -1,
65
71
  endIdx: number = +Infinity,
66
- variant = gray,
72
+ variant = colorize.gray
67
73
  ) {
68
74
  if (!color) return line;
69
75
  if (!line) return line;
@@ -84,14 +90,14 @@ function printPrefixedLines(lines: [string, string][]): string {
84
90
 
85
91
  const padLen = Math.max(...existingLines.map(([prefix]) => prefix.length));
86
92
  const dedentLen = Math.min(
87
- ...existingLines.map(([_, line]) => (line === '' ? Infinity : padSize(line))),
93
+ ...existingLines.map(([_, line]) => (line === '' ? Infinity : padSize(line)))
88
94
  );
89
95
 
90
96
  return existingLines
91
97
  .map(
92
98
  ([prefix, line]) =>
93
- gray(leftPad(padLen, prefix) + ' |') +
94
- (line ? ' ' + limitLineLength(line.substring(dedentLen)) : ''),
99
+ colorize.gray(leftPad(padLen, prefix) + ' |') +
100
+ (line ? ' ' + limitLineLength(line.substring(dedentLen)) : '')
95
101
  )
96
102
  .join('\n');
97
103
  }
@@ -99,7 +105,7 @@ function printPrefixedLines(lines: [string, string][]): string {
99
105
  function limitLineLength(line: string, maxLen: number = MAX_LINE_LENGTH) {
100
106
  const overflowLen = line.length - maxLen;
101
107
  if (overflowLen > 0) {
102
- const charsMoreText = gray(`...<${overflowLen} chars>`);
108
+ const charsMoreText = colorize.gray(`...<${overflowLen} chars>`);
103
109
  return line.substring(0, maxLen - charsMoreText.length) + charsMoreText;
104
110
  } else {
105
111
  return line;
@@ -146,7 +152,7 @@ export function getLineColLocation(location: LocationObject): LineColLocationObj
146
152
  function positionsToLoc(
147
153
  source: string,
148
154
  startPos: number,
149
- endPos: number,
155
+ endPos: number
150
156
  ): { start: Loc; end: Loc } {
151
157
  let currentLine = 1;
152
158
  let currentCol = 1;
@@ -1,20 +1,12 @@
1
1
  import * as path from 'path';
2
- import {
3
- options as colorOptions,
4
- gray,
5
- blue,
6
- bgRed,
7
- bgYellow,
8
- black,
9
- yellow,
10
- red,
11
- } from 'colorette';
2
+ import { colorOptions, colorize, logger } from '../logger';
3
+ import { output } from '../output';
12
4
 
13
5
  const coreVersion = require('../../package.json').version;
14
6
 
15
7
  import { NormalizedProblem, ProblemSeverity, LineColLocationObject, LocationObject } from '../walk';
16
8
  import { getCodeframe, getLineColLocation } from './codeframes';
17
- import { env } from "../config";
9
+ import { env } from '../env';
18
10
 
19
11
  export type Totals = {
20
12
  errors: number;
@@ -27,13 +19,13 @@ const ERROR_MESSAGE = {
27
19
  };
28
20
 
29
21
  const BG_COLORS = {
30
- warn: (str: string) => bgYellow(black(str)),
31
- error: bgRed,
22
+ warn: (str: string) => colorize.bgYellow(colorize.black(str)),
23
+ error: colorize.bgRed,
32
24
  };
33
25
 
34
26
  const COLORS = {
35
- warn: yellow,
36
- error: red,
27
+ warn: colorize.yellow,
28
+ error: colorize.red,
37
29
  };
38
30
 
39
31
  const SEVERITY_NAMES = {
@@ -84,7 +76,7 @@ export function formatProblems(
84
76
  color?: boolean;
85
77
  totals: Totals;
86
78
  version: string;
87
- },
79
+ }
88
80
  ) {
89
81
  const {
90
82
  maxProblems = 100,
@@ -114,38 +106,38 @@ export function formatProblems(
114
106
  case 'codeframe':
115
107
  for (let i = 0; i < problems.length; i++) {
116
108
  const problem = problems[i];
117
- process.stderr.write(`${formatCodeframe(problem, i)}\n`);
109
+ logger.info(`${formatCodeframe(problem, i)}\n`);
118
110
  }
119
111
  break;
120
112
  case 'stylish': {
121
113
  const groupedByFile = groupByFiles(problems);
122
114
  for (const [file, { ruleIdPad, locationPad: positionPad, fileProblems }] of Object.entries(
123
- groupedByFile,
115
+ groupedByFile
124
116
  )) {
125
- process.stderr.write(`${blue(path.relative(cwd, file))}:\n`);
117
+ logger.info(`${colorize.blue(path.relative(cwd, file))}:\n`);
126
118
 
127
119
  for (let i = 0; i < fileProblems.length; i++) {
128
120
  const problem = fileProblems[i];
129
- process.stderr.write(`${formatStylish(problem, positionPad, ruleIdPad)}\n`);
121
+ logger.info(`${formatStylish(problem, positionPad, ruleIdPad)}\n`);
130
122
  }
131
123
 
132
- process.stderr.write('\n');
124
+ logger.info('\n');
133
125
  }
134
126
  break;
135
127
  }
136
128
  case 'checkstyle': {
137
129
  const groupedByFile = groupByFiles(problems);
138
130
 
139
- process.stdout.write('<?xml version="1.0" encoding="UTF-8"?>\n');
140
- process.stdout.write('<checkstyle version="4.3">\n');
131
+ output.write('<?xml version="1.0" encoding="UTF-8"?>\n');
132
+ output.write('<checkstyle version="4.3">\n');
141
133
 
142
134
  for (const [file, { fileProblems }] of Object.entries(groupedByFile)) {
143
- process.stdout.write(`<file name="${xmlEscape(path.relative(cwd, file))}">\n`);
135
+ output.write(`<file name="${xmlEscape(path.relative(cwd, file))}">\n`);
144
136
  fileProblems.forEach(formatCheckstyle);
145
- process.stdout.write(`</file>\n`);
137
+ output.write(`</file>\n`);
146
138
  }
147
139
 
148
- process.stdout.write(`</checkstyle>\n`);
140
+ output.write(`</checkstyle>\n`);
149
141
  break;
150
142
  }
151
143
  case 'codeclimate':
@@ -154,10 +146,10 @@ export function formatProblems(
154
146
  }
155
147
 
156
148
  if (totalProblems - ignoredProblems > maxProblems) {
157
- process.stderr.write(
158
- `< ... ${totalProblems - maxProblems} more problems hidden > ${gray(
159
- 'increase with `--max-problems N`',
160
- )}\n`,
149
+ logger.info(
150
+ `< ... ${totalProblems - maxProblems} more problems hidden > ${colorize.gray(
151
+ 'increase with `--max-problems N`'
152
+ )}\n`
161
153
  );
162
154
  }
163
155
 
@@ -177,7 +169,7 @@ export function formatProblems(
177
169
  fingerprint: `${p.ruleId}${p.location.length > 0 ? '-' + p.location[0].pointer : ''}`,
178
170
  };
179
171
  });
180
- process.stdout.write(JSON.stringify(issues, null, 2));
172
+ output.write(JSON.stringify(issues, null, 2));
181
173
  }
182
174
 
183
175
  function outputJSON() {
@@ -185,7 +177,7 @@ export function formatProblems(
185
177
  totals,
186
178
  version,
187
179
  problems: problems.map((p) => {
188
- let problem = {
180
+ const problem = {
189
181
  ...p,
190
182
  location: p.location.map((location: any) => ({
191
183
  ...location,
@@ -211,7 +203,7 @@ export function formatProblems(
211
203
  return problem;
212
204
  }),
213
205
  };
214
- process.stdout.write(JSON.stringify(resultObject, null, 2));
206
+ output.write(JSON.stringify(resultObject, null, 2));
215
207
  }
216
208
 
217
209
  function getBgColor(problem: NormalizedProblem) {
@@ -227,7 +219,7 @@ export function formatProblems(
227
219
  const location = problem.location[0]; // TODO: support multiple locations
228
220
  const relativePath = path.relative(cwd, location.source.absoluteRef);
229
221
  const loc = getLineColLocation(location);
230
- const atPointer = location.pointer ? gray(`at ${location.pointer}`) : '';
222
+ const atPointer = location.pointer ? colorize.gray(`at ${location.pointer}`) : '';
231
223
  const fileWithLoc = `${relativePath}:${loc.start.line}:${loc.start.col}`;
232
224
  return (
233
225
  `[${idx + 1}] ${bgColor(fileWithLoc)} ${atPointer}\n\n` +
@@ -236,19 +228,21 @@ export function formatProblems(
236
228
  getCodeframe(loc, color) +
237
229
  '\n\n' +
238
230
  formatFrom(cwd, problem.from) +
239
- `${SEVERITY_NAMES[problem.severity]} was generated by the ${blue(problem.ruleId)} rule.\n\n`
231
+ `${SEVERITY_NAMES[problem.severity]} was generated by the ${colorize.blue(
232
+ problem.ruleId
233
+ )} rule.\n\n`
240
234
  );
241
235
  }
242
236
 
243
237
  function formatStylish(problem: OnlyLineColProblem, locationPad: number, ruleIdPad: number) {
244
238
  const color = COLORS[problem.severity];
245
239
  if (!SEVERITY_NAMES[problem.severity]) {
246
- return 'Error not found severity. Please check your config file. Allowed values: \`warn,error,off\`'
240
+ return 'Error not found severity. Please check your config file. Allowed values: `warn,error,off`';
247
241
  }
248
242
  const severityName = color(SEVERITY_NAMES[problem.severity].toLowerCase().padEnd(7));
249
243
  const { start } = problem.location[0];
250
244
  return ` ${`${start.line}:${start.col}`.padEnd(
251
- locationPad,
245
+ locationPad
252
246
  )} ${severityName} ${problem.ruleId.padEnd(ruleIdPad)} ${problem.message}`;
253
247
  }
254
248
 
@@ -257,8 +251,8 @@ export function formatProblems(
257
251
  const severity = problem.severity == 'warn' ? 'warning' : 'error';
258
252
  const message = xmlEscape(problem.message);
259
253
  const source = xmlEscape(problem.ruleId);
260
- process.stdout.write(
261
- `<error line="${line}" column="${col}" severity="${severity}" message="${message}" source="${source}" />\n`,
254
+ output.write(
255
+ `<error line="${line}" column="${col}" severity="${severity}" message="${message}" source="${source}" />\n`
262
256
  );
263
257
  }
264
258
  }
@@ -269,7 +263,7 @@ function formatFrom(cwd: string, location?: LocationObject) {
269
263
  const loc = getLineColLocation(location);
270
264
  const fileWithLoc = `${relativePath}:${loc.start.line}:${loc.start.col}`;
271
265
 
272
- return `referenced from ${blue(fileWithLoc)}\n\n`;
266
+ return `referenced from ${colorize.blue(fileWithLoc)}\n\n`;
273
267
  }
274
268
 
275
269
  function formatDidYouMean(problem: NormalizedProblem) {
@@ -307,12 +301,12 @@ const groupByFiles = (problems: NormalizedProblem[]) => {
307
301
  fileGroups[absoluteRef].fileProblems.push(mappedProblem);
308
302
  fileGroups[absoluteRef].ruleIdPad = Math.max(
309
303
  problem.ruleId.length,
310
- fileGroups[absoluteRef].ruleIdPad,
304
+ fileGroups[absoluteRef].ruleIdPad
311
305
  );
312
306
 
313
307
  fileGroups[absoluteRef].locationPad = Math.max(
314
308
  Math.max(...mappedProblem.location.map((loc) => `${loc.start.line}:${loc.start.col}`.length)),
315
- fileGroups[absoluteRef].locationPad,
309
+ fileGroups[absoluteRef].locationPad
316
310
  );
317
311
  }
318
312
 
@@ -320,6 +314,7 @@ const groupByFiles = (problems: NormalizedProblem[]) => {
320
314
  };
321
315
 
322
316
  function xmlEscape(s: string): string {
317
+ // eslint-disable-next-line no-control-regex
323
318
  return s.replace(/[<>&"'\x00-\x1F\x7F\u0080-\uFFFF]/gu, (char) => {
324
319
  switch (char) {
325
320
  case '<':
package/src/index.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { BundleOutputFormat, readFileFromUrl, slash, doesYamlFileExist } from './utils';
1
+ export { BundleOutputFormat, readFileFromUrl, slash, doesYamlFileExist, isTruthy } from './utils';
2
2
  export { Oas3_1Types } from './types/oas3_1';
3
3
  export { Oas3Types } from './types/oas3';
4
4
  export { Oas2Types } from './types/oas2';
5
5
  export { ConfigTypes } from './types/redocly-yaml';
6
- export {
6
+ export type {
7
7
  Oas3Definition,
8
8
  Oas3_1Definition,
9
9
  Oas3Components,
@@ -15,15 +15,16 @@ export {
15
15
  Oas3Tag,
16
16
  Oas3_1Webhooks,
17
17
  Referenced,
18
+ OasRef,
18
19
  } from './typings/openapi';
19
- export { Oas2Definition } from './typings/swagger';
20
- export { StatsAccumulator, StatsName } from './typings/common';
20
+ export type { Oas2Definition } from './typings/swagger';
21
+ export type { StatsAccumulator, StatsName } from './typings/common';
21
22
  export { normalizeTypes } from './types';
22
23
  export { Stats } from './rules/other/stats';
23
24
 
24
25
  export {
25
26
  Config,
26
- LintConfig,
27
+ StyleguideConfig,
27
28
  RawConfig,
28
29
  IGNORE_FILE,
29
30
  Region,
@@ -33,10 +34,10 @@ export {
33
34
  getConfig,
34
35
  findConfig,
35
36
  CONFIG_FILE_NAMES,
36
- RuleSeverity
37
+ RuleSeverity,
38
+ createConfig,
37
39
  } from './config';
38
40
 
39
-
40
41
  export { RedoclyClient, isRedoclyRegistryURL } from './redocly';
41
42
 
42
43
  export {
@@ -1,18 +1,14 @@
1
1
  // TODO: add a type for "types" https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/js-yaml/index.d.ts
2
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
3
  // @ts-ignore
3
- import { JSON_SCHEMA, types, LoadOptions, DumpOptions, load, dump } from 'js-yaml';
4
+ import { JSON_SCHEMA, types, LoadOptions, DumpOptions, load, dump } from 'js-yaml';
4
5
 
5
6
  const DEFAULT_SCHEMA_WITHOUT_TIMESTAMP = JSON_SCHEMA.extend({
6
7
  implicit: [types.merge],
7
- explicit: [
8
- types.binary,
9
- types.omap,
10
- types.pairs,
11
- types.set,
12
- ],
8
+ explicit: [types.binary, types.omap, types.pairs, types.set],
13
9
  });
14
10
 
15
11
  export const parseYaml = (str: string, opts?: LoadOptions): unknown =>
16
- load(str, {schema: DEFAULT_SCHEMA_WITHOUT_TIMESTAMP, ...opts});
12
+ load(str, { schema: DEFAULT_SCHEMA_WITHOUT_TIMESTAMP, ...opts });
17
13
 
18
14
  export const stringifyYaml = (obj: any, opts?: DumpOptions): string => dump(obj, opts);
package/src/lint.ts CHANGED
@@ -1,20 +1,17 @@
1
1
  import { BaseResolver, resolveDocument, Document, makeDocumentFromString } from './resolve';
2
- import {
3
- normalizeVisitors,
4
- } from './visitors';
2
+ import { normalizeVisitors } from './visitors';
5
3
  import { Oas3_1Types } from './types/oas3_1';
6
4
  import { Oas3Types } from './types/oas3';
7
5
  import { Oas2Types } from './types/oas2';
8
6
  import { NodeType } from './types';
9
7
  import { ProblemSeverity, WalkContext, walkDocument } from './walk';
10
- import { LintConfig, Config, initRules, defaultPlugin, resolvePlugins } from './config';
8
+ import { StyleguideConfig, Config, initRules, defaultPlugin, resolvePlugins } from './config';
11
9
  import { normalizeTypes } from './types';
12
10
  import { releaseAjvInstance } from './rules/ajv';
13
11
  import { detectOpenAPI, Oas3RuleSet, OasMajorVersion, OasVersion, openAPIMajor } from './oas-types';
14
12
  import { ConfigTypes } from './types/redocly-yaml';
15
13
  import { OasSpec } from './rules/common/spec';
16
14
 
17
-
18
15
  export async function lint(opts: {
19
16
  ref: string;
20
17
  config: Config;
@@ -27,7 +24,7 @@ export async function lint(opts: {
27
24
  document,
28
25
  ...opts,
29
26
  externalRefResolver,
30
- config: opts.config.lint,
27
+ config: opts.config.styleguide,
31
28
  });
32
29
  }
33
30
 
@@ -44,13 +41,13 @@ export async function lintFromString(opts: {
44
41
  document,
45
42
  ...opts,
46
43
  externalRefResolver,
47
- config: opts.config.lint,
44
+ config: opts.config.styleguide,
48
45
  });
49
46
  }
50
47
 
51
48
  export async function lintDocument(opts: {
52
49
  document: Document;
53
- config: LintConfig;
50
+ config: StyleguideConfig;
54
51
  customTypes?: Record<string, NodeType>;
55
52
  externalRefResolver: BaseResolver;
56
53
  }) {
@@ -62,10 +59,14 @@ export async function lintDocument(opts: {
62
59
  const rules = config.getRulesForOasVersion(oasMajorVersion);
63
60
  const types = normalizeTypes(
64
61
  config.extendTypes(
65
- customTypes ?? oasMajorVersion === OasMajorVersion.Version3 ? (oasVersion === OasVersion.Version3_1 ? Oas3_1Types : Oas3Types) : Oas2Types,
66
- oasVersion,
62
+ customTypes ?? oasMajorVersion === OasMajorVersion.Version3
63
+ ? oasVersion === OasVersion.Version3_1
64
+ ? Oas3_1Types
65
+ : Oas3Types
66
+ : Oas2Types,
67
+ oasVersion
67
68
  ),
68
- config,
69
+ config
69
70
  );
70
71
 
71
72
  const ctx: WalkContext = {
@@ -80,7 +81,7 @@ export async function lintDocument(opts: {
80
81
  const resolvedRefMap = await resolveDocument({
81
82
  rootDocument: document,
82
83
  rootType: types.DefinitionRoot,
83
- externalRefResolver
84
+ externalRefResolver,
84
85
  });
85
86
 
86
87
  walkDocument({
@@ -93,10 +94,7 @@ export async function lintDocument(opts: {
93
94
  return ctx.problems.map((problem) => config.addProblemToIgnore(problem));
94
95
  }
95
96
 
96
- export async function lintConfig(opts: {
97
- document: Document
98
- severity?: ProblemSeverity
99
- }) {
97
+ export async function lintConfig(opts: { document: Document; severity?: ProblemSeverity }) {
100
98
  const { document, severity } = opts;
101
99
 
102
100
  const ctx: WalkContext = {
@@ -105,13 +103,19 @@ export async function lintConfig(opts: {
105
103
  visitorsData: {},
106
104
  };
107
105
  const plugins = resolvePlugins([defaultPlugin]);
108
- const config = new LintConfig({
106
+ const config = new StyleguideConfig({
109
107
  plugins,
110
108
  rules: { spec: 'error' },
111
109
  });
112
110
 
113
111
  const types = normalizeTypes(ConfigTypes, config);
114
- const rules = [{ severity: severity || 'error', ruleId: 'configuration spec', visitor: OasSpec({ severity: 'error' }) }];
112
+ const rules = [
113
+ {
114
+ severity: severity || 'error',
115
+ ruleId: 'configuration spec',
116
+ visitor: OasSpec({ severity: 'error' }),
117
+ },
118
+ ];
115
119
  const normalizedVisitors = normalizeVisitors(rules, types);
116
120
 
117
121
  walkDocument({
package/src/logger.ts ADDED
@@ -0,0 +1,34 @@
1
+ import * as colorette from 'colorette';
2
+ export { options as colorOptions } from 'colorette';
3
+
4
+ import { isBrowser } from './env';
5
+ import { identity } from './utils';
6
+
7
+ export const colorize = new Proxy(colorette, {
8
+ get(target: typeof colorette, prop: string): typeof identity {
9
+ if (isBrowser) {
10
+ return identity;
11
+ }
12
+
13
+ return (target as any)[prop];
14
+ },
15
+ });
16
+ class Logger {
17
+ protected stderr(str: string) {
18
+ return process.stderr.write(str);
19
+ }
20
+
21
+ info(str: string) {
22
+ return isBrowser ? console.log(str) : this.stderr(str);
23
+ }
24
+
25
+ warn(str: string) {
26
+ return isBrowser ? console.warn(str) : this.stderr(colorize.yellow(str));
27
+ }
28
+
29
+ error(str: string) {
30
+ return isBrowser ? console.error(str) : this.stderr(colorize.red(str));
31
+ }
32
+ }
33
+
34
+ export const logger = new Logger();
package/src/oas-types.ts CHANGED
@@ -1,9 +1,4 @@
1
- import {
2
- Oas3Rule,
3
- Oas3Preprocessor,
4
- Oas2Rule,
5
- Oas2Preprocessor,
6
- } from './visitors';
1
+ import { Oas3Rule, Oas3Preprocessor, Oas2Rule, Oas2Preprocessor } from './visitors';
7
2
 
8
3
  export type RuleSet<T> = Record<string, T>;
9
4
 
package/src/output.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { isBrowser } from './env';
2
+
3
+ export const output = {
4
+ write(str: string) {
5
+ return isBrowser ? undefined : process.stdout.write(str);
6
+ },
7
+ };
@@ -59,55 +59,57 @@ describe('RedoclyClient', () => {
59
59
 
60
60
  it('should resolve all tokens', async () => {
61
61
  let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation(() => {
62
- return { token: "accessToken", us: "accessToken", eu: "eu-accessToken" };
62
+ return { token: 'accessToken', us: 'accessToken', eu: 'eu-accessToken' };
63
63
  });
64
64
  const client = new RedoclyClient();
65
65
  const tokens = client.getAllTokens();
66
66
  expect(tokens).toStrictEqual([
67
67
  { region: 'us', token: 'accessToken' },
68
- { region: 'eu', token: 'eu-accessToken' }
68
+ { region: 'eu', token: 'eu-accessToken' },
69
69
  ]);
70
70
  spy.mockRestore();
71
71
  });
72
72
 
73
73
  it('should resolve valid tokens data', async () => {
74
74
  let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation(() => {
75
- return { us: "accessToken", eu: "eu-accessToken" }
75
+ return { us: 'accessToken', eu: 'eu-accessToken' };
76
76
  });
77
77
  const client = new RedoclyClient();
78
78
  const tokens = await client.getValidTokens();
79
79
  expect(tokens).toStrictEqual([
80
80
  { region: 'us', token: 'accessToken', valid: true },
81
- { region: 'eu', token: 'eu-accessToken', valid: true }
81
+ { region: 'eu', token: 'eu-accessToken', valid: true },
82
82
  ]);
83
83
  spy.mockRestore();
84
84
  });
85
85
 
86
86
  it('should not call setAccessTokens by default', () => {
87
- let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation(() => ({}));
87
+ let spy = jest
88
+ .spyOn(RedoclyClient.prototype, 'readCredentialsFile')
89
+ .mockImplementation(() => ({}));
88
90
  jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
89
91
  const client = new RedoclyClient();
90
- expect(client.setAccessTokens).not.toHaveBeenCalled()
92
+ expect(client.setAccessTokens).not.toHaveBeenCalled();
91
93
  spy.mockRestore();
92
94
  });
93
95
 
94
96
  it('should set correct accessTokens - backward compatibility: default US region', () => {
95
- let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation(() => ({ token: testToken }));
97
+ let spy = jest
98
+ .spyOn(RedoclyClient.prototype, 'readCredentialsFile')
99
+ .mockImplementation(() => ({ token: testToken }));
96
100
  jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
97
101
  const client = new RedoclyClient();
98
- expect(client.setAccessTokens).toBeCalledWith(
99
- expect.objectContaining({ us: testToken })
100
- );
102
+ expect(client.setAccessTokens).toBeCalledWith(expect.objectContaining({ us: testToken }));
101
103
  spy.mockRestore();
102
104
  });
103
105
 
104
106
  it('should set correct accessTokens - backward compatibility: EU region', () => {
105
- let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation(() => ({ token: testToken }));
107
+ let spy = jest
108
+ .spyOn(RedoclyClient.prototype, 'readCredentialsFile')
109
+ .mockImplementation(() => ({ token: testToken }));
106
110
  jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
107
111
  const client = new RedoclyClient('eu');
108
- expect(client.setAccessTokens).toBeCalledWith(
109
- expect.objectContaining({ eu: testToken })
110
- );
112
+ expect(client.setAccessTokens).toBeCalledWith(expect.objectContaining({ eu: testToken }));
111
113
  spy.mockRestore();
112
114
  });
113
115
 
@@ -116,25 +118,29 @@ describe('RedoclyClient', () => {
116
118
  let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation();
117
119
  jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
118
120
  const client = new RedoclyClient();
119
- expect(client.setAccessTokens).toHaveBeenNthCalledWith(1, { "us": REDOCLY_AUTHORIZATION_TOKEN });
121
+ expect(client.setAccessTokens).toHaveBeenNthCalledWith(1, { us: REDOCLY_AUTHORIZATION_TOKEN });
120
122
  spy.mockRestore();
121
123
  });
122
124
 
123
125
  it('should set correct accessTokens prioritizing REDOCLY_AUTHORIZATION env over token in file', () => {
124
126
  process.env.REDOCLY_AUTHORIZATION = REDOCLY_AUTHORIZATION_TOKEN;
125
- let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation(() => ({ token: testToken }));
127
+ let spy = jest
128
+ .spyOn(RedoclyClient.prototype, 'readCredentialsFile')
129
+ .mockImplementation(() => ({ token: testToken }));
126
130
  jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
127
131
  const client = new RedoclyClient();
128
- expect(client.setAccessTokens).toHaveBeenNthCalledWith(2, { "us": REDOCLY_AUTHORIZATION_TOKEN });
132
+ expect(client.setAccessTokens).toHaveBeenNthCalledWith(2, { us: REDOCLY_AUTHORIZATION_TOKEN });
129
133
  spy.mockRestore();
130
134
  });
131
135
 
132
136
  it('should set correct accessTokens prioritizing REDOCLY_AUTHORIZATION env over EU token', () => {
133
137
  process.env.REDOCLY_AUTHORIZATION = REDOCLY_AUTHORIZATION_TOKEN;
134
- let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation(() => ({ us: testToken }));
138
+ let spy = jest
139
+ .spyOn(RedoclyClient.prototype, 'readCredentialsFile')
140
+ .mockImplementation(() => ({ us: testToken }));
135
141
  jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
136
142
  const client = new RedoclyClient('eu');
137
- expect(client.setAccessTokens).toHaveBeenNthCalledWith(2, { "eu": REDOCLY_AUTHORIZATION_TOKEN });
143
+ expect(client.setAccessTokens).toHaveBeenNthCalledWith(2, { eu: REDOCLY_AUTHORIZATION_TOKEN });
138
144
  spy.mockRestore();
139
145
  });
140
146
  });