@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/minimal.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { PluginLintConfig } from './types';
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
rules: {
|
|
@@ -55,4 +55,4 @@ export default {
|
|
|
55
55
|
'no-undefined-server-variable': 'warn',
|
|
56
56
|
'no-servers-empty-enum': 'error',
|
|
57
57
|
},
|
|
58
|
-
} as
|
|
58
|
+
} as PluginLintConfig;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { PluginLintConfig } from './types';
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
rules: {
|
|
@@ -55,4 +55,4 @@ export default {
|
|
|
55
55
|
'no-undefined-server-variable': 'error',
|
|
56
56
|
'no-servers-empty-enum': 'error',
|
|
57
57
|
},
|
|
58
|
-
} as
|
|
58
|
+
} as PluginLintConfig;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { ProblemSeverity } from '../walk';
|
|
2
|
+
import type {
|
|
3
|
+
Oas3PreprocessorsSet,
|
|
4
|
+
OasMajorVersion,
|
|
5
|
+
Oas3DecoratorsSet,
|
|
6
|
+
Oas2RuleSet,
|
|
7
|
+
Oas2PreprocessorsSet,
|
|
8
|
+
Oas2DecoratorsSet,
|
|
9
|
+
Oas3RuleSet,
|
|
10
|
+
OasVersion,
|
|
11
|
+
} from '../oas-types';
|
|
12
|
+
import type { NodeType } from '../types';
|
|
13
|
+
|
|
14
|
+
export type RuleConfig =
|
|
15
|
+
| ProblemSeverity
|
|
16
|
+
| 'off'
|
|
17
|
+
| ({
|
|
18
|
+
severity?: ProblemSeverity;
|
|
19
|
+
} & Record<string, any>);
|
|
20
|
+
|
|
21
|
+
export type PreprocessorConfig =
|
|
22
|
+
| ProblemSeverity
|
|
23
|
+
| 'off'
|
|
24
|
+
| 'on'
|
|
25
|
+
| ({
|
|
26
|
+
severity?: ProblemSeverity;
|
|
27
|
+
} & Record<string, any>);
|
|
28
|
+
|
|
29
|
+
export type DecoratorConfig = PreprocessorConfig;
|
|
30
|
+
|
|
31
|
+
export type LintRawConfig = {
|
|
32
|
+
plugins?: (string | Plugin)[];
|
|
33
|
+
extends?: string[];
|
|
34
|
+
doNotResolveExamples?: boolean;
|
|
35
|
+
recommendedFallback?: boolean;
|
|
36
|
+
|
|
37
|
+
rules?: Record<string, RuleConfig>;
|
|
38
|
+
oas2Rules?: Record<string, RuleConfig>;
|
|
39
|
+
oas3_0Rules?: Record<string, RuleConfig>;
|
|
40
|
+
oas3_1Rules?: Record<string, RuleConfig>;
|
|
41
|
+
|
|
42
|
+
preprocessors?: Record<string, PreprocessorConfig>;
|
|
43
|
+
oas2Preprocessors?: Record<string, PreprocessorConfig>;
|
|
44
|
+
oas3_0Preprocessors?: Record<string, PreprocessorConfig>;
|
|
45
|
+
oas3_1Preprocessors?: Record<string, PreprocessorConfig>;
|
|
46
|
+
|
|
47
|
+
decorators?: Record<string, DecoratorConfig>;
|
|
48
|
+
oas2Decorators?: Record<string, DecoratorConfig>;
|
|
49
|
+
oas3_0Decorators?: Record<string, DecoratorConfig>;
|
|
50
|
+
oas3_1Decorators?: Record<string, DecoratorConfig>;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type ResolvedLintConfig = PluginLintConfig & {
|
|
54
|
+
plugins?: Plugin[];
|
|
55
|
+
recommendedFallback?: boolean;
|
|
56
|
+
extends?: void | never;
|
|
57
|
+
extendPaths?: string[];
|
|
58
|
+
pluginPaths?: string[];
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type PreprocessorsConfig = {
|
|
62
|
+
oas3?: Oas3PreprocessorsSet;
|
|
63
|
+
oas2?: Oas2PreprocessorsSet;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type DecoratorsConfig = {
|
|
67
|
+
oas3?: Oas3DecoratorsSet;
|
|
68
|
+
oas2?: Oas2DecoratorsSet;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type TypesExtensionFn = (
|
|
72
|
+
types: Record<string, NodeType>,
|
|
73
|
+
oasVersion: OasVersion,
|
|
74
|
+
) => Record<string, NodeType>;
|
|
75
|
+
|
|
76
|
+
export type TypeExtensionsConfig = Partial<Record<OasMajorVersion, TypesExtensionFn>>;
|
|
77
|
+
|
|
78
|
+
export type CustomRulesConfig = {
|
|
79
|
+
oas3?: Oas3RuleSet;
|
|
80
|
+
oas2?: Oas2RuleSet;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type Plugin = {
|
|
84
|
+
id: string;
|
|
85
|
+
configs?: Record<string, PluginLintConfig>;
|
|
86
|
+
rules?: CustomRulesConfig;
|
|
87
|
+
preprocessors?: PreprocessorsConfig;
|
|
88
|
+
decorators?: DecoratorsConfig;
|
|
89
|
+
typeExtension?: TypeExtensionsConfig;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type PluginLintConfig = Omit<LintRawConfig, 'plugins' | 'extends'>;
|
|
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
|
+
export type Region = 'us' | 'eu';
|
|
122
|
+
|
|
123
|
+
export type AccessTokens = { [region in Region]?: string };
|
|
124
|
+
|
|
125
|
+
export type DeprecatedRawConfig = {
|
|
126
|
+
apiDefinitions?: Record<string, string>;
|
|
127
|
+
lint?: LintRawConfig;
|
|
128
|
+
resolve?: RawResolveConfig;
|
|
129
|
+
region?: Region;
|
|
130
|
+
referenceDocs?: Record<string, any>;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export type Api = {
|
|
134
|
+
root: string;
|
|
135
|
+
lint?: Omit<LintRawConfig, 'plugins'>;
|
|
136
|
+
'features.openapi'?: Record<string, any>;
|
|
137
|
+
'features.mockServer'?: Record<string, any>;
|
|
138
|
+
};
|
|
139
|
+
export type ResolvedApi = Omit<Api, 'lint'> & { lint: Omit<ResolvedLintConfig, 'plugins'>};
|
|
140
|
+
|
|
141
|
+
export type RawConfig = {
|
|
142
|
+
apis?: Record<string, Api>;
|
|
143
|
+
lint?: LintRawConfig;
|
|
144
|
+
resolve?: RawResolveConfig;
|
|
145
|
+
region?: Region;
|
|
146
|
+
'features.openapi'?: Record<string, any>;
|
|
147
|
+
'features.mockServer'?: Record<string, any>;
|
|
148
|
+
organization?: string;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export type ResolvedConfig = Omit<RawConfig, 'lint' | 'apis'> & {
|
|
152
|
+
lint: ResolvedLintConfig;
|
|
153
|
+
apis: Record<string,ResolvedApi>
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export type RulesFields =
|
|
157
|
+
| 'rules'
|
|
158
|
+
| 'oas2Rules'
|
|
159
|
+
| 'oas3_0Rules'
|
|
160
|
+
| 'oas3_1Rules'
|
|
161
|
+
| 'preprocessors'
|
|
162
|
+
| 'oas2Preprocessors'
|
|
163
|
+
| 'oas3_0Preprocessors'
|
|
164
|
+
| 'oas3_1Preprocessors'
|
|
165
|
+
| 'decorators'
|
|
166
|
+
| 'oas2Decorators'
|
|
167
|
+
| 'oas3_0Decorators'
|
|
168
|
+
| 'oas3_1Decorators';
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { green, yellow } from 'colorette';
|
|
2
|
+
import { assignExisting } from '../utils';
|
|
3
|
+
import { Config } from './config';
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
Api,
|
|
7
|
+
DeprecatedRawConfig,
|
|
8
|
+
Plugin,
|
|
9
|
+
RawConfig,
|
|
10
|
+
RawResolveConfig,
|
|
11
|
+
ResolveConfig,
|
|
12
|
+
ResolvedLintConfig,
|
|
13
|
+
RulesFields,
|
|
14
|
+
} from './types';
|
|
15
|
+
|
|
16
|
+
export function parsePresetName(presetName: string): { pluginId: string; configName: string } {
|
|
17
|
+
if (presetName.indexOf('/') > -1) {
|
|
18
|
+
const [pluginId, configName] = presetName.split('/');
|
|
19
|
+
return { pluginId, configName };
|
|
20
|
+
} else {
|
|
21
|
+
return { pluginId: '', configName: presetName };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function transformApiDefinitionsToApis(
|
|
26
|
+
apiDefinitions: Record<string, string> = {},
|
|
27
|
+
): Record<string, Api> {
|
|
28
|
+
let apis: Record<string, Api> = {};
|
|
29
|
+
for (const [apiName, apiPath] of Object.entries(apiDefinitions)) {
|
|
30
|
+
apis[apiName] = { root: apiPath };
|
|
31
|
+
}
|
|
32
|
+
return apis;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function prefixRules<T extends Record<string, any>>(rules: T, prefix: string) {
|
|
36
|
+
if (!prefix) return rules;
|
|
37
|
+
|
|
38
|
+
const res: any = {};
|
|
39
|
+
for (const name of Object.keys(rules)) {
|
|
40
|
+
res[`${prefix}/${name}`] = rules[name];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return res;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function mergeExtends(rulesConfList: ResolvedLintConfig[]) {
|
|
47
|
+
const result: Omit<ResolvedLintConfig, RulesFields> &
|
|
48
|
+
Required<Pick<ResolvedLintConfig, RulesFields>> = {
|
|
49
|
+
rules: {},
|
|
50
|
+
oas2Rules: {},
|
|
51
|
+
oas3_0Rules: {},
|
|
52
|
+
oas3_1Rules: {},
|
|
53
|
+
|
|
54
|
+
preprocessors: {},
|
|
55
|
+
oas2Preprocessors: {},
|
|
56
|
+
oas3_0Preprocessors: {},
|
|
57
|
+
oas3_1Preprocessors: {},
|
|
58
|
+
|
|
59
|
+
decorators: {},
|
|
60
|
+
oas2Decorators: {},
|
|
61
|
+
oas3_0Decorators: {},
|
|
62
|
+
oas3_1Decorators: {},
|
|
63
|
+
|
|
64
|
+
plugins: [],
|
|
65
|
+
pluginPaths: [],
|
|
66
|
+
extendPaths: [],
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
for (let rulesConf of rulesConfList) {
|
|
70
|
+
if (rulesConf.extends) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`\`extends\` is not supported in shared configs yet: ${JSON.stringify(
|
|
73
|
+
rulesConf,
|
|
74
|
+
null,
|
|
75
|
+
2,
|
|
76
|
+
)}.`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
Object.assign(result.rules, rulesConf.rules);
|
|
81
|
+
Object.assign(result.oas2Rules, rulesConf.oas2Rules);
|
|
82
|
+
assignExisting(result.oas2Rules, rulesConf.rules || {});
|
|
83
|
+
Object.assign(result.oas3_0Rules, rulesConf.oas3_0Rules);
|
|
84
|
+
assignExisting(result.oas3_0Rules, rulesConf.rules || {});
|
|
85
|
+
Object.assign(result.oas3_1Rules, rulesConf.oas3_1Rules);
|
|
86
|
+
assignExisting(result.oas3_1Rules, rulesConf.rules || {});
|
|
87
|
+
|
|
88
|
+
Object.assign(result.preprocessors, rulesConf.preprocessors);
|
|
89
|
+
Object.assign(result.oas2Preprocessors, rulesConf.oas2Preprocessors);
|
|
90
|
+
assignExisting(result.oas2Preprocessors, rulesConf.preprocessors || {});
|
|
91
|
+
Object.assign(result.oas3_0Preprocessors, rulesConf.oas3_0Preprocessors);
|
|
92
|
+
assignExisting(result.oas3_0Preprocessors, rulesConf.preprocessors || {});
|
|
93
|
+
Object.assign(result.oas3_1Preprocessors, rulesConf.oas3_1Preprocessors);
|
|
94
|
+
assignExisting(result.oas3_1Preprocessors, rulesConf.preprocessors || {});
|
|
95
|
+
|
|
96
|
+
Object.assign(result.decorators, rulesConf.decorators);
|
|
97
|
+
Object.assign(result.oas2Decorators, rulesConf.oas2Decorators);
|
|
98
|
+
assignExisting(result.oas2Decorators, rulesConf.decorators || {});
|
|
99
|
+
Object.assign(result.oas3_0Decorators, rulesConf.oas3_0Decorators);
|
|
100
|
+
assignExisting(result.oas3_0Decorators, rulesConf.decorators || {});
|
|
101
|
+
Object.assign(result.oas3_1Decorators, rulesConf.oas3_1Decorators);
|
|
102
|
+
assignExisting(result.oas3_1Decorators, rulesConf.decorators || {});
|
|
103
|
+
|
|
104
|
+
result.plugins!.push(...(rulesConf.plugins || []));
|
|
105
|
+
result.pluginPaths!.push(...(rulesConf.pluginPaths || []));
|
|
106
|
+
result.extendPaths!.push(...new Set(rulesConf.extendPaths));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function getMergedConfig(config: Config, entrypointAlias?: string): Config {
|
|
113
|
+
const extendPaths = [
|
|
114
|
+
...Object.values(config.apis).map((api) => api?.lint?.extendPaths),
|
|
115
|
+
config.rawConfig?.lint?.extendPaths,
|
|
116
|
+
]
|
|
117
|
+
.flat()
|
|
118
|
+
.filter(Boolean) as string[];
|
|
119
|
+
|
|
120
|
+
const pluginPaths = [
|
|
121
|
+
...Object.values(config.apis).map((api) => api?.lint?.pluginPaths),
|
|
122
|
+
config.rawConfig?.lint?.pluginPaths,
|
|
123
|
+
]
|
|
124
|
+
.flat()
|
|
125
|
+
.filter(Boolean) as string[];
|
|
126
|
+
|
|
127
|
+
return entrypointAlias
|
|
128
|
+
? new Config(
|
|
129
|
+
{
|
|
130
|
+
...config.rawConfig,
|
|
131
|
+
lint: {
|
|
132
|
+
...(config.apis[entrypointAlias]
|
|
133
|
+
? config.apis[entrypointAlias].lint
|
|
134
|
+
: config.rawConfig.lint),
|
|
135
|
+
extendPaths,
|
|
136
|
+
pluginPaths,
|
|
137
|
+
},
|
|
138
|
+
'features.openapi': {
|
|
139
|
+
...config['features.openapi'],
|
|
140
|
+
...config.apis[entrypointAlias]?.['features.openapi'],
|
|
141
|
+
},
|
|
142
|
+
'features.mockServer': {
|
|
143
|
+
...config['features.mockServer'],
|
|
144
|
+
...config.apis[entrypointAlias]?.['features.mockServer'],
|
|
145
|
+
},
|
|
146
|
+
// TODO: merge everything else here
|
|
147
|
+
},
|
|
148
|
+
config.configFile,
|
|
149
|
+
)
|
|
150
|
+
: config;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function transformConfig(rawConfig: DeprecatedRawConfig | RawConfig): RawConfig {
|
|
154
|
+
if ((rawConfig as RawConfig).apis && (rawConfig as DeprecatedRawConfig).apiDefinitions) {
|
|
155
|
+
throw new Error("Do not use 'apiDefinitions' field. Use 'apis' instead.\n");
|
|
156
|
+
}
|
|
157
|
+
if (
|
|
158
|
+
(rawConfig as RawConfig)['features.openapi'] &&
|
|
159
|
+
(rawConfig as DeprecatedRawConfig).referenceDocs
|
|
160
|
+
) {
|
|
161
|
+
throw new Error("Do not use 'referenceDocs' field. Use 'features.openapi' instead.\n");
|
|
162
|
+
}
|
|
163
|
+
const { apiDefinitions, referenceDocs, ...rest } = rawConfig as DeprecatedRawConfig & RawConfig;
|
|
164
|
+
if (apiDefinitions) {
|
|
165
|
+
process.stderr.write(
|
|
166
|
+
`The ${yellow('apiDefinitions')} field is deprecated. Use ${green(
|
|
167
|
+
'apis',
|
|
168
|
+
)} instead. Read more about this change: https://redocly.com/docs/api-registry/guides/migration-guide-config-file/#changed-properties\n`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
if (referenceDocs) {
|
|
172
|
+
process.stderr.write(
|
|
173
|
+
`The ${yellow('referenceDocs')} field is deprecated. Use ${green(
|
|
174
|
+
'features.openapi',
|
|
175
|
+
)} instead. Read more about this change: https://redocly.com/docs/api-registry/guides/migration-guide-config-file/#changed-properties\n`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
'features.openapi': referenceDocs,
|
|
180
|
+
apis: transformApiDefinitionsToApis(apiDefinitions),
|
|
181
|
+
...rest,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function getResolveConfig(resolve?: RawResolveConfig): ResolveConfig {
|
|
186
|
+
return {
|
|
187
|
+
http: {
|
|
188
|
+
headers: resolve?.http?.headers ?? [],
|
|
189
|
+
customFetch: undefined,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function getUniquePlugins(plugins: Plugin[]): Plugin[] {
|
|
195
|
+
const seen = new Set();
|
|
196
|
+
const results = [];
|
|
197
|
+
for (const p of plugins) {
|
|
198
|
+
if (!seen.has(p.id)) {
|
|
199
|
+
results.push(p);
|
|
200
|
+
seen.add(p.id);
|
|
201
|
+
} else if (p.id) {
|
|
202
|
+
process.stderr.write(
|
|
203
|
+
`Duplicate plugin id "${yellow(p.id)}".\n`,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return results;
|
|
208
|
+
}
|
|
@@ -25,7 +25,7 @@ describe('oas3 remove-x-internal', () => {
|
|
|
25
25
|
const { bundle: res } = await bundleDocument({
|
|
26
26
|
document: testDocument,
|
|
27
27
|
externalRefResolver: new BaseResolver(),
|
|
28
|
-
config: makeConfig({}, { 'remove-x-internal': { internalFlagProperty: 'removeit' } }),
|
|
28
|
+
config: await makeConfig({}, { 'remove-x-internal': { internalFlagProperty: 'removeit' } }),
|
|
29
29
|
});
|
|
30
30
|
expect(res.parsed).toMatchInlineSnapshot(`
|
|
31
31
|
openapi: 3.0.0
|
|
@@ -92,7 +92,7 @@ describe('oas3 remove-x-internal', () => {
|
|
|
92
92
|
const { bundle: res } = await bundleDocument({
|
|
93
93
|
document: testDoc,
|
|
94
94
|
externalRefResolver: new BaseResolver(),
|
|
95
|
-
config: makeConfig({}, { 'remove-x-internal': 'on' }),
|
|
95
|
+
config: await makeConfig({}, { 'remove-x-internal': 'on' }),
|
|
96
96
|
});
|
|
97
97
|
expect(res.parsed).toMatchInlineSnapshot(`
|
|
98
98
|
openapi: 3.1.0
|
|
@@ -165,7 +165,7 @@ describe('oas3 remove-x-internal', () => {
|
|
|
165
165
|
const { bundle: res } = await bundleDocument({
|
|
166
166
|
document: testDoc,
|
|
167
167
|
externalRefResolver: new BaseResolver(),
|
|
168
|
-
config: makeConfig({}, { 'remove-x-internal': 'on' }),
|
|
168
|
+
config: await makeConfig({}, { 'remove-x-internal': 'on' }),
|
|
169
169
|
});
|
|
170
170
|
|
|
171
171
|
expect(res.parsed).toMatchInlineSnapshot(`
|
|
@@ -239,7 +239,7 @@ describe('oas3 remove-x-internal', () => {
|
|
|
239
239
|
const { bundle: res } = await bundleDocument({
|
|
240
240
|
document: testDoc,
|
|
241
241
|
externalRefResolver: new BaseResolver(),
|
|
242
|
-
config: makeConfig({}, { 'remove-x-internal': 'on' }),
|
|
242
|
+
config: await makeConfig({}, { 'remove-x-internal': 'on' }),
|
|
243
243
|
});
|
|
244
244
|
expect(res.parsed).toMatchInlineSnapshot(`
|
|
245
245
|
openapi: 3.0.1
|
|
@@ -302,7 +302,7 @@ describe('oas2 remove-x-internal', () => {
|
|
|
302
302
|
const { bundle: res } = await bundleDocument({
|
|
303
303
|
document: testDoc,
|
|
304
304
|
externalRefResolver: new BaseResolver(),
|
|
305
|
-
config: makeConfig({}, { 'remove-x-internal': 'on' }),
|
|
305
|
+
config: await makeConfig({}, { 'remove-x-internal': 'on' }),
|
|
306
306
|
});
|
|
307
307
|
expect(res.parsed).toMatchInlineSnapshot(`
|
|
308
308
|
swagger: '2.0'
|
package/src/format/format.ts
CHANGED
|
@@ -14,12 +14,13 @@ const coreVersion = require('../../package.json').version;
|
|
|
14
14
|
|
|
15
15
|
import { NormalizedProblem, ProblemSeverity, LineColLocationObject, LocationObject } from '../walk';
|
|
16
16
|
import { getCodeframe, getLineColLocation } from './codeframes';
|
|
17
|
+
import { env } from "../config";
|
|
17
18
|
|
|
18
19
|
export type Totals = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
20
|
+
errors: number;
|
|
21
|
+
warnings: number;
|
|
22
|
+
ignored: number;
|
|
23
|
+
};
|
|
23
24
|
|
|
24
25
|
const ERROR_MESSAGE = {
|
|
25
26
|
INVALID_SEVERITY_LEVEL: 'Invalid severity level; accepted values: error or warn',
|
|
@@ -40,13 +41,18 @@ const SEVERITY_NAMES = {
|
|
|
40
41
|
error: 'Error',
|
|
41
42
|
};
|
|
42
43
|
|
|
44
|
+
const CODECLIMATE_SEVERITY_MAPPING = {
|
|
45
|
+
error: 'critical',
|
|
46
|
+
warn: 'minor',
|
|
47
|
+
};
|
|
48
|
+
|
|
43
49
|
const MAX_SUGGEST = 5;
|
|
44
50
|
|
|
45
51
|
function severityToNumber(severity: ProblemSeverity) {
|
|
46
52
|
return severity === 'error' ? 1 : 2;
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
export type OutputFormat = 'codeframe' | 'stylish' | 'json' | 'checkstyle';
|
|
55
|
+
export type OutputFormat = 'codeframe' | 'stylish' | 'json' | 'checkstyle' | 'codeclimate';
|
|
50
56
|
|
|
51
57
|
export function getTotals(problems: (NormalizedProblem & { ignored?: boolean })[]): Totals {
|
|
52
58
|
let errors = 0;
|
|
@@ -76,7 +82,7 @@ export function formatProblems(
|
|
|
76
82
|
cwd?: string;
|
|
77
83
|
format?: OutputFormat;
|
|
78
84
|
color?: boolean;
|
|
79
|
-
totals: Totals
|
|
85
|
+
totals: Totals;
|
|
80
86
|
version: string;
|
|
81
87
|
},
|
|
82
88
|
) {
|
|
@@ -142,6 +148,9 @@ export function formatProblems(
|
|
|
142
148
|
process.stdout.write(`</checkstyle>\n`);
|
|
143
149
|
break;
|
|
144
150
|
}
|
|
151
|
+
case 'codeclimate':
|
|
152
|
+
outputForCodeClimate();
|
|
153
|
+
break;
|
|
145
154
|
}
|
|
146
155
|
|
|
147
156
|
if (totalProblems - ignoredProblems > maxProblems) {
|
|
@@ -152,6 +161,25 @@ export function formatProblems(
|
|
|
152
161
|
);
|
|
153
162
|
}
|
|
154
163
|
|
|
164
|
+
function outputForCodeClimate() {
|
|
165
|
+
const issues = problems.map((p) => {
|
|
166
|
+
const location = p.location[0]; // TODO: support multiple location
|
|
167
|
+
const lineCol = getLineColLocation(location);
|
|
168
|
+
return {
|
|
169
|
+
description: p.message,
|
|
170
|
+
location: {
|
|
171
|
+
path: path.relative(cwd, location.source.absoluteRef),
|
|
172
|
+
lines: {
|
|
173
|
+
begin: lineCol.start.line,
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
severity: CODECLIMATE_SEVERITY_MAPPING[p.severity],
|
|
177
|
+
fingerprint: `${p.ruleId}${p.location.length > 0 ? '-' + p.location[0].pointer : ''}`,
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
process.stdout.write(JSON.stringify(issues, null, 2));
|
|
181
|
+
}
|
|
182
|
+
|
|
155
183
|
function outputJSON() {
|
|
156
184
|
const resultObject = {
|
|
157
185
|
totals,
|
|
@@ -175,7 +203,7 @@ export function formatProblems(
|
|
|
175
203
|
: undefined,
|
|
176
204
|
};
|
|
177
205
|
|
|
178
|
-
if (
|
|
206
|
+
if (env.FORMAT_JSON_WITH_CODEFRAMES) {
|
|
179
207
|
const location = p.location[0]; // TODO: support multiple locations
|
|
180
208
|
const loc = getLineColLocation(location);
|
|
181
209
|
(problem as any).codeframe = getCodeframe(loc, color);
|
|
@@ -214,6 +242,9 @@ export function formatProblems(
|
|
|
214
242
|
|
|
215
243
|
function formatStylish(problem: OnlyLineColProblem, locationPad: number, ruleIdPad: number) {
|
|
216
244
|
const color = COLORS[problem.severity];
|
|
245
|
+
if (!SEVERITY_NAMES[problem.severity]) {
|
|
246
|
+
return 'Error not found severity. Please check your config file. Allowed values: \`warn,error,off\`'
|
|
247
|
+
}
|
|
217
248
|
const severityName = color(SEVERITY_NAMES[problem.severity].toLowerCase().padEnd(7));
|
|
218
249
|
const { start } = problem.location[0];
|
|
219
250
|
return ` ${`${start.line}:${start.col}`.padEnd(
|
package/src/index.ts
CHANGED
|
@@ -29,9 +29,13 @@ export {
|
|
|
29
29
|
Region,
|
|
30
30
|
getMergedConfig,
|
|
31
31
|
transformConfig,
|
|
32
|
-
|
|
32
|
+
loadConfig,
|
|
33
|
+
getConfig,
|
|
34
|
+
findConfig,
|
|
35
|
+
CONFIG_FILE_NAMES,
|
|
36
|
+
} from './config';
|
|
37
|
+
|
|
33
38
|
|
|
34
|
-
export { loadConfig, getConfig, findConfig, CONFIG_FILE_NAMES } from './config/load';
|
|
35
39
|
export { RedoclyClient, isRedoclyRegistryURL } from './redocly';
|
|
36
40
|
|
|
37
41
|
export {
|
package/src/lint.ts
CHANGED
|
@@ -7,14 +7,13 @@ import { Oas3Types } from './types/oas3';
|
|
|
7
7
|
import { Oas2Types } from './types/oas2';
|
|
8
8
|
import { NodeType } from './types';
|
|
9
9
|
import { ProblemSeverity, WalkContext, walkDocument } from './walk';
|
|
10
|
-
import { LintConfig, Config } from './config
|
|
10
|
+
import { LintConfig, Config, initRules, defaultPlugin, resolvePlugins } from './config';
|
|
11
11
|
import { normalizeTypes } from './types';
|
|
12
|
-
import { initRules } from './config/rules';
|
|
13
12
|
import { releaseAjvInstance } from './rules/ajv';
|
|
14
13
|
import { detectOpenAPI, Oas3RuleSet, OasMajorVersion, OasVersion, openAPIMajor } from './oas-types';
|
|
15
14
|
import { ConfigTypes } from './types/redocly-yaml';
|
|
16
15
|
import { OasSpec } from './rules/common/spec';
|
|
17
|
-
|
|
16
|
+
|
|
18
17
|
|
|
19
18
|
export async function lint(opts: {
|
|
20
19
|
ref: string;
|
|
@@ -104,9 +103,9 @@ export async function lintConfig(opts: {
|
|
|
104
103
|
oasVersion: OasVersion.Version3_0,
|
|
105
104
|
visitorsData: {},
|
|
106
105
|
};
|
|
106
|
+
const plugins = resolvePlugins([defaultPlugin]);
|
|
107
107
|
const config = new LintConfig({
|
|
108
|
-
plugins
|
|
109
|
-
extends: [],
|
|
108
|
+
plugins,
|
|
110
109
|
rules: { spec: 'error' },
|
|
111
110
|
});
|
|
112
111
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { RedoclyClient } from '../index';
|
|
2
2
|
|
|
3
|
+
jest.mock('node-fetch', () => ({
|
|
4
|
+
default: jest.fn(() => ({
|
|
5
|
+
ok: true,
|
|
6
|
+
json: jest.fn().mockResolvedValue({}),
|
|
7
|
+
})),
|
|
8
|
+
}));
|
|
9
|
+
|
|
3
10
|
describe('RedoclyClient', () => {
|
|
4
11
|
const REDOCLY_DOMAIN_US = 'redocly.com';
|
|
5
12
|
const REDOCLY_DOMAIN_EU = 'eu.redocly.com';
|