@redocly/openapi-core 1.0.0-beta.69 → 1.0.0-beta.70
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/__tests__/lint.test.ts +1 -1
- package/__tests__/login.test.ts +17 -0
- package/lib/config/all.js +2 -0
- package/lib/config/config.d.ts +10 -0
- package/lib/config/config.js +7 -1
- package/lib/config/load.js +17 -8
- package/lib/index.d.ts +2 -2
- package/lib/redocly/index.d.ts +22 -6
- package/lib/redocly/index.js +61 -31
- package/lib/redocly/registry-api.d.ts +8 -5
- package/lib/redocly/registry-api.js +31 -20
- package/lib/rules/common/no-invalid-parameter-examples.d.ts +1 -0
- package/lib/rules/common/no-invalid-parameter-examples.js +25 -0
- package/lib/rules/common/no-invalid-schema-examples.d.ts +1 -0
- package/lib/rules/common/no-invalid-schema-examples.js +23 -0
- package/lib/rules/common/paths-kebab-case.js +1 -1
- package/lib/rules/oas2/index.d.ts +2 -0
- package/lib/rules/oas2/index.js +4 -0
- package/lib/rules/oas3/index.js +4 -0
- package/lib/rules/oas3/no-invalid-media-type-examples.js +5 -26
- package/lib/rules/utils.d.ts +3 -0
- package/lib/rules/utils.js +26 -1
- package/lib/typings/openapi.d.ts +3 -0
- package/lib/utils.d.ts +1 -0
- package/lib/utils.js +5 -1
- package/package.json +2 -2
- package/src/config/__tests__/load.test.ts +35 -0
- package/src/config/all.ts +2 -0
- package/src/config/config.ts +11 -0
- package/src/config/load.ts +20 -9
- package/src/index.ts +2 -8
- package/src/redocly/__tests__/redocly-client.test.ts +114 -0
- package/src/redocly/index.ts +77 -37
- package/src/redocly/registry-api.ts +33 -29
- package/src/rules/common/__tests__/paths-kebab-case.test.ts +23 -0
- package/src/rules/common/no-invalid-parameter-examples.ts +36 -0
- package/src/rules/common/no-invalid-schema-examples.ts +27 -0
- package/src/rules/common/paths-kebab-case.ts +1 -1
- package/src/rules/oas2/index.ts +4 -0
- package/src/rules/oas3/index.ts +4 -0
- package/src/rules/oas3/no-invalid-media-type-examples.ts +16 -36
- package/src/rules/utils.ts +43 -2
- package/src/typings/openapi.ts +4 -0
- package/src/utils.ts +5 -1
- package/tsconfig.tsbuildinfo +1 -1
package/__tests__/lint.test.ts
CHANGED
|
@@ -2,7 +2,7 @@ import outdent from 'outdent';
|
|
|
2
2
|
import { detectOpenAPI } from '../src/oas-types';
|
|
3
3
|
import { parseYamlToDocument } from './utils';
|
|
4
4
|
|
|
5
|
-
describe
|
|
5
|
+
describe('lint', () => {
|
|
6
6
|
it('detect OpenAPI should throw an error when version is not string', () => {
|
|
7
7
|
|
|
8
8
|
const testDocument = parseYamlToDocument(
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RedoclyClient } from '../src/redocly';
|
|
2
|
+
|
|
3
|
+
describe('login', () => {
|
|
4
|
+
it('should call login with setAccessTokens function', async () => {
|
|
5
|
+
const client = new RedoclyClient();
|
|
6
|
+
Object.defineProperty(client, 'registryApi', {
|
|
7
|
+
value: {
|
|
8
|
+
setAccessTokens: jest.fn(),
|
|
9
|
+
authStatus: jest.fn(() => true)
|
|
10
|
+
},
|
|
11
|
+
writable: true,
|
|
12
|
+
configurable: true
|
|
13
|
+
});
|
|
14
|
+
await client.login('token');
|
|
15
|
+
expect(client.registryApi.setAccessTokens).toHaveBeenCalled();
|
|
16
|
+
});
|
|
17
|
+
});
|
package/lib/config/all.js
CHANGED
package/lib/config/config.d.ts
CHANGED
|
@@ -70,11 +70,20 @@ export declare type HttpResolveConfig = {
|
|
|
70
70
|
export declare type ResolveConfig = {
|
|
71
71
|
http: HttpResolveConfig;
|
|
72
72
|
};
|
|
73
|
+
export declare const DEFAULT_REGION = "us";
|
|
74
|
+
export declare type Region = 'us' | 'eu';
|
|
75
|
+
export declare type AccessTokens = {
|
|
76
|
+
[region in Region]?: string;
|
|
77
|
+
};
|
|
78
|
+
export declare const DOMAINS: {
|
|
79
|
+
[region in Region]: string;
|
|
80
|
+
};
|
|
73
81
|
export declare type RawConfig = {
|
|
74
82
|
referenceDocs?: any;
|
|
75
83
|
apiDefinitions?: Record<string, string>;
|
|
76
84
|
lint?: LintRawConfig;
|
|
77
85
|
resolve?: RawResolveConfig;
|
|
86
|
+
region?: Region;
|
|
78
87
|
};
|
|
79
88
|
export declare class LintConfig {
|
|
80
89
|
rawConfig: LintRawConfig;
|
|
@@ -126,5 +135,6 @@ export declare class Config {
|
|
|
126
135
|
lint: LintConfig;
|
|
127
136
|
resolve: ResolveConfig;
|
|
128
137
|
licenseKey?: string;
|
|
138
|
+
region?: Region;
|
|
129
139
|
constructor(rawConfig: RawConfig, configFile?: string | undefined);
|
|
130
140
|
}
|
package/lib/config/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Config = exports.LintConfig = exports.IGNORE_FILE = void 0;
|
|
3
|
+
exports.Config = exports.LintConfig = exports.DOMAINS = exports.DEFAULT_REGION = exports.IGNORE_FILE = void 0;
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const path_1 = require("path");
|
|
@@ -12,6 +12,11 @@ const recommended_1 = require("./recommended");
|
|
|
12
12
|
exports.IGNORE_FILE = '.redocly.lint-ignore.yaml';
|
|
13
13
|
const IGNORE_BANNER = `# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.\n` +
|
|
14
14
|
`# See https://redoc.ly/docs/cli/ for more information.\n`;
|
|
15
|
+
exports.DEFAULT_REGION = 'us';
|
|
16
|
+
exports.DOMAINS = {
|
|
17
|
+
us: 'redoc.ly',
|
|
18
|
+
eu: 'eu.redocly.com',
|
|
19
|
+
};
|
|
15
20
|
class LintConfig {
|
|
16
21
|
constructor(rawConfig, configFile) {
|
|
17
22
|
this.rawConfig = rawConfig;
|
|
@@ -233,6 +238,7 @@ class Config {
|
|
|
233
238
|
customFetch: undefined,
|
|
234
239
|
},
|
|
235
240
|
};
|
|
241
|
+
this.region = rawConfig.region;
|
|
236
242
|
}
|
|
237
243
|
}
|
|
238
244
|
exports.Config = Config;
|
package/lib/config/load.js
CHANGED
|
@@ -35,20 +35,29 @@ function loadConfig(configPath, customExtends) {
|
|
|
35
35
|
rawConfig.lint.extends = customExtends;
|
|
36
36
|
}
|
|
37
37
|
const redoclyClient = new redocly_1.RedoclyClient();
|
|
38
|
-
|
|
38
|
+
const tokens = yield redoclyClient.getTokens();
|
|
39
|
+
if (tokens.length) {
|
|
39
40
|
if (!rawConfig.resolve)
|
|
40
41
|
rawConfig.resolve = {};
|
|
41
42
|
if (!rawConfig.resolve.http)
|
|
42
43
|
rawConfig.resolve.http = {};
|
|
43
|
-
rawConfig.resolve.http.headers = [
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
rawConfig.resolve.http.headers = [...((_a = rawConfig.resolve.http.headers) !== null && _a !== void 0 ? _a : [])];
|
|
45
|
+
for (const item of tokens) {
|
|
46
|
+
const domain = config_1.DOMAINS[item.region];
|
|
47
|
+
rawConfig.resolve.http.headers.push({
|
|
48
|
+
matches: `https://api.${domain}/registry/**`,
|
|
46
49
|
name: 'Authorization',
|
|
47
50
|
envVariable: undefined,
|
|
48
|
-
value:
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
value: item.token,
|
|
52
|
+
},
|
|
53
|
+
//support redocly.com domain for future compatibility
|
|
54
|
+
...(item.region === 'us' ? [{
|
|
55
|
+
matches: `https://api.redocly.com/registry/**`,
|
|
56
|
+
name: 'Authorization',
|
|
57
|
+
envVariable: undefined,
|
|
58
|
+
value: item.token,
|
|
59
|
+
}] : []));
|
|
60
|
+
}
|
|
52
61
|
}
|
|
53
62
|
return new config_1.Config(Object.assign(Object.assign({}, rawConfig), { lint: Object.assign(Object.assign({}, rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.lint), { plugins: [...(((_b = rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.lint) === null || _b === void 0 ? void 0 : _b.plugins) || []), builtIn_1.defaultPlugin] }) }), configPath);
|
|
54
63
|
});
|
package/lib/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { Oas2Definition } from './typings/swagger';
|
|
|
8
8
|
export { StatsAccumulator, StatsName } from './typings/common';
|
|
9
9
|
export { normalizeTypes } from './types';
|
|
10
10
|
export { Stats } from './rules/other/stats';
|
|
11
|
-
export { Config, LintConfig, RawConfig, IGNORE_FILE } from './config/config';
|
|
11
|
+
export { Config, LintConfig, RawConfig, IGNORE_FILE, Region } from './config/config';
|
|
12
12
|
export { loadConfig } from './config/load';
|
|
13
13
|
export { RedoclyClient } from './redocly';
|
|
14
14
|
export { Source, BaseResolver, Document, resolveDocument, ResolveError, YamlParseError, makeDocumentFromString, } from './resolve';
|
|
@@ -19,5 +19,5 @@ export { normalizeVisitors } from './visitors';
|
|
|
19
19
|
export { WalkContext, walkDocument, NormalizedProblem, ProblemSeverity, LineColLocationObject, LocationObject, Loc, } from './walk';
|
|
20
20
|
export { getAstNodeByPointer, getLineColLocation } from './format/codeframes';
|
|
21
21
|
export { formatProblems, OutputFormat, getTotals, Totals } from './format/format';
|
|
22
|
-
export { lint, lint as validate, lintDocument, lintFromString, lintConfig
|
|
22
|
+
export { lint, lint as validate, lintDocument, lintFromString, lintConfig } from './lint';
|
|
23
23
|
export { bundle, bundleDocument } from './bundle';
|
package/lib/redocly/index.d.ts
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import { RegistryApi } from './registry-api';
|
|
2
|
+
import { AccessTokens, Region } from '../config/config';
|
|
2
3
|
export declare class RedoclyClient {
|
|
3
|
-
private
|
|
4
|
+
private accessTokens;
|
|
5
|
+
private region;
|
|
6
|
+
domain: string;
|
|
4
7
|
registryApi: RegistryApi;
|
|
5
|
-
constructor();
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
constructor(region?: Region);
|
|
9
|
+
loadRegion(region?: Region): Region;
|
|
10
|
+
hasTokens(): boolean;
|
|
11
|
+
setAccessTokens(accessTokens: AccessTokens): void;
|
|
12
|
+
loadTokens(): void;
|
|
13
|
+
getValidTokens(): Promise<{
|
|
14
|
+
region: string;
|
|
15
|
+
token: string;
|
|
16
|
+
valid: boolean;
|
|
17
|
+
}[]>;
|
|
18
|
+
getTokens(): Promise<{
|
|
19
|
+
region: string;
|
|
20
|
+
token: string;
|
|
21
|
+
valid: boolean;
|
|
22
|
+
}[]>;
|
|
23
|
+
isAuthorizedWithRedoclyByRegion(): Promise<boolean>;
|
|
8
24
|
isAuthorizedWithRedocly(): Promise<boolean>;
|
|
9
|
-
|
|
10
|
-
|
|
25
|
+
readCredentialsFile(credentialsPath: string): any;
|
|
26
|
+
verifyToken(accessToken: string, region: Region, verbose?: boolean): Promise<boolean>;
|
|
11
27
|
login(accessToken: string, verbose?: boolean): Promise<void>;
|
|
12
28
|
logout(): void;
|
|
13
29
|
}
|
package/lib/redocly/index.js
CHANGED
|
@@ -15,61 +15,91 @@ const path_1 = require("path");
|
|
|
15
15
|
const os_1 = require("os");
|
|
16
16
|
const colorette_1 = require("colorette");
|
|
17
17
|
const registry_api_1 = require("./registry-api");
|
|
18
|
+
const config_1 = require("../config/config");
|
|
19
|
+
const utils_1 = require("../utils");
|
|
18
20
|
const TOKEN_FILENAME = '.redocly-config.json';
|
|
19
21
|
class RedoclyClient {
|
|
20
|
-
constructor() {
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
22
|
+
constructor(region) {
|
|
23
|
+
this.accessTokens = {};
|
|
24
|
+
this.region = this.loadRegion(region);
|
|
25
|
+
this.loadTokens();
|
|
26
|
+
this.domain = region
|
|
27
|
+
? config_1.DOMAINS[region]
|
|
28
|
+
: process.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
|
|
29
|
+
this.registryApi = new registry_api_1.RegistryApi(this.accessTokens, this.region);
|
|
23
30
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (process.env.REDOCLY_AUTHORIZATION) {
|
|
29
|
-
this.accessToken = process.env.REDOCLY_AUTHORIZATION;
|
|
30
|
-
return;
|
|
31
|
+
loadRegion(region) {
|
|
32
|
+
if (region && !config_1.DOMAINS[region]) {
|
|
33
|
+
process.stdout.write(colorette_1.red(`Invalid argument: region in config file.\nGiven: ${colorette_1.green(region)}, choices: "us", "eu".\n`));
|
|
34
|
+
process.exit(1);
|
|
31
35
|
}
|
|
36
|
+
return region || config_1.DEFAULT_REGION;
|
|
37
|
+
}
|
|
38
|
+
hasTokens() {
|
|
39
|
+
return utils_1.isNotEmptyObject(this.accessTokens);
|
|
40
|
+
}
|
|
41
|
+
setAccessTokens(accessTokens) {
|
|
42
|
+
this.accessTokens = accessTokens;
|
|
43
|
+
}
|
|
44
|
+
loadTokens() {
|
|
32
45
|
const credentialsPath = path_1.resolve(os_1.homedir(), TOKEN_FILENAME);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
this.
|
|
46
|
+
const credentials = this.readCredentialsFile(credentialsPath);
|
|
47
|
+
if (utils_1.isNotEmptyObject(credentials)) {
|
|
48
|
+
this.setAccessTokens(Object.assign(Object.assign({}, credentials), (credentials.token && !credentials[this.region] && {
|
|
49
|
+
[this.region]: credentials.token
|
|
50
|
+
})));
|
|
51
|
+
}
|
|
52
|
+
if (process.env.REDOCLY_AUTHORIZATION) {
|
|
53
|
+
this.setAccessTokens(Object.assign(Object.assign({}, this.accessTokens), { [this.region]: process.env.REDOCLY_AUTHORIZATION }));
|
|
36
54
|
}
|
|
37
55
|
}
|
|
38
|
-
|
|
56
|
+
getValidTokens() {
|
|
39
57
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
-
return this.
|
|
58
|
+
return (yield Promise.all(Object.entries(this.accessTokens).map(([key, value]) => __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
return { region: key, token: value, valid: yield this.verifyToken(value, key) };
|
|
60
|
+
})))).filter(item => Boolean(item.valid));
|
|
41
61
|
});
|
|
42
62
|
}
|
|
43
|
-
|
|
63
|
+
getTokens() {
|
|
44
64
|
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
-
|
|
65
|
+
return this.hasTokens() ? yield this.getValidTokens() : [];
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
isAuthorizedWithRedoclyByRegion() {
|
|
69
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
if (!this.hasTokens())
|
|
46
71
|
return false;
|
|
47
|
-
|
|
72
|
+
const accessToken = this.accessTokens[this.region];
|
|
73
|
+
return !!accessToken && (yield this.verifyToken(accessToken, this.region));
|
|
48
74
|
});
|
|
49
75
|
}
|
|
50
|
-
|
|
76
|
+
isAuthorizedWithRedocly() {
|
|
51
77
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
78
|
+
return this.hasTokens() && utils_1.isNotEmptyObject(yield this.getValidTokens());
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
readCredentialsFile(credentialsPath) {
|
|
82
|
+
return fs_1.existsSync(credentialsPath) ? JSON.parse(fs_1.readFileSync(credentialsPath, 'utf-8')) : {};
|
|
83
|
+
}
|
|
84
|
+
verifyToken(accessToken, region, verbose = false) {
|
|
85
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
86
|
+
if (!accessToken)
|
|
87
|
+
return false;
|
|
88
|
+
return this.registryApi.authStatus(accessToken, region, verbose);
|
|
58
89
|
});
|
|
59
90
|
}
|
|
60
91
|
login(accessToken, verbose = false) {
|
|
61
92
|
return __awaiter(this, void 0, void 0, function* () {
|
|
62
93
|
const credentialsPath = path_1.resolve(os_1.homedir(), TOKEN_FILENAME);
|
|
63
94
|
process.stdout.write(colorette_1.gray('\n Logging in...\n'));
|
|
64
|
-
const authorized = yield this.verifyToken(accessToken, verbose);
|
|
95
|
+
const authorized = yield this.verifyToken(accessToken, this.region, verbose);
|
|
65
96
|
if (!authorized) {
|
|
66
97
|
process.stdout.write(colorette_1.red('Authorization failed. Please check if you entered a valid API key.\n'));
|
|
67
98
|
process.exit(1);
|
|
68
99
|
}
|
|
69
|
-
this.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
};
|
|
100
|
+
const credentials = Object.assign(Object.assign({}, this.readCredentialsFile(credentialsPath)), { [this.region]: accessToken });
|
|
101
|
+
this.accessTokens = credentials;
|
|
102
|
+
this.registryApi.setAccessTokens(credentials);
|
|
73
103
|
fs_1.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2));
|
|
74
104
|
process.stdout.write(colorette_1.green(' Authorization confirmed. ✅\n\n'));
|
|
75
105
|
});
|
|
@@ -84,7 +114,7 @@ class RedoclyClient {
|
|
|
84
114
|
}
|
|
85
115
|
exports.RedoclyClient = RedoclyClient;
|
|
86
116
|
function isRedoclyRegistryURL(link) {
|
|
87
|
-
const domain = process.env.REDOCLY_DOMAIN ||
|
|
117
|
+
const domain = process.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
|
|
88
118
|
if (!link.startsWith(`https://api.${domain}/registry/`))
|
|
89
119
|
return false;
|
|
90
120
|
const registryPath = link.replace(`https://api.${domain}/registry/`, '');
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { RegistryApiTypes } from './registry-api-types';
|
|
2
|
+
import { AccessTokens, Region } from '../config/config';
|
|
2
3
|
export declare class RegistryApi {
|
|
3
|
-
private
|
|
4
|
-
private
|
|
5
|
-
constructor(
|
|
4
|
+
private accessTokens;
|
|
5
|
+
private region;
|
|
6
|
+
constructor(accessTokens: AccessTokens, region: Region);
|
|
7
|
+
get accessToken(): string | false | undefined;
|
|
8
|
+
getBaseUrl(region?: Region): string;
|
|
9
|
+
setAccessTokens(accessTokens: AccessTokens): this;
|
|
6
10
|
private request;
|
|
7
|
-
|
|
8
|
-
authStatus(verbose?: boolean): Promise<boolean>;
|
|
11
|
+
authStatus(accessToken: string, region: Region, verbose?: boolean): Promise<boolean>;
|
|
9
12
|
prepareFileUpload({ organizationId, name, version, filesHash, filename, isUpsert, }: RegistryApiTypes.PrepareFileuploadParams): Promise<RegistryApiTypes.PrepareFileuploadOKResponse>;
|
|
10
13
|
pushApi({ organizationId, name, version, rootFilePath, filePaths, branch, isUpsert, }: RegistryApiTypes.PushApiParams): Promise<void>;
|
|
11
14
|
}
|
|
@@ -11,22 +11,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.RegistryApi = void 0;
|
|
13
13
|
const node_fetch_1 = require("node-fetch");
|
|
14
|
+
const config_1 = require("../config/config");
|
|
15
|
+
const utils_1 = require("../utils");
|
|
14
16
|
const version = require('../../package.json').version;
|
|
15
17
|
class RegistryApi {
|
|
16
|
-
constructor(
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
18
|
+
constructor(accessTokens, region) {
|
|
19
|
+
this.accessTokens = accessTokens;
|
|
20
|
+
this.region = region;
|
|
19
21
|
}
|
|
20
|
-
|
|
22
|
+
get accessToken() {
|
|
23
|
+
return utils_1.isNotEmptyObject(this.accessTokens) && this.accessTokens[this.region];
|
|
24
|
+
}
|
|
25
|
+
getBaseUrl(region = config_1.DEFAULT_REGION) {
|
|
26
|
+
return `https://api.${config_1.DOMAINS[region]}/registry`;
|
|
27
|
+
}
|
|
28
|
+
setAccessTokens(accessTokens) {
|
|
29
|
+
this.accessTokens = accessTokens;
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
request(path = '', options = {}, region) {
|
|
21
33
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
|
|
34
|
+
const headers = Object.assign({}, options.headers || {}, { 'x-redocly-cli-version': version });
|
|
35
|
+
if (!headers.hasOwnProperty('authorization')) {
|
|
23
36
|
throw new Error('Unauthorized');
|
|
24
37
|
}
|
|
25
|
-
const
|
|
26
|
-
authorization: this.accessToken,
|
|
27
|
-
'x-redocly-cli-version': version,
|
|
28
|
-
});
|
|
29
|
-
const response = yield node_fetch_1.default(`${this.baseUrl}${path}`, Object.assign({}, options, { headers }));
|
|
38
|
+
const response = yield node_fetch_1.default(`${this.getBaseUrl(region)}${path}`, Object.assign({}, options, { headers }));
|
|
30
39
|
if (response.status === 401) {
|
|
31
40
|
throw new Error('Unauthorized');
|
|
32
41
|
}
|
|
@@ -37,14 +46,10 @@ class RegistryApi {
|
|
|
37
46
|
return response;
|
|
38
47
|
});
|
|
39
48
|
}
|
|
40
|
-
|
|
41
|
-
this.accessToken = accessToken;
|
|
42
|
-
return this;
|
|
43
|
-
}
|
|
44
|
-
authStatus(verbose = false) {
|
|
49
|
+
authStatus(accessToken, region, verbose = false) {
|
|
45
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
51
|
try {
|
|
47
|
-
const response = yield this.request();
|
|
52
|
+
const response = yield this.request('', { headers: { authorization: accessToken } }, region);
|
|
48
53
|
return response.ok;
|
|
49
54
|
}
|
|
50
55
|
catch (error) {
|
|
@@ -59,13 +64,16 @@ class RegistryApi {
|
|
|
59
64
|
return __awaiter(this, void 0, void 0, function* () {
|
|
60
65
|
const response = yield this.request(`/${organizationId}/${name}/${version}/prepare-file-upload`, {
|
|
61
66
|
method: 'POST',
|
|
62
|
-
headers: {
|
|
67
|
+
headers: {
|
|
68
|
+
'content-type': 'application/json',
|
|
69
|
+
authorization: this.accessToken,
|
|
70
|
+
},
|
|
63
71
|
body: JSON.stringify({
|
|
64
72
|
filesHash,
|
|
65
73
|
filename,
|
|
66
74
|
isUpsert,
|
|
67
75
|
}),
|
|
68
|
-
});
|
|
76
|
+
}, this.region);
|
|
69
77
|
if (response.ok) {
|
|
70
78
|
return response.json();
|
|
71
79
|
}
|
|
@@ -76,14 +84,17 @@ class RegistryApi {
|
|
|
76
84
|
return __awaiter(this, void 0, void 0, function* () {
|
|
77
85
|
const response = yield this.request(`/${organizationId}/${name}/${version}`, {
|
|
78
86
|
method: 'PUT',
|
|
79
|
-
headers: {
|
|
87
|
+
headers: {
|
|
88
|
+
'content-type': 'application/json',
|
|
89
|
+
authorization: this.accessToken
|
|
90
|
+
},
|
|
80
91
|
body: JSON.stringify({
|
|
81
92
|
rootFilePath,
|
|
82
93
|
filePaths,
|
|
83
94
|
branch,
|
|
84
95
|
isUpsert,
|
|
85
96
|
}),
|
|
86
|
-
});
|
|
97
|
+
}, this.region);
|
|
87
98
|
if (response.ok) {
|
|
88
99
|
return;
|
|
89
100
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const NoInvalidParameterExamples: any;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NoInvalidParameterExamples = void 0;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const NoInvalidParameterExamples = (opts) => {
|
|
6
|
+
var _a;
|
|
7
|
+
const disallowAdditionalProperties = (_a = opts.disallowAdditionalProperties) !== null && _a !== void 0 ? _a : true;
|
|
8
|
+
return {
|
|
9
|
+
Parameter: {
|
|
10
|
+
leave(parameter, ctx) {
|
|
11
|
+
if (parameter.example) {
|
|
12
|
+
utils_1.validateExample(parameter.example, parameter.schema, ctx.location.child('example'), ctx, disallowAdditionalProperties);
|
|
13
|
+
}
|
|
14
|
+
if (parameter.examples) {
|
|
15
|
+
for (const [key, example] of Object.entries(parameter.examples)) {
|
|
16
|
+
if ('value' in example) {
|
|
17
|
+
utils_1.validateExample(example.value, parameter.schema, ctx.location.child(['examples', key]), ctx, false);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
exports.NoInvalidParameterExamples = NoInvalidParameterExamples;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const NoInvalidSchemaExamples: any;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NoInvalidSchemaExamples = void 0;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const NoInvalidSchemaExamples = (opts) => {
|
|
6
|
+
var _a;
|
|
7
|
+
const disallowAdditionalProperties = (_a = opts.disallowAdditionalProperties) !== null && _a !== void 0 ? _a : true;
|
|
8
|
+
return {
|
|
9
|
+
Schema: {
|
|
10
|
+
leave(schema, ctx) {
|
|
11
|
+
if (schema.examples) {
|
|
12
|
+
for (const example of schema.examples) {
|
|
13
|
+
utils_1.validateExample(example, schema, ctx.location.child(['examples', schema.examples.indexOf(example)]), ctx, disallowAdditionalProperties);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (schema.example) {
|
|
17
|
+
utils_1.validateExample(schema.example, schema, ctx.location.child('example'), ctx, false);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
exports.NoInvalidSchemaExamples = NoInvalidSchemaExamples;
|
|
@@ -4,7 +4,7 @@ exports.PathsKebabCase = void 0;
|
|
|
4
4
|
const PathsKebabCase = () => {
|
|
5
5
|
return {
|
|
6
6
|
PathItem(_path, { report, key }) {
|
|
7
|
-
const segments = key.substr(1).split('/');
|
|
7
|
+
const segments = key.substr(1).split('/').filter(s => s !== ''); // filter out empty segments
|
|
8
8
|
if (!segments.every((segment) => /^{.+}$/.test(segment) || /^[a-z0-9-.]+$/.test(segment))) {
|
|
9
9
|
report({
|
|
10
10
|
message: `\`${key}\` does not use kebab-case.`,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Oas2Decorator, Oas2Rule } from '../../visitors';
|
|
2
2
|
export declare const rules: {
|
|
3
3
|
spec: Oas2Rule;
|
|
4
|
+
'no-invalid-schema-examples': any;
|
|
5
|
+
'no-invalid-parameter-examples': any;
|
|
4
6
|
'info-description': Oas2Rule;
|
|
5
7
|
'info-contact': Oas2Rule;
|
|
6
8
|
'info-license': Oas2Rule;
|
package/lib/rules/oas2/index.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.decorators = exports.preprocessors = exports.rules = void 0;
|
|
4
4
|
const spec_1 = require("../common/spec");
|
|
5
|
+
const no_invalid_schema_examples_1 = require("../common/no-invalid-schema-examples");
|
|
6
|
+
const no_invalid_parameter_examples_1 = require("../common/no-invalid-parameter-examples");
|
|
5
7
|
const info_description_1 = require("../common/info-description");
|
|
6
8
|
const info_contact_1 = require("../common/info-contact");
|
|
7
9
|
const info_license_url_1 = require("../common/info-license-url");
|
|
@@ -42,6 +44,8 @@ const tag_description_override_1 = require("../common/tag-description-override")
|
|
|
42
44
|
const info_description_override_1 = require("../common/info-description-override");
|
|
43
45
|
exports.rules = {
|
|
44
46
|
spec: spec_1.OasSpec,
|
|
47
|
+
'no-invalid-schema-examples': no_invalid_schema_examples_1.NoInvalidSchemaExamples,
|
|
48
|
+
'no-invalid-parameter-examples': no_invalid_parameter_examples_1.NoInvalidParameterExamples,
|
|
45
49
|
'info-description': info_description_1.InfoDescription,
|
|
46
50
|
'info-contact': info_contact_1.InfoContact,
|
|
47
51
|
'info-license': info_license_url_1.InfoLicense,
|
package/lib/rules/oas3/index.js
CHANGED
|
@@ -48,6 +48,8 @@ const operation_description_override_1 = require("../common/operation-descriptio
|
|
|
48
48
|
const tag_description_override_1 = require("../common/tag-description-override");
|
|
49
49
|
const info_description_override_1 = require("../common/info-description-override");
|
|
50
50
|
const path_excludes_patterns_1 = require("../common/path-excludes-patterns");
|
|
51
|
+
const no_invalid_schema_examples_1 = require("../common/no-invalid-schema-examples");
|
|
52
|
+
const no_invalid_parameter_examples_1 = require("../common/no-invalid-parameter-examples");
|
|
51
53
|
exports.rules = {
|
|
52
54
|
spec: spec_1.OasSpec,
|
|
53
55
|
'info-description': info_description_1.InfoDescription,
|
|
@@ -93,6 +95,8 @@ exports.rules = {
|
|
|
93
95
|
'request-mime-type': request_mime_type_1.RequestMimeType,
|
|
94
96
|
'response-mime-type': response_mime_type_1.ResponseMimeType,
|
|
95
97
|
'path-segment-plural': path_segment_plural_1.PathSegmentPlural,
|
|
98
|
+
'no-invalid-schema-examples': no_invalid_schema_examples_1.NoInvalidSchemaExamples,
|
|
99
|
+
'no-invalid-parameter-examples': no_invalid_parameter_examples_1.NoInvalidParameterExamples,
|
|
96
100
|
};
|
|
97
101
|
exports.preprocessors = {};
|
|
98
102
|
exports.decorators = {
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ValidContentExamples = void 0;
|
|
4
|
-
const ajv_1 = require("../ajv");
|
|
5
4
|
const ref_utils_1 = require("../../ref-utils");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
6
|
const ValidContentExamples = (opts) => {
|
|
7
7
|
var _a;
|
|
8
8
|
const disallowAdditionalProperties = (_a = opts.disallowAdditionalProperties) !== null && _a !== void 0 ? _a : true;
|
|
9
9
|
return {
|
|
10
10
|
MediaType: {
|
|
11
|
-
leave(mediaType,
|
|
11
|
+
leave(mediaType, ctx) {
|
|
12
|
+
const { location, resolve } = ctx;
|
|
12
13
|
if (!mediaType.schema)
|
|
13
14
|
return;
|
|
14
15
|
if (mediaType.example) {
|
|
15
|
-
validateExample(mediaType.example, location.child('example'));
|
|
16
|
+
utils_1.validateExample(mediaType.example, mediaType.schema, location.child('example'), ctx, disallowAdditionalProperties);
|
|
16
17
|
}
|
|
17
18
|
else if (mediaType.examples) {
|
|
18
19
|
for (const exampleName of Object.keys(mediaType.examples)) {
|
|
@@ -25,29 +26,7 @@ const ValidContentExamples = (opts) => {
|
|
|
25
26
|
dataLoc = resolved.location.child('value');
|
|
26
27
|
example = resolved.node;
|
|
27
28
|
}
|
|
28
|
-
validateExample(example.value, dataLoc);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
function validateExample(example, dataLoc) {
|
|
32
|
-
try {
|
|
33
|
-
const { valid, errors } = ajv_1.validateJsonSchema(example, mediaType.schema, location.child('schema'), dataLoc.pointer, resolve, disallowAdditionalProperties);
|
|
34
|
-
if (!valid) {
|
|
35
|
-
for (let error of errors) {
|
|
36
|
-
report({
|
|
37
|
-
message: `Example value must conform to the schema: ${error.message}.`,
|
|
38
|
-
location: Object.assign(Object.assign({}, new ref_utils_1.Location(dataLoc.source, error.instancePath)), { reportOnKey: error.keyword === 'additionalProperties' }),
|
|
39
|
-
from: location,
|
|
40
|
-
suggest: error.suggest,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
catch (e) {
|
|
46
|
-
report({
|
|
47
|
-
message: `Example validation errored: ${e.message}.`,
|
|
48
|
-
location: location.child('schema'),
|
|
49
|
-
from: location
|
|
50
|
-
});
|
|
29
|
+
utils_1.validateExample(example.value, mediaType.schema, dataLoc, ctx, disallowAdditionalProperties);
|
|
51
30
|
}
|
|
52
31
|
}
|
|
53
32
|
},
|
package/lib/rules/utils.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { UserContext } from '../walk';
|
|
2
|
+
import { Location } from '../ref-utils';
|
|
3
|
+
import { Oas3Schema, Referenced } from '../typings/openapi';
|
|
2
4
|
export declare function oasTypeOf(value: unknown): "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | "array" | "null";
|
|
3
5
|
/**
|
|
4
6
|
* Checks if value matches specified JSON schema type
|
|
@@ -12,3 +14,4 @@ export declare function missingRequiredField(type: string, field: string): strin
|
|
|
12
14
|
export declare function fieldNonEmpty(type: string, field: string): string;
|
|
13
15
|
export declare function validateDefinedAndNonEmpty(fieldName: string, value: any, ctx: UserContext): void;
|
|
14
16
|
export declare function getSuggest(given: string, variants: string[]): string[];
|
|
17
|
+
export declare function validateExample(example: any, schema: Referenced<Oas3Schema>, dataLoc: Location, { resolve, location, report }: UserContext, disallowAdditionalProperties: boolean): void;
|