fork of hey-api/openapi-ts because I need some additional things
at feat/skip-token 169 lines 4.2 kB view raw
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};