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

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 (159) hide show
  1. package/README.md +2 -2
  2. package/lib/benchmark/benches/resolve-with-no-external.bench.js +1 -1
  3. package/lib/bundle.d.ts +1 -1
  4. package/lib/bundle.js +4 -4
  5. package/lib/config/all.js +3 -1
  6. package/lib/config/config-resolvers.js +22 -4
  7. package/lib/config/config.d.ts +1 -0
  8. package/lib/config/config.js +1 -0
  9. package/lib/config/load.d.ts +8 -2
  10. package/lib/config/load.js +4 -2
  11. package/lib/config/minimal.js +3 -1
  12. package/lib/config/recommended.js +3 -1
  13. package/lib/config/rules.js +1 -1
  14. package/lib/config/types.d.ts +17 -0
  15. package/lib/config/utils.d.ts +2 -2
  16. package/lib/config/utils.js +44 -6
  17. package/lib/decorators/common/registry-dependencies.js +1 -1
  18. package/lib/format/format.d.ts +1 -1
  19. package/lib/format/format.js +22 -1
  20. package/lib/lint.js +2 -2
  21. package/lib/redocly/registry-api.d.ts +0 -1
  22. package/lib/redocly/registry-api.js +5 -4
  23. package/lib/resolve.js +3 -1
  24. package/lib/rules/ajv.d.ts +1 -1
  25. package/lib/rules/ajv.js +5 -5
  26. package/lib/rules/common/assertions/asserts.d.ts +3 -5
  27. package/lib/rules/common/assertions/asserts.js +137 -97
  28. package/lib/rules/common/assertions/index.js +2 -6
  29. package/lib/rules/common/assertions/utils.d.ts +12 -6
  30. package/lib/rules/common/assertions/utils.js +33 -20
  31. package/lib/rules/common/no-ambiguous-paths.js +1 -1
  32. package/lib/rules/common/no-identical-paths.js +1 -1
  33. package/lib/rules/common/operation-2xx-response.js +1 -1
  34. package/lib/rules/common/operation-4xx-response.js +1 -1
  35. package/lib/rules/common/operation-operationId.js +1 -1
  36. package/lib/rules/common/operation-tag-defined.js +1 -1
  37. package/lib/rules/common/path-not-include-query.js +1 -1
  38. package/lib/rules/common/security-defined.d.ts +2 -0
  39. package/lib/rules/common/{operation-security-defined.js → security-defined.js} +18 -4
  40. package/lib/rules/common/spec.js +12 -1
  41. package/lib/rules/common/tags-alphabetical.js +1 -1
  42. package/lib/rules/oas2/index.d.ts +1 -1
  43. package/lib/rules/oas2/index.js +2 -2
  44. package/lib/rules/oas2/remove-unused-components.js +1 -1
  45. package/lib/rules/oas2/request-mime-type.js +1 -1
  46. package/lib/rules/oas2/response-mime-type.js +1 -1
  47. package/lib/rules/oas3/index.js +6 -2
  48. package/lib/rules/oas3/no-empty-servers.js +1 -1
  49. package/lib/rules/oas3/no-server-variables-empty-enum.js +1 -1
  50. package/lib/rules/oas3/no-unused-components.js +1 -1
  51. package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.d.ts +5 -0
  52. package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.js +36 -0
  53. package/lib/rules/oas3/remove-unused-components.js +1 -1
  54. package/lib/rules/oas3/request-mime-type.js +1 -1
  55. package/lib/rules/oas3/response-mime-type.js +1 -1
  56. package/lib/rules/oas3/spec-components-invalid-map-name.d.ts +2 -0
  57. package/lib/rules/oas3/spec-components-invalid-map-name.js +46 -0
  58. package/lib/rules/other/stats.d.ts +2 -2
  59. package/lib/rules/other/stats.js +2 -2
  60. package/lib/rules/utils.js +1 -1
  61. package/lib/types/oas2.js +5 -5
  62. package/lib/types/oas3.js +27 -20
  63. package/lib/types/oas3_1.js +3 -3
  64. package/lib/types/redocly-yaml.js +60 -54
  65. package/lib/utils.d.ts +3 -3
  66. package/lib/utils.js +5 -5
  67. package/lib/visitors.d.ts +11 -11
  68. package/lib/visitors.js +13 -1
  69. package/package.json +3 -5
  70. package/src/__tests__/__snapshots__/bundle.test.ts.snap +3 -3
  71. package/src/__tests__/fixtures/extension.js +3 -3
  72. package/src/__tests__/format.test.ts +76 -0
  73. package/src/__tests__/lint.test.ts +184 -121
  74. package/src/__tests__/resolve-http.test.ts +1 -1
  75. package/src/__tests__/resolve.test.ts +9 -9
  76. package/src/__tests__/walk.test.ts +78 -10
  77. package/src/benchmark/benches/resolve-with-no-external.bench.ts +1 -1
  78. package/src/bundle.ts +4 -4
  79. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +6 -2
  80. package/src/config/__tests__/config-resolvers.test.ts +37 -1
  81. package/src/config/__tests__/config.test.ts +5 -0
  82. package/src/config/__tests__/fixtures/plugin-config.yaml +2 -3
  83. package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +11 -12
  84. package/src/config/__tests__/fixtures/resolve-config/local-config-with-circular.yaml +7 -8
  85. package/src/config/__tests__/fixtures/resolve-config/local-config-with-custom-function.yaml +16 -0
  86. package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +18 -19
  87. package/src/config/__tests__/fixtures/resolve-config/local-config-with-wrong-custom-function.yaml +16 -0
  88. package/src/config/__tests__/fixtures/resolve-config/local-config.yaml +9 -10
  89. package/src/config/__tests__/fixtures/resolve-config/plugin.js +11 -0
  90. package/src/config/__tests__/fixtures/resolve-remote-configs/nested-remote-config.yaml +3 -4
  91. package/src/config/__tests__/fixtures/resolve-remote-configs/remote-config.yaml +4 -5
  92. package/src/config/__tests__/load.test.ts +13 -16
  93. package/src/config/__tests__/resolve-plugins.test.ts +3 -3
  94. package/src/config/__tests__/utils.test.ts +64 -4
  95. package/src/config/all.ts +3 -1
  96. package/src/config/config-resolvers.ts +30 -7
  97. package/src/config/config.ts +2 -0
  98. package/src/config/load.ts +13 -6
  99. package/src/config/minimal.ts +3 -1
  100. package/src/config/recommended.ts +3 -1
  101. package/src/config/rules.ts +2 -2
  102. package/src/config/types.ts +24 -0
  103. package/src/config/utils.ts +103 -13
  104. package/src/decorators/common/registry-dependencies.ts +1 -1
  105. package/src/format/format.ts +32 -2
  106. package/src/lint.ts +2 -2
  107. package/src/redocly/registry-api.ts +5 -4
  108. package/src/resolve.ts +3 -1
  109. package/src/rules/__tests__/utils.test.ts +1 -1
  110. package/src/rules/ajv.ts +4 -4
  111. package/src/rules/common/__tests__/no-enum-type-mismatch.test.ts +1 -0
  112. package/src/rules/common/__tests__/operation-2xx-response.test.ts +1 -1
  113. package/src/rules/common/__tests__/operation-4xx-response.test.ts +26 -3
  114. package/src/rules/common/__tests__/security-defined.test.ts +175 -0
  115. package/src/rules/common/__tests__/spec.test.ts +79 -0
  116. package/src/rules/common/assertions/__tests__/asserts.test.ts +491 -428
  117. package/src/rules/common/assertions/__tests__/utils.test.ts +2 -2
  118. package/src/rules/common/assertions/asserts.ts +155 -97
  119. package/src/rules/common/assertions/index.ts +2 -11
  120. package/src/rules/common/assertions/utils.ts +66 -36
  121. package/src/rules/common/no-ambiguous-paths.ts +1 -1
  122. package/src/rules/common/no-identical-paths.ts +1 -1
  123. package/src/rules/common/operation-2xx-response.ts +1 -1
  124. package/src/rules/common/operation-4xx-response.ts +1 -1
  125. package/src/rules/common/operation-operationId.ts +1 -1
  126. package/src/rules/common/operation-tag-defined.ts +1 -1
  127. package/src/rules/common/path-not-include-query.ts +1 -1
  128. package/src/rules/common/{operation-security-defined.ts → security-defined.ts} +19 -4
  129. package/src/rules/common/spec.ts +15 -1
  130. package/src/rules/common/tags-alphabetical.ts +1 -1
  131. package/src/rules/oas2/index.ts +2 -2
  132. package/src/rules/oas2/remove-unused-components.ts +1 -1
  133. package/src/rules/oas2/request-mime-type.ts +1 -1
  134. package/src/rules/oas2/response-mime-type.ts +1 -1
  135. package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +51 -2
  136. package/src/rules/oas3/__tests__/operation-4xx-problem-details-rfc7807.test.ts +145 -0
  137. package/src/rules/oas3/__tests__/spec/spec.test.ts +10 -0
  138. package/src/rules/oas3/__tests__/spec-components-invalid-map-name.test.ts +217 -0
  139. package/src/rules/oas3/index.ts +6 -2
  140. package/src/rules/oas3/no-empty-servers.ts +1 -1
  141. package/src/rules/oas3/no-server-variables-empty-enum.ts +1 -1
  142. package/src/rules/oas3/no-unused-components.ts +1 -1
  143. package/src/rules/oas3/operation-4xx-problem-details-rfc7807.ts +36 -0
  144. package/src/rules/oas3/remove-unused-components.ts +1 -1
  145. package/src/rules/oas3/request-mime-type.ts +1 -1
  146. package/src/rules/oas3/response-mime-type.ts +1 -1
  147. package/src/rules/oas3/spec-components-invalid-map-name.ts +53 -0
  148. package/src/rules/other/stats.ts +2 -2
  149. package/src/rules/utils.ts +2 -1
  150. package/src/types/index.ts +2 -2
  151. package/src/types/oas2.ts +5 -5
  152. package/src/types/oas3.ts +27 -20
  153. package/src/types/oas3_1.ts +3 -3
  154. package/src/types/redocly-yaml.ts +66 -38
  155. package/src/utils.ts +11 -7
  156. package/src/visitors.ts +29 -13
  157. package/tsconfig.tsbuildinfo +1 -1
  158. package/lib/rules/common/operation-security-defined.d.ts +0 -2
  159. package/src/rules/common/__tests__/operation-security-defined.test.ts +0 -69
