@redocly/openapi-core 1.0.0-beta.86 → 1.0.0-beta.89
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/__tests__/codeframes.test.ts +22 -0
- package/__tests__/utils.ts +2 -2
- package/__tests__/walk.test.ts +84 -0
- package/lib/config/config.d.ts +46 -4
- package/lib/config/config.js +66 -6
- package/lib/config/load.d.ts +4 -3
- package/lib/config/load.js +22 -16
- package/lib/format/codeframes.js +5 -2
- package/lib/index.d.ts +3 -3
- package/lib/index.js +4 -1
- package/lib/redocly/index.js +7 -2
- package/lib/rules/oas3/no-empty-servers.js +2 -1
- package/lib/types/oas2.js +1 -1
- package/lib/types/redocly-yaml.js +8 -0
- package/package.json +1 -1
- package/src/config/__tests__/load.test.ts +7 -0
- package/src/config/config.ts +104 -16
- package/src/config/load.ts +18 -20
- package/src/format/codeframes.ts +4 -2
- package/src/index.ts +11 -3
- package/src/redocly/index.ts +7 -2
- package/src/rules/oas3/__tests__/spec/spec.test.ts +4 -4
- package/src/rules/oas3/no-empty-servers.ts +2 -1
- package/src/types/oas2.ts +2 -1
- package/src/types/redocly-yaml.ts +9 -0
- package/src/utils.ts +0 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -85,6 +85,28 @@ describe('Location', () => {
|
|
|
85
85
|
expect(preciseLocation.end).toEqual({ line: 5, col: 28 });
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
+
it('should correctly fallback to the closest parent node if node value is null', () => {
|
|
89
|
+
const loc = {
|
|
90
|
+
reportOnKey: false,
|
|
91
|
+
pointer: '#/servers',
|
|
92
|
+
source: new Source(
|
|
93
|
+
'foobar.yaml',
|
|
94
|
+
outdent`
|
|
95
|
+
openapi: 3.0.2
|
|
96
|
+
servers:
|
|
97
|
+
info:
|
|
98
|
+
license:
|
|
99
|
+
name: MIT
|
|
100
|
+
url: https://google.com
|
|
101
|
+
`,
|
|
102
|
+
),
|
|
103
|
+
};
|
|
104
|
+
const preciseLocation = getLineColLocation(loc);
|
|
105
|
+
expect(preciseLocation.start).toEqual({ line: 2, col: 1 });
|
|
106
|
+
expect(preciseLocation.end).toEqual({ line: 2, col: 9 });
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
|
|
88
110
|
it('should return first line for empty doc', () => {
|
|
89
111
|
const loc = {
|
|
90
112
|
reportOnKey: false,
|
package/__tests__/utils.ts
CHANGED
|
@@ -44,7 +44,7 @@ export const yamlSerializer = {
|
|
|
44
44
|
},
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
export function makeConfigForRuleset(rules: Oas3RuleSet, plugin?: Partial<Plugin
|
|
47
|
+
export function makeConfigForRuleset(rules: Oas3RuleSet, plugin?: Partial<Plugin>, version: string = 'oas3') {
|
|
48
48
|
const rulesConf: Record<string, RuleConfig> = {};
|
|
49
49
|
const ruleId = 'test';
|
|
50
50
|
Object.keys(rules).forEach((name) => {
|
|
@@ -56,7 +56,7 @@ export function makeConfigForRuleset(rules: Oas3RuleSet, plugin?: Partial<Plugin
|
|
|
56
56
|
{
|
|
57
57
|
...plugin,
|
|
58
58
|
id: ruleId,
|
|
59
|
-
rules: {
|
|
59
|
+
rules: { [version]: rules },
|
|
60
60
|
},
|
|
61
61
|
],
|
|
62
62
|
extends: [],
|
package/__tests__/walk.test.ts
CHANGED
|
@@ -143,6 +143,90 @@ describe('walk order', () => {
|
|
|
143
143
|
`);
|
|
144
144
|
});
|
|
145
145
|
|
|
146
|
+
it('should run nested visitors correctly oas2', async () => {
|
|
147
|
+
const calls: string[] = [];
|
|
148
|
+
|
|
149
|
+
const testRuleSet: Oas3RuleSet = {
|
|
150
|
+
test: jest.fn(() => {
|
|
151
|
+
return {
|
|
152
|
+
Operation: {
|
|
153
|
+
enter: jest.fn((op) => calls.push(`enter operation: ${op.operationId}`)),
|
|
154
|
+
leave: jest.fn((op) => calls.push(`leave operation: ${op.operationId}`)),
|
|
155
|
+
Parameter: {
|
|
156
|
+
enter: jest.fn((param, _ctx, parents) =>
|
|
157
|
+
calls.push(
|
|
158
|
+
`enter operation ${parents.Operation.operationId} > param ${param.name}`,
|
|
159
|
+
),
|
|
160
|
+
),
|
|
161
|
+
leave: jest.fn((param, _ctx, parents) =>
|
|
162
|
+
calls.push(
|
|
163
|
+
`leave operation ${parents.Operation.operationId} > param ${param.name}`,
|
|
164
|
+
),
|
|
165
|
+
),
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
Parameter: {
|
|
169
|
+
enter: jest.fn((param) => calls.push(`enter param ${param.name}`)),
|
|
170
|
+
leave: jest.fn((param) => calls.push(`leave param ${param.name}`)),
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}),
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const document = parseYamlToDocument(
|
|
177
|
+
outdent`
|
|
178
|
+
swagger: "2.0"
|
|
179
|
+
info:
|
|
180
|
+
contact: {}
|
|
181
|
+
license: {}
|
|
182
|
+
paths:
|
|
183
|
+
/pet:
|
|
184
|
+
parameters:
|
|
185
|
+
- name: path-param
|
|
186
|
+
get:
|
|
187
|
+
operationId: get
|
|
188
|
+
parameters:
|
|
189
|
+
- name: get_a
|
|
190
|
+
- name: get_b
|
|
191
|
+
post:
|
|
192
|
+
operationId: post
|
|
193
|
+
parameters:
|
|
194
|
+
- name: post_a
|
|
195
|
+
|
|
196
|
+
`,
|
|
197
|
+
'',
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
await lintDocument({
|
|
201
|
+
externalRefResolver: new BaseResolver(),
|
|
202
|
+
document,
|
|
203
|
+
config: makeConfigForRuleset(testRuleSet, undefined, 'oas2'),
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
expect(calls).toMatchInlineSnapshot(`
|
|
207
|
+
Array [
|
|
208
|
+
"enter param path-param",
|
|
209
|
+
"leave param path-param",
|
|
210
|
+
"enter operation: get",
|
|
211
|
+
"enter operation get > param get_a",
|
|
212
|
+
"enter param get_a",
|
|
213
|
+
"leave param get_a",
|
|
214
|
+
"leave operation get > param get_a",
|
|
215
|
+
"enter operation get > param get_b",
|
|
216
|
+
"enter param get_b",
|
|
217
|
+
"leave param get_b",
|
|
218
|
+
"leave operation get > param get_b",
|
|
219
|
+
"leave operation: get",
|
|
220
|
+
"enter operation: post",
|
|
221
|
+
"enter operation post > param post_a",
|
|
222
|
+
"enter param post_a",
|
|
223
|
+
"leave param post_a",
|
|
224
|
+
"leave operation post > param post_a",
|
|
225
|
+
"leave operation: post",
|
|
226
|
+
]
|
|
227
|
+
`);
|
|
228
|
+
});
|
|
229
|
+
|
|
146
230
|
it('should resolve refs', async () => {
|
|
147
231
|
const calls: string[] = [];
|
|
148
232
|
|
package/lib/config/config.d.ts
CHANGED
|
@@ -78,12 +78,27 @@ export declare const DOMAINS: {
|
|
|
78
78
|
[region in Region]: string;
|
|
79
79
|
};
|
|
80
80
|
export declare const AVAILABLE_REGIONS: Region[];
|
|
81
|
-
export declare type
|
|
82
|
-
referenceDocs?: any;
|
|
81
|
+
export declare type DeprecatedRawConfig = {
|
|
83
82
|
apiDefinitions?: Record<string, string>;
|
|
84
83
|
lint?: LintRawConfig;
|
|
85
84
|
resolve?: RawResolveConfig;
|
|
86
85
|
region?: Region;
|
|
86
|
+
referenceDocs?: Record<string, any>;
|
|
87
|
+
};
|
|
88
|
+
export declare type Api = {
|
|
89
|
+
root: string;
|
|
90
|
+
lint?: Omit<LintRawConfig, 'plugins'>;
|
|
91
|
+
'features.openapi'?: Record<string, any>;
|
|
92
|
+
'features.mockServer'?: Record<string, any>;
|
|
93
|
+
};
|
|
94
|
+
export declare type RawConfig = {
|
|
95
|
+
apis?: Record<string, Api>;
|
|
96
|
+
lint?: LintRawConfig;
|
|
97
|
+
resolve?: RawResolveConfig;
|
|
98
|
+
region?: Region;
|
|
99
|
+
'features.openapi'?: Record<string, any>;
|
|
100
|
+
'features.mockServer'?: Record<string, any>;
|
|
101
|
+
organization?: string;
|
|
87
102
|
};
|
|
88
103
|
export declare class LintConfig {
|
|
89
104
|
rawConfig: LintRawConfig;
|
|
@@ -124,11 +139,38 @@ export declare class LintConfig {
|
|
|
124
139
|
export declare class Config {
|
|
125
140
|
rawConfig: RawConfig;
|
|
126
141
|
configFile?: string | undefined;
|
|
127
|
-
|
|
128
|
-
apiDefinitions: Record<string, string>;
|
|
142
|
+
apis: Record<string, Api>;
|
|
129
143
|
lint: LintConfig;
|
|
130
144
|
resolve: ResolveConfig;
|
|
131
145
|
licenseKey?: string;
|
|
132
146
|
region?: Region;
|
|
147
|
+
'features.openapi': Record<string, any>;
|
|
148
|
+
'features.mockServer'?: Record<string, any>;
|
|
149
|
+
organization?: string;
|
|
133
150
|
constructor(rawConfig: RawConfig, configFile?: string | undefined);
|
|
134
151
|
}
|
|
152
|
+
export declare function getMergedConfig(config: Config, entrypointAlias?: string): Config;
|
|
153
|
+
export declare function getMergedLintConfig(config: Config, entrypointAlias?: string): {
|
|
154
|
+
rules: {
|
|
155
|
+
[x: string]: RuleConfig;
|
|
156
|
+
};
|
|
157
|
+
preprocessors: {
|
|
158
|
+
[x: string]: PreprocessorConfig;
|
|
159
|
+
};
|
|
160
|
+
decorators: {
|
|
161
|
+
[x: string]: PreprocessorConfig;
|
|
162
|
+
};
|
|
163
|
+
extends?: string[] | undefined;
|
|
164
|
+
doNotResolveExamples?: boolean | undefined;
|
|
165
|
+
oas2Rules?: Record<string, RuleConfig> | undefined;
|
|
166
|
+
oas3_0Rules?: Record<string, RuleConfig> | undefined;
|
|
167
|
+
oas3_1Rules?: Record<string, RuleConfig> | undefined;
|
|
168
|
+
oas2Preprocessors?: Record<string, PreprocessorConfig> | undefined;
|
|
169
|
+
oas3_0Preprocessors?: Record<string, PreprocessorConfig> | undefined;
|
|
170
|
+
oas3_1Preprocessors?: Record<string, PreprocessorConfig> | undefined;
|
|
171
|
+
oas2Decorators?: Record<string, PreprocessorConfig> | undefined;
|
|
172
|
+
oas3_0Decorators?: Record<string, PreprocessorConfig> | undefined;
|
|
173
|
+
oas3_1Decorators?: Record<string, PreprocessorConfig> | undefined;
|
|
174
|
+
plugins?: (string | Plugin)[] | undefined;
|
|
175
|
+
};
|
|
176
|
+
export declare function transformConfig(rawConfig: DeprecatedRawConfig | RawConfig): RawConfig;
|
package/lib/config/config.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
2
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Config = exports.LintConfig = exports.AVAILABLE_REGIONS = exports.DOMAINS = exports.DEFAULT_REGION = exports.IGNORE_FILE = void 0;
|
|
14
|
+
exports.transformConfig = exports.getMergedLintConfig = exports.getMergedConfig = exports.Config = exports.LintConfig = exports.AVAILABLE_REGIONS = exports.DOMAINS = exports.DEFAULT_REGION = exports.IGNORE_FILE = void 0;
|
|
4
15
|
const fs = require("fs");
|
|
5
16
|
const path = require("path");
|
|
6
17
|
const path_1 = require("path");
|
|
@@ -18,7 +29,6 @@ exports.DOMAINS = {
|
|
|
18
29
|
us: 'redocly.com',
|
|
19
30
|
eu: 'eu.redocly.com',
|
|
20
31
|
};
|
|
21
|
-
exports.AVAILABLE_REGIONS = Object.keys(exports.DOMAINS);
|
|
22
32
|
// FIXME: temporary fix for our lab environments
|
|
23
33
|
if (REDOCLY_DOMAIN === null || REDOCLY_DOMAIN === void 0 ? void 0 : REDOCLY_DOMAIN.endsWith('.redocly.host')) {
|
|
24
34
|
exports.DOMAINS[REDOCLY_DOMAIN.split('.')[0]] = REDOCLY_DOMAIN;
|
|
@@ -26,6 +36,7 @@ if (REDOCLY_DOMAIN === null || REDOCLY_DOMAIN === void 0 ? void 0 : REDOCLY_DOMA
|
|
|
26
36
|
if (REDOCLY_DOMAIN === 'redoc.online') {
|
|
27
37
|
exports.DOMAINS[REDOCLY_DOMAIN] = REDOCLY_DOMAIN;
|
|
28
38
|
}
|
|
39
|
+
exports.AVAILABLE_REGIONS = Object.keys(exports.DOMAINS);
|
|
29
40
|
class LintConfig {
|
|
30
41
|
constructor(rawConfig, configFile) {
|
|
31
42
|
this.rawConfig = rawConfig;
|
|
@@ -65,7 +76,9 @@ class LintConfig {
|
|
|
65
76
|
[oas_types_1.OasVersion.Version3_0]: Object.assign(Object.assign({}, merged.decorators), merged.oas3_0Decorators),
|
|
66
77
|
[oas_types_1.OasVersion.Version3_1]: Object.assign(Object.assign({}, merged.decorators), merged.oas3_1Decorators),
|
|
67
78
|
};
|
|
68
|
-
const dir = this.configFile
|
|
79
|
+
const dir = this.configFile
|
|
80
|
+
? path.dirname(this.configFile)
|
|
81
|
+
: (typeof process !== 'undefined' && process.cwd()) || '';
|
|
69
82
|
const ignoreFile = path.join(dir, exports.IGNORE_FILE);
|
|
70
83
|
/* no crash when using it on the client */
|
|
71
84
|
if (fs.hasOwnProperty('existsSync') && fs.existsSync(ignoreFile)) {
|
|
@@ -87,7 +100,8 @@ class LintConfig {
|
|
|
87
100
|
const ignoreFile = path.join(dir, exports.IGNORE_FILE);
|
|
88
101
|
const mapped = {};
|
|
89
102
|
for (const absFileName of Object.keys(this.ignore)) {
|
|
90
|
-
const ignoredRules = (mapped[utils_1.slash(path.relative(dir, absFileName))] =
|
|
103
|
+
const ignoredRules = (mapped[utils_1.slash(path.relative(dir, absFileName))] =
|
|
104
|
+
this.ignore[absFileName]);
|
|
91
105
|
for (const ruleId of Object.keys(ignoredRules)) {
|
|
92
106
|
ignoredRules[ruleId] = Array.from(ignoredRules[ruleId]);
|
|
93
107
|
}
|
|
@@ -238,9 +252,10 @@ class Config {
|
|
|
238
252
|
var _a, _b, _c;
|
|
239
253
|
this.rawConfig = rawConfig;
|
|
240
254
|
this.configFile = configFile;
|
|
241
|
-
this.
|
|
255
|
+
this.apis = rawConfig.apis || {};
|
|
242
256
|
this.lint = new LintConfig(rawConfig.lint || {}, configFile);
|
|
243
|
-
this.
|
|
257
|
+
this['features.openapi'] = rawConfig['features.openapi'] || {};
|
|
258
|
+
this['features.mockServer'] = rawConfig['features.mockServer'] || {};
|
|
244
259
|
this.resolve = {
|
|
245
260
|
http: {
|
|
246
261
|
headers: (_c = (_b = (_a = rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.resolve) === null || _a === void 0 ? void 0 : _a.http) === null || _b === void 0 ? void 0 : _b.headers) !== null && _c !== void 0 ? _c : [],
|
|
@@ -248,6 +263,7 @@ class Config {
|
|
|
248
263
|
},
|
|
249
264
|
};
|
|
250
265
|
this.region = rawConfig.region;
|
|
266
|
+
this.organization = rawConfig.organization;
|
|
251
267
|
}
|
|
252
268
|
}
|
|
253
269
|
exports.Config = Config;
|
|
@@ -398,3 +414,47 @@ function assignExisting(target, obj) {
|
|
|
398
414
|
}
|
|
399
415
|
}
|
|
400
416
|
}
|
|
417
|
+
function getMergedConfig(config, entrypointAlias) {
|
|
418
|
+
var _a, _b;
|
|
419
|
+
return entrypointAlias
|
|
420
|
+
? new Config(Object.assign(Object.assign({}, config.rawConfig), { lint: getMergedLintConfig(config, entrypointAlias), 'features.openapi': Object.assign(Object.assign({}, config['features.openapi']), (_a = config.apis[entrypointAlias]) === null || _a === void 0 ? void 0 : _a['features.openapi']), 'features.mockServer': Object.assign(Object.assign({}, config['features.mockServer']), (_b = config.apis[entrypointAlias]) === null || _b === void 0 ? void 0 : _b['features.mockServer']) }))
|
|
421
|
+
: config;
|
|
422
|
+
}
|
|
423
|
+
exports.getMergedConfig = getMergedConfig;
|
|
424
|
+
function getMergedLintConfig(config, entrypointAlias) {
|
|
425
|
+
var _a, _b, _c, _d;
|
|
426
|
+
const apiLint = entrypointAlias ? (_a = config.apis[entrypointAlias]) === null || _a === void 0 ? void 0 : _a.lint : {};
|
|
427
|
+
const mergedLint = Object.assign(Object.assign(Object.assign({}, config.rawConfig.lint), apiLint), { rules: Object.assign(Object.assign({}, (_b = config.rawConfig.lint) === null || _b === void 0 ? void 0 : _b.rules), apiLint === null || apiLint === void 0 ? void 0 : apiLint.rules), preprocessors: Object.assign(Object.assign({}, (_c = config.rawConfig.lint) === null || _c === void 0 ? void 0 : _c.preprocessors), apiLint === null || apiLint === void 0 ? void 0 : apiLint.preprocessors), decorators: Object.assign(Object.assign({}, (_d = config.rawConfig.lint) === null || _d === void 0 ? void 0 : _d.decorators), apiLint === null || apiLint === void 0 ? void 0 : apiLint.decorators) });
|
|
428
|
+
return mergedLint;
|
|
429
|
+
}
|
|
430
|
+
exports.getMergedLintConfig = getMergedLintConfig;
|
|
431
|
+
function transformApiDefinitionsToApis(apiDefinitions = {}) {
|
|
432
|
+
let apis = {};
|
|
433
|
+
for (const [apiName, apiPath] of Object.entries(apiDefinitions)) {
|
|
434
|
+
apis[apiName] = { root: apiPath };
|
|
435
|
+
}
|
|
436
|
+
return apis;
|
|
437
|
+
}
|
|
438
|
+
function transformConfig(rawConfig) {
|
|
439
|
+
if (rawConfig.apis && rawConfig.apiDefinitions) {
|
|
440
|
+
throw new Error("Do not use 'apiDefinitions' field. Use 'apis' instead.\n");
|
|
441
|
+
}
|
|
442
|
+
if (rawConfig['features.openapi'] &&
|
|
443
|
+
rawConfig.referenceDocs) {
|
|
444
|
+
throw new Error("Do not use 'referenceDocs' field. Use 'features.openapi' instead.\n");
|
|
445
|
+
}
|
|
446
|
+
const _a = rawConfig, { apiDefinitions, referenceDocs } = _a, rest = __rest(_a, ["apiDefinitions", "referenceDocs"]);
|
|
447
|
+
// TODO: put links to the changelog and uncomment this after successful release of ReferenceDocs/Redoc, Portal and Workflows
|
|
448
|
+
// if (apiDefinitions) {
|
|
449
|
+
// process.stderr.write(
|
|
450
|
+
// `The ${yellow('apiDefinitions')} field is deprecated. Use ${green('apis')} instead, see changelog: <link>\n`
|
|
451
|
+
// );
|
|
452
|
+
// }
|
|
453
|
+
// if (referenceDocs) {
|
|
454
|
+
// process.stderr.write(
|
|
455
|
+
// `The ${yellow('referenceDocs')} field is deprecated. Use ${green('features.openapi')} instead, see changelog: <link>\n`
|
|
456
|
+
// );
|
|
457
|
+
// }
|
|
458
|
+
return Object.assign({ 'features.openapi': referenceDocs, apis: transformApiDefinitionsToApis(apiDefinitions) }, rest);
|
|
459
|
+
}
|
|
460
|
+
exports.transformConfig = transformConfig;
|
package/lib/config/load.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Config } from './config';
|
|
2
|
-
export declare function loadConfig(configPath?: string, customExtends?: string[]): Promise<Config>;
|
|
1
|
+
import { Config, RawConfig } from './config';
|
|
2
|
+
export declare function loadConfig(configPath?: string | undefined, customExtends?: string[]): Promise<Config>;
|
|
3
3
|
export declare const CONFIG_FILE_NAMES: string[];
|
|
4
|
-
export declare function findConfig(): string | undefined;
|
|
4
|
+
export declare function findConfig(dir?: string): string | undefined;
|
|
5
|
+
export declare function getConfig(configPath?: string | undefined): Promise<RawConfig>;
|
package/lib/config/load.js
CHANGED
|
@@ -9,27 +9,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.findConfig = exports.CONFIG_FILE_NAMES = exports.loadConfig = void 0;
|
|
12
|
+
exports.getConfig = exports.findConfig = exports.CONFIG_FILE_NAMES = exports.loadConfig = void 0;
|
|
13
13
|
const fs = require("fs");
|
|
14
|
+
const path = require("path");
|
|
14
15
|
const redocly_1 = require("../redocly");
|
|
15
16
|
const utils_1 = require("../utils");
|
|
16
17
|
const config_1 = require("./config");
|
|
17
18
|
const builtIn_1 = require("./builtIn");
|
|
18
|
-
function loadConfig(configPath, customExtends) {
|
|
19
|
+
function loadConfig(configPath = findConfig(), customExtends) {
|
|
19
20
|
var _a, _b;
|
|
20
21
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
-
|
|
22
|
-
configPath = findConfig();
|
|
23
|
-
}
|
|
24
|
-
let rawConfig = {};
|
|
25
|
-
if (configPath !== undefined) {
|
|
26
|
-
try {
|
|
27
|
-
rawConfig = (yield utils_1.loadYaml(configPath));
|
|
28
|
-
}
|
|
29
|
-
catch (e) {
|
|
30
|
-
throw new Error(`Error parsing config file at \`${configPath}\`: ${e.message}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
22
|
+
const rawConfig = yield getConfig(configPath);
|
|
33
23
|
if (customExtends !== undefined) {
|
|
34
24
|
rawConfig.lint = rawConfig.lint || {};
|
|
35
25
|
rawConfig.lint.extends = customExtends;
|
|
@@ -64,10 +54,12 @@ function loadConfig(configPath, customExtends) {
|
|
|
64
54
|
}
|
|
65
55
|
exports.loadConfig = loadConfig;
|
|
66
56
|
exports.CONFIG_FILE_NAMES = ['redocly.yaml', 'redocly.yml', '.redocly.yaml', '.redocly.yml'];
|
|
67
|
-
function findConfig() {
|
|
57
|
+
function findConfig(dir) {
|
|
68
58
|
if (!fs.hasOwnProperty('existsSync'))
|
|
69
59
|
return;
|
|
70
|
-
const existingConfigFiles = exports.CONFIG_FILE_NAMES
|
|
60
|
+
const existingConfigFiles = exports.CONFIG_FILE_NAMES
|
|
61
|
+
.map(name => dir ? path.resolve(dir, name) : name)
|
|
62
|
+
.filter(fs.existsSync);
|
|
71
63
|
if (existingConfigFiles.length > 1) {
|
|
72
64
|
throw new Error(`
|
|
73
65
|
Multiple configuration files are not allowed.
|
|
@@ -78,3 +70,17 @@ function findConfig() {
|
|
|
78
70
|
return existingConfigFiles[0];
|
|
79
71
|
}
|
|
80
72
|
exports.findConfig = findConfig;
|
|
73
|
+
function getConfig(configPath = findConfig()) {
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
if (!configPath)
|
|
76
|
+
return {};
|
|
77
|
+
try {
|
|
78
|
+
const rawConfig = ((yield utils_1.loadYaml(configPath)) || {});
|
|
79
|
+
return config_1.transformConfig(rawConfig);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
throw new Error(`Error parsing config file at '${configPath}': ${e.message}`);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
exports.getConfig = getConfig;
|
package/lib/format/codeframes.js
CHANGED
|
@@ -142,9 +142,12 @@ function getAstNodeByPointer(root, pointer, reportOnKey) {
|
|
|
142
142
|
for (const key of pointerSegments) {
|
|
143
143
|
if (currentNode.kind === yamlAst.Kind.MAP) {
|
|
144
144
|
const mapping = currentNode.mappings.find((m) => m.key.value === key);
|
|
145
|
-
if (!
|
|
145
|
+
if (!mapping)
|
|
146
146
|
break;
|
|
147
|
-
currentNode = mapping
|
|
147
|
+
currentNode = mapping;
|
|
148
|
+
if (!(mapping === null || mapping === void 0 ? void 0 : mapping.value))
|
|
149
|
+
break; // If node has value - return value, if not - return node itself
|
|
150
|
+
currentNode = mapping.value;
|
|
148
151
|
}
|
|
149
152
|
else if (currentNode.kind === yamlAst.Kind.SEQ) {
|
|
150
153
|
const elem = currentNode.items[parseInt(key, 10)];
|
package/lib/index.d.ts
CHANGED
|
@@ -3,13 +3,13 @@ export { Oas3_1Types } from './types/oas3_1';
|
|
|
3
3
|
export { Oas3Types } from './types/oas3';
|
|
4
4
|
export { Oas2Types } from './types/oas2';
|
|
5
5
|
export { ConfigTypes } from './types/redocly-yaml';
|
|
6
|
-
export { Oas3Definition, Oas3_1Definition, Oas3Components, Oas3PathItem, Oas3Paths, Oas3ComponentName, Oas3Schema, Oas3_1Schema, Oas3Tag, Oas3_1Webhooks, Referenced } from './typings/openapi';
|
|
6
|
+
export { Oas3Definition, Oas3_1Definition, Oas3Components, Oas3PathItem, Oas3Paths, Oas3ComponentName, Oas3Schema, Oas3_1Schema, Oas3Tag, Oas3_1Webhooks, Referenced, } from './typings/openapi';
|
|
7
7
|
export { Oas2Definition } from './typings/swagger';
|
|
8
8
|
export { StatsAccumulator, StatsName } from './typings/common';
|
|
9
9
|
export { normalizeTypes } from './types';
|
|
10
10
|
export { Stats } from './rules/other/stats';
|
|
11
|
-
export { Config, LintConfig, RawConfig, IGNORE_FILE, Region } from './config/config';
|
|
12
|
-
export { loadConfig, findConfig, CONFIG_FILE_NAMES } from './config/load';
|
|
11
|
+
export { Config, LintConfig, RawConfig, IGNORE_FILE, Region, getMergedConfig, transformConfig, } from './config/config';
|
|
12
|
+
export { loadConfig, getConfig, findConfig, CONFIG_FILE_NAMES } from './config/load';
|
|
13
13
|
export { RedoclyClient, isRedoclyRegistryURL } from './redocly';
|
|
14
14
|
export { Source, BaseResolver, Document, resolveDocument, ResolveError, YamlParseError, makeDocumentFromString, } from './resolve';
|
|
15
15
|
export { parseYaml, stringifyYaml } from './js-yaml';
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.mapTypeToComponent = exports.bundleDocument = exports.bundle = exports.lintConfig = exports.lintFromString = exports.lintDocument = exports.validate = exports.lint = exports.getTotals = exports.formatProblems = exports.getLineColLocation = exports.getAstNodeByPointer = exports.walkDocument = exports.normalizeVisitors = exports.OasVersion = exports.openAPIMajor = exports.OasMajorVersion = exports.detectOpenAPI = exports.isRef = exports.unescapePointer = exports.stringifyYaml = exports.parseYaml = exports.makeDocumentFromString = exports.YamlParseError = exports.ResolveError = exports.resolveDocument = exports.BaseResolver = exports.Source = exports.isRedoclyRegistryURL = exports.RedoclyClient = exports.CONFIG_FILE_NAMES = exports.findConfig = exports.loadConfig = exports.IGNORE_FILE = exports.LintConfig = exports.Config = exports.Stats = exports.normalizeTypes = exports.ConfigTypes = exports.Oas2Types = exports.Oas3Types = exports.Oas3_1Types = exports.slash = exports.readFileFromUrl = void 0;
|
|
3
|
+
exports.mapTypeToComponent = exports.bundleDocument = exports.bundle = exports.lintConfig = exports.lintFromString = exports.lintDocument = exports.validate = exports.lint = exports.getTotals = exports.formatProblems = exports.getLineColLocation = exports.getAstNodeByPointer = exports.walkDocument = exports.normalizeVisitors = exports.OasVersion = exports.openAPIMajor = exports.OasMajorVersion = exports.detectOpenAPI = exports.isRef = exports.unescapePointer = exports.stringifyYaml = exports.parseYaml = exports.makeDocumentFromString = exports.YamlParseError = exports.ResolveError = exports.resolveDocument = exports.BaseResolver = exports.Source = exports.isRedoclyRegistryURL = exports.RedoclyClient = exports.CONFIG_FILE_NAMES = exports.findConfig = exports.getConfig = exports.loadConfig = exports.transformConfig = exports.getMergedConfig = exports.IGNORE_FILE = exports.LintConfig = exports.Config = exports.Stats = exports.normalizeTypes = exports.ConfigTypes = exports.Oas2Types = exports.Oas3Types = exports.Oas3_1Types = exports.slash = exports.readFileFromUrl = void 0;
|
|
4
4
|
var utils_1 = require("./utils");
|
|
5
5
|
Object.defineProperty(exports, "readFileFromUrl", { enumerable: true, get: function () { return utils_1.readFileFromUrl; } });
|
|
6
6
|
Object.defineProperty(exports, "slash", { enumerable: true, get: function () { return utils_1.slash; } });
|
|
@@ -20,8 +20,11 @@ var config_1 = require("./config/config");
|
|
|
20
20
|
Object.defineProperty(exports, "Config", { enumerable: true, get: function () { return config_1.Config; } });
|
|
21
21
|
Object.defineProperty(exports, "LintConfig", { enumerable: true, get: function () { return config_1.LintConfig; } });
|
|
22
22
|
Object.defineProperty(exports, "IGNORE_FILE", { enumerable: true, get: function () { return config_1.IGNORE_FILE; } });
|
|
23
|
+
Object.defineProperty(exports, "getMergedConfig", { enumerable: true, get: function () { return config_1.getMergedConfig; } });
|
|
24
|
+
Object.defineProperty(exports, "transformConfig", { enumerable: true, get: function () { return config_1.transformConfig; } });
|
|
23
25
|
var load_1 = require("./config/load");
|
|
24
26
|
Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return load_1.loadConfig; } });
|
|
27
|
+
Object.defineProperty(exports, "getConfig", { enumerable: true, get: function () { return load_1.getConfig; } });
|
|
25
28
|
Object.defineProperty(exports, "findConfig", { enumerable: true, get: function () { return load_1.findConfig; } });
|
|
26
29
|
Object.defineProperty(exports, "CONFIG_FILE_NAMES", { enumerable: true, get: function () { return load_1.CONFIG_FILE_NAMES; } });
|
|
27
30
|
var redocly_1 = require("./redocly");
|
package/lib/redocly/index.js
CHANGED
|
@@ -18,6 +18,7 @@ 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
|
|
21
22
|
class RedoclyClient {
|
|
22
23
|
constructor(region) {
|
|
23
24
|
this.accessTokens = {};
|
|
@@ -26,7 +27,11 @@ class RedoclyClient {
|
|
|
26
27
|
this.domain = region
|
|
27
28
|
? config_1.DOMAINS[region]
|
|
28
29
|
: process.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
|
|
29
|
-
|
|
30
|
+
/*
|
|
31
|
+
* We can't use process.env here because it is replaced by a const in some client-side bundles,
|
|
32
|
+
* which breaks assignment.
|
|
33
|
+
*/
|
|
34
|
+
REDOCLY_DOMAIN = this.domain; // isRedoclyRegistryURL depends on the value to be set
|
|
30
35
|
this.registryApi = new registry_api_1.RegistryApi(this.accessTokens, this.region);
|
|
31
36
|
}
|
|
32
37
|
loadRegion(region) {
|
|
@@ -144,7 +149,7 @@ class RedoclyClient {
|
|
|
144
149
|
}
|
|
145
150
|
exports.RedoclyClient = RedoclyClient;
|
|
146
151
|
function isRedoclyRegistryURL(link) {
|
|
147
|
-
const domain = process.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
|
|
152
|
+
const domain = REDOCLY_DOMAIN || process.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
|
|
148
153
|
const legacyDomain = domain === 'redocly.com' ? 'redoc.ly' : domain;
|
|
149
154
|
if (!link.startsWith(`https://api.${domain}/registry/`) &&
|
|
150
155
|
!link.startsWith(`https://api.${legacyDomain}/registry/`)) {
|
|
@@ -4,9 +4,10 @@ exports.NoEmptyServers = void 0;
|
|
|
4
4
|
const NoEmptyServers = () => {
|
|
5
5
|
return {
|
|
6
6
|
DefinitionRoot(root, { report, location }) {
|
|
7
|
-
if (!root.servers) {
|
|
7
|
+
if (!root.hasOwnProperty('servers')) {
|
|
8
8
|
report({
|
|
9
9
|
message: 'Servers must be present.',
|
|
10
|
+
location: location.child(['openapi']).key()
|
|
10
11
|
});
|
|
11
12
|
return;
|
|
12
13
|
}
|
package/lib/types/oas2.js
CHANGED
|
@@ -55,6 +55,7 @@ const PathMap = {
|
|
|
55
55
|
const PathItem = {
|
|
56
56
|
properties: {
|
|
57
57
|
$ref: { type: 'string' },
|
|
58
|
+
parameters: _1.listOf('Parameter'),
|
|
58
59
|
get: 'Operation',
|
|
59
60
|
put: 'Operation',
|
|
60
61
|
post: 'Operation',
|
|
@@ -62,7 +63,6 @@ const PathItem = {
|
|
|
62
63
|
options: 'Operation',
|
|
63
64
|
head: 'Operation',
|
|
64
65
|
patch: 'Operation',
|
|
65
|
-
parameters: _1.listOf('Parameter'),
|
|
66
66
|
},
|
|
67
67
|
};
|
|
68
68
|
const Operation = {
|
|
@@ -12,6 +12,7 @@ const ConfigRoot = {
|
|
|
12
12
|
},
|
|
13
13
|
lint: 'ConfigLint',
|
|
14
14
|
referenceDocs: 'ConfigReferenceDocs',
|
|
15
|
+
'features.mockServer': 'ConfigMockServer',
|
|
15
16
|
},
|
|
16
17
|
};
|
|
17
18
|
const ConfigHTTP = {
|
|
@@ -445,10 +446,17 @@ const ConfigReferenceDocs = {
|
|
|
445
446
|
},
|
|
446
447
|
additionalProperties: { type: 'string' },
|
|
447
448
|
};
|
|
449
|
+
const ConfigMockServer = {
|
|
450
|
+
properties: {
|
|
451
|
+
strictExamples: { type: 'boolean' },
|
|
452
|
+
errorIfForcedExampleNotFound: { type: 'boolean' },
|
|
453
|
+
},
|
|
454
|
+
};
|
|
448
455
|
exports.ConfigTypes = {
|
|
449
456
|
ConfigRoot,
|
|
450
457
|
ConfigLint,
|
|
451
458
|
ConfigReferenceDocs,
|
|
459
|
+
ConfigMockServer,
|
|
452
460
|
ConfigHTTP,
|
|
453
461
|
ConfigLanguage,
|
|
454
462
|
ConfigLabels,
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@ import { loadConfig, findConfig } from '../load';
|
|
|
2
2
|
import { RedoclyClient } from '../../redocly';
|
|
3
3
|
|
|
4
4
|
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
5
6
|
|
|
6
7
|
describe('loadConfig', () => {
|
|
7
8
|
it('should resolve config http header by US region', async () => {
|
|
@@ -66,4 +67,10 @@ describe('findConfig', () => {
|
|
|
66
67
|
Please use 'redocly.yaml' instead.
|
|
67
68
|
`);
|
|
68
69
|
});
|
|
70
|
+
it('should find a nested config ', async () => {
|
|
71
|
+
jest.spyOn(fs, 'existsSync').mockImplementation((name) => name === 'dir/redocly.yaml');
|
|
72
|
+
jest.spyOn(path, 'resolve').mockImplementationOnce((dir, name) => `${dir}/${name}`);
|
|
73
|
+
const configName = findConfig('dir');
|
|
74
|
+
expect(configName).toStrictEqual('dir/redocly.yaml');
|
|
75
|
+
});
|
|
69
76
|
});
|