@redocly/openapi-core 1.0.0-beta.124 → 1.0.0-beta.126

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/bundle.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BaseResolver, Document } from './resolve';
2
2
  import { Oas3Rule } from './visitors';
3
3
  import { NormalizedNodeType, NodeType } from './types';
4
+ import { NormalizedProblem } from './walk';
4
5
  import { OasMajorVersion } from './oas-types';
5
6
  import type { Config, StyleguideConfig } from './config';
6
7
  export declare type Oas3RuleSet = Record<string, Oas3Rule>;
@@ -19,14 +20,15 @@ export declare function bundle(opts: {
19
20
  skipRedoclyRegistryRefs?: boolean;
20
21
  removeUnusedComponents?: boolean;
21
22
  keepUrlRefs?: boolean;
22
- }): Promise<{
23
+ }): Promise<BundleResult>;
24
+ export declare type BundleResult = {
23
25
  bundle: Document;
24
- problems: import("./walk").NormalizedProblem[];
26
+ problems: NormalizedProblem[];
25
27
  fileDependencies: Set<string>;
26
28
  rootType: NormalizedNodeType;
27
- refTypes: Map<string, NormalizedNodeType> | undefined;
29
+ refTypes?: Map<string, NormalizedNodeType>;
28
30
  visitorsData: Record<string, Record<string, unknown>>;
29
- }>;
31
+ };
30
32
  export declare function bundleDocument(opts: {
31
33
  document: Document;
32
34
  config: StyleguideConfig;
@@ -36,12 +38,5 @@ export declare function bundleDocument(opts: {
36
38
  skipRedoclyRegistryRefs?: boolean;
37
39
  removeUnusedComponents?: boolean;
38
40
  keepUrlRefs?: boolean;
39
- }): Promise<{
40
- bundle: Document;
41
- problems: import("./walk").NormalizedProblem[];
42
- fileDependencies: Set<string>;
43
- rootType: NormalizedNodeType;
44
- refTypes: Map<string, NormalizedNodeType> | undefined;
45
- visitorsData: Record<string, Record<string, unknown>>;
46
- }>;
41
+ }): Promise<BundleResult>;
47
42
  export declare function mapTypeToComponent(typeName: string, version: OasMajorVersion): "headers" | "definitions" | "parameters" | "examples" | "schemas" | "responses" | "requestBodies" | "securitySchemes" | "links" | "callbacks" | null;
package/lib/config/all.js CHANGED
@@ -36,7 +36,14 @@ exports.default = {
36
36
  severity: 'error',
37
37
  patterns: [],
38
38
  },
39
- 'request-mime-type': 'error',
39
+ 'request-mime-type': {
40
+ severity: 'error',
41
+ allowedValues: ['application/json'],
42
+ },
43
+ 'response-mime-type': {
44
+ severity: 'error',
45
+ allowedValues: ['application/json'],
46
+ },
40
47
  spec: 'error',
41
48
  'no-invalid-schema-examples': 'error',
42
49
  'no-invalid-parameter-examples': 'error',
@@ -1,7 +1,8 @@
1
- import type { ProblemSeverity } from '../walk';
1
+ import type { ProblemSeverity, UserContext } 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
4
  import { Location } from '../ref-utils';
5
+ import { SkipFunctionContext } from '../visitors';
5
6
  export declare type RuleSeverity = ProblemSeverity | 'off';
6
7
  export declare type RuleSettings = {
7
8
  severity: RuleSeverity;
@@ -54,6 +55,9 @@ export declare type CustomRulesConfig = {
54
55
  oas3?: Oas3RuleSet;
55
56
  oas2?: Oas2RuleSet;
56
57
  };
58
+ export declare type AssertionContext = Partial<UserContext> & SkipFunctionContext & {
59
+ node: any;
60
+ };
57
61
  export declare type AssertResult = {
58
62
  message?: string;
59
63
  location?: Location;
package/lib/resolve.js CHANGED
@@ -110,12 +110,16 @@ class BaseResolver {
110
110
  return new Source(absoluteRef, body, mimeType);
111
111
  }
112
112
  else {
113
+ if (fs.lstatSync(absoluteRef).isDirectory()) {
114
+ throw new Error(`Expected a file but received a folder at ${absoluteRef}`);
115
+ }
113
116
  const content = yield fs.promises.readFile(absoluteRef, 'utf-8');
114
117
  // In some cases file have \r\n line delimeters like on windows, we should skip it.
115
118
  return new Source(absoluteRef, content.replace(/\r\n/g, '\n'));
116
119
  }
117
120
  }
118
121
  catch (error) {
122
+ error.message = error.message.replace(', lstat', '');
119
123
  throw new ResolveError(error);
120
124
  }
121
125
  });
