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; }