fork of hey-api/openapi-ts because I need some additional things
1import type { Context } from '../../../ir/context';
2import type { IR } from '../../../ir/types';
3import type {
4 OperationObject,
5 ParameterObject,
6 ReferenceObject,
7 SchemaObject,
8} from '../types/spec';
9import { paginationField } from './pagination';
10import { parseExtensions, schemaToIrSchema } from './schema';
11
12type Parameter = Exclude<ParameterObject, { in: 'body' }>;
13
14/**
15 * Returns default parameter `explode` based on value of `collectionFormat`.
16 */
17const defaultExplode = (collectionFormat: Parameter['collectionFormat']): boolean => {
18 switch (collectionFormat) {
19 case 'multi':
20 return true;
21 case 'csv':
22 case 'pipes':
23 case 'ssv':
24 case 'tsv':
25 default:
26 return false;
27 }
28};
29
30/**
31 * Returns default parameter `style` based on value of `in`.
32 */
33const defaultStyle = (_in: Parameter['in']): Required<IR.ParameterObject>['style'] => {
34 switch (_in) {
35 case 'header':
36 case 'path':
37 return 'simple';
38 case 'query':
39 default:
40 return 'form';
41 }
42};
43
44export const parametersArrayToObject = ({
45 context,
46 operation,
47 parameters,
48}: {
49 context: Context;
50 operation: OperationObject;
51 parameters?: ReadonlyArray<ParameterObject | ReferenceObject>;
52}): IR.ParametersObject | undefined => {
53 if (!parameters || !Object.keys(parameters).length) {
54 return;
55 }
56
57 const parametersObject: IR.ParametersObject = {};
58
59 for (const parameterOrReference of parameters) {
60 const parameter =
61 '$ref' in parameterOrReference
62 ? context.dereference<ParameterObject>(parameterOrReference)
63 : parameterOrReference;
64
65 // push request body parameters into a separate field
66 if (parameter.in === 'body' || parameter.in === 'formData') {
67 // @ts-expect-error
68 if (!operation.requestBody) {
69 // @ts-expect-error
70 operation.requestBody = [];
71 }
72
73 // @ts-expect-error
74 operation.requestBody.push(parameter);
75 continue;
76 }
77
78 if (!parametersObject[parameter.in]) {
79 parametersObject[parameter.in] = {};
80 }
81
82 // lowercase keys for case insensitive access
83 parametersObject[parameter.in]![parameter.name.toLocaleLowerCase()] = parameterToIrParameter({
84 $ref: `#/todo/real/path/to/parameter/${parameter.name}`,
85 context,
86 parameter,
87 });
88 }
89
90 return parametersObject;
91};
92
93const parameterToIrParameter = ({
94 $ref,
95 context,
96 parameter,
97}: {
98 $ref: string;
99 context: Context;
100 parameter: Parameter;
101}): IR.ParameterObject => {
102 const schema = parameter;
103
104 const finalSchema: SchemaObject =
105 schema && '$ref' in schema
106 ? {
107 allOf: [
108 {
109 ...schema,
110 $ref: schema.$ref as string,
111 required: Array.isArray(schema.required) ? schema.required : [],
112 type: schema.type as SchemaObject['type'],
113 },
114 ],
115 description: parameter.description,
116 }
117 : {
118 description: parameter.description,
119 ...schema,
120 required: Array.isArray(schema.required) ? schema.required : [],
121 type: schema.type as SchemaObject['type'],
122 };
123
124 const pagination = paginationField({
125 context,
126 name: parameter.name,
127 schema: finalSchema,
128 });
129
130 const style = defaultStyle(parameter.in);
131 const explode = defaultExplode(parameter.collectionFormat);
132 const allowReserved = false;
133
134 const irParameter: IR.ParameterObject = {
135 allowReserved,
136 explode,
137 location: parameter.in as IR.ParameterObject['location'],
138 name: parameter.name,
139 schema: schemaToIrSchema({
140 context,
141 schema: finalSchema,
142 state: {
143 $ref,
144 circularReferenceTracker: new Set(),
145 },
146 }),
147 style,
148 };
149
150 if (parameter.description) {
151 irParameter.description = parameter.description;
152 }
153
154 if (pagination) {
155 irParameter.pagination = pagination;
156 }
157
158 if (parameter.required) {
159 irParameter.required = parameter.required;
160 }
161
162 parseExtensions({
163 source: parameter,
164 target: irParameter,
165 });
166
167 return irParameter;
168};