package/README.md CHANGED
@@ -10,7 +10,7 @@ See https://github.com/Redocly/redocly-cli
10
10
  import { formatProblems, lint, loadConfig } from '@redocly/openapi-core';
11
11
 
12
12
  const pathToApi = 'openapi.yaml';
13
- const config = loadConfig('optional/path/to/.redocly.yaml');
13
+ const config = loadConfig({ configPath: 'optional/path/to/.redocly.yaml' });
14
14
  const lintResults = await lint({ ref: pathToApi, config });
15
15
  ```
16
16
 
@@ -20,6 +20,6 @@ const lintResults = await lint({ ref: pathToApi, config });
20
20
  import { formatProblems, bundle, loadConfig } from '@redocly/openapi-core';
21
21
 
22
22
  const pathToApi = 'openapi.yaml';
23
- const config = loadConfig('optional/path/to/.redocly.yaml');
23
+ const config = loadConfig({ configPath: 'optional/path/to/.redocly.yaml' });
24
24
  const { bundle, problems } = await bundle({ ref: pathToApi, config });
25
25
  ```
@@ -16,7 +16,7 @@ function measureAsync() {
16
16
  return resolve_1.resolveDocument({
17
17
  rootDocument: rebillyDocument,
18
18
  externalRefResolver,
19
- rootType: types_1.normalizeTypes(oas3_1.Oas3Types).DefinitionRoot,
19
+ rootType: types_1.normalizeTypes(oas3_1.Oas3Types).Root,
20
20
  });
21
21
  }
