@redocly/openapi-core 1.0.0-beta.110 → 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 (57) hide show
  1. package/lib/config/config-resolvers.js +23 -22
  2. package/lib/rules/common/no-ambiguous-paths.js +1 -1
  3. package/lib/rules/common/no-identical-paths.js +4 -4
  4. package/lib/rules/common/operation-2xx-response.js +2 -2
  5. package/lib/rules/common/operation-4xx-response.js +2 -2
  6. package/lib/rules/common/path-not-include-query.js +1 -1
  7. package/lib/rules/common/path-params-defined.js +7 -2
  8. package/lib/rules/common/response-contains-header.js +2 -2
  9. package/lib/rules/common/security-defined.js +10 -5
  10. package/lib/rules/common/spec.js +14 -12
  11. package/lib/rules/oas3/request-mime-type.js +1 -1
  12. package/lib/rules/oas3/response-mime-type.js +1 -1
  13. package/lib/rules/other/stats.d.ts +1 -1
  14. package/lib/rules/other/stats.js +1 -1
  15. package/lib/rules/utils.d.ts +1 -0
  16. package/lib/rules/utils.js +17 -1
  17. package/lib/types/oas2.js +6 -6
  18. package/lib/types/oas3.js +11 -11
  19. package/lib/types/oas3_1.js +3 -3
  20. package/lib/types/redocly-yaml.js +14 -4
  21. package/lib/utils.d.ts +1 -0
  22. package/lib/utils.js +13 -1
  23. package/lib/visitors.d.ts +7 -6
  24. package/lib/visitors.js +11 -3
  25. package/package.json +1 -1
  26. package/src/__tests__/__snapshots__/bundle.test.ts.snap +1 -1
  27. package/src/__tests__/utils.test.ts +11 -0
  28. package/src/__tests__/walk.test.ts +2 -2
  29. package/src/config/__tests__/config-resolvers.test.ts +25 -0
  30. package/src/config/config-resolvers.ts +2 -1
  31. package/src/rules/common/__tests__/operation-2xx-response.test.ts +37 -0
  32. package/src/rules/common/__tests__/operation-4xx-response.test.ts +37 -0
  33. package/src/rules/common/__tests__/path-params-defined.test.ts +69 -0
  34. package/src/rules/common/__tests__/security-defined.test.ts +6 -6
  35. package/src/rules/common/__tests__/spec.test.ts +125 -0
  36. package/src/rules/common/assertions/__tests__/utils.test.ts +2 -2
  37. package/src/rules/common/no-ambiguous-paths.ts +1 -1
  38. package/src/rules/common/no-identical-paths.ts +4 -4
  39. package/src/rules/common/operation-2xx-response.ts +2 -2
  40. package/src/rules/common/operation-4xx-response.ts +2 -2
  41. package/src/rules/common/path-not-include-query.ts +1 -1
  42. package/src/rules/common/path-params-defined.ts +9 -2
  43. package/src/rules/common/response-contains-header.ts +6 -1
  44. package/src/rules/common/security-defined.ts +10 -5
  45. package/src/rules/common/spec.ts +15 -11
  46. package/src/rules/oas3/__tests__/response-contains-header.test.ts +116 -0
  47. package/src/rules/oas3/request-mime-type.ts +1 -1
  48. package/src/rules/oas3/response-mime-type.ts +1 -1
  49. package/src/rules/other/stats.ts +1 -1
  50. package/src/rules/utils.ts +22 -0
  51. package/src/types/oas2.ts +6 -6
  52. package/src/types/oas3.ts +11 -11
  53. package/src/types/oas3_1.ts +3 -3
  54. package/src/types/redocly-yaml.ts +14 -4
  55. package/src/utils.ts +13 -0
  56. package/src/visitors.ts +25 -10
  57. package/tsconfig.tsbuildinfo +1 -1
@@ -23,21 +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");
33
34
  const asserts_1 = require("../rules/common/assertions/asserts");
