fork of hey-api/openapi-ts because I need some additional things
1interface SerializeOptions<T>
2 extends SerializePrimitiveOptions,
3 SerializerOptions<T> {}
4
5interface SerializePrimitiveOptions {
6 allowReserved?: boolean;
7 name: string;
8}
9
10export interface SerializerOptions<T> {
11 /**
12 * @default true
13 */
14 explode: boolean;
15 style: T;
16}
17
18export type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited';
19export type ArraySeparatorStyle = ArrayStyle | MatrixStyle;
20type MatrixStyle = 'label' | 'matrix' | 'simple';
21export type ObjectStyle = 'form' | 'deepObject';
22type ObjectSeparatorStyle = ObjectStyle | MatrixStyle;
23
24interface SerializePrimitiveParam extends SerializePrimitiveOptions {
25 value: string;
26}
27
28export const separatorArrayExplode = (style: ArraySeparatorStyle) => {
29 switch (style) {
30 case 'label':
31 return '.';
32 case 'matrix':
33 return ';';
34 case 'simple':
35 return ',';
36 default:
37 return '&';
38 }
39};
40
41export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => {
42 switch (style) {
43 case 'form':
44 return ',';
45 case 'pipeDelimited':
46 return '|';
47 case 'spaceDelimited':
48 return '%20';
49 default:
50 return ',';
51 }
52};
53
54export const separatorObjectExplode = (style: ObjectSeparatorStyle) => {
55 switch (style) {
56 case 'label':
57 return '.';
58 case 'matrix':
59 return ';';
60 case 'simple':
61 return ',';
62 default:
63 return '&';
64 }
65};
66
67export const serializeArrayParam = ({
68 allowReserved,
69 explode,
70 name,
71 style,
72 value,
73}: SerializeOptions<ArraySeparatorStyle> & {
74 value: unknown[];
75}) => {
76 if (!explode) {
77 const joinedValues = (
78 allowReserved ? value : value.map((v) => encodeURIComponent(v as string))
79 ).join(separatorArrayNoExplode(style));
80 switch (style) {
81 case 'label':
82 return `.${joinedValues}`;
83 case 'matrix':
84 return `;${name}=${joinedValues}`;
85 case 'simple':
86 return joinedValues;
87 default:
88 return `${name}=${joinedValues}`;
89 }
90 }
91
92 const separator = separatorArrayExplode(style);
93 const joinedValues = value
94 .map((v) => {
95 if (style === 'label' || style === 'simple') {
96 return allowReserved ? v : encodeURIComponent(v as string);
97 }
98
99 return serializePrimitiveParam({
100 allowReserved,
101 name,
102 value: v as string,
103 });
104 })
105 .join(separator);
106 return style === 'label' || style === 'matrix'
107 ? separator + joinedValues
108 : joinedValues;
109};
110
111export const serializePrimitiveParam = ({
112 allowReserved,
113 name,
114 value,
115}: SerializePrimitiveParam) => {
116 if (value === undefined || value === null) {
117 return '';
118 }
119
120 if (typeof value === 'object') {
121 throw new Error(
122 'Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.',
123 );
124 }
125
126 return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
127};
128
129export const serializeObjectParam = ({
130 allowReserved,
131 explode,
132 name,
133 style,
134 value,
135 valueOnly,
136}: SerializeOptions<ObjectSeparatorStyle> & {
137 value: Record<string, unknown> | Date;
138 valueOnly?: boolean;
139}) => {
140 if (value instanceof Date) {
141 return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
142 }
143
144 if (style !== 'deepObject' && !explode) {
145 let values: string[] = [];
146 Object.entries(value).forEach(([key, v]) => {
147 values = [
148 ...values,
149 key,
150 allowReserved ? (v as string) : encodeURIComponent(v as string),
151 ];
152 });
153 const joinedValues = values.join(',');
154 switch (style) {
155 case 'form':
156 return `${name}=${joinedValues}`;
157 case 'label':
158 return `.${joinedValues}`;
159 case 'matrix':
160 return `;${name}=${joinedValues}`;
161 default:
162 return joinedValues;
163 }
164 }
165
166 const separator = separatorObjectExplode(style);
167 const joinedValues = Object.entries(value)
168 .map(([key, v]) =>
169 serializePrimitiveParam({
170 allowReserved,
171 name: style === 'deepObject' ? `${name}[${key}]` : key,
172 value: v as string,
173 }),
174 )
175 .join(separator);
176 return style === 'label' || style === 'matrix'
177 ? separator + joinedValues
178 : joinedValues;
179};