22
22
  exports.measureAsync = measureAsync;
package/lib/bundle.d.ts CHANGED
@@ -44,4 +44,4 @@ export declare function bundleDocument(opts: {
44
44
  refTypes: Map<string, NormalizedNodeType> | undefined;
45
45
  visitorsData: Record<string, Record<string, unknown>>;
46
46
  }>;
47
- export declare function mapTypeToComponent(typeName: string, version: OasMajorVersion): "headers" | "definitions" | "parameters" | "examples" | "responses" | "schemas" | "requestBodies" | "securitySchemes" | "links" | "callbacks" | null;
47
+ export declare function mapTypeToComponent(typeName: string, version: OasMajorVersion): "headers" | "definitions" | "parameters" | "examples" | "responses" | "schemas" | "requestBodies" | "links" | "callbacks" | "securitySchemes" | null;
package/lib/bundle.js CHANGED
@@ -76,7 +76,7 @@ function bundleDocument(opts) {
76
76
  }
77
77
  const resolvedRefMap = yield resolve_1.resolveDocument({
78
78
  rootDocument: document,
79
- rootType: types.DefinitionRoot,
79
+ rootType: types.Root,
80
80
  externalRefResolver,
81
81
  });
82
82
  const bundleVisitor = visitors_1.normalizeVisitors([
@@ -90,7 +90,7 @@ function bundleDocument(opts) {
90
90
  ], types);
91
91
  walk_1.walkDocument({
92
92
  document,
93
- rootType: types.DefinitionRoot,
93
+ rootType: types.Root,
94
94
  normalizedVisitors: bundleVisitor,
95
95
  resolvedRefMap,
96
96
  ctx,
@@ -99,7 +99,7 @@ function bundleDocument(opts) {
99
99
  bundle: document,
100
100
  problems: ctx.problems.map((problem) => config.addProblemToIgnore(problem)),
101
101
  fileDependencies: externalRefResolver.getFiles(),
102
- rootType: types.DefinitionRoot,
102
+ rootType: types.Root,
103
103
  refTypes: ctx.refTypes,
104
104
  visitorsData: ctx.visitorsData,
105
105
  };
@@ -184,7 +184,7 @@ function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDo
184
184
  }
185
185
  },
186
186
  },
187
- DefinitionRoot: {
187
+ Root: {
188
188
  enter(root) {
189
189
  if (version === oas_types_1.OasMajorVersion.Version3) {
190
190
  components = root.components = root.components || {};
package/lib/config/all.js CHANGED
@@ -26,7 +26,7 @@ exports.default = {
26
26
  'operation-operationId-url-safe': 'error',
27
27
  'operation-parameters-unique': 'error',
28
28
  'operation-tag-defined': 'error',
29
- 'operation-security-defined': 'error',
29
+ 'security-defined': 'error',
30
30
  'operation-singular-tag': 'error',
31
31
  'no-unresolved-refs': 'error',
32
32
  'no-enum-type-mismatch': 'error',
@@ -52,6 +52,7 @@ exports.default = {
52
52
  'no-unused-components': 'error',
53
53
  'no-undefined-server-variable': 'error',
54
54
  'no-server-variables-empty-enum': 'error',
55
+ 'operation-4xx-problem-details-rfc7807': 'error',
55
56
  },
56
57
  oas3_1Rules: {
57
58
  'no-server-example.com': 'error',
@@ -61,5 +62,6 @@ exports.default = {
61
62
  'no-unused-components': 'error',
62
63
  'no-undefined-server-variable': 'error',
63
64
  'no-server-variables-empty-enum': 'error',
65
+ 'operation-4xx-problem-details-rfc7807': 'error',
64
66
  },
65
67
  };
@@ -30,6 +30,7 @@ const env_1 = require("../env");
30
30
  const utils_2 = require("../utils");
31
31
  const config_1 = require("./config");
32
32
  const logger_1 = require("../logger");
33
+ const asserts_1 = require("../rules/common/assertions/asserts");
33
34
  function resolveConfig(rawConfig, configPath) {
34
35
  var _a, _b, _c, _d, _e;
35
36
  return __awaiter(this, void 0, void 0, function* () {
@@ -133,9 +134,12 @@ function resolvePlugins(plugins, configPath = '') {
133
134
  plugin.decorators.oas2 = utils_1.prefixRules(pluginModule.decorators.oas2, id);
134
135
  }
135
136
  }
137
+ if (pluginModule.assertions) {
138
+ plugin.assertions = pluginModule.assertions;
139
+ }
136
140
  return plugin;
137
141
  })
138
- .filter(utils_2.notUndefined);
142
+ .filter(utils_2.isDefined);
139
143
  }
140
144
  exports.resolvePlugins = resolvePlugins;
141
145
  function resolveApis({ rawConfig, configPath = '', resolver, }) {
@@ -196,8 +200,7 @@ function resolveAndMergeNestedStyleguideConfig({ styleguideConfig, configPath =
196
200
  function resolveStyleguideConfig(opts, parentConfigPaths = [], extendPaths = []) {
197
201
  return __awaiter(this, void 0, void 0, function* () {
198
202
  const resolvedStyleguideConfig = yield resolveAndMergeNestedStyleguideConfig(opts, parentConfigPaths, extendPaths);
199
- return Object.assign(Object.assign({}, resolvedStyleguideConfig), { rules: resolvedStyleguideConfig.rules &&
200
- groupStyleguideAssertionRules(resolvedStyleguideConfig.rules) });
203
+ return Object.assign(Object.assign({}, resolvedStyleguideConfig), { rules: resolvedStyleguideConfig.rules && groupStyleguideAssertionRules(resolvedStyleguideConfig) });
201
204
  });
202
205
  }
203
206
  exports.resolveStyleguideConfig = resolveStyleguideConfig;
@@ -238,7 +241,7 @@ function getMergedRawStyleguideConfig(rootStyleguideConfig, apiStyleguideConfig)
238
241
  : rootStyleguideConfig.recommendedFallback });
239
242
  return resultLint;
240
243
  }
241
- function groupStyleguideAssertionRules(rules) {
244
+ function groupStyleguideAssertionRules({ rules, plugins, }) {
242
245
  if (!rules) {
243
246
  return rules;
244
247
  }
@@ -249,6 +252,21 @@ function groupStyleguideAssertionRules(rules) {
249
252
  for (const [ruleKey, rule] of Object.entries(rules)) {
250
253
  if (ruleKey.startsWith('assert/') && typeof rule === 'object' && rule !== null) {
251
254
  const assertion = rule;
255
+ if (plugins) {
256
+ for (const field of Object.keys(assertion)) {
257
+ const [pluginId, fn] = field.split('/');
258
+ if (!pluginId || !fn)
259
+ continue;
260
+ const plugin = plugins.find((plugin) => plugin.id === pluginId);
261
+ if (!plugin) {
262
+ throw Error(logger_1.colorize.red(`Plugin ${logger_1.colorize.blue(pluginId)} isn't found.`));
263
+ }
264
+ if (!plugin.assertions || !plugin.assertions[fn]) {
265
+ throw Error(`Plugin ${logger_1.colorize.red(pluginId)} doesn't export assertions function with name ${logger_1.colorize.red(fn)}.`);
266
+ }
267
+ asserts_1.asserts[field] = asserts_1.buildAssertCustomFunction(plugin.assertions[fn]);
268
+ }
269
+ }
252
270
  assertions.push(Object.assign(Object.assign({}, assertion), { assertionId: ruleKey.replace('assert/', '') }));
253
271
  }
254
272
  else {
@@ -59,5 +59,6 @@ export declare class Config {
59
59
  'features.openapi': Record<string, any>;
60
60
  'features.mockServer'?: Record<string, any>;
61
61
  organization?: string;
62
+ files: string[];
62
63
  constructor(rawConfig: ResolvedConfig, configFile?: string | undefined);
63
64
  }
@@ -249,6 +249,7 @@ class Config {
249
249
  this.resolve = utils_2.getResolveConfig(rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.resolve);
250
250
  this.region = rawConfig.region;
251
251
  this.organization = rawConfig.organization;
252
+ this.files = rawConfig.files || [];
252
253
  }
253
254
  }
254
255
  exports.Config = Config;
@@ -1,7 +1,13 @@
1
1
  import { Config } from './config';
2
- import type { RawConfig } from './types';
2
+ import type { RawConfig, Region } from './types';
3
3
  import { RegionalTokenWithValidity } from '../redocly/redocly-client-types';
4
- export declare function loadConfig(configPath?: string | undefined, customExtends?: string[], processRawConfig?: (rawConfig: RawConfig) => void | Promise<void>): Promise<Config>;
4
+ export declare function loadConfig(options?: {
5
+ configPath?: string;
6
+ customExtends?: string[];
7
+ processRawConfig?: (rawConfig: RawConfig) => void | Promise<void>;
8
+ files?: string[];
9
+ region?: Region;
10
+ }): Promise<Config>;
5
11
  export declare const CONFIG_FILE_NAMES: string[];
6
12
  export declare function findConfig(dir?: string): string | undefined;
7
13
  export declare function getConfig(configPath?: string | undefined): Promise<RawConfig>;
@@ -59,9 +59,11 @@ function addConfigMetadata({ rawConfig, customExtends, configPath, tokens, }) {
59
59
  return config_resolvers_1.resolveConfig(rawConfig, configPath);
60
60
  });
61
61
  }
62
- function loadConfig(configPath = findConfig(), customExtends, processRawConfig) {
62
+ function loadConfig(options = {}) {
63
63
  return __awaiter(this, void 0, void 0, function* () {
64
- const rawConfig = yield getConfig(configPath);
64
+ const { configPath = findConfig(), customExtends, processRawConfig, files, region } = options;
65
+ const config = yield getConfig(configPath);
66
+ const rawConfig = Object.assign(Object.assign({}, config), { files: files !== null && files !== void 0 ? files : config.files, region: region !== null && region !== void 0 ? region : config.region });
65
67
  if (typeof processRawConfig === 'function') {
66
68
  yield processRawConfig(rawConfig);
67
69
  }
@@ -24,7 +24,7 @@ exports.default = {
24
24
  'operation-operationId-unique': 'warn',
25
25
  'operation-parameters-unique': 'warn',
26
26
  'operation-tag-defined': 'off',
27
- 'operation-security-defined': 'warn',
27
+ 'security-defined': 'warn',
28
28
  'operation-operationId-url-safe': 'warn',
29
29
  'operation-singular-tag': 'off',
30
30
  'no-unresolved-refs': 'error',
@@ -45,6 +45,7 @@ exports.default = {
45
45
  'no-unused-components': 'warn',
46
46
  'no-undefined-server-variable': 'warn',
47
47
  'no-server-variables-empty-enum': 'error',
48
+ 'spec-components-invalid-map-name': 'warn',
48
49
  },
49
50
  oas3_1Rules: {
50
51
  'no-invalid-media-type-examples': 'warn',
@@ -55,5 +56,6 @@ exports.default = {
55
56
  'no-unused-components': 'warn',
56
57
  'no-undefined-server-variable': 'warn',
57
58
  'no-server-variables-empty-enum': 'error',
59
+ 'spec-components-invalid-map-name': 'warn',
58
60
  },
59
61
  };
@@ -25,7 +25,7 @@ exports.default = {
25
25
  'operation-operationId-url-safe': 'error',
26
26
  'operation-parameters-unique': 'error',
27
27
  'operation-tag-defined': 'off',
28
- 'operation-security-defined': 'error',
28
+ 'security-defined': 'error',
29
29
  'operation-singular-tag': 'off',
30
30
  'no-unresolved-refs': 'error',
31
31
  'no-enum-type-mismatch': 'error',
@@ -45,6 +45,7 @@ exports.default = {
45
45
  'no-unused-components': 'warn',
46
46
  'no-undefined-server-variable': 'error',
47
47
  'no-server-variables-empty-enum': 'error',
48
+ 'spec-components-invalid-map-name': 'error',
48
49
  },
49
50
  oas3_1Rules: {
50
51
  'no-invalid-media-type-examples': 'warn',
@@ -55,5 +56,6 @@ exports.default = {
55
56
  'no-unused-components': 'warn',
56
57
  'no-undefined-server-variable': 'error',
57
58
  'no-server-variables-empty-enum': 'error',
59
+ 'spec-components-invalid-map-name': 'error',
58
60
  },
59
61
  };
@@ -29,6 +29,6 @@ function initRules(rules, config, type, oasVersion) {
29
29
  };
30
30
  }))
31
31
  .flatMap((visitor) => visitor)
32
- .filter(utils_1.notUndefined);
32
+ .filter(utils_1.isDefined);
33
33
  }
34
34
  exports.initRules = initRules;
@@ -1,6 +1,7 @@
1
1
  import type { ProblemSeverity } from '../walk';
2
2
  import type { Oas3PreprocessorsSet, OasMajorVersion, Oas3DecoratorsSet, Oas2RuleSet, Oas2PreprocessorsSet, Oas2DecoratorsSet, Oas3RuleSet, OasVersion } from '../oas-types';
3
3
  import type { NodeType } from '../types';
4
+ import { Location } from '../ref-utils';
4
5
  export declare type RuleSeverity = ProblemSeverity | 'off';
5
6
  export declare type PreprocessorSeverity = RuleSeverity | 'on';
6
7
  export declare type RuleConfig = RuleSeverity | ({
@@ -50,6 +51,12 @@ export declare type CustomRulesConfig = {
50
51
  oas3?: Oas3RuleSet;
51
52
  oas2?: Oas2RuleSet;
52
53
  };
54
+ export declare type AssertResult = {
55
+ message?: string;
56
+ location?: Location;
57
+ };
58
+ export declare type CustomFunction = (value: any, options: unknown, baseLocation: Location) => AssertResult[];
59
+ export declare type AssertionsConfig = Record<string, CustomFunction>;
53
60
  export declare type Plugin = {
54
61
  id: string;
55
62
  configs?: Record<string, PluginStyleguideConfig>;
@@ -57,6 +64,7 @@ export declare type Plugin = {
57
64
  preprocessors?: PreprocessorsConfig;
58
65
  decorators?: DecoratorsConfig;
59
66
  typeExtension?: TypeExtensionsConfig;
67
+ assertions?: AssertionsConfig;
60
68
  };
61
69
  export declare type PluginStyleguideConfig = Omit<StyleguideRawConfig, 'plugins' | 'extends'>;
62
70
  export declare type ResolveHeader = {
@@ -72,6 +80,7 @@ export declare type ResolveHeader = {
72
80
  };
73
81
  export declare type RawResolveConfig = {
74
82
  http?: Partial<HttpResolveConfig>;
83
+ doNotResolveExamples?: boolean;
75
84
  };
76
85
  export declare type HttpResolveConfig = {
77
86
  headers: ResolveHeader[];
@@ -87,6 +96,7 @@ export declare type AccessTokens = {
87
96
  export declare type DeprecatedInRawConfig = {
88
97
  apiDefinitions?: Record<string, string>;
89
98
  lint?: StyleguideRawConfig;
99
+ styleguide?: StyleguideRawConfig;
90
100
  referenceDocs?: Record<string, any>;
91
101
  apis?: Record<string, Api & DeprecatedInApi>;
92
102
  };
@@ -99,6 +109,7 @@ export declare type DeprecatedInApi = {
99
109
  };
100
110
  export declare type ResolvedApi = Omit<Api, 'styleguide'> & {
101
111
  styleguide: ResolvedStyleguideConfig;
112
+ files?: string[];
102
113
  };
103
114
  export declare type RawConfig = {
104
115
  apis?: Record<string, Api>;
@@ -106,7 +117,13 @@ export declare type RawConfig = {
106
117
  resolve?: RawResolveConfig;
107
118
  region?: Region;
108
119
  organization?: string;
120
+ files?: string[];
109
121
  } & FeaturesConfig;
122
+ export declare type FlatApi = Omit<Api, 'styleguide'> & Omit<ApiStyleguideRawConfig, 'doNotResolveExamples'>;
123
+ export declare type FlatRawConfig = Omit<RawConfig, 'styleguide' | 'resolve' | 'apis'> & Omit<StyleguideRawConfig, 'doNotResolveExamples'> & {
124
+ resolve?: RawResolveConfig;
125
+ apis?: Record<string, FlatApi>;
126
+ };
110
127
  export declare type ResolvedConfig = Omit<RawConfig, 'apis' | 'styleguide'> & {
111
128
  apis: Record<string, ResolvedApi>;
112
129
  styleguide: ResolvedStyleguideConfig;
@@ -1,5 +1,5 @@
1
1
  import { Config } from './config';
2
- import type { Api, DeprecatedInRawConfig, Plugin, RawConfig, RawResolveConfig, ResolveConfig, ResolvedStyleguideConfig, RulesFields } from './types';
2
+ import type { Api, DeprecatedInRawConfig, FlatRawConfig, Plugin, RawConfig, RawResolveConfig, ResolveConfig, ResolvedStyleguideConfig, RulesFields } from './types';
3
3
  export declare function parsePresetName(presetName: string): {
4
4
  pluginId: string;
5
5
  configName: string;
@@ -8,6 +8,6 @@ export declare function transformApiDefinitionsToApis(apiDefinitions?: Deprecate
8
8
  export declare function prefixRules<T extends Record<string, any>>(rules: T, prefix: string): any;
9
9
  export declare function mergeExtends(rulesConfList: ResolvedStyleguideConfig[]): Omit<ResolvedStyleguideConfig, RulesFields> & Required<Pick<ResolvedStyleguideConfig, RulesFields>>;
10
10
  export declare function getMergedConfig(config: Config, apiName?: string): Config;
11
- export declare function transformConfig(rawConfig: DeprecatedInRawConfig & RawConfig): RawConfig;
11
+ export declare function transformConfig(rawConfig: DeprecatedInRawConfig & RawConfig & FlatRawConfig): RawConfig;
12
12
  export declare function getResolveConfig(resolve?: RawResolveConfig): ResolveConfig;
13
13
  export declare function getUniquePlugins(plugins: Plugin[]): Plugin[];
@@ -35,13 +35,46 @@ function transformApiDefinitionsToApis(apiDefinitions) {
35
35
  return apis;
36
36
  }
37
37
  exports.transformApiDefinitionsToApis = transformApiDefinitionsToApis;
38
+ function extractFlatConfig(_a) {
39
+ var _b;
40
+ var { plugins, extends: _extends, rules, oas2Rules, oas3_0Rules, oas3_1Rules, preprocessors, oas2Preprocessors, oas3_0Preprocessors, oas3_1Preprocessors, decorators, oas2Decorators, oas3_0Decorators, oas3_1Decorators } = _a, rawConfigRest = __rest(_a, ["plugins", "extends", "rules", "oas2Rules", "oas3_0Rules", "oas3_1Rules", "preprocessors", "oas2Preprocessors", "oas3_0Preprocessors", "oas3_1Preprocessors", "decorators", "oas2Decorators", "oas3_0Decorators", "oas3_1Decorators"]);
41
+ const styleguideConfig = {
42
+ plugins,
43
+ extends: _extends,
44
+ rules,
45
+ oas2Rules,
46
+ oas3_0Rules,
47
+ oas3_1Rules,
48
+ preprocessors,
49
+ oas2Preprocessors,
50
+ oas3_0Preprocessors,
51
+ oas3_1Preprocessors,
52
+ decorators,
53
+ oas2Decorators,
54
+ oas3_0Decorators,
55
+ oas3_1Decorators,
56
+ doNotResolveExamples: (_b = rawConfigRest.resolve) === null || _b === void 0 ? void 0 : _b.doNotResolveExamples,
57
+ };
58
+ if ((rawConfigRest.lint && rawConfigRest.styleguide) ||
59
+ (Object.values(styleguideConfig).some(utils_1.isDefined) &&
60
+ (rawConfigRest.lint || rawConfigRest.styleguide))) {
61
+ throw new Error(`Do not use 'lint', 'styleguide' and flat syntax together. \nSee more about the configuration in the docs: https://redocly.com/docs/cli/configuration/ \n`);
62
+ }
63
+ return {
64
+ styleguideConfig: Object.values(styleguideConfig).some(utils_1.isDefined)
65
+ ? styleguideConfig
66
+ : undefined,
67
+ rawConfigRest,
68
+ };
69
+ }
38
70
  function transformApis(legacyApis) {
39
71
  if (!legacyApis)
40
72
  return undefined;
41
73
  const apis = {};
42
74
  for (let _a of Object.entries(legacyApis)) {
43
75
  const [apiName, _b] = _a, { lint } = _b, apiContent = __rest(_b, ["lint"]);
44
- apis[apiName] = Object.assign({ styleguide: lint }, apiContent);
76
+ const { styleguideConfig, rawConfigRest } = extractFlatConfig(apiContent);
77
+ apis[apiName] = Object.assign({ styleguide: styleguideConfig || lint }, rawConfigRest);
45
78
  }
46
79
  return apis;
47
80
  }
@@ -106,7 +139,7 @@ function mergeExtends(rulesConfList) {
106
139
  }
107
140
  exports.mergeExtends = mergeExtends;
108
141
  function getMergedConfig(config, apiName) {
109
- var _a, _b, _c, _d, _e, _f;
142
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
110
143
  const extendPaths = [
111
144
  ...Object.values(config.apis).map((api) => { var _a; return (_a = api === null || api === void 0 ? void 0 : api.styleguide) === null || _a === void 0 ? void 0 : _a.extendPaths; }),
112
145
  (_b = (_a = config.rawConfig) === null || _a === void 0 ? void 0 : _a.styleguide) === null || _b === void 0 ? void 0 : _b.extendPaths,
@@ -123,14 +156,17 @@ function getMergedConfig(config, apiName) {
123
156
  ? new config_1.Config(Object.assign(Object.assign({}, config.rawConfig), { styleguide: Object.assign(Object.assign({}, (config.apis[apiName]
124
157
  ? config.apis[apiName].styleguide
125
158
  : config.rawConfig.styleguide)), { extendPaths,
126
- pluginPaths }), 'features.openapi': Object.assign(Object.assign({}, config['features.openapi']), (_e = config.apis[apiName]) === null || _e === void 0 ? void 0 : _e['features.openapi']), 'features.mockServer': Object.assign(Object.assign({}, config['features.mockServer']), (_f = config.apis[apiName]) === null || _f === void 0 ? void 0 : _f['features.mockServer']) }), config.configFile)
159
+ pluginPaths }), 'features.openapi': Object.assign(Object.assign({}, config['features.openapi']), (_e = config.apis[apiName]) === null || _e === void 0 ? void 0 : _e['features.openapi']), 'features.mockServer': Object.assign(Object.assign({}, config['features.mockServer']), (_f = config.apis[apiName]) === null || _f === void 0 ? void 0 : _f['features.mockServer']), files: [...config.files, ...((_j = (_h = (_g = config.apis) === null || _g === void 0 ? void 0 : _g[apiName]) === null || _h === void 0 ? void 0 : _h.files) !== null && _j !== void 0 ? _j : [])] }), config.configFile)
127
160
  : config;
128
161
  }
129
162
  exports.getMergedConfig = getMergedConfig;
130
163
  function checkForDeprecatedFields(deprecatedField, updatedField, rawConfig) {
131
164
  const isDeprecatedFieldInApis = rawConfig.apis &&
132
165
  Object.values(rawConfig.apis).some((api) => api[deprecatedField]);
133
- if (rawConfig[deprecatedField] && rawConfig[updatedField]) {
166
+ if (rawConfig[deprecatedField] && updatedField === null) {
167
+ utils_1.showWarningForDeprecatedField(deprecatedField);
168
+ }
169
+ if (rawConfig[deprecatedField] && updatedField && rawConfig[updatedField]) {
134
170
  utils_1.showErrorForDeprecatedField(deprecatedField, updatedField);
135
171
  }
136
172
  if (rawConfig[deprecatedField] || isDeprecatedFieldInApis) {
@@ -141,13 +177,15 @@ function transformConfig(rawConfig) {
141
177
  const migratedFields = [
142
178
  ['apiDefinitions', 'apis'],
143
179
  ['referenceDocs', 'features.openapi'],
144
- ['lint', 'styleguide'], // TODO: update docs
180
+ ['lint', undefined],
181
+ ['styleguide', undefined],
145
182
  ];
146
183
  for (const [deprecatedField, updatedField] of migratedFields) {
147
184
  checkForDeprecatedFields(deprecatedField, updatedField, rawConfig);
148
185
  }
149
186
  const { apis, apiDefinitions, referenceDocs, lint } = rawConfig, rest = __rest(rawConfig, ["apis", "apiDefinitions", "referenceDocs", "lint"]);
150
- return Object.assign({ 'features.openapi': referenceDocs, apis: transformApis(apis) || transformApiDefinitionsToApis(apiDefinitions), styleguide: lint }, rest);
187
+ const { styleguideConfig, rawConfigRest } = extractFlatConfig(rest);
188
+ return Object.assign({ 'features.openapi': referenceDocs, apis: transformApis(apis) || transformApiDefinitionsToApis(apiDefinitions), styleguide: styleguideConfig || lint }, rawConfigRest);
151
189
  }
152
190
  exports.transformConfig = transformConfig;
153
191
  function getResolveConfig(resolve) {
@@ -5,7 +5,7 @@ const redocly_1 = require("../../redocly");
5
5
  const RegistryDependencies = () => {
6
6
  const registryDependencies = new Set();
7
7
  return {
8
- DefinitionRoot: {
8
+ Root: {
9
9
  leave(_, ctx) {
10
10
  const data = ctx.getVisitorData();
11
11
  data.links = Array.from(registryDependencies);
@@ -4,7 +4,7 @@ export declare type Totals = {
4
4
  warnings: number;
5
5
  ignored: number;
6
6
  };
7
- export declare type OutputFormat = 'codeframe' | 'stylish' | 'json' | 'checkstyle' | 'codeclimate';
7
+ export declare type OutputFormat = 'codeframe' | 'stylish' | 'json' | 'checkstyle' | 'codeclimate' | 'summary';
8
8
  export declare function getTotals(problems: (NormalizedProblem & {
9
9
  ignored?: boolean;
10
10
  })[]): Totals;
@@ -99,6 +99,9 @@ function formatProblems(problems, opts) {
99
99
  case 'codeclimate':
100
100
  outputForCodeClimate();
101
101
  break;
102
+ case 'summary':
103
+ formatSummary(problems);
104
+ break;
102
105
  }
103
106
  if (totalProblems - ignoredProblems > maxProblems) {
104
107
  logger_1.logger.info(`< ... ${totalProblems - maxProblems} more problems hidden > ${logger_1.colorize.gray('increase with `--max-problems N`')}\n`);
@@ -183,13 +186,31 @@ function formatProblems(problems, opts) {
183
186
  }
184
187
  }
185
188
  exports.formatProblems = formatProblems;
189
+ function formatSummary(problems) {
190
+ const counts = {};
191
+ for (const problem of problems) {
192
+ counts[problem.ruleId] = counts[problem.ruleId] || { count: 0, severity: problem.severity };
193
+ counts[problem.ruleId].count++;
194
+ }
195
+ const sorted = Object.entries(counts).sort(([, a], [, b]) => {
196
+ const severityDiff = severityToNumber(a.severity) - severityToNumber(b.severity);
197
+ return severityDiff || b.count - a.count;
198
+ });
199
+ for (const [ruleId, info] of sorted) {
200
+ const color = COLORS[info.severity];
201
+ const severityName = color(SEVERITY_NAMES[info.severity].toLowerCase().padEnd(7));
202
+ logger_1.logger.info(`${severityName} ${ruleId}: ${info.count}\n`);
203
+ }
204
+ logger_1.logger.info('\n');
205
+ }
186
206
  function formatFrom(cwd, location) {
187
207
  if (!location)
188
208
  return '';
189
209
  const relativePath = path.relative(cwd, location.source.absoluteRef);
190
210
  const loc = codeframes_1.getLineColLocation(location);
191
211
  const fileWithLoc = `${relativePath}:${loc.start.line}:${loc.start.col}`;
192
- return `referenced from ${logger_1.colorize.blue(fileWithLoc)}\n\n`;
212
+ const atPointer = location.pointer ? logger_1.colorize.gray(`at ${location.pointer}`) : '';
213
+ return `referenced from ${logger_1.colorize.blue(fileWithLoc)} ${atPointer} \n\n`;
193
214
  }
194
215
  function formatDidYouMean(problem) {
195
216
  if (problem.suggest.length === 0)
package/lib/lint.js CHANGED
@@ -60,12 +60,12 @@ function lintDocument(opts) {
60
60
  const normalizedVisitors = visitors_1.normalizeVisitors([...preprocessors, ...regularRules], types);
61
61
  const resolvedRefMap = yield resolve_1.resolveDocument({
62
62
  rootDocument: document,
63
- rootType: types.DefinitionRoot,
63
+ rootType: types.Root,
64
64
  externalRefResolver,
65
65
  });
66
66
  walk_1.walkDocument({
67
67
  document,
68
- rootType: types.DefinitionRoot,
68
+ rootType: types.Root,
69
69
  normalizedVisitors,
70
70
  resolvedRefMap,
71
71
  ctx,
@@ -1,6 +1,5 @@
1
1
  import type { PrepareFileuploadOKResponse, PrepareFileuploadParams, PushApiParams } from './registry-api-types';
2
2
  import type { AccessTokens, Region } from '../config/types';
3
- export declare const currentCommand: string;
4
3
  export declare class RegistryApi {
5
4
  private accessTokens;
6
5
  private region;
@@ -8,14 +8,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var _a;
12
11
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.RegistryApi = exports.currentCommand = void 0;
12
+ exports.RegistryApi = void 0;
14
13
  const node_fetch_1 = require("node-fetch");
15
14
  const config_1 = require("../config/config");
16
15
  const utils_1 = require("../utils");
17
16
  const version = require('../../package.json').version;
18
- exports.currentCommand = typeof process !== 'undefined' ? ((_a = process.env) === null || _a === void 0 ? void 0 : _a.REDOCLY_CLI_COMMAND) || '' : '';
19
17
  class RegistryApi {
20
18
  constructor(accessTokens, region) {
21
19
  this.accessTokens = accessTokens;
@@ -32,10 +30,13 @@ class RegistryApi {
32
30
  return this;
33
31
  }
34
32
  request(path = '', options = {}, region) {
33
+ var _a, _b;
35
34
  return __awaiter(this, void 0, void 0, function* () {
35
+ const currentCommand = typeof process !== 'undefined' ? ((_a = process.env) === null || _a === void 0 ? void 0 : _a.REDOCLY_CLI_COMMAND) || '' : '';
36
+ const redoclyEnv = typeof process !== 'undefined' ? ((_b = process.env) === null || _b === void 0 ? void 0 : _b.REDOCLY_ENVIRONMENT) || '' : '';
36
37
  const headers = Object.assign({}, options.headers || {}, {
37
38
  'x-redocly-cli-version': version,
38
- 'user-agent': `redocly-cli / ${version} ${exports.currentCommand}`,
39
+ 'user-agent': `redocly-cli / ${version} ${currentCommand} ${redoclyEnv}`,
39
40
  });
40
41
  if (!headers.hasOwnProperty('authorization')) {
41
42
  throw new Error('Unauthorized');
package/lib/resolve.js CHANGED
@@ -110,7 +110,9 @@ class BaseResolver {
110
110
  return new Source(absoluteRef, body, mimeType);
111
111
  }
112
112
  else {
113
- return new Source(absoluteRef, yield fs.promises.readFile(absoluteRef, 'utf-8'));
113
+ const content = yield fs.promises.readFile(absoluteRef, 'utf-8');
114
+ // In some cases file have \r\n line delimeters like on windows, we should skip it.
115
+ return new Source(absoluteRef, content.replace(/\r\n/g, '\n'));
114
116
  }
115
117
  }
116
118
  catch (error) {
@@ -1,4 +1,4 @@
1
- import { ErrorObject } from '@redocly/ajv';
1
+ import { ErrorObject } from '@redocly/ajv/dist/2020';
2
2
  import { Location } from '../ref-utils';
3
3
  import { ResolveFn } from '../walk';
4
4
  export declare function releaseAjvInstance(): void;
package/lib/rules/ajv.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validateJsonSchema = exports.releaseAjvInstance = void 0;
4
- const ajv_1 = require("@redocly/ajv");
4
+ const _2020_1 = require("@redocly/ajv/dist/2020");
5
5
  const ref_utils_1 = require("../ref-utils");
6
6
  let ajvInstance = null;
7
7
  function releaseAjvInstance() {
@@ -10,7 +10,7 @@ function releaseAjvInstance() {
10
10
  exports.releaseAjvInstance = releaseAjvInstance;
11
11
  function getAjv(resolve, allowAdditionalProperties) {
12
12
  if (!ajvInstance) {
13
- ajvInstance = new ajv_1.default({
13
+ ajvInstance = new _2020_1.default({
14
14
  schemaId: '$id',
15
15
  meta: true,
16
16
  allErrors: true,
@@ -20,7 +20,7 @@ function getAjv(resolve, allowAdditionalProperties) {
20
20
  discriminator: true,
21
21
  allowUnionTypes: true,
22
22
  validateFormats: false,
23
- defaultAdditionalProperties: allowAdditionalProperties,
23
+ defaultUnevaluatedProperties: allowAdditionalProperties,
24
24
  loadSchemaSync(base, $ref) {
25
25
  const resolvedRef = resolve({ $ref }, base.split('#')[0]);
26
26
  if (!resolvedRef || !resolvedRef.location)
@@ -68,8 +68,8 @@ function validateJsonSchema(data, schema, schemaLoc, instancePath, resolve, allo
68
68
  if (propName) {
69
69
  message = `\`${propName}\` property ${message}`;
70
70
  }
71
- if (error.keyword === 'additionalProperties') {
72
- const property = error.params.additionalProperty;
71
+ if (error.keyword === 'additionalProperties' || error.keyword === 'unevaluatedProperties') {
72
+ const property = error.params.additionalProperty || error.params.unevaluatedProperty;
73
73
  message = `${message} \`${property}\``;
74
74
  error.instancePath += '/' + ref_utils_1.escapePointer(property);
75
75
  }
@@ -1,10 +1,8 @@
1
+ import { AssertResult, CustomFunction } from 'core/src/config/types';
1
2
  import { Location } from '../../../ref-utils';
2
- declare type AssertResult = {
3
- isValid: boolean;
4
- location?: Location;
5
- };
6
- declare type Asserts = Record<string, (value: any, condition: any, baseLocation: Location, rawValue?: any) => AssertResult>;
3
+ declare type Asserts = Record<string, (value: any, condition: any, baseLocation: Location, rawValue?: any) => AssertResult[]>;
7
4
  export declare const runOnKeysSet: Set<string>;
8
5
  export declare const runOnValuesSet: Set<string>;
9
6
  export declare const asserts: Asserts;
7
+ export declare function buildAssertCustomFunction(fn: CustomFunction): (value: string[], options: any, baseLocation: Location) => any;
10
8
  export {};