@redocly/openapi-core 1.0.0-beta.104 → 1.0.0-beta.107
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 +3 -2
- package/lib/config/recommended.d.ts +2 -2
- package/lib/config/recommended.js +3 -2
- 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/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 +6 -6
- 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/no-invalid-parameter-examples.js +3 -3
- package/lib/rules/common/no-invalid-schema-examples.js +3 -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/no-invalid-media-type-examples.js +2 -2
- package/lib/rules/oas3/remove-unused-components.js +2 -2
- package/lib/rules/other/stats.js +43 -14
- package/lib/rules/utils.d.ts +3 -2
- package/lib/rules/utils.js +19 -4
- package/lib/types/index.d.ts +2 -2
- package/lib/types/redocly-yaml.js +8 -7
- package/lib/utils.d.ts +5 -2
- package/lib/utils.js +20 -2
- package/lib/walk.d.ts +2 -1
- package/lib/walk.js +6 -3
- package/package.json +2 -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 +3 -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 +5 -4
- package/src/config/recommended.ts +5 -4
- package/src/config/rules.ts +6 -6
- package/src/config/types.ts +28 -19
- package/src/config/utils.ts +74 -54
- package/src/decorators/__tests__/filter-out.test.ts +8 -4
- 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 +160 -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 +4 -4
- package/src/rules/common/no-invalid-schema-examples.ts +4 -4
- 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 +13 -13
- 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 +14 -6
- 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 +19 -3
- package/src/types/index.ts +5 -5
- package/src/types/redocly-yaml.ts +8 -7
- package/src/typings/common.ts +9 -1
- package/src/typings/openapi.ts +1 -1
- package/src/utils.ts +31 -8
- package/src/visitors.ts +4 -4
- package/src/walk.ts +15 -11
- 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
package/src/lint.ts
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import { BaseResolver, resolveDocument, Document, makeDocumentFromString } from './resolve';
|
|
2
|
-
import {
|
|
3
|
-
normalizeVisitors,
|
|
4
|
-
} from './visitors';
|
|
2
|
+
import { normalizeVisitors } from './visitors';
|
|
5
3
|
import { Oas3_1Types } from './types/oas3_1';
|
|
6
4
|
import { Oas3Types } from './types/oas3';
|
|
7
5
|
import { Oas2Types } from './types/oas2';
|
|
8
6
|
import { NodeType } from './types';
|
|
9
7
|
import { ProblemSeverity, WalkContext, walkDocument } from './walk';
|
|
10
|
-
import {
|
|
8
|
+
import { StyleguideConfig, Config, initRules, defaultPlugin, resolvePlugins } from './config';
|
|
11
9
|
import { normalizeTypes } from './types';
|
|
12
10
|
import { releaseAjvInstance } from './rules/ajv';
|
|
13
11
|
import { detectOpenAPI, Oas3RuleSet, OasMajorVersion, OasVersion, openAPIMajor } from './oas-types';
|
|
14
12
|
import { ConfigTypes } from './types/redocly-yaml';
|
|
15
13
|
import { OasSpec } from './rules/common/spec';
|
|
16
14
|
|
|
17
|
-
|
|
18
15
|
export async function lint(opts: {
|
|
19
16
|
ref: string;
|
|
20
17
|
config: Config;
|
|
@@ -27,7 +24,7 @@ export async function lint(opts: {
|
|
|
27
24
|
document,
|
|
28
25
|
...opts,
|
|
29
26
|
externalRefResolver,
|
|
30
|
-
config: opts.config.
|
|
27
|
+
config: opts.config.styleguide,
|
|
31
28
|
});
|
|
32
29
|
}
|
|
33
30
|
|
|
@@ -44,13 +41,13 @@ export async function lintFromString(opts: {
|
|
|
44
41
|
document,
|
|
45
42
|
...opts,
|
|
46
43
|
externalRefResolver,
|
|
47
|
-
config: opts.config.
|
|
44
|
+
config: opts.config.styleguide,
|
|
48
45
|
});
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
export async function lintDocument(opts: {
|
|
52
49
|
document: Document;
|
|
53
|
-
config:
|
|
50
|
+
config: StyleguideConfig;
|
|
54
51
|
customTypes?: Record<string, NodeType>;
|
|
55
52
|
externalRefResolver: BaseResolver;
|
|
56
53
|
}) {
|
|
@@ -62,10 +59,14 @@ export async function lintDocument(opts: {
|
|
|
62
59
|
const rules = config.getRulesForOasVersion(oasMajorVersion);
|
|
63
60
|
const types = normalizeTypes(
|
|
64
61
|
config.extendTypes(
|
|
65
|
-
customTypes ?? oasMajorVersion === OasMajorVersion.Version3
|
|
66
|
-
|
|
62
|
+
customTypes ?? oasMajorVersion === OasMajorVersion.Version3
|
|
63
|
+
? oasVersion === OasVersion.Version3_1
|
|
64
|
+
? Oas3_1Types
|
|
65
|
+
: Oas3Types
|
|
66
|
+
: Oas2Types,
|
|
67
|
+
oasVersion
|
|
67
68
|
),
|
|
68
|
-
config
|
|
69
|
+
config
|
|
69
70
|
);
|
|
70
71
|
|
|
71
72
|
const ctx: WalkContext = {
|
|
@@ -80,7 +81,7 @@ export async function lintDocument(opts: {
|
|
|
80
81
|
const resolvedRefMap = await resolveDocument({
|
|
81
82
|
rootDocument: document,
|
|
82
83
|
rootType: types.DefinitionRoot,
|
|
83
|
-
externalRefResolver
|
|
84
|
+
externalRefResolver,
|
|
84
85
|
});
|
|
85
86
|
|
|
86
87
|
walkDocument({
|
|
@@ -93,10 +94,7 @@ export async function lintDocument(opts: {
|
|
|
93
94
|
return ctx.problems.map((problem) => config.addProblemToIgnore(problem));
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
export async function lintConfig(opts: {
|
|
97
|
-
document: Document
|
|
98
|
-
severity?: ProblemSeverity
|
|
99
|
-
}) {
|
|
97
|
+
export async function lintConfig(opts: { document: Document; severity?: ProblemSeverity }) {
|
|
100
98
|
const { document, severity } = opts;
|
|
101
99
|
|
|
102
100
|
const ctx: WalkContext = {
|
|
@@ -105,13 +103,19 @@ export async function lintConfig(opts: {
|
|
|
105
103
|
visitorsData: {},
|
|
106
104
|
};
|
|
107
105
|
const plugins = resolvePlugins([defaultPlugin]);
|
|
108
|
-
const config = new
|
|
106
|
+
const config = new StyleguideConfig({
|
|
109
107
|
plugins,
|
|
110
108
|
rules: { spec: 'error' },
|
|
111
109
|
});
|
|
112
110
|
|
|
113
111
|
const types = normalizeTypes(ConfigTypes, config);
|
|
114
|
-
const rules = [
|
|
112
|
+
const rules = [
|
|
113
|
+
{
|
|
114
|
+
severity: severity || 'error',
|
|
115
|
+
ruleId: 'configuration spec',
|
|
116
|
+
visitor: OasSpec({ severity: 'error' }),
|
|
117
|
+
},
|
|
118
|
+
];
|
|
115
119
|
const normalizedVisitors = normalizeVisitors(rules, types);
|
|
116
120
|
|
|
117
121
|
walkDocument({
|
package/src/oas-types.ts
CHANGED
|
@@ -59,55 +59,57 @@ describe('RedoclyClient', () => {
|
|
|
59
59
|
|
|
60
60
|
it('should resolve all tokens', async () => {
|
|
61
61
|
let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation(() => {
|
|
62
|
-
return { token:
|
|
62
|
+
return { token: 'accessToken', us: 'accessToken', eu: 'eu-accessToken' };
|
|
63
63
|
});
|
|
64
64
|
const client = new RedoclyClient();
|
|
65
65
|
const tokens = client.getAllTokens();
|
|
66
66
|
expect(tokens).toStrictEqual([
|
|
67
67
|
{ region: 'us', token: 'accessToken' },
|
|
68
|
-
{ region: 'eu', token: 'eu-accessToken' }
|
|
68
|
+
{ region: 'eu', token: 'eu-accessToken' },
|
|
69
69
|
]);
|
|
70
70
|
spy.mockRestore();
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
it('should resolve valid tokens data', async () => {
|
|
74
74
|
let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation(() => {
|
|
75
|
-
return { us:
|
|
75
|
+
return { us: 'accessToken', eu: 'eu-accessToken' };
|
|
76
76
|
});
|
|
77
77
|
const client = new RedoclyClient();
|
|
78
78
|
const tokens = await client.getValidTokens();
|
|
79
79
|
expect(tokens).toStrictEqual([
|
|
80
80
|
{ region: 'us', token: 'accessToken', valid: true },
|
|
81
|
-
{ region: 'eu', token: 'eu-accessToken', valid: true }
|
|
81
|
+
{ region: 'eu', token: 'eu-accessToken', valid: true },
|
|
82
82
|
]);
|
|
83
83
|
spy.mockRestore();
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
it('should not call setAccessTokens by default', () => {
|
|
87
|
-
let spy = jest
|
|
87
|
+
let spy = jest
|
|
88
|
+
.spyOn(RedoclyClient.prototype, 'readCredentialsFile')
|
|
89
|
+
.mockImplementation(() => ({}));
|
|
88
90
|
jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
|
|
89
91
|
const client = new RedoclyClient();
|
|
90
|
-
expect(client.setAccessTokens).not.toHaveBeenCalled()
|
|
92
|
+
expect(client.setAccessTokens).not.toHaveBeenCalled();
|
|
91
93
|
spy.mockRestore();
|
|
92
94
|
});
|
|
93
95
|
|
|
94
96
|
it('should set correct accessTokens - backward compatibility: default US region', () => {
|
|
95
|
-
let spy = jest
|
|
97
|
+
let spy = jest
|
|
98
|
+
.spyOn(RedoclyClient.prototype, 'readCredentialsFile')
|
|
99
|
+
.mockImplementation(() => ({ token: testToken }));
|
|
96
100
|
jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
|
|
97
101
|
const client = new RedoclyClient();
|
|
98
|
-
expect(client.setAccessTokens).toBeCalledWith(
|
|
99
|
-
expect.objectContaining({ us: testToken })
|
|
100
|
-
);
|
|
102
|
+
expect(client.setAccessTokens).toBeCalledWith(expect.objectContaining({ us: testToken }));
|
|
101
103
|
spy.mockRestore();
|
|
102
104
|
});
|
|
103
105
|
|
|
104
106
|
it('should set correct accessTokens - backward compatibility: EU region', () => {
|
|
105
|
-
let spy = jest
|
|
107
|
+
let spy = jest
|
|
108
|
+
.spyOn(RedoclyClient.prototype, 'readCredentialsFile')
|
|
109
|
+
.mockImplementation(() => ({ token: testToken }));
|
|
106
110
|
jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
|
|
107
111
|
const client = new RedoclyClient('eu');
|
|
108
|
-
expect(client.setAccessTokens).toBeCalledWith(
|
|
109
|
-
expect.objectContaining({ eu: testToken })
|
|
110
|
-
);
|
|
112
|
+
expect(client.setAccessTokens).toBeCalledWith(expect.objectContaining({ eu: testToken }));
|
|
111
113
|
spy.mockRestore();
|
|
112
114
|
});
|
|
113
115
|
|
|
@@ -116,25 +118,29 @@ describe('RedoclyClient', () => {
|
|
|
116
118
|
let spy = jest.spyOn(RedoclyClient.prototype, 'readCredentialsFile').mockImplementation();
|
|
117
119
|
jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
|
|
118
120
|
const client = new RedoclyClient();
|
|
119
|
-
expect(client.setAccessTokens).toHaveBeenNthCalledWith(1, {
|
|
121
|
+
expect(client.setAccessTokens).toHaveBeenNthCalledWith(1, { us: REDOCLY_AUTHORIZATION_TOKEN });
|
|
120
122
|
spy.mockRestore();
|
|
121
123
|
});
|
|
122
124
|
|
|
123
125
|
it('should set correct accessTokens prioritizing REDOCLY_AUTHORIZATION env over token in file', () => {
|
|
124
126
|
process.env.REDOCLY_AUTHORIZATION = REDOCLY_AUTHORIZATION_TOKEN;
|
|
125
|
-
let spy = jest
|
|
127
|
+
let spy = jest
|
|
128
|
+
.spyOn(RedoclyClient.prototype, 'readCredentialsFile')
|
|
129
|
+
.mockImplementation(() => ({ token: testToken }));
|
|
126
130
|
jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
|
|
127
131
|
const client = new RedoclyClient();
|
|
128
|
-
expect(client.setAccessTokens).toHaveBeenNthCalledWith(2, {
|
|
132
|
+
expect(client.setAccessTokens).toHaveBeenNthCalledWith(2, { us: REDOCLY_AUTHORIZATION_TOKEN });
|
|
129
133
|
spy.mockRestore();
|
|
130
134
|
});
|
|
131
135
|
|
|
132
136
|
it('should set correct accessTokens prioritizing REDOCLY_AUTHORIZATION env over EU token', () => {
|
|
133
137
|
process.env.REDOCLY_AUTHORIZATION = REDOCLY_AUTHORIZATION_TOKEN;
|
|
134
|
-
let spy = jest
|
|
138
|
+
let spy = jest
|
|
139
|
+
.spyOn(RedoclyClient.prototype, 'readCredentialsFile')
|
|
140
|
+
.mockImplementation(() => ({ us: testToken }));
|
|
135
141
|
jest.spyOn(RedoclyClient.prototype, 'setAccessTokens').mockImplementation();
|
|
136
142
|
const client = new RedoclyClient('eu');
|
|
137
|
-
expect(client.setAccessTokens).toHaveBeenNthCalledWith(2, {
|
|
143
|
+
expect(client.setAccessTokens).toHaveBeenNthCalledWith(2, { eu: REDOCLY_AUTHORIZATION_TOKEN });
|
|
138
144
|
spy.mockRestore();
|
|
139
145
|
});
|
|
140
146
|
});
|
package/src/redocly/index.ts
CHANGED
|
@@ -28,12 +28,14 @@ export class RedoclyClient {
|
|
|
28
28
|
|
|
29
29
|
loadRegion(region?: Region) {
|
|
30
30
|
if (region && !DOMAINS[region]) {
|
|
31
|
-
throw new Error(
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Invalid argument: region in config file.\nGiven: ${green(region)}, choices: "us", "eu".`
|
|
33
|
+
);
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
if (env.REDOCLY_DOMAIN) {
|
|
35
37
|
return (AVAILABLE_REGIONS.find(
|
|
36
|
-
(region) => DOMAINS[region as Region] === env.REDOCLY_DOMAIN
|
|
38
|
+
(region) => DOMAINS[region as Region] === env.REDOCLY_DOMAIN
|
|
37
39
|
) || DEFAULT_REGION) as Region;
|
|
38
40
|
}
|
|
39
41
|
return region || DEFAULT_REGION;
|
|
@@ -91,7 +93,7 @@ export class RedoclyClient {
|
|
|
91
93
|
const allTokens = this.getAllTokens();
|
|
92
94
|
|
|
93
95
|
const verifiedTokens = await Promise.allSettled(
|
|
94
|
-
allTokens.map(({ token, region }) => this.verifyToken(token, region))
|
|
96
|
+
allTokens.map(({ token, region }) => this.verifyToken(token, region))
|
|
95
97
|
);
|
|
96
98
|
|
|
97
99
|
return allTokens
|
|
@@ -134,7 +136,7 @@ export class RedoclyClient {
|
|
|
134
136
|
async verifyToken(
|
|
135
137
|
accessToken: string,
|
|
136
138
|
region: Region,
|
|
137
|
-
verbose: boolean = false
|
|
139
|
+
verbose: boolean = false
|
|
138
140
|
): Promise<{ viewerId: string; organizations: string[] }> {
|
|
139
141
|
return this.registryApi.authStatus(accessToken, region, verbose);
|
|
140
142
|
}
|
|
@@ -31,7 +31,7 @@ export class RegistryApi {
|
|
|
31
31
|
|
|
32
32
|
const response = await fetch(
|
|
33
33
|
`${this.getBaseUrl(region)}${path}`,
|
|
34
|
-
Object.assign({}, options, { headers })
|
|
34
|
+
Object.assign({}, options, { headers })
|
|
35
35
|
);
|
|
36
36
|
|
|
37
37
|
if (response.status === 401) {
|
|
@@ -49,7 +49,7 @@ export class RegistryApi {
|
|
|
49
49
|
async authStatus(
|
|
50
50
|
accessToken: string,
|
|
51
51
|
region: Region,
|
|
52
|
-
verbose = false
|
|
52
|
+
verbose = false
|
|
53
53
|
): Promise<{ viewerId: string; organizations: string[] }> {
|
|
54
54
|
try {
|
|
55
55
|
const response = await this.request('', { headers: { authorization: accessToken } }, region);
|
|
@@ -86,7 +86,7 @@ export class RegistryApi {
|
|
|
86
86
|
isUpsert,
|
|
87
87
|
}),
|
|
88
88
|
},
|
|
89
|
-
this.region
|
|
89
|
+
this.region
|
|
90
90
|
);
|
|
91
91
|
|
|
92
92
|
if (response.ok) {
|
|
@@ -106,7 +106,7 @@ export class RegistryApi {
|
|
|
106
106
|
isUpsert,
|
|
107
107
|
isPublic,
|
|
108
108
|
batchId,
|
|
109
|
-
batchSize
|
|
109
|
+
batchSize,
|
|
110
110
|
}: RegistryApiTypes.PushApiParams) {
|
|
111
111
|
const response = await this.request(
|
|
112
112
|
`/${organizationId}/${name}/${version}`,
|
|
@@ -123,10 +123,10 @@ export class RegistryApi {
|
|
|
123
123
|
isUpsert,
|
|
124
124
|
isPublic,
|
|
125
125
|
batchId,
|
|
126
|
-
batchSize
|
|
126
|
+
batchSize,
|
|
127
127
|
}),
|
|
128
128
|
},
|
|
129
|
-
this.region
|
|
129
|
+
this.region
|
|
130
130
|
);
|
|
131
131
|
|
|
132
132
|
if (response.ok) {
|
package/src/ref-utils.ts
CHANGED
|
@@ -18,8 +18,8 @@ export class Location {
|
|
|
18
18
|
this.source,
|
|
19
19
|
joinPointer(
|
|
20
20
|
this.pointer,
|
|
21
|
-
(Array.isArray(components) ? components : [components]).map(escapePointer).join('/')
|
|
22
|
-
)
|
|
21
|
+
(Array.isArray(components) ? components : [components]).map(escapePointer).join('/')
|
|
22
|
+
)
|
|
23
23
|
);
|
|
24
24
|
}
|
|
25
25
|
|
package/src/resolve.ts
CHANGED
|
@@ -232,7 +232,7 @@ export async function resolveDocument(opts: {
|
|
|
232
232
|
rootNode: any,
|
|
233
233
|
rootNodeDocument: Document,
|
|
234
234
|
rootNodePointer: string,
|
|
235
|
-
type: any
|
|
235
|
+
type: any
|
|
236
236
|
) {
|
|
237
237
|
const rootNodeDocAbsoluteRef = rootNodeDocument.source.absoluteRef;
|
|
238
238
|
|
|
@@ -295,7 +295,7 @@ export async function resolveDocument(opts: {
|
|
|
295
295
|
resolvedRef.node,
|
|
296
296
|
resolvedRef.document,
|
|
297
297
|
resolvedRef.nodePointer!,
|
|
298
|
-
type
|
|
298
|
+
type
|
|
299
299
|
);
|
|
300
300
|
}
|
|
301
301
|
});
|
|
@@ -306,7 +306,7 @@ export async function resolveDocument(opts: {
|
|
|
306
306
|
async function followRef(
|
|
307
307
|
document: Document,
|
|
308
308
|
ref: OasRef,
|
|
309
|
-
refStack: RefFrame
|
|
309
|
+
refStack: RefFrame
|
|
310
310
|
): Promise<ResolvedRef> {
|
|
311
311
|
if (hasRef(refStack.prev, ref)) {
|
|
312
312
|
throw new Error('Self-referencing circular pointer');
|
|
@@ -316,7 +316,10 @@ export async function resolveDocument(opts: {
|
|
|
316
316
|
let targetDoc: Document;
|
|
317
317
|
try {
|
|
318
318
|
targetDoc = isRemote
|
|
319
|
-
? ((await externalRefResolver.resolveDocument(
|
|
319
|
+
? ((await externalRefResolver.resolveDocument(
|
|
320
|
+
document.source.absoluteRef,
|
|
321
|
+
uri!
|
|
322
|
+
)) as Document)
|
|
320
323
|
: document;
|
|
321
324
|
} catch (error) {
|
|
322
325
|
const resolvedRef = {
|
|
@@ -15,7 +15,7 @@ describe('oas3 boolean-parameter-prefixes', () => {
|
|
|
15
15
|
requestBody:
|
|
16
16
|
$ref: 'invalid.yaml'
|
|
17
17
|
`,
|
|
18
|
-
path.join(__dirname, 'foobar.yaml')
|
|
18
|
+
path.join(__dirname, 'foobar.yaml')
|
|
19
19
|
);
|
|
20
20
|
|
|
21
21
|
const results = await lintDocument({
|
|
@@ -55,7 +55,7 @@ describe('oas3 boolean-parameter-prefixes', () => {
|
|
|
55
55
|
requestBody:
|
|
56
56
|
$ref: 'fixtures/invalid-yaml.yaml'
|
|
57
57
|
`,
|
|
58
|
-
path.join(__dirname, 'foobar.yaml')
|
|
58
|
+
path.join(__dirname, 'foobar.yaml')
|
|
59
59
|
);
|
|
60
60
|
|
|
61
61
|
const results = await lintDocument({
|
|
@@ -112,7 +112,7 @@ describe('oas3 boolean-parameter-prefixes', () => {
|
|
|
112
112
|
requestBody:
|
|
113
113
|
$ref: 'fixtures/ref.yaml'
|
|
114
114
|
`,
|
|
115
|
-
path.join(__dirname, 'foobar.yaml')
|
|
115
|
+
path.join(__dirname, 'foobar.yaml')
|
|
116
116
|
);
|
|
117
117
|
|
|
118
118
|
const results = await lintDocument({
|
|
@@ -136,7 +136,7 @@ describe('oas3 boolean-parameter-prefixes', () => {
|
|
|
136
136
|
requestBody:
|
|
137
137
|
$ref: '#/components/requestBodies/a'
|
|
138
138
|
`,
|
|
139
|
-
path.join(__dirname, 'foobar.yaml')
|
|
139
|
+
path.join(__dirname, 'foobar.yaml')
|
|
140
140
|
);
|
|
141
141
|
|
|
142
142
|
const results = await lintDocument({
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fieldNonEmpty,
|
|
3
|
+
matchesJsonSchemaType,
|
|
4
|
+
missingRequiredField,
|
|
5
|
+
oasTypeOf,
|
|
6
|
+
getAdditionalPropertiesOption,
|
|
7
|
+
} from '../utils';
|
|
8
|
+
|
|
9
|
+
describe('field-non-empty', () => {
|
|
10
|
+
it('should match expected message', () => {
|
|
11
|
+
const message = fieldNonEmpty('Car', 'color');
|
|
12
|
+
expect(message).toBe('Car object `color` must be non-empty string.');
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('matches-json-schema-type', () => {
|
|
17
|
+
it('should report true on a null value with nullable type', () => {
|
|
18
|
+
const results = matchesJsonSchemaType(null, 'string', true);
|
|
19
|
+
expect(results).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should report true on a value and type integer', () => {
|
|
23
|
+
const results = matchesJsonSchemaType(123, 'integer', false);
|
|
24
|
+
expect(results).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should report false when the value is not integer and type is integer', () => {
|
|
28
|
+
const results = matchesJsonSchemaType(3.14, 'integer', false);
|
|
29
|
+
expect(results).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should report true when the value is a number and type is number', () => {
|
|
33
|
+
const results = matchesJsonSchemaType(3.14, 'number', false);
|
|
34
|
+
expect(results).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should report true when the value is an integer and type is number', () => {
|
|
38
|
+
const results = matchesJsonSchemaType(3, 'number', false);
|
|
39
|
+
expect(results).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should report true when the value is true and type is boolean', () => {
|
|
43
|
+
const results = matchesJsonSchemaType(true, 'boolean', false);
|
|
44
|
+
expect(results).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should report true when the value is false and type is boolean', () => {
|
|
48
|
+
const results = matchesJsonSchemaType(false, 'boolean', false);
|
|
49
|
+
expect(results).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should report true when the value is a string and type is boolean', () => {
|
|
53
|
+
const results = matchesJsonSchemaType('test', 'boolean', false);
|
|
54
|
+
expect(results).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should report true on an array value with array type', () => {
|
|
58
|
+
const results = matchesJsonSchemaType(['foo', 'bar'], 'array', false);
|
|
59
|
+
expect(results).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should report false on an array value with object type', () => {
|
|
63
|
+
const results = matchesJsonSchemaType(['foo', 'bar'], 'object', false);
|
|
64
|
+
expect(results).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should report true on an object value with object type', () => {
|
|
68
|
+
const car = { type: 'Fiat', model: '500', color: 'white' };
|
|
69
|
+
const results = matchesJsonSchemaType(car, 'object', true);
|
|
70
|
+
expect(results).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should report false on an object value with array type', () => {
|
|
74
|
+
const car = { type: 'Fiat', model: '500', color: 'white' };
|
|
75
|
+
const results = matchesJsonSchemaType(car, 'array', true);
|
|
76
|
+
expect(results).toBe(false);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('missing-required-field', () => {
|
|
81
|
+
it('should match expected message for missing required field', () => {
|
|
82
|
+
const message = missingRequiredField('Car', 'color');
|
|
83
|
+
expect(message).toBe('Car object should contain `color` field.');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('oas-type-of', () => {
|
|
88
|
+
it('should report the correct oas type for a string', () => {
|
|
89
|
+
const results = oasTypeOf('word');
|
|
90
|
+
expect(results).toBe('string');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should report the correct oas type for an integer', () => {
|
|
94
|
+
const results = oasTypeOf(123);
|
|
95
|
+
expect(results).toBe('integer');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should report the correct oas type for a number', () => {
|
|
99
|
+
const results = oasTypeOf(3.14);
|
|
100
|
+
expect(results).toBe('number');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should report the correct oas type for a null value', () => {
|
|
104
|
+
const results = oasTypeOf(null);
|
|
105
|
+
expect(results).toBe('null');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should report the correct oas type for a true boolean', () => {
|
|
109
|
+
const results = oasTypeOf(true);
|
|
110
|
+
expect(results).toBe('boolean');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should report the correct oas type for a false boolean', () => {
|
|
114
|
+
const results = oasTypeOf(false);
|
|
115
|
+
expect(results).toBe('boolean');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should report the correct oas type for an array', () => {
|
|
119
|
+
const results = oasTypeOf(['foo', 'bar']);
|
|
120
|
+
expect(results).toBe('array');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should report the correct oas type for an object', () => {
|
|
124
|
+
const car = { type: 'Fiat', model: '500', color: 'white' };
|
|
125
|
+
const results = oasTypeOf(car);
|
|
126
|
+
expect(results).toBe('object');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('get-additional-properties-option', () => {
|
|
131
|
+
it('should return actual option', () => {
|
|
132
|
+
const options = {
|
|
133
|
+
allowAdditionalProperties: true,
|
|
134
|
+
};
|
|
135
|
+
expect(getAdditionalPropertiesOption(options)).toBeTruthy();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should reverse option', () => {
|
|
139
|
+
const options = {
|
|
140
|
+
disallowAdditionalProperties: true,
|
|
141
|
+
};
|
|
142
|
+
expect(getAdditionalPropertiesOption(options)).toBeFalsy();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should throw error with message', () => {
|
|
146
|
+
const options = {
|
|
147
|
+
allowAdditionalProperties: true,
|
|
148
|
+
disallowAdditionalProperties: false,
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
getAdditionalPropertiesOption(options);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
expect(error).toBeInstanceOf(Error);
|
|
155
|
+
expect(error.message).toEqual(
|
|
156
|
+
"Do not use 'disallowAdditionalProperties' field. Use 'allowAdditionalProperties' instead.\n"
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
});
|
package/src/rules/ajv.ts
CHANGED
|
@@ -8,7 +8,7 @@ export function releaseAjvInstance() {
|
|
|
8
8
|
ajvInstance = null;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
function getAjv(resolve: ResolveFn,
|
|
11
|
+
function getAjv(resolve: ResolveFn, allowAdditionalProperties: boolean) {
|
|
12
12
|
if (!ajvInstance) {
|
|
13
13
|
ajvInstance = new Ajv({
|
|
14
14
|
schemaId: '$id',
|
|
@@ -20,7 +20,7 @@ function getAjv(resolve: ResolveFn, disallowAdditionalProperties: boolean) {
|
|
|
20
20
|
discriminator: true,
|
|
21
21
|
allowUnionTypes: true,
|
|
22
22
|
validateFormats: false, // TODO: fix it
|
|
23
|
-
defaultAdditionalProperties:
|
|
23
|
+
defaultAdditionalProperties: allowAdditionalProperties,
|
|
24
24
|
loadSchemaSync(base: string, $ref: string) {
|
|
25
25
|
const resolvedRef = resolve({ $ref }, base.split('#')[0]);
|
|
26
26
|
if (!resolvedRef || !resolvedRef.location) return false;
|
|
@@ -36,9 +36,9 @@ function getAjvValidator(
|
|
|
36
36
|
schema: any,
|
|
37
37
|
loc: Location,
|
|
38
38
|
resolve: ResolveFn,
|
|
39
|
-
|
|
39
|
+
allowAdditionalProperties: boolean
|
|
40
40
|
): ValidateFunction | undefined {
|
|
41
|
-
const ajv = getAjv(resolve,
|
|
41
|
+
const ajv = getAjv(resolve, allowAdditionalProperties);
|
|
42
42
|
|
|
43
43
|
if (!ajv.getSchema(loc.absolutePointer)) {
|
|
44
44
|
ajv.addSchema({ $id: loc.absolutePointer, ...schema }, loc.absolutePointer);
|
|
@@ -53,9 +53,9 @@ export function validateJsonSchema(
|
|
|
53
53
|
schemaLoc: Location,
|
|
54
54
|
instancePath: string,
|
|
55
55
|
resolve: ResolveFn,
|
|
56
|
-
|
|
56
|
+
allowAdditionalProperties: boolean
|
|
57
57
|
): { valid: boolean; errors: (ErrorObject & { suggest?: string[] })[] } {
|
|
58
|
-
const validate = getAjvValidator(schema, schemaLoc, resolve,
|
|
58
|
+
const validate = getAjvValidator(schema, schemaLoc, resolve, allowAdditionalProperties);
|
|
59
59
|
if (!validate) return { valid: true, errors: [] }; // unresolved refs are reported
|
|
60
60
|
|
|
61
61
|
const valid = validate(data, {
|
|
@@ -73,8 +73,7 @@ export function validateJsonSchema(
|
|
|
73
73
|
|
|
74
74
|
function beatifyErrorMessage(error: ErrorObject) {
|
|
75
75
|
let message = error.message;
|
|
76
|
-
let suggest =
|
|
77
|
-
error.keyword === 'enum' ? error.params.allowedValues : undefined;
|
|
76
|
+
let suggest = error.keyword === 'enum' ? error.params.allowedValues : undefined;
|
|
78
77
|
if (suggest) {
|
|
79
78
|
message += ` ${suggest.map((e: any) => `"${e}"`).join(', ')}`;
|
|
80
79
|
}
|
|
@@ -11,7 +11,7 @@ describe('Oas3 info-description', () => {
|
|
|
11
11
|
info:
|
|
12
12
|
version: '1.0'
|
|
13
13
|
`,
|
|
14
|
-
'foobar.yaml'
|
|
14
|
+
'foobar.yaml'
|
|
15
15
|
);
|
|
16
16
|
|
|
17
17
|
const results = await lintDocument({
|
|
@@ -49,7 +49,7 @@ describe('Oas3 info-description', () => {
|
|
|
49
49
|
version: '1.0'
|
|
50
50
|
description: ''
|
|
51
51
|
`,
|
|
52
|
-
'foobar.yaml'
|
|
52
|
+
'foobar.yaml'
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
const results = await lintDocument({
|
|
@@ -86,7 +86,7 @@ describe('Oas3 info-description', () => {
|
|
|
86
86
|
info:
|
|
87
87
|
description: test description
|
|
88
88
|
`,
|
|
89
|
-
'foobar.yaml'
|
|
89
|
+
'foobar.yaml'
|
|
90
90
|
);
|
|
91
91
|
|
|
92
92
|
const results = await lintDocument({
|
|
@@ -11,7 +11,7 @@ describe('Oas3 info-license', () => {
|
|
|
11
11
|
info:
|
|
12
12
|
version: '1.0'
|
|
13
13
|
`,
|
|
14
|
-
'foobar.yaml'
|
|
14
|
+
'foobar.yaml'
|
|
15
15
|
);
|
|
16
16
|
|
|
17
17
|
const results = await lintDocument({
|
|
@@ -48,7 +48,7 @@ describe('Oas3 info-license', () => {
|
|
|
48
48
|
name: MIT
|
|
49
49
|
url: google.com
|
|
50
50
|
`,
|
|
51
|
-
'foobar.yaml'
|
|
51
|
+
'foobar.yaml'
|
|
52
52
|
);
|
|
53
53
|
|
|
54
54
|
const results = await lintDocument({
|
|
@@ -12,7 +12,7 @@ describe('Oas3 license-url', () => {
|
|
|
12
12
|
license:
|
|
13
13
|
name: MIT
|
|
14
14
|
`,
|
|
15
|
-
'foobar.yaml'
|
|
15
|
+
'foobar.yaml'
|
|
16
16
|
);
|
|
17
17
|
|
|
18
18
|
const results = await lintDocument({
|
|
@@ -49,7 +49,7 @@ describe('Oas3 license-url', () => {
|
|
|
49
49
|
name: MIT
|
|
50
50
|
url: google.com
|
|
51
51
|
`,
|
|
52
|
-
'foobar.yaml'
|
|
52
|
+
'foobar.yaml'
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
const results = await lintDocument({
|