41 lines · 1.2 KB
const REGEX_SPECIAL = /[.+^${}()|[\]\\]/g;

/** Glob matching for ref and path filters: `*` matches within a segment, `**` across segments, `?` one char. */
export function globToRegExp(pattern: string): RegExp {
  let source = "";
  for (let index = 0; index < pattern.length; index++) {
    const char = pattern[index];
    if (char === "*") {
      if (pattern[index + 1] === "*") {
        source += ".*";
        index++;
        if (pattern[index + 1] === "/") index++;
      } else {
        source += "[^/]*";
      }
    } else if (char === "?") {
      source += "[^/]";
    } else {
      source += char.replace(REGEX_SPECIAL, "\\$&");
    }
  }
  return new RegExp(`^${source}$`);
}

export function matchesGlob(pattern: string, value: string): boolean {
  return globToRegExp(pattern).test(value);
}

/** GitHub-style filters: patterns prefixed with `!` exclude; the last matching pattern wins. */
export function matchesFilters(patterns: string[], value: string): boolean {
  let matched = false;
  for (const pattern of patterns) {
    if (pattern.startsWith("!")) {
      if (matchesGlob(pattern.slice(1), value)) matched = false;
    } else if (matchesGlob(pattern, value)) {
      matched = true;
    }
  }
  return matched;
}