import { TDynamicObj , IFinalConfig , IParamsOption , TBaseObj , TRuleOption , TRuleOptionVal } from '../../typings' ; import { hasProp } from '../utils/has-prop' ; import { isObj } from '../utils/is-obj' ; import { paramsConfig , rulesConfig } from './config' ; const browserslist = require ( 'browserslist' ) as ( query ? : string | string [ ] ) => string [ ] ; const browserConfig = ( query ? ) => { const browsers = browserslist ( query ) ; const res = { } ; browsers . forEach ( val => { const num = /\s\d/ . exec ( val ) ; if ( num ) { const key = val . slice ( 0 , num . index ) ; const ver = parseFloat ( val . slice ( num . index ) ) ; if ( ! hasProp ( res , key ) ) { res [ key ] = ver ; } else { if ( ver < res [ key ] ) { res [ key ] = ver ; } } } } ) ; return res ; } ; const mergeUserVal = ( v , _v ) : TRuleOptionVal => { if ( Array . isArray ( v ) ) { if ( Array . isArray ( _v ) ) { return _v . filter ( s => typeof s === 'string' ) ; } } else if ( typeof v === typeof _v ) { if ( typeof _v === 'number' ) { if ( _v >= 0 && _v !== Infinity ) { return Math . floor ( _v ) ; } } else { return _v as boolean ; } } return v ; } ; const checkRules = ( userConfig , finalRules ) => { for ( const [ key , val ] of Object . entries ( userConfig ) ) { if ( hasProp ( finalRules , key ) ) { const conf = finalRules [ key ] ; if ( typeof val === 'boolean' ) { conf [ 0 ] = val ; } else if ( Array . isArray ( val ) && typeof val [ 0 ] === 'boolean' ) { conf [ 0 ] = val [ 0 ] as boolean ; if ( conf [ 0 ] && conf [ 1 ] ) { const option = conf [ 1 ] ; const userOption = val [ 1 ] ; if ( isObj < TDynamicObj < TRuleOptionVal > > ( userOption ) ) { for ( const [ k , v ] of Object . entries ( userOption ) ) { if ( hasProp ( option , k ) ) { option [ k ] = mergeUserVal ( option [ k ] , v ) ; } } } } } } } } ; export const mergeConfig = ( userConfig ) : IFinalConfig => { const finalConfig = { rules : { } , params : { ... paramsConfig } , browsers : browserConfig ( ) , } ; for ( const [ key , [ _switch , _option ] ] of Object . entries ( rulesConfig ) ) { finalConfig . rules [ key ] = [ _switch ] ; if ( _option ) { const option = { } ; for ( const [ k , v ] of Object . entries ( _option ) ) { option [ k ] = Array . isArray ( v ) ? v . slice ( ) : v ; } finalConfig . rules [ key ] ! . push ( option ) ; } } if ( isObj < TDynamicObj < unknown > > ( userConfig ) ) { const uConfig = userConfig ; checkRules ( uConfig , finalConfig . rules ) ; if ( hasProp ( uConfig , 'rules' ) && isObj < TRuleOption > ( uConfig . rules ) ) { checkRules ( uConfig . rules , finalConfig . rules ) ; } const uParams = uConfig . params ; if ( hasProp ( uConfig , 'params' ) && isObj < IParamsOption > ( uParams ) ) { ( Object . keys ( paramsConfig ) ) . forEach ( k => { if ( hasProp ( uParams , k ) ) { const uk = uParams [ k ] ; finalConfig . params [ k ] = mergeUserVal ( paramsConfig [ k ] , uk ) as never ; } } ) ; } if ( hasProp ( uConfig , 'browsers' ) && ( typeof uConfig . browsers === 'string' || Array . isArray ( uConfig . browsers ) ) ) { finalConfig . browsers = browserConfig ( uConfig . browsers ) ; } } return finalConfig as IFinalConfig ; } ;