import Variable from './variable' ; import Color from '../colors/color' ; import { dirname } from 'path' ; class VariablesStore { private entries : Map < string , Variable [ ] > = new Map ( ) ; public has ( variable = null , fileName = null , line = null ) { const declarations = this . get ( variable , fileName , line ) ; return declarations && declarations . length > 0 ; } public get ( variable , fileName = null , line = null ) { let decorations = this . entries . get ( variable ) || [ ] ; if ( fileName !== null ) { decorations = decorations . filter ( _ => _ . location . fileName === fileName ) ; } if ( line !== null ) { decorations = decorations . filter ( _ => _ . location . line === line ) ; } return decorations ; } private __delete ( variable , fileName , line ) { let decorations = this . get ( variable ) ; if ( line !== null ) { decorations = decorations . filter ( _ => _ . location . fileName !== fileName || ( _ . location . fileName === fileName && _ . location . line !== line ) ) ; } else if ( fileName !== null ) { decorations = decorations . filter ( _ => _ . location . fileName !== fileName ) ; } this . entries . set ( variable , decorations ) ; return ; } public delete ( variable = null , fileName = null , line = null ) { if ( variable !== null ) { return this . __delete ( variable , fileName , line ) ; } const IT = this . entries . entries ( ) ; let tmp = IT . next ( ) ; while ( tmp . done === false ) { const varName = tmp . value [ 0 ] ; this . __delete ( varName , fileName , line ) ; tmp = IT . next ( ) ; } } private getColor ( match , fileName , line ) { let color = null ; const varName = match [ 1 ] || match [ 2 ] ; let variables = [ ] . concat ( this . get ( varName , fileName , line ) ) ; if ( variables . length === 0 ) { variables = [ ] . concat ( this . get ( varName ) ) ; } if ( variables . length !== 0 ) { const variable = variables . pop ( ) ; color = new Color ( varName , match . index , variable . color . rgb , variable . color . alpha ) ; } return color ; } public addEntry ( key , value ) { const _value = Array . isArray ( value ) ? value : [ value ] ; if ( this . entries . has ( key ) ) { const decorations = this . entries . get ( key ) ; this . entries . set ( key , decorations . concat ( _value ) ) ; } else { this . entries . set ( key , _value ) ; } } public get count ( ) : number { return this . entries . size ; } public findDeclaration ( variable , file , line ) { return this . findClosestDeclaration ( variable , file , line ) ; } public findClosestDeclaration ( variable , file , line ? ) { let decorations = this . get ( variable , file ) ; if ( decorations . length === 0 ) { decorations = this . get ( variable ) ; } if ( decorations . length === 0 ) { this . delete ( variable ) ; } decorations = this . filterDecorations ( decorations , file ) ; if ( line ) { decorations = decorations . filter ( decoration => decoration . location . line === line ) ; } else { decorations = decorations . sort ( ( a , b ) => a . location . line - b . location . line ) ; } const _closest = decorations [ decorations . length - 1 ] ; let closest = decorations . pop ( ) ; while ( closest && closest . color === undefined ) { closest = decorations . pop ( ) ; } return closest || _closest ; } private filterDecorations ( decorations , dir ) { const folder = dirname ( dir ) ; const r = new RegExp ( `^${ encodeURI ( folder ) }` ) ; const decorationsFound = decorations . filter ( ( deco ) => r . test ( encodeURI ( deco . location . fileName ) ) ) ; if ( decorationsFound . length !== 0 || folder === dir ) { return decorationsFound ; } return this . filterDecorations ( decorations , folder ) ; } } export default VariablesStore ;