@redocly/openapi-core 1.5.0 → 1.7.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 (40) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/lib/bundle.d.ts +8 -6
  3. package/lib/bundle.js +48 -14
  4. package/lib/config/config-resolvers.d.ts +9 -1
  5. package/lib/config/config-resolvers.js +22 -1
  6. package/lib/config/load.d.ts +11 -3
  7. package/lib/config/load.js +12 -6
  8. package/lib/lint.d.ts +6 -3
  9. package/lib/lint.js +14 -3
  10. package/lib/rules/ajv.d.ts +2 -2
  11. package/lib/rules/ajv.js +2 -2
  12. package/lib/rules/utils.d.ts +2 -2
  13. package/lib/types/asyncapi.js +2 -8
  14. package/lib/types/portal-config-schema.d.ts +22 -2465
  15. package/lib/types/portal-config-schema.js +56 -38
  16. package/lib/types/redocly-yaml.js +4 -4
  17. package/lib/typings/openapi.d.ts +14 -11
  18. package/lib/visitors.d.ts +5 -5
  19. package/lib/visitors.js +4 -6
  20. package/lib/walk.d.ts +3 -3
  21. package/lib/walk.js +2 -2
  22. package/package.json +2 -2
  23. package/src/__tests__/lint.test.ts +2 -2
  24. package/src/bundle.ts +67 -26
  25. package/src/config/__tests__/fixtures/resolve-refs-in-config/config-with-refs.yaml +8 -0
  26. package/src/config/__tests__/fixtures/resolve-refs-in-config/rules.yaml +2 -0
  27. package/src/config/__tests__/fixtures/resolve-refs-in-config/seo.yaml +1 -0
  28. package/src/config/__tests__/load.test.ts +80 -1
  29. package/src/config/config-resolvers.ts +41 -11
  30. package/src/config/load.ts +36 -19
  31. package/src/lint.ts +32 -10
  32. package/src/rules/ajv.ts +6 -4
  33. package/src/rules/utils.ts +2 -2
  34. package/src/types/asyncapi.ts +2 -8
  35. package/src/types/portal-config-schema.ts +65 -42
  36. package/src/types/redocly-yaml.ts +2 -4
  37. package/src/typings/openapi.ts +15 -11
  38. package/src/visitors.ts +20 -22
  39. package/src/walk.ts +8 -8
  40. package/tsconfig.tsbuildinfo +1 -1
@@ -1,7 +1,7 @@
1
1
  import * as path from 'path';
2
2
  import { isAbsoluteUrl } from '../ref-utils';
3
3
  import { pickDefined } from '../utils';
4
- import { BaseResolver } from '../resolve';
4
+ import { resolveDocument, BaseResolver } from '../resolve';
5
5
  import { defaultPlugin } from './builtIn';
