import { camelCase as camelCaseString } from 'camel-case' ; import { snakeCase as snakeCaseString } from 'snake-case' ; import { headerCase as headerCaseString } from 'header-case' ; import { applyCaseOptions , preserveSpecificKeys } from './decorators' ; import { isFormData , isTransformable , isURLSearchParams } from './util' ; import { CaseFunction , CaseFunctions , CaseFunctionTypes , CreateObjectTransformer , CreateObjectTransformerOf , CreateObjectTransformers , ObjectTransformerOptions , ObjectTransformers , Transformable , } from './types' ; const caseFunctions = { snake : snakeCaseString , camel : camelCaseString , header : headerCaseString , } ; const transformObjectUsingCallbackRecursive = ( data , fn , overwrite ) : unknown => { if ( ! isTransformable ( data ) ) { return data ; } if ( ( isFormData ( data ) || isURLSearchParams ( data ) ) && ( ! data . entries || ( overwrite && ! data . delete ) ) ) { const type = isFormData ( data ) ? 'FormData' : 'URLSearchParams' ; const polyfill = isFormData ( data ) ? 'https://github.com/jimmywarting/FormData' : 'https://github.com/jerrybendy/url-search-params-polyfill' ; if ( typeof navigator !== 'undefined' && navigator . product === 'ReactNative' ) { console . warn ( `Be careful that ${ type } cannot be transformed on React Native. If you intentionally implemented, ignore this kind of warning: https://facebook.github.io/react-native/docs/debugging.html` ) ; } else { if ( ! data . entries ) { console . warn ( `You must use polyfill of ${ type }.prototype.entries() on Internet Explorer or Safari: ${ polyfill }` ) ; } if ( overwrite && ! data . delete ) { console . warn ( `You must use polyfill of ${ type }.prototype.delete() on Internet Explorer or Safari: ${ polyfill }` ) ; } } return data ; } const prototype = Object . getPrototypeOf ( data ) ; const store = overwrite ? data : ! prototype ? Object . create ( null ) : new prototype . constructor ( ) ; let series ; if ( isFormData ( data ) || isURLSearchParams ( data ) ) { series = data . entries ( ) ; if ( overwrite ) { series = [ ... series ] ; for ( const [ key ] of series ) { data . delete ( key as string ) ; } } } else { series = Object . entries ( data ) ; if ( overwrite && ! Array . isArray ( data ) ) { for ( const [ key ] of series ) { delete data [ key as string ] ; } } } for ( const [ key , value ] of series ) { if ( isFormData ( store ) || isURLSearchParams ( store ) ) { store . append ( fn ( key as string ) , value as string & File ) ; } else if ( key !== '__proto__' ) { store [ fn ( typeof key === 'string' ? key : `${ key }` ) ] = transformObjectUsingCallbackRecursive ( value , fn , overwrite ) ; } } return store ; } ; const transformObjectUsingCallback = ( data , fn , options ? ) : unknown => { fn = applyCaseOptions ( fn , { stripRegexp : /[^A-Z0-9[\]]+/gi , ... options ?. caseOptions , } ) ; if ( options ?. preservedKeys ) { fn = preserveSpecificKeys ( fn , options . preservedKeys ) ; } return transformObjectUsingCallbackRecursive ( data , fn , options ?. overwrite || false ) ; } ; export const createObjectTransformer = ( fn ) => { return ( data , options ) : ReturnType < ReturnType < CreateObjectTransformer > > => { return transformObjectUsingCallback ( data , fn , options ) ; } ; } ; export const createObjectTransformerOf = ( functionName , options ) => { return createObjectTransformer ( options ?. [ functionName ] || caseFunctions [ functionName ] ) ; } ; export const createObjectTransformers = ( options ) => { const functionNames = Object . keys ( caseFunctions ) as CaseFunctionTypes [ ] ; const objectTransformers = { } as ObjectTransformers ; for ( const functionName of functionNames ) { objectTransformers [ functionName ] = createObjectTransformerOf ( functionName , options ) ; } return objectTransformers ; } ;