@redocly/openapi-core 1.9.0 → 1.10.0

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.
Files changed (67) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/lib/bundle.d.ts +1 -1
  3. package/lib/bundle.js +2 -2
  4. package/lib/config/config.d.ts +0 -6
  5. package/lib/config/config.js +1 -19
  6. package/lib/config/load.js +2 -2
  7. package/lib/decorators/common/registry-dependencies.js +2 -2
  8. package/lib/index.d.ts +3 -2
  9. package/lib/index.js +17 -2
  10. package/lib/lint.d.ts +1 -0
  11. package/lib/lint.js +1 -1
  12. package/lib/oas-types.d.ts +1 -1
  13. package/lib/redocly/domains.d.ts +14 -0
  14. package/lib/redocly/domains.js +41 -0
  15. package/lib/redocly/index.d.ts +1 -2
  16. package/lib/redocly/index.js +14 -24
  17. package/lib/redocly/registry-api.d.ts +2 -2
  18. package/lib/redocly/registry-api.js +9 -9
  19. package/lib/ref-utils.js +2 -2
  20. package/lib/resolve.js +9 -1
  21. package/lib/types/index.d.ts +7 -7
  22. package/lib/types/json-schema-adapter.d.ts +3 -0
  23. package/lib/types/json-schema-adapter.js +173 -0
  24. package/lib/types/oas2.d.ts +3 -2
  25. package/lib/types/oas3.d.ts +3 -2
  26. package/lib/types/oas3_1.d.ts +3 -2
  27. package/lib/types/portal-config-schema.d.ts +5261 -52
  28. package/lib/types/portal-config-schema.js +71 -55
  29. package/lib/types/redocly-yaml.d.ts +13 -1
  30. package/lib/types/redocly-yaml.js +101 -39
  31. package/lib/types/theme-config.d.ts +819 -36
  32. package/lib/types/theme-config.js +67 -29
  33. package/lib/utils.d.ts +4 -2
  34. package/lib/utils.js +7 -1
  35. package/lib/visitors.js +1 -1
  36. package/lib/walk.js +7 -1
  37. package/package.json +2 -1
  38. package/src/__tests__/lint.test.ts +1218 -36
  39. package/src/__tests__/ref-utils.test.ts +22 -0
  40. package/src/bundle.ts +1 -1
  41. package/src/config/__tests__/load.test.ts +13 -13
  42. package/src/config/config.ts +1 -23
  43. package/src/config/load.ts +2 -1
  44. package/src/decorators/common/registry-dependencies.ts +1 -1
  45. package/src/decorators/oas2/remove-unused-components.ts +3 -2
  46. package/src/decorators/oas3/remove-unused-components.ts +3 -2
  47. package/src/index.ts +11 -2
  48. package/src/lint.ts +2 -1
  49. package/src/redocly/__tests__/domains.test.ts +52 -0
  50. package/src/redocly/__tests__/redocly-client.test.ts +5 -3
  51. package/src/redocly/domains.ts +48 -0
  52. package/src/redocly/index.ts +14 -24
  53. package/src/redocly/registry-api.ts +25 -31
  54. package/src/ref-utils.ts +2 -2
  55. package/src/resolve.ts +13 -1
  56. package/src/types/index.ts +7 -12
  57. package/src/types/json-schema-adapter.ts +217 -0
  58. package/src/types/oas2.ts +5 -2
  59. package/src/types/oas3.ts +6 -2
  60. package/src/types/oas3_1.ts +5 -2
  61. package/src/types/portal-config-schema.ts +111 -61
  62. package/src/types/redocly-yaml.ts +118 -43
  63. package/src/types/theme-config.ts +125 -27
  64. package/src/utils.ts +9 -3
  65. package/src/visitors.ts +1 -1
  66. package/src/walk.ts +7 -1
  67. package/tsconfig.tsbuildinfo +1 -1
@@ -96,6 +96,28 @@ describe('ref-utils', () => {
96
96
  expect(result).toMatchInlineSnapshot(`[]`);
97
97
  });
98
98
 