6
6
  import {
7
7
  getResolveConfig,
@@ -11,6 +11,14 @@ import {
11
11
  prefixRules,
12
12
  transformConfig,
13
13
  } from './utils';
14
+ import { isBrowser } from '../env';
15
+ import { isNotString, isString, isDefined, parseYaml, keysOf } from '../utils';
16
+ import { Config } from './config';
17
+ import { colorize, logger } from '../logger';
18
+ import { asserts, buildAssertCustomFunction } from '../rules/common/assertions/asserts';
19
+ import { normalizeTypes } from '../types';
20
+ import { ConfigTypes } from '../types/redocly-yaml';
21
+
14
22
  import type {
15
23
  StyleguideRawConfig,
16
24
  ApiStyleguideRawConfig,
@@ -21,17 +29,39 @@ import type {
21
29
  RuleConfig,
22
30
  DeprecatedInRawConfig,
23
31
  } from './types';
24
- import { isBrowser } from '../env';
25
- import { isNotString, isString, isDefined, parseYaml, keysOf } from '../utils';
26
- import { Config } from './config';
27
- import { colorize, logger } from '../logger';
28
- import {
29
- Asserts,
30
- AssertionFn,
31
- asserts,
32
- buildAssertCustomFunction,
33
- } from '../rules/common/assertions/asserts';
34
32
  import type { Assertion, AssertionDefinition, RawAssertion } from '../rules/common/assertions';
33
+ import type { Asserts, AssertionFn } from '../rules/common/assertions/asserts';
34
+ import type { BundleOptions } from '../bundle';
35
+ import type { Document, ResolvedRefMap } from '../resolve';
36
+
37
+ export async function resolveConfigFileAndRefs({
38
+ configPath,
39
+ externalRefResolver = new BaseResolver(),
40
+ base = null,
41
+ }: Omit<BundleOptions, 'config'> & { configPath?: string }): Promise<{
42
+ document: Document;
43
+ resolvedRefMap: ResolvedRefMap;
44
+ }> {
45
+ if (!configPath) {
46
+ throw new Error('Reference to a config is required.\n');
47
+ }
48
+
49
+ const document = await externalRefResolver.resolveDocument(base, configPath, true);
50
+
51
+ if (document instanceof Error) {
52
+ throw document;
53
+ }
54
+
55
+ const types = normalizeTypes(ConfigTypes);
56
+
57
+ const resolvedRefMap = await resolveDocument({
58
+ rootDocument: document,
59
+ rootType: types.ConfigRoot,
60
+ externalRefResolver,
61
+ });
62
+
63
+ return { document, resolvedRefMap };
64
+ }
35
65
 
36
66
  export async function resolveConfig(rawConfig: RawConfig, configPath?: string): Promise<Config> {
37
67
  if (rawConfig.styleguide?.extends?.some(isNotString)) {
@@ -1,20 +1,17 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { RedoclyClient } from '../redocly';
4
- import { isEmptyObject, loadYaml, doesYamlFileExist } from '../utils';
4
+ import { isEmptyObject, doesYamlFileExist } from '../utils';
5
5
  import { parseYaml } from '../js-yaml';
6
6
  import { Config, DOMAINS } from './config';
7
7
  import { ConfigValidationError, transformConfig } from './utils';
8
- import { resolveConfig } from './config-resolvers';
8
+ import { resolveConfig, resolveConfigFileAndRefs } from './config-resolvers';
9
+ import { bundleConfig } from '../bundle';
9
10
 
10
- import type {
11
- DeprecatedInRawConfig,
12
- FlatRawConfig,
13
- RawConfig,
14
- RawUniversalConfig,
15
- Region,
16
- } from './types';
17
- import { RegionalTokenWithValidity } from '../redocly/redocly-client-types';
11
+ import type { Document } from '../resolve';
12
+ import type { RegionalTokenWithValidity } from '../redocly/redocly-client-types';
13
+ import type { RawConfig, RawUniversalConfig, Region } from './types';
14
+ import type { BaseResolver, ResolvedRefMap } from '../resolve';
18
15
 
19
16
  async function addConfigMetadata({
20
17
  rawConfig,
@@ -73,17 +70,30 @@ async function addConfigMetadata({
73
70
  );
74
71
  }
75
72
 
73
+ export type RawConfigProcessor = (
74
+ rawConfig: Document,
75
+ resolvedRefMap: ResolvedRefMap
76
+ ) => void | Promise<void>;
77
+
76
78
  export async function loadConfig(
77
79
  options: {
78
80
  configPath?: string;
79
81
  customExtends?: string[];
80
- processRawConfig?: (rawConfig: RawConfig) => void | Promise<void>;
82
+ processRawConfig?: RawConfigProcessor;
83
+ externalRefResolver?: BaseResolver;
81
84
  files?: string[];
82
85
  region?: Region;
83
86
  } = {}
84
87
  ): Promise<Config> {
85
- const { configPath = findConfig(), customExtends, processRawConfig, files, region } = options;
86
- const rawConfig = await getConfig(configPath, processRawConfig);
88
+ const {
89
+ configPath = findConfig(),
90
+ customExtends,
91
+ processRawConfig,
92
+ files,
93
+ region,
94
+ externalRefResolver,
95
+ } = options;
96
+ const rawConfig = await getConfig({ configPath, processRawConfig, externalRefResolver });
87
97
 
88
98
  const redoclyClient = new RedoclyClient();
89
99
  const tokens = await redoclyClient.getTokens();
@@ -116,17 +126,24 @@ export function findConfig(dir?: string): string | undefined {
116
126
  }
117
127
 
118
128
  export async function getConfig(
119
- configPath: string | undefined = findConfig(),
120
- processRawConfig?: (rawConfig: RawConfig) => void | Promise<void>
129
+ options: {
130
+ configPath?: string;
131
+ processRawConfig?: RawConfigProcessor;
132
+ externalRefResolver?: BaseResolver;
133
+ } = {}
121
134
  ): Promise<RawConfig> {
135
+ const { configPath = findConfig(), processRawConfig, externalRefResolver } = options;
122
136
  if (!configPath || !doesYamlFileExist(configPath)) return {};
123
137
  try {
124
- const rawConfig =
125
- (await loadYaml<RawConfig & DeprecatedInRawConfig & FlatRawConfig>(configPath)) || {};
138
+ const { document, resolvedRefMap } = await resolveConfigFileAndRefs({
139
+ configPath,
140
+ externalRefResolver,
141
+ });
126
142
  if (typeof processRawConfig === 'function') {
127
- await processRawConfig(rawConfig);
143
+ await processRawConfig(document, resolvedRefMap);
128
144
  }
129
- return transformConfig(rawConfig);
145
+ const bundledConfig = await bundleConfig(document, resolvedRefMap);
146
+ return transformConfig(bundledConfig);
130
147
  } catch (e) {
131
148
  if (e instanceof ConfigValidationError) {
132
149
  throw e;
package/src/lint.ts CHANGED
@@ -1,13 +1,18 @@
1
- import { BaseResolver, resolveDocument, Document, makeDocumentFromString } from './resolve';
1
+ import { BaseResolver, resolveDocument, makeDocumentFromString } from './resolve';
2
2
  import { normalizeVisitors } from './visitors';
3
- import { NodeType } from './types';
4
- import { ProblemSeverity, WalkContext, walkDocument } from './walk';
3
+ import { walkDocument } from './walk';
5
4
  import { StyleguideConfig, Config, initRules, defaultPlugin, resolvePlugins } from './config';
6
5
  import { normalizeTypes } from './types';
7
6
  import { releaseAjvInstance } from './rules/ajv';
8
7
  import { SpecVersion, getMajorSpecVersion, detectSpec, getTypes } from './oas-types';
9
8
  import { ConfigTypes } from './types/redocly-yaml';
10
9
  import { Spec } from './rules/common/spec';
10
+ import { NoUnresolvedRefs } from './rules/no-unresolved-refs';
11
+
12
+ import type { Document, ResolvedRefMap } from './resolve';
13
+ import type { ProblemSeverity, WalkContext } from './walk';
14
+ import type { NodeType } from './types';
15
+ import type { NestedVisitObject, Oas3Visitor, RuleInstanceConfig } from './visitors';
11
16
 
12
17
  export async function lint(opts: {
13
18
  ref: string;
@@ -102,8 +107,13 @@ export async function lintDocument(opts: {
102
107
  return ctx.problems.map((problem) => config.addProblemToIgnore(problem));
103
108
  }
104
109
 
105
- export async function lintConfig(opts: { document: Document; severity?: ProblemSeverity }) {
106
- const { document, severity } = opts;
110
+ export async function lintConfig(opts: {
111
+ document: Document;
112
+ resolvedRefMap?: ResolvedRefMap;
113
+ severity?: ProblemSeverity;
114
+ externalRefResolver?: BaseResolver;
115
+ }) {
116
+ const { document, severity, externalRefResolver = new BaseResolver() } = opts;
107
117
 
108
118
  const ctx: WalkContext = {
109
119
  problems: [],
@@ -117,21 +127,33 @@ export async function lintConfig(opts: { document: Document; severity?: ProblemS
117
127
  });
118
128
 
119
129
  const types = normalizeTypes(ConfigTypes, config);
120
- const rules = [
130
+ const rules: (RuleInstanceConfig & {
131
+ visitor: NestedVisitObject<unknown, Oas3Visitor | Oas3Visitor[]>;
132
+ })[] = [
121
133
  {
122
134
  severity: severity || 'error',
123
135
  ruleId: 'configuration spec',
124
136
  visitor: Spec({ severity: 'error' }),
125
137
  },
138
+ {
139
+ severity: severity || 'error',
140
+ ruleId: 'configuration no-unresolved-refs',
141
+ visitor: NoUnresolvedRefs({ severity: 'error' }),
142
+ },
126
143
  ];
127
- // TODO: check why any is needed
128
- const normalizedVisitors = normalizeVisitors(rules as any, types);
129
-
144
+ const normalizedVisitors = normalizeVisitors(rules, types);
145
+ const resolvedRefMap =
146
+ opts.resolvedRefMap ||
147
+ (await resolveDocument({
148
+ rootDocument: document,
149
+ rootType: types.ConfigRoot,
150
+ externalRefResolver,
151
+ }));
130
152
  walkDocument({
131
153
  document,
132
154
  rootType: types.ConfigRoot,
133
155
  normalizedVisitors,
134
- resolvedRefMap: new Map(),
156
+ resolvedRefMap,
135
157
  ctx,
136
158
  });
137
159
 
package/src/rules/ajv.ts CHANGED
@@ -1,6 +1,8 @@
1
- import Ajv, { ValidateFunction, ErrorObject } from '@redocly/ajv/dist/2020';
1
+ import Ajv from '@redocly/ajv/dist/2020';
2
2
  import { Location, escapePointer } from '../ref-utils';
3
- import { ResolveFn } from '../walk';
3
+
4
+ import type { ValidateFunction, ErrorObject } from '@redocly/ajv/dist/2020';
5
+ import type { ResolveFn } from '../walk';
4
6
 
5
7
  let ajvInstance: Ajv | null = null;
6
8
 
@@ -21,10 +23,10 @@ function getAjv(resolve: ResolveFn, allowAdditionalProperties: boolean) {
21
23
  allowUnionTypes: true,
22
24
  validateFormats: false, // TODO: fix it
23
25
  defaultUnevaluatedProperties: allowAdditionalProperties,
24
- loadSchemaSync(base: string, $ref: string) {
26
+ loadSchemaSync(base: string, $ref: string, $id: string) {
25
27
  const resolvedRef = resolve({ $ref }, base.split('#')[0]);
26
28
  if (!resolvedRef || !resolvedRef.location) return false;
27
- return { $id: resolvedRef.location.absolutePointer, ...resolvedRef.node };
29
+ return { $id: resolvedRef.location.source.absoluteRef + '#' + $id, ...resolvedRef.node };
28
30
  },
29
31
  logger: false,
30
32
  });
@@ -2,7 +2,7 @@ import levenshtein = require('js-levenshtein');
2
2
  import { UserContext } from '../walk';
3
3
  import { Location } from '../ref-utils';
4
4
  import { validateJsonSchema } from './ajv';
5
- import { Oas3Schema, Referenced } from '../typings/openapi';
5
+ import { Oas3Schema, Oas3_1Schema, Referenced } from '../typings/openapi';
6
6
  import { showErrorForDeprecatedField, showWarningForDeprecatedField } from '../utils';
7
7
 
8
8
  export function oasTypeOf(value: unknown) {
@@ -91,7 +91,7 @@ export function getSuggest(given: string, variants: string[]): string[] {
91
91
 
92
92
  export function validateExample(
93
93
  example: any,
94
- schema: Referenced<Oas3Schema>,
94
+ schema: Referenced<Oas3Schema | Oas3_1Schema>,
95
95
  dataLoc: Location,
96
96
  { resolve, location, report }: UserContext,
97
97
  allowAdditionalProperties: boolean
@@ -274,10 +274,7 @@ const OperationBindings: NodeType = {
274
274
 
275
275
  const OperationTrait: NodeType = {
276
276
  properties: {
277
- tags: {
278
- type: 'array',
279
- items: { type: 'string' },
280
- },
277
+ tags: 'TagList',
281
278
  summary: { type: 'string' },
282
279
  description: { type: 'string' },
283
280
  externalDocs: 'ExternalDocs',
@@ -311,10 +308,7 @@ const MessageTrait: NodeType = {
311
308
 
312
309
  const Operation: NodeType = {
313
310
  properties: {
314
- tags: {
315
- type: 'array',
316
- items: { type: 'string' },
317
- },
311
+ tags: 'TagList',
318
312
  summary: { type: 'string' },
319
313
  description: { type: 'string' },
320
314
  externalDocs: 'ExternalDocs',
@@ -4,6 +4,8 @@ import {
4
4
  DEFAULT_TEAM_CLAIM_NAME,
5
5
  } from '../config';
6
6
 
7
+ import type { NodeType } from '.';
8
+
7
9
  const oidcIssuerMetadataSchema = {
8
10
  type: 'object',
9
11
  properties: {
@@ -87,8 +89,9 @@ const authProviderConfigSchema = {
87
89
 
88
90
  export const ssoConfigSchema = {
89
91
  type: 'object',
92
+ properties: {},
90
93
  additionalProperties: authProviderConfigSchema,
91
- } as const;
94
+ } as NodeType;
92
95
 
93
96
  const redirectConfigSchema = {
94
97
  type: 'object',
@@ -97,8 +100,14 @@ const redirectConfigSchema = {
97
100
  type: { type: 'number', default: 301 },
98
101
  },
99
102
  required: ['to'],
100
- additionalProperties: false,
101
- } as const;
103
+ } as NodeType;
104
+
105
+ const redirectsConfigSchema = {
106
+ type: 'object',
107
+ properties: {},
108
+ additionalProperties: 'redirectConfigSchema',
109
+ default: {},
110
+ } as NodeType;
102
111
 
103
112
  export const apiConfigSchema = {
104
113
  type: 'object',
@@ -147,18 +156,21 @@ const seoConfigSchema = {
147
156
  },
148
157
  },
149
158
  },
150
- additionalProperties: false,
151
159
  } as const;
152
160
 
153
- const rbacScopeItemsSchema = { type: 'object', additionalProperties: { type: 'string' } } as const;
161
+ const rbacScopeItemsSchema = {
162
+ type: 'object',
163
+ properties: {},
164
+ additionalProperties: { type: 'string' },
165
+ } as NodeType;
154
166
 
155
167
  const rbacConfigSchema = {
156
168
  type: 'object',
157
169
  properties: {
158
- defaults: rbacScopeItemsSchema,
170
+ defaults: 'rbacScopeItemsSchema',
159
171
  },
160
172
  additionalProperties: rbacScopeItemsSchema,
161
- } as const;
173
+ } as NodeType;
162
174
 
163
175
  const graviteeAdapterConfigSchema = {
164
176
  type: 'object',
@@ -234,14 +246,38 @@ const devOnboardingAdapterConfigSchema = {
234
246
  const devOnboardingConfigSchema = {
235
247
  type: 'object',
236
248
  required: ['adapters'],
237
- additionalProperties: false,
238
249
  properties: {
239
250
  adapters: {
240
251
  type: 'array',
241
252
  items: devOnboardingAdapterConfigSchema,
242
253
  },
243
254
  },
244
- } as const;
255
+ } as NodeType;
256
+
257
+ const i18ConfigSchema = {
258
+ type: 'object',
259
+ properties: {
260
+ defaultLocale: {
261
+ type: 'string',
262
+ },
263
+ locales: {
264
+ type: 'array',
265
+ items: {
266
+ type: 'object',
267
+ properties: {
268
+ code: {
269
+ type: 'string',
270
+ },
271
+ name: {
272
+ type: 'string',
273
+ },
274
+ },
275
+ required: ['code'],
276
+ },
277
+ },
278
+ },
279
+ required: ['defaultLocale', 'locales'],
280
+ } as NodeType;
245
281
 
246
282
  const responseHeaderSchema = {
247
283
  type: 'object',
@@ -253,14 +289,25 @@ const responseHeaderSchema = {
253
289
  required: ['name', 'value'],
254
290
  } as const;
255
291
 
292
+ export const PortalConfigNodeTypes: Record<string, NodeType> = {
293
+ seoConfigSchema,
294
+ rbacConfigSchema,
295
+ rbacScopeItemsSchema,
296
+ ssoConfigSchema,
297
+ devOnboardingConfigSchema,
298
+ i18ConfigSchema,
299
+ redirectsConfigSchema,
300
+ redirectConfigSchema,
301
+ // TODO: Extract other types that need to be linted in the config
302
+ };
303
+
256
304
  export const redoclyConfigSchema = {
257
305
  type: 'object',
258
306
  properties: {
259
307
  licenseKey: { type: 'string' },
260
- theme: { type: 'object', default: {} }, // ThemeConfig
261
- redirects: { type: 'object', additionalProperties: redirectConfigSchema, default: {} },
262
- seo: seoConfigSchema,
263
- rbac: rbacConfigSchema,
308
+ redirects: 'redirectsConfigSchema',
309
+ seo: 'seoConfigSchema',
310
+ rbac: 'rbacConfigSchema',
264
311
  responseHeaders: {
265
312
  type: 'object',
266
313
  additionalProperties: {
@@ -282,38 +329,13 @@ export const redoclyConfigSchema = {
282
329
  type: 'object',
283
330
  additionalProperties: apiConfigSchema,
284
331
  },
285
- sso: ssoConfigSchema,
286
- developerOnboarding: devOnboardingConfigSchema,
287
- i18n: {
288
- type: 'object',
289
- properties: {
290
- defaultLocale: {
291
- type: 'string',
292
- },
293
- locales: {
294
- type: 'array',
295
- items: {
296
- type: 'object',
297
- properties: {
298
- code: {
299
- type: 'string',
300
- },
301
- name: {
302
- type: 'string',
303
- },
304
- },
305
- required: ['code'],
306
- },
307
- },
308
- },
309
- additionalProperties: false,
310
- required: ['defaultLocale', 'locales'],
311
- },
332
+ sso: 'ssoConfigSchema',
333
+ developerOnboarding: 'devOnboardingConfigSchema',
334
+ i18n: 'i18ConfigSchema',
312
335
  metadata: metadataConfigSchema,
313
336
  },
314
337
  default: {},
315
- additionalProperties: true,
316
- } as const;
338
+ } as NodeType;
317
339
 
318
340
  export const environmentSchema = {
319
341
  oneOf: [
@@ -335,6 +357,7 @@ export const rootRedoclyConfigSchema = {
335
357
  ...redoclyConfigSchema.properties,
336
358
  env: {
337
359
  type: 'object',
360
+ properties: {},
338
361
  additionalProperties: environmentSchema,
339
362
  },
340
363
  },
@@ -1,8 +1,8 @@
1
1
  import { rootRedoclyConfigSchema, apiConfigSchema } from './portal-config-schema';
2
2
  import { themeConfigSchema } from './theme-config';
3
3
  import { NodeType, listOf } from '.';
4
- import { Oas3_1Types } from './oas3_1';
5
4
  import { omitObjectProps, pickObjectProps, isCustomRuleId } from '../utils';
5
+ import { PortalConfigNodeTypes } from './portal-config-schema';
6
6
 
7
7
  const builtInCommonRules = [
8
8
  'spec',
@@ -236,8 +236,6 @@ const ConfigApisProperties: NodeType = {
236
236
  type: 'string',
237
237
  },
238
238
  },
239
- lint: 'ConfigStyleguide', // deprecated
240
- styleguide: 'ConfigStyleguide', // deprecated
241
239
  ...ConfigStyleguide.properties,
242
240
  'features.openapi': 'ConfigReferenceDocs', // deprecated
243
241
  'features.mockServer': 'ConfigMockServer', // deprecated
@@ -997,7 +995,6 @@ const ConfigMockServer: NodeType = {
997
995
  };
998
996
 
999
997
  export const ConfigTypes: Record<string, NodeType> = {
1000
- ...Oas3_1Types,
1001
998
  Assert,
1002
999
  ConfigRoot,
1003
1000
  ConfigApis,
@@ -1062,4 +1059,5 @@ export const ConfigTypes: Record<string, NodeType> = {
1062
1059
  Typography,
1063
1060
  AssertionDefinitionAssertions,
1064
1061
  AssertionDefinitionSubject,
1062
+ ...PortalConfigNodeTypes,
1065
1063
  };
@@ -111,14 +111,14 @@ export interface Oas3Xml {
111
111
  wrapped?: string;
112
112
  }
113
113
 
114
- export interface Oas3Schema {
114
+ // common fields for OpenAPI Schema v3.x
115
+ interface Oas3XSchemaBase<T> {
115
116
  $ref?: string;
116
- type?: string;
117
- properties?: { [name: string]: Oas3Schema };
118
- additionalProperties?: boolean | Oas3Schema;
117
+ properties?: { [name: string]: T };
118
+ additionalProperties?: boolean | T;
119
119
  description?: string;
120
120
  default?: any;
121
- items?: Oas3Schema;
121
+ items?: T;
122
122
  required?: string[];
123
123
  readOnly?: boolean;
124
124
  writeOnly?: boolean;
@@ -127,10 +127,10 @@ export interface Oas3Schema {
127
127
  externalDocs?: Oas3ExternalDocs;
128
128
  discriminator?: Oas3Discriminator;
129
129
  nullable?: boolean;
130
- oneOf?: Oas3Schema[];
131
- anyOf?: Oas3Schema[];
132
- allOf?: Oas3Schema[];
133
- not?: Oas3Schema;
130
+ oneOf?: T[];
131
+ anyOf?: T[];
132
+ allOf?: T[];
133
+ not?: T;
134
134
 
135
135
  title?: string;
136
136
  multipleOf?: number;
@@ -153,11 +153,15 @@ export interface Oas3Schema {
153
153
  'x-tags'?: string[];
154
154
  }
155
155
 
156
- export type Oas3_1Schema = Oas3Schema & {
156
+ export interface Oas3Schema extends Oas3XSchemaBase<Oas3Schema> {
157
+ type?: string;
158
+ }
159
+
160
+ export interface Oas3_1Schema extends Oas3XSchemaBase<Oas3_1Schema> {
157
161
  type?: string | string[];
158
162
  examples?: any[];
159
163
  prefixItems?: Oas3_1Schema[];
160
- };
164
+ }
161
165
 
162
166
  export interface Oas3_1Definition extends Oas3Definition {
163
167
  webhooks?: Oas3_1Webhooks;
package/src/visitors.ts CHANGED
@@ -1,3 +1,9 @@
1
+ import { SpecExtension } from './types';
2
+
3
+ import type { NormalizedNodeType } from './types';
4
+ import type { Stack } from './utils';
5
+ import type { UserContext, ResolveResult, ProblemSeverity } from './walk';
6
+ import type { Location } from './ref-utils';
1
7
  import type {
2
8
  Oas3Definition,
3
9
  Oas3ExternalDocs,
@@ -26,7 +32,6 @@ import type {
26
32
  Oas3Discriminator,
27
33
  Oas3Callback,
28
34
  } from './typings/openapi';
29
-
30
35
  import type {
31
36
  Oas2Definition,
32
37
  Oas2Tag,
@@ -44,12 +49,7 @@ import type {
44
49
  Oas2Parameter,
45
50
  Oas2SecurityScheme,
46
51
  } from './typings/swagger';
47
-
48
- import { NormalizedNodeType, SpecExtension } from './types';
49
- import type { Stack } from './utils';
50
- import type { UserContext, ResolveResult, ProblemSeverity } from './walk';
51
- import type { Location } from './ref-utils';
52
- import { Async2Definition } from './typings/asyncapi';
52
+ import type { Async2Definition } from './typings/asyncapi';
53
53
 
54
54
  export type SkipFunctionContext = Pick<
55
55
  UserContext,
@@ -297,7 +297,7 @@ export type RuleInstanceConfig = {
297
297
  };
298
298
 
299
299
  export function normalizeVisitors<T extends BaseVisitor>(
300
- visitorsConfig: (RuleInstanceConfig & { visitor: NestedVisitObject<any, T> })[],
300
+ visitorsConfig: (RuleInstanceConfig & { visitor: NestedVisitObject<unknown, T> })[],
301
301
  types: Record<keyof T, NormalizedNodeType>
302
302
  ): NormalizedOasVisitors<T> {
303
303
  const normalizedVisitors: NormalizedOasVisitors<T> = {} as any;
@@ -377,12 +377,10 @@ export function normalizeVisitors<T extends BaseVisitor>(
377
377
 
378
378
  function addWeakFromStack(ruleConf: RuleInstanceConfig, stack: NormalizedNodeType[]) {
379
379
  for (const interType of stack.slice(1)) {
380
- (normalizedVisitors as any)[interType.name] =
381
- normalizedVisitors[interType.name] ||
382
- ({
383
- enter: [],
384
- leave: [],
385
- } as any);
380
+ (normalizedVisitors as any)[interType.name] = normalizedVisitors[interType.name] || {
381
+ enter: [],
382
+ leave: [],
383
+ };
386
384
  normalizedVisitors[interType.name].enter.push({
387
385
  ...ruleConf,
388
386
  visit: () => undefined,
@@ -398,7 +396,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
398
396
  }
399
397
 
400
398
  function findLegacyVisitorNode<T>(
401
- visitor: NestedVisitObject<any, T>,
399
+ visitor: NestedVisitObject<unknown, T>,
402
400
  typeName: keyof T | Array<keyof T>
403
401
  ) {
404
402
  if (Array.isArray(typeName)) {
@@ -411,7 +409,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
411
409
 
412
410
  function normalizeVisitorLevel(
413
411
  ruleConf: RuleInstanceConfig,
414
- visitor: NestedVisitObject<any, T>,
412
+ visitor: NestedVisitObject<unknown, T>,
415
413
  parentContext: VisitorLevelContext | null,
416
414
  depth = 0
417
415
  ) {
@@ -434,14 +432,14 @@ export function normalizeVisitors<T extends BaseVisitor>(
434
432
  findLegacyVisitorNode(
435
433
  visitor,
436
434
  legacyTypesMap[typeName as keyof typeof legacyTypesMap] as keyof T
437
- )) as any as NestedVisitObject<any, T>;
435
+ )) as NestedVisitObject<unknown, T>;
438
436
  const normalizedTypeVisitor = normalizedVisitors[typeName];
439
437
 
440
438
  if (!typeVisitor) continue;
441
439
 
442
- let visitorEnter: VisitFunction<any> | undefined;
443
- let visitorLeave: VisitFunction<any> | undefined;
444
- let visitorSkip: SkipFunction<any> | undefined;
440
+ let visitorEnter: VisitFunction<unknown> | undefined;
441
+ let visitorLeave: VisitFunction<unknown> | undefined;
442
+ let visitorSkip: SkipFunction<unknown> | undefined;
445
443
 
446
444
  const isObjectVisitor = typeof typeVisitor === 'object';
447
445
 
@@ -450,7 +448,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
450
448
  }
451
449
 
452
450
  if (typeof typeVisitor === 'function') {
453
- visitorEnter = typeVisitor as any;
451
+ visitorEnter = typeVisitor;
454
452
  } else if (isObjectVisitor) {
455
453
  visitorEnter = typeVisitor.enter;
456
454
  visitorLeave = typeVisitor.leave;
@@ -465,7 +463,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
465
463
  };
466
464
 
467
465
  if (typeof typeVisitor === 'object') {
468
- normalizeVisitorLevel(ruleConf, typeVisitor as any, context, depth + 1);
466
+ normalizeVisitorLevel(ruleConf, typeVisitor, context, depth + 1);
469
467
  }
470
468
 
471
469
  if (parentContext) {