@redocly/openapi-core 1.0.0-beta.96 → 1.0.0-beta.99
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 +2 -0
- package/lib/bundle.js +6 -3
- package/lib/config/all.js +1 -0
- package/lib/config/config-resolvers.d.ts +1 -1
- package/lib/config/config-resolvers.js +31 -2
- package/lib/config/config.d.ts +4 -1
- package/lib/config/config.js +18 -12
- package/lib/format/format.js +2 -1
- package/lib/redocly/index.js +10 -26
- package/lib/redocly/registry-api-types.d.ts +1 -0
- package/lib/redocly/registry-api.d.ts +1 -1
- package/lib/redocly/registry-api.js +2 -1
- package/lib/ref-utils.js +1 -0
- package/lib/rules/common/response-contains-header.d.ts +2 -0
- package/lib/rules/common/response-contains-header.js +29 -0
- package/lib/rules/common/scalar-property-missing-example.d.ts +2 -0
- package/lib/rules/common/scalar-property-missing-example.js +41 -0
- package/lib/rules/oas2/index.d.ts +3 -0
- package/lib/rules/oas2/index.js +6 -0
- package/lib/rules/oas2/response-contains-property.d.ts +2 -0
- package/lib/rules/oas2/response-contains-property.js +38 -0
- package/lib/rules/oas3/index.js +6 -0
- package/lib/rules/oas3/response-contains-property.d.ts +2 -0
- package/lib/rules/oas3/response-contains-property.js +40 -0
- package/lib/types/oas2.js +3 -1
- package/lib/types/oas3.js +21 -8
- package/lib/types/oas3_1.js +12 -8
- package/lib/types/redocly-yaml.js +12 -0
- package/lib/typings/openapi.d.ts +5 -2
- package/lib/typings/swagger.d.ts +2 -0
- package/lib/utils.d.ts +1 -1
- package/lib/utils.js +5 -3
- package/package.json +3 -3
- package/{__tests__ → src/__tests__}/__snapshots__/bundle.test.ts.snap +26 -0
- package/{__tests__ → src/__tests__}/bundle.test.ts +30 -6
- package/{__tests__ → src/__tests__}/codeframes.test.ts +3 -3
- package/{__tests__ → src/__tests__}/fixtures/extension.js +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/definitions.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/examples.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/external-request-body.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/externalref.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/hosted.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/openapi-with-external-refs-conflicting-names.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/openapi-with-external-refs.yaml +0 -0
- package/src/__tests__/fixtures/refs/openapi-with-url-refs.yaml +18 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/param-b.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/param-c.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/rename.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/requestBody.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/schema-a.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/simple.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/vendor.schema.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/External.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/External2.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/description.md +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/externalInfo.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/externalLicense.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/openapi-with-back.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/openapi-with-md-description.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/openapi.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/schemas/type-a.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/schemas/type-b.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/a.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/components.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/schemas.yaml +0 -0
- package/src/__tests__/lint.test.ts +13 -0
- package/{__tests__ → src/__tests__}/login.test.ts +1 -1
- package/{__tests__ → src/__tests__}/normalizeVisitors.test.ts +4 -4
- package/{__tests__ → src/__tests__}/ref-utils.test.ts +5 -5
- package/{__tests__ → src/__tests__}/resolve-http.test.ts +4 -4
- package/{__tests__ → src/__tests__}/resolve.test.ts +4 -4
- package/src/__tests__/utils.test.ts +12 -1
- package/{__tests__ → src/__tests__}/walk.test.ts +5 -5
- package/src/bundle.ts +18 -3
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +18 -1
- package/src/config/__tests__/config-resolvers.test.ts +32 -1
- package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +5 -0
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +7 -0
- package/src/config/all.ts +1 -0
- package/src/config/config-resolvers.ts +58 -3
- package/src/config/config.ts +21 -12
- package/src/format/format.ts +2 -1
- package/src/redocly/index.ts +12 -41
- package/src/redocly/registry-api-types.ts +1 -0
- package/src/redocly/registry-api.ts +2 -0
- package/src/ref-utils.ts +1 -0
- package/src/rules/common/__tests__/scalar-property-missing-example.test.ts +207 -0
- package/src/rules/common/response-contains-header.ts +30 -0
- package/src/rules/common/scalar-property-missing-example.ts +55 -0
- package/src/rules/oas2/__tests__/response-contains-header.test.ts +174 -0
- package/src/rules/oas2/__tests__/response-contains-property.test.ts +155 -0
- package/src/rules/oas2/index.ts +6 -0
- package/src/rules/oas2/response-contains-property.ts +36 -0
- package/src/rules/oas3/__tests__/response-contains-header.test.ts +273 -0
- package/src/rules/oas3/__tests__/response-contains-property.test.ts +403 -0
- package/src/rules/oas3/index.ts +6 -0
- package/src/rules/oas3/response-contains-property.ts +38 -0
- package/src/types/oas2.ts +2 -0
- package/src/types/oas3.ts +18 -7
- package/src/types/oas3_1.ts +11 -7
- package/src/types/redocly-yaml.ts +12 -0
- package/src/typings/openapi.ts +4 -1
- package/src/typings/swagger.ts +2 -0
- package/src/utils.ts +6 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/__tests__/lint.test.ts +0 -17
package/lib/bundle.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export declare function bundle(opts: {
|
|
|
18
18
|
base?: string;
|
|
19
19
|
skipRedoclyRegistryRefs?: boolean;
|
|
20
20
|
removeUnusedComponents?: boolean;
|
|
21
|
+
keepUrlRefs?: boolean;
|
|
21
22
|
}): Promise<{
|
|
22
23
|
bundle: Document;
|
|
23
24
|
problems: import("./walk").NormalizedProblem[];
|
|
@@ -34,6 +35,7 @@ export declare function bundleDocument(opts: {
|
|
|
34
35
|
dereference?: boolean;
|
|
35
36
|
skipRedoclyRegistryRefs?: boolean;
|
|
36
37
|
removeUnusedComponents?: boolean;
|
|
38
|
+
keepUrlRefs?: boolean;
|
|
37
39
|
}): Promise<{
|
|
38
40
|
bundle: Document;
|
|
39
41
|
problems: import("./walk").NormalizedProblem[];
|
package/lib/bundle.js
CHANGED
|
@@ -48,7 +48,7 @@ function bundle(opts) {
|
|
|
48
48
|
exports.bundle = bundle;
|
|
49
49
|
function bundleDocument(opts) {
|
|
50
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
-
const { document, config, customTypes, externalRefResolver, dereference = false, skipRedoclyRegistryRefs = false, removeUnusedComponents = false, } = opts;
|
|
51
|
+
const { document, config, customTypes, externalRefResolver, dereference = false, skipRedoclyRegistryRefs = false, removeUnusedComponents = false, keepUrlRefs = false, } = opts;
|
|
52
52
|
const oasVersion = oas_types_1.detectOpenAPI(document.parsed);
|
|
53
53
|
const oasMajorVersion = oas_types_1.openAPIMajor(oasVersion);
|
|
54
54
|
const rules = config.getRulesForOasVersion(oasMajorVersion);
|
|
@@ -84,7 +84,7 @@ function bundleDocument(opts) {
|
|
|
84
84
|
{
|
|
85
85
|
severity: 'error',
|
|
86
86
|
ruleId: 'bundler',
|
|
87
|
-
visitor: makeBundleVisitor(oasMajorVersion, dereference, skipRedoclyRegistryRefs, document, resolvedRefMap),
|
|
87
|
+
visitor: makeBundleVisitor(oasMajorVersion, dereference, skipRedoclyRegistryRefs, document, resolvedRefMap, keepUrlRefs),
|
|
88
88
|
},
|
|
89
89
|
...decorators,
|
|
90
90
|
], types);
|
|
@@ -146,7 +146,7 @@ function mapTypeToComponent(typeName, version) {
|
|
|
146
146
|
}
|
|
147
147
|
exports.mapTypeToComponent = mapTypeToComponent;
|
|
148
148
|
// function oas3Move
|
|
149
|
-
function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDocument, resolvedRefMap) {
|
|
149
|
+
function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDocument, resolvedRefMap, keepUrlRefs) {
|
|
150
150
|
let components;
|
|
151
151
|
const visitor = {
|
|
152
152
|
ref: {
|
|
@@ -165,6 +165,9 @@ function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDo
|
|
|
165
165
|
if (skipRedoclyRegistryRefs && redocly_1.isRedoclyRegistryURL(node.$ref)) {
|
|
166
166
|
return;
|
|
167
167
|
}
|
|
168
|
+
if (keepUrlRefs && ref_utils_1.isAbsoluteUrl(node.$ref)) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
168
171
|
const componentType = mapTypeToComponent(ctx.type.name, version);
|
|
169
172
|
if (!componentType) {
|
|
170
173
|
replaceRef(node, resolved, ctx);
|
package/lib/config/all.js
CHANGED
|
@@ -8,7 +8,7 @@ export declare function resolveApis({ rawConfig, configPath, resolver, }: {
|
|
|
8
8
|
configPath?: string;
|
|
9
9
|
resolver?: BaseResolver;
|
|
10
10
|
}): Promise<Record<string, ResolvedApi>>;
|
|
11
|
-
export declare function resolveLint(
|
|
11
|
+
export declare function resolveLint(lintOpts: {
|
|
12
12
|
lintConfig?: LintRawConfig;
|
|
13
13
|
configPath?: string;
|
|
14
14
|
resolver?: BaseResolver;
|
|
@@ -141,7 +141,7 @@ function resolveApis({ rawConfig, configPath = '', resolver, }) {
|
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
exports.resolveApis = resolveApis;
|
|
144
|
-
function
|
|
144
|
+
function resolveAndMergeNestedLint({ lintConfig, configPath = '', resolver = new resolve_1.BaseResolver(), }, parentConfigPaths = [], extendPaths = []) {
|
|
145
145
|
var _a, _b, _c;
|
|
146
146
|
return __awaiter(this, void 0, void 0, function* () {
|
|
147
147
|
if (parentConfigPaths.includes(configPath)) {
|
|
@@ -162,7 +162,7 @@ function resolveLint({ lintConfig, configPath = '', resolver = new resolve_1.Bas
|
|
|
162
162
|
? new URL(presetItem, configPath).href
|
|
163
163
|
: path.resolve(path.dirname(configPath), presetItem);
|
|
164
164
|
const extendedLintConfig = yield loadExtendLintConfig(pathItem, resolver);
|
|
165
|
-
return yield
|
|
165
|
+
return yield resolveAndMergeNestedLint({
|
|
166
166
|
lintConfig: extendedLintConfig,
|
|
167
167
|
configPath: pathItem,
|
|
168
168
|
resolver: resolver,
|
|
@@ -175,6 +175,12 @@ function resolveLint({ lintConfig, configPath = '', resolver = new resolve_1.Bas
|
|
|
175
175
|
return Object.assign(Object.assign({}, lint), { extendPaths: (_c = lint.extendPaths) === null || _c === void 0 ? void 0 : _c.filter((path) => path && !ref_utils_1.isAbsoluteUrl(path)), plugins: utils_1.getUniquePlugins(mergedPlugins), recommendedFallback: lintConfig === null || lintConfig === void 0 ? void 0 : lintConfig.recommendedFallback, doNotResolveExamples: lintConfig === null || lintConfig === void 0 ? void 0 : lintConfig.doNotResolveExamples });
|
|
176
176
|
});
|
|
177
177
|
}
|
|
178
|
+
function resolveLint(lintOpts, parentConfigPaths = [], extendPaths = []) {
|
|
179
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
180
|
+
const resolvedLint = yield resolveAndMergeNestedLint(lintOpts, parentConfigPaths, extendPaths);
|
|
181
|
+
return Object.assign(Object.assign({}, resolvedLint), { rules: resolvedLint.rules && groupLintAssertionRules(resolvedLint.rules) });
|
|
182
|
+
});
|
|
183
|
+
}
|
|
178
184
|
exports.resolveLint = resolveLint;
|
|
179
185
|
function resolvePreset(presetName, plugins) {
|
|
180
186
|
var _a;
|
|
@@ -211,3 +217,26 @@ function getMergedLintRawConfig(configLint, apiLint) {
|
|
|
211
217
|
const resultLint = Object.assign(Object.assign(Object.assign({}, configLint), apiLint), { rules: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.rules), apiLint === null || apiLint === void 0 ? void 0 : apiLint.rules), oas2Rules: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas2Rules), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas2Rules), oas3_0Rules: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_0Rules), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_0Rules), oas3_1Rules: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_1Rules), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_1Rules), preprocessors: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.preprocessors), apiLint === null || apiLint === void 0 ? void 0 : apiLint.preprocessors), oas2Preprocessors: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas2Preprocessors), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas2Preprocessors), oas3_0Preprocessors: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_0Preprocessors), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_0Preprocessors), oas3_1Preprocessors: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_1Preprocessors), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_1Preprocessors), decorators: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.decorators), apiLint === null || apiLint === void 0 ? void 0 : apiLint.decorators), oas2Decorators: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas2Decorators), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas2Decorators), oas3_0Decorators: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_0Decorators), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_0Decorators), oas3_1Decorators: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_1Decorators), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_1Decorators), recommendedFallback: (apiLint === null || apiLint === void 0 ? void 0 : apiLint.extends) ? false : configLint.recommendedFallback });
|
|
212
218
|
return resultLint;
|
|
213
219
|
}
|
|
220
|
+
function groupLintAssertionRules(rules) {
|
|
221
|
+
if (!rules) {
|
|
222
|
+
return rules;
|
|
223
|
+
}
|
|
224
|
+
// Create a new record to avoid mutating original
|
|
225
|
+
const transformedRules = {};
|
|
226
|
+
// Collect assertion rules
|
|
227
|
+
const assertions = [];
|
|
228
|
+
for (const [ruleKey, rule] of Object.entries(rules)) {
|
|
229
|
+
if (ruleKey.startsWith('assert/') && typeof rule === 'object' && rule !== null) {
|
|
230
|
+
const assertion = rule;
|
|
231
|
+
assertions.push(Object.assign(Object.assign({}, assertion), { assertionId: ruleKey.replace('assert/', '') }));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// If it's not an assertion, keep it as is
|
|
235
|
+
transformedRules[ruleKey] = rule;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (assertions.length > 0) {
|
|
239
|
+
transformedRules.assertions = assertions;
|
|
240
|
+
}
|
|
241
|
+
return transformedRules;
|
|
242
|
+
}
|
package/lib/config/config.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import { NormalizedProblem } from '../walk';
|
|
2
3
|
import { OasVersion, OasMajorVersion, Oas2RuleSet, Oas3RuleSet } from '../oas-types';
|
|
3
4
|
import type { NodeType } from '../types';
|
|
4
5
|
import type { DecoratorConfig, Plugin, PreprocessorConfig, Region, ResolveConfig, ResolvedApi, ResolvedConfig, ResolvedLintConfig, RuleConfig } from './types';
|
|
6
|
+
export declare const env: NodeJS.ProcessEnv;
|
|
5
7
|
export declare const IGNORE_FILE = ".redocly.lint-ignore.yaml";
|
|
6
8
|
export declare const DEFAULT_REGION = "us";
|
|
7
9
|
export declare const DOMAINS: {
|
|
8
|
-
|
|
10
|
+
us: string;
|
|
11
|
+
eu: string;
|
|
9
12
|
};
|
|
10
13
|
export declare const AVAILABLE_REGIONS: Region[];
|
|
11
14
|
export declare class LintConfig {
|
package/lib/config/config.js
CHANGED
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Config = exports.LintConfig = exports.AVAILABLE_REGIONS = exports.DOMAINS = exports.DEFAULT_REGION = exports.IGNORE_FILE = void 0;
|
|
3
|
+
exports.Config = exports.LintConfig = exports.AVAILABLE_REGIONS = exports.DOMAINS = exports.DEFAULT_REGION = exports.IGNORE_FILE = exports.env = void 0;
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const js_yaml_1 = require("../js-yaml");
|
|
7
7
|
const utils_1 = require("../utils");
|
|
8
8
|
const oas_types_1 = require("../oas-types");
|
|
9
9
|
const utils_2 = require("./utils");
|
|
10
|
+
// Alias environment here so this file can work in browser environments too.
|
|
11
|
+
exports.env = typeof process !== 'undefined' ? process.env || {} : {};
|
|
10
12
|
exports.IGNORE_FILE = '.redocly.lint-ignore.yaml';
|
|
11
13
|
const IGNORE_BANNER = `# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.\n` +
|
|
12
14
|
`# See https://redoc.ly/docs/cli/ for more information.\n`;
|
|
13
15
|
exports.DEFAULT_REGION = 'us';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
};
|
|
19
|
-
// FIXME: temporary fix for our lab environments
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
function getDomains() {
|
|
17
|
+
const domains = {
|
|
18
|
+
us: 'redocly.com',
|
|
19
|
+
eu: 'eu.redocly.com',
|
|
20
|
+
};
|
|
21
|
+
// FIXME: temporary fix for our lab environments
|
|
22
|
+
const domain = exports.env.REDOCLY_DOMAIN;
|
|
23
|
+
if (domain === null || domain === void 0 ? void 0 : domain.endsWith('.redocly.host')) {
|
|
24
|
+
domains[domain.split('.')[0]] = domain;
|
|
25
|
+
}
|
|
26
|
+
if (domain === 'redoc.online') {
|
|
27
|
+
domains[domain] = domain;
|
|
28
|
+
}
|
|
29
|
+
return domains;
|
|
25
30
|
}
|
|
31
|
+
exports.DOMAINS = getDomains();
|
|
26
32
|
exports.AVAILABLE_REGIONS = Object.keys(exports.DOMAINS);
|
|
27
33
|
class LintConfig {
|
|
28
34
|
constructor(rawConfig, configFile) {
|
package/lib/format/format.js
CHANGED
|
@@ -5,6 +5,7 @@ const path = require("path");
|
|
|
5
5
|
const colorette_1 = require("colorette");
|
|
6
6
|
const coreVersion = require('../../package.json').version;
|
|
7
7
|
const codeframes_1 = require("./codeframes");
|
|
8
|
+
const config_1 = require("../config");
|
|
8
9
|
const ERROR_MESSAGE = {
|
|
9
10
|
INVALID_SEVERITY_LEVEL: 'Invalid severity level; accepted values: error or warn',
|
|
10
11
|
};
|
|
@@ -131,7 +132,7 @@ function formatProblems(problems, opts) {
|
|
|
131
132
|
? Object.assign(Object.assign({}, p.from), { source: {
|
|
132
133
|
ref: path.relative(cwd, ((_a = p.from) === null || _a === void 0 ? void 0 : _a.source.absoluteRef) || cwd),
|
|
133
134
|
} }) : undefined });
|
|
134
|
-
if (
|
|
135
|
+
if (config_1.env.FORMAT_JSON_WITH_CODEFRAMES) {
|
|
135
136
|
const location = p.location[0]; // TODO: support multiple locations
|
|
136
137
|
const loc = codeframes_1.getLineColLocation(location);
|
|
137
138
|
problem.codeframe = codeframes_1.getCodeframe(loc, color);
|
package/lib/redocly/index.js
CHANGED
|
@@ -18,27 +18,21 @@ const registry_api_1 = require("./registry-api");
|
|
|
18
18
|
const config_1 = require("../config/config");
|
|
19
19
|
const utils_1 = require("../utils");
|
|
20
20
|
const TOKEN_FILENAME = '.redocly-config.json';
|
|
21
|
-
let REDOCLY_DOMAIN; // workaround for the isRedoclyRegistryURL, see more below
|
|
22
21
|
class RedoclyClient {
|
|
23
22
|
constructor(region) {
|
|
24
23
|
this.accessTokens = {};
|
|
25
24
|
this.region = this.loadRegion(region);
|
|
26
25
|
this.loadTokens();
|
|
27
|
-
this.domain = region ? config_1.DOMAINS[region] :
|
|
28
|
-
|
|
29
|
-
* We can't use process.env here because it is replaced by a const in some client-side bundles,
|
|
30
|
-
* which breaks assignment.
|
|
31
|
-
*/
|
|
32
|
-
REDOCLY_DOMAIN = this.domain; // isRedoclyRegistryURL depends on the value to be set
|
|
26
|
+
this.domain = region ? config_1.DOMAINS[region] : config_1.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
|
|
27
|
+
config_1.env.REDOCLY_DOMAIN = this.domain; // isRedoclyRegistryURL depends on the value to be set
|
|
33
28
|
this.registryApi = new registry_api_1.RegistryApi(this.accessTokens, this.region);
|
|
34
29
|
}
|
|
35
30
|
loadRegion(region) {
|
|
36
31
|
if (region && !config_1.DOMAINS[region]) {
|
|
37
|
-
|
|
38
|
-
process.exit(1);
|
|
32
|
+
throw new Error(`Invalid argument: region in config file.\nGiven: ${colorette_1.green(region)}, choices: "us", "eu".`);
|
|
39
33
|
}
|
|
40
|
-
if (
|
|
41
|
-
return (config_1.AVAILABLE_REGIONS.find((region) => config_1.DOMAINS[region] ===
|
|
34
|
+
if (config_1.env.REDOCLY_DOMAIN) {
|
|
35
|
+
return (config_1.AVAILABLE_REGIONS.find((region) => config_1.DOMAINS[region] === config_1.env.REDOCLY_DOMAIN) || config_1.DEFAULT_REGION);
|
|
42
36
|
}
|
|
43
37
|
return region || config_1.DEFAULT_REGION;
|
|
44
38
|
}
|
|
@@ -54,13 +48,7 @@ class RedoclyClient {
|
|
|
54
48
|
}
|
|
55
49
|
getAuthorizationHeader() {
|
|
56
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
-
|
|
58
|
-
// print this only if there is token but invalid
|
|
59
|
-
if (token && !this.isAuthorizedWithRedoclyByRegion()) {
|
|
60
|
-
process.stderr.write(`${colorette_1.yellow('Warning:')} invalid Redocly API key. Use "npx @redocly/cli login" to provide your API key\n`);
|
|
61
|
-
return undefined;
|
|
62
|
-
}
|
|
63
|
-
return token;
|
|
51
|
+
return this.accessTokens[this.region];
|
|
64
52
|
});
|
|
65
53
|
}
|
|
66
54
|
// </backward compatibility: portal>
|
|
@@ -76,8 +64,8 @@ class RedoclyClient {
|
|
|
76
64
|
[this.region]: credentials.token,
|
|
77
65
|
})));
|
|
78
66
|
}
|
|
79
|
-
if (
|
|
80
|
-
this.setAccessTokens(Object.assign(Object.assign({}, this.accessTokens), { [this.region]:
|
|
67
|
+
if (config_1.env.REDOCLY_AUTHORIZATION) {
|
|
68
|
+
this.setAccessTokens(Object.assign(Object.assign({}, this.accessTokens), { [this.region]: config_1.env.REDOCLY_AUTHORIZATION }));
|
|
81
69
|
}
|
|
82
70
|
}
|
|
83
71
|
getAllTokens() {
|
|
@@ -133,19 +121,16 @@ class RedoclyClient {
|
|
|
133
121
|
login(accessToken, verbose = false) {
|
|
134
122
|
return __awaiter(this, void 0, void 0, function* () {
|
|
135
123
|
const credentialsPath = path_1.resolve(os_1.homedir(), TOKEN_FILENAME);
|
|
136
|
-
process.stdout.write(colorette_1.gray('\n Logging in...\n'));
|
|
137
124
|
try {
|
|
138
125
|
yield this.verifyToken(accessToken, this.region, verbose);
|
|
139
126
|
}
|
|
140
127
|
catch (err) {
|
|
141
|
-
|
|
142
|
-
process.exit(1);
|
|
128
|
+
throw new Error('Authorization failed. Please check if you entered a valid API key.');
|
|
143
129
|
}
|
|
144
130
|
const credentials = Object.assign(Object.assign({}, this.readCredentialsFile(credentialsPath)), { [this.region]: accessToken, token: accessToken });
|
|
145
131
|
this.accessTokens = credentials;
|
|
146
132
|
this.registryApi.setAccessTokens(credentials);
|
|
147
133
|
fs_1.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2));
|
|
148
|
-
process.stdout.write(colorette_1.green(' Authorization confirmed. ✅\n\n'));
|
|
149
134
|
});
|
|
150
135
|
}
|
|
151
136
|
logout() {
|
|
@@ -153,12 +138,11 @@ class RedoclyClient {
|
|
|
153
138
|
if (fs_1.existsSync(credentialsPath)) {
|
|
154
139
|
fs_1.unlinkSync(credentialsPath);
|
|
155
140
|
}
|
|
156
|
-
process.stdout.write('Logged out from the Redocly account. ✋\n');
|
|
157
141
|
}
|
|
158
142
|
}
|
|
159
143
|
exports.RedoclyClient = RedoclyClient;
|
|
160
144
|
function isRedoclyRegistryURL(link) {
|
|
161
|
-
const domain =
|
|
145
|
+
const domain = config_1.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
|
|
162
146
|
const legacyDomain = domain === 'redocly.com' ? 'redoc.ly' : domain;
|
|
163
147
|
if (!link.startsWith(`https://api.${domain}/registry/`) &&
|
|
164
148
|
!link.startsWith(`https://api.${legacyDomain}/registry/`)) {
|
|
@@ -13,5 +13,5 @@ export declare class RegistryApi {
|
|
|
13
13
|
organizations: string[];
|
|
14
14
|
}>;
|
|
15
15
|
prepareFileUpload({ organizationId, name, version, filesHash, filename, isUpsert, }: RegistryApiTypes.PrepareFileuploadParams): Promise<RegistryApiTypes.PrepareFileuploadOKResponse>;
|
|
16
|
-
pushApi({ organizationId, name, version, rootFilePath, filePaths, branch, isUpsert, }: RegistryApiTypes.PushApiParams): Promise<void>;
|
|
16
|
+
pushApi({ organizationId, name, version, rootFilePath, filePaths, branch, isUpsert, isPublic, }: RegistryApiTypes.PushApiParams): Promise<void>;
|
|
17
17
|
}
|
|
@@ -80,7 +80,7 @@ class RegistryApi {
|
|
|
80
80
|
throw new Error('Could not prepare file upload');
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
-
pushApi({ organizationId, name, version, rootFilePath, filePaths, branch, isUpsert, }) {
|
|
83
|
+
pushApi({ organizationId, name, version, rootFilePath, filePaths, branch, isUpsert, isPublic, }) {
|
|
84
84
|
return __awaiter(this, void 0, void 0, function* () {
|
|
85
85
|
const response = yield this.request(`/${organizationId}/${name}/${version}`, {
|
|
86
86
|
method: 'PUT',
|
|
@@ -93,6 +93,7 @@ class RegistryApi {
|
|
|
93
93
|
filePaths,
|
|
94
94
|
branch,
|
|
95
95
|
isUpsert,
|
|
96
|
+
isPublic,
|
|
96
97
|
}),
|
|
97
98
|
}, this.region);
|
|
98
99
|
if (response.ok) {
|
package/lib/ref-utils.js
CHANGED
|
@@ -67,6 +67,7 @@ function isMappingRef(mapping) {
|
|
|
67
67
|
// TODO: proper detection of mapping refs
|
|
68
68
|
return (mapping.startsWith('#') ||
|
|
69
69
|
mapping.startsWith('https://') ||
|
|
70
|
+
mapping.startsWith('http://') ||
|
|
70
71
|
mapping.startsWith('./') ||
|
|
71
72
|
mapping.startsWith('../') ||
|
|
72
73
|
mapping.indexOf('/') > -1);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResponseContainsHeader = void 0;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const ResponseContainsHeader = (options) => {
|
|
6
|
+
const names = options.names || {};
|
|
7
|
+
return {
|
|
8
|
+
Operation: {
|
|
9
|
+
Response: {
|
|
10
|
+
enter: (response, { report, location, key }) => {
|
|
11
|
+
var _a;
|
|
12
|
+
const expectedHeaders = names[key] ||
|
|
13
|
+
names[utils_1.getMatchingStatusCodeRange(key)] ||
|
|
14
|
+
names[utils_1.getMatchingStatusCodeRange(key).toLowerCase()] ||
|
|
15
|
+
[];
|
|
16
|
+
for (const expectedHeader of expectedHeaders) {
|
|
17
|
+
if (!((_a = response.headers) === null || _a === void 0 ? void 0 : _a[expectedHeader])) {
|
|
18
|
+
report({
|
|
19
|
+
message: `Response object must contain a "${expectedHeader}" header.`,
|
|
20
|
+
location: location.child('headers').key(),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
exports.ResponseContainsHeader = ResponseContainsHeader;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ScalarPropertyMissingExample = void 0;
|
|
4
|
+
const oas_types_1 = require("../../oas-types");
|
|
5
|
+
const SCALAR_TYPES = ['string', 'integer', 'number', 'boolean', 'null'];
|
|
6
|
+
const ScalarPropertyMissingExample = () => {
|
|
7
|
+
return {
|
|
8
|
+
SchemaProperties(properties, { report, location, oasVersion, resolve }) {
|
|
9
|
+
for (const propName of Object.keys(properties)) {
|
|
10
|
+
const propSchema = resolve(properties[propName]).node;
|
|
11
|
+
if (!propSchema || !isScalarSchema(propSchema)) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
if (!propSchema.example && !propSchema.examples) {
|
|
15
|
+
report({
|
|
16
|
+
message: `Scalar property should have "example"${oasVersion === oas_types_1.OasVersion.Version3_1 ? ' or "examples"' : ''} defined.`,
|
|
17
|
+
location: location.child(propName).key(),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
exports.ScalarPropertyMissingExample = ScalarPropertyMissingExample;
|
|
25
|
+
function isScalarSchema(schema) {
|
|
26
|
+
if (!schema.type) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
if (schema.allOf || schema.anyOf || schema.oneOf) {
|
|
30
|
+
// Skip allOf/oneOf/anyOf as it's complicated to validate it right now.
|
|
31
|
+
// We need core support for checking contrstrains through those keywords.
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (schema.format === 'binary') {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if (Array.isArray(schema.type)) {
|
|
38
|
+
return schema.type.every((t) => SCALAR_TYPES.includes(t));
|
|
39
|
+
}
|
|
40
|
+
return SCALAR_TYPES.includes(schema.type);
|
|
41
|
+
}
|
|
@@ -39,5 +39,8 @@ export declare const rules: {
|
|
|
39
39
|
'request-mime-type': Oas2Rule;
|
|
40
40
|
'response-mime-type': Oas2Rule;
|
|
41
41
|
'path-segment-plural': Oas2Rule;
|
|
42
|
+
'response-contains-header': Oas2Rule;
|
|
43
|
+
'response-contains-property': Oas2Rule;
|
|
44
|
+
'scalar-property-missing-example': import("../../visitors").Oas3Rule | Oas2Rule;
|
|
42
45
|
};
|
|
43
46
|
export declare const preprocessors: {};
|
package/lib/rules/oas2/index.js
CHANGED
|
@@ -39,6 +39,9 @@ const path_excludes_patterns_1 = require("../common/path-excludes-patterns");
|
|
|
39
39
|
const request_mime_type_1 = require("./request-mime-type");
|
|
40
40
|
const response_mime_type_1 = require("./response-mime-type");
|
|
41
41
|
const path_segment_plural_1 = require("../common/path-segment-plural");
|
|
42
|
+
const response_contains_header_1 = require("../common/response-contains-header");
|
|
43
|
+
const response_contains_property_1 = require("./response-contains-property");
|
|
44
|
+
const scalar_property_missing_example_1 = require("../common/scalar-property-missing-example");
|
|
42
45
|
exports.rules = {
|
|
43
46
|
spec: spec_1.OasSpec,
|
|
44
47
|
'no-invalid-schema-examples': no_invalid_schema_examples_1.NoInvalidSchemaExamples,
|
|
@@ -79,5 +82,8 @@ exports.rules = {
|
|
|
79
82
|
'request-mime-type': request_mime_type_1.RequestMimeType,
|
|
80
83
|
'response-mime-type': response_mime_type_1.ResponseMimeType,
|
|
81
84
|
'path-segment-plural': path_segment_plural_1.PathSegmentPlural,
|
|
85
|
+
'response-contains-header': response_contains_header_1.ResponseContainsHeader,
|
|
86
|
+
'response-contains-property': response_contains_property_1.ResponseContainsProperty,
|
|
87
|
+
'scalar-property-missing-example': scalar_property_missing_example_1.ScalarPropertyMissingExample,
|
|
82
88
|
};
|
|
83
89
|
exports.preprocessors = {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResponseContainsProperty = void 0;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const ResponseContainsProperty = (options) => {
|
|
6
|
+
const names = options.names || {};
|
|
7
|
+
let key;
|
|
8
|
+
return {
|
|
9
|
+
Operation: {
|
|
10
|
+
Response: {
|
|
11
|
+
skip: (_response, key) => {
|
|
12
|
+
return `${key}` === '204';
|
|
13
|
+
},
|
|
14
|
+
enter: (_response, ctx) => {
|
|
15
|
+
key = ctx.key;
|
|
16
|
+
},
|
|
17
|
+
Schema(schema, { report, location }) {
|
|
18
|
+
var _a;
|
|
19
|
+
if (schema.type !== 'object')
|
|
20
|
+
return;
|
|
21
|
+
const expectedProperties = names[key] ||
|
|
22
|
+
names[utils_1.getMatchingStatusCodeRange(key)] ||
|
|
23
|
+
names[utils_1.getMatchingStatusCodeRange(key).toLowerCase()] ||
|
|
24
|
+
[];
|
|
25
|
+
for (const expectedProperty of expectedProperties) {
|
|
26
|
+
if (!((_a = schema.properties) === null || _a === void 0 ? void 0 : _a[expectedProperty])) {
|
|
27
|
+
report({
|
|
28
|
+
message: `Response object must contain a top-level "${expectedProperty}" property.`,
|
|
29
|
+
location: location.child('properties').key(),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
exports.ResponseContainsProperty = ResponseContainsProperty;
|
package/lib/rules/oas3/index.js
CHANGED
|
@@ -47,6 +47,9 @@ const path_segment_plural_1 = require("../common/path-segment-plural");
|
|
|
47
47
|
const path_excludes_patterns_1 = require("../common/path-excludes-patterns");
|
|
48
48
|
const no_invalid_schema_examples_1 = require("../common/no-invalid-schema-examples");
|
|
49
49
|
const no_invalid_parameter_examples_1 = require("../common/no-invalid-parameter-examples");
|
|
50
|
+
const response_contains_header_1 = require("../common/response-contains-header");
|
|
51
|
+
const response_contains_property_1 = require("./response-contains-property");
|
|
52
|
+
const scalar_property_missing_example_1 = require("../common/scalar-property-missing-example");
|
|
50
53
|
exports.rules = {
|
|
51
54
|
spec: spec_1.OasSpec,
|
|
52
55
|
'info-description': info_description_1.InfoDescription,
|
|
@@ -95,5 +98,8 @@ exports.rules = {
|
|
|
95
98
|
'path-segment-plural': path_segment_plural_1.PathSegmentPlural,
|
|
96
99
|
'no-invalid-schema-examples': no_invalid_schema_examples_1.NoInvalidSchemaExamples,
|
|
97
100
|
'no-invalid-parameter-examples': no_invalid_parameter_examples_1.NoInvalidParameterExamples,
|
|
101
|
+
'response-contains-header': response_contains_header_1.ResponseContainsHeader,
|
|
102
|
+
'response-contains-property': response_contains_property_1.ResponseContainsProperty,
|
|
103
|
+
'scalar-property-missing-example': scalar_property_missing_example_1.ScalarPropertyMissingExample,
|
|
98
104
|
};
|
|
99
105
|
exports.preprocessors = {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResponseContainsProperty = void 0;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const ResponseContainsProperty = (options) => {
|
|
6
|
+
const names = options.names || {};
|
|
7
|
+
let key;
|
|
8
|
+
return {
|
|
9
|
+
Operation: {
|
|
10
|
+
Response: {
|
|
11
|
+
skip: (_response, key) => {
|
|
12
|
+
return `${key}` === '204';
|
|
13
|
+
},
|
|
14
|
+
enter: (_response, ctx) => {
|
|
15
|
+
key = ctx.key;
|
|
16
|
+
},
|
|
17
|
+
MediaType: {
|
|
18
|
+
Schema(schema, { report, location }) {
|
|
19
|
+
var _a;
|
|
20
|
+
if (schema.type !== 'object')
|
|
21
|
+
return;
|
|
22
|
+
const expectedProperties = names[key] ||
|
|
23
|
+
names[utils_1.getMatchingStatusCodeRange(key)] ||
|
|
24
|
+
names[utils_1.getMatchingStatusCodeRange(key).toLowerCase()] ||
|
|
25
|
+
[];
|
|
26
|
+
for (const expectedProperty of expectedProperties) {
|
|
27
|
+
if (!((_a = schema.properties) === null || _a === void 0 ? void 0 : _a[expectedProperty])) {
|
|
28
|
+
report({
|
|
29
|
+
message: `Response object must contain a top-level "${expectedProperty}" property.`,
|
|
30
|
+
location: location.child('properties').key(),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
exports.ResponseContainsProperty = ResponseContainsProperty;
|
package/lib/types/oas2.js
CHANGED
|
@@ -80,7 +80,8 @@ const Operation = {
|
|
|
80
80
|
deprecated: { type: 'boolean' },
|
|
81
81
|
security: _1.listOf('SecurityRequirement'),
|
|
82
82
|
'x-codeSamples': _1.listOf('XCodeSample'),
|
|
83
|
-
'x-code-samples': _1.listOf('XCodeSample'),
|
|
83
|
+
'x-code-samples': _1.listOf('XCodeSample'),
|
|
84
|
+
'x-hideTryItPanel': { type: 'boolean' },
|
|
84
85
|
},
|
|
85
86
|
required: ['responses'],
|
|
86
87
|
};
|
|
@@ -275,6 +276,7 @@ const Schema = {
|
|
|
275
276
|
xml: 'Xml',
|
|
276
277
|
externalDocs: 'ExternalDocs',
|
|
277
278
|
example: { isExample: true },
|
|
279
|
+
'x-tags': { type: 'array', items: { type: 'string' } },
|
|
278
280
|
},
|
|
279
281
|
};
|
|
280
282
|
const SchemaProperties = {
|