import VCF from '@gmod/vcf' ; import { VcfFeature } from '@jbrowse/plugin-variants' ; import { bufferToString , Row , RowSet , Column , ParseOptions , } from './ImportUtils' ; const vcfCoreColumns = [ { name : 'CHROM' , type : 'Text' } , { name : 'POS' , type : 'Number' } , { name : 'ID' , type : 'Text' } , { name : 'REF' , type : 'Text' } , { name : 'ALT' , type : 'Text' } , { name : 'QUAL' , type : 'Number' } , { name : 'FILTER' , type : 'Text' } , { name : 'INFO' , type : 'Text' } , { name : 'FORMAT' , type : 'Text' } , ] ; function vcfRecordToRow ( vcfParser , line , lineNumber ) { const vcfVariant = vcfParser . parseLine ( line ) ; const vcfFeature = new VcfFeature ( { variant : vcfVariant , parser : vcfParser , id : `vcf-${ lineNumber }` , } ) ; const data = line . split ( '\t' ) . map ( d => ( d === '.' ? '' : d ) ) ; if ( data . length === 8 ) { data . push ( '' ) ; } const row = { id : String ( lineNumber + 1 ) , extendedData : { vcfFeature : vcfFeature . toJSON ( ) } , cells : data . map ( ( text , columnNumber ) => { return { columnNumber , text , } ; } ) , } ; return row ; } export function parseVcfBuffer ( buffer , options = { hasColumnNameLine : false , columnNameLineNumber : 0 , isValidRefName : ( ) => false , } ) { let { header , body } = splitVcfFileHeaderAndBody ( bufferToString ( buffer ) ) ; const rows = [ ] ; const vcfParser = new VCF ( { header } ) ; header = '' ; body . split ( '\n' ) . forEach ( ( line , lineNumber ) => { if ( /\S/ . test ( line ) ) { rows . push ( vcfRecordToRow ( vcfParser , line , lineNumber ) ) ; } } ) ; body = '' ; const rowSet = { isLoaded : true , rows , } ; const columnDisplayOrder = [ ] ; const columns = [ ] ; for ( let i = 0 ; i < vcfCoreColumns . length ; i += 1 ) { columnDisplayOrder . push ( i ) ; columns [ i ] = { name : vcfCoreColumns [ i ] . name , dataType : { type : vcfCoreColumns [ i ] . type } , } ; } for ( let i = 0 ; i < vcfParser . samples . length ; i += 1 ) { const oi = vcfCoreColumns . length + i ; columnDisplayOrder . push ( oi ) ; columns [ oi ] = { name : vcfParser . samples [ i ] , dataType : { type : 'Text' } } ; } columnDisplayOrder . push ( columnDisplayOrder . length ) ; columns . unshift ( { name : 'Location' , dataType : { type : 'LocString' } , isDerived : true , derivationFunctionText : `jexl:{text:row.extendedData.vcfFeature.refName+':'\n
    +row.extendedData.vcfFeature.start+'..'+row.extendedData.vcfFeature.end, extendedData:\n
    {refName:row.extendedData.vcfFeature.refName,start:row.extendedData.vcfFeature.start,end:row.extendedData.vcfFeature.end}}` , } ) ; return { rowSet , columnDisplayOrder , hasColumnNames : true , columns , assemblyName : options . selectedAssemblyName , } ; } export function splitVcfFileHeaderAndBody ( wholeFile ) { let headerEndIndex = 0 ; let prevChar ; for ( ; headerEndIndex < wholeFile . length ; headerEndIndex += 1 ) { const c = wholeFile [ headerEndIndex ] ; if ( prevChar === '\n' && c !== '#' ) { break ; } prevChar = c ; } return { header : wholeFile . substr ( 0 , headerEndIndex ) , body : wholeFile . substr ( headerEndIndex ) , } ; }