@redocly/openapi-core 1.0.0-beta.103 → 1.0.0-beta.106
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 +4 -4
- package/__tests__/utils.ts +8 -6
- package/lib/benchmark/benches/recommended-oas3.bench.js +1 -1
- package/lib/benchmark/utils.d.ts +2 -2
- package/lib/benchmark/utils.js +2 -2
- package/lib/bundle.d.ts +2 -2
- package/lib/bundle.js +2 -2
- package/lib/config/all.d.ts +2 -2
- package/lib/config/all.js +1 -1
- package/lib/config/builtIn.d.ts +2 -2
- package/lib/config/builtIn.js +2 -2
- package/lib/config/config-resolvers.d.ts +5 -5
- package/lib/config/config-resolvers.js +39 -36
- package/lib/config/config.d.ts +6 -5
- package/lib/config/config.js +27 -20
- package/lib/config/load.js +6 -7
- package/lib/config/minimal.d.ts +2 -2
- package/lib/config/minimal.js +1 -1
- package/lib/config/recommended.d.ts +2 -2
- package/lib/config/recommended.js +1 -1
- package/lib/config/rules.d.ts +2 -2
- package/lib/config/rules.js +1 -1
- package/lib/config/types.d.ts +23 -19
- package/lib/config/utils.d.ts +5 -5
- package/lib/config/utils.js +43 -26
- package/lib/decorators/common/filters/filter-helper.js +1 -1
- package/lib/decorators/common/remove-x-internal.js +2 -2
- package/lib/format/format.js +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.js +3 -2
- package/lib/js-yaml/index.js +1 -6
- package/lib/lint.d.ts +2 -2
- package/lib/lint.js +16 -6
- package/lib/redocly/registry-api.d.ts +1 -1
- package/lib/redocly/registry-api.js +2 -2
- package/lib/rules/ajv.d.ts +1 -1
- package/lib/rules/ajv.js +1 -1
- package/lib/rules/common/info-license-url.d.ts +1 -1
- package/lib/rules/common/info-license-url.js +5 -10
- package/lib/rules/common/info-license.d.ts +2 -0
- package/lib/rules/common/info-license.js +17 -0
- package/lib/rules/common/no-enum-type-mismatch.js +1 -3
- package/lib/rules/common/operation-operationId.js +1 -1
- package/lib/rules/common/path-not-include-query.js +1 -1
- package/lib/rules/common/paths-kebab-case.js +4 -1
- package/lib/rules/common/spec.js +1 -1
- package/lib/rules/oas2/index.js +4 -4
- package/lib/rules/oas2/remove-unused-components.js +3 -3
- package/lib/rules/oas3/index.js +4 -4
- package/lib/rules/oas3/no-empty-servers.js +1 -1
- package/lib/rules/oas3/remove-unused-components.js +2 -2
- package/lib/rules/other/stats.js +43 -14
- package/lib/rules/utils.d.ts +1 -1
- package/lib/rules/utils.js +4 -1
- package/lib/types/index.d.ts +2 -2
- package/lib/types/redocly-yaml.js +9 -7
- package/lib/utils.d.ts +3 -2
- package/lib/utils.js +11 -2
- package/lib/walk.d.ts +2 -14
- package/lib/walk.js +19 -19
- package/package.json +3 -2
- package/src/__tests__/__snapshots__/bundle.test.ts.snap +141 -0
- package/src/__tests__/bundle.test.ts +68 -34
- package/src/__tests__/codeframes.test.ts +13 -14
- package/src/__tests__/fixtures/.redocly.lint-ignore.yaml +5 -0
- package/src/__tests__/js-yaml.test.ts +6 -4
- package/src/__tests__/lint.test.ts +127 -12
- package/src/__tests__/login.test.ts +2 -2
- package/src/__tests__/normalizeVisitors.test.ts +4 -4
- package/src/__tests__/ref-utils.test.ts +13 -13
- package/src/__tests__/resolve-http.test.ts +1 -1
- package/src/__tests__/resolve.test.ts +14 -11
- package/src/__tests__/utils.test.ts +42 -1
- package/src/__tests__/walk.test.ts +48 -56
- package/src/benchmark/benches/lint-with-many-rules.bench.ts +1 -1
- package/src/benchmark/benches/lint-with-nested-rule.bench.ts +1 -1
- package/src/benchmark/benches/lint-with-no-rules.bench.ts +1 -1
- package/src/benchmark/benches/lint-with-top-level-rule-report.bench.ts +1 -1
- package/src/benchmark/benches/lint-with-top-level-rule.bench.ts +1 -1
- package/src/benchmark/benches/recommended-oas3.bench.ts +3 -3
- package/src/benchmark/benches/resolve-with-no-external.bench.ts +1 -1
- package/src/benchmark/benchmark.js +9 -5
- package/src/benchmark/utils.ts +5 -5
- package/src/bundle.ts +18 -17
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +1 -1
- package/src/config/__tests__/config-resolvers.test.ts +123 -121
- package/src/config/__tests__/config.test.ts +76 -76
- package/src/config/__tests__/fixtures/resolve-config/api/plugin.js +4 -2
- package/src/config/__tests__/fixtures/resolve-config/plugin.js +4 -1
- package/src/config/__tests__/load.test.ts +2 -2
- package/src/config/__tests__/resolve-plugins.test.ts +3 -3
- package/src/config/__tests__/utils.test.ts +83 -0
- package/src/config/all.ts +3 -4
- package/src/config/builtIn.ts +5 -5
- package/src/config/config-resolvers.ts +122 -83
- package/src/config/config.ts +36 -32
- package/src/config/load.ts +13 -16
- package/src/config/minimal.ts +3 -3
- package/src/config/recommended.ts +3 -3
- package/src/config/rules.ts +6 -6
- package/src/config/types.ts +28 -19
- package/src/config/utils.ts +70 -50
- package/src/decorators/__tests__/filter-out.test.ts +113 -5
- package/src/decorators/__tests__/remove-x-internal.test.ts +5 -5
- package/src/decorators/common/filters/filter-helper.ts +1 -1
- package/src/decorators/common/info-description-override.ts +1 -1
- package/src/decorators/common/operation-description-override.ts +1 -1
- package/src/decorators/common/remove-x-internal.ts +4 -4
- package/src/decorators/common/tag-description-override.ts +1 -1
- package/src/format/codeframes.ts +4 -4
- package/src/format/format.ts +10 -10
- package/src/index.ts +3 -4
- package/src/js-yaml/index.ts +3 -8
- package/src/lint.ts +22 -18
- package/src/oas-types.ts +1 -6
- package/src/redocly/__tests__/redocly-client.test.ts +25 -19
- package/src/redocly/index.ts +6 -4
- package/src/redocly/registry-api.ts +6 -6
- package/src/ref-utils.ts +2 -2
- package/src/resolve.ts +7 -4
- package/src/rules/__tests__/no-unresolved-refs.test.ts +4 -4
- package/src/rules/__tests__/utils.test.ts +122 -0
- package/src/rules/ajv.ts +7 -8
- 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 +8 -8
- 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 +15 -15
- package/src/rules/common/__tests__/scalar-property-missing-example.test.ts +8 -8
- package/src/rules/common/__tests__/spec.test.ts +2 -2
- 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/__tests__/asserts.test.ts +513 -130
- package/src/rules/common/assertions/index.ts +6 -6
- package/src/rules/common/info-license-url.ts +4 -9
- package/src/rules/common/info-license.ts +15 -0
- package/src/rules/common/no-ambiguous-paths.ts +1 -1
- package/src/rules/common/no-enum-type-mismatch.ts +12 -9
- package/src/rules/common/no-invalid-parameter-examples.ts +2 -2
- package/src/rules/common/no-invalid-schema-examples.ts +1 -1
- package/src/rules/common/operation-operationId.ts +1 -1
- package/src/rules/common/operation-parameters-unique.ts +2 -2
- package/src/rules/common/path-not-include-query.ts +1 -1
- package/src/rules/common/path-params-defined.ts +1 -1
- package/src/rules/common/paths-kebab-case.ts +4 -1
- package/src/rules/common/scalar-property-missing-example.ts +1 -1
- package/src/rules/common/spec.ts +10 -7
- package/src/rules/no-unresolved-refs.ts +1 -1
- package/src/rules/oas2/__tests__/boolean-parameter-prefixes.test.ts +3 -3
- package/src/rules/oas2/__tests__/spec/info.test.ts +12 -12
- package/src/rules/oas2/__tests__/spec/operation.test.ts +4 -4
- package/src/rules/oas2/__tests__/spec/paths.test.ts +10 -10
- package/src/rules/oas2/__tests__/spec/referenceableScalars.test.ts +6 -2
- package/src/rules/oas2/__tests__/spec/utils.ts +6 -6
- package/src/rules/oas2/index.ts +3 -3
- package/src/rules/oas2/remove-unused-components.ts +13 -8
- package/src/rules/oas3/__tests__/boolean-parameter-prefixes.test.ts +3 -3
- 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/callbacks.test.ts +1 -1
- package/src/rules/oas3/__tests__/spec/info.test.ts +12 -12
- package/src/rules/oas3/__tests__/spec/operation.test.ts +8 -8
- package/src/rules/oas3/__tests__/spec/paths.test.ts +10 -10
- package/src/rules/oas3/__tests__/spec/referenceableScalars.test.ts +12 -12
- package/src/rules/oas3/__tests__/spec/servers.test.ts +15 -15
- package/src/rules/oas3/__tests__/spec/spec.test.ts +6 -6
- package/src/rules/oas3/__tests__/spec/utils.ts +6 -6
- package/src/rules/oas3/index.ts +3 -3
- package/src/rules/oas3/no-empty-servers.ts +1 -1
- package/src/rules/oas3/no-invalid-media-type-examples.ts +12 -4
- package/src/rules/oas3/no-servers-empty-enum.ts +9 -10
- package/src/rules/oas3/remove-unused-components.ts +18 -7
- package/src/rules/other/stats.ts +46 -17
- package/src/rules/utils.ts +5 -3
- package/src/types/index.ts +5 -5
- package/src/types/redocly-yaml.ts +9 -7
- package/src/typings/common.ts +9 -1
- package/src/typings/openapi.ts +1 -1
- package/src/utils.ts +18 -8
- package/src/visitors.ts +4 -4
- package/src/walk.ts +23 -31
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/rules/common/license-url.d.ts +0 -2
- package/lib/rules/common/license-url.js +0 -12
- package/src/rules/common/license-url.ts +0 -10
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { outdent } from 'outdent';
|
|
2
2
|
import { lintDocument } from '../../../../lint';
|
|
3
3
|
import { parseYamlToDocument, replaceSourceWithRef } from '../../../../../__tests__/utils';
|
|
4
|
-
import {
|
|
4
|
+
import { StyleguideConfig, defaultPlugin, resolvePlugins, resolvePreset } from '../../../../config';
|
|
5
5
|
|
|
6
6
|
import { BaseResolver } from '../../../../resolve';
|
|
7
7
|
|
|
8
8
|
const plugins = resolvePlugins([defaultPlugin]);
|
|
9
9
|
const pressets = resolvePreset('all', plugins);
|
|
10
|
-
const allConfig = new
|
|
10
|
+
const allConfig = new StyleguideConfig({ ...pressets, plugins });
|
|
11
11
|
describe('Oas3 Structural visitor basic', () => {
|
|
12
12
|
it('should report wrong types', async () => {
|
|
13
13
|
const document = parseYamlToDocument(
|
|
@@ -35,7 +35,7 @@ describe('Oas3 Structural visitor basic', () => {
|
|
|
35
35
|
license: invalid
|
|
36
36
|
paths: {}
|
|
37
37
|
`,
|
|
38
|
-
'foobar.yaml'
|
|
38
|
+
'foobar.yaml'
|
|
39
39
|
);
|
|
40
40
|
|
|
41
41
|
const results = await lintDocument({
|
|
@@ -110,7 +110,7 @@ describe('Oas3 Structural visitor basic', () => {
|
|
|
110
110
|
"source": "foobar.yaml",
|
|
111
111
|
},
|
|
112
112
|
],
|
|
113
|
-
"message": "Expected type \`string\` but got \`
|
|
113
|
+
"message": "Expected type \`string\` but got \`integer\`.",
|
|
114
114
|
"ruleId": "spec",
|
|
115
115
|
"severity": "error",
|
|
116
116
|
"suggest": Array [],
|
|
@@ -163,7 +163,7 @@ describe('Oas3 Structural visitor basic', () => {
|
|
|
163
163
|
x-test: vendor
|
|
164
164
|
paths: {}
|
|
165
165
|
`,
|
|
166
|
-
'foobar.yaml'
|
|
166
|
+
'foobar.yaml'
|
|
167
167
|
);
|
|
168
168
|
|
|
169
169
|
const results = await lintDocument({
|
|
@@ -232,7 +232,7 @@ describe('Oas3 Structural visitor basic', () => {
|
|
|
232
232
|
contact:
|
|
233
233
|
name: string
|
|
234
234
|
`,
|
|
235
|
-
'foobar.yaml'
|
|
235
|
+
'foobar.yaml'
|
|
236
236
|
);
|
|
237
237
|
|
|
238
238
|
const results = await lintDocument({
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StyleguideConfig, RuleConfig, resolveStyleguideConfig } from '../../../../config';
|
|
2
2
|
import { parseYamlToDocument } from '../../../../../__tests__/utils';
|
|
3
3
|
import { lintDocument } from '../../../../lint';
|
|
4
4
|
import { BaseResolver } from '../../../../resolve';
|
|
5
5
|
|
|
6
6
|
export async function validateDoc(
|
|
7
7
|
source: string,
|
|
8
|
-
rules: Record<string, RuleConfig> = { spec: 'error' }
|
|
8
|
+
rules: Record<string, RuleConfig> = { spec: 'error' }
|
|
9
9
|
) {
|
|
10
10
|
const document = parseYamlToDocument(source, 'foobar.yaml');
|
|
11
11
|
|
|
12
12
|
const results = await lintDocument({
|
|
13
13
|
externalRefResolver: new BaseResolver(),
|
|
14
14
|
document,
|
|
15
|
-
config: new
|
|
16
|
-
await
|
|
17
|
-
|
|
15
|
+
config: new StyleguideConfig(
|
|
16
|
+
await resolveStyleguideConfig({
|
|
17
|
+
styleguideConfig: {
|
|
18
18
|
plugins: [],
|
|
19
19
|
extends: [],
|
|
20
20
|
rules,
|
|
21
21
|
},
|
|
22
|
-
})
|
|
22
|
+
})
|
|
23
23
|
),
|
|
24
24
|
});
|
|
25
25
|
|
package/src/rules/oas3/index.ts
CHANGED
|
@@ -18,13 +18,13 @@ import { NoServerTrailingSlash } from './no-server-trailing-slash';
|
|
|
18
18
|
import { InfoDescription } from '../common/info-description';
|
|
19
19
|
import { TagDescription } from '../common/tag-description';
|
|
20
20
|
import { InfoContact } from '../common/info-contact';
|
|
21
|
-
import { InfoLicense } from '../common/info-license
|
|
21
|
+
import { InfoLicense } from '../common/info-license';
|
|
22
|
+
import { InfoLicenseUrl } from '../common/info-license-url';
|
|
22
23
|
import { OperationDescription } from '../common/operation-description';
|
|
23
24
|
import { NoUnusedComponents } from './no-unused-components';
|
|
24
25
|
import { PathNotIncludeQuery } from '../common/path-not-include-query';
|
|
25
26
|
import { ParameterDescription } from '../common/parameter-description';
|
|
26
27
|
import { OperationSingularTag } from '../common/operation-singular-tag';
|
|
27
|
-
import { InfoLicenseUrl } from '../common/license-url';
|
|
28
28
|
import { OperationSecurityDefined } from '../common/operation-security-defined';
|
|
29
29
|
import { NoUnresolvedRefs } from '../no-unresolved-refs';
|
|
30
30
|
import { BooleanParameterPrefixes } from './boolean-parameter-prefixes';
|
|
@@ -57,7 +57,7 @@ export const rules = {
|
|
|
57
57
|
'info-license-url': InfoLicenseUrl,
|
|
58
58
|
'operation-2xx-response': Operation2xxResponse,
|
|
59
59
|
'operation-4xx-response': Operation4xxResponse,
|
|
60
|
-
|
|
60
|
+
assertions: Assertions,
|
|
61
61
|
'operation-operationId-unique': OperationIdUnique,
|
|
62
62
|
'operation-parameters-unique': OperationParametersUnique,
|
|
63
63
|
'path-parameters-defined': PathParamsDefined,
|
|
@@ -13,14 +13,22 @@ export const ValidContentExamples: Oas3Rule = (opts) => {
|
|
|
13
13
|
const { location, resolve } = ctx;
|
|
14
14
|
if (!mediaType.schema) return;
|
|
15
15
|
if (mediaType.example) {
|
|
16
|
-
|
|
16
|
+
resolveAndValidateExample(mediaType.example, location.child('example'));
|
|
17
17
|
} else if (mediaType.examples) {
|
|
18
18
|
for (const exampleName of Object.keys(mediaType.examples)) {
|
|
19
|
-
resolveAndValidateExample(
|
|
19
|
+
resolveAndValidateExample(
|
|
20
|
+
mediaType.examples[exampleName],
|
|
21
|
+
location.child(['examples', exampleName, 'value']),
|
|
22
|
+
true
|
|
23
|
+
);
|
|
20
24
|
}
|
|
21
25
|
}
|
|
22
26
|
|
|
23
|
-
function resolveAndValidateExample(
|
|
27
|
+
function resolveAndValidateExample(
|
|
28
|
+
example: Oas3Example | any,
|
|
29
|
+
location: Location,
|
|
30
|
+
isMultiple?: boolean
|
|
31
|
+
) {
|
|
24
32
|
if (isRef(example)) {
|
|
25
33
|
const resolved = resolve<Oas3Example>(example);
|
|
26
34
|
if (!resolved.location) return;
|
|
@@ -32,7 +40,7 @@ export const ValidContentExamples: Oas3Rule = (opts) => {
|
|
|
32
40
|
mediaType.schema!,
|
|
33
41
|
location,
|
|
34
42
|
ctx,
|
|
35
|
-
disallowAdditionalProperties
|
|
43
|
+
disallowAdditionalProperties
|
|
36
44
|
);
|
|
37
45
|
}
|
|
38
46
|
},
|
|
@@ -25,16 +25,17 @@ export const NoEmptyEnumServers: Oas3Rule = () => {
|
|
|
25
25
|
invalidVariables.push(...enumErrors);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
for(const invalidVariable of invalidVariables) {
|
|
29
|
-
if(invalidVariable === enumError.empty) {
|
|
28
|
+
for (const invalidVariable of invalidVariables) {
|
|
29
|
+
if (invalidVariable === enumError.empty) {
|
|
30
30
|
report({
|
|
31
31
|
message: 'Server variable with `enum` must be a non-empty array.',
|
|
32
32
|
location: location.child(['servers']).key(),
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
|
-
if(invalidVariable === enumError.invalidDefaultValue) {
|
|
35
|
+
if (invalidVariable === enumError.invalidDefaultValue) {
|
|
36
36
|
report({
|
|
37
|
-
message:
|
|
37
|
+
message:
|
|
38
|
+
'Server variable define `enum` and `default`. `enum` must include default value',
|
|
38
39
|
location: location.child(['servers']).key(),
|
|
39
40
|
});
|
|
40
41
|
}
|
|
@@ -43,20 +44,18 @@ export const NoEmptyEnumServers: Oas3Rule = () => {
|
|
|
43
44
|
};
|
|
44
45
|
};
|
|
45
46
|
|
|
46
|
-
function checkEnumVariables(server: Oas3Server): enumError[] | undefined{
|
|
47
|
-
if (server.variables && Object.keys(server.variables).length === 0)
|
|
48
|
-
return;
|
|
47
|
+
function checkEnumVariables(server: Oas3Server): enumError[] | undefined {
|
|
48
|
+
if (server.variables && Object.keys(server.variables).length === 0) return;
|
|
49
49
|
|
|
50
50
|
const errors: enumError[] = [];
|
|
51
|
-
for(var variable in server.variables) {
|
|
51
|
+
for (var variable in server.variables) {
|
|
52
52
|
const serverVariable = server.variables[variable];
|
|
53
53
|
if (!serverVariable.enum) continue;
|
|
54
54
|
|
|
55
55
|
if (Array.isArray(serverVariable.enum) && serverVariable.enum?.length === 0)
|
|
56
56
|
errors.push(enumError.empty);
|
|
57
57
|
|
|
58
|
-
if (!serverVariable.default)
|
|
59
|
-
continue;
|
|
58
|
+
if (!serverVariable.default) continue;
|
|
60
59
|
|
|
61
60
|
const defaultValue = server.variables[variable].default;
|
|
62
61
|
if (serverVariable.enum && !serverVariable.enum.includes(defaultValue))
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { Oas3Rule } from '../../visitors';
|
|
2
2
|
import { Location } from '../../ref-utils';
|
|
3
|
-
import { Oas3Components } from '../../typings/openapi'
|
|
3
|
+
import { Oas3Components } from '../../typings/openapi';
|
|
4
4
|
import { isEmptyObject } from '../../utils';
|
|
5
5
|
|
|
6
6
|
export const RemoveUnusedComponents: Oas3Rule = () => {
|
|
7
|
-
let components = new Map<
|
|
7
|
+
let components = new Map<
|
|
8
|
+
string,
|
|
9
|
+
{ used: boolean; componentType?: keyof Oas3Components; name: string }
|
|
10
|
+
>();
|
|
8
11
|
|
|
9
|
-
function registerComponent(
|
|
12
|
+
function registerComponent(
|
|
13
|
+
location: Location,
|
|
14
|
+
componentType: keyof Oas3Components,
|
|
15
|
+
name: string
|
|
16
|
+
): void {
|
|
10
17
|
components.set(location.absolutePointer, {
|
|
11
18
|
used: components.get(location.absolutePointer)?.used || false,
|
|
12
19
|
componentType,
|
|
@@ -18,7 +25,9 @@ export const RemoveUnusedComponents: Oas3Rule = () => {
|
|
|
18
25
|
ref: {
|
|
19
26
|
leave(ref, { type, resolve, key }) {
|
|
20
27
|
if (
|
|
21
|
-
['Schema', 'Header', 'Parameter', 'Response', 'Example', 'RequestBody'].includes(
|
|
28
|
+
['Schema', 'Header', 'Parameter', 'Response', 'Example', 'RequestBody'].includes(
|
|
29
|
+
type.name
|
|
30
|
+
)
|
|
22
31
|
) {
|
|
23
32
|
const resolvedRef = resolve(ref);
|
|
24
33
|
if (!resolvedRef.location) return;
|
|
@@ -27,14 +36,14 @@ export const RemoveUnusedComponents: Oas3Rule = () => {
|
|
|
27
36
|
name: key.toString(),
|
|
28
37
|
});
|
|
29
38
|
}
|
|
30
|
-
}
|
|
39
|
+
},
|
|
31
40
|
},
|
|
32
41
|
DefinitionRoot: {
|
|
33
42
|
leave(root, ctx) {
|
|
34
43
|
const data = ctx.getVisitorData() as { removedCount: number };
|
|
35
44
|
data.removedCount = 0;
|
|
36
45
|
|
|
37
|
-
components.forEach(usageInfo => {
|
|
46
|
+
components.forEach((usageInfo) => {
|
|
38
47
|
const { used, componentType, name } = usageInfo;
|
|
39
48
|
if (!used && componentType) {
|
|
40
49
|
let componentChild = root.components![componentType];
|
|
@@ -45,7 +54,9 @@ export const RemoveUnusedComponents: Oas3Rule = () => {
|
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
56
|
});
|
|
48
|
-
if (isEmptyObject(root.components)) {
|
|
57
|
+
if (isEmptyObject(root.components)) {
|
|
58
|
+
delete root.components;
|
|
59
|
+
}
|
|
49
60
|
},
|
|
50
61
|
},
|
|
51
62
|
NamedSchemas: {
|
package/src/rules/other/stats.ts
CHANGED
|
@@ -4,10 +4,26 @@ import { StatsAccumulator } from '../../typings/common';
|
|
|
4
4
|
|
|
5
5
|
export const Stats = (statsAccumulator: StatsAccumulator) => {
|
|
6
6
|
return {
|
|
7
|
-
ExternalDocs: {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
ExternalDocs: {
|
|
8
|
+
leave() {
|
|
9
|
+
statsAccumulator.externalDocs.total++;
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
ref: {
|
|
13
|
+
enter(ref: OasRef) {
|
|
14
|
+
statsAccumulator.refs.items!.add(ref['$ref']);
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
Tag: {
|
|
18
|
+
leave(tag: Oas3Tag) {
|
|
19
|
+
statsAccumulator.tags.items!.add(tag.name);
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
Link: {
|
|
23
|
+
leave(link: any) {
|
|
24
|
+
statsAccumulator.links.items!.add(link.operationId);
|
|
25
|
+
},
|
|
26
|
+
},
|
|
11
27
|
DefinitionRoot: {
|
|
12
28
|
leave() {
|
|
13
29
|
statsAccumulator.parameters.total = statsAccumulator.parameters.items!.size;
|
|
@@ -19,26 +35,39 @@ export const Stats = (statsAccumulator: StatsAccumulator) => {
|
|
|
19
35
|
WebhooksMap: {
|
|
20
36
|
Operation: {
|
|
21
37
|
leave(operation: any) {
|
|
22
|
-
operation.tags.forEach((tag: string) => {
|
|
23
|
-
|
|
24
|
-
|
|
38
|
+
operation.tags.forEach((tag: string) => {
|
|
39
|
+
statsAccumulator.tags.items!.add(tag);
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
},
|
|
25
43
|
},
|
|
26
44
|
PathMap: {
|
|
27
45
|
PathItem: {
|
|
28
|
-
leave() {
|
|
46
|
+
leave() {
|
|
47
|
+
statsAccumulator.pathItems.total++;
|
|
48
|
+
},
|
|
29
49
|
Operation: {
|
|
30
50
|
leave(operation: any) {
|
|
31
51
|
statsAccumulator.operations.total++;
|
|
32
|
-
operation.tags &&
|
|
33
|
-
|
|
52
|
+
operation.tags &&
|
|
53
|
+
operation.tags.forEach((tag: string) => {
|
|
54
|
+
statsAccumulator.tags.items!.add(tag);
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
Parameter: {
|
|
59
|
+
leave(parameter: Oas2Parameter | Oas3Parameter) {
|
|
60
|
+
statsAccumulator.parameters.items!.add(parameter.name);
|
|
61
|
+
},
|
|
34
62
|
},
|
|
35
|
-
Parameter: { leave(parameter: Oas2Parameter | Oas3Parameter) {
|
|
36
|
-
statsAccumulator.parameters.items!.add(parameter.name)
|
|
37
|
-
}},
|
|
38
63
|
},
|
|
39
64
|
},
|
|
40
65
|
NamedSchemas: {
|
|
41
|
-
Schema: {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
66
|
+
Schema: {
|
|
67
|
+
leave() {
|
|
68
|
+
statsAccumulator.schemas.total++;
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
};
|
package/src/rules/utils.ts
CHANGED
|
@@ -9,6 +9,8 @@ export function oasTypeOf(value: unknown) {
|
|
|
9
9
|
return 'array';
|
|
10
10
|
} else if (value === null) {
|
|
11
11
|
return 'null';
|
|
12
|
+
} else if (Number.isInteger(value)) {
|
|
13
|
+
return 'integer';
|
|
12
14
|
} else {
|
|
13
15
|
return typeof value;
|
|
14
16
|
}
|
|
@@ -23,7 +25,7 @@ export function oasTypeOf(value: unknown) {
|
|
|
23
25
|
*/
|
|
24
26
|
export function matchesJsonSchemaType(value: unknown, type: string, nullable: boolean): boolean {
|
|
25
27
|
if (nullable && value === null) {
|
|
26
|
-
return
|
|
28
|
+
return true;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
switch (type) {
|
|
@@ -89,7 +91,7 @@ export function validateExample(
|
|
|
89
91
|
schema: Referenced<Oas3Schema>,
|
|
90
92
|
dataLoc: Location,
|
|
91
93
|
{ resolve, location, report }: UserContext,
|
|
92
|
-
disallowAdditionalProperties: boolean
|
|
94
|
+
disallowAdditionalProperties: boolean
|
|
93
95
|
) {
|
|
94
96
|
try {
|
|
95
97
|
const { valid, errors } = validateJsonSchema(
|
|
@@ -98,7 +100,7 @@ export function validateExample(
|
|
|
98
100
|
location.child('schema'),
|
|
99
101
|
dataLoc.pointer,
|
|
100
102
|
resolve,
|
|
101
|
-
disallowAdditionalProperties
|
|
103
|
+
disallowAdditionalProperties
|
|
102
104
|
);
|
|
103
105
|
if (!valid) {
|
|
104
106
|
for (let error of errors) {
|
package/src/types/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ export type NodeType = {
|
|
|
24
24
|
items?: string;
|
|
25
25
|
required?: string[] | ((value: any, key: string | number | undefined) => string[]);
|
|
26
26
|
requiredOneOf?: string[];
|
|
27
|
-
allowed?: (
|
|
27
|
+
allowed?: (value: any) => string[] | undefined;
|
|
28
28
|
extensionsPrefix?: string;
|
|
29
29
|
};
|
|
30
30
|
type PropType = string | NodeType | ScalarSchema | undefined | null;
|
|
@@ -37,14 +37,14 @@ export type NormalizedNodeType = {
|
|
|
37
37
|
items?: NormalizedNodeType;
|
|
38
38
|
required?: string[] | ((value: any, key: string | number | undefined) => string[]);
|
|
39
39
|
requiredOneOf?: string[];
|
|
40
|
-
allowed?: (
|
|
40
|
+
allowed?: (value: any) => string[] | undefined;
|
|
41
41
|
extensionsPrefix?: string;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
type NormalizedPropType = NormalizedNodeType | NormalizedScalarSchema | undefined | null;
|
|
45
45
|
type NormalizedResolveTypeFn = (
|
|
46
46
|
value: any,
|
|
47
|
-
key: string
|
|
47
|
+
key: string
|
|
48
48
|
) => NormalizedNodeType | NormalizedScalarSchema | undefined | null;
|
|
49
49
|
|
|
50
50
|
export function listOf(typeName: string) {
|
|
@@ -65,7 +65,7 @@ export function mapOf(typeName: string) {
|
|
|
65
65
|
|
|
66
66
|
export function normalizeTypes(
|
|
67
67
|
types: Record<string, NodeType>,
|
|
68
|
-
options: { doNotResolveExamples?: boolean } = {}
|
|
68
|
+
options: { doNotResolveExamples?: boolean } = {}
|
|
69
69
|
): Record<string, NormalizedNodeType> {
|
|
70
70
|
const normalizedTypes: Record<string, NormalizedNodeType> = {};
|
|
71
71
|
|
|
@@ -132,7 +132,7 @@ export function normalizeTypes(
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
export function isNamedType(
|
|
135
|
-
t: NormalizedNodeType | NormalizedScalarSchema | null | undefined
|
|
135
|
+
t: NormalizedNodeType | NormalizedScalarSchema | null | undefined
|
|
136
136
|
): t is NormalizedNodeType {
|
|
137
137
|
return typeof t?.name === 'string';
|
|
138
138
|
}
|
|
@@ -50,6 +50,7 @@ const builtInRulesList = [
|
|
|
50
50
|
'no-invalid-parameter-examples',
|
|
51
51
|
'response-contains-header',
|
|
52
52
|
'response-contains-property',
|
|
53
|
+
'scalar-property-missing-example',
|
|
53
54
|
];
|
|
54
55
|
const nodeTypesList = [
|
|
55
56
|
'DefinitionRoot',
|
|
@@ -109,7 +110,8 @@ const ConfigRoot: NodeType = {
|
|
|
109
110
|
properties: {},
|
|
110
111
|
additionalProperties: { properties: { type: 'string' } },
|
|
111
112
|
}, // deprecated
|
|
112
|
-
|
|
113
|
+
styleguide: 'RootConfigStyleguide',
|
|
114
|
+
lint: 'RootConfigStyleguide', // deprecated
|
|
113
115
|
'features.openapi': 'ConfigReferenceDocs',
|
|
114
116
|
referenceDocs: 'ConfigReferenceDocs', // deprecated
|
|
115
117
|
'features.mockServer': 'ConfigMockServer',
|
|
@@ -136,7 +138,7 @@ const ConfigApisProperties: NodeType = {
|
|
|
136
138
|
type: 'string',
|
|
137
139
|
},
|
|
138
140
|
},
|
|
139
|
-
|
|
141
|
+
styleguide: 'ConfigStyleguide',
|
|
140
142
|
'features.openapi': 'ConfigReferenceDocs',
|
|
141
143
|
'features.mockServer': 'ConfigMockServer',
|
|
142
144
|
},
|
|
@@ -154,7 +156,7 @@ const ConfigHTTP: NodeType = {
|
|
|
154
156
|
},
|
|
155
157
|
};
|
|
156
158
|
|
|
157
|
-
const
|
|
159
|
+
const ConfigStyleguide: NodeType = {
|
|
158
160
|
properties: {
|
|
159
161
|
extends: {
|
|
160
162
|
type: 'array',
|
|
@@ -178,13 +180,13 @@ const ConfigLint: NodeType = {
|
|
|
178
180
|
},
|
|
179
181
|
};
|
|
180
182
|
|
|
181
|
-
const
|
|
183
|
+
const RootConfigStyleguide: NodeType = {
|
|
182
184
|
properties: {
|
|
183
185
|
plugins: {
|
|
184
186
|
type: 'array',
|
|
185
187
|
items: { type: 'string' },
|
|
186
188
|
},
|
|
187
|
-
...
|
|
189
|
+
...ConfigStyleguide.properties,
|
|
188
190
|
},
|
|
189
191
|
};
|
|
190
192
|
|
|
@@ -876,8 +878,8 @@ export const ConfigTypes: Record<string, NodeType> = {
|
|
|
876
878
|
ConfigRoot,
|
|
877
879
|
ConfigApis,
|
|
878
880
|
ConfigApisProperties,
|
|
879
|
-
|
|
880
|
-
|
|
881
|
+
RootConfigStyleguide,
|
|
882
|
+
ConfigStyleguide,
|
|
881
883
|
ConfigReferenceDocs,
|
|
882
884
|
ConfigMockServer,
|
|
883
885
|
ConfigHTTP,
|
package/src/typings/common.ts
CHANGED
|
@@ -5,5 +5,13 @@ export interface StatsRow {
|
|
|
5
5
|
items?: Set<string>;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
export type StatsName =
|
|
8
|
+
export type StatsName =
|
|
9
|
+
| 'operations'
|
|
10
|
+
| 'refs'
|
|
11
|
+
| 'tags'
|
|
12
|
+
| 'externalDocs'
|
|
13
|
+
| 'pathItems'
|
|
14
|
+
| 'links'
|
|
15
|
+
| 'schemas'
|
|
16
|
+
| 'parameters';
|
|
9
17
|
export type StatsAccumulator = Record<StatsName, StatsRow>;
|
package/src/typings/openapi.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
+
import { extname } from 'path';
|
|
2
3
|
import * as minimatch from 'minimatch';
|
|
3
4
|
import fetch from 'node-fetch';
|
|
4
5
|
import * as pluralize from 'pluralize';
|
|
5
6
|
import { parseYaml } from './js-yaml';
|
|
6
7
|
import { UserContext } from './walk';
|
|
7
|
-
import
|
|
8
|
+
import { HttpResolveConfig } from './config';
|
|
8
9
|
import { env } from './config';
|
|
9
10
|
|
|
10
11
|
export { parseYaml, stringifyYaml } from './js-yaml';
|
|
@@ -77,16 +78,16 @@ function match(url: string, pattern: string) {
|
|
|
77
78
|
|
|
78
79
|
export function pickObjectProps<T extends Record<string, unknown>>(
|
|
79
80
|
object: T,
|
|
80
|
-
keys: Array<string
|
|
81
|
+
keys: Array<string>
|
|
81
82
|
): T {
|
|
82
83
|
return Object.fromEntries(
|
|
83
|
-
keys.filter((key: string) => key in object).map((key: string) => [key, object[key]])
|
|
84
|
+
keys.filter((key: string) => key in object).map((key: string) => [key, object[key]])
|
|
84
85
|
) as T;
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
export function omitObjectProps<T extends Record<string, unknown>>(
|
|
88
89
|
object: T,
|
|
89
|
-
keys: Array<string
|
|
90
|
+
keys: Array<string>
|
|
90
91
|
): T {
|
|
91
92
|
return Object.fromEntries(Object.entries(object).filter(([key]) => !keys.includes(key))) as T;
|
|
92
93
|
}
|
|
@@ -106,7 +107,7 @@ export function splitCamelCaseIntoWords(str: string) {
|
|
|
106
107
|
export function validateMimeType(
|
|
107
108
|
{ type, value }: any,
|
|
108
109
|
{ report, location }: UserContext,
|
|
109
|
-
allowedValues: string[]
|
|
110
|
+
allowedValues: string[]
|
|
110
111
|
) {
|
|
111
112
|
const ruleType = type === 'consumes' ? 'request' : 'response';
|
|
112
113
|
if (!allowedValues)
|
|
@@ -126,7 +127,7 @@ export function validateMimeType(
|
|
|
126
127
|
export function validateMimeTypeOAS3(
|
|
127
128
|
{ type, value }: any,
|
|
128
129
|
{ report, location }: UserContext,
|
|
129
|
-
allowedValues: string[]
|
|
130
|
+
allowedValues: string[]
|
|
130
131
|
) {
|
|
131
132
|
const ruleType = type === 'consumes' ? 'request' : 'response';
|
|
132
133
|
if (!allowedValues)
|
|
@@ -188,9 +189,18 @@ export function assignExisting<T>(target: Record<string, T>, obj: Record<string,
|
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
191
|
|
|
191
|
-
export
|
|
192
|
-
`${code}`.replace(/^(\d)\d\d$/, (_, firstDigit) => `${firstDigit}XX`);
|
|
192
|
+
export function getMatchingStatusCodeRange(code: number | string): string {
|
|
193
|
+
return `${code}`.replace(/^(\d)\d\d$/, (_, firstDigit) => `${firstDigit}XX`);
|
|
194
|
+
}
|
|
193
195
|
|
|
194
196
|
export function isCustomRuleId(id: string) {
|
|
195
197
|
return id.includes('/');
|
|
196
198
|
}
|
|
199
|
+
|
|
200
|
+
export function doesYamlFileExist(filePath: string): boolean {
|
|
201
|
+
return (
|
|
202
|
+
(extname(filePath) === '.yaml' || extname(filePath) === '.yml') &&
|
|
203
|
+
fs.hasOwnProperty('existsSync') &&
|
|
204
|
+
fs.existsSync(filePath)
|
|
205
|
+
);
|
|
206
|
+
}
|
package/src/visitors.ts
CHANGED
|
@@ -53,7 +53,7 @@ export type VisitFunction<T> = (
|
|
|
53
53
|
node: T,
|
|
54
54
|
ctx: UserContext & { ignoreNextVisitorsOnNode: () => void },
|
|
55
55
|
parents?: any,
|
|
56
|
-
context?: any
|
|
56
|
+
context?: any
|
|
57
57
|
) => void;
|
|
58
58
|
|
|
59
59
|
type VisitRefFunction = (node: OasRef, ctx: UserContext, resolved: ResolveResult<any>) => void;
|
|
@@ -264,7 +264,7 @@ export type RuleInstanceConfig = {
|
|
|
264
264
|
|
|
265
265
|
export function normalizeVisitors<T extends BaseVisitor>(
|
|
266
266
|
visitorsConfig: (RuleInstanceConfig & { visitor: NestedVisitObject<any, T> })[],
|
|
267
|
-
types: Record<keyof T, NormalizedNodeType
|
|
267
|
+
types: Record<keyof T, NormalizedNodeType>
|
|
268
268
|
): NormalizedOasVisitors<T> {
|
|
269
269
|
const normalizedVisitors: NormalizedOasVisitors<T> = {} as any;
|
|
270
270
|
|
|
@@ -301,7 +301,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
|
|
|
301
301
|
from: NormalizedNodeType,
|
|
302
302
|
to: NormalizedNodeType,
|
|
303
303
|
parentContext: VisitorLevelContext,
|
|
304
|
-
stack: NormalizedNodeType[] = []
|
|
304
|
+
stack: NormalizedNodeType[] = []
|
|
305
305
|
) {
|
|
306
306
|
if (stack.includes(from)) return;
|
|
307
307
|
|
|
@@ -363,7 +363,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
|
|
|
363
363
|
ruleConf: RuleInstanceConfig,
|
|
364
364
|
visitor: NestedVisitObject<any, T>,
|
|
365
365
|
parentContext: VisitorLevelContext | null,
|
|
366
|
-
depth = 0
|
|
366
|
+
depth = 0
|
|
367
367
|
) {
|
|
368
368
|
const visitorKeys = Object.keys(types) as Array<keyof T | 'any'>;
|
|
369
369
|
|