@redocly/openapi-core 1.0.0-beta.109 → 1.0.0-beta.111

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 (88) hide show
  1. package/README.md +2 -2
  2. package/lib/config/config-resolvers.js +44 -25
  3. package/lib/config/config.d.ts +1 -0
  4. package/lib/config/config.js +1 -0
  5. package/lib/config/load.d.ts +8 -2
  6. package/lib/config/load.js +4 -2
  7. package/lib/config/types.d.ts +10 -0
  8. package/lib/config/utils.js +2 -2
  9. package/lib/rules/ajv.d.ts +1 -1
  10. package/lib/rules/ajv.js +5 -5
  11. package/lib/rules/common/assertions/asserts.d.ts +3 -5
  12. package/lib/rules/common/assertions/asserts.js +137 -97
  13. package/lib/rules/common/assertions/index.js +2 -6
  14. package/lib/rules/common/assertions/utils.d.ts +12 -6
  15. package/lib/rules/common/assertions/utils.js +33 -20
  16. package/lib/rules/common/no-ambiguous-paths.js +1 -1
  17. package/lib/rules/common/no-identical-paths.js +4 -4
  18. package/lib/rules/common/operation-2xx-response.js +2 -2
  19. package/lib/rules/common/operation-4xx-response.js +2 -2
  20. package/lib/rules/common/path-not-include-query.js +1 -1
  21. package/lib/rules/common/path-params-defined.js +7 -2
  22. package/lib/rules/common/response-contains-header.js +2 -2
  23. package/lib/rules/common/security-defined.js +10 -5
  24. package/lib/rules/common/spec.js +14 -12
  25. package/lib/rules/oas3/request-mime-type.js +1 -1
  26. package/lib/rules/oas3/response-mime-type.js +1 -1
  27. package/lib/rules/other/stats.d.ts +1 -1
  28. package/lib/rules/other/stats.js +1 -1
  29. package/lib/rules/utils.d.ts +1 -0
  30. package/lib/rules/utils.js +18 -2
  31. package/lib/types/oas2.js +6 -6
  32. package/lib/types/oas3.js +11 -11
  33. package/lib/types/oas3_1.js +3 -3
  34. package/lib/types/redocly-yaml.js +30 -5
  35. package/lib/utils.d.ts +1 -0
  36. package/lib/utils.js +13 -1
  37. package/lib/visitors.d.ts +7 -6
  38. package/lib/visitors.js +11 -3
  39. package/package.json +3 -5
  40. package/src/__tests__/__snapshots__/bundle.test.ts.snap +1 -1
  41. package/src/__tests__/lint.test.ts +88 -0
  42. package/src/__tests__/utils.test.ts +11 -0
  43. package/src/__tests__/walk.test.ts +2 -2
  44. package/src/config/__tests__/config-resolvers.test.ts +62 -1
  45. package/src/config/__tests__/config.test.ts +5 -0
  46. package/src/config/__tests__/fixtures/resolve-config/local-config-with-custom-function.yaml +16 -0
  47. package/src/config/__tests__/fixtures/resolve-config/local-config-with-wrong-custom-function.yaml +16 -0
  48. package/src/config/__tests__/fixtures/resolve-config/plugin.js +11 -0
  49. package/src/config/__tests__/load.test.ts +1 -1
  50. package/src/config/__tests__/resolve-plugins.test.ts +3 -3
  51. package/src/config/config-resolvers.ts +30 -6
  52. package/src/config/config.ts +2 -0
  53. package/src/config/load.ts +10 -4
  54. package/src/config/types.ts +13 -0
  55. package/src/config/utils.ts +1 -0
  56. package/src/rules/ajv.ts +4 -4
  57. package/src/rules/common/__tests__/operation-2xx-response.test.ts +37 -0
  58. package/src/rules/common/__tests__/operation-4xx-response.test.ts +37 -0
  59. package/src/rules/common/__tests__/path-params-defined.test.ts +69 -0
  60. package/src/rules/common/__tests__/security-defined.test.ts +6 -6
  61. package/src/rules/common/__tests__/spec.test.ts +125 -0
  62. package/src/rules/common/assertions/__tests__/asserts.test.ts +491 -428
  63. package/src/rules/common/assertions/__tests__/utils.test.ts +2 -2
  64. package/src/rules/common/assertions/asserts.ts +155 -97
  65. package/src/rules/common/assertions/index.ts +2 -11
  66. package/src/rules/common/assertions/utils.ts +66 -36
  67. package/src/rules/common/no-ambiguous-paths.ts +1 -1
  68. package/src/rules/common/no-identical-paths.ts +4 -4
  69. package/src/rules/common/operation-2xx-response.ts +2 -2
  70. package/src/rules/common/operation-4xx-response.ts +2 -2
  71. package/src/rules/common/path-not-include-query.ts +1 -1
  72. package/src/rules/common/path-params-defined.ts +9 -2
  73. package/src/rules/common/response-contains-header.ts +6 -1
  74. package/src/rules/common/security-defined.ts +10 -5
  75. package/src/rules/common/spec.ts +15 -11
  76. package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +51 -2
  77. package/src/rules/oas3/__tests__/response-contains-header.test.ts +116 -0
  78. package/src/rules/oas3/request-mime-type.ts +1 -1
  79. package/src/rules/oas3/response-mime-type.ts +1 -1
  80. package/src/rules/other/stats.ts +1 -1
  81. package/src/rules/utils.ts +24 -1
  82. package/src/types/oas2.ts +6 -6
  83. package/src/types/oas3.ts +11 -11
  84. package/src/types/oas3_1.ts +3 -3
  85. package/src/types/redocly-yaml.ts +30 -4
  86. package/src/utils.ts +13 -0
  87. package/src/visitors.ts +25 -10
  88. package/tsconfig.tsbuildinfo +1 -1
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
  ```
@@ -23,20 +23,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
23
23
  exports.resolvePreset = exports.resolveStyleguideConfig = exports.resolveApis = exports.resolvePlugins = exports.resolveConfig = void 0;
24
24
  const path = require("path");
25
25
  const ref_utils_1 = require("../ref-utils");
26
+ const utils_1 = require("../utils");
26
27
  const resolve_1 = require("../resolve");
27
28
  const builtIn_1 = require("./builtIn");
28
- const utils_1 = require("./utils");
29
+ const utils_2 = require("./utils");
29
30
  const env_1 = require("../env");
30
- const utils_2 = require("../utils");
31
+ const utils_3 = require("../utils");
31
32
  const config_1 = require("./config");
32
33
  const logger_1 = require("../logger");
34
+ const asserts_1 = require("../rules/common/assertions/asserts");
33
35
  function resolveConfig(rawConfig, configPath) {
34
36
  var _a, _b, _c, _d, _e;
35
37
  return __awaiter(this, void 0, void 0, function* () {
36
- if ((_b = (_a = rawConfig.styleguide) === null || _a === void 0 ? void 0 : _a.extends) === null || _b === void 0 ? void 0 : _b.some(utils_2.isNotString)) {
38
+ if ((_b = (_a = rawConfig.styleguide) === null || _a === void 0 ? void 0 : _a.extends) === null || _b === void 0 ? void 0 : _b.some(utils_3.isNotString)) {
37
39
  throw new Error(`Error configuration format not detected in extends value must contain strings`);
38
40
  }
39
- const resolver = new resolve_1.BaseResolver(utils_1.getResolveConfig(rawConfig.resolve));
41
+ const resolver = new resolve_1.BaseResolver(utils_2.getResolveConfig(rawConfig.resolve));
40
42
  const configExtends = (_d = (_c = rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.styleguide) === null || _c === void 0 ? void 0 : _c.extends) !== null && _d !== void 0 ? _d : ['recommended'];
41
43
  const recommendedFallback = !((_e = rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.styleguide) === null || _e === void 0 ? void 0 : _e.extends);
42
44
  const styleguideConfig = Object.assign(Object.assign({}, rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.styleguide), { extends: configExtends, recommendedFallback });
@@ -60,11 +62,11 @@ function resolvePlugins(plugins, configPath = '') {
60
62
  return [];
61
63
  // TODO: implement or reuse Resolver approach so it will work in node and browser envs
62
64
  const requireFunc = (plugin) => {
63
- if (env_1.isBrowser && utils_2.isString(plugin)) {
65
+ if (env_1.isBrowser && utils_3.isString(plugin)) {
64
66
  logger_1.logger.error(`Cannot load ${plugin}. Plugins aren't supported in browser yet.`);
