import { NameGenerator } from './nameGenerator' ; import warnings , { Source } from './allWarnings' ; export interface BaseLibraryOptions { ignoreAttributeSelectors ? : boolean ; source ? : Source ; isOriginalValue ? : boolean ; preventRandomName ? : boolean ; addSelectorType ? : boolean ; countStats ? : boolean ; getRenamedValues ? : boolean ; regex ? : boolean ; } export class BaseLibrary { nameGenerator : NameGenerator ; values : { [ s ] : string ; } = { } ; compressedValues : { [ s ] : string ; } = { } ; reserved : string [ ] = [ ] ; excludes : string [ ] = [ ] ; excludesRegex : ( RegExp | string ) [ ] = [ ] ; includes : string [ ] = [ ] ; includesRegex : ( RegExp | string ) [ ] = [ ] ; prefix = '' ; suffix = '' ; meta : { [ s ] : { appearanceCount : number ; } ; } = { } ; static hasReservedValue ( value , source ? ) { warnings . append ( value , source , 'compressed' ) ; return `${ value }_conflict` ; } constructor ( name ? ) { this . nameGenerator = new NameGenerator ( name ) ; this . initReset ( ) ; } prefetchValue = ( value ) : string => value ; initReset ( ) { this . values = { } ; this . compressedValues = { } ; this . reserved = [ ] ; this . excludes = [ ] ; this . excludesRegex = [ ] ; this . includes = [ ] ; this . includesRegex = [ ] ; this . prefix = '' ; this . suffix = '' ; this . meta = { } ; this . nameGenerator . reset ( ) ; } reset ( ) { this . initReset ( ) ; } setAlphabet ( alphabet ) { this . nameGenerator . setAlphabet ( alphabet ) ; } fillLibrary ( data , options ? ) { } prepareValue ( replacementObject , opts ) { return replacementObject ; } postfetchValue ( value , opts ? ) { return value ; } get ( value , opts = { } ) { const options = { isOriginalValue : true , countStats : true , ... opts , } ; const finalValue = this . prefetchValue ( value ) ; if ( this . isExcluded ( finalValue ) ) { warnings . append ( finalValue , opts . source , 'ignoredFound' ) ; return value ; } if ( ! this . values [ finalValue ] && options . isOriginalValue && this . compressedValues [ finalValue ] ) { return BaseLibrary . hasReservedValue ( value , options . source ) ; } let found = finalValue in this . values ; let result = this . values [ finalValue ] || finalValue ; if ( ! options . isOriginalValue ) { found = finalValue in this . compressedValues ; result = this . compressedValues [ finalValue ] || result ; } if ( options . isOriginalValue && options . countStats ) { if ( ! this . meta [ finalValue ] ) { this . meta [ finalValue ] = { appearanceCount : 0 , } ; } this . meta [ finalValue ] . appearanceCount += 1 ; } if ( ! found ) { return ! options . addSelectorType ? finalValue : value ; } return this . postfetchValue ( result , options ) ; } set ( value , renamedValue ? , opts = { } ) { if ( ! value ) { return ; } let options = opts ; let thisRenamedValue ; if ( typeof renamedValue === 'object' ) { options = renamedValue ; thisRenamedValue = undefined ; } else { thisRenamedValue = renamedValue as string ; } if ( Array . isArray ( value ) ) { value . forEach ( ( item ) => this . set ( item , thisRenamedValue , options ) ) ; return ; } const repObj = this . prepareValue ( { value , renamedValue : thisRenamedValue } , options ) ; if ( ! repObj ) { return ; } if ( this . isExcluded ( repObj . value ) ) { return ; } if ( this . values [ repObj . value ] ) { return ; } if ( options . preventRandomName === true ) { this . values [ repObj . value ] = repObj . value ; this . compressedValues [ repObj . value ] = repObj . value ; this . meta [ repObj . value ] = { appearanceCount : 0 } ; return ; } this . smartAllocate ( repObj . value , repObj . renamedValue ) ; } smartAllocate ( value , renamedValue ) { let randomName = renamedValue || this . nameGenerator . generate ( value ) ; while ( this . compressedValues [ randomName ] || this . isReserved ( randomName ) ) { randomName = this . nameGenerator . generate ( value ) ; } this . values [ value ] = randomName ; this . meta [ value ] = { appearanceCount : 0 , } ; this . compressedValues [ randomName ] = value ; if ( this . compressedValues [ value ] || randomName . length > value . length ) { this . swap ( value , this . compressedValues [ value ] ) ; } } swap ( val1 , val2 ) { if ( ! this . values [ val1 ] || ! this . values [ val2 ] ) { return ; } [ this . values [ val1 ] , this . values [ val2 ] ] = [ this . values [ val2 ] , this . values [ val1 ] ] ; [ this . meta [ val1 ] , this . meta [ val2 ] ] = [ this . meta [ val2 ] , this . meta [ val1 ] ] ; [ this . compressedValues [ this . values [ val2 ] ] , this . compressedValues [ this . values [ val1 ] ] , ] = [ val2 , val1 ] ; } setMultiple ( values = { } , options = { } ) { if ( Object . prototype . toString . call ( values ) !== '[object Object]' ) { return ; } Object . entries ( values ) . forEach ( ( entry ) => this . set ( entry [ 0 ] , entry [ 1 ] , options ) ) ; } setPrefix ( prefix ) { if ( typeof prefix !== 'string' ) { return ; } this . prefix = prefix ; } setSuffix ( suffix ) { if ( typeof suffix !== 'string' ) { return ; } this . suffix = suffix ; } private setInternalLists ( string , listPointer , regexListPointer ) { if ( ! string ) return ; if ( Array . isArray ( string ) ) { string . forEach ( ( e ) => this . setInternalLists ( e , listPointer , regexListPointer ) ) ; return ; } if ( listPointer . includes ( string as any ) || regexListPointer . includes ( string ) ) { return ; } if ( string instanceof RegExp ) { ( regexListPointer ) . push ( string ) ; } else { ( listPointer ) . push ( string ) ; } } setExclude ( toExclude ) { this . setInternalLists ( toExclude , this . excludes , this . excludesRegex ) ; } setInclude ( toInclude ) { this . setInternalLists ( toInclude , this . includes , this . includesRegex ) ; } setReserved ( toReserve ) { if ( ! toReserve ) return ; this . reserved = [ ] ; if ( ! Array . isArray ( toReserve ) ) { this . reserved . push ( toReserve ) ; } else { this . reserved = [ ... new Set ( toReserve ) ] ; } } isReserved ( string ) { return this . reserved . includes ( string ) ; } isExcluded ( string ) { if ( string === '__proto__' ) { return true ; } if ( this . excludes . includes ( string ) ) { if ( this . includesRegex . some ( ( includeRegex ) => string . match ( includeRegex ) ) ) { return false ; } return ! this . includes . includes ( string ) ; } return ( this . excludesRegex . some ( ( excludeRegex ) => ( string . match ( excludeRegex ) && ! this . includesRegex . some ( ( includeRegex ) => string . match ( includeRegex ) ) ) ) ) ; } } export default new BaseLibrary ( ) ;