All files / key-parser priority-calculator.js

94.59% Statements 70/74
68.42% Branches 13/19
100% Functions 3/3
94.59% Lines 70/74

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 751x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 82x 82x 82x 82x 82x 82x 82x 82x 82x 1x 1x 1x 1x 1x 1x 23x 23x 2x 2x 21x 21x 21x 23x 27x 27x 25x 25x 27x 2x 2x 2x 27x     27x 27x 27x     27x 27x 21x 21x 21x 21x 21x 21x 21x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x  
/**
 * @file responsible of calculating key priority in key
 */
 
import { states } from './key-ast.util.js'
import { captureExpressions } from './capture-expression-values.js'
 
/**
 * @param {import('./key-ast.util.js').AST} ast - AST of parsed key
 * @returns {KeyPriority} - priority of parsed key
 */
export function calculatePriority (ast) {
  const captureTokens = ast.tokens.filter((token) => token.type === states.capture)
  const captureValues = captureTokens.length
  const captureExpressionsInfo = captureTokens.map(calculateCaptureTokenPriority)
  const sum = captureExpressionsInfo.reduce((a, b) => a + b, 0)
  return {
    priority: [captureValues, sum],
    priorityAsNumber: getNumericValuePriority(captureValues, sum),
  }
}
 
/**
 * Calculates the priority of a capture token
 * @param {import('./key-ast.util.js').Token} captureToken - target capture token
 * @returns {number} priority value of target token
 */
function calculateCaptureTokenPriority (captureToken) {
  if (captureToken.childTokens.length === 0) {
    return captureExpressions.special.any.value
  }
 
  let value = Number.MAX_SAFE_INTEGER
  let currentExpression = ''
  for (const token of captureToken.childTokens) {
    switch (token.type) {
      case states.capture_expr:
        currentExpression = currentExpression ? `${currentExpression} ${token.text}` : token.text
        continue
      case states.capture_expr_sep:
        value = Math.min(value, captureExpressions.named[currentExpression]?.value ?? 0)
        currentExpression = ''
        continue
      case states.regex:
        value = Math.min(value, captureExpressions.special.regex.value)
        continue
      case states.sq_string:
      case states.dq_string:
      case states.bt_string:
        value = Math.min(value, captureExpressions.named.string.value)
        continue
    }
  }
 
  if (currentExpression) {
    value = Math.min(value, captureExpressions.named[currentExpression]?.value ?? 0)
  }
 
  return value
}
 
/**
 * Calculates the priority into a numeric value to ease comparison of keys priority
 * @param {number} captures - first value of priority - the number of capture tokens
 * @param {number} sum      - second value of priority - the sum of capture token values
 * @returns {number} the numeric representation of priority tuple
 */
export const getNumericValuePriority = (captures, sum) => Number.MAX_SAFE_INTEGER - (captures << 20) + sum
 
/**
 * @typedef {object} KeyPriority
 * @property {[number, number]} priority - priority in groups
 * @property {number} priorityAsNumber - priority as number to improve comparison speed
 */