@mintlify/validation 0.1.98 → 0.1.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.
@@ -0,0 +1,467 @@
1
+ import lcm from 'lcm';
2
+ import _ from 'lodash';
3
+ import { ConversionError, ImpossibleSchemaError, InvalidSchemaError } from './errors.js';
4
+ import { typeList, } from './types/endpoint.js';
5
+ import { addKeyIfDefined, copyKeyIfDefined } from './utils.js';
6
+ export class SchemaConverter {
7
+ constructor(schema, required, path = ['#'], location) {
8
+ this.schema = schema;
9
+ this.required = required;
10
+ this.path = path;
11
+ this.location = location;
12
+ }
13
+ convert() {
14
+ if (this.schema === undefined) {
15
+ throw new InvalidSchemaError(this.path, 'schema undefined');
16
+ }
17
+ // TODO(ronan): remove when fully migrated to endpoint type, or don't modify schema in evaluateCompositionsRecursive
18
+ let schema = _.cloneDeep(this.schema);
19
+ schema = this.evaluateCompositionsRecursive(this.path, schema);
20
+ return this.convertSchemaRecursive(this.path, schema, this.required);
21
+ }
22
+ /**
23
+ * This function should be used to reduce strictly `oneOf` and `anyOf` compositions.
24
+ *
25
+ * @param schemaArray `schema.allOf` or `schema.oneOf`
26
+ * @returns a schema array equivalent to the `schemaArray` argument, but in reduced form
27
+ */
28
+ evaluateOptionsCompositions(path, schemaArray) {
29
+ const evaluatedArray = schemaArray.flatMap((subschema, i) => {
30
+ var _a;
31
+ try {
32
+ return (_a = this.evaluateCompositionsRecursive([...path, i.toString()], subschema).oneOf) !== null && _a !== void 0 ? _a : [];
33
+ }
34
+ catch (error) {
35
+ if (error instanceof ImpossibleSchemaError) {
36
+ return [];
37
+ }
38
+ else {
39
+ throw error;
40
+ }
41
+ }
42
+ });
43
+ if (evaluatedArray.length === 0) {
44
+ throw new ImpossibleSchemaError(path, 'no valid options in schema:', JSON.stringify(schemaArray, undefined, 2));
45
+ }
46
+ return evaluatedArray;
47
+ }
48
+ evaluateCompositionsRecursive(path, schema) {
49
+ // evaluate compositions first; we are currently ignoring `not`
50
+ if (schema.oneOf && schema.oneOf.length > 0) {
51
+ schema.oneOf = this.evaluateOptionsCompositions([...path, 'oneOf'], schema.oneOf);
52
+ }
53
+ else {
54
+ schema.oneOf = [];
55
+ }
56
+ if (schema.anyOf && schema.anyOf.length > 0) {
57
+ schema.anyOf = this.evaluateOptionsCompositions([...path, 'anyOf'], schema.anyOf);
58
+ }
59
+ if (schema.allOf && schema.allOf.length > 0) {
60
+ const totalAllOfObj = schema.allOf
61
+ .map((subschema, i) => this.evaluateCompositionsRecursive([...path, 'allOf', i.toString()], subschema))
62
+ .reduce((schema1, schema2, i) => this.combineReducedSchemas([...path, 'allOf', i.toString()], schema1, schema2), {
63
+ oneOf: [],
64
+ });
65
+ schema.oneOf = this.multiplySchemaArrays(path, schema.oneOf, totalAllOfObj.oneOf);
66
+ }
67
+ // evaluate subschemas, if present
68
+ if (schema.properties) {
69
+ for (const key in schema.properties) {
70
+ schema.properties[key] = this.evaluateCompositionsRecursive([...path, 'properties', key], schema.properties[key]);
71
+ }
72
+ }
73
+ if ('items' in schema && schema.items) {
74
+ schema.items = this.evaluateCompositionsRecursive([...path, 'items'], schema.items);
75
+ }
76
+ if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
77
+ try {
78
+ schema.additionalProperties = this.evaluateCompositionsRecursive([...path, 'additionalProperties'], schema.additionalProperties);
79
+ }
80
+ catch (error) {
81
+ if (error instanceof ImpossibleSchemaError) {
82
+ // if additionalProperties schema is impossible, rather than error, just disallow additionalProperties
83
+ schema.additionalProperties = false;
84
+ }
85
+ else {
86
+ throw error;
87
+ }
88
+ }
89
+ }
90
+ if (schema.anyOf && schema.anyOf.length > 0) {
91
+ schema.oneOf = this.multiplySchemaArrays(path, schema.oneOf, schema.anyOf);
92
+ }
93
+ const topLevelSchemaArray = this.generateTopLevelSchemaArray(schema);
94
+ return { oneOf: this.multiplySchemaArrays(path, schema.oneOf, topLevelSchemaArray) };
95
+ }
96
+ generateTopLevelSchemaArray(schema) {
97
+ if (schema.nullable) {
98
+ const typedSchema = Object.assign({}, schema);
99
+ delete typedSchema.oneOf;
100
+ delete typedSchema.nullable;
101
+ const nullSchema = Object.assign({}, schema);
102
+ delete nullSchema.oneOf;
103
+ delete nullSchema.nullable;
104
+ nullSchema.type = 'null';
105
+ return [typedSchema, nullSchema];
106
+ }
107
+ if (Array.isArray(schema.type)) {
108
+ if (schema.type.length === 0) {
109
+ const topLevelSchema = Object.assign({}, schema);
110
+ delete topLevelSchema.oneOf;
111
+ delete topLevelSchema.type;
112
+ return [topLevelSchema];
113
+ }
114
+ return schema.type.map((typeString) => {
115
+ const topLevelSchema = Object.assign({}, schema);
116
+ delete topLevelSchema.oneOf;
117
+ topLevelSchema.type = typeString;
118
+ return topLevelSchema;
119
+ });
120
+ }
121
+ const topLevelSchema = Object.assign({}, schema);
122
+ delete topLevelSchema.oneOf;
123
+ return [topLevelSchema];
124
+ }
125
+ /**
126
+ * Given two arrays representing schema options, return an array representing schema options that satisfy one element in both arrays.
127
+ *
128
+ * It is helpful to think of each array as a union of all the schemas in the array. This function can then be thought of as taking
129
+ * the intersection of the two union types.
130
+ *
131
+ * @param a first array of schema options
132
+ * @param b second array of schema options
133
+ * @returns array of schemas that satisfy both arrays
134
+ */
135
+ multiplySchemaArrays(path, a, b) {
136
+ if (a.length === 0 && b.length === 0) {
137
+ return [{}];
138
+ }
139
+ if (a.length === 0) {
140
+ return b;
141
+ }
142
+ if (b.length === 0) {
143
+ return a;
144
+ }
145
+ const product = a.flatMap((schema1) => {
146
+ return b.flatMap((schema2) => {
147
+ try {
148
+ const combinedSchema = this.combineTopLevelSchemas(path, schema1, schema2);
149
+ return [combinedSchema];
150
+ }
151
+ catch (error) {
152
+ if (error instanceof ImpossibleSchemaError) {
153
+ return [];
154
+ }
155
+ else {
156
+ throw error;
157
+ }
158
+ }
159
+ });
160
+ });
161
+ if (product.length === 0) {
162
+ throw new ImpossibleSchemaError(path, 'impossible schema combination:', 'schema array 1:', JSON.stringify(a, undefined, 2), 'schema array 2:', JSON.stringify(b, undefined, 2));
163
+ }
164
+ return product;
165
+ }
166
+ combineReducedSchemas(path, schema1, schema2) {
167
+ var _a, _b;
168
+ return {
169
+ oneOf: this.multiplySchemaArrays(path, ((_a = schema1.oneOf) !== null && _a !== void 0 ? _a : []), ((_b = schema2.oneOf) !== null && _b !== void 0 ? _b : [])),
170
+ };
171
+ }
172
+ combineTopLevelSchemas(path, schema1, schema2) {
173
+ var _a, _b;
174
+ let type1 = schema1.type;
175
+ let type2 = schema2.type;
176
+ // don't throw an error if number type is being constricted
177
+ if (type1 === 'integer' && type2 === 'number') {
178
+ type2 = 'integer';
179
+ }
180
+ else if (type1 === 'number' && type2 === 'integer') {
181
+ type1 = 'integer';
182
+ }
183
+ if (type1 && type2 && type1 !== type2) {
184
+ throw new ImpossibleSchemaError(path, `mismatched type in composition: "${type1}" "${type2}"`);
185
+ }
186
+ for (const schema of [schema1, schema2]) {
187
+ if (typeof schema.exclusiveMaximum === 'number') {
188
+ if (schema.maximum === undefined || schema.maximum >= schema.exclusiveMaximum) {
189
+ schema.maximum = schema.exclusiveMaximum;
190
+ schema.exclusiveMaximum = true;
191
+ }
192
+ else {
193
+ schema.exclusiveMaximum = undefined;
194
+ }
195
+ }
196
+ if (typeof schema.exclusiveMinimum === 'number') {
197
+ if (schema.minimum === undefined || schema.minimum <= schema.exclusiveMinimum) {
198
+ schema.minimum = schema.exclusiveMinimum;
199
+ schema.exclusiveMinimum = true;
200
+ }
201
+ else {
202
+ schema.exclusiveMinimum = undefined;
203
+ }
204
+ }
205
+ }
206
+ const combinedSchema = {
207
+ title: takeLast(schema1, schema2, 'title'),
208
+ description: takeLast(schema1, schema2, 'description'),
209
+ format: takeLast(schema1, schema2, 'format'),
210
+ multipleOf: combine(schema1, schema2, 'multipleOf', lcm),
211
+ maximum: combine(schema1, schema2, 'maximum', Math.min),
212
+ minimum: combine(schema1, schema2, 'minimum', Math.max),
213
+ maxLength: combine(schema1, schema2, 'maxLength', Math.min),
214
+ minLength: combine(schema1, schema2, 'minLength', Math.max),
215
+ maxItems: combine(schema1, schema2, 'maxItems', Math.min),
216
+ minItems: combine(schema1, schema2, 'minItems', Math.max),
217
+ maxProperties: combine(schema1, schema2, 'maxProperties', Math.min),
218
+ minProperties: combine(schema1, schema2, 'minProperties', Math.max),
219
+ required: combine(schema1, schema2, 'required', (a, b) => b.concat(a.filter((value) => !b.includes(value)))),
220
+ enum: combine(schema1, schema2, 'enum', (a, b) => b.filter((value) => a.includes(value))),
221
+ readOnly: schema1.readOnly && schema2.readOnly,
222
+ writeOnly: schema1.writeOnly && schema2.writeOnly,
223
+ deprecated: schema1.deprecated && schema2.deprecated,
224
+ };
225
+ combinedSchema.exclusiveMaximum =
226
+ (schema1.maximum === combinedSchema.maximum ? schema1.exclusiveMaximum : undefined) ||
227
+ (schema2.maximum === combinedSchema.maximum ? schema2.exclusiveMaximum : undefined);
228
+ combinedSchema.exclusiveMinimum =
229
+ (schema1.minimum === combinedSchema.minimum ? schema1.exclusiveMinimum : undefined) ||
230
+ (schema2.minimum === combinedSchema.minimum ? schema2.exclusiveMinimum : undefined);
231
+ // don't use coalesce operator, since null is a valid example
232
+ const example1 = ((_a = schema1.examples) === null || _a === void 0 ? void 0 : _a[0]) !== undefined ? schema1.examples[0] : schema1.example;
233
+ const example2 = ((_b = schema2.examples) === null || _b === void 0 ? void 0 : _b[0]) !== undefined ? schema2.examples[0] : schema2.example;
234
+ if (example1 && example2 && typeof example1 === 'object' && typeof example2 === 'object') {
235
+ combinedSchema.example = Object.assign(Object.assign({}, example1), example2);
236
+ }
237
+ else {
238
+ // don't use coalesce operator, since null is a valid example
239
+ combinedSchema.example = example2 !== undefined ? example2 : example1;
240
+ }
241
+ const type = type1 !== null && type1 !== void 0 ? type1 : type2;
242
+ if (type === 'array') {
243
+ return Object.assign({ type, items: this.combineReducedSchemas([...path, 'items'], 'items' in schema1 && schema1.items ? schema1.items : {}, 'items' in schema2 && schema2.items ? schema2.items : {}) }, combinedSchema);
244
+ }
245
+ if (schema1.properties && schema2.properties) {
246
+ const combinedProperties = Object.assign({}, schema1.properties);
247
+ Object.entries(schema2.properties).forEach(([property, schema]) => {
248
+ const schema1Property = combinedProperties[property];
249
+ if (schema1Property) {
250
+ combinedProperties[property] = this.combineReducedSchemas([...path, 'properties', property], schema1Property, schema);
251
+ }
252
+ else {
253
+ combinedProperties[property] = schema;
254
+ }
255
+ });
256
+ combinedSchema.properties = combinedProperties;
257
+ }
258
+ else if (schema1.properties || schema2.properties) {
259
+ combinedSchema.properties = Object.assign(Object.assign({}, schema1.properties), schema2.properties);
260
+ }
261
+ if (schema1.additionalProperties === false || schema2.additionalProperties === false) {
262
+ combinedSchema.additionalProperties = false;
263
+ }
264
+ else if (schema1.additionalProperties &&
265
+ typeof schema1.additionalProperties === 'object' &&
266
+ schema2.additionalProperties &&
267
+ typeof schema2.additionalProperties === 'object') {
268
+ combinedSchema.additionalProperties = this.combineReducedSchemas([...path, 'additionalProperties'], schema1.additionalProperties, schema2.additionalProperties);
269
+ }
270
+ else if (schema1.additionalProperties && typeof schema1.additionalProperties === 'object') {
271
+ combinedSchema.additionalProperties = schema1.additionalProperties;
272
+ }
273
+ else if (schema2.additionalProperties && typeof schema2.additionalProperties === 'object') {
274
+ combinedSchema.additionalProperties = schema2.additionalProperties;
275
+ }
276
+ return Object.assign({ type }, combinedSchema);
277
+ }
278
+ convertSchemaRecursive(path, schema, required) {
279
+ if (schema.oneOf === undefined || schema.oneOf.length === 0) {
280
+ throw new ConversionError(path, 'missing schema definition');
281
+ }
282
+ const schemaArray = schema.oneOf.map((schema) => {
283
+ const sharedProps = {};
284
+ addKeyIfDefined('required', required, sharedProps);
285
+ copyKeyIfDefined('title', schema, sharedProps);
286
+ copyKeyIfDefined('description', schema, sharedProps);
287
+ copyKeyIfDefined('readOnly', schema, sharedProps);
288
+ copyKeyIfDefined('writeOnly', schema, sharedProps);
289
+ copyKeyIfDefined('deprecated', schema, sharedProps);
290
+ if (schema.type === undefined) {
291
+ const inferredType = inferType(schema);
292
+ if (inferredType === undefined) {
293
+ return Object.assign({ type: 'any' }, sharedProps);
294
+ }
295
+ schema.type = inferredType;
296
+ }
297
+ const type = schema.type;
298
+ if (!typeList.includes(type)) {
299
+ throw new InvalidSchemaError(path, `invalid schema type: ${schema.type}`);
300
+ }
301
+ switch (schema.type) {
302
+ case 'boolean':
303
+ const booleanProps = sharedProps;
304
+ copyKeyIfDefined('default', schema, booleanProps);
305
+ copyExampleIfDefined(schema, booleanProps);
306
+ return Object.assign({ type: schema.type }, booleanProps);
307
+ case 'number':
308
+ case 'integer':
309
+ if (schema.enum) {
310
+ const numberEnumProps = sharedProps;
311
+ copyKeyIfDefined('default', schema, numberEnumProps);
312
+ copyExampleIfDefined(schema, numberEnumProps);
313
+ return Object.assign({ type: schema.type === 'number' ? 'enum<number>' : 'enum<integer>', enum: schema.enum }, numberEnumProps);
314
+ }
315
+ const numberProps = sharedProps;
316
+ copyKeyIfDefined('multipleOf', schema, numberProps);
317
+ copyKeyIfDefined('maximum', schema, numberProps);
318
+ copyKeyIfDefined('exclusiveMaximum', schema, numberProps);
319
+ copyKeyIfDefined('minimum', schema, numberProps);
320
+ copyKeyIfDefined('exclusiveMinimum', schema, numberProps);
321
+ copyKeyIfDefined('default', schema, numberProps);
322
+ copyExampleIfDefined(schema, numberProps);
323
+ return Object.assign({ type: schema.type }, numberProps);
324
+ case 'string':
325
+ if (schema.enum) {
326
+ const stringEnumProps = sharedProps;
327
+ copyKeyIfDefined('default', schema, stringEnumProps);
328
+ copyExampleIfDefined(schema, stringEnumProps);
329
+ return Object.assign({ type: 'enum<string>', enum: schema.enum }, stringEnumProps);
330
+ }
331
+ const stringProps = sharedProps;
332
+ copyKeyIfDefined('format', schema, stringProps);
333
+ copyKeyIfDefined('pattern', schema, stringProps);
334
+ copyKeyIfDefined('maxLength', schema, stringProps);
335
+ copyKeyIfDefined('minLength', schema, stringProps);
336
+ copyKeyIfDefined('default', schema, stringProps);
337
+ copyExampleIfDefined(schema, stringProps);
338
+ return Object.assign({ type: schema.type }, stringProps);
339
+ case 'array':
340
+ const arrayProps = sharedProps;
341
+ const items =
342
+ // validator allows items to be null
343
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
344
+ typeof schema.items === 'object' && schema.items != null
345
+ ? this.convertSchemaRecursive([...path, 'items'], schema.items)
346
+ : [{ type: 'any' }];
347
+ copyKeyIfDefined('maxItems', schema, arrayProps);
348
+ copyKeyIfDefined('minItems', schema, arrayProps);
349
+ copyKeyIfDefined('uniqueItems', schema, arrayProps);
350
+ copyKeyIfDefined('default', schema, arrayProps);
351
+ copyExampleIfDefined(schema, arrayProps);
352
+ return Object.assign({ type: schema.type, items }, arrayProps);
353
+ case 'object':
354
+ const properties = this.convertProperties([...path, 'properties'], schema.properties, schema.required);
355
+ const additionalProperties =
356
+ // validator allows additionalProperties to be null
357
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
358
+ typeof schema.additionalProperties === 'object' && schema.additionalProperties != null
359
+ ? this.convertSchemaRecursive([...path, 'additionalProperties'], schema.additionalProperties)
360
+ : schema.additionalProperties;
361
+ const objectProperties = sharedProps;
362
+ addKeyIfDefined('additionalProperties', additionalProperties, objectProperties);
363
+ copyKeyIfDefined('maxProperties', schema, objectProperties);
364
+ copyKeyIfDefined('minProperties', schema, objectProperties);
365
+ copyKeyIfDefined('default', schema, objectProperties);
366
+ copyExampleIfDefined(schema, objectProperties);
367
+ return Object.assign({ type: schema.type, properties }, objectProperties);
368
+ case 'null':
369
+ const nullProps = sharedProps;
370
+ copyKeyIfDefined('default', schema, nullProps);
371
+ copyExampleIfDefined(schema, nullProps);
372
+ return Object.assign({ type: schema.type }, nullProps);
373
+ default:
374
+ throw new ImpossibleSchemaError(path, `impossible type reached: ${schema.type}`);
375
+ }
376
+ });
377
+ if (!schemaArray[0]) {
378
+ throw new ConversionError(path, 'missing schema definition in position 0');
379
+ }
380
+ // must unpack first element to satisfy type
381
+ return [schemaArray[0], ...schemaArray.slice(1)];
382
+ }
383
+ convertProperties(path, properties, required) {
384
+ if (properties === undefined) {
385
+ return {};
386
+ }
387
+ const newEntries = Object.entries(properties).map(([name, schema]) => {
388
+ return [
389
+ name,
390
+ this.convertSchemaRecursive([...path, name], schema, (required === null || required === void 0 ? void 0 : required.includes(name)) ? true : undefined),
391
+ ];
392
+ });
393
+ return Object.fromEntries(newEntries);
394
+ }
395
+ static convert({ schema, required, path, location, }) {
396
+ return new SchemaConverter(schema, required, path, location).convert();
397
+ }
398
+ }
399
+ const copyExampleIfDefined = (source, destination) => {
400
+ var _a;
401
+ const example = ((_a = source.examples) === null || _a === void 0 ? void 0 : _a[0]) !== undefined ? source.examples[0] : source.example;
402
+ if (example !== undefined) {
403
+ destination.example = example;
404
+ }
405
+ };
406
+ const takeLast = (schema1, schema2, key) => {
407
+ var _a;
408
+ return (_a = schema2[key]) !== null && _a !== void 0 ? _a : schema1[key];
409
+ };
410
+ const combine = (schema1, schema2, key, transform) => {
411
+ var _a;
412
+ return schema1[key] !== undefined && schema2[key] !== undefined
413
+ ? transform(schema1[key], schema2[key])
414
+ : (_a = schema1[key]) !== null && _a !== void 0 ? _a : schema2[key];
415
+ };
416
+ /**
417
+ * Given an OpenAPI 3.1 schema, this function will attempt to determine the schema type
418
+ * based on the properties present in the schema. This is useful for assigning types to
419
+ * schemas that are missing a type.
420
+ *
421
+ * For example, if a schema has no type but has `schema.properties`, we can infer the
422
+ * intended type is `object`.
423
+ *
424
+ * @param schema
425
+ * @returns if exactly one type can be inferred, the string corresponding to that type; otherwise `undefined`
426
+ */
427
+ const inferType = (schema) => {
428
+ var _a, _b;
429
+ let type = undefined;
430
+ if (schema.format !== undefined ||
431
+ schema.pattern !== undefined ||
432
+ schema.minLength !== undefined ||
433
+ schema.maxLength !== undefined ||
434
+ ((_a = schema.enum) === null || _a === void 0 ? void 0 : _a.every((option) => typeof option === 'string'))) {
435
+ type = 'string';
436
+ }
437
+ if (schema.multipleOf !== undefined ||
438
+ schema.minimum !== undefined ||
439
+ schema.maximum !== undefined ||
440
+ schema.exclusiveMinimum !== undefined ||
441
+ schema.exclusiveMaximum !== undefined ||
442
+ ((_b = schema.enum) === null || _b === void 0 ? void 0 : _b.every((option) => typeof option === 'number'))) {
443
+ if (type !== undefined) {
444
+ return undefined;
445
+ }
446
+ type = 'number'; // less specific than 'integer'
447
+ }
448
+ if (('items' in schema && schema.items !== undefined) ||
449
+ schema.minItems !== undefined ||
450
+ schema.maxItems !== undefined ||
451
+ schema.uniqueItems !== undefined) {
452
+ if (type !== undefined) {
453
+ return undefined;
454
+ }
455
+ type = 'array';
456
+ }
457
+ if (schema.additionalProperties !== undefined ||
458
+ schema.properties !== undefined ||
459
+ schema.minProperties !== undefined ||
460
+ schema.maxProperties !== undefined) {
461
+ if (type !== undefined) {
462
+ return undefined;
463
+ }
464
+ type = 'object';
465
+ }
466
+ return type;
467
+ };
@@ -0,0 +1,10 @@
1
+ import { OpenAPIV3_1 } from 'openapi-types';
2
+ import { SecurityOption } from './types/endpoint.js';
3
+ export declare class SecurityConverter {
4
+ readonly securityRequirements: OpenAPIV3_1.SecurityRequirementObject[] | undefined;
5
+ readonly securitySchemes: OpenAPIV3_1.ComponentsObject['securitySchemes'];
6
+ private constructor();
7
+ private convert;
8
+ private addSecurityParameters;
9
+ static convert(securityRequirements: OpenAPIV3_1.SecurityRequirementObject[] | undefined, securitySchemes: OpenAPIV3_1.ComponentsObject['securitySchemes']): SecurityOption[];
10
+ }
@@ -0,0 +1,80 @@
1
+ import { InvalidSchemaError } from './errors.js';
2
+ import { copyKeyIfDefined } from './utils.js';
3
+ export class SecurityConverter {
4
+ constructor(securityRequirements, securitySchemes) {
5
+ this.securityRequirements = securityRequirements;
6
+ this.securitySchemes = securitySchemes;
7
+ }
8
+ convert() {
9
+ if (this.securityRequirements === undefined || this.securityRequirements.length === 0) {
10
+ return [];
11
+ }
12
+ if (this.securitySchemes === undefined) {
13
+ throw new InvalidSchemaError(['#', 'components'], 'securitySchemes not defined');
14
+ }
15
+ // TODO(ronan): make this work for camel-case as well
16
+ return this.securityRequirements.map((security) => {
17
+ const title = Object.keys(security)
18
+ .map((securityName) => securityName.replace(/[_-]/g, ' '))
19
+ .join(' & ');
20
+ const parameterSections = {
21
+ query: {},
22
+ header: {},
23
+ cookie: {},
24
+ };
25
+ Object.keys(security).forEach((securityName) => {
26
+ var _a;
27
+ const securityScheme = (_a = this.securitySchemes) === null || _a === void 0 ? void 0 : _a[securityName];
28
+ if (securityScheme === undefined) {
29
+ throw new InvalidSchemaError(['#', 'components', 'securitySchemes'], `security scheme not defined: '${securityName}'`);
30
+ }
31
+ this.addSecurityParameters(securityName, securityScheme, parameterSections);
32
+ });
33
+ return {
34
+ title,
35
+ parameters: parameterSections,
36
+ };
37
+ });
38
+ }
39
+ addSecurityParameters(securityName, securityScheme, parameterSections) {
40
+ switch (securityScheme.type) {
41
+ case 'apiKey': {
42
+ if (!['header', 'query', 'cookie'].includes(securityScheme.in)) {
43
+ throw new InvalidSchemaError(['#', 'components', 'securitySchemes', securityName], `invalid security scheme location provided: '${securityScheme.in}'`);
44
+ }
45
+ const paramGroup = securityScheme.in;
46
+ const schema = { type: 'apiKey' };
47
+ copyKeyIfDefined('description', securityScheme, schema);
48
+ parameterSections[paramGroup][securityScheme.name] = schema;
49
+ return;
50
+ }
51
+ case 'http': {
52
+ const scheme = securityScheme.scheme;
53
+ if (scheme === 'basic' || scheme === 'bearer') {
54
+ const schema = {
55
+ type: 'http',
56
+ scheme,
57
+ };
58
+ copyKeyIfDefined('description', securityScheme, schema);
59
+ parameterSections.header['Authorization'] = schema;
60
+ }
61
+ else {
62
+ throw new InvalidSchemaError(['#', 'components', 'securitySchemes', securityName], `encountered unknown HTTP security scheme: '${securityScheme.scheme}'`);
63
+ }
64
+ return;
65
+ }
66
+ case 'oauth2': {
67
+ const schema = { type: 'oauth2' };
68
+ copyKeyIfDefined('description', securityScheme, schema);
69
+ parameterSections.header['Authorization'] = schema;
70
+ return;
71
+ }
72
+ case 'openIdConnect': {
73
+ return;
74
+ }
75
+ }
76
+ }
77
+ static convert(securityRequirements, securitySchemes) {
78
+ return new SecurityConverter(securityRequirements, securitySchemes).convert();
79
+ }
80
+ }
@@ -0,0 +1,9 @@
1
+ import { OpenAPIV3_1 } from 'openapi-types';
2
+ import { Server } from './types/endpoint.js';
3
+ export declare class ServersConverter {
4
+ readonly servers: OpenAPIV3_1.ServerObject[] | undefined;
5
+ private constructor();
6
+ private convert;
7
+ private convertVariables;
8
+ static convert(servers: OpenAPIV3_1.ServerObject[] | undefined): Server[] | undefined;
9
+ }
@@ -0,0 +1,47 @@
1
+ export class ServersConverter {
2
+ constructor(servers) {
3
+ this.servers = servers;
4
+ }
5
+ convert() {
6
+ if (this.servers === undefined || this.servers.length === 0) {
7
+ return undefined;
8
+ }
9
+ return this.servers.map(({ url, description, variables }) => {
10
+ return {
11
+ url,
12
+ description,
13
+ variables: this.convertVariables(variables),
14
+ };
15
+ });
16
+ }
17
+ convertVariables(variables) {
18
+ if (variables === undefined || Object.keys(variables).length === 0) {
19
+ return undefined;
20
+ }
21
+ const newEntries = Object.entries(variables).map(([name, variable]) => {
22
+ if (variable.enum) {
23
+ return [
24
+ name,
25
+ {
26
+ type: 'enum<string>',
27
+ enum: variable.enum,
28
+ description: variable.description,
29
+ default: variable.default,
30
+ },
31
+ ];
32
+ }
33
+ return [
34
+ name,
35
+ {
36
+ type: 'string',
37
+ description: variable.description,
38
+ default: variable.default,
39
+ },
40
+ ];
41
+ });
42
+ return Object.fromEntries(newEntries);
43
+ }
44
+ static convert(servers) {
45
+ return new ServersConverter(servers).convert();
46
+ }
47
+ }
@@ -0,0 +1,10 @@
1
+ export declare const generateMessage: (path: string[], messages?: string[]) => string;
2
+ export declare class InvalidSchemaError extends Error {
3
+ constructor(path: string[], ...messages: string[]);
4
+ }
5
+ export declare class ImpossibleSchemaError extends Error {
6
+ constructor(path: string[], ...messages: string[]);
7
+ }
8
+ export declare class ConversionError extends Error {
9
+ constructor(path: string[], ...messages: string[]);
10
+ }
@@ -0,0 +1,27 @@
1
+ export const generateMessage = (path, messages = []) => {
2
+ const pathString = path
3
+ .map((component) => component.replace('\\', '\\\\').replace('/', '\\/'))
4
+ .join('/');
5
+ return [pathString, ...messages].join('\n');
6
+ };
7
+ export class InvalidSchemaError extends Error {
8
+ constructor(path, ...messages) {
9
+ super(generateMessage(path, messages));
10
+ this.name = 'InvalidSchemaError';
11
+ Object.setPrototypeOf(this, InvalidSchemaError.prototype);
12
+ }
13
+ }
14
+ export class ImpossibleSchemaError extends Error {
15
+ constructor(path, ...messages) {
16
+ super(generateMessage(path, messages));
17
+ this.name = 'ImpossibleSchemaError';
18
+ Object.setPrototypeOf(this, ImpossibleSchemaError.prototype);
19
+ }
20
+ }
21
+ export class ConversionError extends Error {
22
+ constructor(path, ...messages) {
23
+ super(generateMessage(path, messages));
24
+ this.name = 'ConversionError';
25
+ Object.setPrototypeOf(this, ConversionError.prototype);
26
+ }
27
+ }
@@ -0,0 +1,2 @@
1
+ export declare const addKeyIfDefined: <D, K extends keyof D>(key: K, value: D[K] | undefined, destination: D) => void;
2
+ export declare const copyKeyIfDefined: <D, K extends keyof D>(key: K, source: Pick<D, K>, destination: D) => void;
@@ -0,0 +1,12 @@
1
+ export const addKeyIfDefined = (key, value, destination) => {
2
+ if (value !== undefined) {
3
+ destination[key] = value;
4
+ }
5
+ };
6
+ export const copyKeyIfDefined = (key, source, destination) => {
7
+ // eslint does not recognize that D[K] could be undefined
8
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
9
+ if (source[key] !== undefined) {
10
+ destination[key] = source[key];
11
+ }
12
+ };