65
67
  return undefined;
66
68
  }
67
- if (utils_2.isString(plugin)) {
69
+ if (utils_3.isString(plugin)) {
68
70
  const absoltePluginPath = path.resolve(path.dirname(configPath), plugin);
69
71
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
70
72
  // @ts-ignore
@@ -79,7 +81,7 @@ function resolvePlugins(plugins, configPath = '') {
79
81
  const seenPluginIds = new Map();
80
82
  return plugins
81
83
  .map((p) => {
82
- if (utils_2.isString(p) && ref_utils_1.isAbsoluteUrl(p)) {
84
+ if (utils_3.isString(p) && ref_utils_1.isAbsoluteUrl(p)) {
83
85
  throw new Error(logger_1.colorize.red(`We don't support remote plugins yet.`));
84
86
  }
85
87
  // TODO: resolve npm packages similar to eslint
@@ -103,10 +105,10 @@ function resolvePlugins(plugins, configPath = '') {
103
105
  }
104
106
  plugin.rules = {};
105
107
  if (pluginModule.rules.oas3) {
106
- plugin.rules.oas3 = utils_1.prefixRules(pluginModule.rules.oas3, id);
108
+ plugin.rules.oas3 = utils_2.prefixRules(pluginModule.rules.oas3, id);
107
109
  }
108
110
  if (pluginModule.rules.oas2) {
109
- plugin.rules.oas2 = utils_1.prefixRules(pluginModule.rules.oas2, id);
111
+ plugin.rules.oas2 = utils_2.prefixRules(pluginModule.rules.oas2, id);
110
112
  }
111
113
  }
112
114
  if (pluginModule.preprocessors) {
@@ -115,10 +117,10 @@ function resolvePlugins(plugins, configPath = '') {
115
117
  }
116
118
  plugin.preprocessors = {};
117
119
  if (pluginModule.preprocessors.oas3) {
118
- plugin.preprocessors.oas3 = utils_1.prefixRules(pluginModule.preprocessors.oas3, id);
120
+ plugin.preprocessors.oas3 = utils_2.prefixRules(pluginModule.preprocessors.oas3, id);
119
121
  }
120
122
  if (pluginModule.preprocessors.oas2) {
121
- plugin.preprocessors.oas2 = utils_1.prefixRules(pluginModule.preprocessors.oas2, id);
123
+ plugin.preprocessors.oas2 = utils_2.prefixRules(pluginModule.preprocessors.oas2, id);
122
124
  }
123
125
  }
124
126
  if (pluginModule.decorators) {
@@ -127,15 +129,18 @@ function resolvePlugins(plugins, configPath = '') {
127
129
  }
128
130
  plugin.decorators = {};
129
131
  if (pluginModule.decorators.oas3) {
130
- plugin.decorators.oas3 = utils_1.prefixRules(pluginModule.decorators.oas3, id);
132
+ plugin.decorators.oas3 = utils_2.prefixRules(pluginModule.decorators.oas3, id);
131
133
  }
132
134
  if (pluginModule.decorators.oas2) {
133
- plugin.decorators.oas2 = utils_1.prefixRules(pluginModule.decorators.oas2, id);
135
+ plugin.decorators.oas2 = utils_2.prefixRules(pluginModule.decorators.oas2, id);
134
136
  }
135
137
  }
138
+ if (pluginModule.assertions) {
139
+ plugin.assertions = pluginModule.assertions;
140
+ }
136
141
  return plugin;
137
142
  })
138
- .filter(utils_2.isDefined);
143
+ .filter(utils_3.isDefined);
139
144
  }
140
145
  exports.resolvePlugins = resolvePlugins;
141
146
  function resolveApis({ rawConfig, configPath = '', resolver, }) {
@@ -144,7 +149,7 @@ function resolveApis({ rawConfig, configPath = '', resolver, }) {
144
149
  const { apis = {}, styleguide: styleguideConfig = {} } = rawConfig;
145
150
  const resolvedApis = {};
146
151
  for (const [apiName, apiContent] of Object.entries(apis || {})) {
147
- if ((_b = (_a = apiContent.styleguide) === null || _a === void 0 ? void 0 : _a.extends) === null || _b === void 0 ? void 0 : _b.some(utils_2.isNotString)) {
152
+ if ((_b = (_a = apiContent.styleguide) === null || _a === void 0 ? void 0 : _a.extends) === null || _b === void 0 ? void 0 : _b.some(utils_3.isNotString)) {
148
153
  throw new Error(`Error configuration format not detected in extends value must contain strings`);
149
154
  }
150
155
  const rawStyleguideConfig = getMergedRawStyleguideConfig(styleguideConfig, apiContent.styleguide);
@@ -165,8 +170,8 @@ function resolveAndMergeNestedStyleguideConfig({ styleguideConfig, configPath =
165
170
  if (parentConfigPaths.includes(configPath)) {
166
171
  throw new Error(`Circular dependency in config file: "${configPath}"`);
167
172
  }
168
- const plugins = utils_1.getUniquePlugins(resolvePlugins([...((styleguideConfig === null || styleguideConfig === void 0 ? void 0 : styleguideConfig.plugins) || []), builtIn_1.defaultPlugin], configPath));
169
- const pluginPaths = (_a = styleguideConfig === null || styleguideConfig === void 0 ? void 0 : styleguideConfig.plugins) === null || _a === void 0 ? void 0 : _a.filter(utils_2.isString).map((p) => path.resolve(path.dirname(configPath), p));
173
+ const plugins = utils_2.getUniquePlugins(resolvePlugins([...((styleguideConfig === null || styleguideConfig === void 0 ? void 0 : styleguideConfig.plugins) || []), builtIn_1.defaultPlugin], configPath));
174
+ const pluginPaths = (_a = styleguideConfig === null || styleguideConfig === void 0 ? void 0 : styleguideConfig.plugins) === null || _a === void 0 ? void 0 : _a.filter(utils_3.isString).map((p) => path.resolve(path.dirname(configPath), p));
170
175
  const resolvedConfigPath = ref_utils_1.isAbsoluteUrl(configPath)
171
176
  ? configPath
172
177
  : configPath && path.resolve(configPath);
@@ -186,24 +191,23 @@ function resolveAndMergeNestedStyleguideConfig({ styleguideConfig, configPath =
186
191
  resolver: resolver,
187
192
  }, [...parentConfigPaths, resolvedConfigPath], extendPaths);
188
193
  }))) || []);
189
- const _d = utils_1.mergeExtends([
194
+ const _d = utils_2.mergeExtends([
190
195
  ...extendConfigs,
191
196
  Object.assign(Object.assign({}, styleguideConfig), { plugins, extends: undefined, extendPaths: [...parentConfigPaths, resolvedConfigPath], pluginPaths }),
192
197
  ]), { plugins: mergedPlugins = [] } = _d, styleguide = __rest(_d, ["plugins"]);
193
- return Object.assign(Object.assign({}, styleguide), { extendPaths: (_c = styleguide.extendPaths) === null || _c === void 0 ? void 0 : _c.filter((path) => path && !ref_utils_1.isAbsoluteUrl(path)), plugins: utils_1.getUniquePlugins(mergedPlugins), recommendedFallback: styleguideConfig === null || styleguideConfig === void 0 ? void 0 : styleguideConfig.recommendedFallback, doNotResolveExamples: styleguideConfig === null || styleguideConfig === void 0 ? void 0 : styleguideConfig.doNotResolveExamples });
198
+ return Object.assign(Object.assign({}, styleguide), { extendPaths: (_c = styleguide.extendPaths) === null || _c === void 0 ? void 0 : _c.filter((path) => path && !ref_utils_1.isAbsoluteUrl(path)), plugins: utils_2.getUniquePlugins(mergedPlugins), recommendedFallback: styleguideConfig === null || styleguideConfig === void 0 ? void 0 : styleguideConfig.recommendedFallback, doNotResolveExamples: styleguideConfig === null || styleguideConfig === void 0 ? void 0 : styleguideConfig.doNotResolveExamples });
194
199
  });
195
200
  }
196
201
  function resolveStyleguideConfig(opts, parentConfigPaths = [], extendPaths = []) {
197
202
  return __awaiter(this, void 0, void 0, function* () {
198
203
  const resolvedStyleguideConfig = yield resolveAndMergeNestedStyleguideConfig(opts, parentConfigPaths, extendPaths);
199
- return Object.assign(Object.assign({}, resolvedStyleguideConfig), { rules: resolvedStyleguideConfig.rules &&
200
- groupStyleguideAssertionRules(resolvedStyleguideConfig.rules) });
204
+ return Object.assign(Object.assign({}, resolvedStyleguideConfig), { rules: resolvedStyleguideConfig.rules && groupStyleguideAssertionRules(resolvedStyleguideConfig) });
201
205
  });
202
206
  }
203
207
  exports.resolveStyleguideConfig = resolveStyleguideConfig;
204
208
  function resolvePreset(presetName, plugins) {
205
209
  var _a;
206
- const { pluginId, configName } = utils_1.parsePresetName(presetName);
210
+ const { pluginId, configName } = utils_2.parsePresetName(presetName);
207
211
  const plugin = plugins.find((p) => p.id === pluginId);
208
212
  if (!plugin) {
209
213
  throw new Error(`Invalid config ${logger_1.colorize.red(presetName)}: plugin ${pluginId} is not included.`);
@@ -221,7 +225,7 @@ function loadExtendStyleguideConfig(filePath, resolver) {
221
225
  return __awaiter(this, void 0, void 0, function* () {
222
226
  try {
223
227
  const fileSource = yield resolver.loadExternalRef(filePath);
224
- const rawConfig = utils_1.transformConfig(utils_2.parseYaml(fileSource.body));
228
+ const rawConfig = utils_2.transformConfig(utils_3.parseYaml(fileSource.body));
225
229
  if (!rawConfig.styleguide) {
226
230
  throw new Error(`Styleguide configuration format not detected: "${filePath}"`);
227
231
  }
@@ -233,12 +237,12 @@ function loadExtendStyleguideConfig(filePath, resolver) {
233
237
  });
234
238
  }
235
239
  function getMergedRawStyleguideConfig(rootStyleguideConfig, apiStyleguideConfig) {
236
- const resultLint = Object.assign(Object.assign(Object.assign({}, rootStyleguideConfig), apiStyleguideConfig), { rules: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.rules), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.rules), oas2Rules: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas2Rules), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas2Rules), oas3_0Rules: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_0Rules), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_0Rules), oas3_1Rules: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_1Rules), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_1Rules), preprocessors: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.preprocessors), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.preprocessors), oas2Preprocessors: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas2Preprocessors), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas2Preprocessors), oas3_0Preprocessors: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_0Preprocessors), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_0Preprocessors), oas3_1Preprocessors: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_1Preprocessors), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_1Preprocessors), decorators: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.decorators), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.decorators), oas2Decorators: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas2Decorators), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas2Decorators), oas3_0Decorators: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_0Decorators), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_0Decorators), oas3_1Decorators: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_1Decorators), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_1Decorators), recommendedFallback: (apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.extends)
240
+ const resultLint = Object.assign(Object.assign(Object.assign({}, rootStyleguideConfig), utils_1.pickDefined(apiStyleguideConfig)), { rules: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.rules), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.rules), oas2Rules: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas2Rules), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas2Rules), oas3_0Rules: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_0Rules), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_0Rules), oas3_1Rules: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_1Rules), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_1Rules), preprocessors: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.preprocessors), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.preprocessors), oas2Preprocessors: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas2Preprocessors), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas2Preprocessors), oas3_0Preprocessors: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_0Preprocessors), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_0Preprocessors), oas3_1Preprocessors: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_1Preprocessors), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_1Preprocessors), decorators: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.decorators), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.decorators), oas2Decorators: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas2Decorators), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas2Decorators), oas3_0Decorators: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_0Decorators), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_0Decorators), oas3_1Decorators: Object.assign(Object.assign({}, rootStyleguideConfig === null || rootStyleguideConfig === void 0 ? void 0 : rootStyleguideConfig.oas3_1Decorators), apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.oas3_1Decorators), recommendedFallback: (apiStyleguideConfig === null || apiStyleguideConfig === void 0 ? void 0 : apiStyleguideConfig.extends)
237
241
  ? false
