import debug from './debug' ; import { presetIdJsonReg } from '../variables' ; import { VERSION_FRESH , VERSION_UPDATED , VERSION_OUTDATED , VERSION_SAME , } from '../types' ; export const istype = ( target , type ) => { let types = [ ] ; if ( typeof type === 'string' ) { types = [ type ] ; } else { types = [ ... type ] ; } if ( ! types . length ) { return false ; } for ( const t of types as string [ ] ) { const ck = Object . prototype . toString . call ( target ) . match ( /\[object\s(.+)\]/ ) ! [ 1 ] . toLowerCase ( ) === t ; if ( ck ) { return ck ; } } return false ; } ; export const plainCopy = ( target ) : std < any > => { try { const copy = JSON . parse ( JSON . stringify ( target ) ) ; return [ null , copy ] ; } catch ( error ) { return [ new Error ( error ) ] ; } } ; export const configRegister = ( pairs , order ) => { const items = Object . entries ( pairs ) ; return ( states ) => { const s = { ... states } ; return items . reduce ( ( p , c ) => { const [ k , v ] = c as [ string , string ] ; if ( order === 'pull' && s . hasOwnProperty ( k ) ) { p [ v ] = s [ k ] ; } if ( order === 'push' && s . hasOwnProperty ( v ) ) { p [ k ] = s [ v ] ; } return p ; } , { } as { [ k ] : any ; } ) ; } ; } ; export const stringParamsParaser = ( target ) => { if ( istype ( target , 'string' ) ) { const [ host , paramsString ] = ( target as string ) . split ( '?' ) ; const params = ( paramsString || host ) . split ( '&' ) . reduce ( ( p , c ) => ! ! ( ( o ) => Object . assign ( p , { [ o [ 0 ] ] : o [ 1 ] || true } ) ) ( c . split ( '=' ) ) && p , { } ) ; return [ null , params , host ] ; } let s = '' ; if ( istype ( target , 'array' ) ) { for ( const [ k , v ] of target as string [ ] [ ] ) { s += `${ k }=${ v }&` ; } } if ( istype ( target , 'object' ) ) { for ( const [ k , v ] of Object . entries ( target ) ) { if ( istype ( v , 'array' ) ) { for ( const e of v ) { s += `${ k }=${ e }&` ; } continue ; } s += `${ k }=${ v }&` ; } } if ( ! s . length ) { return [ `target param: ${ target } gets nothing.` ] ; } return [ null , s . replace ( /&$/ , '' ) ] ; } ; export const versionCheck = ( current , last ) : std < versionStatus > => { if ( ! last ) { return [ `last version is not existed` , VERSION_FRESH , - 1 ] ; } const intArr = ( s ) : number [ ] => s . split ( /\./ ) . map ( ( n ) => parseInt ( n , 10 ) ) ; const [ c , l ] = [ intArr ( current ) , intArr ( last ) ] ; const incompatibleLevel = ( idx , c , l ) : number => { if ( idx === 0 && c [ 0 ] !== l [ 0 ] ) { return 1 ; } const [ cv , lv ] = [ c [ 1 ] , l [ 1 ] ] ; if ( cv >= 10 && lv >= 10 ) { const [ c , l ] = [ `${ cv }` . replace ( /\d$/ , '' ) , `${ lv }` . replace ( /\d$/ , '' ) ] ; if ( Math . abs ( parseInt ( c , 10 ) - parseInt ( l , 10 ) ) > 0 ) { return 0 ; } } return - 1 ; } ; for ( let i = 0 ; i < c . length ; i ++ ) { if ( c [ i ] > l [ i ] ) { return [ null , VERSION_UPDATED , incompatibleLevel ( i , c , l ) ] ; } if ( c [ i ] < l [ i ] ) { return [ null , VERSION_OUTDATED , incompatibleLevel ( i , c , l ) ] ; } } return [ null , VERSION_SAME , - 1 ] ; } ; export const presetsParser = ( presets ) => { try { const tmp = { } ; const result = presets . map ( ( preset ) => { const json = JSON . parse ( preset ) ; tmp [ json . id ] = json ; return json ; } ) ; for ( let i = 0 ; i < result . length ; i ++ ) { const preset = result [ i ] ; const parentId = preset . extends ; if ( ! ! parentId && tmp [ parentId ] ) { result [ i ] = Object . assign ( { } , tmp [ parentId ] , preset ) ; } } return [ null , result ] ; } catch ( error ) { return [ new Error ( `translation sources's presets parse failed` ) , error ] ; } } ; export const presetsStringifier = ( presets ) => { try { const result = presets . map ( ( preset ) => JSON . stringify ( preset ) ) ; return [ null , result ] ; } catch ( error ) { return [ new Error ( `translation sources's presets stringify failed` ) , error ] ; } } ; export const paramsParaser = ( target , params , parse = true ) => { let out ; out = JSON . stringify ( target ) . replace ( /{\b(.+?)\b}/g , ( _ , $ ) => params [ $ ] || _ ) . replace ( /(\r\n|\r|\n)/g , '\\n' ) as string ; if ( parse ) { try { out = JSON . parse ( out ) as queryParams ; } catch ( error ) { return [ new Error ( error ) , out ] ; } } return [ null , out ] ; } ; export const presetParamsParser = ( target , requestParams , stringify = false ) => { if ( ! istype ( target , [ 'object' , 'array' , 'string' ] ) ) { return [ `check target params type: ${ target }` ] ; } const params = paramsParaser ( target , requestParams ) [ 1 ] ! ; let out ; if ( istype ( params , 'object' ) ) { out = new URLSearchParams ( stringParamsParaser ( params ) [ 1 ] as string ) ; } if ( istype ( params , 'array' ) ) { out = new URLSearchParams ( params as string [ ] [ ] ) ; } if ( istype ( params , 'string' ) ) { out = new URLSearchParams ( params as string ) ; } return [ null , ! stringify ? out ! : out ! . toString ( ) ] ; } ; export const parserPathSplitter = ( path ) => { const sectionReg = /(\/.*?\/)/ ; const operatorReg = /(\[.*?\]|\{.*?\}|\<.*?\>)/ ; const cleaner = ( target ) : string [ ] => target . filter ( ( s ) => ! ! s . length ) . map ( ( s ) => s . trim ( ) ) ; const sections = cleaner ( path . split ( sectionReg ) ) ; let out ; out = sections . map ( ( s ) => cleaner ( s . split ( operatorReg ) ) ) ; return [ null , out ] ; } ; export const parserPathReducer = ( path , response , stringify = false ) => { const sectionReg = /\/(.*?)\// ; const identifierReg = /\./ ; const rangeReg = /\[([-]*\d*),*\s*([-]*\d*)\]/ ; const selectReg = /\{(.*?)\}/ ; const multiReg = /\s*,\s*/ ; const separatorReg = /\<(.*?)\>/ ; const [ _ , splitedPath ] = parserPathSplitter ( path ) ; if ( ! splitedPath ) { return [ `${ splitedPath } is invaild path` ] ; } let out = [ ] ; for ( const sp of splitedPath ) { for ( const point of sp ) { if ( sectionReg . test ( point ) ) { out . push ( point . match ( sectionReg ) ! [ 1 ] as string ) ; continue ; } if ( identifierReg . test ( point ) ) { const identifiers = point . split ( identifierReg ) . filter ( ( e ) => e !== '$' ) ; const value = ( identifiers as string [ ] ) . reduce ( ( r , c ) => { if ( istype ( r , 'object' ) ) { return r [ c ] ; } if ( istype ( r , 'array' ) ) { const match = c . match ( /-(\d+)/ ) ; if ( ! match ) { return r [ c ] ; } return r [ r . length - parseInt ( match [ 1 ] , 10 ) - 1 ] ; } return r ; } , response ) ; out . push ( value ) ; continue ; } const last = out [ out . length - 1 ] ; if ( last === undefined ) { continue ; } if ( rangeReg . test ( point ) && istype ( last , 'array' ) ) { const [ _ , start = '0' , end = '0' ] = point . match ( rangeReg ) ! ; const [ s , e ] = [ parseInt ( start , 10 ) , parseInt ( end , 10 ) ] ; if ( s >= 0 && e >= 0 ) { last . splice ( 0 , s ) ; last . splice ( ( e - s ) + 1 ) ; } if ( s >= 0 && e < 0 ) { last . splice ( 0 , s ) ; last . splice ( - 1 , - e ) ; } if ( s < 0 && e < 0 ) { last . splice ( s ) ; last . splice ( 0 , ( last . length + ( e - s ) ) - 1 ) ; } continue ; } if ( selectReg . test ( point ) ) { const keys = point . match ( selectReg ) ! [ 1 ] . split ( multiReg ) ; let r = [ ] as any [ ] ; for ( const item of last ) { r = [ ... r , ... Object . entries ( item ) . filter ( ( [ k , v ] ) => keys . includes ( k ) ) . map ( ( [ k , v ] ) => v ) , ] ; } out [ out . length - 1 ] = r ; continue ; } if ( separatorReg . test ( point ) ) { const separator = point . match ( separatorReg ) ! [ 1 ] ; const r = out [ out . length - 1 ] ; if ( istype ( r , 'array' ) ) { out [ out . length - 1 ] = r . join ( separator || '' ) ; continue ; } if ( istype ( r , 'object' ) ) { out [ out . length - 1 ] = Object . values ( r ) . join ( separator || '' ) ; continue ; } } } } out = out . filter ( ( s ) => s !== '' || s !== undefined ) ; return [ null , ! stringify ? out : out . join ( '' ) ] ; } ; export const translationResultParser = ( response , { parser , test = { } } , stringify = true ) => { const result = { } ; for ( const [ name , selector ] of Object . entries ( parser ) ) { const [ error , r = '' ] = parserPathReducer ( ( selector as string ) , response , stringify ) ; if ( error !== null ) { return [ error ] ; } result [ name ] = r ; const rule = test [ name ] ; try { if ( istype ( rule , 'string' ) ) { if ( ! new RegExp ( rule as string ) . test ( r as string ) ) { result [ name ] = '__unfound__' ; } } else if ( istype ( rule , 'array' ) ) { const [ reg , placeholder ] = rule ; if ( ! new RegExp ( reg as string ) . test ( r as string ) ) { result [ name ] = placeholder || '__unfound__' ; } } } catch ( error ) { return [ error . message , result ] ; } } return [ null , result ] ; } ; export const templateLayoutParser = ( result , { rows } ) => { const out = [ ] ; for ( let i = 0 ; i < rows . length ; i ++ ) { out [ i ] = rows [ i ] . map ( ( e ) => e . replace ( /{(.+?)}/gmi , ( _ , $1 ) => result ! [ $1 ] as string || '' ) ) ; } return [ null , out ] ; } ; export const configKeysReducer = ( keys , config ) => { const out = { } ; if ( istype ( keys , 'string' ) ) { const k = keys as string ; out [ k ] = config [ k ] ; } if ( istype ( keys , 'array' ) ) { for ( const k of keys as string [ ] ) { out [ k ] = config [ k ] ; } } if ( istype ( keys , 'object' ) ) { for ( const k of Object . keys ( keys as string [ ] ) ) { out [ k ] = config [ k ] ; } } return [ null , out ] ; } ; export const presetLanguagesModifier = ( languages , rules = [ ] ) => { if ( ! rules . length ) { return [ null , languages ] ; } const out = [ ] ; for ( const lang of languages ) { let { code , name , locale } = lang ; for ( const rule of rules ) { if ( istype ( rule , 'string' ) ) { const [ origin , target ] = ( rule as string ) . split ( ':>' ) ; if ( ! origin || ! target ) { continue ; } if ( code === origin ) { code = target ; name = name ; locale = locale ; } continue ; } if ( istype ( rule , 'array' ) ) { const [ origin , target ] = rule ; if ( istype ( origin , 'string' ) && istype ( target , 'string' ) ) { if ( ! origin || ! target ) { continue ; } if ( code === origin ) { code = ( target as string ) ; name = name ; locale = locale ; } continue ; } if ( istype ( origin , 'object' ) , istype ( target , 'object' ) ) { if ( code === ( origin as Language ) . code ) { const { code : tc , name : tn , locale : tl } = ( target as Language ) ; code = tc || code ; name = tn || name ; locale = tl || locale ; } } } } out . push ( { code , name , locale } ) ; } return [ null , out ] ; } ; export const presetLanguagesFilter = ( languages , include , exclude ) => { if ( ! include && ! exclude ) { return [ null , languages ] ; } let out = [ ... languages ] ; if ( include && include . length ) { out = out . filter ( ( { code } ) => include . includes ( code ) ) ; } if ( exclude && exclude . length ) { out = out . filter ( ( { code } ) => ! exclude . includes ( code ) ) ; } return [ null , out ] ; } ; export const presetInvoker = ( presetId , presets ) => { let preset ; const find = ( id ) => presets . filter ( ( stringifyPreset ) => { const [ _ , mid ] = stringifyPreset . match ( presetIdJsonReg ) || [ '' , '' ] ; return id === mid ; } ) [ 0 ] ; try { preset = find ( presetId ) as presetStringJson ; if ( ! preset ) { return [ `no preset id is "${ presetId }"` ] ; } preset = JSON . parse ( preset ) as Preset | SourcePreset | LayoutPreset ; if ( ! ! preset . extends ) { const parent = find ( preset . extends ) ; if ( ! parent ) { return [ `no parent preset id is "${ preset . extends }"` , preset ] ; } preset = Object . assign ( JSON . parse ( parent ) , preset ) as Preset | SourcePreset | LayoutPreset ; } } catch ( error ) { return [ new Error ( error ) ] ; } return [ null , preset ] ; } ;