@redocly/openapi-core 1.0.0-beta.94 → 1.0.0-beta.97
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/README.md +1 -1
- package/__tests__/bundle.test.ts +6 -6
- package/__tests__/fixtures/extension.js +1 -1
- package/__tests__/login.test.ts +2 -2
- package/__tests__/ref-utils.test.ts +1 -1
- package/__tests__/utils.ts +30 -18
- package/lib/benchmark/benches/recommended-oas3.bench.js +2 -3
- package/lib/benchmark/utils.d.ts +2 -1
- package/lib/benchmark/utils.js +10 -7
- package/lib/bundle.d.ts +2 -2
- package/lib/config/all.d.ts +2 -2
- package/lib/config/builtIn.d.ts +1 -1
- package/lib/config/config-resolvers.d.ts +16 -0
- package/lib/config/config-resolvers.js +242 -0
- package/lib/config/config.d.ts +18 -130
- package/lib/config/config.js +34 -245
- package/lib/config/index.d.ts +7 -0
- package/lib/config/index.js +19 -0
- package/lib/config/load.d.ts +2 -1
- package/lib/config/load.js +20 -13
- package/lib/config/minimal.d.ts +2 -2
- package/lib/config/recommended.d.ts +2 -2
- package/lib/config/types.d.ts +113 -0
- package/lib/config/types.js +2 -0
- package/lib/config/utils.d.ts +13 -0
- package/lib/config/utils.js +160 -0
- package/lib/format/format.d.ts +1 -1
- package/lib/format/format.js +30 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.js +5 -6
- package/lib/lint.d.ts +1 -1
- package/lib/lint.js +5 -7
- package/lib/redocly/index.d.ts +1 -1
- package/lib/redocly/index.js +10 -26
- package/lib/redocly/redocly-client-types.d.ts +1 -1
- package/lib/redocly/registry-api-types.d.ts +1 -0
- package/lib/redocly/registry-api.d.ts +2 -2
- package/lib/redocly/registry-api.js +2 -1
- package/lib/resolve.d.ts +1 -1
- package/lib/resolve.js +1 -2
- package/lib/rules/common/assertions/index.js +1 -1
- package/lib/rules/common/assertions/utils.d.ts +1 -1
- package/lib/rules/common/assertions/utils.js +6 -2
- package/lib/utils.d.ts +4 -2
- package/lib/utils.js +20 -3
- package/package.json +9 -6
- package/src/__tests__/lint.test.ts +1 -1
- package/src/benchmark/benches/recommended-oas3.bench.ts +2 -3
- package/src/benchmark/benchmark.js +1 -1
- package/src/benchmark/utils.ts +13 -8
- package/src/bundle.ts +2 -1
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +157 -0
- package/src/config/__tests__/config-resolvers.test.ts +429 -0
- package/src/config/__tests__/config.test.ts +17 -29
- package/src/config/__tests__/fixtures/plugin.js +1 -1
- package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +12 -0
- package/src/config/__tests__/fixtures/resolve-config/api/plugin.js +67 -0
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-circular.yaml +8 -0
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +19 -0
- package/src/config/__tests__/fixtures/resolve-config/local-config.yaml +10 -0
- package/src/config/__tests__/fixtures/resolve-config/plugin.js +66 -0
- package/src/config/__tests__/fixtures/resolve-remote-configs/nested-remote-config.yaml +4 -0
- package/src/config/__tests__/fixtures/resolve-remote-configs/remote-config.yaml +5 -0
- package/src/config/__tests__/load.test.ts +8 -1
- package/src/config/all.ts +3 -2
- package/src/config/builtIn.ts +2 -1
- package/src/config/config-resolvers.ts +359 -0
- package/src/config/config.ts +60 -468
- package/src/config/index.ts +7 -0
- package/src/config/load.ts +37 -31
- package/src/config/minimal.ts +2 -2
- package/src/config/recommended.ts +2 -2
- package/src/config/types.ts +168 -0
- package/src/config/utils.ts +208 -0
- package/src/decorators/__tests__/remove-x-internal.test.ts +5 -5
- package/src/format/format.ts +38 -7
- package/src/index.ts +6 -2
- package/src/lint.ts +4 -5
- package/src/redocly/__tests__/redocly-client.test.ts +7 -0
- package/src/redocly/index.ts +14 -41
- package/src/redocly/redocly-client-types.ts +1 -1
- package/src/redocly/registry-api-types.ts +1 -0
- package/src/redocly/registry-api.ts +5 -1
- package/src/resolve.ts +2 -4
- package/src/rules/__tests__/no-unresolved-refs.test.ts +4 -4
- package/src/rules/common/__tests__/info-description.test.ts +3 -3
- package/src/rules/common/__tests__/info-license.test.ts +2 -2
- package/src/rules/common/__tests__/license-url.test.ts +2 -2
- package/src/rules/common/__tests__/no-ambiguous-paths.test.ts +1 -1
- package/src/rules/common/__tests__/no-enum-type-mismatch.test.ts +5 -5
- package/src/rules/common/__tests__/no-identical-paths.test.ts +1 -1
- package/src/rules/common/__tests__/no-path-trailing-slash.test.ts +3 -3
- package/src/rules/common/__tests__/operation-2xx-response.test.ts +3 -3
- package/src/rules/common/__tests__/operation-4xx-response.test.ts +3 -3
- package/src/rules/common/__tests__/operation-operationId-unique.test.ts +2 -2
- package/src/rules/common/__tests__/operation-operationId-url-safe.test.ts +1 -1
- package/src/rules/common/__tests__/operation-parameters-unique.test.ts +4 -4
- package/src/rules/common/__tests__/operation-security-defined.test.ts +2 -2
- package/src/rules/common/__tests__/operation-singular-tag.test.ts +2 -2
- package/src/rules/common/__tests__/path-http-verbs-order.test.ts +2 -2
- package/src/rules/common/__tests__/path-not-include-query.test.ts +2 -2
- package/src/rules/common/__tests__/path-params-defined.test.ts +3 -3
- package/src/rules/common/__tests__/paths-kebab-case.test.ts +3 -3
- package/src/rules/common/__tests__/spec.test.ts +1 -1
- package/src/rules/common/__tests__/tag-description.test.ts +2 -2
- package/src/rules/common/__tests__/tags-alphabetical.test.ts +2 -2
- package/src/rules/common/assertions/index.ts +1 -1
- package/src/rules/common/assertions/utils.ts +5 -2
- package/src/rules/oas2/__tests__/boolean-parameter-prefixes.test.ts +3 -3
- package/src/rules/oas2/__tests__/spec/referenceableScalars.test.ts +1 -1
- package/src/rules/oas2/__tests__/spec/utils.ts +10 -7
- package/src/rules/oas3/__tests__/boolean-parameter-prefixes.test.ts +3 -3
- package/src/rules/oas3/__tests__/no-empty-enum-servers.com.test.ts +6 -6
- package/src/rules/oas3/__tests__/no-example-value-and-externalValue.test.ts +2 -2
- package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +8 -8
- package/src/rules/oas3/__tests__/no-server-example.com.test.ts +2 -2
- package/src/rules/oas3/__tests__/no-server-trailing-slash.test.ts +3 -3
- package/src/rules/oas3/__tests__/no-unused-components.test.ts +1 -1
- package/src/rules/oas3/__tests__/spec/referenceableScalars.test.ts +23 -14
- package/src/rules/oas3/__tests__/spec/spec.test.ts +4 -4
- package/src/rules/oas3/__tests__/spec/utils.ts +10 -7
- package/src/utils.ts +21 -4
- package/tsconfig.tsbuildinfo +1 -1
package/src/config/config.ts
CHANGED
|
@@ -1,165 +1,53 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import { dirname } from 'path';
|
|
4
|
-
import { red, blue, yellow, green } from 'colorette';
|
|
5
3
|
import { parseYaml, stringifyYaml } from '../js-yaml';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
4
|
+
import { slash } from '../utils';
|
|
5
|
+
import { NormalizedProblem } from '../walk';
|
|
6
|
+
import { OasVersion, OasMajorVersion, Oas2RuleSet, Oas3RuleSet } from '../oas-types';
|
|
7
|
+
|
|
8
|
+
import type { NodeType } from '../types';
|
|
9
|
+
import type {
|
|
10
|
+
DecoratorConfig,
|
|
11
|
+
Plugin,
|
|
12
|
+
PreprocessorConfig,
|
|
13
|
+
Region,
|
|
14
|
+
ResolveConfig,
|
|
15
|
+
ResolvedApi,
|
|
16
|
+
ResolvedConfig,
|
|
17
|
+
ResolvedLintConfig,
|
|
18
|
+
RuleConfig,
|
|
19
|
+
} from './types';
|
|
20
|
+
import { getResolveConfig } from './utils';
|
|
21
|
+
|
|
22
|
+
// Alias environment here so this file can work in browser environments too.
|
|
23
|
+
export const env = typeof process !== 'undefined' ? process.env || {} : {};
|
|
20
24
|
|
|
21
25
|
export const IGNORE_FILE = '.redocly.lint-ignore.yaml';
|
|
22
26
|
const IGNORE_BANNER =
|
|
23
27
|
`# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.\n` +
|
|
24
28
|
`# See https://redoc.ly/docs/cli/ for more information.\n`;
|
|
25
29
|
|
|
26
|
-
export type RuleConfig =
|
|
27
|
-
| ProblemSeverity
|
|
28
|
-
| 'off'
|
|
29
|
-
| ({
|
|
30
|
-
severity?: ProblemSeverity;
|
|
31
|
-
} & Record<string, any>);
|
|
32
|
-
|
|
33
|
-
export type PreprocessorConfig =
|
|
34
|
-
| ProblemSeverity
|
|
35
|
-
| 'off'
|
|
36
|
-
| 'on'
|
|
37
|
-
| ({
|
|
38
|
-
severity?: ProblemSeverity;
|
|
39
|
-
} & Record<string, any>);
|
|
40
|
-
|
|
41
|
-
export type DecoratorConfig = PreprocessorConfig;
|
|
42
|
-
|
|
43
|
-
export type LintRawConfig = {
|
|
44
|
-
plugins?: (string | Plugin)[];
|
|
45
|
-
extends?: string[];
|
|
46
|
-
doNotResolveExamples?: boolean;
|
|
47
|
-
|
|
48
|
-
rules?: Record<string, RuleConfig>;
|
|
49
|
-
oas2Rules?: Record<string, RuleConfig>;
|
|
50
|
-
oas3_0Rules?: Record<string, RuleConfig>;
|
|
51
|
-
oas3_1Rules?: Record<string, RuleConfig>;
|
|
52
|
-
|
|
53
|
-
preprocessors?: Record<string, PreprocessorConfig>;
|
|
54
|
-
oas2Preprocessors?: Record<string, PreprocessorConfig>;
|
|
55
|
-
oas3_0Preprocessors?: Record<string, PreprocessorConfig>;
|
|
56
|
-
oas3_1Preprocessors?: Record<string, PreprocessorConfig>;
|
|
57
|
-
|
|
58
|
-
decorators?: Record<string, DecoratorConfig>;
|
|
59
|
-
oas2Decorators?: Record<string, DecoratorConfig>;
|
|
60
|
-
oas3_0Decorators?: Record<string, DecoratorConfig>;
|
|
61
|
-
oas3_1Decorators?: Record<string, DecoratorConfig>;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export type PreprocessorsConfig = {
|
|
65
|
-
oas3?: Oas3PreprocessorsSet;
|
|
66
|
-
oas2?: Oas2PreprocessorsSet;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export type DecoratorsConfig = {
|
|
70
|
-
oas3?: Oas3DecoratorsSet;
|
|
71
|
-
oas2?: Oas2DecoratorsSet;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export type TypesExtensionFn = (
|
|
75
|
-
types: Record<string, NodeType>,
|
|
76
|
-
oasVersion: OasVersion,
|
|
77
|
-
) => Record<string, NodeType>;
|
|
78
|
-
|
|
79
|
-
export type TypeExtensionsConfig = Partial<Record<OasMajorVersion, TypesExtensionFn>>;
|
|
80
|
-
export type CustomRulesConfig = {
|
|
81
|
-
oas3?: Oas3RuleSet;
|
|
82
|
-
oas2?: Oas2RuleSet;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
export type Plugin = {
|
|
86
|
-
id: string;
|
|
87
|
-
configs?: Record<string, LintRawConfig>;
|
|
88
|
-
rules?: CustomRulesConfig;
|
|
89
|
-
preprocessors?: PreprocessorsConfig;
|
|
90
|
-
decorators?: DecoratorsConfig;
|
|
91
|
-
typeExtension?: TypeExtensionsConfig;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
export type ResolveHeader =
|
|
95
|
-
| {
|
|
96
|
-
name: string;
|
|
97
|
-
envVariable?: undefined;
|
|
98
|
-
value: string;
|
|
99
|
-
matches: string;
|
|
100
|
-
}
|
|
101
|
-
| {
|
|
102
|
-
name: string;
|
|
103
|
-
value?: undefined;
|
|
104
|
-
envVariable: string;
|
|
105
|
-
matches: string;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
export type RawResolveConfig = {
|
|
109
|
-
http?: Partial<HttpResolveConfig>;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
export type HttpResolveConfig = {
|
|
113
|
-
headers: ResolveHeader[];
|
|
114
|
-
customFetch?: Function;
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
export type ResolveConfig = {
|
|
118
|
-
http: HttpResolveConfig;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
30
|
export const DEFAULT_REGION = 'us';
|
|
122
|
-
export type Region = 'us' | 'eu';
|
|
123
|
-
export type AccessTokens = { [region in Region]?: string };
|
|
124
|
-
const REDOCLY_DOMAIN = process.env.REDOCLY_DOMAIN;
|
|
125
|
-
export const DOMAINS: { [region in Region]: string } = {
|
|
126
|
-
us: 'redocly.com',
|
|
127
|
-
eu: 'eu.redocly.com',
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
// FIXME: temporary fix for our lab environments
|
|
131
|
-
if (REDOCLY_DOMAIN?.endsWith('.redocly.host')) {
|
|
132
|
-
DOMAINS[REDOCLY_DOMAIN.split('.')[0] as Region] = REDOCLY_DOMAIN;
|
|
133
|
-
}
|
|
134
|
-
if (REDOCLY_DOMAIN === 'redoc.online') {
|
|
135
|
-
DOMAINS[REDOCLY_DOMAIN as Region] = REDOCLY_DOMAIN;
|
|
136
|
-
}
|
|
137
|
-
export const AVAILABLE_REGIONS = Object.keys(DOMAINS) as Region[];
|
|
138
31
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
referenceDocs?: Record<string, any>;
|
|
145
|
-
};
|
|
32
|
+
function getDomains() {
|
|
33
|
+
const domains: { [region in Region]: string } = {
|
|
34
|
+
us: 'redocly.com',
|
|
35
|
+
eu: 'eu.redocly.com',
|
|
36
|
+
};
|
|
146
37
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
38
|
+
// FIXME: temporary fix for our lab environments
|
|
39
|
+
const domain = env.REDOCLY_DOMAIN;
|
|
40
|
+
if (domain?.endsWith('.redocly.host')) {
|
|
41
|
+
domains[domain.split('.')[0] as Region] = domain;
|
|
42
|
+
}
|
|
43
|
+
if (domain === 'redoc.online') {
|
|
44
|
+
domains[domain as Region] = domain;
|
|
45
|
+
}
|
|
46
|
+
return domains;
|
|
47
|
+
}
|
|
153
48
|
|
|
154
|
-
export
|
|
155
|
-
|
|
156
|
-
lint?: LintRawConfig;
|
|
157
|
-
resolve?: RawResolveConfig;
|
|
158
|
-
region?: Region;
|
|
159
|
-
'features.openapi'?: Record<string, any>;
|
|
160
|
-
'features.mockServer'?: Record<string, any>;
|
|
161
|
-
organization?: string;
|
|
162
|
-
};
|
|
49
|
+
export const DOMAINS = getDomains();
|
|
50
|
+
export const AVAILABLE_REGIONS = Object.keys(DOMAINS) as Region[];
|
|
163
51
|
|
|
164
52
|
export class LintConfig {
|
|
165
53
|
plugins: Plugin[];
|
|
@@ -172,48 +60,38 @@ export class LintConfig {
|
|
|
172
60
|
private _usedRules: Set<string> = new Set();
|
|
173
61
|
private _usedVersions: Set<OasVersion> = new Set();
|
|
174
62
|
|
|
175
|
-
recommendedFallback: boolean
|
|
176
|
-
|
|
177
|
-
constructor(public rawConfig: LintRawConfig, public configFile?: string) {
|
|
178
|
-
this.plugins = rawConfig.plugins ? resolvePlugins(rawConfig.plugins, configFile) : [];
|
|
179
|
-
this.doNotResolveExamples = !!rawConfig.doNotResolveExamples;
|
|
180
|
-
|
|
181
|
-
if (!rawConfig.extends) {
|
|
182
|
-
this.recommendedFallback = true;
|
|
183
|
-
}
|
|
63
|
+
recommendedFallback: boolean;
|
|
184
64
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
: [recommended];
|
|
65
|
+
extendPaths: string[];
|
|
66
|
+
pluginPaths: string[];
|
|
188
67
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
preprocessors: rawConfig.preprocessors,
|
|
193
|
-
decorators: rawConfig.decorators,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
68
|
+
constructor(public rawConfig: ResolvedLintConfig, public configFile?: string) {
|
|
69
|
+
this.plugins = rawConfig.plugins || [];
|
|
70
|
+
this.doNotResolveExamples = !!rawConfig.doNotResolveExamples;
|
|
196
71
|
|
|
197
|
-
|
|
72
|
+
this.recommendedFallback = rawConfig.recommendedFallback || false
|
|
198
73
|
|
|
199
74
|
this.rules = {
|
|
200
|
-
[OasVersion.Version2]: { ...
|
|
201
|
-
[OasVersion.Version3_0]: { ...
|
|
202
|
-
[OasVersion.Version3_1]: { ...
|
|
75
|
+
[OasVersion.Version2]: { ...rawConfig.rules, ...rawConfig.oas2Rules },
|
|
76
|
+
[OasVersion.Version3_0]: { ...rawConfig.rules, ...rawConfig.oas3_0Rules },
|
|
77
|
+
[OasVersion.Version3_1]: { ...rawConfig.rules, ...rawConfig.oas3_1Rules },
|
|
203
78
|
};
|
|
204
79
|
|
|
205
80
|
this.preprocessors = {
|
|
206
|
-
[OasVersion.Version2]: { ...
|
|
207
|
-
[OasVersion.Version3_0]: { ...
|
|
208
|
-
[OasVersion.Version3_1]: { ...
|
|
81
|
+
[OasVersion.Version2]: { ...rawConfig.preprocessors, ...rawConfig.oas2Preprocessors },
|
|
82
|
+
[OasVersion.Version3_0]: { ...rawConfig.preprocessors, ...rawConfig.oas3_0Preprocessors },
|
|
83
|
+
[OasVersion.Version3_1]: { ...rawConfig.preprocessors, ...rawConfig.oas3_1Preprocessors },
|
|
209
84
|
};
|
|
210
85
|
|
|
211
86
|
this.decorators = {
|
|
212
|
-
[OasVersion.Version2]: { ...
|
|
213
|
-
[OasVersion.Version3_0]: { ...
|
|
214
|
-
[OasVersion.Version3_1]: { ...
|
|
87
|
+
[OasVersion.Version2]: { ...rawConfig.decorators, ...rawConfig.oas2Decorators },
|
|
88
|
+
[OasVersion.Version3_0]: { ...rawConfig.decorators, ...rawConfig.oas3_0Decorators },
|
|
89
|
+
[OasVersion.Version3_1]: { ...rawConfig.decorators, ...rawConfig.oas3_1Decorators },
|
|
215
90
|
};
|
|
216
91
|
|
|
92
|
+
this.extendPaths = rawConfig.extendPaths || [];
|
|
93
|
+
this.pluginPaths = rawConfig.pluginPaths || [];
|
|
94
|
+
|
|
217
95
|
const dir = this.configFile
|
|
218
96
|
? path.dirname(this.configFile)
|
|
219
97
|
: (typeof process !== 'undefined' && process.cwd()) || '';
|
|
@@ -230,7 +108,7 @@ export class LintConfig {
|
|
|
230
108
|
|
|
231
109
|
// resolve ignore paths
|
|
232
110
|
for (const fileName of Object.keys(this.ignore)) {
|
|
233
|
-
this.ignore[path.resolve(dirname(ignoreFile), fileName)] = this.ignore[fileName];
|
|
111
|
+
this.ignore[path.resolve(path.dirname(ignoreFile), fileName)] = this.ignore[fileName];
|
|
234
112
|
for (const ruleId of Object.keys(this.ignore[fileName])) {
|
|
235
113
|
this.ignore[fileName][ruleId] = new Set(this.ignore[fileName][ruleId]);
|
|
236
114
|
}
|
|
@@ -414,7 +292,7 @@ export class LintConfig {
|
|
|
414
292
|
}
|
|
415
293
|
|
|
416
294
|
export class Config {
|
|
417
|
-
apis: Record<string,
|
|
295
|
+
apis: Record<string, ResolvedApi>;
|
|
418
296
|
lint: LintConfig;
|
|
419
297
|
resolve: ResolveConfig;
|
|
420
298
|
licenseKey?: string;
|
|
@@ -422,299 +300,13 @@ export class Config {
|
|
|
422
300
|
'features.openapi': Record<string, any>;
|
|
423
301
|
'features.mockServer'?: Record<string, any>;
|
|
424
302
|
organization?: string;
|
|
425
|
-
constructor(public rawConfig:
|
|
303
|
+
constructor(public rawConfig: ResolvedConfig, public configFile?: string) {
|
|
426
304
|
this.apis = rawConfig.apis || {};
|
|
427
305
|
this.lint = new LintConfig(rawConfig.lint || {}, configFile);
|
|
428
306
|
this['features.openapi'] = rawConfig['features.openapi'] || {};
|
|
429
307
|
this['features.mockServer'] = rawConfig['features.mockServer'] || {};
|
|
430
|
-
this.resolve =
|
|
431
|
-
http: {
|
|
432
|
-
headers: rawConfig?.resolve?.http?.headers ?? [],
|
|
433
|
-
customFetch: undefined,
|
|
434
|
-
},
|
|
435
|
-
};
|
|
308
|
+
this.resolve = getResolveConfig(rawConfig?.resolve);
|
|
436
309
|
this.region = rawConfig.region;
|
|
437
310
|
this.organization = rawConfig.organization;
|
|
438
311
|
}
|
|
439
312
|
}
|
|
440
|
-
|
|
441
|
-
function resolvePresets(presets: string[], plugins: Plugin[]) {
|
|
442
|
-
return presets.map((presetName) => {
|
|
443
|
-
const { pluginId, configName } = parsePresetName(presetName);
|
|
444
|
-
const plugin = plugins.find((p) => p.id === pluginId);
|
|
445
|
-
if (!plugin) {
|
|
446
|
-
throw new Error(`Invalid config ${red(presetName)}: plugin ${pluginId} is not included.`);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
const preset = plugin.configs?.[configName]!;
|
|
450
|
-
if (!preset) {
|
|
451
|
-
throw new Error(
|
|
452
|
-
pluginId
|
|
453
|
-
? `Invalid config ${red(
|
|
454
|
-
presetName,
|
|
455
|
-
)}: plugin ${pluginId} doesn't export config with name ${configName}.`
|
|
456
|
-
: `Invalid config ${red(presetName)}: there is no such built-in config.`,
|
|
457
|
-
);
|
|
458
|
-
}
|
|
459
|
-
return preset;
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
function parsePresetName(presetName: string): { pluginId: string; configName: string } {
|
|
464
|
-
if (presetName.indexOf('/') > -1) {
|
|
465
|
-
const [pluginId, configName] = presetName.split('/');
|
|
466
|
-
return { pluginId, configName };
|
|
467
|
-
} else {
|
|
468
|
-
return { pluginId: '', configName: presetName };
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
function resolvePlugins(plugins: (string | Plugin)[] | null, configPath: string = ''): Plugin[] {
|
|
473
|
-
if (!plugins) return [];
|
|
474
|
-
|
|
475
|
-
// @ts-ignore
|
|
476
|
-
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require;
|
|
477
|
-
|
|
478
|
-
const seenPluginIds = new Map<string, string>();
|
|
479
|
-
|
|
480
|
-
return plugins
|
|
481
|
-
.map((p) => {
|
|
482
|
-
// TODO: resolve npm packages similar to eslint
|
|
483
|
-
const pluginModule =
|
|
484
|
-
typeof p === 'string'
|
|
485
|
-
? (requireFunc(path.resolve(path.dirname(configPath), p)) as Plugin)
|
|
486
|
-
: p;
|
|
487
|
-
|
|
488
|
-
const id = pluginModule.id;
|
|
489
|
-
if (typeof id !== 'string') {
|
|
490
|
-
throw new Error(red(`Plugin must define \`id\` property in ${blue(p.toString())}.`));
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
if (seenPluginIds.has(id)) {
|
|
494
|
-
const pluginPath = seenPluginIds.get(id)!;
|
|
495
|
-
throw new Error(
|
|
496
|
-
red(
|
|
497
|
-
`Plugin "id" must be unique. Plugin ${blue(p.toString())} uses id "${blue(
|
|
498
|
-
id,
|
|
499
|
-
)}" already seen in ${blue(pluginPath)}`,
|
|
500
|
-
),
|
|
501
|
-
);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
seenPluginIds.set(id, p.toString());
|
|
505
|
-
|
|
506
|
-
const plugin: Plugin = {
|
|
507
|
-
id,
|
|
508
|
-
...(pluginModule.configs ? { configs: pluginModule.configs } : {}),
|
|
509
|
-
...(pluginModule.typeExtension ? { typeExtension: pluginModule.typeExtension } : {}),
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
if (pluginModule.rules) {
|
|
513
|
-
if (!pluginModule.rules.oas3 && !pluginModule.rules.oas2) {
|
|
514
|
-
throw new Error(`Plugin rules must have \`oas3\` or \`oas2\` rules "${p}.`);
|
|
515
|
-
}
|
|
516
|
-
plugin.rules = {};
|
|
517
|
-
if (pluginModule.rules.oas3) {
|
|
518
|
-
plugin.rules.oas3 = prefixRules(pluginModule.rules.oas3, id);
|
|
519
|
-
}
|
|
520
|
-
if (pluginModule.rules.oas2) {
|
|
521
|
-
plugin.rules.oas2 = prefixRules(pluginModule.rules.oas2, id);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
if (pluginModule.preprocessors) {
|
|
525
|
-
if (!pluginModule.preprocessors.oas3 && !pluginModule.preprocessors.oas2) {
|
|
526
|
-
throw new Error(
|
|
527
|
-
`Plugin \`preprocessors\` must have \`oas3\` or \`oas2\` preprocessors "${p}.`,
|
|
528
|
-
);
|
|
529
|
-
}
|
|
530
|
-
plugin.preprocessors = {};
|
|
531
|
-
if (pluginModule.preprocessors.oas3) {
|
|
532
|
-
plugin.preprocessors.oas3 = prefixRules(pluginModule.preprocessors.oas3, id);
|
|
533
|
-
}
|
|
534
|
-
if (pluginModule.preprocessors.oas2) {
|
|
535
|
-
plugin.preprocessors.oas2 = prefixRules(pluginModule.preprocessors.oas2, id);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
if (pluginModule.decorators) {
|
|
540
|
-
if (!pluginModule.decorators.oas3 && !pluginModule.decorators.oas2) {
|
|
541
|
-
throw new Error(`Plugin \`decorators\` must have \`oas3\` or \`oas2\` decorators "${p}.`);
|
|
542
|
-
}
|
|
543
|
-
plugin.decorators = {};
|
|
544
|
-
if (pluginModule.decorators.oas3) {
|
|
545
|
-
plugin.decorators.oas3 = prefixRules(pluginModule.decorators.oas3, id);
|
|
546
|
-
}
|
|
547
|
-
if (pluginModule.decorators.oas2) {
|
|
548
|
-
plugin.decorators.oas2 = prefixRules(pluginModule.decorators.oas2, id);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
return plugin;
|
|
553
|
-
})
|
|
554
|
-
.filter(notUndefined);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
function prefixRules<T extends Record<string, any>>(rules: T, prefix: string) {
|
|
558
|
-
if (!prefix) return rules;
|
|
559
|
-
|
|
560
|
-
const res: any = {};
|
|
561
|
-
for (const name of Object.keys(rules)) {
|
|
562
|
-
res[`${prefix}/${name}`] = rules[name];
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
return res;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
type RulesFields =
|
|
569
|
-
| 'rules'
|
|
570
|
-
| 'oas2Rules'
|
|
571
|
-
| 'oas3_0Rules'
|
|
572
|
-
| 'oas3_1Rules'
|
|
573
|
-
| 'preprocessors'
|
|
574
|
-
| 'oas2Preprocessors'
|
|
575
|
-
| 'oas3_0Preprocessors'
|
|
576
|
-
| 'oas3_1Preprocessors'
|
|
577
|
-
| 'decorators'
|
|
578
|
-
| 'oas2Decorators'
|
|
579
|
-
| 'oas3_0Decorators'
|
|
580
|
-
| 'oas3_1Decorators';
|
|
581
|
-
|
|
582
|
-
function mergeExtends(rulesConfList: LintRawConfig[]) {
|
|
583
|
-
const result: Omit<LintRawConfig, RulesFields> & Required<Pick<LintRawConfig, RulesFields>> = {
|
|
584
|
-
rules: {},
|
|
585
|
-
oas2Rules: {},
|
|
586
|
-
oas3_0Rules: {},
|
|
587
|
-
oas3_1Rules: {},
|
|
588
|
-
|
|
589
|
-
preprocessors: {},
|
|
590
|
-
oas2Preprocessors: {},
|
|
591
|
-
oas3_0Preprocessors: {},
|
|
592
|
-
oas3_1Preprocessors: {},
|
|
593
|
-
|
|
594
|
-
decorators: {},
|
|
595
|
-
oas2Decorators: {},
|
|
596
|
-
oas3_0Decorators: {},
|
|
597
|
-
oas3_1Decorators: {},
|
|
598
|
-
};
|
|
599
|
-
|
|
600
|
-
for (let rulesConf of rulesConfList) {
|
|
601
|
-
if (rulesConf.extends) {
|
|
602
|
-
throw new Error(
|
|
603
|
-
`\`extends\` is not supported in shared configs yet: ${JSON.stringify(
|
|
604
|
-
rulesConf,
|
|
605
|
-
null,
|
|
606
|
-
2,
|
|
607
|
-
)}.`,
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
Object.assign(result.rules, rulesConf.rules);
|
|
612
|
-
Object.assign(result.oas2Rules, rulesConf.oas2Rules);
|
|
613
|
-
assignExisting(result.oas2Rules, rulesConf.rules || {});
|
|
614
|
-
Object.assign(result.oas3_0Rules, rulesConf.oas3_0Rules);
|
|
615
|
-
assignExisting(result.oas3_0Rules, rulesConf.rules || {});
|
|
616
|
-
Object.assign(result.oas3_1Rules, rulesConf.oas3_1Rules);
|
|
617
|
-
assignExisting(result.oas3_1Rules, rulesConf.rules || {});
|
|
618
|
-
|
|
619
|
-
Object.assign(result.preprocessors, rulesConf.preprocessors);
|
|
620
|
-
Object.assign(result.oas2Preprocessors, rulesConf.oas2Preprocessors);
|
|
621
|
-
assignExisting(result.oas2Preprocessors, rulesConf.preprocessors || {});
|
|
622
|
-
Object.assign(result.oas3_0Preprocessors, rulesConf.oas3_0Preprocessors);
|
|
623
|
-
assignExisting(result.oas3_0Preprocessors, rulesConf.preprocessors || {});
|
|
624
|
-
Object.assign(result.oas3_1Preprocessors, rulesConf.oas3_1Preprocessors);
|
|
625
|
-
assignExisting(result.oas3_1Preprocessors, rulesConf.preprocessors || {});
|
|
626
|
-
|
|
627
|
-
Object.assign(result.decorators, rulesConf.decorators);
|
|
628
|
-
Object.assign(result.oas2Decorators, rulesConf.oas2Decorators);
|
|
629
|
-
assignExisting(result.oas2Decorators, rulesConf.decorators || {});
|
|
630
|
-
Object.assign(result.oas3_0Decorators, rulesConf.oas3_0Decorators);
|
|
631
|
-
assignExisting(result.oas3_0Decorators, rulesConf.decorators || {});
|
|
632
|
-
Object.assign(result.oas3_1Decorators, rulesConf.oas3_1Decorators);
|
|
633
|
-
assignExisting(result.oas3_1Decorators, rulesConf.decorators || {});
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
return result;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
function assignExisting<T>(target: Record<string, T>, obj: Record<string, T>) {
|
|
640
|
-
for (let k of Object.keys(obj)) {
|
|
641
|
-
if (target.hasOwnProperty(k)) {
|
|
642
|
-
target[k] = obj[k];
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
export function getMergedConfig(config: Config, entrypointAlias?: string): Config {
|
|
648
|
-
return entrypointAlias
|
|
649
|
-
? new Config(
|
|
650
|
-
{
|
|
651
|
-
...config.rawConfig,
|
|
652
|
-
lint: getMergedLintConfig(config, entrypointAlias),
|
|
653
|
-
'features.openapi': {
|
|
654
|
-
...config['features.openapi'],
|
|
655
|
-
...config.apis[entrypointAlias]?.['features.openapi'],
|
|
656
|
-
},
|
|
657
|
-
'features.mockServer': {
|
|
658
|
-
...config['features.mockServer'],
|
|
659
|
-
...config.apis[entrypointAlias]?.['features.mockServer'],
|
|
660
|
-
},
|
|
661
|
-
// TODO: merge everything else here
|
|
662
|
-
},
|
|
663
|
-
config.configFile,
|
|
664
|
-
)
|
|
665
|
-
: config;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
export function getMergedLintConfig(config: Config, entrypointAlias?: string) {
|
|
669
|
-
const apiLint = entrypointAlias ? config.apis[entrypointAlias]?.lint : {};
|
|
670
|
-
const mergedLint = {
|
|
671
|
-
...config.rawConfig.lint,
|
|
672
|
-
...apiLint,
|
|
673
|
-
rules: { ...config.rawConfig.lint?.rules, ...apiLint?.rules },
|
|
674
|
-
preprocessors: { ...config.rawConfig.lint?.preprocessors, ...apiLint?.preprocessors },
|
|
675
|
-
decorators: { ...config.rawConfig.lint?.decorators, ...apiLint?.decorators },
|
|
676
|
-
};
|
|
677
|
-
return mergedLint;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
function transformApiDefinitionsToApis(
|
|
681
|
-
apiDefinitions: Record<string, string> = {},
|
|
682
|
-
): Record<string, Api> {
|
|
683
|
-
let apis: Record<string, Api> = {};
|
|
684
|
-
for (const [apiName, apiPath] of Object.entries(apiDefinitions)) {
|
|
685
|
-
apis[apiName] = { root: apiPath };
|
|
686
|
-
}
|
|
687
|
-
return apis;
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
export function transformConfig(rawConfig: DeprecatedRawConfig | RawConfig): RawConfig {
|
|
691
|
-
if ((rawConfig as RawConfig).apis && (rawConfig as DeprecatedRawConfig).apiDefinitions) {
|
|
692
|
-
throw new Error("Do not use 'apiDefinitions' field. Use 'apis' instead.\n");
|
|
693
|
-
}
|
|
694
|
-
if (
|
|
695
|
-
(rawConfig as RawConfig)['features.openapi'] &&
|
|
696
|
-
(rawConfig as DeprecatedRawConfig).referenceDocs
|
|
697
|
-
) {
|
|
698
|
-
throw new Error("Do not use 'referenceDocs' field. Use 'features.openapi' instead.\n");
|
|
699
|
-
}
|
|
700
|
-
const { apiDefinitions, referenceDocs, ...rest } = rawConfig as DeprecatedRawConfig & RawConfig;
|
|
701
|
-
if (apiDefinitions) {
|
|
702
|
-
process.stderr.write(
|
|
703
|
-
`The ${yellow('apiDefinitions')} field is deprecated. Use ${green(
|
|
704
|
-
'apis',
|
|
705
|
-
)} instead. Read more about this change: https://redocly.com/docs/api-registry/guides/migration-guide-config-file/#changed-properties\n`,
|
|
706
|
-
);
|
|
707
|
-
}
|
|
708
|
-
if (referenceDocs) {
|
|
709
|
-
process.stderr.write(
|
|
710
|
-
`The ${yellow('referenceDocs')} field is deprecated. Use ${green(
|
|
711
|
-
'features.openapi',
|
|
712
|
-
)} instead. Read more about this change: https://redocly.com/docs/api-registry/guides/migration-guide-config-file/#changed-properties\n`,
|
|
713
|
-
);
|
|
714
|
-
}
|
|
715
|
-
return {
|
|
716
|
-
'features.openapi': referenceDocs,
|
|
717
|
-
apis: transformApiDefinitionsToApis(apiDefinitions),
|
|
718
|
-
...rest,
|
|
719
|
-
};
|
|
720
|
-
}
|
package/src/config/load.ts
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { RedoclyClient } from '../redocly';
|
|
4
|
-
import { loadYaml } from '../utils';
|
|
5
|
-
import { Config, DOMAINS
|
|
6
|
-
import {
|
|
4
|
+
import { isEmptyObject, loadYaml } from '../utils';
|
|
5
|
+
import { Config, DOMAINS } from './config';
|
|
6
|
+
import { transformConfig } from './utils';
|
|
7
|
+
import { resolveConfig } from './config-resolvers';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
const rawConfig = await getConfig(configPath);
|
|
9
|
+
import type { RawConfig, Region } from './types';
|
|
10
10
|
|
|
11
|
+
export async function loadConfig(
|
|
12
|
+
configPath: string | undefined = findConfig(),
|
|
13
|
+
customExtends?: string[],
|
|
14
|
+
): Promise<Config> {
|
|
15
|
+
const rawConfig = await getConfig(configPath);
|
|
11
16
|
if (customExtends !== undefined) {
|
|
12
17
|
rawConfig.lint = rawConfig.lint || {};
|
|
13
18
|
rawConfig.lint.extends = customExtends;
|
|
19
|
+
} else if (isEmptyObject(rawConfig)) {
|
|
20
|
+
// TODO: check if we can add recommended here. add message here?
|
|
21
|
+
// rawConfig.lint = { extends: ['recommended'], recommendedFallback: true };
|
|
14
22
|
}
|
|
15
23
|
|
|
16
24
|
const redoclyClient = new RedoclyClient();
|
|
@@ -23,40 +31,38 @@ export async function loadConfig(configPath: string | undefined = findConfig(),
|
|
|
23
31
|
|
|
24
32
|
for (const item of tokens) {
|
|
25
33
|
const domain = DOMAINS[item.region as Region];
|
|
26
|
-
rawConfig.resolve.http.headers.push(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
rawConfig.resolve.http.headers.push(
|
|
35
|
+
{
|
|
36
|
+
matches: `https://api.${domain}/registry/**`,
|
|
37
|
+
name: 'Authorization',
|
|
38
|
+
envVariable: undefined,
|
|
39
|
+
value: item.token,
|
|
40
|
+
},
|
|
41
|
+
//support redocly.com domain for future compatibility
|
|
42
|
+
...(item.region === 'us'
|
|
43
|
+
? [
|
|
44
|
+
{
|
|
45
|
+
matches: `https://api.redoc.ly/registry/**`,
|
|
46
|
+
name: 'Authorization',
|
|
47
|
+
envVariable: undefined,
|
|
48
|
+
value: item.token,
|
|
49
|
+
},
|
|
50
|
+
]
|
|
51
|
+
: []),
|
|
52
|
+
);
|
|
39
53
|
}
|
|
40
54
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
...rawConfig,
|
|
44
|
-
lint: {
|
|
45
|
-
...rawConfig?.lint,
|
|
46
|
-
plugins: [...(rawConfig?.lint?.plugins || []), defaultPlugin], // inject default plugin
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
configPath,
|
|
50
|
-
);
|
|
55
|
+
|
|
56
|
+
return resolveConfig(rawConfig, configPath);
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
export const CONFIG_FILE_NAMES = ['redocly.yaml', 'redocly.yml', '.redocly.yaml', '.redocly.yml'];
|
|
54
60
|
|
|
55
61
|
export function findConfig(dir?: string): string | undefined {
|
|
56
62
|
if (!fs.hasOwnProperty('existsSync')) return;
|
|
57
|
-
const existingConfigFiles = CONFIG_FILE_NAMES
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
const existingConfigFiles = CONFIG_FILE_NAMES.map((name) =>
|
|
64
|
+
dir ? path.resolve(dir, name) : name,
|
|
65
|
+
).filter(fs.existsSync);
|
|
60
66
|
if (existingConfigFiles.length > 1) {
|
|
61
67
|
throw new Error(`
|
|
62
68
|
Multiple configuration files are not allowed.
|