import * as t from "@babel/types" ; import { trackComments } from "../util" ; export const ObjectTypeAnnotation = { enter ( path , state ) { const { properties } = path . node ; if ( properties . length > 0 ) { const trailingComments = [ ] ; const lastProp = properties [ properties . length - 1 ] ; for ( let i = lastProp . loc . end . line ; i < path . node . loc . end . line ; i ++ ) { if ( state . startLineToComments [ i ] ) { trailingComments . push ( state . startLineToComments [ i ] ) ; } } lastProp . trailingComments = trailingComments ; } } , exit ( path ) { const { exact , callProperties , properties , indexers } = path . node ; if ( exact ) { console . warn ( "downgrading exact object type" ) ; } const elements = [ ] ; const spreads = [ ] ; if ( callProperties ) { for ( const prop of callProperties ) { elements . push ( prop ) ; } } for ( const prop of properties ) { if ( t . isObjectTypeSpreadProperty ( prop ) ) { const { argument } = prop ; spreads . push ( argument ) ; } else { elements . push ( prop ) ; } } indexers . forEach ( ( indexer ) => { const value = indexer . typeAnnotation . typeAnnotation ; const key = indexer . parameters [ 0 ] . typeAnnotation . typeAnnotation ; if ( t . isTSSymbolKeyword ( key ) || t . isTSStringKeyword ( key ) || t . isTSNumberKeyword ( key ) || t . isTSTypeReference ( key ) ) { elements . push ( indexer ) ; } else { const name = indexer . parameters [ 0 ] . name ; const typeParameter = t . tsTypeParameter ( key , undefined , name ) ; const mappedType = { type : "TSMappedType" , typeParameter : typeParameter , typeAnnotation : value , optional : true , } ; spreads . push ( mappedType ) ; } } ) ; if ( spreads . length === 0 && elements . length === 1 && indexers . length === 1 ) { const indexer = indexers [ 0 ] ; const value = indexer . typeAnnotation . typeAnnotation ; const key = indexer . parameters [ 0 ] . typeAnnotation . typeAnnotation ; const record = t . tsTypeReference ( t . identifier ( "Record" ) , t . tsTypeParameterInstantiation ( [ key , value ] ) ) ; if ( indexer . readonly ) { path . replaceWith ( t . tsTypeReference ( t . identifier ( "Readonly" ) , t . tsTypeParameterInstantiation ( [ record ] ) ) ) ; } else { path . replaceWith ( record ) ; } return ; } if ( spreads . length > 0 && elements . length > 0 ) { path . replaceWith ( t . tsIntersectionType ( [ ... spreads , t . tsTypeLiteral ( elements ) ] ) ) ; } else if ( spreads . length > 0 ) { path . replaceWith ( t . tsIntersectionType ( spreads ) ) ; } else { const typeLiteral = t . tsTypeLiteral ( elements ) ; path . replaceWith ( typeLiteral ) ; } } , } ; export const ObjectTypeCallProperty = { exit ( path , state ) { const { value , leadingComments , trailingComments , loc } = path . node ; const { typeParameters , parameters , typeAnnotation } = value ; const replacement = t . tsCallSignatureDeclaration ( typeParameters , parameters , typeAnnotation ) ; replacement . leadingComments = leadingComments ; replacement . trailingComments = trailingComments ; replacement . loc = loc ; trackComments ( replacement , state ) ; path . replaceWith ( replacement ) ; } , } ; export const ObjectTypeProperty = { exit ( path , state ) { const { key , value , optional , variance , kind , method , leadingComments , trailingComments , loc , } = path . node ; const typeAnnotation = t . tsTypeAnnotation ( value ) ; const initializer = undefined ; const computed = false ; const readonly = variance && variance . kind === "plus" ; if ( variance && variance . kind === "minus" ) { console . warn ( "typescript doesn't support writeonly properties" ) ; } if ( kind !== "init" ) { console . warn ( "we don't handle get() or set() yet, :P" ) ; } if ( method ) { const methodSignature = { type : "TSMethodSignature" , key , typeParameters : value . typeParameters , parameters : value . parameters , typeAnnotation : value . typeAnnotation , computed , optional , leadingComments , trailingComments , loc , } ; trackComments ( methodSignature , state ) ; path . replaceWith ( methodSignature ) ; } else { const propertySignature = { type : "TSPropertySignature" , key , typeAnnotation , computed , optional , readonly , leadingComments , trailingComments , loc , } ; trackComments ( propertySignature , state ) ; path . replaceWith ( propertySignature ) ; } } , } ; export const ObjectTypeIndexer = { exit ( path , state ) { const { id , key , value , variance , leadingComments , trailingComments , loc , } = path . node ; const readonly = variance && variance . kind === "plus" ; if ( variance && variance . kind === "minus" ) { console . warn ( "typescript doesn't support writeonly properties" ) ; } const identifier = { type : "Identifier" , name : id ? id . name : "key" , typeAnnotation : t . tsTypeAnnotation ( key ) , } ; const indexSignature = { type : "TSIndexSignature" , parameters : [ identifier ] , typeAnnotation : t . tsTypeAnnotation ( value ) , readonly , leadingComments , trailingComments , loc , } ; trackComments ( indexSignature , state ) ; path . replaceWith ( indexSignature ) ; } , } ;