@@ -204,7 +208,7 @@ function resolveDocument(opts) {
204
208
  if (Array.isArray(node)) {
205
209
  const itemsType = type.items;
206
210
  // we continue resolving unknown types, but stop early on known scalars
207
- if (type !== unknownType && itemsType === undefined) {
211
+ if (itemsType === undefined && type !== unknownType && type !== types_1.SpecExtension) {
208
212
  return;
209
213
  }
210
214
  for (let i = 0; i < node.length; i++) {
@@ -1,6 +1,10 @@
1
- import { AssertResult, CustomFunction } from 'core/src/config/types';
1
+ import { AssertionContext, AssertResult, CustomFunction } from 'core/src/config/types';
2
2
  import { Location } from '../../../ref-utils';
3
- export declare type AssertionFn = (value: any, condition: any, baseLocation: Location, rawValue?: any) => AssertResult[];
3
+ export declare type AssertionFnContext = AssertionContext & {
4
+ baseLocation: Location;
5
+ rawValue?: any;
6
+ };
7
+ export declare type AssertionFn = (value: any, condition: any, ctx: AssertionFnContext) => AssertResult[];
4
8
  export declare type Asserts = {
5
9
  pattern: AssertionFn;
6
10
  notPattern: AssertionFn;
@@ -35,7 +35,7 @@ exports.runOnValuesSet = new Set([
35
35
  'const',
36
36
  ]);
37
37
  exports.asserts = {
38
- pattern: (value, condition, baseLocation) => {
38
+ pattern: (value, condition, { baseLocation }) => {
39
39
  if (typeof value === 'undefined' || utils_1.isPlainObject(value))
40
40
  return []; // property doesn't exist or is an object, no need to lint it with this assert
41
41
  const values = Array.isArray(value) ? value : [value];
@@ -47,7 +47,7 @@ exports.asserts = {
47
47
  })
48
48
  .filter(utils_1.isTruthy);
49
49
  },
50
- notPattern: (value, condition, baseLocation) => {
50
+ notPattern: (value, condition, { baseLocation }) => {
51
51
  if (typeof value === 'undefined' || utils_1.isPlainObject(value))
52
52
  return []; // property doesn't exist or is an object, no need to lint it with this assert
53
53
  const values = Array.isArray(value) ? value : [value];
@@ -59,7 +59,7 @@ exports.asserts = {
59
59
  })
60
60
  .filter(utils_1.isTruthy);
61
61
  },
62
- enum: (value, condition, baseLocation) => {
62
+ enum: (value, condition, { baseLocation }) => {
63
63
  if (typeof value === 'undefined' || utils_1.isPlainObject(value))
64
64
  return []; // property doesn't exist or is an object, no need to lint it with this assert
65
65
  const values = Array.isArray(value) ? value : [value];
@@ -70,7 +70,7 @@ exports.asserts = {
70
70
  })
71
71
  .filter(utils_1.isTruthy);
72
72
  },
73
- defined: (value, condition = true, baseLocation) => {
73
+ defined: (value, condition = true, { baseLocation }) => {
74
74
  const isDefined = typeof value !== 'undefined';
75
75
  const isValid = condition ? isDefined : !isDefined;
76
76
  return isValid
@@ -82,7 +82,7 @@ exports.asserts = {
82
82
  },
83
83
  ];
84
84
  },
85
- required: (value, keys, baseLocation) => {
85
+ required: (value, keys, { baseLocation }) => {
86
86
  return keys
87
87
  .map((requiredKey) => !value.includes(requiredKey) && {
88
88
  message: `${requiredKey} is required`,
@@ -90,7 +90,7 @@ exports.asserts = {
90
90
  })
91
91
  .filter(utils_1.isTruthy);
92
92
  },
93
- disallowed: (value, condition, baseLocation) => {
93
+ disallowed: (value, condition, { baseLocation }) => {
94
94
  if (typeof value === 'undefined' || utils_1.isPlainObject(value))
95
95
  return []; // property doesn't exist or is an object, no need to lint it with this assert
96
96
  const values = Array.isArray(value) ? value : [value];
@@ -101,7 +101,7 @@ exports.asserts = {
101
101
  })
102
102
  .filter(utils_1.isTruthy);
103
103
  },
104
- const: (value, condition, baseLocation) => {
104
+ const: (value, condition, { baseLocation }) => {
105
105
  if (typeof value === 'undefined')
106
106
  return [];
107
107
  if (Array.isArray(value)) {
@@ -123,7 +123,7 @@ exports.asserts = {
123
123
  : [];
124
124
  }
125
125
  },
126
- undefined: (value, condition = true, baseLocation) => {
126
+ undefined: (value, condition = true, { baseLocation }) => {
127
127
  const isUndefined = typeof value === 'undefined';
128
128
  const isValid = condition ? isUndefined : !isUndefined;
129
129
  return isValid
@@ -135,7 +135,7 @@ exports.asserts = {
135
135
  },
136
136
  ];
137
137
  },
138
- nonEmpty: (value, condition = true, baseLocation) => {
138
+ nonEmpty: (value, condition = true, { baseLocation }) => {
139
139
  const isEmpty = typeof value === 'undefined' || value === null || value === '';
140
140
  const isValid = condition ? !isEmpty : isEmpty;
141
141
  return isValid
@@ -147,17 +147,27 @@ exports.asserts = {
147
147
  },
148
148
  ];
149
149
  },
150
- minLength: (value, condition, baseLocation) => {
150
+ minLength: (value, condition, { baseLocation }) => {
151
151
  if (typeof value === 'undefined' || value.length >= condition)
152
152
  return []; // property doesn't exist, no need to lint it with this assert
153
- return [{ message: `Should have at least ${condition} characters`, location: baseLocation }];
153
+ return [
154
+ {
155
+ message: `Should have at least ${condition} characters`,
156
+ location: baseLocation,
157
+ },
158
+ ];
154
159
  },
155
- maxLength: (value, condition, baseLocation) => {
160
+ maxLength: (value, condition, { baseLocation }) => {
156
161
  if (typeof value === 'undefined' || value.length <= condition)
157
162
  return []; // property doesn't exist, no need to lint it with this assert
158
- return [{ message: `Should have at most ${condition} characters`, location: baseLocation }];
163
+ return [
164
+ {
165
+ message: `Should have at most ${condition} characters`,
166
+ location: baseLocation,
167
+ },
168
+ ];
159
169
  },
160
- casing: (value, condition, baseLocation) => {
170
+ casing: (value, condition, { baseLocation }) => {
161
171
  if (typeof value === 'undefined' || utils_1.isPlainObject(value))
162
172
  return []; // property doesn't exist or is an object, no need to lint it with this assert
163
173
  const values = Array.isArray(value) ? value : [value];
@@ -177,7 +187,7 @@ exports.asserts = {
177
187
  })
178
188
  .filter(utils_1.isTruthy);
179
189
  },
180
- sortOrder: (value, condition, baseLocation) => {
190
+ sortOrder: (value, condition, { baseLocation }) => {
181
191
  const direction = condition.direction || condition;
182
192
  const property = condition.property;
183
193
  if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'object' && !property) {
@@ -197,7 +207,7 @@ exports.asserts = {
197
207
  },
198
208
  ];
199
209
  },
200
- mutuallyExclusive: (value, condition, baseLocation) => {
210
+ mutuallyExclusive: (value, condition, { baseLocation }) => {
201
211
  if (utils_2.getIntersectionLength(value, condition) < 2)
202
212
  return [];
203
213
  return [
@@ -207,7 +217,7 @@ exports.asserts = {
207
217
  },
208
218
  ];
209
219
  },
210
- mutuallyRequired: (value, condition, baseLocation) => {
220
+ mutuallyRequired: (value, condition, { baseLocation }) => {
211
221
  const isValid = utils_2.getIntersectionLength(value, condition) > 0
212
222
  ? utils_2.getIntersectionLength(value, condition) === condition.length
213
223
  : true;
@@ -220,7 +230,7 @@ exports.asserts = {
220
230
  },
221
231
  ];
222
232
  },
223
- requireAny: (value, condition, baseLocation) => {
233
+ requireAny: (value, condition, { baseLocation }) => {
224
234
  return utils_2.getIntersectionLength(value, condition) >= 1
225
235
  ? []
226
236
  : [
@@ -230,7 +240,7 @@ exports.asserts = {
230
240
  },
231
241
  ];
232
242
  },
233
- ref: (_value, condition, baseLocation, rawValue) => {
243
+ ref: (_value, condition, { baseLocation, rawValue }) => {
234
244
  if (typeof rawValue === 'undefined')
235
245
  return []; // property doesn't exist, no need to lint it with this assert
236
246
  const hasRef = rawValue.hasOwnProperty('$ref');
@@ -258,6 +268,6 @@ exports.asserts = {
258
268
  },
259
269
  };
260
270
  function buildAssertCustomFunction(fn) {
261
- return (value, options, baseLocation) => fn.call(null, value, options, baseLocation);
271
+ return (value, options, ctx) => fn.call(null, value, options, ctx);
262
272
  }
263
273
  exports.buildAssertCustomFunction = buildAssertCustomFunction;
@@ -1,4 +1,5 @@
1
1
  import { Asserts } from './asserts';
2
+ import type { AssertionContext, AssertResult } from '../../../config';
2
3
  import type { Assertion, AssertionDefinition } from '.';
3
4
  import type { Oas2Visitor, Oas3Visitor, VisitFunction } from '../../../visitors';
4
5
  export declare type OrderDirection = 'asc' | 'desc';
@@ -12,9 +13,16 @@ export declare type AssertToApply = {
12
13
  runsOnKeys: boolean;
13
14
  runsOnValues: boolean;
14
15
  };
16
+ declare type RunAssertionParams = {
17
+ ctx: AssertionContext;
18
+ assert: AssertToApply;
19
+ assertionProperty?: string;
20
+ };
15
21
  export declare function getAssertsToApply(assertion: AssertionDefinition): AssertToApply[];
16
22
  export declare function buildVisitorObject(assertion: Assertion, subjectVisitor: VisitFunction<any>): Oas2Visitor | Oas3Visitor;
17
23
  export declare function buildSubjectVisitor(assertId: string, assertion: Assertion): VisitFunction<any>;
18
24
  export declare function getIntersectionLength(keys: string[], properties: string[]): number;
19
25
  export declare function isOrdered(value: any[], options: OrderOptions | OrderDirection): boolean;
26
+ export declare function runAssertion({ assert, ctx, assertionProperty, }: RunAssertionParams): AssertResult[];
20
27
  export declare function regexFromString(input: string): RegExp | null;
28
+ export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.regexFromString = exports.isOrdered = exports.getIntersectionLength = exports.buildSubjectVisitor = exports.buildVisitorObject = exports.getAssertsToApply = void 0;
3
+ exports.regexFromString = exports.runAssertion = exports.isOrdered = exports.getIntersectionLength = exports.buildSubjectVisitor = exports.buildVisitorObject = exports.getAssertsToApply = void 0;
4
4
  const asserts_1 = require("./asserts");
5
5
  const logger_1 = require("../../../logger");
6
6
  const ref_utils_1 = require("../../../ref-utils");
@@ -43,31 +43,23 @@ exports.getAssertsToApply = getAssertsToApply;
43
43
  function getAssertionProperties({ subject }) {
44
44
  return (Array.isArray(subject.property) ? subject.property : [subject === null || subject === void 0 ? void 0 : subject.property]).filter(Boolean);
45
45
  }
46
- function applyAssertions(assertionDefinition, asserts, { rawLocation, rawNode, resolve, location, node }) {
47
- var _a;
46
+ function applyAssertions(assertionDefinition, asserts, ctx) {
48
47
  const properties = getAssertionProperties(assertionDefinition);
49
48
  const assertResults = [];
50
49
  for (const assert of asserts) {
51
- const currentLocation = assert.name === 'ref' ? rawLocation : location;
52
50
  if (properties.length) {
53
51
  for (const property of properties) {
54
- // we can have resolvable scalar so need to resolve value here.
55
- const value = ref_utils_1.isRef(node[property]) ? (_a = resolve(node[property])) === null || _a === void 0 ? void 0 : _a.node : node[property];
56
52
  assertResults.push(runAssertion({
57
- values: value,
58
- rawValues: rawNode[property],
59
53
  assert,
60
- location: currentLocation.child(property),
54
+ ctx,
55
+ assertionProperty: property,
61
56
  }));
62
57
  }
63
58
  }
64
59
  else {
65
- const value = Array.isArray(node) ? node : Object.keys(node);
66
60
  assertResults.push(runAssertion({
67
- values: value,
68
- rawValues: rawNode,
69
61
  assert,
70
- location: currentLocation,
62
+ ctx,
71
63
  }));
72
64
  }
73
65
  }
@@ -77,7 +69,7 @@ function buildVisitorObject(assertion, subjectVisitor) {
77
69
  var _a, _b;
78
70
  const targetVisitorLocatorPredicates = getPredicatesFromLocators(assertion.subject);
79
71
  const targetVisitorSkipFunction = targetVisitorLocatorPredicates.length
80
- ? (node, key) => !targetVisitorLocatorPredicates.every((predicate) => predicate(key))
72
+ ? (_, key) => !targetVisitorLocatorPredicates.every((predicate) => predicate(key))
81
73
  : undefined;
82
74
  const targetVisitor = {
83
75
  [assertion.subject.type]: Object.assign({ enter: subjectVisitor }, (targetVisitorSkipFunction && { skip: targetVisitorSkipFunction })),
@@ -95,14 +87,8 @@ function buildVisitorObject(assertion, subjectVisitor) {
95
87
  }
96
88
  const locatorPredicates = getPredicatesFromLocators(assertionDefinitionNode.subject);
97
89
  const assertsToApply = getAssertsToApply(assertionDefinitionNode);
98
- const skipFunction = (node, key, { location, rawLocation, resolve, rawNode }) => !locatorPredicates.every((predicate) => predicate(key)) ||
99
- !!applyAssertions(assertionDefinitionNode, assertsToApply, {
100
- location,
101
- node,
102
- rawLocation,
103
- rawNode,
104
- resolve,
105
- }).length;
90
+ const skipFunction = (node, key, ctx) => !locatorPredicates.every((predicate) => predicate(key)) ||
91
+ !!applyAssertions(assertionDefinitionNode, assertsToApply, Object.assign(Object.assign({}, ctx), { node })).length;
106
92
  const nodeVisitor = Object.assign({}, ((locatorPredicates.length || assertsToApply.length) && { skip: skipFunction }));
107
93
  if (assertionDefinitionNode.subject.type === assertion.subject.type &&
108
94
  index === context.length - 1) {
@@ -123,23 +109,17 @@ function buildVisitorObject(assertion, subjectVisitor) {
123
109
  }
124
110
  exports.buildVisitorObject = buildVisitorObject;
125
111
  function buildSubjectVisitor(assertId, assertion) {
126
- return (node, { report, location, rawLocation, resolve, rawNode }) => {
112
+ return (node, ctx) => {
127
113
  const properties = getAssertionProperties(assertion);
128
114
  const defaultMessage = `${logger_1.colorize.blue(assertId)} failed because the ${logger_1.colorize.blue(assertion.subject.type)} ${logger_1.colorize.blue(properties.join(', '))} didn't meet the assertions: ${assertionMessageTemplates.problems}`.replace(/ +/g, ' ');
129
- const problems = applyAssertions(assertion, getAssertsToApply(assertion), {
130
- rawLocation,
131
- rawNode,
132
- resolve,
133
- location,
134
- node,
135
- });
115
+ const problems = applyAssertions(assertion, getAssertsToApply(assertion), Object.assign(Object.assign({}, ctx), { node }));
136
116
  if (problems.length) {
137
117
  for (const problemGroup of groupProblemsByPointer(problems)) {
138
118
  const message = assertion.message || defaultMessage;
139
119
  const problemMessage = getProblemsMessage(problemGroup);
140
- report({
120
+ ctx.report({
141
121
  message: message.replace(assertionMessageTemplates.problems, problemMessage),
142
- location: getProblemsLocation(problemGroup) || location,
122
+ location: getProblemsLocation(problemGroup) || ctx.location,
143
123
  forceSeverity: assertion.severity || 'error',
144
124
  suggest: assertion.suggest || [],
145
125
  ruleId: assertId,
@@ -207,9 +187,23 @@ function isOrdered(value, options) {
207
187
  return true;
208
188
  }
209
189
  exports.isOrdered = isOrdered;
210
- function runAssertion({ values, rawValues, assert, location }) {
211
- return asserts_1.asserts[assert.name](values, assert.conditions, location, rawValues);
190
+ function runAssertion({ assert, ctx, assertionProperty, }) {
191
+ var _a;
192
+ const currentLocation = assert.name === 'ref' ? ctx.rawLocation : ctx.location;
193
+ if (assertionProperty) {
194
+ const values = ref_utils_1.isRef(ctx.node[assertionProperty])
195
+ ? (_a = ctx.resolve(ctx.node[assertionProperty])) === null || _a === void 0 ? void 0 : _a.node
196
+ : ctx.node[assertionProperty];
197
+ const rawValues = ctx.rawNode[assertionProperty];
198
+ const location = currentLocation.child(assertionProperty);
199
+ return asserts_1.asserts[assert.name](values, assert.conditions, Object.assign(Object.assign({}, ctx), { baseLocation: location, rawValue: rawValues }));
200
+ }
201
+ else {
202
+ const value = Array.isArray(ctx.node) ? ctx.node : Object.keys(ctx.node);
203
+ return asserts_1.asserts[assert.name](value, assert.conditions, Object.assign(Object.assign({}, ctx), { rawValue: ctx.rawNode, baseLocation: currentLocation }));
204
+ }
212
205
  }
206
+ exports.runAssertion = runAssertion;
213
207
  function regexFromString(input) {
214
208
  const matches = input.match(/^\/(.*)\/(.*)|(.*)/);
215
209
  return matches && new RegExp(matches[1] || matches[3], matches[2]);
@@ -0,0 +1,2 @@
1
+ import { Oas3Rule } from 'core/src/visitors';
2
+ export declare const RequiredStringPropertyMissingMinLength: Oas3Rule;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RequiredStringPropertyMissingMinLength = void 0;
4
+ const RequiredStringPropertyMissingMinLength = () => {
5
+ let skipSchemaProperties;
6
+ let requiredPropertiesSet;
7
+ return {
8
+ Schema: {
9
+ enter(schema) {
10
+ if (!(schema === null || schema === void 0 ? void 0 : schema.required)) {
11
+ skipSchemaProperties = true;
12
+ return;
13
+ }
14
+ requiredPropertiesSet = new Set(schema.required);
15
+ skipSchemaProperties = false;
16
+ },
17
+ SchemaProperties: {
18
+ skip() {
19
+ return skipSchemaProperties;
20
+ },
21
+ Schema: {
22
+ enter(schema, { key, location, report }) {
23
+ if (requiredPropertiesSet.has(key) && schema.type === 'string') {
24
+ if (!(schema === null || schema === void 0 ? void 0 : schema.minLength)) {
25
+ report({
26
+ message: 'Property minLength is required.',
27
+ location: location.key(),
28
+ });
29
+ }
30
+ }
31
+ },
32
+ },
33
+ },
34
+ },
35
+ };
36
+ };
37
+ exports.RequiredStringPropertyMissingMinLength = RequiredStringPropertyMissingMinLength;
@@ -41,5 +41,6 @@ export declare const rules: {
41
41
  'response-contains-header': Oas2Rule;
42
42
  'response-contains-property': Oas2Rule;
43
43
  'scalar-property-missing-example': import("../../visitors").Oas3Rule | Oas2Rule;
44
+ 'required-string-property-missing-min-length': import("../../visitors").Oas3Rule;
44
45
  };
45
46
  export declare const preprocessors: {};
@@ -41,6 +41,7 @@ const path_segment_plural_1 = require("../common/path-segment-plural");
41
41
  const response_contains_header_1 = require("../common/response-contains-header");
42
42
  const response_contains_property_1 = require("./response-contains-property");
43
43
  const scalar_property_missing_example_1 = require("../common/scalar-property-missing-example");
44
+ const required_string_property_missing_min_length_1 = require("../common/required-string-property-missing-min-length");
44
45
  exports.rules = {
45
46
  spec: spec_1.OasSpec,
46
47
  'no-invalid-schema-examples': no_invalid_schema_examples_1.NoInvalidSchemaExamples,
@@ -83,5 +84,6 @@ exports.rules = {
83
84
  'response-contains-header': response_contains_header_1.ResponseContainsHeader,
84
85
  'response-contains-property': response_contains_property_1.ResponseContainsProperty,
85
86
  'scalar-property-missing-example': scalar_property_missing_example_1.ScalarPropertyMissingExample,
87
+ 'required-string-property-missing-min-length': required_string_property_missing_min_length_1.RequiredStringPropertyMissingMinLength,
86
88
  };
87
89
  exports.preprocessors = {};
@@ -51,6 +51,7 @@ const response_contains_property_1 = require("./response-contains-property");
51
51
  const scalar_property_missing_example_1 = require("../common/scalar-property-missing-example");
52
52
  const spec_components_invalid_map_name_1 = require("./spec-components-invalid-map-name");
53
53
  const operation_4xx_problem_details_rfc7807_1 = require("./operation-4xx-problem-details-rfc7807");
54
+ const required_string_property_missing_min_length_1 = require("../common/required-string-property-missing-min-length");
54
55
  exports.rules = {
55
56
  spec: spec_1.OasSpec,
56
57
  'info-contact': info_contact_1.InfoContact,
@@ -103,5 +104,6 @@ exports.rules = {
103
104
  'response-contains-property': response_contains_property_1.ResponseContainsProperty,
104
105
  'scalar-property-missing-example': scalar_property_missing_example_1.ScalarPropertyMissingExample,
105
106
  'spec-components-invalid-map-name': spec_components_invalid_map_name_1.SpecComponentsInvalidMapName,
107
+ 'required-string-property-missing-min-length': required_string_property_missing_min_length_1.RequiredStringPropertyMissingMinLength,
106
108
  };
107
109
  exports.preprocessors = {};
@@ -55,6 +55,7 @@ const builtInRulesList = [
55
55
  'response-contains-property',
56
56
  'scalar-property-missing-example',
57
57
  'spec-components-invalid-map-name',
58
+ 'required-string-property-missing-min-length',
58
59
  ];
59
60
  const nodeTypesList = [
60
61
  'any',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/openapi-core",
3
- "version": "1.0.0-beta.124",
3
+ "version": "1.0.0-beta.126",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "engines": {
@@ -5,6 +5,7 @@ import { resolveDocument, BaseResolver, Document } from '../resolve';
5
5
  import { parseYamlToDocument } from '../../__tests__/utils';
6
6
  import { Oas3Types } from '../types/oas3';
7
7
  import { normalizeTypes } from '../types';
8
+ import * as fs from 'fs';
8
9
 
9
10
  describe('collect refs', () => {
10
11
  it('should resolve local refs', async () => {
@@ -405,4 +406,25 @@ describe('collect refs', () => {
405
406
 
406
407
  expect(Array.from(resolvedRefs.values()).pop()!.node).toEqual({ type: 'string' });
407
408
  });
409
+
410
+ it('should throw error if ref is folder', async () => {
411
+ const cwd = path.join(__dirname, 'fixtures/resolve');
412
+ const rootDocument = parseYamlToDocument(
413
+ outdent`
414
+ openapi: 3.0.0
415
+ components:
416
+ $ref: "./transitive/components.yaml#/components/schemas/a"
417
+ `,
418
+ path.join(cwd, 'foobar')
419
+ );
420
+ jest.spyOn(fs, 'lstatSync').mockImplementation((_) => ({ isDirectory: () => true } as any));
421
+
422
+ const resolvedRefs = await resolveDocument({
423
+ rootDocument,
424
+ externalRefResolver: new BaseResolver(),
425
+ rootType: normalizeTypes(Oas3Types).Root,
426
+ });
427
+
428
+ expect(Array.from(resolvedRefs.values()).pop()!.error).toBeInstanceOf(Error);
429
+ });
408
430
  });
package/src/bundle.ts CHANGED
@@ -5,7 +5,7 @@ import { Oas3Types } from './types/oas3';
5
5
  import { Oas2Types } from './types/oas2';
6
6
  import { Oas3_1Types } from './types/oas3_1';
7
7
  import { NormalizedNodeType, normalizeTypes, NodeType } from './types';
8
- import { WalkContext, walkDocument, UserContext, ResolveResult } from './walk';
8
+ import { WalkContext, walkDocument, UserContext, ResolveResult, NormalizedProblem } from './walk';
9
9
  import { detectOpenAPI, openAPIMajor, OasMajorVersion } from './oas-types';
10
10
  import { isAbsoluteUrl, isRef, Location, refBaseName } from './ref-utils';
11
11
  import { initRules } from './config/rules';
@@ -64,6 +64,15 @@ export async function bundle(opts: {
64
64
 
65
65
  type BundleContext = WalkContext;
66
66
 
67
+ export type BundleResult = {
68
+ bundle: Document;
69
+ problems: NormalizedProblem[];
70
+ fileDependencies: Set<string>;
71
+ rootType: NormalizedNodeType;
72
+ refTypes?: Map<string, NormalizedNodeType>;
73
+ visitorsData: Record<string, Record<string, unknown>>;
74
+ };
75
+
67
76
  export async function bundleDocument(opts: {
68
77
  document: Document;
69
78
  config: StyleguideConfig;
@@ -73,7 +82,7 @@ export async function bundleDocument(opts: {
73
82
  skipRedoclyRegistryRefs?: boolean;
74
83
  removeUnusedComponents?: boolean;
75
84
  keepUrlRefs?: boolean;
76
- }) {
85
+ }): Promise<BundleResult> {
77
86
  const {
78
87
  document,
79
88
  config,
package/src/config/all.ts CHANGED
@@ -36,7 +36,14 @@ export default {
36
36
  severity: 'error',
37
37
  patterns: [],
38
38
  },
39
- 'request-mime-type': 'error',
39
+ 'request-mime-type': {
40
+ severity: 'error',
41
+ allowedValues: ['application/json'],
42
+ },
43
+ 'response-mime-type': {
44
+ severity: 'error',
45
+ allowedValues: ['application/json'],
46
+ },
40
47
  spec: 'error',
41
48
  'no-invalid-schema-examples': 'error',
42
49
  'no-invalid-parameter-examples': 'error',
@@ -1,4 +1,4 @@
1
- import type { ProblemSeverity } from '../walk';
1
+ import type { ProblemSeverity, UserContext } from '../walk';
2
2
  import type {
3
3
  Oas3PreprocessorsSet,
4
4
  OasMajorVersion,
@@ -11,6 +11,7 @@ import type {
11
11
  } from '../oas-types';
12
12
  import type { NodeType } from '../types';
13
13
  import { Location } from '../ref-utils';
14
+ import { SkipFunctionContext } from '../visitors';
14
15
 
15
16
  export type RuleSeverity = ProblemSeverity | 'off';
16
17
 
@@ -86,6 +87,8 @@ export type CustomRulesConfig = {
86
87
  oas2?: Oas2RuleSet;
87
88
  };
88
89
 
90
+ export type AssertionContext = Partial<UserContext> & SkipFunctionContext & { node: any };
91
+
89
92
  export type AssertResult = { message?: string; location?: Location };
90
93
  export type CustomFunction = (
91
94
  value: any,