@redocly/openapi-core 1.16.0 → 1.17.1
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/CHANGELOG.md +17 -0
- package/lib/bundle.d.ts +1 -1
- package/lib/config/load.d.ts +12 -3
- package/lib/config/load.js +32 -12
- package/lib/config/utils.d.ts +1 -0
- package/lib/config/utils.js +5 -1
- package/lib/lint.d.ts +1 -0
- package/lib/lint.js +3 -7
- package/lib/oas-types.d.ts +1 -1
- package/lib/types/oas3_1.js +8 -1
- package/lib/types/redocly-yaml.d.ts +4 -2
- package/lib/types/redocly-yaml.js +35 -36
- package/package.json +2 -2
- package/src/__tests__/lint.test.ts +146 -12
- package/src/config/__tests__/load.test.ts +86 -61
- package/src/config/load.ts +49 -23
- package/src/config/utils.ts +4 -0
- package/src/lint.ts +10 -9
- package/src/types/oas3_1.ts +8 -0
- package/src/types/redocly-yaml.ts +33 -33
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @redocly/openapi-core
|
|
2
2
|
|
|
3
|
+
## 1.17.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Added JSON Schema draft 2019-09+ validation keyword - `dependentRequired`.
|
|
8
|
+
- Updated @redocly/config to v0.6.2.
|
|
9
|
+
|
|
10
|
+
## 1.17.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- Changed resolution process to include extendedTypes and plugins before linting.
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Added support for the `contentSchema` keyword to parse as a schema instance.
|
|
19
|
+
|
|
3
20
|
## 1.16.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
package/lib/bundle.d.ts
CHANGED
|
@@ -47,4 +47,4 @@ export declare function bundleDocument(opts: {
|
|
|
47
47
|
removeUnusedComponents?: boolean;
|
|
48
48
|
keepUrlRefs?: boolean;
|
|
49
49
|
}): Promise<BundleResult>;
|
|
50
|
-
export declare function mapTypeToComponent(typeName: string, version: SpecMajorVersion): "definitions" | "examples" | "
|
|
50
|
+
export declare function mapTypeToComponent(typeName: string, version: SpecMajorVersion): "definitions" | "examples" | "parameters" | "headers" | "schemas" | "responses" | "requestBodies" | "securitySchemes" | "links" | "callbacks" | null;
|
package/lib/config/load.d.ts
CHANGED
|
@@ -4,7 +4,12 @@ import type { Document } from '../resolve';
|
|
|
4
4
|
import type { RegionalTokenWithValidity } from '../redocly/redocly-client-types';
|
|
5
5
|
import type { RawConfig, RawUniversalConfig, Region } from './types';
|
|
6
6
|
import type { ResolvedRefMap } from '../resolve';
|
|
7
|
-
export type RawConfigProcessor = (
|
|
7
|
+
export type RawConfigProcessor = (params: {
|
|
8
|
+
document: Document;
|
|
9
|
+
resolvedRefMap: ResolvedRefMap;
|
|
10
|
+
config: Config;
|
|
11
|
+
parsed: Document['parsed'];
|
|
12
|
+
}) => void | Promise<void>;
|
|
8
13
|
export declare function loadConfig(options?: {
|
|
9
14
|
configPath?: string;
|
|
10
15
|
customExtends?: string[];
|
|
@@ -17,9 +22,13 @@ export declare const CONFIG_FILE_NAMES: string[];
|
|
|
17
22
|
export declare function findConfig(dir?: string): string | undefined;
|
|
18
23
|
export declare function getConfig(options?: {
|
|
19
24
|
configPath?: string;
|
|
20
|
-
processRawConfig?: RawConfigProcessor;
|
|
21
25
|
externalRefResolver?: BaseResolver;
|
|
22
|
-
}): Promise<
|
|
26
|
+
}): Promise<{
|
|
27
|
+
rawConfig: RawConfig;
|
|
28
|
+
document?: Document;
|
|
29
|
+
parsed?: Document['parsed'];
|
|
30
|
+
resolvedRefMap?: ResolvedRefMap;
|
|
31
|
+
}>;
|
|
23
32
|
type CreateConfigOptions = {
|
|
24
33
|
extends?: string[];
|
|
25
34
|
tokens?: RegionalTokenWithValidity[];
|
package/lib/config/load.js
CHANGED
|
@@ -68,10 +68,13 @@ function addConfigMetadata({ rawConfig, customExtends, configPath, tokens, files
|
|
|
68
68
|
function loadConfig(options = {}) {
|
|
69
69
|
return __awaiter(this, void 0, void 0, function* () {
|
|
70
70
|
const { configPath = findConfig(), customExtends, processRawConfig, files, region, externalRefResolver, } = options;
|
|
71
|
-
const rawConfig = yield getConfig({
|
|
71
|
+
const { rawConfig, document, parsed, resolvedRefMap } = yield getConfig({
|
|
72
|
+
configPath,
|
|
73
|
+
externalRefResolver,
|
|
74
|
+
});
|
|
72
75
|
const redoclyClient = env_1.isBrowser ? undefined : new redocly_1.RedoclyClient();
|
|
73
76
|
const tokens = redoclyClient && redoclyClient.hasTokens() ? redoclyClient.getAllTokens() : [];
|
|
74
|
-
|
|
77
|
+
const config = yield addConfigMetadata({
|
|
75
78
|
rawConfig,
|
|
76
79
|
customExtends,
|
|
77
80
|
configPath,
|
|
@@ -80,6 +83,23 @@ function loadConfig(options = {}) {
|
|
|
80
83
|
region,
|
|
81
84
|
externalRefResolver,
|
|
82
85
|
});
|
|
86
|
+
if (document && parsed && resolvedRefMap && typeof processRawConfig === 'function') {
|
|
87
|
+
try {
|
|
88
|
+
yield processRawConfig({
|
|
89
|
+
document,
|
|
90
|
+
resolvedRefMap,
|
|
91
|
+
config,
|
|
92
|
+
parsed,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
if (e instanceof utils_2.ConfigValidationError) {
|
|
97
|
+
throw e;
|
|
98
|
+
}
|
|
99
|
+
throw new Error(`Error parsing config file at '${configPath}': ${e.message}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return config;
|
|
83
103
|
});
|
|
84
104
|
}
|
|
85
105
|
exports.loadConfig = loadConfig;
|
|
@@ -101,24 +121,24 @@ function findConfig(dir) {
|
|
|
101
121
|
exports.findConfig = findConfig;
|
|
102
122
|
function getConfig(options = {}) {
|
|
103
123
|
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
-
const { configPath = findConfig(),
|
|
124
|
+
const { configPath = findConfig(), externalRefResolver = new resolve_1.BaseResolver() } = options;
|
|
105
125
|
if (!configPath)
|
|
106
|
-
return {};
|
|
126
|
+
return { rawConfig: {} };
|
|
107
127
|
try {
|
|
108
128
|
const { document, resolvedRefMap } = yield (0, config_resolvers_1.resolveConfigFileAndRefs)({
|
|
109
129
|
configPath,
|
|
110
130
|
externalRefResolver,
|
|
111
131
|
});
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
132
|
+
const bundledRefMap = (0, utils_2.deepCloneMapWithJSON)(resolvedRefMap);
|
|
133
|
+
const parsed = yield (0, bundle_1.bundleConfig)(JSON.parse(JSON.stringify(document)), bundledRefMap);
|
|
134
|
+
return {
|
|
135
|
+
rawConfig: (0, utils_2.transformConfig)(parsed),
|
|
136
|
+
document,
|
|
137
|
+
parsed,
|
|
138
|
+
resolvedRefMap,
|
|
139
|
+
};
|
|
117
140
|
}
|
|
118
141
|
catch (e) {
|
|
119
|
-
if (e instanceof utils_2.ConfigValidationError) {
|
|
120
|
-
throw e;
|
|
121
|
-
}
|
|
122
142
|
throw new Error(`Error parsing config file at '${configPath}': ${e.message}`);
|
|
123
143
|
}
|
|
124
144
|
});
|
package/lib/config/utils.d.ts
CHANGED
|
@@ -14,3 +14,4 @@ export declare function getResolveConfig(resolve?: RawResolveConfig): ResolveCon
|
|
|
14
14
|
export declare function getUniquePlugins(plugins: Plugin[]): Plugin[];
|
|
15
15
|
export declare class ConfigValidationError extends Error {
|
|
16
16
|
}
|
|
17
|
+
export declare function deepCloneMapWithJSON<K, V>(originalMap: Map<K, V>): Map<K, V>;
|
package/lib/config/utils.js
CHANGED
|
@@ -11,7 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
return t;
|
|
12
12
|
};
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.ConfigValidationError = exports.getUniquePlugins = exports.getResolveConfig = exports.transformConfig = exports.checkForDeprecatedFields = exports.getMergedConfig = exports.mergeExtends = exports.prefixRules = exports.transformApiDefinitionsToApis = exports.parsePresetName = void 0;
|
|
14
|
+
exports.deepCloneMapWithJSON = exports.ConfigValidationError = exports.getUniquePlugins = exports.getResolveConfig = exports.transformConfig = exports.checkForDeprecatedFields = exports.getMergedConfig = exports.mergeExtends = exports.prefixRules = exports.transformApiDefinitionsToApis = exports.parsePresetName = void 0;
|
|
15
15
|
const utils_1 = require("../utils");
|
|
16
16
|
const config_1 = require("./config");
|
|
17
17
|
const logger_1 = require("../logger");
|
|
@@ -251,3 +251,7 @@ exports.getUniquePlugins = getUniquePlugins;
|
|
|
251
251
|
class ConfigValidationError extends Error {
|
|
252
252
|
}
|
|
253
253
|
exports.ConfigValidationError = ConfigValidationError;
|
|
254
|
+
function deepCloneMapWithJSON(originalMap) {
|
|
255
|
+
return new Map(JSON.parse(JSON.stringify([...originalMap])));
|
|
256
|
+
}
|
|
257
|
+
exports.deepCloneMapWithJSON = deepCloneMapWithJSON;
|
package/lib/lint.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export declare function lintDocument(opts: {
|
|
|
22
22
|
}): Promise<import("./walk").NormalizedProblem[]>;
|
|
23
23
|
export declare function lintConfig(opts: {
|
|
24
24
|
document: Document;
|
|
25
|
+
config: Config;
|
|
25
26
|
resolvedRefMap?: ResolvedRefMap;
|
|
26
27
|
severity?: ProblemSeverity;
|
|
27
28
|
externalRefResolver?: BaseResolver;
|
package/lib/lint.js
CHANGED
|
@@ -20,6 +20,7 @@ const oas_types_1 = require("./oas-types");
|
|
|
20
20
|
const redocly_yaml_1 = require("./types/redocly-yaml");
|
|
21
21
|
const spec_1 = require("./rules/common/spec");
|
|
22
22
|
const no_unresolved_refs_1 = require("./rules/no-unresolved-refs");
|
|
23
|
+
const config_2 = require("@redocly/config");
|
|
23
24
|
function lint(opts) {
|
|
24
25
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
26
|
const { ref, externalRefResolver = new resolve_1.BaseResolver(opts.config.resolve) } = opts;
|
|
@@ -85,18 +86,13 @@ function lintDocument(opts) {
|
|
|
85
86
|
exports.lintDocument = lintDocument;
|
|
86
87
|
function lintConfig(opts) {
|
|
87
88
|
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
-
const { document, severity, externalRefResolver = new resolve_1.BaseResolver() } = opts;
|
|
89
|
+
const { document, severity, externalRefResolver = new resolve_1.BaseResolver(), config } = opts;
|
|
89
90
|
const ctx = {
|
|
90
91
|
problems: [],
|
|
91
92
|
oasVersion: oas_types_1.SpecVersion.OAS3_0,
|
|
92
93
|
visitorsData: {},
|
|
93
94
|
};
|
|
94
|
-
const
|
|
95
|
-
const config = new config_1.StyleguideConfig({
|
|
96
|
-
plugins,
|
|
97
|
-
rules: { spec: 'error' },
|
|
98
|
-
});
|
|
99
|
-
const types = (0, types_1.normalizeTypes)(opts.externalConfigTypes || redocly_yaml_1.ConfigTypes, config);
|
|
95
|
+
const types = (0, types_1.normalizeTypes)(opts.externalConfigTypes || (0, redocly_yaml_1.createConfigTypes)(config_2.rootRedoclyConfigSchema, config), { doNotResolveExamples: config.styleguide.doNotResolveExamples });
|
|
100
96
|
const rules = [
|
|
101
97
|
{
|
|
102
98
|
severity: severity || 'error',
|
package/lib/oas-types.d.ts
CHANGED
|
@@ -24,4 +24,4 @@ export type Oas2DecoratorsSet = Record<string, Oas2Preprocessor>;
|
|
|
24
24
|
export type Async2DecoratorsSet = Record<string, Async2Preprocessor>;
|
|
25
25
|
export declare function detectSpec(root: any): SpecVersion;
|
|
26
26
|
export declare function getMajorSpecVersion(version: SpecVersion): SpecMajorVersion;
|
|
27
|
-
export declare function getTypes(spec: SpecVersion): Record<string, import("./types").NodeType> | Record<"Root" | "Tag" | "ExternalDocs" | "SecurityRequirement" | "Info" | "Contact" | "License" | "Paths" | "PathItem" | "Parameter" | "Operation" | "Example" | "Header" | "Responses" | "Response" | "Schema" | "Xml" | "SchemaProperties" | "NamedSchemas" | "NamedResponses" | "NamedParameters" | "NamedSecuritySchemes" | "SecurityScheme" | "Examples" | "ExamplesMap" | "TagList" | "SecurityRequirementList" | "ParameterList" | "ParameterItems" | "TagGroup" | "TagGroups" | "EnumDescriptions" | "Logo" | "XCodeSample" | "XCodeSampleList" | "XServer" | "XServerList", import("./types").NodeType> | Record<"Root" | "Tag" | "ExternalDocs" | "Server" | "ServerVariable" | "SecurityRequirement" | "Info" | "Contact" | "License" | "Paths" | "PathItem" | "Callback" | "CallbacksMap" | "Parameter" | "Operation" | "RequestBody" | "MediaTypesMap" | "MediaType" | "Example" | "Encoding" | "Header" | "Responses" | "Response" | "Link" | "Schema" | "Xml" | "SchemaProperties" | "DiscriminatorMapping" | "Discriminator" | "Components" | "NamedSchemas" | "NamedResponses" | "NamedParameters" | "NamedExamples" | "NamedRequestBodies" | "NamedHeaders" | "NamedSecuritySchemes" | "NamedLinks" | "NamedCallbacks" | "ImplicitFlow" | "PasswordFlow" | "ClientCredentials" | "AuthorizationCode" | "OAuth2Flows" | "SecurityScheme" | "ServerVariablesMap" | "ExamplesMap" | "EncodingMap" | "HeadersMap" | "LinksMap" | "TagList" | "SecurityRequirementList" | "ParameterList" | "TagGroup" | "TagGroups" | "EnumDescriptions" | "Logo" | "XCodeSample" | "XCodeSampleList" | "ServerList" | "XUsePkce"
|
|
27
|
+
export declare function getTypes(spec: SpecVersion): Record<string, import("./types").NodeType> | Record<"Root" | "Tag" | "ExternalDocs" | "SecurityRequirement" | "Info" | "Contact" | "License" | "Paths" | "PathItem" | "Parameter" | "Operation" | "Example" | "Header" | "Responses" | "Response" | "Schema" | "Xml" | "SchemaProperties" | "NamedSchemas" | "NamedResponses" | "NamedParameters" | "NamedSecuritySchemes" | "SecurityScheme" | "Examples" | "ExamplesMap" | "TagList" | "SecurityRequirementList" | "ParameterList" | "ParameterItems" | "TagGroup" | "TagGroups" | "EnumDescriptions" | "Logo" | "XCodeSample" | "XCodeSampleList" | "XServer" | "XServerList", import("./types").NodeType> | Record<"Root" | "Tag" | "ExternalDocs" | "Server" | "ServerVariable" | "SecurityRequirement" | "Info" | "Contact" | "License" | "Paths" | "PathItem" | "Callback" | "CallbacksMap" | "Parameter" | "Operation" | "RequestBody" | "MediaTypesMap" | "MediaType" | "Example" | "Encoding" | "Header" | "Responses" | "Response" | "Link" | "Schema" | "Xml" | "SchemaProperties" | "DiscriminatorMapping" | "Discriminator" | "Components" | "NamedSchemas" | "NamedResponses" | "NamedParameters" | "NamedExamples" | "NamedRequestBodies" | "NamedHeaders" | "NamedSecuritySchemes" | "NamedLinks" | "NamedCallbacks" | "ImplicitFlow" | "PasswordFlow" | "ClientCredentials" | "AuthorizationCode" | "OAuth2Flows" | "SecurityScheme" | "ServerVariablesMap" | "ExamplesMap" | "EncodingMap" | "HeadersMap" | "LinksMap" | "WebhooksMap" | "TagList" | "SecurityRequirementList" | "ParameterList" | "TagGroup" | "TagGroups" | "EnumDescriptions" | "Logo" | "XCodeSample" | "XCodeSampleList" | "ServerList" | "XUsePkce", import("./types").NodeType> | Record<"Root" | "Info" | "License" | "Operation" | "Schema" | "SchemaProperties" | "Components" | "SecurityScheme" | "NamedPathItems" | "DependentRequired", import("./types").NodeType>;
|
package/lib/types/oas3_1.js
CHANGED
|
@@ -129,6 +129,7 @@ const Schema = {
|
|
|
129
129
|
then: 'Schema',
|
|
130
130
|
else: 'Schema',
|
|
131
131
|
dependentSchemas: (0, _1.listOf)('Schema'),
|
|
132
|
+
dependentRequired: 'DependentRequired',
|
|
132
133
|
prefixItems: (0, _1.listOf)('Schema'),
|
|
133
134
|
contains: 'Schema',
|
|
134
135
|
minContains: { type: 'integer', minimum: 0 },
|
|
@@ -168,6 +169,7 @@ const Schema = {
|
|
|
168
169
|
format: { type: 'string' },
|
|
169
170
|
contentEncoding: { type: 'string' },
|
|
170
171
|
contentMediaType: { type: 'string' },
|
|
172
|
+
contentSchema: 'Schema',
|
|
171
173
|
default: null,
|
|
172
174
|
readOnly: { type: 'boolean' },
|
|
173
175
|
writeOnly: { type: 'boolean' },
|
|
@@ -261,10 +263,15 @@ const SecurityScheme = {
|
|
|
261
263
|
},
|
|
262
264
|
extensionsPrefix: 'x-',
|
|
263
265
|
};
|
|
266
|
+
const DependentRequired = {
|
|
267
|
+
properties: {},
|
|
268
|
+
additionalProperties: { type: 'array', items: { type: 'string' } },
|
|
269
|
+
};
|
|
264
270
|
exports.Oas3_1Types = Object.assign(Object.assign({}, oas3_1.Oas3Types), { Info,
|
|
265
271
|
Root,
|
|
266
272
|
Schema,
|
|
267
273
|
SchemaProperties,
|
|
268
274
|
License,
|
|
269
275
|
Components, NamedPathItems: (0, _1.mapOf)('PathItem'), SecurityScheme,
|
|
270
|
-
Operation
|
|
276
|
+
Operation,
|
|
277
|
+
DependentRequired });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { NodeType } from '.';
|
|
2
2
|
import type { JSONSchema } from 'json-schema-to-ts';
|
|
3
|
+
import { Config } from '../config';
|
|
3
4
|
declare const builtInCommonRules: readonly ["spec", "info-contact", "operation-operationId", "tag-description", "tags-alphabetical"];
|
|
4
5
|
export type BuiltInCommonRuleId = typeof builtInCommonRules[number];
|
|
5
6
|
declare const builtInCommonOASRules: readonly ["info-license-url", "info-license", "no-ambiguous-paths", "no-enum-type-mismatch", "no-http-verbs-in-paths", "no-identical-paths", "no-invalid-parameter-examples", "no-invalid-schema-examples", "no-path-trailing-slash", "operation-2xx-response", "operation-4xx-response", "operation-description", "operation-operationId-unique", "operation-operationId-url-safe", "operation-parameters-unique", "operation-singular-tag", "operation-summary", "operation-tag-defined", "parameter-description", "path-declaration-must-exist", "path-excludes-patterns", "path-http-verbs-order", "path-not-include-query", "path-params-defined", "path-parameters-defined", "path-segment-plural", "paths-kebab-case", "required-string-property-missing-min-length", "response-contains-header", "scalar-property-missing-example", "security-defined", "spec-strict-refs", "no-unresolved-refs", "no-required-schema-properties-undefined"];
|
|
@@ -14,11 +15,12 @@ declare const oas2NodeTypesList: readonly ["Root", "Tag", "TagList", "ExternalDo
|
|
|
14
15
|
export type Oas2NodeType = typeof oas2NodeTypesList[number];
|
|
15
16
|
declare const oas3NodeTypesList: readonly ["Root", "Tag", "TagList", "ExternalDocs", "Server", "ServerList", "ServerVariable", "ServerVariablesMap", "SecurityRequirement", "SecurityRequirementList", "Info", "Contact", "License", "Paths", "PathItem", "Parameter", "ParameterList", "Operation", "Callback", "CallbacksMap", "RequestBody", "MediaTypesMap", "MediaType", "Example", "ExamplesMap", "Encoding", "EncodingMap", "Header", "HeadersMap", "Responses", "Response", "Link", "LinksMap", "Schema", "Xml", "SchemaProperties", "DiscriminatorMapping", "Discriminator", "Components", "NamedSchemas", "NamedResponses", "NamedParameters", "NamedExamples", "NamedRequestBodies", "NamedHeaders", "NamedSecuritySchemes", "NamedLinks", "NamedCallbacks", "ImplicitFlow", "PasswordFlow", "ClientCredentials", "AuthorizationCode", "OAuth2Flows", "SecurityScheme", "TagGroup", "TagGroups", "EnumDescriptions", "Logo", "XCodeSample", "XCodeSampleList", "XUsePkce", "WebhooksMap"];
|
|
16
17
|
export type Oas3NodeType = typeof oas3NodeTypesList[number];
|
|
17
|
-
declare const oas3_1NodeTypesList: readonly ["Root", "Schema", "SchemaProperties", "Info", "License", "Components", "NamedPathItems", "SecurityScheme", "Operation"];
|
|
18
|
+
declare const oas3_1NodeTypesList: readonly ["Root", "Schema", "SchemaProperties", "Info", "License", "Components", "NamedPathItems", "SecurityScheme", "Operation", "DependentRequired"];
|
|
18
19
|
export type Oas3_1NodeType = typeof oas3_1NodeTypesList[number];
|
|
19
|
-
export declare
|
|
20
|
+
export declare function createConfigTypes(extraSchemas: JSONSchema, config?: Config): {
|
|
20
21
|
ConfigRoot: NodeType;
|
|
21
22
|
ConfigApisProperties: NodeType;
|
|
23
|
+
AssertionDefinitionSubject: NodeType;
|
|
22
24
|
};
|
|
23
25
|
export declare const ConfigTypes: Record<string, NodeType>;
|
|
24
26
|
export {};
|
|
@@ -5,6 +5,7 @@ const config_1 = require("@redocly/config");
|
|
|
5
5
|
const _1 = require(".");
|
|
6
6
|
const utils_1 = require("../utils");
|
|
7
7
|
const json_schema_adapter_1 = require("./json-schema-adapter");
|
|
8
|
+
const oas_types_1 = require("../oas-types");
|
|
8
9
|
const builtInCommonRules = [
|
|
9
10
|
'spec',
|
|
10
11
|
'info-contact',
|
|
@@ -193,8 +194,8 @@ const oas3_1NodeTypesList = [
|
|
|
193
194
|
'NamedPathItems',
|
|
194
195
|
'SecurityScheme',
|
|
195
196
|
'Operation',
|
|
197
|
+
'DependentRequired',
|
|
196
198
|
];
|
|
197
|
-
const asyncNodeTypesList = ['Message'];
|
|
198
199
|
const ConfigStyleguide = {
|
|
199
200
|
properties: {
|
|
200
201
|
extends: {
|
|
@@ -296,37 +297,30 @@ const Schema = {
|
|
|
296
297
|
properties: {},
|
|
297
298
|
additionalProperties: {},
|
|
298
299
|
};
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
...new Set([
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
}
|
|
320
|
-
else {
|
|
321
|
-
return { type: 'string' };
|
|
322
|
-
}
|
|
300
|
+
function createAssertionDefinitionSubject(nodeNames) {
|
|
301
|
+
return {
|
|
302
|
+
properties: {
|
|
303
|
+
type: {
|
|
304
|
+
enum: [...new Set(['any', ...nodeNames, 'SpecExtension'])],
|
|
305
|
+
},
|
|
306
|
+
property: (value) => {
|
|
307
|
+
if (Array.isArray(value)) {
|
|
308
|
+
return { type: 'array', items: { type: 'string' } };
|
|
309
|
+
}
|
|
310
|
+
else if (value === null) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
return { type: 'string' };
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
filterInParentKeys: { type: 'array', items: { type: 'string' } },
|
|
318
|
+
filterOutParentKeys: { type: 'array', items: { type: 'string' } },
|
|
319
|
+
matchParentKeys: { type: 'string' },
|
|
323
320
|
},
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
},
|
|
328
|
-
required: ['type'],
|
|
329
|
-
};
|
|
321
|
+
required: ['type'],
|
|
322
|
+
};
|
|
323
|
+
}
|
|
330
324
|
const AssertionDefinitionAssertions = {
|
|
331
325
|
properties: {
|
|
332
326
|
enum: { type: 'array', items: { type: 'string' } },
|
|
@@ -897,11 +891,17 @@ const ConfigMockServer = {
|
|
|
897
891
|
errorIfForcedExampleNotFound: { type: 'boolean' },
|
|
898
892
|
},
|
|
899
893
|
};
|
|
900
|
-
|
|
894
|
+
function createConfigTypes(extraSchemas, config) {
|
|
895
|
+
const nodeNames = Object.values(oas_types_1.SpecVersion).flatMap((version) => {
|
|
896
|
+
const types = (config === null || config === void 0 ? void 0 : config.styleguide)
|
|
897
|
+
? config.styleguide.extendTypes((0, oas_types_1.getTypes)(version), version)
|
|
898
|
+
: (0, oas_types_1.getTypes)(version);
|
|
899
|
+
return Object.keys(types);
|
|
900
|
+
});
|
|
901
901
|
// Create types based on external schemas
|
|
902
902
|
const nodeTypes = (0, json_schema_adapter_1.getNodeTypesFromJSONSchema)('rootRedoclyConfigSchema', extraSchemas);
|
|
903
|
-
return Object.assign(Object.assign(Object.assign({}, CoreConfigTypes), { ConfigRoot: createConfigRoot(nodeTypes), ConfigApisProperties: createConfigApisProperties(nodeTypes) }), nodeTypes);
|
|
904
|
-
}
|
|
903
|
+
return Object.assign(Object.assign(Object.assign({}, CoreConfigTypes), { ConfigRoot: createConfigRoot(nodeTypes), ConfigApisProperties: createConfigApisProperties(nodeTypes), AssertionDefinitionSubject: createAssertionDefinitionSubject(nodeNames) }), nodeTypes);
|
|
904
|
+
}
|
|
905
905
|
exports.createConfigTypes = createConfigTypes;
|
|
906
906
|
const CoreConfigTypes = {
|
|
907
907
|
Assert,
|
|
@@ -964,6 +964,5 @@ const CoreConfigTypes = {
|
|
|
964
964
|
Heading,
|
|
965
965
|
Typography,
|
|
966
966
|
AssertionDefinitionAssertions,
|
|
967
|
-
AssertionDefinitionSubject,
|
|
968
967
|
};
|
|
969
|
-
exports.ConfigTypes =
|
|
968
|
+
exports.ConfigTypes = createConfigTypes(config_1.rootRedoclyConfigSchema);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/openapi-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@redocly/ajv": "^8.11.0",
|
|
39
|
-
"@redocly/config": "^0.6.
|
|
39
|
+
"@redocly/config": "^0.6.2",
|
|
40
40
|
"colorette": "^1.2.0",
|
|
41
41
|
"https-proxy-agent": "^7.0.4",
|
|
42
42
|
"js-levenshtein": "^1.1.6",
|
|
@@ -3,7 +3,7 @@ import { outdent } from 'outdent';
|
|
|
3
3
|
|
|
4
4
|
import { lintFromString, lintConfig, lintDocument, lint } from '../lint';
|
|
5
5
|
import { BaseResolver } from '../resolve';
|
|
6
|
-
import { loadConfig } from '../config/load';
|
|
6
|
+
import { createConfig, loadConfig } from '../config/load';
|
|
7
7
|
import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../__tests__/utils';
|
|
8
8
|
import { detectSpec } from '../oas-types';
|
|
9
9
|
import { rootRedoclyConfigSchema } from '@redocly/config';
|
|
@@ -293,7 +293,7 @@ describe('lint', () => {
|
|
|
293
293
|
- url: http://redocly-example.com
|
|
294
294
|
paths: {}
|
|
295
295
|
`,
|
|
296
|
-
config: await loadConfig(),
|
|
296
|
+
config: await loadConfig({ configPath: path.join(__dirname, 'fixtures/redocly.yaml') }),
|
|
297
297
|
});
|
|
298
298
|
|
|
299
299
|
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
@@ -374,7 +374,8 @@ describe('lint', () => {
|
|
|
374
374
|
`,
|
|
375
375
|
''
|
|
376
376
|
);
|
|
377
|
-
const
|
|
377
|
+
const config = await createConfig({});
|
|
378
|
+
const results = await lintConfig({ document, config });
|
|
378
379
|
|
|
379
380
|
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
380
381
|
[
|
|
@@ -435,7 +436,8 @@ describe('lint', () => {
|
|
|
435
436
|
`,
|
|
436
437
|
''
|
|
437
438
|
);
|
|
438
|
-
const
|
|
439
|
+
const config = await createConfig({});
|
|
440
|
+
const results = await lintConfig({ document, config });
|
|
439
441
|
|
|
440
442
|
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
441
443
|
[
|
|
@@ -475,7 +477,8 @@ describe('lint', () => {
|
|
|
475
477
|
`,
|
|
476
478
|
''
|
|
477
479
|
);
|
|
478
|
-
const
|
|
480
|
+
const config = await createConfig({});
|
|
481
|
+
const results = await lintConfig({ document, config });
|
|
479
482
|
|
|
480
483
|
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
481
484
|
[
|
|
@@ -510,7 +513,8 @@ describe('lint', () => {
|
|
|
510
513
|
`,
|
|
511
514
|
''
|
|
512
515
|
);
|
|
513
|
-
const
|
|
516
|
+
const config = await createConfig({});
|
|
517
|
+
const results = await lintConfig({ document, config });
|
|
514
518
|
|
|
515
519
|
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
516
520
|
[
|
|
@@ -534,7 +538,8 @@ describe('lint', () => {
|
|
|
534
538
|
|
|
535
539
|
it('lintConfig should detect wrong fields in the default configuration after merging with the portal config schema', async () => {
|
|
536
540
|
const document = testPortalConfig;
|
|
537
|
-
const
|
|
541
|
+
const config = await createConfig({});
|
|
542
|
+
const results = await lintConfig({ document, config });
|
|
538
543
|
|
|
539
544
|
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
540
545
|
[
|
|
@@ -1165,13 +1170,18 @@ describe('lint', () => {
|
|
|
1165
1170
|
|
|
1166
1171
|
it('lintConfig should alternate its behavior when supplied externalConfigTypes', async () => {
|
|
1167
1172
|
const document = testPortalConfig;
|
|
1173
|
+
const config = await createConfig({});
|
|
1168
1174
|
const results = await lintConfig({
|
|
1169
1175
|
document,
|
|
1170
|
-
externalConfigTypes: createConfigTypes(
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1176
|
+
externalConfigTypes: createConfigTypes(
|
|
1177
|
+
{
|
|
1178
|
+
type: 'object',
|
|
1179
|
+
properties: { theme: rootRedoclyConfigSchema.properties.theme },
|
|
1180
|
+
additionalProperties: false,
|
|
1181
|
+
},
|
|
1182
|
+
config
|
|
1183
|
+
),
|
|
1184
|
+
config,
|
|
1175
1185
|
});
|
|
1176
1186
|
|
|
1177
1187
|
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
@@ -1583,4 +1593,128 @@ describe('lint', () => {
|
|
|
1583
1593
|
expect(result[0]).toHaveProperty('ignored', true);
|
|
1584
1594
|
expect(result[0]).toHaveProperty('ruleId', 'operation-operationId');
|
|
1585
1595
|
});
|
|
1596
|
+
|
|
1597
|
+
it('should throw an error for dependentRequired not expected here - OAS 3.0.x', async () => {
|
|
1598
|
+
const document = parseYamlToDocument(
|
|
1599
|
+
outdent`
|
|
1600
|
+
openapi: 3.0.3
|
|
1601
|
+
info:
|
|
1602
|
+
title: test json schema validation keyword - dependentRequired
|
|
1603
|
+
version: 1.0.0
|
|
1604
|
+
paths:
|
|
1605
|
+
'/thing':
|
|
1606
|
+
get:
|
|
1607
|
+
summary: a sample api
|
|
1608
|
+
responses:
|
|
1609
|
+
'200':
|
|
1610
|
+
description: OK
|
|
1611
|
+
content:
|
|
1612
|
+
'application/json':
|
|
1613
|
+
schema:
|
|
1614
|
+
$ref: '#/components/schemas/test_schema'
|
|
1615
|
+
examples:
|
|
1616
|
+
dependentRequired_passing:
|
|
1617
|
+
summary: an example schema
|
|
1618
|
+
value: { "name": "bobby", "age": 25}
|
|
1619
|
+
dependentRequired_failing:
|
|
1620
|
+
summary: an example schema
|
|
1621
|
+
value: { "name": "jennie"}
|
|
1622
|
+
components:
|
|
1623
|
+
schemas:
|
|
1624
|
+
test_schema:
|
|
1625
|
+
type: object
|
|
1626
|
+
properties:
|
|
1627
|
+
name:
|
|
1628
|
+
type: string
|
|
1629
|
+
age:
|
|
1630
|
+
type: number
|
|
1631
|
+
dependentRequired:
|
|
1632
|
+
name:
|
|
1633
|
+
- age
|
|
1634
|
+
`,
|
|
1635
|
+
''
|
|
1636
|
+
);
|
|
1637
|
+
|
|
1638
|
+
const configFilePath = path.join(__dirname, '..', '..', '..', 'redocly.yaml');
|
|
1639
|
+
|
|
1640
|
+
const results = await lintDocument({
|
|
1641
|
+
externalRefResolver: new BaseResolver(),
|
|
1642
|
+
document,
|
|
1643
|
+
config: await makeConfig({ spec: 'error' }, undefined, configFilePath),
|
|
1644
|
+
});
|
|
1645
|
+
|
|
1646
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
1647
|
+
[
|
|
1648
|
+
{
|
|
1649
|
+
"from": {
|
|
1650
|
+
"pointer": "#/paths/~1thing/get/responses/200/content/application~1json/schema",
|
|
1651
|
+
"source": "",
|
|
1652
|
+
},
|
|
1653
|
+
"location": [
|
|
1654
|
+
{
|
|
1655
|
+
"pointer": "#/components/schemas/test_schema/dependentRequired",
|
|
1656
|
+
"reportOnKey": true,
|
|
1657
|
+
"source": "",
|
|
1658
|
+
},
|
|
1659
|
+
],
|
|
1660
|
+
"message": "Property \`dependentRequired\` is not expected here.",
|
|
1661
|
+
"ruleId": "spec",
|
|
1662
|
+
"severity": "error",
|
|
1663
|
+
"suggest": [],
|
|
1664
|
+
},
|
|
1665
|
+
]
|
|
1666
|
+
`);
|
|
1667
|
+
});
|
|
1668
|
+
|
|
1669
|
+
it('should not throw an error for dependentRequired not expected here - OAS 3.1.x', async () => {
|
|
1670
|
+
const document = parseYamlToDocument(
|
|
1671
|
+
outdent`
|
|
1672
|
+
openapi: 3.1.0
|
|
1673
|
+
info:
|
|
1674
|
+
title: test json schema validation keyword - dependentRequired
|
|
1675
|
+
version: 1.0.0
|
|
1676
|
+
paths:
|
|
1677
|
+
'/thing':
|
|
1678
|
+
get:
|
|
1679
|
+
summary: a sample api
|
|
1680
|
+
responses:
|
|
1681
|
+
'200':
|
|
1682
|
+
description: OK
|
|
1683
|
+
content:
|
|
1684
|
+
'application/json':
|
|
1685
|
+
schema:
|
|
1686
|
+
$ref: '#/components/schemas/test_schema'
|
|
1687
|
+
examples:
|
|
1688
|
+
dependentRequired_passing:
|
|
1689
|
+
summary: an example schema
|
|
1690
|
+
value: { "name": "bobby", "age": 25}
|
|
1691
|
+
dependentRequired_failing:
|
|
1692
|
+
summary: an example schema
|
|
1693
|
+
value: { "name": "jennie"}
|
|
1694
|
+
components:
|
|
1695
|
+
schemas:
|
|
1696
|
+
test_schema:
|
|
1697
|
+
type: object
|
|
1698
|
+
properties:
|
|
1699
|
+
name:
|
|
1700
|
+
type: string
|
|
1701
|
+
age:
|
|
1702
|
+
type: number
|
|
1703
|
+
dependentRequired:
|
|
1704
|
+
name:
|
|
1705
|
+
- age
|
|
1706
|
+
`,
|
|
1707
|
+
''
|
|
1708
|
+
);
|
|
1709
|
+
|
|
1710
|
+
const configFilePath = path.join(__dirname, '..', '..', '..', 'redocly.yaml');
|
|
1711
|
+
|
|
1712
|
+
const results = await lintDocument({
|
|
1713
|
+
externalRefResolver: new BaseResolver(),
|
|
1714
|
+
document,
|
|
1715
|
+
config: await makeConfig({ spec: 'error' }, undefined, configFilePath),
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
|
|
1719
|
+
});
|
|
1586
1720
|
});
|