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