namespace ts . formatting { export function getFormatContext ( options , host ) { return { options , getRules : getRulesMap ( ) , host } ; } let rulesMapCache ; function getRulesMap ( ) { if ( rulesMapCache === undefined ) { rulesMapCache = createRulesMap ( getAllRules ( ) ) ; } return rulesMapCache ; } /**
     * For a given rule action, gets a mask of other rule actions that
     * cannot be applied at the same position.
     */ function getRuleActionExclusion ( ruleAction ) { let mask = 0 ; if ( ruleAction & RuleAction . StopProcessingSpaceActions ) { mask |= RuleAction . ModifySpaceAction ; } if ( ruleAction & RuleAction . StopProcessingTokenActions ) { mask |= RuleAction . ModifyTokenAction ; } if ( ruleAction & RuleAction . ModifySpaceAction ) { mask |= RuleAction . ModifySpaceAction ; } if ( ruleAction & RuleAction . ModifyTokenAction ) { mask |= RuleAction . ModifyTokenAction ; } return mask ; } export type RulesMap = ( context : FormattingContext ) => readonly Rule [ ] | undefined ; function createRulesMap ( rules ) { const map = buildMap ( rules ) ; return context => { const bucket = map [ getRuleBucketIndex ( context . currentTokenSpan . kind , context . nextTokenSpan . kind ) ] ; if ( bucket ) { const rules = [ ] ; let ruleActionMask = 0 ; for ( const rule of bucket ) { const acceptRuleActions = ~ getRuleActionExclusion ( ruleActionMask ) ; if ( rule . action & acceptRuleActions && every ( rule . context , c => c ( context ) ) ) { rules . push ( rule ) ; ruleActionMask |= rule . action ; } } if ( rules . length ) { return rules ; } } } ; } function buildMap ( rules ) { const map = new Array ( mapRowLength * mapRowLength ) ; const rulesBucketConstructionStateList = new Array < number > ( map . length ) ; for ( const rule of rules ) { const specificRule = rule . leftTokenRange . isSpecific && rule . rightTokenRange . isSpecific ; for ( const left of rule . leftTokenRange . tokens ) { for ( const right of rule . rightTokenRange . tokens ) { const index = getRuleBucketIndex ( left , right ) ; let rulesBucket = map [ index ] ; if ( rulesBucket === undefined ) { rulesBucket = map [ index ] = [ ] ; } addRule ( rulesBucket , rule . rule , specificRule , rulesBucketConstructionStateList , index ) ; } } } return map ; } function getRuleBucketIndex ( row , column ) { Debug . assert ( row <= SyntaxKind . LastKeyword && column <= SyntaxKind . LastKeyword , "Must compute formatting context from tokens" ) ; return ( row * mapRowLength ) + column ; } const maskBitSize = 5 ; const mask = 0b11111 ; const mapRowLength = SyntaxKind . LastToken + 1 ; enum RulesPosition { StopRulesSpecific = 0 , StopRulesAny = maskBitSize * 1 , ContextRulesSpecific = maskBitSize * 2 , ContextRulesAny = maskBitSize * 3 , NoContextRulesSpecific = maskBitSize * 4 , NoContextRulesAny = maskBitSize * 5 } function addRule ( rules , rule , specificTokens , constructionState , rulesBucketIndex ) { const position = rule . action & RuleAction . StopAction ? specificTokens ? RulesPosition . StopRulesSpecific : RulesPosition . StopRulesAny : rule . context !== anyContext ? specificTokens ? RulesPosition . ContextRulesSpecific : RulesPosition . ContextRulesAny : specificTokens ? RulesPosition . NoContextRulesSpecific : RulesPosition . NoContextRulesAny ; const state = constructionState [ rulesBucketIndex ] || 0 ; rules . splice ( getInsertionIndex ( state , position ) , 0 , rule ) ; constructionState [ rulesBucketIndex ] = increaseInsertionIndex ( state , position ) ; } function getInsertionIndex ( indexBitmap , maskPosition ) { let index = 0 ; for ( let pos = 0 ; pos <= maskPosition ; pos += maskBitSize ) { index += indexBitmap & mask ; indexBitmap >>= maskBitSize ; } return index ; } function increaseInsertionIndex ( indexBitmap , maskPosition ) { const value = ( ( indexBitmap >> maskPosition ) & mask ) + 1 ; Debug . assert ( ( value & mask ) === value , "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules." ) ; return ( indexBitmap & ~ ( mask << maskPosition ) ) | ( value << maskPosition ) ; } }