@redocly/openapi-core 1.0.0-beta.96 → 1.0.0-beta.99
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/lib/bundle.d.ts +2 -0
- package/lib/bundle.js +6 -3
- package/lib/config/all.js +1 -0
- package/lib/config/config-resolvers.d.ts +1 -1
- package/lib/config/config-resolvers.js +31 -2
- package/lib/config/config.d.ts +4 -1
- package/lib/config/config.js +18 -12
- package/lib/format/format.js +2 -1
- package/lib/redocly/index.js +10 -26
- package/lib/redocly/registry-api-types.d.ts +1 -0
- package/lib/redocly/registry-api.d.ts +1 -1
- package/lib/redocly/registry-api.js +2 -1
- package/lib/ref-utils.js +1 -0
- package/lib/rules/common/response-contains-header.d.ts +2 -0
- package/lib/rules/common/response-contains-header.js +29 -0
- package/lib/rules/common/scalar-property-missing-example.d.ts +2 -0
- package/lib/rules/common/scalar-property-missing-example.js +41 -0
- package/lib/rules/oas2/index.d.ts +3 -0
- package/lib/rules/oas2/index.js +6 -0
- package/lib/rules/oas2/response-contains-property.d.ts +2 -0
- package/lib/rules/oas2/response-contains-property.js +38 -0
- package/lib/rules/oas3/index.js +6 -0
- package/lib/rules/oas3/response-contains-property.d.ts +2 -0
- package/lib/rules/oas3/response-contains-property.js +40 -0
- package/lib/types/oas2.js +3 -1
- package/lib/types/oas3.js +21 -8
- package/lib/types/oas3_1.js +12 -8
- package/lib/types/redocly-yaml.js +12 -0
- package/lib/typings/openapi.d.ts +5 -2
- package/lib/typings/swagger.d.ts +2 -0
- package/lib/utils.d.ts +1 -1
- package/lib/utils.js +5 -3
- package/package.json +3 -3
- package/{__tests__ → src/__tests__}/__snapshots__/bundle.test.ts.snap +26 -0
- package/{__tests__ → src/__tests__}/bundle.test.ts +30 -6
- package/{__tests__ → src/__tests__}/codeframes.test.ts +3 -3
- package/{__tests__ → src/__tests__}/fixtures/extension.js +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/definitions.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/examples.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/external-request-body.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/externalref.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/hosted.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/openapi-with-external-refs-conflicting-names.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/openapi-with-external-refs.yaml +0 -0
- package/src/__tests__/fixtures/refs/openapi-with-url-refs.yaml +18 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/param-b.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/param-c.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/rename.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/requestBody.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/schema-a.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/simple.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/refs/vendor.schema.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/External.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/External2.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/description.md +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/externalInfo.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/externalLicense.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/openapi-with-back.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/openapi-with-md-description.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/openapi.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/schemas/type-a.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/schemas/type-b.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/a.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/components.yaml +0 -0
- package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/schemas.yaml +0 -0
- package/src/__tests__/lint.test.ts +13 -0
- package/{__tests__ → src/__tests__}/login.test.ts +1 -1
- package/{__tests__ → src/__tests__}/normalizeVisitors.test.ts +4 -4
- package/{__tests__ → src/__tests__}/ref-utils.test.ts +5 -5
- package/{__tests__ → src/__tests__}/resolve-http.test.ts +4 -4
- package/{__tests__ → src/__tests__}/resolve.test.ts +4 -4
- package/src/__tests__/utils.test.ts +12 -1
- package/{__tests__ → src/__tests__}/walk.test.ts +5 -5
- package/src/bundle.ts +18 -3
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +18 -1
- package/src/config/__tests__/config-resolvers.test.ts +32 -1
- package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +5 -0
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +7 -0
- package/src/config/all.ts +1 -0
- package/src/config/config-resolvers.ts +58 -3
- package/src/config/config.ts +21 -12
- package/src/format/format.ts +2 -1
- package/src/redocly/index.ts +12 -41
- package/src/redocly/registry-api-types.ts +1 -0
- package/src/redocly/registry-api.ts +2 -0
- package/src/ref-utils.ts +1 -0
- package/src/rules/common/__tests__/scalar-property-missing-example.test.ts +207 -0
- package/src/rules/common/response-contains-header.ts +30 -0
- package/src/rules/common/scalar-property-missing-example.ts +55 -0
- package/src/rules/oas2/__tests__/response-contains-header.test.ts +174 -0
- package/src/rules/oas2/__tests__/response-contains-property.test.ts +155 -0
- package/src/rules/oas2/index.ts +6 -0
- package/src/rules/oas2/response-contains-property.ts +36 -0
- package/src/rules/oas3/__tests__/response-contains-header.test.ts +273 -0
- package/src/rules/oas3/__tests__/response-contains-property.test.ts +403 -0
- package/src/rules/oas3/index.ts +6 -0
- package/src/rules/oas3/response-contains-property.ts +38 -0
- package/src/types/oas2.ts +2 -0
- package/src/types/oas3.ts +18 -7
- package/src/types/oas3_1.ts +11 -7
- package/src/types/redocly-yaml.ts +12 -0
- package/src/typings/openapi.ts +4 -1
- package/src/typings/swagger.ts +2 -0
- package/src/utils.ts +6 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/__tests__/lint.test.ts +0 -17
package/src/bundle.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { Oas3_1Types } from './types/oas3_1';
|
|
|
7
7
|
import { NormalizedNodeType, normalizeTypes, NodeType } from './types';
|
|
8
8
|
import { WalkContext, walkDocument, UserContext, ResolveResult } from './walk';
|
|
9
9
|
import { detectOpenAPI, openAPIMajor, OasMajorVersion } from './oas-types';
|
|
10
|
-
import { isRef, Location, refBaseName
|
|
10
|
+
import {isAbsoluteUrl, isRef, Location, refBaseName} from './ref-utils';
|
|
11
11
|
import { initRules } from './config/rules';
|
|
12
12
|
import { reportUnresolvedRef } from './rules/no-unresolved-refs';
|
|
13
13
|
import { isPlainObject } from './utils';
|
|
@@ -35,6 +35,7 @@ export async function bundle(opts: {
|
|
|
35
35
|
base?: string;
|
|
36
36
|
skipRedoclyRegistryRefs?: boolean;
|
|
37
37
|
removeUnusedComponents?: boolean;
|
|
38
|
+
keepUrlRefs?: boolean;
|
|
38
39
|
}) {
|
|
39
40
|
const {
|
|
40
41
|
ref,
|
|
@@ -71,6 +72,7 @@ export async function bundleDocument(opts: {
|
|
|
71
72
|
dereference?: boolean;
|
|
72
73
|
skipRedoclyRegistryRefs?: boolean;
|
|
73
74
|
removeUnusedComponents?: boolean;
|
|
75
|
+
keepUrlRefs?: boolean;
|
|
74
76
|
}) {
|
|
75
77
|
const {
|
|
76
78
|
document,
|
|
@@ -80,6 +82,7 @@ export async function bundleDocument(opts: {
|
|
|
80
82
|
dereference = false,
|
|
81
83
|
skipRedoclyRegistryRefs = false,
|
|
82
84
|
removeUnusedComponents = false,
|
|
85
|
+
keepUrlRefs = false,
|
|
83
86
|
} = opts;
|
|
84
87
|
const oasVersion = detectOpenAPI(document.parsed);
|
|
85
88
|
const oasMajorVersion = openAPIMajor(oasVersion);
|
|
@@ -128,7 +131,14 @@ export async function bundleDocument(opts: {
|
|
|
128
131
|
{
|
|
129
132
|
severity: 'error',
|
|
130
133
|
ruleId: 'bundler',
|
|
131
|
-
visitor: makeBundleVisitor(
|
|
134
|
+
visitor: makeBundleVisitor(
|
|
135
|
+
oasMajorVersion,
|
|
136
|
+
dereference,
|
|
137
|
+
skipRedoclyRegistryRefs,
|
|
138
|
+
document,
|
|
139
|
+
resolvedRefMap,
|
|
140
|
+
keepUrlRefs,
|
|
141
|
+
),
|
|
132
142
|
},
|
|
133
143
|
...decorators,
|
|
134
144
|
] as any,
|
|
@@ -199,7 +209,8 @@ function makeBundleVisitor(
|
|
|
199
209
|
dereference: boolean,
|
|
200
210
|
skipRedoclyRegistryRefs: boolean,
|
|
201
211
|
rootDocument: Document,
|
|
202
|
-
resolvedRefMap: ResolvedRefMap
|
|
212
|
+
resolvedRefMap: ResolvedRefMap,
|
|
213
|
+
keepUrlRefs: boolean,
|
|
203
214
|
) {
|
|
204
215
|
let components: Record<string, Record<string, any>>;
|
|
205
216
|
|
|
@@ -224,6 +235,10 @@ function makeBundleVisitor(
|
|
|
224
235
|
return;
|
|
225
236
|
}
|
|
226
237
|
|
|
238
|
+
if (keepUrlRefs && isAbsoluteUrl(node.$ref)) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
227
242
|
const componentType = mapTypeToComponent(ctx.type.name, version);
|
|
228
243
|
if (!componentType) {
|
|
229
244
|
replaceRef(node, resolved, ctx);
|
|
@@ -103,7 +103,24 @@ Object {
|
|
|
103
103
|
"preprocessors": Object {},
|
|
104
104
|
"recommendedFallback": undefined,
|
|
105
105
|
"rules": Object {
|
|
106
|
-
"assertions":
|
|
106
|
+
"assertions": Array [
|
|
107
|
+
Object {
|
|
108
|
+
"assertionId": "path-item-get-defined",
|
|
109
|
+
"defined": true,
|
|
110
|
+
"message": "Every path item must have a GET operation.",
|
|
111
|
+
"property": "get",
|
|
112
|
+
"subject": "PathItem",
|
|
113
|
+
},
|
|
114
|
+
Object {
|
|
115
|
+
"assertionId": "tag-description",
|
|
116
|
+
"message": "Tag description must be at least 13 characters and end with a full stop.",
|
|
117
|
+
"minLength": 13,
|
|
118
|
+
"pattern": "/\\\\.$/",
|
|
119
|
+
"property": "description",
|
|
120
|
+
"severity": "error",
|
|
121
|
+
"subject": "Tag",
|
|
122
|
+
},
|
|
123
|
+
],
|
|
107
124
|
"boolean-parameter-prefixes": "error",
|
|
108
125
|
"info-contact": "off",
|
|
109
126
|
"info-description": "warn",
|
|
@@ -130,11 +130,42 @@ describe('resolveLint', () => {
|
|
|
130
130
|
expect(lint).toMatchSnapshot();
|
|
131
131
|
});
|
|
132
132
|
|
|
133
|
+
it('should correctly merge assertions from nested config', async () => {
|
|
134
|
+
const lintConfig = {
|
|
135
|
+
extends: ['local-config-with-file.yaml'],
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const lint = await resolveLint({
|
|
139
|
+
lintConfig,
|
|
140
|
+
configPath,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expect(Array.isArray(lint.rules?.assertions)).toEqual(true);
|
|
144
|
+
expect(lint.rules?.assertions).toMatchObject( [
|
|
145
|
+
{
|
|
146
|
+
subject: 'PathItem',
|
|
147
|
+
property: 'get',
|
|
148
|
+
message: 'Every path item must have a GET operation.',
|
|
149
|
+
defined: true,
|
|
150
|
+
assertionId: 'path-item-get-defined'
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
subject: 'Tag',
|
|
154
|
+
property: 'description',
|
|
155
|
+
message: 'Tag description must be at least 13 characters and end with a full stop.',
|
|
156
|
+
severity: 'error',
|
|
157
|
+
minLength: 13,
|
|
158
|
+
pattern: '/\\.$/',
|
|
159
|
+
assertionId: 'tag-description'
|
|
160
|
+
}
|
|
161
|
+
])
|
|
162
|
+
});
|
|
163
|
+
|
|
133
164
|
it('should resolve extends with url file config witch contains path to nested config', async () => {
|
|
134
165
|
const lintConfig = {
|
|
135
166
|
// This points to ./fixtures/resolve-remote-configs/remote-config.yaml
|
|
136
167
|
extends: [
|
|
137
|
-
'https://raw.githubusercontent.com/Redocly/
|
|
168
|
+
'https://raw.githubusercontent.com/Redocly/redocly-cli/master/packages/core/src/config/__tests__/fixtures/resolve-remote-configs/remote-config.yaml',
|
|
138
169
|
],
|
|
139
170
|
};
|
|
140
171
|
|
|
@@ -2,6 +2,13 @@ lint:
|
|
|
2
2
|
rules:
|
|
3
3
|
no-invalid-media-type-examples: warn
|
|
4
4
|
operation-4xx-response: off
|
|
5
|
+
assert/tag-description:
|
|
6
|
+
subject: Tag
|
|
7
|
+
property: description
|
|
8
|
+
message: Tag description must be at least 13 characters and end with a full stop.
|
|
9
|
+
severity: error
|
|
10
|
+
minLength: 13
|
|
11
|
+
pattern: /\.$/
|
|
5
12
|
plugins:
|
|
6
13
|
- plugin.js
|
|
7
14
|
- api/plugin.js
|
package/src/config/all.ts
CHANGED
|
@@ -11,7 +11,14 @@ import {
|
|
|
11
11
|
prefixRules,
|
|
12
12
|
transformConfig,
|
|
13
13
|
} from './utils';
|
|
14
|
-
import type {
|
|
14
|
+
import type {
|
|
15
|
+
LintRawConfig,
|
|
16
|
+
Plugin,
|
|
17
|
+
RawConfig,
|
|
18
|
+
ResolvedApi,
|
|
19
|
+
ResolvedLintConfig,
|
|
20
|
+
RuleConfig,
|
|
21
|
+
} from './types';
|
|
15
22
|
import { isNotString, isString, notUndefined, parseYaml } from '../utils';
|
|
16
23
|
import { Config } from './config';
|
|
17
24
|
|
|
@@ -175,7 +182,7 @@ export async function resolveApis({
|
|
|
175
182
|
return resolvedApis;
|
|
176
183
|
}
|
|
177
184
|
|
|
178
|
-
|
|
185
|
+
async function resolveAndMergeNestedLint(
|
|
179
186
|
{
|
|
180
187
|
lintConfig,
|
|
181
188
|
configPath = '',
|
|
@@ -213,7 +220,7 @@ export async function resolveLint(
|
|
|
213
220
|
? new URL(presetItem, configPath).href
|
|
214
221
|
: path.resolve(path.dirname(configPath), presetItem);
|
|
215
222
|
const extendedLintConfig = await loadExtendLintConfig(pathItem, resolver);
|
|
216
|
-
return await
|
|
223
|
+
return await resolveAndMergeNestedLint(
|
|
217
224
|
{
|
|
218
225
|
lintConfig: extendedLintConfig,
|
|
219
226
|
configPath: pathItem,
|
|
@@ -245,6 +252,23 @@ export async function resolveLint(
|
|
|
245
252
|
};
|
|
246
253
|
}
|
|
247
254
|
|
|
255
|
+
export async function resolveLint(
|
|
256
|
+
lintOpts: {
|
|
257
|
+
lintConfig?: LintRawConfig;
|
|
258
|
+
configPath?: string;
|
|
259
|
+
resolver?: BaseResolver;
|
|
260
|
+
},
|
|
261
|
+
parentConfigPaths: string[] = [],
|
|
262
|
+
extendPaths: string[] = [],
|
|
263
|
+
): Promise<ResolvedLintConfig> {
|
|
264
|
+
const resolvedLint = await resolveAndMergeNestedLint(lintOpts, parentConfigPaths, extendPaths);
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
...resolvedLint,
|
|
268
|
+
rules: resolvedLint.rules && groupLintAssertionRules(resolvedLint.rules),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
248
272
|
export function resolvePreset(presetName: string, plugins: Plugin[]): ResolvedLintConfig {
|
|
249
273
|
const { pluginId, configName } = parsePresetName(presetName);
|
|
250
274
|
const plugin = plugins.find((p) => p.id === pluginId);
|
|
@@ -302,3 +326,34 @@ function getMergedLintRawConfig(configLint: LintRawConfig, apiLint?: LintRawConf
|
|
|
302
326
|
};
|
|
303
327
|
return resultLint;
|
|
304
328
|
}
|
|
329
|
+
|
|
330
|
+
function groupLintAssertionRules(
|
|
331
|
+
rules: Record<string, RuleConfig> | undefined,
|
|
332
|
+
): Record<string, RuleConfig> | undefined {
|
|
333
|
+
if (!rules) {
|
|
334
|
+
return rules;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Create a new record to avoid mutating original
|
|
338
|
+
const transformedRules: Record<string, RuleConfig> = {};
|
|
339
|
+
|
|
340
|
+
// Collect assertion rules
|
|
341
|
+
const assertions = [];
|
|
342
|
+
for (const [ruleKey, rule] of Object.entries(rules)) {
|
|
343
|
+
if (ruleKey.startsWith('assert/') && typeof rule === 'object' && rule !== null) {
|
|
344
|
+
const assertion = rule;
|
|
345
|
+
assertions.push({
|
|
346
|
+
...assertion,
|
|
347
|
+
assertionId: ruleKey.replace('assert/', ''),
|
|
348
|
+
});
|
|
349
|
+
} else {
|
|
350
|
+
// If it's not an assertion, keep it as is
|
|
351
|
+
transformedRules[ruleKey] = rule;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (assertions.length > 0) {
|
|
355
|
+
transformedRules.assertions = assertions;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return transformedRules;
|
|
359
|
+
}
|
package/src/config/config.ts
CHANGED
|
@@ -19,25 +19,34 @@ import type {
|
|
|
19
19
|
} from './types';
|
|
20
20
|
import { getResolveConfig } from './utils';
|
|
21
21
|
|
|
22
|
+
// Alias environment here so this file can work in browser environments too.
|
|
23
|
+
export const env = typeof process !== 'undefined' ? process.env || {} : {};
|
|
24
|
+
|
|
22
25
|
export const IGNORE_FILE = '.redocly.lint-ignore.yaml';
|
|
23
26
|
const IGNORE_BANNER =
|
|
24
27
|
`# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.\n` +
|
|
25
28
|
`# See https://redoc.ly/docs/cli/ for more information.\n`;
|
|
26
29
|
|
|
27
30
|
export const DEFAULT_REGION = 'us';
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
|
|
32
|
+
function getDomains() {
|
|
33
|
+
const domains: { [region in Region]: string } = {
|
|
34
|
+
us: 'redocly.com',
|
|
35
|
+
eu: 'eu.redocly.com',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// FIXME: temporary fix for our lab environments
|
|
39
|
+
const domain = env.REDOCLY_DOMAIN;
|
|
40
|
+
if (domain?.endsWith('.redocly.host')) {
|
|
41
|
+
domains[domain.split('.')[0] as Region] = domain;
|
|
42
|
+
}
|
|
43
|
+
if (domain === 'redoc.online') {
|
|
44
|
+
domains[domain as Region] = domain;
|
|
45
|
+
}
|
|
46
|
+
return domains;
|
|
40
47
|
}
|
|
48
|
+
|
|
49
|
+
export const DOMAINS = getDomains();
|
|
41
50
|
export const AVAILABLE_REGIONS = Object.keys(DOMAINS) as Region[];
|
|
42
51
|
|
|
43
52
|
export class LintConfig {
|
package/src/format/format.ts
CHANGED
|
@@ -14,6 +14,7 @@ const coreVersion = require('../../package.json').version;
|
|
|
14
14
|
|
|
15
15
|
import { NormalizedProblem, ProblemSeverity, LineColLocationObject, LocationObject } from '../walk';
|
|
16
16
|
import { getCodeframe, getLineColLocation } from './codeframes';
|
|
17
|
+
import { env } from "../config";
|
|
17
18
|
|
|
18
19
|
export type Totals = {
|
|
19
20
|
errors: number;
|
|
@@ -202,7 +203,7 @@ export function formatProblems(
|
|
|
202
203
|
: undefined,
|
|
203
204
|
};
|
|
204
205
|
|
|
205
|
-
if (
|
|
206
|
+
if (env.FORMAT_JSON_WITH_CODEFRAMES) {
|
|
206
207
|
const location = p.location[0]; // TODO: support multiple locations
|
|
207
208
|
const loc = getLineColLocation(location);
|
|
208
209
|
(problem as any).codeframe = getCodeframe(loc, color);
|
package/src/redocly/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
3
|
import { homedir } from 'os';
|
|
4
|
-
import {
|
|
4
|
+
import { green } from 'colorette';
|
|
5
5
|
import { RegistryApi } from './registry-api';
|
|
6
|
-
import { DEFAULT_REGION, DOMAINS, AVAILABLE_REGIONS } from '../config/config';
|
|
6
|
+
import { DEFAULT_REGION, DOMAINS, AVAILABLE_REGIONS, env } from '../config/config';
|
|
7
7
|
import { RegionalToken, RegionalTokenWithValidity } from './redocly-client-types';
|
|
8
8
|
import { isNotEmptyObject } from '../utils';
|
|
9
9
|
|
|
@@ -11,7 +11,6 @@ import type { AccessTokens, Region } from '../config/types';
|
|
|
11
11
|
|
|
12
12
|
const TOKEN_FILENAME = '.redocly-config.json';
|
|
13
13
|
|
|
14
|
-
let REDOCLY_DOMAIN: string; // workaround for the isRedoclyRegistryURL, see more below
|
|
15
14
|
export class RedoclyClient {
|
|
16
15
|
private accessTokens: AccessTokens = {};
|
|
17
16
|
private region: Region;
|
|
@@ -21,31 +20,20 @@ export class RedoclyClient {
|
|
|
21
20
|
constructor(region?: Region) {
|
|
22
21
|
this.region = this.loadRegion(region);
|
|
23
22
|
this.loadTokens();
|
|
24
|
-
this.domain = region ? DOMAINS[region] :
|
|
23
|
+
this.domain = region ? DOMAINS[region] : env.REDOCLY_DOMAIN || DOMAINS[DEFAULT_REGION];
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
* We can't use process.env here because it is replaced by a const in some client-side bundles,
|
|
28
|
-
* which breaks assignment.
|
|
29
|
-
*/
|
|
30
|
-
REDOCLY_DOMAIN = this.domain; // isRedoclyRegistryURL depends on the value to be set
|
|
25
|
+
env.REDOCLY_DOMAIN = this.domain; // isRedoclyRegistryURL depends on the value to be set
|
|
31
26
|
this.registryApi = new RegistryApi(this.accessTokens, this.region);
|
|
32
27
|
}
|
|
33
28
|
|
|
34
29
|
loadRegion(region?: Region) {
|
|
35
30
|
if (region && !DOMAINS[region]) {
|
|
36
|
-
|
|
37
|
-
red(
|
|
38
|
-
`Invalid argument: region in config file.\nGiven: ${green(
|
|
39
|
-
region,
|
|
40
|
-
)}, choices: "us", "eu".\n`,
|
|
41
|
-
),
|
|
42
|
-
);
|
|
43
|
-
process.exit(1);
|
|
31
|
+
throw new Error(`Invalid argument: region in config file.\nGiven: ${green(region)}, choices: "us", "eu".`);
|
|
44
32
|
}
|
|
45
33
|
|
|
46
|
-
if (
|
|
34
|
+
if (env.REDOCLY_DOMAIN) {
|
|
47
35
|
return (AVAILABLE_REGIONS.find(
|
|
48
|
-
(region) => DOMAINS[region as Region] ===
|
|
36
|
+
(region) => DOMAINS[region as Region] === env.REDOCLY_DOMAIN,
|
|
49
37
|
) || DEFAULT_REGION) as Region;
|
|
50
38
|
}
|
|
51
39
|
return region || DEFAULT_REGION;
|
|
@@ -65,18 +53,7 @@ export class RedoclyClient {
|
|
|
65
53
|
}
|
|
66
54
|
|
|
67
55
|
async getAuthorizationHeader(): Promise<string | undefined> {
|
|
68
|
-
|
|
69
|
-
// print this only if there is token but invalid
|
|
70
|
-
if (token && !this.isAuthorizedWithRedoclyByRegion()) {
|
|
71
|
-
process.stderr.write(
|
|
72
|
-
`${yellow(
|
|
73
|
-
'Warning:',
|
|
74
|
-
)} invalid Redocly API key. Use "npx @redocly/cli login" to provide your API key\n`,
|
|
75
|
-
);
|
|
76
|
-
return undefined;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return token;
|
|
56
|
+
return this.accessTokens[this.region];
|
|
80
57
|
}
|
|
81
58
|
// </backward compatibility: portal>
|
|
82
59
|
|
|
@@ -96,10 +73,10 @@ export class RedoclyClient {
|
|
|
96
73
|
}),
|
|
97
74
|
});
|
|
98
75
|
}
|
|
99
|
-
if (
|
|
76
|
+
if (env.REDOCLY_AUTHORIZATION) {
|
|
100
77
|
this.setAccessTokens({
|
|
101
78
|
...this.accessTokens,
|
|
102
|
-
[this.region]:
|
|
79
|
+
[this.region]: env.REDOCLY_AUTHORIZATION,
|
|
103
80
|
});
|
|
104
81
|
}
|
|
105
82
|
}
|
|
@@ -164,15 +141,11 @@ export class RedoclyClient {
|
|
|
164
141
|
|
|
165
142
|
async login(accessToken: string, verbose: boolean = false) {
|
|
166
143
|
const credentialsPath = resolve(homedir(), TOKEN_FILENAME);
|
|
167
|
-
process.stdout.write(gray('\n Logging in...\n'));
|
|
168
144
|
|
|
169
145
|
try {
|
|
170
146
|
await this.verifyToken(accessToken, this.region, verbose);
|
|
171
147
|
} catch (err) {
|
|
172
|
-
|
|
173
|
-
red('Authorization failed. Please check if you entered a valid API key.\n'),
|
|
174
|
-
);
|
|
175
|
-
process.exit(1);
|
|
148
|
+
throw new Error('Authorization failed. Please check if you entered a valid API key.');
|
|
176
149
|
}
|
|
177
150
|
|
|
178
151
|
const credentials = {
|
|
@@ -183,7 +156,6 @@ export class RedoclyClient {
|
|
|
183
156
|
this.accessTokens = credentials;
|
|
184
157
|
this.registryApi.setAccessTokens(credentials);
|
|
185
158
|
writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2));
|
|
186
|
-
process.stdout.write(green(' Authorization confirmed. ✅\n\n'));
|
|
187
159
|
}
|
|
188
160
|
|
|
189
161
|
logout(): void {
|
|
@@ -191,12 +163,11 @@ export class RedoclyClient {
|
|
|
191
163
|
if (existsSync(credentialsPath)) {
|
|
192
164
|
unlinkSync(credentialsPath);
|
|
193
165
|
}
|
|
194
|
-
process.stdout.write('Logged out from the Redocly account. ✋\n');
|
|
195
166
|
}
|
|
196
167
|
}
|
|
197
168
|
|
|
198
169
|
export function isRedoclyRegistryURL(link: string): boolean {
|
|
199
|
-
const domain =
|
|
170
|
+
const domain = env.REDOCLY_DOMAIN || DOMAINS[DEFAULT_REGION];
|
|
200
171
|
|
|
201
172
|
const legacyDomain = domain === 'redocly.com' ? 'redoc.ly' : domain;
|
|
202
173
|
|
|
@@ -104,6 +104,7 @@ export class RegistryApi {
|
|
|
104
104
|
filePaths,
|
|
105
105
|
branch,
|
|
106
106
|
isUpsert,
|
|
107
|
+
isPublic,
|
|
107
108
|
}: RegistryApiTypes.PushApiParams) {
|
|
108
109
|
const response = await this.request(
|
|
109
110
|
`/${organizationId}/${name}/${version}`,
|
|
@@ -118,6 +119,7 @@ export class RegistryApi {
|
|
|
118
119
|
filePaths,
|
|
119
120
|
branch,
|
|
120
121
|
isUpsert,
|
|
122
|
+
isPublic,
|
|
121
123
|
}),
|
|
122
124
|
},
|
|
123
125
|
this.region,
|
package/src/ref-utils.ts
CHANGED