import varint from 'varint' ; import * as convert from './convert' ; import { protocols } from './protocols' ; function stringToStringTuples ( str ) { const tuples = [ ] ; const parts = str . split ( '/' ) . slice ( 1 ) ; if ( parts . length === 1 && parts [ 0 ] === '' ) { return [ ] ; } for ( let p = 0 ; p < parts . length ; p ++ ) { const part = parts [ p ] ; const proto = ( protocols as any ) ( part ) ; if ( proto . size === 0 ) { tuples . push ( [ part ] ) ; continue ; } p ++ ; if ( p >= parts . length ) { throw ParseError ( 'invalid address: ' + str ) ; } if ( proto . path ) { tuples . push ( [ part , cleanPath ( parts . slice ( p ) . join ( '/' ) ) , ] ) ; break ; } tuples . push ( [ part , parts [ p ] ] ) ; } return tuples ; } function stringTuplesToString ( tuples ) { const parts = [ ] ; tuples . map ( ( tup ) => { const proto = protoFromTuple ( tup ) ; parts . push ( proto . name ) ; if ( tup . length > 1 ) { parts . push ( tup [ 1 ] ) ; } } ) ; return cleanPath ( parts . join ( '/' ) ) ; } function stringTuplesToTuples ( tuples ) { return tuples . map ( ( tup ) => { if ( ! Array . isArray ( tup ) ) { tup = [ tup ] ; } const proto = protoFromTuple ( tup ) ; if ( tup . length > 1 ) { return [ proto . code , convert . toBytes ( proto . code , tup [ 1 ] ) ] ; } return [ proto . code ] ; } ) ; } export function tuplesToStringTuples ( tuples ) { return tuples . map ( ( tup ) => { const proto = protoFromTuple ( tup ) ; if ( tup . length > 1 ) { return [ proto . code , convert . toString ( proto . code , tup [ 1 ] ) ] ; } return [ proto . code ] ; } ) ; } function tuplesToBytes ( tuples ) { return fromBytes ( new Uint8Array ( tuples . flatMap ( ( tup ) => { const proto = protoFromTuple ( tup ) ; let buf = Uint8Array . from ( varint . encode ( proto . code ) ) ; if ( tup . length > 1 ) { buf = new Uint8Array ( [ ... buf , ... tup [ 1 ] ] ) ; } return [ ... buf ] ; } ) ) ) ; } function sizeForAddr ( p , addr ) { if ( p . size > 0 ) { return p . size / 8 ; } else if ( p . size === 0 ) { return 0 ; } else { const size = varint . decode ( addr ) ; return size + varint . decode . bytes ; } } export function bytesToTuples ( buf ) { const tuples = [ ] ; let i = 0 ; while ( i < buf . length ) { const code = varint . decode ( buf , i ) ; const n = varint . decode . bytes ; const p = ( protocols as any ) ( code ) ; const size = sizeForAddr ( p , buf . slice ( i + n ) ) ; if ( size === 0 ) { tuples . push ( [ code ] as any ) ; i += n ; continue ; } const addr = buf . slice ( i + n , i + n + size ) ; i += size + n ; if ( i > buf . length ) { throw ParseError ( 'Invalid address Uint8Array' ) ; } tuples . push ( [ code , addr ] ) ; } return tuples ; } export function bytesToString ( buf ) { const a = bytesToTuples ( buf ) ; const b = tuplesToStringTuples ( a ) ; return stringTuplesToString ( b ) ; } function stringToBytes ( str ) { str = cleanPath ( str ) ; const a = stringToStringTuples ( str ) ; const b = stringTuplesToTuples ( a ) ; return tuplesToBytes ( b ) ; } export function fromString ( str ) { return stringToBytes ( str ) ; } export function fromBytes ( buf ) { const err = validateBytes ( buf ) ; if ( err ) throw err ; return Uint8Array . from ( buf ) ; } function validateBytes ( buf ) { try { bytesToTuples ( buf ) ; } catch ( err ) { return err ; } } function cleanPath ( str ) { return ( '/' + str . trim ( ) . split ( '/' ) . filter ( ( a ) => a ) . join ( '/' ) ) ; } function ParseError ( str ) { return new Error ( 'Error parsing address: ' + str ) ; } function protoFromTuple ( tup ) { const proto = ( protocols as any ) ( tup [ 0 ] ) ; return proto ; }