34
35
  function resolveConfig(rawConfig, configPath) {
35
36
  var _a, _b, _c, _d, _e;
36
37
  return __awaiter(this, void 0, void 0, function* () {
37
- 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)) {
38
39
  throw new Error(`Error configuration format not detected in extends value must contain strings`);
39
40
  }
40
- const resolver = new resolve_1.BaseResolver(utils_1.getResolveConfig(rawConfig.resolve));
41
+ const resolver = new resolve_1.BaseResolver(utils_2.getResolveConfig(rawConfig.resolve));
41
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'];
42
43
  const recommendedFallback = !((_e = rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.styleguide) === null || _e === void 0 ? void 0 : _e.extends);
43
44
  const styleguideConfig = Object.assign(Object.assign({}, rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.styleguide), { extends: configExtends, recommendedFallback });
@@ -61,11 +62,11 @@ function resolvePlugins(plugins, configPath = '') {
61
62
  return [];
62
63
  // TODO: implement or reuse Resolver approach so it will work in node and browser envs
63
64
  const requireFunc = (plugin) => {
64
- if (env_1.isBrowser && utils_2.isString(plugin)) {
65
+ if (env_1.isBrowser && utils_3.isString(plugin)) {
65
66
  logger_1.logger.error(`Cannot load ${plugin}. Plugins aren't supported in browser yet.`);
66
67
  return undefined;
67
68
  }
68
- if (utils_2.isString(plugin)) {
69
+ if (utils_3.isString(plugin)) {
69
70
  const absoltePluginPath = path.resolve(path.dirname(configPath), plugin);
70
71
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
71
72
  // @ts-ignore
@@ -80,7 +81,7 @@ function resolvePlugins(plugins, configPath = '') {
80
81
  const seenPluginIds = new Map();
81
82
  return plugins
82
83
  .map((p) => {
83
- if (utils_2.isString(p) && ref_utils_1.isAbsoluteUrl(p)) {
84
+ if (utils_3.isString(p) && ref_utils_1.isAbsoluteUrl(p)) {
84
85
  throw new Error(logger_1.colorize.red(`We don't support remote plugins yet.`));
85
86
  }
86
87
  // TODO: resolve npm packages similar to eslint
@@ -104,10 +105,10 @@ function resolvePlugins(plugins, configPath = '') {
104
105
  }
105
106
  plugin.rules = {};
106
107
  if (pluginModule.rules.oas3) {
107
- plugin.rules.oas3 = utils_1.prefixRules(pluginModule.rules.oas3, id);
108
+ plugin.rules.oas3 = utils_2.prefixRules(pluginModule.rules.oas3, id);
108
109
  }
109
110
  if (pluginModule.rules.oas2) {
110
- plugin.rules.oas2 = utils_1.prefixRules(pluginModule.rules.oas2, id);
111
+ plugin.rules.oas2 = utils_2.prefixRules(pluginModule.rules.oas2, id);
111
112
  }
112
113
  }
113
114
  if (pluginModule.preprocessors) {
@@ -116,10 +117,10 @@ function resolvePlugins(plugins, configPath = '') {
116
117
  }
117
118
  plugin.preprocessors = {};
118
119
  if (pluginModule.preprocessors.oas3) {
119
- plugin.preprocessors.oas3 = utils_1.prefixRules(pluginModule.preprocessors.oas3, id);
120
+ plugin.preprocessors.oas3 = utils_2.prefixRules(pluginModule.preprocessors.oas3, id);
120
121
  }
121
122
  if (pluginModule.preprocessors.oas2) {
122
- plugin.preprocessors.oas2 = utils_1.prefixRules(pluginModule.preprocessors.oas2, id);
123
+ plugin.preprocessors.oas2 = utils_2.prefixRules(pluginModule.preprocessors.oas2, id);
123
124
  }
124
125
  }
125
126
  if (pluginModule.decorators) {
@@ -128,10 +129,10 @@ function resolvePlugins(plugins, configPath = '') {
128
129
  }
129
130
  plugin.decorators = {};
130
131
  if (pluginModule.decorators.oas3) {
131
- plugin.decorators.oas3 = utils_1.prefixRules(pluginModule.decorators.oas3, id);
132
+ plugin.decorators.oas3 = utils_2.prefixRules(pluginModule.decorators.oas3, id);
132
133
  }
133
134
  if (pluginModule.decorators.oas2) {
134
- plugin.decorators.oas2 = utils_1.prefixRules(pluginModule.decorators.oas2, id);
135
+ plugin.decorators.oas2 = utils_2.prefixRules(pluginModule.decorators.oas2, id);
135
136
  }
136
137
  }
137
138
  if (pluginModule.assertions) {
@@ -139,7 +140,7 @@ function resolvePlugins(plugins, configPath = '') {
139
140
  }
140
141
  return plugin;
141
142
  })
142
- .filter(utils_2.isDefined);
143
+ .filter(utils_3.isDefined);
143
144
  }
144
145
  exports.resolvePlugins = resolvePlugins;
145
146
  function resolveApis({ rawConfig, configPath = '', resolver, }) {
@@ -148,7 +149,7 @@ function resolveApis({ rawConfig, configPath = '', resolver, }) {
148
149
  const { apis = {}, styleguide: styleguideConfig = {} } = rawConfig;
149
150
  const resolvedApis = {};
150
151
  for (const [apiName, apiContent] of Object.entries(apis || {})) {
151
- 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)) {
152
153
  throw new Error(`Error configuration format not detected in extends value must contain strings`);
153
154
  }
154
155
  const rawStyleguideConfig = getMergedRawStyleguideConfig(styleguideConfig, apiContent.styleguide);
@@ -169,8 +170,8 @@ function resolveAndMergeNestedStyleguideConfig({ styleguideConfig, configPath =
169
170
  if (parentConfigPaths.includes(configPath)) {
170
171
  throw new Error(`Circular dependency in config file: "${configPath}"`);
171
172
  }
172
- const plugins = utils_1.getUniquePlugins(resolvePlugins([...((styleguideConfig === null || styleguideConfig === void 0 ? void 0 : styleguideConfig.plugins) || []), builtIn_1.defaultPlugin], configPath));
173
- 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));
174
175
  const resolvedConfigPath = ref_utils_1.isAbsoluteUrl(configPath)
175
176
  ? configPath
176
177
  : configPath && path.resolve(configPath);
@@ -190,11 +191,11 @@ function resolveAndMergeNestedStyleguideConfig({ styleguideConfig, configPath =
190
191
  resolver: resolver,
191
192
  }, [...parentConfigPaths, resolvedConfigPath], extendPaths);
192
193
  }))) || []);
193
- const _d = utils_1.mergeExtends([
194
+ const _d = utils_2.mergeExtends([
194
195
  ...extendConfigs,
195
196
  Object.assign(Object.assign({}, styleguideConfig), { plugins, extends: undefined, extendPaths: [...parentConfigPaths, resolvedConfigPath], pluginPaths }),
196
197
  ]), { plugins: mergedPlugins = [] } = _d, styleguide = __rest(_d, ["plugins"]);
197
- 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 });
198
199
  });
199
200
  }