99
+ it('should parse a ref correctly', () => {
100
+ expect(parseRef('./info.yaml#/description')).toEqual({
101
+ uri: './info.yaml',
102
+ pointer: ['description'],
103
+ });
104
+ });
105
+
106
+ it('should parse a ref which contain a hash in the middle', () => {
107
+ // Here `info#description.md` is a file name
108
+ expect(parseRef('./info#description.md')).toEqual({
109
+ uri: './info#description.md',
110
+ pointer: [],
111
+ });
112
+ });
113
+
114
+ it('should parse a ref which ends with a hash', () => {
115
+ expect(parseRef('./info.yaml#')).toEqual({
116
+ uri: './info.yaml',
117
+ pointer: [],
118
+ });
119
+ });
120
+
99
121
  describe('refBaseName', () => {
100
122
  it('returns base name for file reference', () => {
101
123
  expect(refBaseName('../testcase/Pet.yaml')).toStrictEqual('Pet');
package/src/bundle.ts CHANGED
@@ -14,7 +14,7 @@ import { isAbsoluteUrl, isRef, Location, refBaseName } from './ref-utils';
14
14
  import { initRules } from './config/rules';
15
15
  import { reportUnresolvedRef } from './rules/no-unresolved-refs';
16
16
  import { isPlainObject, isTruthy } from './utils';
17
- import { isRedoclyRegistryURL } from './redocly';
17
+ import { isRedoclyRegistryURL } from './redocly/domains';
18
18
  import { RemoveUnusedComponents as RemoveUnusedComponentsOas2 } from './decorators/oas2/remove-unused-components';
19
19
  import { RemoveUnusedComponents as RemoveUnusedComponentsOas3 } from './decorators/oas3/remove-unused-components';
20
20
  import { ConfigTypes } from './types/redocly-yaml';
@@ -137,6 +137,19 @@ describe('getConfig', () => {
137
137
  "severity": "warn",
138
138
  "suggest": [],
139
139
  },
140
+ {
141
+ "location": [
142
+ {
143
+ "pointer": "#/theme",
144
+ "reportOnKey": false,
145
+ "source": "fixtures/resolve-refs-in-config/config-with-refs.yaml",
146
+ },
147
+ ],
148
+ "message": "Can't resolve $ref: ENOENT: no such file or directory 'fixtures/resolve-refs-in-config/wrong-ref.yaml'",
149
+ "ruleId": "configuration no-unresolved-refs",
150
+ "severity": "warn",
151
+ "suggest": [],
152
+ },
140
153
  {
141
154
  "from": {
142
155
  "pointer": "#/rules",
@@ -154,19 +167,6 @@ describe('getConfig', () => {
154
167
  "severity": "warn",
155
168
  "suggest": [],
156
169
  },
157
- {
158
- "location": [
159
- {
160
- "pointer": "#/theme",
161
- "reportOnKey": false,
162
- "source": "fixtures/resolve-refs-in-config/config-with-refs.yaml",
163
- },
164
- ],
165
- "message": "Can't resolve $ref: ENOENT: no such file or directory 'fixtures/resolve-refs-in-config/wrong-ref.yaml'",
166
- "ruleId": "configuration no-unresolved-refs",
167
- "severity": "warn",
168
- "suggest": [],
169
- },
170
170
  ]
171
171
  `);
172
172
  });
@@ -10,7 +10,7 @@ import {
10
10
  Oas3RuleSet,
11
11
  Async2RuleSet,
12
12
  } from '../oas-types';
13
- import { isBrowser, env } from '../env';
13
+ import { isBrowser } from '../env';
14
14
 
15
15
  import type { NodeType } from '../types';
16
16
  import type {
@@ -35,25 +35,6 @@ const IGNORE_BANNER =
35
35
  `# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.\n` +
36
36
  `# See https://redoc.ly/docs/cli/ for more information.\n`;
37
37
 
38
- export const DEFAULT_REGION = 'us';
39
-
40
- function getDomains() {
41
- const domains: { [region in Region]: string } = {
42
- us: 'redocly.com',
43
- eu: 'eu.redocly.com',
44
- };
45
-
46
- // FIXME: temporary fix for our lab environments
47
- const domain = env.REDOCLY_DOMAIN;
48
- if (domain?.endsWith('.redocly.host')) {
49
- domains[domain.split('.')[0] as Region] = domain;
50
- }
51
- if (domain === 'redoc.online') {
52
- domains[domain as Region] = domain;
53
- }
54
- return domains;
55
- }
56
-
57
38
  function getIgnoreFilePath(configFile?: string): string | undefined {
58
39
  if (configFile) {
59
40
  return doesYamlFileExist(configFile)
@@ -64,9 +45,6 @@ function getIgnoreFilePath(configFile?: string): string | undefined {
64
45
  }
65
46
  }
66
47
 
67
- export const DOMAINS = getDomains();
68
- export const AVAILABLE_REGIONS = Object.keys(DOMAINS) as Region[];
69
-
70
48
  export class StyleguideConfig {
71
49
  plugins: Plugin[];
72
50
  ignore: Record<string, Record<string, Set<string>>> = {};
@@ -3,7 +3,7 @@ import * as path from 'path';
3
3
  import { RedoclyClient } from '../redocly';
4
4
  import { isEmptyObject, doesYamlFileExist } from '../utils';
5
5
  import { parseYaml } from '../js-yaml';
6
- import { Config, DOMAINS } from './config';
6
+ import { Config } from './config';
7
7
  import { ConfigValidationError, transformConfig } from './utils';
8
8
  import { resolveConfig, resolveConfigFileAndRefs } from './config-resolvers';
9
9
  import { bundleConfig } from '../bundle';
@@ -12,6 +12,7 @@ import type { Document } from '../resolve';
12
12
  import type { RegionalTokenWithValidity } from '../redocly/redocly-client-types';
13
13
  import type { RawConfig, RawUniversalConfig, Region } from './types';
14
14
  import type { BaseResolver, ResolvedRefMap } from '../resolve';
15
+ import { DOMAINS } from '../redocly/domains';
15
16
 
16
17
  async function addConfigMetadata({
17
18
  rawConfig,
@@ -1,5 +1,5 @@
1
1
  import { UserContext } from '../../walk';
2
- import { isRedoclyRegistryURL } from '../../redocly';
2
+ import { isRedoclyRegistryURL } from '../../redocly/domains';
3
3
 
4
4
  import { Oas3Decorator, Oas2Decorator } from '../../visitors';
5
5
 
@@ -1,8 +1,9 @@
1
- import type { Oas2Decorator } from '../../visitors';
2
1
  import { Location } from '../../ref-utils';
3
- import type { Oas2Components } from '../../typings/swagger';
4
2
  import { isEmptyObject } from '../../utils';
5
3
 
4
+ import type { Oas2Decorator } from '../../visitors';
5
+ import type { Oas2Components } from '../../typings/swagger';
6
+
6
7
  export const RemoveUnusedComponents: Oas2Decorator = () => {
7
8
  const components = new Map<
8
9
  string,
@@ -1,8 +1,9 @@
1
- import type { Oas3Decorator } from '../../visitors';
2
1
  import { Location } from '../../ref-utils';
3
- import type { Oas3Components } from '../../typings/openapi';
4
2
  import { isEmptyObject } from '../../utils';
5
3
 
4
+ import type { Oas3Decorator } from '../../visitors';
5
+ import type { Oas3Components } from '../../typings/openapi';
6
+
6
7
  export const RemoveUnusedComponents: Oas3Decorator = () => {
7
8
  const components = new Map<
8
9
  string,
package/src/index.ts CHANGED
@@ -1,4 +1,11 @@
1
- export { BundleOutputFormat, readFileFromUrl, slash, doesYamlFileExist, isTruthy } from './utils';
1
+ export {
2
+ BundleOutputFormat,
3
+ readFileFromUrl,
4
+ slash,
5
+ doesYamlFileExist,
6
+ isTruthy,
7
+ getProxyAgent,
8
+ } from './utils';
2
9
  export { Oas3_1Types } from './types/oas3_1';
3
10
  export { Oas3Types } from './types/oas3';
4
11
  export { Oas2Types } from './types/oas2';
@@ -41,7 +48,9 @@ export {
41
48
  ResolvedApi,
42
49
  } from './config';
43
50
 
44
- export { RedoclyClient, isRedoclyRegistryURL } from './redocly';
51
+ export { RedoclyClient } from './redocly';
52
+
53
+ export * from './redocly/domains';
45
54
 
46
55
  export {
47
56
  Source,
package/src/lint.ts CHANGED
@@ -112,6 +112,7 @@ export async function lintConfig(opts: {
112
112
  resolvedRefMap?: ResolvedRefMap;
113
113
  severity?: ProblemSeverity;
114
114
  externalRefResolver?: BaseResolver;
115
+ externalConfigTypes?: Record<string, NodeType>;
115
116
  }) {
116
117
  const { document, severity, externalRefResolver = new BaseResolver() } = opts;
117
118
 
@@ -126,7 +127,7 @@ export async function lintConfig(opts: {
126
127
  rules: { spec: 'error' },
127
128
  });
128
129
 
129
- const types = normalizeTypes(ConfigTypes, config);
130
+ const types = normalizeTypes(opts.externalConfigTypes || ConfigTypes, config);
130
131
  const rules: (RuleInstanceConfig & {
131
132
  visitor: NestedVisitObject<unknown, Oas3Visitor | Oas3Visitor[]>;
132
133
  })[] = [
@@ -0,0 +1,52 @@
1
+ import { RedoclyClient } from '../../index';
2
+ import { setRedoclyDomain, getRedoclyDomain, getDomains, AVAILABLE_REGIONS } from '../domains';
3
+
4
+ describe('domains', () => {
5
+ const REDOCLY_DOMAIN_US = 'redocly.com';
6
+ const TEST_DOMAIN = 'redoclyDomain.com';
7
+ const TEST_LAB_DOMAIN = 'lab.redocly.host';
8
+ const TEST_REDOC_ONLINE_DOMAIN = 'redoc.online';
9
+
10
+ afterEach(() => {
11
+ delete process.env.REDOCLY_DOMAIN;
12
+ setRedoclyDomain('');
13
+ });
14
+
15
+ it('should resolve the US domain by default', () => {
16
+ expect(getRedoclyDomain()).toBe(REDOCLY_DOMAIN_US);
17
+ });
18
+
19
+ it('should resolve the US and EU regions by default', () => {
20
+ expect(AVAILABLE_REGIONS).toStrictEqual(['us', 'eu']);
21
+ });
22
+
23
+ it('should resolve the specified domain if used with setter', () => {
24
+ setRedoclyDomain(TEST_DOMAIN);
25
+ expect(getRedoclyDomain()).toBe(TEST_DOMAIN);
26
+ });
27
+
28
+ it('should resolve the specified domain provided in environmental variable, after initializing RedoclyClient', () => {
29
+ process.env.REDOCLY_DOMAIN = TEST_DOMAIN;
30
+ const client = new RedoclyClient();
31
+ expect(getRedoclyDomain()).toBe(TEST_DOMAIN);
32
+ expect(client.domain).toBe(TEST_DOMAIN);
33
+ });
34
+
35
+ it('should return correct object when redocly domain is set to lab env', () => {
36
+ setRedoclyDomain(TEST_LAB_DOMAIN);
37
+ const domains = getDomains();
38
+ expect(domains).toEqual({ us: 'redocly.com', eu: 'eu.redocly.com', lab: 'lab.redocly.host' });
39
+ expect(getRedoclyDomain()).toBe(TEST_LAB_DOMAIN);
40
+ });
41
+
42
+ it('should return correct object when redocly domain is set to redoc.online env', () => {
43
+ setRedoclyDomain(TEST_REDOC_ONLINE_DOMAIN);
44
+ const domains = getDomains();
45
+ expect(domains).toEqual({
46
+ us: 'redocly.com',
47
+ eu: 'eu.redocly.com',
48
+ 'redoc.online': 'redoc.online',
49
+ });
50
+ expect(getRedoclyDomain()).toBe(TEST_REDOC_ONLINE_DOMAIN);
51
+ });
52
+ });
@@ -1,3 +1,4 @@
1
+ import { setRedoclyDomain } from '../domains';
1
2
  import { RedoclyClient } from '../index';
2
3
 
3
4
  jest.mock('node-fetch', () => ({
@@ -16,6 +17,7 @@ describe('RedoclyClient', () => {
16
17
 
17
18
  afterEach(() => {
18
19
  delete process.env.REDOCLY_DOMAIN;
20
+ setRedoclyDomain('');
19
21
  });
20
22
 
21
23
  it('should resolve the US domain by default', () => {
@@ -40,19 +42,19 @@ describe('RedoclyClient', () => {
40
42
  });
41
43
 
42
44
  it('should resolve domain by EU region prioritizing flag over env variable', () => {
43
- process.env.REDOCLY_DOMAIN = testRedoclyDomain;
45
+ setRedoclyDomain(testRedoclyDomain);
44
46
  const client = new RedoclyClient('eu');
45
47
  expect(client.domain).toBe(REDOCLY_DOMAIN_EU);
46
48
  });
47
49
 
48
50
  it('should resolve domain by US region prioritizing flag over env variable', () => {
49
- process.env.REDOCLY_DOMAIN = testRedoclyDomain;
51
+ setRedoclyDomain(testRedoclyDomain);
50
52
  const client = new RedoclyClient('us');
51
53
  expect(client.domain).toBe(REDOCLY_DOMAIN_US);
52
54
  });
53
55
 
54
56
  it('should resolve domain by US region when REDOCLY_DOMAIN consists EU domain', () => {
55
- process.env.REDOCLY_DOMAIN = REDOCLY_DOMAIN_EU;
57
+ setRedoclyDomain(REDOCLY_DOMAIN_EU);
56
58
  const client = new RedoclyClient();
57
59
  expect(client.getRegion()).toBe('eu');
58
60
  });
@@ -0,0 +1,48 @@
1
+ import { Region } from '../config/types';
2
+
3
+ let redoclyDomain = 'redocly.com';
4
+
5
+ export const DEFAULT_REGION = 'us';
6
+
7
+ export const DOMAINS = getDomains();
8
+ export const AVAILABLE_REGIONS = Object.keys(DOMAINS) as Region[];
9
+
10
+ export function getDomains() {
11
+ const domains: { [region in Region]: string } = {
12
+ us: 'redocly.com',
13
+ eu: 'eu.redocly.com',
14
+ };
15
+
16
+ // FIXME: temporary fix for our lab environments
17
+ const domain = redoclyDomain;
18
+ if (domain?.endsWith('.redocly.host')) {
19
+ domains[domain.split('.')[0] as Region] = domain;
20
+ }
21
+ if (domain === 'redoc.online') {
22
+ domains[domain as Region] = domain;
23
+ }
24
+ return domains;
25
+ }
26
+
27
+ export function setRedoclyDomain(domain: string) {
28
+ redoclyDomain = domain;
29
+ }
30
+
31
+ export function getRedoclyDomain(): string {
32
+ return redoclyDomain;
33
+ }
34
+
35
+ export function isRedoclyRegistryURL(link: string): boolean {
36
+ const domain = getRedoclyDomain() || DOMAINS[DEFAULT_REGION];
37
+
38
+ const legacyDomain = domain === 'redocly.com' ? 'redoc.ly' : domain;
39
+
40
+ if (
41
+ !link.startsWith(`https://api.${domain}/registry/`) &&
42
+ !link.startsWith(`https://api.${legacyDomain}/registry/`)
43
+ ) {
44
+ return false;
45
+ }
46
+
47
+ return true;
48
+ }
@@ -2,13 +2,19 @@ import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
2
2
  import { resolve } from 'path';
3
3
  import { homedir } from 'os';
4
4
  import { RegistryApi } from './registry-api';
5
- import { DEFAULT_REGION, DOMAINS, AVAILABLE_REGIONS } from '../config/config';
6
5
  import { env } from '../env';
7
6
  import { RegionalToken, RegionalTokenWithValidity } from './redocly-client-types';
8
7
  import { isNotEmptyObject } from '../utils';
9
8
  import { colorize } from '../logger';
10
9
 
11
10
  import type { AccessTokens, Region } from '../config/types';
11
+ import {
12
+ AVAILABLE_REGIONS,
13
+ DEFAULT_REGION,
14
+ DOMAINS,
15
+ getRedoclyDomain,
16
+ setRedoclyDomain,
17
+ } from './domains';
12
18
 
13
19
  export const TOKEN_FILENAME = '.redocly-config.json';
14
20
 
@@ -23,7 +29,7 @@ export class RedoclyClient {
23
29
  this.loadTokens();
24
30
  this.domain = region ? DOMAINS[region] : env.REDOCLY_DOMAIN || DOMAINS[DEFAULT_REGION];
25
31
 
26
- env.REDOCLY_DOMAIN = this.domain; // isRedoclyRegistryURL depends on the value to be set
32
+ setRedoclyDomain(this.domain);
27
33
  this.registryApi = new RegistryApi(this.accessTokens, this.region);
28
34
  }
29
35
 
@@ -36,9 +42,9 @@ export class RedoclyClient {
36
42
  );
37
43
  }
38
44
 
39
- if (env.REDOCLY_DOMAIN) {
45
+ if (getRedoclyDomain()) {
40
46
  return (AVAILABLE_REGIONS.find(
41
- (region) => DOMAINS[region as Region] === env.REDOCLY_DOMAIN
47
+ (region) => DOMAINS[region as Region] === getRedoclyDomain()
42
48
  ) || DEFAULT_REGION) as Region;
43
49
  }
44
50
  return region || DEFAULT_REGION;
@@ -96,7 +102,7 @@ export class RedoclyClient {
96
102
  const allTokens = this.getAllTokens();
97
103
 
98
104
  const verifiedTokens = await Promise.allSettled(
99
- allTokens.map(({ token, region }) => this.verifyToken(token, region))
105
+ allTokens.map(({ token }) => this.verifyToken(token))
100
106
  );
101
107
 
102
108
  return allTokens
@@ -120,7 +126,7 @@ export class RedoclyClient {
120
126
  }
121
127
 
122
128
  try {
123
- await this.verifyToken(accessToken, this.region);
129
+ await this.verifyToken(accessToken);
124
130
 
125
131
  return true;
126
132
  } catch (err) {
@@ -138,17 +144,16 @@ export class RedoclyClient {
138
144
 
139
145
  async verifyToken(
140
146
  accessToken: string,
141
- region: Region,
142
147
  verbose: boolean = false
143
148
  ): Promise<{ viewerId: string; organizations: string[] }> {
144
- return this.registryApi.authStatus(accessToken, region, verbose);
149
+ return this.registryApi.authStatus(accessToken, verbose);
145
150
  }
146
151
 
147
152
  async login(accessToken: string, verbose: boolean = false) {
148
153
  const credentialsPath = resolve(homedir(), TOKEN_FILENAME);
149
154
 
150
155
  try {
151
- await this.verifyToken(accessToken, this.region, verbose);
156
+ await this.verifyToken(accessToken, verbose);
152
157
  } catch (err) {
153
158
  throw new Error('Authorization failed. Please check if you entered a valid API key.');
154
159
  }
@@ -170,18 +175,3 @@ export class RedoclyClient {
170
175
  }
171
176
  }
172
177
  }
173
-
174
- export function isRedoclyRegistryURL(link: string): boolean {
175
- const domain = env.REDOCLY_DOMAIN || DOMAINS[DEFAULT_REGION];
176
-
177
- const legacyDomain = domain === 'redocly.com' ? 'redoc.ly' : domain;
178
-
179
- if (
180
- !link.startsWith(`https://api.${domain}/registry/`) &&
181
- !link.startsWith(`https://api.${legacyDomain}/registry/`)
182
- ) {
183
- return false;
184
- }
185
-
186
- return true;
187
- }
@@ -6,8 +6,8 @@ import type {
6
6
  PushApiParams,
7
7
  } from './registry-api-types';
8
8
  import type { AccessTokens, Region } from '../config/types';
9
- import { DEFAULT_REGION, DOMAINS } from '../config/config';
10
- import { isNotEmptyObject } from '../utils';
9
+ import { getProxyAgent, isNotEmptyObject } from '../utils';
10
+ import { getRedoclyDomain } from './domains';
11
11
 
12
12
  const version = require('../../package.json').version;
13
13
 
@@ -18,8 +18,8 @@ export class RegistryApi {
18
18
  return isNotEmptyObject(this.accessTokens) && this.accessTokens[this.region];
19
19
  }
20
20
 
21
- getBaseUrl(region: Region = DEFAULT_REGION) {
22
- return `https://api.${DOMAINS[region]}/registry`;
21
+ getBaseUrl() {
22
+ return `https://api.${getRedoclyDomain()}/registry`;
23
23
  }
24
24
 
25
25
  setAccessTokens(accessTokens: AccessTokens) {
@@ -27,7 +27,7 @@ export class RegistryApi {
27
27
  return this;
28
28
  }
29
29
 
30
- private async request(path = '', options: RequestInit = {}, region?: Region) {
30
+ private async request(path = '', options: RequestInit = {}) {
31
31
  const currentCommand =
32
32
  typeof process !== 'undefined' ? process.env?.REDOCLY_CLI_COMMAND || '' : '';
33
33
  const redoclyEnv = typeof process !== 'undefined' ? process.env?.REDOCLY_ENVIRONMENT || '' : '';
@@ -42,8 +42,8 @@ export class RegistryApi {
42
42
  }
43
43
 
44
44
  const response = await fetch(
45
- `${this.getBaseUrl(region)}${path}`,
46
- Object.assign({}, options, { headers })
45
+ `${this.getBaseUrl()}${path}`,
46
+ Object.assign({}, options, { headers, agent: getProxyAgent() })
47
47
  );
48
48
 
49
49
  if (response.status === 401) {
@@ -60,11 +60,10 @@ export class RegistryApi {
60
60
 
61
61
  async authStatus(
62
62
  accessToken: string,
63
- region: Region,
64
63
  verbose = false
65
64
  ): Promise<{ viewerId: string; organizations: string[] }> {
66
65
  try {
67
- const response = await this.request('', { headers: { authorization: accessToken } }, region);
66
+ const response = await this.request('', { headers: { authorization: accessToken } });
68
67
 
69
68
  return await response.json();
70
69
  } catch (error) {
@@ -97,8 +96,7 @@ export class RegistryApi {
97
96
  filename,
98
97
  isUpsert,
99
98
  }),
100
- },
101
- this.region
99
+ }
102
100
  );
103
101
 
104
102
  if (response.ok) {
@@ -120,26 +118,22 @@ export class RegistryApi {
120
118
  batchId,
121
119
  batchSize,
122
120
  }: PushApiParams) {
123
- const response = await this.request(
124
- `/${organizationId}/${name}/${version}`,
125
- {
126
- method: 'PUT',
127
- headers: {
128
- 'content-type': 'application/json',
129
- authorization: this.accessToken,
130
- } as HeadersInit,
131
- body: JSON.stringify({
132
- rootFilePath,
133
- filePaths,
134
- branch,
135
- isUpsert,
136
- isPublic,
137
- batchId,
138
- batchSize,
139
- }),
140
- },
141
- this.region
142
- );
121
+ const response = await this.request(`/${organizationId}/${name}/${version}`, {
122
+ method: 'PUT',
123
+ headers: {
124
+ 'content-type': 'application/json',
125
+ authorization: this.accessToken,
126
+ } as HeadersInit,
127
+ body: JSON.stringify({
128
+ rootFilePath,
129
+ filePaths,
130
+ branch,
131
+ isUpsert,
132
+ isPublic,
133
+ batchId,
134
+ batchSize,
135
+ }),
136
+ });
143
137
 
144
138
  if (response.ok) {
145
139
  return;
package/src/ref-utils.ts CHANGED
@@ -43,9 +43,9 @@ export function escapePointer<T extends string | number>(fragment: T): T {
43
43
  }
44
44
 
45
45
  export function parseRef(ref: string): { uri: string | null; pointer: string[] } {
46
- const [uri, pointer = ''] = ref.split('#');
46
+ const [uri, pointer = ''] = ref.split('#/');
47
47
  return {
48
- uri: uri || null,
48
+ uri: (uri.endsWith('#') ? uri.slice(0, -1) : uri) || null,
49
49
  pointer: parsePointer(pointer),
50
50
  };
51
51
  }
package/src/resolve.ts CHANGED
@@ -269,8 +269,20 @@ export async function resolveDocument(opts: {
269
269
  if (itemsType === undefined && type !== unknownType && type !== SpecExtension) {
270
270
  return;
271
271
  }
272
+ const isTypeAFunction = typeof itemsType === 'function';
272
273
  for (let i = 0; i < node.length; i++) {
273
- walk(node[i], itemsType || unknownType, joinPointer(nodeAbsoluteRef, i));
274
+ const itemType = isTypeAFunction
275
+ ? itemsType(node[i], joinPointer(nodeAbsoluteRef, i))
276
+ : itemsType;
277
+ // we continue resolving unknown types, but stop early on known scalars
278
+ if (itemType === undefined && type !== unknownType && type !== SpecExtension) {
279
+ continue;
280
+ }
281
+ walk(
282
+ node[i],
283
+ isNamedType(itemType) ? itemType : unknownType,
284
+ joinPointer(nodeAbsoluteRef, i)
285
+ );
274
286
  }
275
287
  return;
276
288
  }
@@ -21,31 +21,28 @@ export type NormalizedScalarSchema = {
21
21
  export type NodeType = {
22
22
  properties: Record<string, PropType | ResolveTypeFn>;
23
23
  additionalProperties?: PropType | ResolveTypeFn;
24
- items?: string;
24
+ items?: PropType | ResolveTypeFn;
25
25
  required?: string[] | ((value: any, key: string | number | undefined) => string[]);
26
26
  requiredOneOf?: string[];
27
27
  allowed?: (value: any) => string[] | undefined;
28
28
  extensionsPrefix?: string;
29
29
  };
30
- type PropType = string | NodeType | ScalarSchema | undefined | null;
31
- type ResolveTypeFn = (value: any, key: string) => string | PropType;
30
+ export type PropType = string | NodeType | ScalarSchema | undefined | null;
31
+ export type ResolveTypeFn = (value: any, key: string) => string | PropType;
32
32
 
33
33
  export type NormalizedNodeType = {
34
34
  name: string;
35
35
  properties: Record<string, NormalizedPropType | NormalizedResolveTypeFn>;
36
36
  additionalProperties?: NormalizedPropType | NormalizedResolveTypeFn;
37
- items?: NormalizedNodeType;
37
+ items?: NormalizedPropType | NormalizedResolveTypeFn;
38
38
  required?: string[] | ((value: any, key: string | number | undefined) => string[]);
39
39
  requiredOneOf?: string[];
40
40
  allowed?: (value: any) => string[] | undefined;
41
41
  extensionsPrefix?: string;
42
42
  };
43
43
 
44
- type NormalizedPropType = NormalizedNodeType | NormalizedScalarSchema | undefined | null;
45
- type NormalizedResolveTypeFn = (
46
- value: any,
47
- key: string
48
- ) => NormalizedNodeType | NormalizedScalarSchema | undefined | null;
44
+ type NormalizedPropType = NormalizedNodeType | NormalizedScalarSchema | null | undefined;
45
+ type NormalizedResolveTypeFn = (value: any, key: string) => NormalizedPropType;
49
46
 
50
47
  export function listOf(typeName: string) {
51
48
  return {
@@ -142,8 +139,6 @@ export function normalizeTypes(
142
139
  }
143
140
  }
144
141
 
145
- export function isNamedType(
146
- t: NormalizedNodeType | NormalizedScalarSchema | null | undefined
147
- ): t is NormalizedNodeType {
142
+ export function isNamedType(t: NormalizedPropType): t is NormalizedNodeType {
148
143
  return typeof t?.name === 'string';
149
144
  }