// // Copyright (c) StellaOps. Licensed under BUSL-1.1. // using DotNet.Globbing; namespace StellaOps.Facet; /// /// Utility for matching file paths against glob patterns. /// public sealed class GlobMatcher { private readonly List _globs; /// /// Initializes a new instance of the class. /// /// Glob patterns to match against. public GlobMatcher(IEnumerable patterns) { ArgumentNullException.ThrowIfNull(patterns); _globs = patterns .Select(p => Glob.Parse(NormalizePattern(p))) .ToList(); } /// /// Check if a path matches any of the patterns. /// /// The path to check (Unix-style). /// True if any pattern matches. public bool IsMatch(string path) { ArgumentNullException.ThrowIfNull(path); var normalizedPath = NormalizePath(path); return _globs.Any(g => g.IsMatch(normalizedPath)); } /// /// Create a matcher for a single facet. /// /// The facet to create a matcher for. /// A GlobMatcher for the facet's selectors. public static GlobMatcher ForFacet(IFacet facet) { ArgumentNullException.ThrowIfNull(facet); return new GlobMatcher(facet.Selectors); } private static string NormalizePattern(string pattern) { // Ensure patterns use forward slashes return pattern.Replace('\\', '/'); } private static string NormalizePath(string path) { // Ensure paths use forward slashes and are rooted var normalized = path.Replace('\\', '/'); if (!normalized.StartsWith('/')) { normalized = "/" + normalized; } return normalized; } }