@redocly/openapi-core 1.0.0-beta.129 → 1.0.0-beta.130

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.
package/lib/config/all.js CHANGED
@@ -49,6 +49,7 @@ exports.default = {
49
49
  'no-invalid-parameter-examples': 'error',
50
50
  'scalar-property-missing-example': 'error',
51
51
  'spec-strict-refs': 'error',
52
+ 'component-name-unique': 'error',
52
53
  },
53
54
  oas3_0Rules: {
54
55
  'no-invalid-media-type-examples': 'error',
@@ -32,6 +32,7 @@ exports.default = {
32
32
  'paths-kebab-case': 'off',
33
33
  spec: 'error',
34
34
  'spec-strict-refs': 'off',
35
+ 'component-name-unique': 'off',
35
36
  },
36
37
  oas3_0Rules: {
37
38
  'no-invalid-media-type-examples': {
@@ -32,6 +32,7 @@ exports.default = {
32
32
  'paths-kebab-case': 'off',
33
33
  spec: 'error',
34
34
  'spec-strict-refs': 'off',
35
+ 'component-name-unique': 'off',
35
36
  },
36
37
  oas3_0Rules: {
37
38
  'no-invalid-media-type-examples': {
@@ -0,0 +1,2 @@
1
+ import { Oas2Rule, Oas3Rule } from '../../visitors';
2
+ export declare const ComponentNameUnique: Oas3Rule | Oas2Rule;
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ComponentNameUnique = void 0;
4
+ const TYPE_NAME_SCHEMA = 'Schema';
5
+ const TYPE_NAME_PARAMETER = 'Parameter';
6
+ const TYPE_NAME_RESPONSE = 'Response';
7
+ const TYPE_NAME_REQUEST_BODY = 'RequestBody';
8
+ const TYPE_NAME_TO_OPTION_COMPONENT_NAME = {
9
+ [TYPE_NAME_SCHEMA]: 'schemas',
10
+ [TYPE_NAME_PARAMETER]: 'parameters',
11
+ [TYPE_NAME_RESPONSE]: 'responses',
12
+ [TYPE_NAME_REQUEST_BODY]: 'requestBodies',
13
+ };
14
+ const ComponentNameUnique = (options) => {
15
+ const components = new Map();
16
+ const typeNames = [];
17
+ if (options.schemas !== 'off') {
18
+ typeNames.push(TYPE_NAME_SCHEMA);
19
+ }
20
+ if (options.parameters !== 'off') {
21
+ typeNames.push(TYPE_NAME_PARAMETER);
22
+ }
23
+ if (options.responses !== 'off') {
24
+ typeNames.push(TYPE_NAME_RESPONSE);
25
+ }
26
+ if (options.requestBodies !== 'off') {
27
+ typeNames.push(TYPE_NAME_REQUEST_BODY);
28
+ }
29
+ const rule = {
30
+ ref: {
31
+ leave(ref, { type, resolve }) {
32
+ const typeName = type.name;
33
+ if (typeNames.includes(typeName)) {
34
+ const resolvedRef = resolve(ref);
35
+ if (!resolvedRef.location)
36
+ return;
37
+ addComponentFromAbsoluteLocation(typeName, resolvedRef.location.absolutePointer.toString());
38
+ }
39
+ },
40
+ },
41
+ Root: {
42
+ leave(root, ctx) {
43
+ components.forEach((value, key, _) => {
44
+ if (value.size > 1) {
45
+ const component = getComponentFromKey(key);
46
+ const optionComponentName = getOptionComponentNameForTypeName(component.typeName);
47
+ const definitions = Array.from(value)
48
+ .map((v) => `- ${v}`)
49
+ .join('\n');
50
+ const problem = {
51
+ message: `Component '${optionComponentName}/${component.componentName}' is not unique. It is defined at:\n${definitions}`,
52
+ };
53
+ const componentSeverity = optionComponentName ? options[optionComponentName] : null;
54
+ if (componentSeverity) {
55
+ problem.forceSeverity = componentSeverity;
56
+ }
57
+ ctx.report(problem);
58
+ }
59
+ });
60
+ },
61
+ },
62
+ };
63
+ if (options.schemas != 'off') {
64
+ rule.NamedSchemas = {
65
+ Schema(_, { location }) {
66
+ addComponentFromAbsoluteLocation(TYPE_NAME_SCHEMA, location.absolutePointer.toString());
67
+ },
68
+ };
69
+ }
70
+ if (options.responses != 'off') {
71
+ rule.NamedResponses = {
72
+ Response(_, { location }) {
73
+ addComponentFromAbsoluteLocation(TYPE_NAME_RESPONSE, location.absolutePointer.toString());
74
+ },
75
+ };
76
+ }
77
+ if (options.parameters != 'off') {
78
+ rule.NamedParameters = {
79
+ Parameter(_, { location }) {
80
+ addComponentFromAbsoluteLocation(TYPE_NAME_PARAMETER, location.absolutePointer.toString());
81
+ },
82
+ };
83
+ }
84
+ if (options.requestBodies != 'off') {
85
+ rule.NamedRequestBodies = {
86
+ RequestBody(_, { location }) {
87
+ addComponentFromAbsoluteLocation(TYPE_NAME_REQUEST_BODY, location.absolutePointer.toString());
88
+ },
89
+ };
90
+ }
91
+ return rule;
92
+ function getComponentNameFromAbsoluteLocation(absoluteLocation) {
93
+ const componentName = absoluteLocation.split('/').slice(-1)[0];
94
+ if (componentName.endsWith('.yml') ||
95
+ componentName.endsWith('.yaml') ||
96
+ componentName.endsWith('.json')) {
97
+ return componentName.slice(0, componentName.lastIndexOf('.'));
98
+ }
99
+ return componentName;
100
+ }
101
+ function addFoundComponent(typeName, componentName, absoluteLocation) {
102
+ var _a;
103
+ const key = getKeyForComponent(typeName, componentName);
104
+ const locations = (_a = components.get(key)) !== null && _a !== void 0 ? _a : new Set();
105
+ locations.add(absoluteLocation);
106
+ components.set(key, locations);
107
+ }
108
+ function addComponentFromAbsoluteLocation(typeName, absoluteLocation) {
109
+ const componentName = getComponentNameFromAbsoluteLocation(absoluteLocation);
110
+ addFoundComponent(typeName, componentName, absoluteLocation);
111
+ }
112
+ };
113
+ exports.ComponentNameUnique = ComponentNameUnique;
114
+ function getOptionComponentNameForTypeName(typeName) {
115
+ var _a;
116
+ return (_a = TYPE_NAME_TO_OPTION_COMPONENT_NAME[typeName]) !== null && _a !== void 0 ? _a : null;
117
+ }
118
+ function getKeyForComponent(typeName, componentName) {
119
+ return `${typeName}/${componentName}`;
120
+ }
121
+ function getComponentFromKey(key) {
122
+ const [typeName, componentName] = key.split('/');
123
+ return { typeName, componentName };
124
+ }
@@ -53,6 +53,7 @@ const spec_components_invalid_map_name_1 = require("./spec-components-invalid-ma
53
53
  const operation_4xx_problem_details_rfc7807_1 = require("./operation-4xx-problem-details-rfc7807");
54
54
  const required_string_property_missing_min_length_1 = require("../common/required-string-property-missing-min-length");
55
55
  const spec_strict_refs_1 = require("../common/spec-strict-refs");
56
+ const component_name_unique_1 = require("./component-name-unique");
56
57
  exports.rules = {
57
58
  spec: spec_1.OasSpec,
58
59
  'info-contact': info_contact_1.InfoContact,
@@ -107,5 +108,6 @@ exports.rules = {
107
108
  'spec-components-invalid-map-name': spec_components_invalid_map_name_1.SpecComponentsInvalidMapName,
108
109
  'required-string-property-missing-min-length': required_string_property_missing_min_length_1.RequiredStringPropertyMissingMinLength,
109
110
  'spec-strict-refs': spec_strict_refs_1.SpecStrictRefs,
111
+ 'component-name-unique': component_name_unique_1.ComponentNameUnique,
110
112
  };
111
113
  exports.preprocessors = {};
@@ -72,6 +72,8 @@ function validateDefinedAndNonEmpty(fieldName, value, ctx) {
72
72
  }
73
73
  exports.validateDefinedAndNonEmpty = validateDefinedAndNonEmpty;
74
74
  function getSuggest(given, variants) {
75
+ if (given === null)
76
+ return variants;
75
77
  if (typeof given !== 'string' || !variants.length)
76
78
  return [];
77
79
  const distances = [];
@@ -127,7 +129,7 @@ function validateSchemaEnumType(schemaEnum, propertyValue, propName, refLocation
127
129
  if (!schemaEnum) {
128
130
  return;
129
131
  }
130
- if (!schemaEnum.includes(propertyValue === null ? 'null' : propertyValue)) {
132
+ if (!schemaEnum.includes(propertyValue)) {
131
133
  report({
132
134
  location,
133
135
  message: `\`${propName}\` can be one of the following only: ${schemaEnum
@@ -58,6 +58,7 @@ const builtInRulesList = [
58
58
  'spec-components-invalid-map-name',
59
59
  'required-string-property-missing-min-length',
60
60
  'spec-strict-refs',
61
+ 'component-name-unique',
61
62
  ];
62
63
  const nodeTypesList = [
63
64
  'any',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/openapi-core",
3
- "version": "1.0.0-beta.129",
3
+ "version": "1.0.0-beta.130",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "engines": {