@redocly/openapi-core 1.8.2 → 1.9.1

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 (60) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/lib/bundle.d.ts +1 -1
  3. package/lib/config/all.js +1 -0
  4. package/lib/config/minimal.js +1 -0
  5. package/lib/config/recommended-strict.js +1 -0
  6. package/lib/config/recommended.js +1 -0
  7. package/lib/lint.d.ts +1 -0
  8. package/lib/lint.js +1 -1
  9. package/lib/oas-types.d.ts +1 -1
  10. package/lib/ref-utils.js +4 -4
  11. package/lib/resolve.js +9 -1
  12. package/lib/rules/common/no-required-schema-properties-undefined.d.ts +2 -0
  13. package/lib/rules/common/no-required-schema-properties-undefined.js +37 -0
  14. package/lib/rules/oas2/index.js +2 -0
  15. package/lib/rules/oas3/index.js +2 -0
  16. package/lib/types/index.d.ts +7 -7
  17. package/lib/types/json-schema-adapter.d.ts +3 -0
  18. package/lib/types/json-schema-adapter.js +173 -0
  19. package/lib/types/oas2.d.ts +3 -2
  20. package/lib/types/oas3.d.ts +3 -2
  21. package/lib/types/oas3_1.d.ts +3 -2
  22. package/lib/types/portal-config-schema.d.ts +5261 -52
  23. package/lib/types/portal-config-schema.js +71 -55
  24. package/lib/types/redocly-yaml.d.ts +14 -2
  25. package/lib/types/redocly-yaml.js +102 -39
  26. package/lib/types/theme-config.d.ts +819 -36
  27. package/lib/types/theme-config.js +67 -29
  28. package/lib/utils.d.ts +2 -2
  29. package/lib/visitors.js +1 -1
  30. package/lib/walk.js +7 -1
  31. package/package.json +1 -1
  32. package/src/__tests__/lint.test.ts +1218 -36
  33. package/src/__tests__/ref-utils.test.ts +22 -0
  34. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +2 -0
  35. package/src/config/__tests__/load.test.ts +13 -13
  36. package/src/config/all.ts +1 -0
  37. package/src/config/minimal.ts +1 -0
  38. package/src/config/recommended-strict.ts +1 -0
  39. package/src/config/recommended.ts +1 -0
  40. package/src/decorators/oas2/remove-unused-components.ts +3 -2
  41. package/src/decorators/oas3/remove-unused-components.ts +3 -2
  42. package/src/lint.ts +2 -1
  43. package/src/ref-utils.ts +4 -4
  44. package/src/resolve.ts +13 -1
  45. package/src/rules/common/__tests__/no-required-schema-properties-undefined.test.ts +550 -0
  46. package/src/rules/common/no-required-schema-properties-undefined.ts +53 -0
  47. package/src/rules/oas2/index.ts +2 -0
  48. package/src/rules/oas3/index.ts +2 -0
  49. package/src/types/index.ts +7 -12
  50. package/src/types/json-schema-adapter.ts +217 -0
  51. package/src/types/oas2.ts +5 -2
  52. package/src/types/oas3.ts +6 -2
  53. package/src/types/oas3_1.ts +5 -2
  54. package/src/types/portal-config-schema.ts +111 -61
  55. package/src/types/redocly-yaml.ts +119 -43
  56. package/src/types/theme-config.ts +125 -27
  57. package/src/utils.ts +2 -2
  58. package/src/visitors.ts +1 -1
  59. package/src/walk.ts +7 -1
  60. package/tsconfig.tsbuildinfo +1 -1
@@ -1,8 +1,10 @@
1
- import { rootRedoclyConfigSchema, apiConfigSchema } from './portal-config-schema';
2
- import { themeConfigSchema } from './theme-config';
3
- import { NodeType, listOf } from '.';
1
+ import { rootRedoclyConfigSchema } from './portal-config-schema';
2
+ import { listOf } from '.';
4
3
  import { omitObjectProps, pickObjectProps, isCustomRuleId } from '../utils';
5
- import { PortalConfigNodeTypes } from './portal-config-schema';
4
+ import { getNodeTypesFromJSONSchema } from './json-schema-adapter';
5
+
6
+ import type { NodeType } from '.';
7
+ import type { JSONSchema } from 'json-schema-to-ts';
6
8
 
