@redocly/openapi-core 1.0.0-beta.105 → 1.0.0-beta.108
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 +5 -5
- package/lib/benchmark/benches/lint-with-top-level-rule-report.bench.js +0 -1
- 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 +7 -4
- package/lib/config/all.d.ts +2 -2
- package/lib/config/all.js +3 -3
- 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 +70 -49
- package/lib/config/config.d.ts +8 -10
- package/lib/config/config.js +10 -7
- package/lib/config/load.d.ts +7 -0
- package/lib/config/load.js +18 -10
- package/lib/config/minimal.d.ts +2 -2
- package/lib/config/minimal.js +5 -4
- package/lib/config/recommended.d.ts +2 -2
- package/lib/config/recommended.js +5 -4
- package/lib/config/rules.d.ts +3 -3
- 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 +48 -31
- package/lib/decorators/common/registry-dependencies.js +1 -1
- package/lib/decorators/common/remove-x-internal.js +2 -2
- package/lib/env.d.ts +3 -0
- package/lib/env.js +8 -0
- package/lib/format/codeframes.js +16 -10
- package/lib/format/format.js +29 -27
- package/lib/index.d.ts +5 -5
- package/lib/index.js +4 -2
- package/lib/js-yaml/index.js +2 -6
- package/lib/lint.d.ts +2 -2
- package/lib/lint.js +16 -6
- package/lib/logger.d.ts +10 -0
- package/lib/logger.js +31 -0
- package/lib/output.d.ts +3 -0
- package/lib/output.js +9 -0
- package/lib/redocly/index.js +10 -9
- package/lib/redocly/registry-api-types.d.ts +28 -30
- package/lib/redocly/registry-api.d.ts +4 -3
- package/lib/redocly/registry-api.js +9 -4
- package/lib/ref-utils.js +2 -1
- package/lib/resolve.d.ts +1 -1
- package/lib/resolve.js +1 -1
- package/lib/rules/ajv.d.ts +1 -1
- package/lib/rules/ajv.js +7 -7
- package/lib/rules/common/assertions/asserts.js +4 -4
- package/lib/rules/common/assertions/index.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/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/operation-security-defined.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 +3 -3
- package/lib/rules/oas2/index.js +4 -4
- package/lib/rules/oas2/remove-unused-components.js +5 -5
- package/lib/rules/oas3/index.js +6 -6
- 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/no-server-variables-empty-enum.d.ts +2 -0
- package/lib/rules/oas3/{no-servers-empty-enum.js → no-server-variables-empty-enum.js} +4 -4
- package/lib/rules/oas3/no-unused-components.js +1 -1
- package/lib/rules/oas3/remove-unused-components.js +5 -5
- package/lib/rules/other/stats.js +43 -14
- package/lib/rules/utils.d.ts +3 -2
- package/lib/rules/utils.js +20 -5
- package/lib/types/index.d.ts +2 -2
- package/lib/types/redocly-yaml.js +9 -8
- package/lib/utils.d.ts +5 -0
- package/lib/utils.js +22 -5
- package/lib/visitors.d.ts +1 -1
- package/lib/visitors.js +2 -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__/js-yaml.test.ts +6 -4
- package/src/__tests__/lint.test.ts +74 -6
- package/src/__tests__/logger-browser.test.ts +53 -0
- package/src/__tests__/logger.test.ts +47 -0
- package/src/__tests__/login.test.ts +2 -2
- package/src/__tests__/normalizeVisitors.test.ts +4 -4
- package/src/__tests__/output-browser.test.ts +18 -0
- package/src/__tests__/output.test.ts +15 -0
- 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-browser.test.ts +11 -0
- package/src/__tests__/utils.test.ts +7 -0
- 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 -2
- 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 +24 -20
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +7 -5
- package/src/config/__tests__/config-resolvers.test.ts +123 -121
- package/src/config/__tests__/config.test.ts +111 -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 +79 -1
- package/src/config/__tests__/resolve-plugins.test.ts +3 -3
- package/src/config/__tests__/utils.test.ts +83 -0
- package/src/config/all.ts +5 -6
- package/src/config/builtIn.ts +5 -5
- package/src/config/config-resolvers.ts +161 -96
- package/src/config/config.ts +15 -13
- package/src/config/load.ts +34 -11
- package/src/config/minimal.ts +7 -6
- package/src/config/recommended.ts +7 -6
- package/src/config/rules.ts +6 -6
- package/src/config/types.ts +28 -19
- package/src/config/utils.ts +78 -57
- 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/registry-dependencies.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/env.ts +5 -0
- package/src/format/codeframes.ts +18 -12
- package/src/format/format.ts +37 -42
- package/src/index.ts +8 -7
- package/src/js-yaml/index.ts +4 -8
- package/src/lint.ts +22 -18
- package/src/logger.ts +34 -0
- package/src/oas-types.ts +1 -6
- package/src/output.ts +7 -0
- package/src/redocly/__tests__/redocly-client.test.ts +25 -19
- package/src/redocly/index.ts +12 -7
- package/src/redocly/registry-api-types.ts +27 -29
- package/src/redocly/registry-api.ts +22 -12
- package/src/ref-utils.ts +4 -3
- package/src/resolve.ts +11 -8
- 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/asserts.ts +4 -4
- package/src/rules/common/assertions/index.ts +7 -7
- 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/operation-security-defined.ts +1 -1
- 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 +12 -9
- 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 +14 -9
- package/src/rules/oas3/__tests__/boolean-parameter-prefixes.test.ts +3 -3
- package/src/rules/oas3/__tests__/no-empty-enum-servers.com.test.ts +16 -16
- 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 +5 -5
- 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 → no-server-variables-empty-enum.ts} +10 -11
- package/src/rules/oas3/no-unused-components.ts +1 -1
- package/src/rules/oas3/remove-unused-components.ts +21 -10
- package/src/rules/other/stats.ts +46 -17
- package/src/rules/utils.ts +20 -4
- package/src/types/index.ts +5 -5
- package/src/types/redocly-yaml.ts +9 -8
- package/src/typings/common.ts +9 -1
- package/src/typings/openapi.ts +1 -1
- package/src/utils.ts +26 -3
- package/src/visitors.ts +9 -9
- 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/lib/rules/oas3/no-servers-empty-enum.d.ts +0 -2
- package/src/rules/common/license-url.ts +0 -10
package/src/redocly/index.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
3
|
import { homedir } from 'os';
|
|
4
|
-
import { green } from 'colorette';
|
|
5
4
|
import { RegistryApi } from './registry-api';
|
|
6
|
-
import { DEFAULT_REGION, DOMAINS, AVAILABLE_REGIONS
|
|
5
|
+
import { DEFAULT_REGION, DOMAINS, AVAILABLE_REGIONS } from '../config/config';
|
|
6
|
+
import { env } from '../env';
|
|
7
7
|
import { RegionalToken, RegionalTokenWithValidity } from './redocly-client-types';
|
|
8
8
|
import { isNotEmptyObject } from '../utils';
|
|
9
|
+
import { colorize } from '../logger';
|
|
9
10
|
|
|
10
11
|
import type { AccessTokens, Region } from '../config/types';
|
|
11
12
|
|
|
@@ -28,12 +29,16 @@ export class RedoclyClient {
|
|
|
28
29
|
|
|
29
30
|
loadRegion(region?: Region) {
|
|
30
31
|
if (region && !DOMAINS[region]) {
|
|
31
|
-
throw new Error(
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Invalid argument: region in config file.\nGiven: ${colorize.green(
|
|
34
|
+
region
|
|
35
|
+
)}, choices: "us", "eu".`
|
|
36
|
+
);
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
if (env.REDOCLY_DOMAIN) {
|
|
35
40
|
return (AVAILABLE_REGIONS.find(
|
|
36
|
-
(region) => DOMAINS[region as Region] === env.REDOCLY_DOMAIN
|
|
41
|
+
(region) => DOMAINS[region as Region] === env.REDOCLY_DOMAIN
|
|
37
42
|
) || DEFAULT_REGION) as Region;
|
|
38
43
|
}
|
|
39
44
|
return region || DEFAULT_REGION;
|
|
@@ -91,7 +96,7 @@ export class RedoclyClient {
|
|
|
91
96
|
const allTokens = this.getAllTokens();
|
|
92
97
|
|
|
93
98
|
const verifiedTokens = await Promise.allSettled(
|
|
94
|
-
allTokens.map(({ token, region }) => this.verifyToken(token, region))
|
|
99
|
+
allTokens.map(({ token, region }) => this.verifyToken(token, region))
|
|
95
100
|
);
|
|
96
101
|
|
|
97
102
|
return allTokens
|
|
@@ -134,7 +139,7 @@ export class RedoclyClient {
|
|
|
134
139
|
async verifyToken(
|
|
135
140
|
accessToken: string,
|
|
136
141
|
region: Region,
|
|
137
|
-
verbose: boolean = false
|
|
142
|
+
verbose: boolean = false
|
|
138
143
|
): Promise<{ viewerId: string; organizations: string[] }> {
|
|
139
144
|
return this.registryApi.authStatus(accessToken, region, verbose);
|
|
140
145
|
}
|
|
@@ -150,7 +155,7 @@ export class RedoclyClient {
|
|
|
150
155
|
|
|
151
156
|
const credentials = {
|
|
152
157
|
...this.readCredentialsFile(credentialsPath),
|
|
153
|
-
[this.region
|
|
158
|
+
[this.region]: accessToken,
|
|
154
159
|
token: accessToken, // FIXME: backward compatibility, remove on 1.0.0
|
|
155
160
|
};
|
|
156
161
|
this.accessTokens = credentials;
|
|
@@ -1,34 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
1
|
+
interface VersionParams {
|
|
2
|
+
organizationId: string;
|
|
3
|
+
name: string;
|
|
4
|
+
version: string;
|
|
5
|
+
}
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
export interface PrepareFileuploadParams extends VersionParams {
|
|
8
|
+
filesHash: string;
|
|
9
|
+
filename: string;
|
|
10
|
+
isUpsert?: boolean;
|
|
11
|
+
}
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
export interface PushApiParams extends VersionParams {
|
|
14
|
+
rootFilePath: string;
|
|
15
|
+
filePaths: string[];
|
|
16
|
+
branch?: string;
|
|
17
|
+
isUpsert?: boolean;
|
|
18
|
+
isPublic?: boolean;
|
|
19
|
+
batchId?: string;
|
|
20
|
+
batchSize?: number;
|
|
21
|
+
}
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
export interface PrepareFileuploadOKResponse {
|
|
24
|
+
filePath: string;
|
|
25
|
+
signedUploadUrl: string;
|
|
26
|
+
}
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
28
|
+
export interface NotFoundProblemResponse {
|
|
29
|
+
status: 404;
|
|
30
|
+
title: 'Not Found';
|
|
31
|
+
code: 'ORGANIZATION_NOT_FOUND' | 'API_VERSION_NOT_FOUND';
|
|
34
32
|
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import fetch, { RequestInit, HeadersInit } from 'node-fetch';
|
|
2
|
-
import {
|
|
2
|
+
import type {
|
|
3
|
+
NotFoundProblemResponse,
|
|
4
|
+
PrepareFileuploadOKResponse,
|
|
5
|
+
PrepareFileuploadParams,
|
|
6
|
+
PushApiParams,
|
|
7
|
+
} from './registry-api-types';
|
|
8
|
+
import type { AccessTokens, Region } from '../config/types';
|
|
3
9
|
import { DEFAULT_REGION, DOMAINS } from '../config/config';
|
|
4
10
|
import { isNotEmptyObject } from '../utils';
|
|
5
11
|
const version = require('../../package.json').version;
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
export const currentCommand =
|
|
14
|
+
typeof process !== 'undefined' ? process.env?.REDOCLY_CLI_COMMAND || '' : '';
|
|
8
15
|
|
|
9
16
|
export class RegistryApi {
|
|
10
17
|
constructor(private accessTokens: AccessTokens, private region: Region) {}
|
|
@@ -23,7 +30,10 @@ export class RegistryApi {
|
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
private async request(path = '', options: RequestInit = {}, region?: Region) {
|
|
26
|
-
const headers = Object.assign({}, options.headers || {}, {
|
|
33
|
+
const headers = Object.assign({}, options.headers || {}, {
|
|
34
|
+
'x-redocly-cli-version': version,
|
|
35
|
+
'user-agent': `redocly-cli / ${version} ${currentCommand}`,
|
|
36
|
+
});
|
|
27
37
|
|
|
28
38
|
if (!headers.hasOwnProperty('authorization')) {
|
|
29
39
|
throw new Error('Unauthorized');
|
|
@@ -31,7 +41,7 @@ export class RegistryApi {
|
|
|
31
41
|
|
|
32
42
|
const response = await fetch(
|
|
33
43
|
`${this.getBaseUrl(region)}${path}`,
|
|
34
|
-
Object.assign({}, options, { headers })
|
|
44
|
+
Object.assign({}, options, { headers })
|
|
35
45
|
);
|
|
36
46
|
|
|
37
47
|
if (response.status === 401) {
|
|
@@ -39,7 +49,7 @@ export class RegistryApi {
|
|
|
39
49
|
}
|
|
40
50
|
|
|
41
51
|
if (response.status === 404) {
|
|
42
|
-
const body:
|
|
52
|
+
const body: NotFoundProblemResponse = await response.json();
|
|
43
53
|
throw new Error(body.code);
|
|
44
54
|
}
|
|
45
55
|
|
|
@@ -49,7 +59,7 @@ export class RegistryApi {
|
|
|
49
59
|
async authStatus(
|
|
50
60
|
accessToken: string,
|
|
51
61
|
region: Region,
|
|
52
|
-
verbose = false
|
|
62
|
+
verbose = false
|
|
53
63
|
): Promise<{ viewerId: string; organizations: string[] }> {
|
|
54
64
|
try {
|
|
55
65
|
const response = await this.request('', { headers: { authorization: accessToken } }, region);
|
|
@@ -71,7 +81,7 @@ export class RegistryApi {
|
|
|
71
81
|
filesHash,
|
|
72
82
|
filename,
|
|
73
83
|
isUpsert,
|
|
74
|
-
}:
|
|
84
|
+
}: PrepareFileuploadParams): Promise<PrepareFileuploadOKResponse> {
|
|
75
85
|
const response = await this.request(
|
|
76
86
|
`/${organizationId}/${name}/${version}/prepare-file-upload`,
|
|
77
87
|
{
|
|
@@ -86,7 +96,7 @@ export class RegistryApi {
|
|
|
86
96
|
isUpsert,
|
|
87
97
|
}),
|
|
88
98
|
},
|
|
89
|
-
this.region
|
|
99
|
+
this.region
|
|
90
100
|
);
|
|
91
101
|
|
|
92
102
|
if (response.ok) {
|
|
@@ -106,8 +116,8 @@ export class RegistryApi {
|
|
|
106
116
|
isUpsert,
|
|
107
117
|
isPublic,
|
|
108
118
|
batchId,
|
|
109
|
-
batchSize
|
|
110
|
-
}:
|
|
119
|
+
batchSize,
|
|
120
|
+
}: PushApiParams) {
|
|
111
121
|
const response = await this.request(
|
|
112
122
|
`/${organizationId}/${name}/${version}`,
|
|
113
123
|
{
|
|
@@ -123,10 +133,10 @@ export class RegistryApi {
|
|
|
123
133
|
isUpsert,
|
|
124
134
|
isPublic,
|
|
125
135
|
batchId,
|
|
126
|
-
batchSize
|
|
136
|
+
batchSize,
|
|
127
137
|
}),
|
|
128
138
|
},
|
|
129
|
-
this.region
|
|
139
|
+
this.region
|
|
130
140
|
);
|
|
131
141
|
|
|
132
142
|
if (response.ok) {
|
package/src/ref-utils.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Source } from './resolve';
|
|
2
2
|
import { OasRef } from './typings/openapi';
|
|
3
|
+
import { isTruthy } from './utils';
|
|
3
4
|
|
|
4
5
|
export function joinPointer(base: string, key: string | number) {
|
|
5
6
|
if (base === '') base = '#/';
|
|
@@ -18,8 +19,8 @@ export class Location {
|
|
|
18
19
|
this.source,
|
|
19
20
|
joinPointer(
|
|
20
21
|
this.pointer,
|
|
21
|
-
(Array.isArray(components) ? components : [components]).map(escapePointer).join('/')
|
|
22
|
-
)
|
|
22
|
+
(Array.isArray(components) ? components : [components]).map(escapePointer).join('/')
|
|
23
|
+
)
|
|
23
24
|
);
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -45,7 +46,7 @@ export function parseRef(ref: string): { uri: string | null; pointer: string[] }
|
|
|
45
46
|
const [uri, pointer] = ref.split('#/');
|
|
46
47
|
return {
|
|
47
48
|
uri: uri || null,
|
|
48
|
-
pointer: pointer ? pointer.split('/').map(unescapePointer).filter(
|
|
49
|
+
pointer: pointer ? pointer.split('/').map(unescapePointer).filter(isTruthy) : [],
|
|
49
50
|
};
|
|
50
51
|
}
|
|
51
52
|
|
package/src/resolve.ts
CHANGED
|
@@ -91,7 +91,7 @@ export function makeDocumentFromString(sourceString: string, absoluteRef: string
|
|
|
91
91
|
export class BaseResolver {
|
|
92
92
|
cache: Map<string, Promise<Document | ResolveError>> = new Map();
|
|
93
93
|
|
|
94
|
-
constructor(
|
|
94
|
+
constructor(protected config: ResolveConfig = { http: { headers: [] } }) {}
|
|
95
95
|
|
|
96
96
|
getFiles() {
|
|
97
97
|
return new Set(Array.from(this.cache.keys()));
|
|
@@ -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,11 +316,14 @@ 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 = {
|
|
323
|
-
resolved: false as
|
|
326
|
+
resolved: false as const,
|
|
324
327
|
isRemote,
|
|
325
328
|
document: undefined,
|
|
326
329
|
error: error,
|
|
@@ -331,7 +334,7 @@ export async function resolveDocument(opts: {
|
|
|
331
334
|
}
|
|
332
335
|
|
|
333
336
|
let resolvedRef: ResolvedRef = {
|
|
334
|
-
resolved: true as
|
|
337
|
+
resolved: true as const,
|
|
335
338
|
document: targetDoc,
|
|
336
339
|
isRemote,
|
|
337
340
|
node: document.parsed,
|
|
@@ -341,7 +344,7 @@ export async function resolveDocument(opts: {
|
|
|
341
344
|
let target = targetDoc.parsed as any;
|
|
342
345
|
|
|
343
346
|
const segments = pointer;
|
|
344
|
-
for (
|
|
347
|
+
for (const segment of segments) {
|
|
345
348
|
if (typeof target !== 'object') {
|
|
346
349
|
target = undefined;
|
|
347
350
|
break;
|
|
@@ -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
|
-
|
|
77
|
-
error.keyword === 'enum' ? error.params.allowedValues : undefined;
|
|
76
|
+
const 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({
|