{"version":3,"file":"utils.mjs","sources":["../../../../src/grafana/matchers/utils.ts"],"sourcesContent":["import { parseFlags } from '@grafana/data';\n\nimport { Label, LabelMatcher } from './types';\n\ntype LabelMatchingResult = {\n  // wether all of the labels match the given set of matchers\n  matches: boolean;\n  // details of which labels matched which matcher\n  details: LabelMatchDetails[];\n};\n\n// LabelMatchDetails is a map of labels to their match results\nexport type LabelMatchDetails = {\n  labelIndex: number; // index of the label in the labels array\n  match: boolean;\n  matcher: LabelMatcher | null;\n} & (PositiveLabelMatch | NegativeLabelMatch);\n\ntype PositiveLabelMatch = {\n  match: true;\n  matcher: LabelMatcher;\n};\ntype NegativeLabelMatch = {\n  match: false;\n  matcher: null;\n};\n\n// returns a match results for given set of matchers (from a policy for instance) and a set of labels\nexport function matchLabels(matchers: LabelMatcher[], labels: Label[]): LabelMatchingResult {\n  const matches = matchLabelsSet(matchers, labels);\n\n  // create initial map of label => match result\n  const details = labels.map<LabelMatchDetails>((_label, index) => ({\n    labelIndex: index,\n    match: false,\n    matcher: null,\n  }));\n\n  // for each matcher, check which label it matched for\n  matchers.forEach((matcher) => {\n    const matchingLabelIndex = labels.findIndex((label) => isLabelMatch(matcher, label));\n\n    // record that matcher for the label\n    if (matchingLabelIndex > -1) {\n      details[matchingLabelIndex].match = true;\n      details[matchingLabelIndex].matcher = matcher;\n    }\n  });\n\n  return { matches, details };\n}\n\n// ⚠️ DO NOT USE THIS FUNCTION FOR ROUTE SELECTION ALGORITHM\n// for route selection algorithm, always compare a single matcher to the entire label set\n// see \"matchLabelsSet\"\nexport function isLabelMatch(matcher: LabelMatcher, label: Label): boolean {\n  const [labelKey, labelValue] = label;\n  const { label: matcherLabel, type: matcherType, value: matcherValue } = matcher;\n\n  if (labelKey !== matcherLabel) {\n    return false;\n  }\n\n  const matchFunction = OperatorFunctions[matcherType];\n  return matchFunction(labelValue, matcherValue);\n}\n\nexport function matchLabelsSet(matchers: LabelMatcher[], labels: Label[]): boolean {\n  for (const matcher of matchers) {\n    if (!isLabelMatchInSet(matcher, labels)) {\n      return false;\n    }\n  }\n  return true;\n}\n/**\n * Checks if a label matcher matches any of the labels in the provided set.\n */\nfunction isLabelMatchInSet(matcher: LabelMatcher, labels: Label[]): boolean {\n  const { label, type, value } = matcher;\n\n  let labelValue = ''; // matchers that have no labels are treated as empty string label values\n  const labelForMatcher = Object.fromEntries(labels)[label];\n  if (labelForMatcher) {\n    labelValue = labelForMatcher;\n  }\n\n  const matchFunction = OperatorFunctions[type];\n  try {\n    // This can throw because the regex operators use the JavaScript regex engine\n    // and \"new RegExp()\" throws on invalid regular expressions.\n    //\n    // This is usually a user-error (because matcher values are taken from user input)\n    return matchFunction(labelValue, value);\n  } catch (err) {\n    return false;\n  }\n}\n\ntype OperatorPredicate = (labelValue: string, matcherValue: string) => boolean;\nconst OperatorFunctions: Record<LabelMatcher['type'], OperatorPredicate> = {\n  '=': (lv, mv) => lv === mv,\n  '!=': (lv, mv) => lv !== mv,\n  // At the time of writing, Alertmanager compiles to another (anchored) Regular Expression,\n  // so we should also anchor our UI matches for consistency with this behaviour\n  // https://github.com/prometheus/alertmanager/blob/fd37ce9c95898ca68be1ab4d4529517174b73c33/pkg/labels/matcher.go#L69\n  '=~': (lv, mv) => {\n    const valueWithFlagsParsed = parseFlags(`^(?:${mv})$`);\n    const re = new RegExp(valueWithFlagsParsed.cleaned, valueWithFlagsParsed.flags);\n    return re.test(lv);\n  },\n  '!~': (lv, mv) => {\n    const valueWithFlagsParsed = parseFlags(`^(?:${mv})$`);\n    const re = new RegExp(valueWithFlagsParsed.cleaned, valueWithFlagsParsed.flags);\n    return !re.test(lv);\n  },\n};\n"],"names":[],"mappings":"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"}