200
201
  function resolveStyleguideConfig(opts, parentConfigPaths = [], extendPaths = []) {
@@ -206,7 +207,7 @@ function resolveStyleguideConfig(opts, parentConfigPaths = [], extendPaths = [])
206
207
  exports.resolveStyleguideConfig = resolveStyleguideConfig;
207
208
  function resolvePreset(presetName, plugins) {
208
209
  var _a;
209
- const { pluginId, configName } = utils_1.parsePresetName(presetName);
210
+ const { pluginId, configName } = utils_2.parsePresetName(presetName);
210
211
  const plugin = plugins.find((p) => p.id === pluginId);
211
212
  if (!plugin) {
212
213
  throw new Error(`Invalid config ${logger_1.colorize.red(presetName)}: plugin ${pluginId} is not included.`);
@@ -224,7 +225,7 @@ function loadExtendStyleguideConfig(filePath, resolver) {
224
225
  return __awaiter(this, void 0, void 0, function* () {
225
226
  try {
226
227
  const fileSource = yield resolver.loadExternalRef(filePath);
227
- const rawConfig = utils_1.transformConfig(utils_2.parseYaml(fileSource.body));
228
+ const rawConfig = utils_2.transformConfig(utils_3.parseYaml(fileSource.body));
228
229
  if (!rawConfig.styleguide) {
229
230
  throw new Error(`Styleguide configuration format not detected: "${filePath}"`);
230
231
  }
@@ -236,7 +237,7 @@ function loadExtendStyleguideConfig(filePath, resolver) {
236
237
  });
237
238
  }
238
239
  function getMergedRawStyleguideConfig(rootStyleguideConfig, apiStyleguideConfig) {
239
- 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)
240
241
  ? false
241
242
  : rootStyleguideConfig.recommendedFallback });
242
243
  return resultLint;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NoAmbiguousPaths = void 0;
4
4
  const NoAmbiguousPaths = () => {
5
5
  return {
6
- PathsMap(pathMap, { report, location }) {
6
+ Paths(pathMap, { report, location }) {
7
7
  const seenPaths = [];
8
8
  for (const currentPath of Object.keys(pathMap)) {
9
9
  const ambiguousPath = seenPaths.find((seenPath) => arePathsAmbiguous(seenPath, currentPath));
@@ -3,11 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NoIdenticalPaths = void 0;
4
4
  const NoIdenticalPaths = () => {
5
5
  return {
6
- PathsMap(pathMap, { report, location }) {
7
- const pathsMap = new Map();
6
+ Paths(pathMap, { report, location }) {
7
+ const Paths = new Map();
8
8
  for (const pathName of Object.keys(pathMap)) {
9
9
  const id = pathName.replace(/{.+?}/g, '{VARIABLE}');
10
- const existingSamePath = pathsMap.get(id);
10
+ const existingSamePath = Paths.get(id);
11
11
  if (existingSamePath) {
12
12
  report({
13
13
  message: `The path already exists which differs only by path parameter name(s): \`${existingSamePath}\` and \`${pathName}\`.`,
@@ -15,7 +15,7 @@ const NoIdenticalPaths = () => {
15
15
  });
16
16
  }
17
17
  else {
18
- pathsMap.set(id, pathName);
18
+ Paths.set(id, pathName);
19
19
  }
20
20
  }
21
21
  },
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Operation2xxResponse = void 0;
4
4
  const Operation2xxResponse = () => {
5
5
  return {
6
- ResponsesMap(responses, { report }) {
7
- const codes = Object.keys(responses);
6
+ Responses(responses, { report }) {
7
+ const codes = Object.keys(responses || {});
8
8
  if (!codes.some((code) => code === 'default' || /2[Xx0-9]{2}/.test(code))) {
9
9
  report({
10
10
  message: 'Operation must have at least one `2XX` response.',
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Operation4xxResponse = void 0;
4
4
  const Operation4xxResponse = () => {
5
5
  return {
6
- ResponsesMap(responses, { report }) {
7
- const codes = Object.keys(responses);
6
+ Responses(responses, { report }) {
7
+ const codes = Object.keys(responses || {});
8
8
  if (!codes.some((code) => /4[Xx0-9]{2}/.test(code))) {
9
9
  report({
10
10
  message: 'Operation must have at least one `4XX` response.',
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PathNotIncludeQuery = void 0;
4
4
  const PathNotIncludeQuery = () => {
5
5
  return {
6
- PathsMap: {
6
+ Paths: {
7
7
  PathItem(_operation, { report, key }) {
8
8
  if (key.toString().includes('?')) {
9
9
  report({
@@ -6,6 +6,7 @@ const PathParamsDefined = () => {
6
6
  let pathTemplateParams;
7
7
  let definedPathParams;
8
8
  let currentPath;
9
+ let definedOperationParams;
9
10
  return {
10
11
  PathItem: {
11
12
  enter(_, { key }) {
@@ -25,9 +26,13 @@ const PathParamsDefined = () => {
25
26
  }
26
27
  },
27
28
  Operation: {
29
+ enter() {
30
+ definedOperationParams = new Set();
31
+ },
28
32
  leave(_op, { report, location }) {
29
33
  for (const templateParam of Array.from(pathTemplateParams.keys())) {
30
- if (!definedPathParams.has(templateParam)) {
34
+ if (!definedOperationParams.has(templateParam) &&
35
+ !definedPathParams.has(templateParam)) {
31
36
  report({
32
37
  message: `The operation does not define the path parameter \`{${templateParam}}\` expected by path \`${currentPath}\`.`,
33
38
  location: location.child(['parameters']).key(), // report on operation
@@ -37,7 +42,7 @@ const PathParamsDefined = () => {
37
42
  },
38
43
  Parameter(parameter, { report, location }) {
39
44
  if (parameter.in === 'path' && parameter.name) {
40
- definedPathParams.add(parameter.name);
45
+ definedOperationParams.add(parameter.name);
41
46
  if (!pathTemplateParams.has(parameter.name)) {
42
47
  report({
43
48
  message: `Path parameter \`${parameter.name}\` is not used in the path \`${currentPath}\`.`,
@@ -8,13 +8,13 @@ const ResponseContainsHeader = (options) => {
8
8
  Operation: {
9
9
  Response: {
10
10
  enter: (response, { report, location, key }) => {
11
- var _a;
12
11
  const expectedHeaders = names[key] ||
13
12
  names[utils_1.getMatchingStatusCodeRange(key)] ||
14
13
  names[utils_1.getMatchingStatusCodeRange(key).toLowerCase()] ||
15
14
  [];
16
15
  for (const expectedHeader of expectedHeaders) {
17
- if (!((_a = response.headers) === null || _a === void 0 ? void 0 : _a[expectedHeader])) {
16
+ if (!(response === null || response === void 0 ? void 0 : response.headers) ||
17
+ !Object.keys(response === null || response === void 0 ? void 0 : response.headers).some((header) => header.toLowerCase() === expectedHeader.toLowerCase())) {
18
18
  report({
19
19
  message: `Response object must contain a "${expectedHeader}" header.`,
20
20
  location: location.child('headers').key(),
@@ -3,9 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SecurityDefined = void 0;
4
4
  const SecurityDefined = () => {
5
5
  const referencedSchemes = new Map();
6
+ const operationsWithoutSecurity = [];
6
7
  let eachOperationHasSecurity = true;
7
8
  return {
8
- DefinitionRoot: {
9
+ Root: {
9
10
  leave(root, { report }) {
10
11
  for (const [name, scheme] of referencedSchemes.entries()) {
11
12
  if (scheme.defined)
@@ -21,9 +22,12 @@ const SecurityDefined = () => {
21
22
  return;
22
23
  }
23
24
  else {
24
- report({
25
- message: `Every API should have security defined on the root level or for each operation.`,
26
- });
25
+ for (const operationLocation of operationsWithoutSecurity) {
26
+ report({
27
+ message: `Every operation should have security defined on it or on the root level.`,
28
+ location: operationLocation.key(),
29
+ });
30
+ }
27
31
  }
28
32
  },
29
33
  },
@@ -42,9 +46,10 @@ const SecurityDefined = () => {
42
46
  }
43
47
  }
44
48
  },
45
- Operation(operation) {
49
+ Operation(operation, { location }) {
46
50
  if (!(operation === null || operation === void 0 ? void 0 : operation.security)) {
47
51
  eachOperationHasSecurity = false;
52
+ operationsWithoutSecurity.push(location);
48
53
  }
49
54
  },
50
55
  };
@@ -8,7 +8,7 @@ const utils_2 = require("../../utils");
8
8
  const OasSpec = () => {
9
9
  return {
10
10
  any(node, { report, type, location, rawLocation, key, resolve, ignoreNextVisitorsOnNode }) {
11
- var _a, _b, _c, _d;
11
+ var _a, _b, _c, _d, _e, _f;
12
12
  const nodeType = utils_1.oasTypeOf(node);
13
13
  const refLocation = rawLocation !== location ? rawLocation : undefined;
14
14
  if (type.items) {
@@ -99,18 +99,20 @@ const OasSpec = () => {
99
99
  if (propSchema.resolvable !== false && ref_utils_1.isRef(propValue)) {
100
100
  propValue = resolve(propValue).node;
101
101
  }
102
- if (propSchema.enum) {
103
- if (!propSchema.enum.includes(propValue)) {
104
- report({
105
- location: propLocation,
106
- message: `\`${propName}\` can be one of the following only: ${propSchema.enum
107
- .map((i) => `"${i}"`)
108
- .join(', ')}.`,
109
- from: refLocation,
110
- suggest: utils_1.getSuggest(propValue, propSchema.enum),
102
+ if (propSchema.items && ((_c = propSchema.items) === null || _c === void 0 ? void 0 : _c.enum) && Array.isArray(propValue)) {
103
+ for (let i = 0; i < propValue.length; i++) {
104
+ utils_1.validateSchemaEnumType((_d = propSchema.items) === null || _d === void 0 ? void 0 : _d.enum, propValue[i], propName, refLocation, {
105
+ report,
106
+ location: location.child([propName, i]),
111
107
  });
112
108
  }
113
109
  }
110
+ if (propSchema.enum) {
111
+ utils_1.validateSchemaEnumType(propSchema.enum, propValue, propName, refLocation, {
112
+ report,
113
+ location: location.child([propName]),
114
+ });
115
+ }
114
116
  else if (propSchema.type && !utils_1.matchesJsonSchemaType(propValue, propSchema.type, false)) {
115
117
  report({
116
118
  message: `Expected type \`${propSchema.type}\` but got \`${propValueType}\`.`,
@@ -118,8 +120,8 @@ const OasSpec = () => {
118
120
  location: propLocation,
119
121
  });
120
122
  }
121
- else if (propValueType === 'array' && ((_c = propSchema.items) === null || _c === void 0 ? void 0 : _c.type)) {
122
- const itemsType = (_d = propSchema.items) === null || _d === void 0 ? void 0 : _d.type;
123
+ else if (propValueType === 'array' && ((_e = propSchema.items) === null || _e === void 0 ? void 0 : _e.type)) {
124
+ const itemsType = (_f = propSchema.items) === null || _f === void 0 ? void 0 : _f.type;
123
125
  for (let i = 0; i < propValue.length; i++) {
124
126
  const item = propValue[i];
125
127
  if (!utils_1.matchesJsonSchemaType(item, itemsType, false)) {
@@ -4,7 +4,7 @@ exports.RequestMimeType = void 0;
4
4
  const utils_1 = require("../../utils");
5
5
  const RequestMimeType = ({ allowedValues }) => {
6
6
  return {
7
- PathsMap: {
7
+ Paths: {
8
8
  RequestBody: {
9
9
  leave(requestBody, ctx) {
10
10
  utils_1.validateMimeTypeOAS3({ type: 'consumes', value: requestBody }, ctx, allowedValues);
@@ -4,7 +4,7 @@ exports.ResponseMimeType = void 0;
4
4
  const utils_1 = require("../../utils");
5
5
  const ResponseMimeType = ({ allowedValues }) => {
6
6
  return {
7
- PathsMap: {
7
+ Paths: {
8
8
  Response: {
9
9
  leave(response, ctx) {
10
10
  utils_1.validateMimeTypeOAS3({ type: 'produces', value: response }, ctx, allowedValues);
@@ -22,7 +22,7 @@ export declare const Stats: (statsAccumulator: StatsAccumulator) => {
22
22
  leave(operation: any): void;
23
23
  };
24
24
  };
25
- PathsMap: {
25
+ Paths: {
26
26
  PathItem: {
27
27
  leave(): void;
28
28
  Operation: {
@@ -40,7 +40,7 @@ const Stats = (statsAccumulator) => {
40
40
  },
41
41
  },
42
42
  },
43
- PathsMap: {
43
+ Paths: {
44
44
  PathItem: {
45
45
  leave() {
46
46
  statsAccumulator.pathItems.total++;
@@ -16,3 +16,4 @@ export declare function validateDefinedAndNonEmpty(fieldName: string, value: any
16
16
  export declare function getSuggest(given: string, variants: string[]): string[];
17
17
  export declare function validateExample(example: any, schema: Referenced<Oas3Schema>, dataLoc: Location, { resolve, location, report }: UserContext, allowAdditionalProperties: boolean): void;
18
18
  export declare function getAdditionalPropertiesOption(opts: Record<string, any>): boolean;
19
+ export declare function validateSchemaEnumType(schemaEnum: string[], propertyValue: string, propName: string, refLocation: Location | undefined, { report, location }: UserContext): void;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getAdditionalPropertiesOption = exports.validateExample = exports.getSuggest = exports.validateDefinedAndNonEmpty = exports.fieldNonEmpty = exports.missingRequiredField = exports.matchesJsonSchemaType = exports.oasTypeOf = void 0;
3
+ exports.validateSchemaEnumType = exports.getAdditionalPropertiesOption = exports.validateExample = exports.getSuggest = exports.validateDefinedAndNonEmpty = exports.fieldNonEmpty = exports.missingRequiredField = exports.matchesJsonSchemaType = exports.oasTypeOf = void 0;
4
4
  const levenshtein = require("js-levenshtein");
5
5
  const ref_utils_1 = require("../ref-utils");
6
6
  const ajv_1 = require("./ajv");
@@ -120,3 +120,19 @@ function getAdditionalPropertiesOption(opts) {
120
120
  return !opts.disallowAdditionalProperties;
121
121
  }
122
122
  exports.getAdditionalPropertiesOption = getAdditionalPropertiesOption;
123
+ function validateSchemaEnumType(schemaEnum, propertyValue, propName, refLocation, { report, location }) {
124
+ if (!schemaEnum) {
125
+ return;
126
+ }
127
+ if (!schemaEnum.includes(propertyValue === null ? 'null' : propertyValue)) {
128
+ report({
129
+ location,
130
+ message: `\`${propName}\` can be one of the following only: ${schemaEnum
131
+ .map((type) => `"${type}"`)
132
+ .join(', ')}.`,
133
+ from: refLocation,
134
+ suggest: getSuggest(propertyValue, schemaEnum),
135
+ });
136
+ }
137
+ }
138
+ exports.validateSchemaEnumType = validateSchemaEnumType;
package/lib/types/oas2.js CHANGED
@@ -12,7 +12,7 @@ const Root = {
12
12
  schemes: { type: 'array', items: { type: 'string' } },
13
13
  consumes: { type: 'array', items: { type: 'string' } },
14
14
  produces: { type: 'array', items: { type: 'string' } },
15
- paths: 'PathsMap',
15
+ paths: 'Paths',
16
16
  definitions: 'NamedSchemas',
17
17
  parameters: 'NamedParameters',
18
18
  responses: 'NamedResponses',
@@ -48,7 +48,7 @@ const License = {
48
48
  },
49
49
  required: ['name'],
50
50
  };
51
- const PathsMap = {
51
+ const Paths = {
52
52
  properties: {},
53
53
  additionalProperties: (_value, key) => key.startsWith('/') ? 'PathItem' : undefined,
54
54
  };
@@ -75,7 +75,7 @@ const Operation = {
75
75
  consumes: { type: 'array', items: { type: 'string' } },
76
76
  produces: { type: 'array', items: { type: 'string' } },
77
77
  parameters: _1.listOf('Parameter'),
78
- responses: 'ResponsesMap',
78
+ responses: 'Responses',
79
79
  schemes: { type: 'array', items: { type: 'string' } },
80
80
  deprecated: { type: 'boolean' },
81
81
  security: _1.listOf('SecurityRequirement'),
@@ -171,7 +171,7 @@ const ParameterItems = {
171
171
  }
172
172
  },
173
173
  };
174
- const ResponsesMap = {
174
+ const Responses = {
175
175
  properties: {
176
176
  default: 'Response',
177
177
  },
@@ -359,14 +359,14 @@ exports.Oas2Types = {
359
359
  Info,
360
360
  Contact,
361
361
  License,
362
- PathsMap,
362
+ Paths,
363
363
  PathItem,
364
364
  Parameter,
365
365
  ParameterItems,
366
366
  Operation,
367
367
  Examples,
368
368
  Header,
369
- ResponsesMap,
369
+ Responses,
370
370
  Response,
371
371
  Schema,
372
372
  Xml,
package/lib/types/oas3.js CHANGED
@@ -12,7 +12,7 @@ const Root = {
12
12
  security: _1.listOf('SecurityRequirement'),
13
13
  tags: _1.listOf('Tag'),
14
14
  externalDocs: 'ExternalDocs',
15
- paths: 'PathsMap',
15
+ paths: 'Paths',
16
16
  components: 'Components',
17
17
  'x-webhooks': 'WebhooksMap',
18
18
  },
@@ -81,7 +81,7 @@ const License = {
81
81
  },
82
82
  required: ['name'],
83
83
  };
84
- const PathsMap = {
84
+ const Paths = {
85
85
  properties: {},
86
86
  additionalProperties: (_value, key) => key.startsWith('/') ? 'PathItem' : undefined,
87
87
  };
@@ -141,7 +141,7 @@ const Operation = {
141
141
  security: _1.listOf('SecurityRequirement'),
142
142
  servers: _1.listOf('Server'),
143
143
  requestBody: 'RequestBody',
144
- responses: 'ResponsesMap',
144
+ responses: 'Responses',
145
145
  deprecated: { type: 'boolean' },
146
146
  callbacks: 'CallbacksMap',
147
147
  'x-codeSamples': _1.listOf('XCodeSample'),
@@ -174,7 +174,7 @@ const MediaType = {
174
174
  schema: 'Schema',
175
175
  example: { isExample: true },
176
176
  examples: 'ExamplesMap',
177
- encoding: 'EncodingsMap',
177
+ encoding: 'EncodingMap',
178
178
  },
179
179
  };
180
180
  const Example = {
@@ -214,7 +214,7 @@ const Header = {
214
214
  },
215
215
  requiredOneOf: ['schema', 'content'],
216
216
  };
217
- const ResponsesMap = {
217
+ const Responses = {
218
218
  properties: { default: 'Response' },
219
219
  additionalProperties: (_v, key) => responseCodeRegexp.test(key) ? 'Response' : undefined,
220
220
  };
@@ -378,7 +378,7 @@ const AuthorizationCode = {
378
378
  },
379
379
  required: ['authorizationUrl', 'tokenUrl', 'scopes'],
380
380
  };
381
- const SecuritySchemeFlows = {
381
+ const OAuth2Flows = {
382
382
  properties: {
383
383
  implicit: 'ImplicitFlow',
384
384
  password: 'PasswordFlow',
@@ -394,7 +394,7 @@ const SecurityScheme = {
394
394
  in: { type: 'string', enum: ['query', 'header', 'cookie'] },
395
395
  scheme: { type: 'string' },
396
396
  bearerFormat: { type: 'string' },
397
- flows: 'SecuritySchemeFlows',
397
+ flows: 'OAuth2Flows',
398
398
  openIdConnectUrl: { type: 'string' },
399
399
  },
400
400
  required(value) {
@@ -438,7 +438,7 @@ exports.Oas3Types = {
438
438
  Info,
439
439
  Contact,
440
440
  License,
441
- PathsMap,
441
+ Paths,
442
442
  PathItem,
443
443
  Parameter,
444
444
  Operation,
@@ -450,10 +450,10 @@ exports.Oas3Types = {
450
450
  Example,
451
451
  ExamplesMap: _1.mapOf('Example'),
452
452
  Encoding,
453
- EncodingsMap: _1.mapOf('Encoding'),
453
+ EncodingMap: _1.mapOf('Encoding'),
454
454
  Header,
455
455
  HeadersMap: _1.mapOf('Header'),
456
- ResponsesMap,
456
+ Responses,
457
457
  Response,
458
458
  Link,
459
459
  Schema,
@@ -476,7 +476,7 @@ exports.Oas3Types = {
476
476
  PasswordFlow,
477
477
  ClientCredentials,
478
478
  AuthorizationCode,
479
- SecuritySchemeFlows,
479
+ OAuth2Flows,
480
480
  SecurityScheme,
481
481
  XCodeSample,
482
482
  WebhooksMap,
@@ -11,7 +11,7 @@ const Root = {
11
11
  security: _1.listOf('SecurityRequirement'),
12
12
  tags: _1.listOf('Tag'),
13
13
  externalDocs: 'ExternalDocs',
14
- paths: 'PathsMap',
14
+ paths: 'Paths',
15
15
  webhooks: 'WebhooksMap',
16
16
  components: 'Components',
17
17
  jsonSchemaDialect: { type: 'string' },
@@ -67,7 +67,7 @@ const Operation = {
67
67
  security: _1.listOf('SecurityRequirement'),
68
68
  servers: _1.listOf('Server'),
69
69
  requestBody: 'RequestBody',
70
- responses: 'ResponsesMap',
70
+ responses: 'Responses',
71
71
  deprecated: { type: 'boolean' },
72
72
  callbacks: _1.mapOf('Callback'),
73
73
  'x-codeSamples': _1.listOf('XCodeSample'),
@@ -175,7 +175,7 @@ const SecurityScheme = {
175
175
  in: { type: 'string', enum: ['query', 'header', 'cookie'] },
176
176
  scheme: { type: 'string' },
177
177
  bearerFormat: { type: 'string' },
178
- flows: 'SecuritySchemeFlows',
178
+ flows: 'OAuth2Flows',
179
179
  openIdConnectUrl: { type: 'string' },
180
180
  },
181
181
  required(value) {