7
9
  const builtInCommonRules = [
8
10
  'spec',
@@ -48,6 +50,7 @@ const builtInCommonOASRules = [
48
50
  'security-defined',
49
51
  'spec-strict-refs',
50
52
  'no-unresolved-refs',
53
+ 'no-required-schema-properties-undefined',
51
54
  ] as const;
52
55
 
53
56
  export type BuiltInCommonOASRuleId = typeof builtInCommonOASRules[number];
@@ -96,8 +99,49 @@ const builtInRules = [
96
99
 
97
100
  type BuiltInRuleId = typeof builtInRules[number];
98
101
 
99
- const nodeTypesList = [
100
- 'any',
102
+ const oas2NodeTypesList = [
103
+ 'Root',
104
+ 'Tag',
105
+ 'TagList',
106
+ 'ExternalDocs',
107
+ 'SecurityRequirement',
108
+ 'SecurityRequirementList',
109
+ 'Info',
110
+ 'Contact',
111
+ 'License',
112
+ 'Paths',
113
+ 'PathItem',
114
+ 'Parameter',
115
+ 'ParameterList',
116
+ 'ParameterItems',
117
+ 'Operation',
118
+ 'Example',
119
+ 'ExamplesMap',
120
+ 'Examples',
121
+ 'Header',
122
+ 'Responses',
123
+ 'Response',
124
+ 'Schema',
125
+ 'Xml',
126
+ 'SchemaProperties',
127
+ 'NamedSchemas',
128
+ 'NamedResponses',
129
+ 'NamedParameters',
130
+ 'NamedSecuritySchemes',
131
+ 'SecurityScheme',
132
+ 'TagGroup',
133
+ 'TagGroups',
134
+ 'EnumDescriptions',
135
+ 'Logo',
136
+ 'XCodeSample',
137
+ 'XCodeSampleList',
138
+ 'XServer',
139
+ 'XServerList',
140
+ ] as const;
141
+
142
+ export type Oas2NodeType = typeof oas2NodeTypesList[number];
143
+
144
+ const oas3NodeTypesList = [
101
145
  'Root',
102
146
  'Tag',
103
147
  'TagList',
@@ -152,12 +196,33 @@ const nodeTypesList = [
152
196
  'AuthorizationCode',
153
197
  'OAuth2Flows',
154
198
  'SecurityScheme',
199
+ 'TagGroup',
200
+ 'TagGroups',
201
+ 'EnumDescriptions',
202
+ 'Logo',
155
203
  'XCodeSample',
156
204
  'XCodeSampleList',
205
+ 'XUsePkce',
157
206
  'WebhooksMap',
158
- 'SpecExtension',
159
- 'Message',
160
- ];
207
+ ] as const;
208
+
209
+ export type Oas3NodeType = typeof oas3NodeTypesList[number];
210
+
211
+ const oas3_1NodeTypesList = [
212
+ 'Root',
213
+ 'Schema',
214
+ 'SchemaProperties',
215
+ 'Info',
216
+ 'License',
217
+ 'Components',
218
+ 'NamedPathItems',
219
+ 'SecurityScheme',
220
+ 'Operation',
221
+ ] as const;
222
+
223
+ export type Oas3_1NodeType = typeof oas3_1NodeTypesList[number];
224
+
225
+ const asyncNodeTypesList = ['Message'] as const;
161
226
 
162
227
  const ConfigStyleguide: NodeType = {
163
228
  properties: {
@@ -185,22 +250,13 @@ const ConfigStyleguide: NodeType = {
185
250
  },
186
251
  };
187
252
 
188
- const RootConfigStyleguide: NodeType = {
253
+ const createConfigRoot = (nodeTypes: Record<string, NodeType>): NodeType => ({
254
+ ...nodeTypes.rootRedoclyConfigSchema,
189
255
  properties: {
190
- plugins: {
191
- type: 'array',
192
- items: { type: 'string' },
193
- },
256
+ ...nodeTypes.rootRedoclyConfigSchema.properties,
194
257
  ...ConfigStyleguide.properties,
195
- },
196
- };
197
-
198
- const ConfigRoot: NodeType = {
199
- properties: {
200
- ...rootRedoclyConfigSchema.properties,
201
- ...RootConfigStyleguide.properties,
202
- apis: 'ConfigApis',
203
- theme: 'ConfigRootTheme',
258
+ apis: 'ConfigApis', // Override apis with internal format
259
+ theme: 'ConfigRootTheme', // Override theme with internal format
204
260
  'features.openapi': 'ConfigReferenceDocs', // deprecated
205
261
  'features.mockServer': 'ConfigMockServer', // deprecated
206
262
  organization: { type: 'string' },
@@ -219,17 +275,17 @@ const ConfigRoot: NodeType = {
219
275
  },
220
276
  },
221
277
  },
222
- };
278
+ });
223
279
 
224
280
  const ConfigApis: NodeType = {
225
281
  properties: {},
226
282
  additionalProperties: 'ConfigApisProperties',
227
283
  };
228
284
 
229
- const ConfigApisProperties: NodeType = {
285
+ const createConfigApisProperties = (nodeTypes: Record<string, NodeType>): NodeType => ({
286
+ ...nodeTypes['rootRedoclyConfigSchema.apis_additionalProperties'],
230
287
  properties: {
231
- ...apiConfigSchema.properties,
232
- root: { type: 'string' },
288
+ ...nodeTypes['rootRedoclyConfigSchema.apis_additionalProperties']?.properties,
233
289
  labels: {
234
290
  type: 'array',
235
291
  items: {
@@ -239,7 +295,6 @@ const ConfigApisProperties: NodeType = {
239
295
  ...ConfigStyleguide.properties,
240
296
  'features.openapi': 'ConfigReferenceDocs', // deprecated
241
297
  'features.mockServer': 'ConfigMockServer', // deprecated
242
- theme: 'ConfigRootTheme',
243
298
  files: {
244
299
  type: 'array',
245
300
  items: {
@@ -247,8 +302,7 @@ const ConfigApisProperties: NodeType = {
247
302
  },
248
303
  },
249
304
  },
250
- required: ['root'],
251
- };
305
+ });
252
306
 
253
307
  const ConfigHTTP: NodeType = {
254
308
  properties: {
@@ -261,13 +315,13 @@ const ConfigHTTP: NodeType = {
261
315
  },
262
316
  };
263
317
 
264
- const ConfigRootTheme: NodeType = {
318
+ const createConfigRootTheme = (nodeTypes: Record<string, NodeType>): NodeType => ({
319
+ ...nodeTypes['rootRedoclyConfigSchema.theme'],
265
320
  properties: {
266
- ...themeConfigSchema.properties,
267
- openapi: 'ConfigReferenceDocs',
268
- mockServer: 'ConfigMockServer',
321
+ ...nodeTypes['rootRedoclyConfigSchema.theme']?.properties,
322
+ openapi: 'ConfigReferenceDocs', // Override theme.openapi with internal format
269
323
  },
270
- };
324
+ });
271
325
 
272
326
  const Rules: NodeType = {
273
327
  properties: {},
@@ -301,7 +355,18 @@ const ObjectRule: NodeType = {
301
355
 
302
356
  const AssertionDefinitionSubject: NodeType = {
303
357
  properties: {
304
- type: { enum: nodeTypesList },
358
+ type: {
359
+ enum: [
360
+ ...new Set([
361
+ 'any',
362
+ ...oas2NodeTypesList,
363
+ ...oas3NodeTypesList,
364
+ ...oas3_1NodeTypesList,
365
+ ...asyncNodeTypesList,
366
+ 'SpecExtension',
367
+ ]),
368
+ ],
369
+ },
305
370
  property: (value: unknown) => {
306
371
  if (Array.isArray(value)) {
307
372
  return { type: 'array', items: { type: 'string' } };
@@ -862,8 +927,9 @@ const GenerateCodeSamples: NodeType = {
862
927
  };
863
928
 
864
929
  const ConfigReferenceDocs: NodeType = {
930
+ // TODO: partially invalid @Viacheslav
865
931
  properties: {
866
- theme: 'ConfigTheme',
932
+ theme: 'ConfigTheme', // TODO: deprecated @Viacheslav
867
933
  corsProxyUrl: { type: 'string' },
868
934
  ctrlFHijack: { type: 'boolean' },
869
935
  defaultSampleLanguage: { type: 'string' },
@@ -994,12 +1060,22 @@ const ConfigMockServer: NodeType = {
994
1060
  },
995
1061
  };
996
1062
 
997
- export const ConfigTypes: Record<string, NodeType> = {
1063
+ export const createConfigTypes = (extraSchemas: JSONSchema) => {
1064
+ // Create types based on external schemas
1065
+ const nodeTypes = getNodeTypesFromJSONSchema('rootRedoclyConfigSchema', extraSchemas);
1066
+
1067
+ return {
1068
+ ...CoreConfigTypes,
1069
+ ConfigRoot: createConfigRoot(nodeTypes),
1070
+ ConfigApisProperties: createConfigApisProperties(nodeTypes),
1071
+ ConfigRootTheme: createConfigRootTheme(nodeTypes),
1072
+ ...nodeTypes,
1073
+ };
1074
+ };
1075
+
1076
+ const CoreConfigTypes: Record<string, NodeType> = {
998
1077
  Assert,
999
- ConfigRoot,
1000
1078
  ConfigApis,
1001
- ConfigApisProperties,
1002
- RootConfigStyleguide,
1003
1079
  ConfigStyleguide,
1004
1080
  ConfigReferenceDocs,
1005
1081
  ConfigMockServer,
@@ -1009,7 +1085,6 @@ export const ConfigTypes: Record<string, NodeType> = {
1009
1085
  ConfigSidebarLinks,
1010
1086
  CommonConfigSidebarLinks,
1011
1087
  ConfigTheme,
1012
- ConfigRootTheme,
1013
1088
  AssertDefinition,
1014
1089
  ThemeColors,
1015
1090
  CommonThemeColors,
@@ -1059,5 +1134,6 @@ export const ConfigTypes: Record<string, NodeType> = {
1059
1134
  Typography,
1060
1135
  AssertionDefinitionAssertions,
1061
1136
  AssertionDefinitionSubject,
1062
- ...PortalConfigNodeTypes,
1063
1137
  };
1138
+
1139
+ export const ConfigTypes: Record<string, NodeType> = createConfigTypes(rootRedoclyConfigSchema);
@@ -1,3 +1,5 @@
1
+ import type { FromSchema } from 'json-schema-to-ts';
2
+
1
3
  const logoConfigSchema = {
2
4
  type: 'object',
3
5
  properties: {
@@ -68,6 +70,11 @@ const markdownConfigSchema = {
68
70
  items: { type: 'string' },
69
71
  default: ['image', 'links'],
70
72
  },
73
+ partialsFolders: {
74
+ type: 'array',
75
+ items: { type: 'string' },
76
+ default: ['_partials'],
77
+ },
71
78
  lastUpdatedBlock: {
72
79
  type: 'object',
73
80
  properties: {
@@ -76,7 +83,7 @@ const markdownConfigSchema = {
76
83
  enum: ['timeago', 'iso', 'long', 'short'],
77
84
  default: 'timeago',
78
85
  },
79
- locale: { type: 'string', default: 'en-US' },
86
+ locale: { type: 'string' },
80
87
  ...hideConfigSchema.properties,
81
88
  },
82
89
  additionalProperties: false,
@@ -187,6 +194,21 @@ const gtmAnalyticsConfigSchema = {
187
194
  required: ['trackingId'],
188
195
  } as const;
189
196
 
197
+ const productGoogleAnalyticsConfigSchema = {
198
+ type: 'object',
199
+ properties: {
200
+ includeInDevelopment: { type: 'boolean' },
201
+ trackingId: { type: 'string' },
202
+
203
+ conversionId: { type: 'string' },
204
+ floodlightId: { type: 'string' },
205
+ optimizeId: { type: 'string' },
206
+ exclude: { type: 'array', items: { type: 'string' } },
207
+ },
208
+ additionalProperties: false,
209
+ required: ['trackingId'],
210
+ } as const;
211
+
190
212
  const googleAnalyticsConfigSchema = {
191
213
  type: 'object',
192
214
  properties: {
@@ -203,6 +225,12 @@ const googleAnalyticsConfigSchema = {
203
225
  optimizeId: { type: 'string' },
204
226
  anonymizeIp: { type: 'boolean' },
205
227
  cookieExpires: { type: 'number' },
228
+
229
+ // All enabled tracking configs
230
+ trackers: {
231
+ type: 'object',
232
+ additionalProperties: productGoogleAnalyticsConfigSchema,
233
+ },
206
234
  },
207
235
  additionalProperties: false,
208
236
  required: ['trackingId'],
@@ -224,6 +252,7 @@ const navItemSchema = {
224
252
  properties: {
225
253
  page: { type: 'string' },
226
254
  directory: { type: 'string' },
255
+ disconnect: { type: 'boolean', default: false },
227
256
  group: { type: 'string' },
228
257
  label: { type: 'string' },
229
258
  separator: { type: 'string' },
@@ -264,7 +293,7 @@ const productConfigSchema = {
264
293
  folder: { type: 'string' },
265
294
  },
266
295
  additionalProperties: false,
267
- required: ['name', 'icon', 'folder'],
296
+ required: ['name', 'folder'],
268
297
  } as const;
269
298
 
270
299
  const suggestedPageSchema = {
@@ -287,6 +316,7 @@ const catalogFilterSchema = {
287
316
  titleTranslationKey: { type: 'string' },
288
317
  property: { type: 'string' },
289
318
  parentFilter: { type: 'string' },
319
+ valuesMapping: { type: 'object', additionalProperties: { type: 'string' } },
290
320
  missingCategoryName: { type: 'string' },
291
321
  missingCategoryNameTranslationKey: { type: 'string' },
292
322
  options: { type: 'array', items: { type: 'string' } },
@@ -296,9 +326,9 @@ const catalogFilterSchema = {
296
326
  const scorecardConfigSchema = {
297
327
  type: 'object',
298
328
  additionalProperties: true,
299
- required: ['levels'],
329
+ required: [],
300
330
  properties: {
301
- failBuildIfBelowMinimum: { type: 'boolean', default: false },
331
+ ignoreNonCompliant: { type: 'boolean', default: false },
302
332
  teamMetadataProperty: {
303
333
  type: 'object',
304
334
  properties: {
@@ -314,11 +344,12 @@ const scorecardConfigSchema = {
314
344
  required: ['name'],
315
345
  properties: {
316
346
  name: { type: 'string' },
347
+ color: { type: 'string' },
317
348
  extends: { type: 'array', items: { type: 'string' } },
318
349
  rules: {
319
350
  type: 'object',
320
351
  additionalProperties: {
321
- type: ['object', 'string'],
352
+ oneOf: [{ type: 'string' }, { type: 'object' }],
322
353
  },
323
354
  },
324
355
  },
@@ -420,12 +451,6 @@ export const themeConfigSchema = {
420
451
  },
421
452
  additionalProperties: false,
422
453
  },
423
- seo: {
424
- type: 'object',
425
- properties: {
426
- title: { type: 'string' },
427
- },
428
- },
429
454
  scripts: {
430
455
  type: 'object',
431
456
  properties: {
@@ -444,7 +469,7 @@ export const themeConfigSchema = {
444
469
  },
445
470
  type: {
446
471
  type: 'string',
447
- enum: ['rating', 'sentiment', 'comment', 'reasons'],
472
+ enum: ['rating', 'sentiment', 'comment', 'reasons', 'mood', 'scale'],
448
473
  default: 'sentiment',
449
474
  },
450
475
  settings: {
@@ -452,15 +477,27 @@ export const themeConfigSchema = {
452
477
  properties: {
453
478
  label: { type: 'string' },
454
479
  submitText: { type: 'string' },
455
- max: { type: 'number' },
456
480
  buttonText: { type: 'string' },
457
- multi: { type: 'boolean' },
481
+ component: {
482
+ type: 'string',
483
+ enum: ['radio', 'checkbox'],
484
+ default: 'checkbox',
485
+ },
458
486
  items: { type: 'array', items: { type: 'string' }, minItems: 1 },
487
+ leftScaleLabel: { type: 'string' },
488
+ rightScaleLabel: { type: 'string' },
459
489
  reasons: {
460
490
  type: 'object',
461
491
  properties: {
462
- enable: { type: 'boolean', default: true },
463
- multi: { type: 'boolean' },
492
+ hide: {
493
+ type: 'boolean',
494
+ default: false,
495
+ },
496
+ component: {
497
+ type: 'string',
498
+ enum: ['radio', 'checkbox'],
499
+ default: 'checkbox',
500
+ },
464
501
  label: { type: 'string' },
465
502
  items: { type: 'array', items: { type: 'string' } },
466
503
  },
@@ -469,10 +506,16 @@ export const themeConfigSchema = {
469
506
  comment: {
470
507
  type: 'object',
471
508
  properties: {
472
- enable: { type: 'boolean', default: true },
509
+ hide: {
510
+ type: 'boolean',
511
+ default: false,
512
+ },
473
513
  label: { type: 'string' },
474
514
  likeLabel: { type: 'string' },
475
515
  dislikeLabel: { type: 'string' },
516
+ satisfiedLabel: { type: 'string' },
517
+ neutralLabel: { type: 'string' },
518
+ dissatisfiedLabel: { type: 'string' },
476
519
  },
477
520
  additionalProperties: false,
478
521
  },
@@ -525,7 +568,7 @@ export const themeConfigSchema = {
525
568
  nextButton: {
526
569
  type: 'object',
527
570
  properties: {
528
- text: { type: 'string', default: 'Next to {label}' },
571
+ text: { type: 'string', default: 'Next to {{label}}' },
529
572
  ...hideConfigSchema.properties,
530
573
  },
531
574
  additionalProperties: false,
@@ -534,7 +577,7 @@ export const themeConfigSchema = {
534
577
  previousButton: {
535
578
  type: 'object',
536
579
  properties: {
537
- text: { type: 'string', default: 'Back to {label}' },
580
+ text: { type: 'string', default: 'Back to {{label}}' },
538
581
  ...hideConfigSchema.properties,
539
582
  },
540
583
  additionalProperties: false,
@@ -547,7 +590,7 @@ export const themeConfigSchema = {
547
590
  codeSnippet: {
548
591
  type: 'object',
549
592
  properties: {
550
- controlsStyle: { type: 'string', default: 'icon' },
593
+ elementFormat: { type: 'string', default: 'icon' },
551
594
  copy: {
552
595
  type: 'object',
553
596
  properties: {
@@ -559,10 +602,13 @@ export const themeConfigSchema = {
559
602
  report: {
560
603
  type: 'object',
561
604
  properties: {
605
+ tooltipText: { type: 'string' },
606
+ buttonText: { type: 'string' },
607
+ label: { type: 'string' },
562
608
  ...hideConfigSchema.properties,
563
609
  },
564
610
  additionalProperties: false,
565
- default: { hide: true },
611
+ default: { hide: false },
566
612
  },
567
613
  expand: {
568
614
  type: 'object',
@@ -585,7 +631,7 @@ export const themeConfigSchema = {
585
631
  default: {},
586
632
  },
587
633
  markdown: markdownConfigSchema,
588
- openapi: { type: 'object', additionalProperties: true },
634
+ openapi: { type: 'object', additionalProperties: true }, // TODO: put the real schema here @Viacheslav
589
635
  graphql: { type: 'object', additionalProperties: true },
590
636
  analytics: {
591
637
  type: 'object',
@@ -671,13 +717,65 @@ export const productThemeOverrideSchema = {
671
717
  search: themeConfigSchema.properties.search,
672
718
  codeSnippet: themeConfigSchema.properties.codeSnippet,
673
719
  breadcrumbs: themeConfigSchema.properties.breadcrumbs,
720
+ analytics: {
721
+ type: 'object',
722
+ properties: {
723
+ ga: productGoogleAnalyticsConfigSchema,
724
+ },
725
+ },
674
726
  },
675
727
  additionalProperties: true,
676
728
  default: {},
677
729
  } as const;
678
730
 
679
- export enum ScorecardStatus {
680
- BelowMinimum = 'Below minimum',
681
- Highest = 'Highest',
682
- Minimum = 'Minimum',
683
- }
731
+ export type ThemeConfig = FromSchema<typeof themeConfigSchema>;
732
+
733
+ // TODO: cannot export as it relies on external types
734
+ // export type ThemeUIConfig = ThemeConfig & {
735
+ // auth?: {
736
+ // // used by portal dev login emulator
737
+ // idpsInfo?: {
738
+ // idpId: string;
739
+ // type: string; // AuthProviderType
740
+ // title: string | undefined;
741
+ // }[];
742
+ // devLogin?: boolean;
743
+ // loginUrls?: Record<string, string>;
744
+ // };
745
+ // search?: {
746
+ // shortcuts?: string[];
747
+ // suggestedPages?: any[];
748
+ // };
749
+ // breadcrumbs?: {
750
+ // prefixItems?: ResolvedNavLinkItem[];
751
+ // };
752
+ // products?: {
753
+ // [key: string]: ProductUiConfig;
754
+ // };
755
+ // };
756
+
757
+ export type ProductConfig = FromSchema<typeof productConfigSchema>;
758
+
759
+ export type ProductGoogleAnalyticsConfig = FromSchema<typeof productGoogleAnalyticsConfigSchema>;
760
+ // TODO: cannot export as it relies on external types
761
+ // export type ProductThemeOverrideConfig = Pick<
762
+ // ThemeUIConfig,
763
+ // 'logo' | 'navbar' | 'footer' | 'sidebar' | 'search' | 'codeSnippet' | 'breadcrumbs'
764
+ // > & { analytics?: { ga?: ProductGoogleAnalyticsConfig } };
765
+ // export type ProductUiConfig = ProductConfig & {
766
+ // slug: string;
767
+ // link: string;
768
+ // [REDOCLY_TEAMS_RBAC]?: { [key: string]: string };
769
+ // themeOverride?: ProductThemeOverrideConfig;
770
+ // };
771
+
772
+ export type MarkdownConfig = FromSchema<typeof markdownConfigSchema>;
773
+
774
+ export type AmplitudeAnalyticsConfig = FromSchema<typeof amplitudeAnalyticsConfigSchema>;
775
+ export type RudderstackAnalyticsConfig = FromSchema<typeof rudderstackAnalyticsConfigSchema>;
776
+ export type SegmentAnalyticsConfig = FromSchema<typeof segmentAnalyticsConfigSchema>;
777
+ export type GtmAnalyticsConfig = FromSchema<typeof gtmAnalyticsConfigSchema>;
778
+ export type GoogleAnalyticsConfig = FromSchema<typeof googleAnalyticsConfigSchema>;
779
+ export type CatalogConfig = FromSchema<typeof catalogSchema>;
780
+ export type CatalogFilterConfig = FromSchema<typeof catalogFilterSchema>;
781
+ export type ScorecardConfig = FromSchema<typeof scorecardConfigSchema>;
package/src/utils.ts CHANGED
@@ -37,11 +37,11 @@ export function isDefined<T>(x: T | undefined): x is T {
37
37
  return x !== undefined;
38
38
  }
39
39
 
40
- export function isPlainObject(value: any): value is object {
40
+ export function isPlainObject(value: any): value is Record<string, unknown> {
41
41
  return value !== null && typeof value === 'object' && !Array.isArray(value);
42
42
  }
43
43
 
44
- export function isEmptyObject(value: any): value is object {
44
+ export function isEmptyObject(value: any): value is Record<string, unknown> {
45
45
  return isPlainObject(value) && Object.keys(value).length === 0;
46
46
  }
47
47
 
package/src/visitors.ts CHANGED
@@ -359,7 +359,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
359
359
  possibleChildren.add(from.additionalProperties);
360
360
  }
361
361
  }
362
- if (from.items) {
362
+ if (from.items && typeof from.items !== 'function') {
363
363
  if (from.items === to) {
364
364
  addWeakFromStack(ruleConf, stack);
365
365
  } else if (from.items.name !== undefined) {
package/src/walk.ts CHANGED
@@ -271,8 +271,14 @@ export function walkDocument<T extends BaseVisitor>(opts: {
271
271
  if (Array.isArray(resolvedNode)) {
272
272
  const itemsType = type.items;
273
273
  if (itemsType !== undefined) {
274
+ const isTypeAFunction = typeof itemsType === 'function';
274
275
  for (let i = 0; i < resolvedNode.length; i++) {
275
- walkNode(resolvedNode[i], itemsType, resolvedLocation.child([i]), resolvedNode, i);
276
+ const itemType = isTypeAFunction
277
+ ? itemsType(resolvedNode[i], resolvedLocation.child([i]).absolutePointer)
278
+ : itemsType;
279
+ if (isNamedType(itemType)) {
280
+ walkNode(resolvedNode[i], itemType, resolvedLocation.child([i]), resolvedNode, i);
281
+ }
276
282
  }
277
283
  }
278
284
  } else if (typeof resolvedNode === 'object' && resolvedNode !== null) {