238
242
  : rootStyleguideConfig.recommendedFallback });
239
243
  return resultLint;
240
244
  }
241
- function groupStyleguideAssertionRules(rules) {
245
+ function groupStyleguideAssertionRules({ rules, plugins, }) {
242
246
  if (!rules) {
243
247
  return rules;
244
248
  }
@@ -249,6 +253,21 @@ function groupStyleguideAssertionRules(rules) {
249
253
  for (const [ruleKey, rule] of Object.entries(rules)) {
250
254
  if (ruleKey.startsWith('assert/') && typeof rule === 'object' && rule !== null) {
251
255
  const assertion = rule;
256
+ if (plugins) {
257
+ for (const field of Object.keys(assertion)) {
258
+ const [pluginId, fn] = field.split('/');
259
+ if (!pluginId || !fn)
260
+ continue;
261
+ const plugin = plugins.find((plugin) => plugin.id === pluginId);
262
+ if (!plugin) {
263
+ throw Error(logger_1.colorize.red(`Plugin ${logger_1.colorize.blue(pluginId)} isn't found.`));
264
+ }
265
+ if (!plugin.assertions || !plugin.assertions[fn]) {
266
+ throw Error(`Plugin ${logger_1.colorize.red(pluginId)} doesn't export assertions function with name ${logger_1.colorize.red(fn)}.`);
267
+ }
268
+ asserts_1.asserts[field] = asserts_1.buildAssertCustomFunction(plugin.assertions[fn]);
269
+ }
270
+ }
252
271
  assertions.push(Object.assign(Object.assign({}, assertion), { assertionId: ruleKey.replace('assert/', '') }));
253
272
  }
254
273
  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
  }
@@ -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 = {
@@ -101,6 +109,7 @@ export declare type DeprecatedInApi = {
101
109
  };
102
110
  export declare type ResolvedApi = Omit<Api, 'styleguide'> & {
103
111
  styleguide: ResolvedStyleguideConfig;
112
+ files?: string[];
104
113
  };
105
114
  export declare type RawConfig = {
106
115
  apis?: Record<string, Api>;
@@ -108,6 +117,7 @@ export declare type RawConfig = {
108
117
  resolve?: RawResolveConfig;
109
118
  region?: Region;
110
119
  organization?: string;
120
+ files?: string[];
111
121
  } & FeaturesConfig;
112
122
  export declare type FlatApi = Omit<Api, 'styleguide'> & Omit<ApiStyleguideRawConfig, 'doNotResolveExamples'>;
113
123
  export declare type FlatRawConfig = Omit<RawConfig, 'styleguide' | 'resolve' | 'apis'> & Omit<StyleguideRawConfig, 'doNotResolveExamples'> & {
@@ -139,7 +139,7 @@ function mergeExtends(rulesConfList) {
139
139
  }
140
140
  exports.mergeExtends = mergeExtends;
141
141
  function getMergedConfig(config, apiName) {
142
- var _a, _b, _c, _d, _e, _f;
142
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
143
143
  const extendPaths = [
144
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; }),
145
145
  (_b = (_a = config.rawConfig) === null || _a === void 0 ? void 0 : _a.styleguide) === null || _b === void 0 ? void 0 : _b.extendPaths,
@@ -156,7 +156,7 @@ function getMergedConfig(config, apiName) {
156
156
  ? new config_1.Config(Object.assign(Object.assign({}, config.rawConfig), { styleguide: Object.assign(Object.assign({}, (config.apis[apiName]
157
157
  ? config.apis[apiName].styleguide
158
158
  : config.rawConfig.styleguide)), { extendPaths,
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']) }), 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)
160
160
  : config;
161
161
  }
162
162
  exports.getMergedConfig = getMergedConfig;
@@ -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 {};