import Constants from './constants' ; import Config from './config' ; export default class Word { _filterMethod : number ; case ? : number ; escaped : string ; lists : number [ ] ; matchMethod : number ; matchRepeated : number ; matchSeparators : number ; regExp : RegExp ; sub : string ; unicode : boolean ; value : string ; private static readonly _edgePunctuationRegExp = /(^[,.'"!?%$]|[,.'"!?%$]$)/ ; private static readonly _escapeRegExp = /[\/\\^$*+?.()|[\]{}]/g ; private static readonly _unicodeRegExp = /[^\u0000-\u00ff]/ ; private static readonly _unicodeWordBoundary = '[\\s.,\'"+!?|-]' ; static readonly nonWordRegExp = new RegExp ( '^\\s*[^\\w]+\\s*$' , 'g' ) ; static readonly separatorsRegExp = '[-_ ]*' ; static readonly whitespaceRegExp = /^\s+$/ ; static allLowerCase ( string ) { return string . toLowerCase ( ) === string ; } static allUpperCase ( string ) { return string . toUpperCase ( ) === string ; } static capitalizeEachWord ( string ) { const split = string . split ( /[-_ ]+/i ) ; split . forEach ( ( word ) => { string = string . replace ( word , this . capitalizeFirst ( word ) ) ; } ) ; return string ; } static capitalizeFirst ( string ) { return string . charAt ( 0 ) . toUpperCase ( ) + string . substr ( 1 ) ; } static containsDoubleByte ( str ) { if ( ! str . length ) return false ; if ( str . charCodeAt ( 0 ) > 127 ) return true ; return Word . _unicodeRegExp . test ( str ) ; } static eachWordCapitalized ( string ) { const split = string . split ( /[-_ ]+/i ) ; return split . every ( ( word ) => this . firstCapitalized ( word ) ) ; } static escapeRegExp ( str ) { return str . replace ( Word . _escapeRegExp , '\\$&' ) ; } static firstCapitalized ( string ) { return string . charAt ( 0 ) . toUpperCase ( ) === string . charAt ( 0 ) ; } constructor ( word , options , cfg ) { this . value = word ; this . case = options . case > Constants . FALSE ? Constants . TRUE : Constants . FALSE ; this . lists = options . lists === undefined ? [ ] : options . lists ; this . matchMethod = options . matchMethod === undefined ? cfg . defaultWordMatchMethod : options . matchMethod ; this . matchRepeated = options . repeat === undefined ? cfg . defaultWordRepeat : options . repeat ; this . matchSeparators = options . separators === undefined ? cfg . defaultWordSeparators : options . separators ; this . sub = options . sub === undefined ? cfg . defaultSubstitution : options . sub ; this . _filterMethod = options . _filterMethod === undefined ? cfg . filterMethod : options . _filterMethod ; this . unicode = Word . containsDoubleByte ( word ) ; this . escaped = this . matchMethod === Constants . MATCH_METHODS . REGEX ? this . value : Word . escapeRegExp ( this . value ) ; this . regExp = this . buildRegExp ( ) ; } buildRegExp ( ) { try { switch ( this . matchMethod ) { case Constants . MATCH_METHODS . PARTIAL : if ( this . _filterMethod === Constants . FILTER_METHODS . REMOVE ) { if ( this . unicode ) { return new RegExp ( '(^|' + Word . _unicodeWordBoundary + '?)([\\w-]*' + this . processedPhrase ( ) + '[\\w-]*)(' + Word . _unicodeWordBoundary + '?|$)' , this . regexOptions ( ) ) ; } else if ( this . hasEdgePunctuation ( ) ) { return new RegExp ( '(^|\\s)([\\w-]*' + this . processedPhrase ( ) + '[\\w-]*)(\\s|$)' , this . regexOptions ( ) ) ; } else { return new RegExp ( '\\s?\\b[\\w-]*' + this . processedPhrase ( ) + '[\\w-]*\\b\\s?' , this . regexOptions ( ) ) ; } } else { return new RegExp ( this . processedPhrase ( ) , this . regexOptions ( ) ) ; } case Constants . MATCH_METHODS . WHOLE : if ( this . unicode ) { return new RegExp ( '(^|' + Word . _unicodeWordBoundary + '*)([\\S]*' + this . processedPhrase ( ) + '[\\S]*)(' + Word . _unicodeWordBoundary + '*|$)' , this . regexOptions ( ) ) ; } else if ( this . hasEdgePunctuation ( ) ) { return new RegExp ( '(^|\\s)([\\S]*' + this . processedPhrase ( ) + '[\\S]*)(\\s|$)' , this . regexOptions ( ) ) ; } else { return new RegExp ( '\\b[\\w-]*' + this . processedPhrase ( ) + '[\\w-]*\\b' , this . regexOptions ( ) ) ; } case Constants . MATCH_METHODS . REGEX : return new RegExp ( this . value , this . regexOptions ( ) ) ; case Constants . MATCH_METHODS . EXACT : default : if ( this . _filterMethod === Constants . FILTER_METHODS . REMOVE ) { if ( this . unicode ) { return new RegExp ( '(^|' + Word . _unicodeWordBoundary + ')(' + this . processedPhrase ( ) + ')(' + Word . _unicodeWordBoundary + '|$)' , this . regexOptions ( ) ) ; } else if ( this . hasEdgePunctuation ( ) ) { return new RegExp ( '(^|\\s)(' + this . processedPhrase ( ) + ')(\\s|$)' , this . regexOptions ( ) ) ; } else { return new RegExp ( '\\s?\\b' + this . processedPhrase ( ) + '\\b\\s?' , this . regexOptions ( ) ) ; } } else { if ( this . unicode ) { return new RegExp ( '(^|' + Word . _unicodeWordBoundary + '+)(' + this . processedPhrase ( ) + ')(' + Word . _unicodeWordBoundary + '+|$)' , this . regexOptions ( ) ) ; } else if ( this . hasEdgePunctuation ( ) ) { return new RegExp ( '(^|\\s)(' + this . processedPhrase ( ) + ')(\\s|$)' , this . regexOptions ( ) ) ; } else { return new RegExp ( '\\b' + this . processedPhrase ( ) + '\\b' , this . regexOptions ( ) ) ; } } } } catch ( e ) { throw new Error ( 'Failed to create RegExp for "' + this . value + '" - ' + e . name + ' ' + e . message ) ; } } hasEdgePunctuation ( ) { return Word . _edgePunctuationRegExp . test ( this . value ) ; } processedPhrase ( ) { const isEscaped = this . escaped . includes ( '\\' ) ; let val = '' ; const lastCharIndex = this . escaped . length - 1 ; for ( let i = 0 ; i < this . escaped . length ; i ++ ) { if ( isEscaped && this . escaped [ i ] === '\\' ) { val += this . escaped [ i ] ; i ++ ; } val += this . escaped [ i ] ; if ( this . matchRepeated ) { val += '+' ; } if ( this . matchSeparators ) { if ( i != lastCharIndex ) { val += Word . separatorsRegExp ; } } } return val ; } regexOptions ( ) { let options = 'gi' ; if ( this . unicode ) { options += 'u' ; } return options ; } }