//
// Copyright (c) StellaOps. Licensed under BUSL-1.1.
//
namespace StellaOps.Facet;
///
/// Classifies files into facets based on selectors.
///
public sealed class FacetClassifier
{
private readonly List<(IFacet Facet, GlobMatcher Matcher)> _facetMatchers;
///
/// Initializes a new instance of the class.
///
/// Facets to classify against (will be sorted by priority).
public FacetClassifier(IEnumerable facets)
{
ArgumentNullException.ThrowIfNull(facets);
// Sort by priority (lowest first = highest priority)
_facetMatchers = facets
.OrderBy(f => f.Priority)
.Select(f => (f, GlobMatcher.ForFacet(f)))
.ToList();
}
///
/// Creates a classifier using built-in facets.
///
public static FacetClassifier Default { get; } = new(BuiltInFacets.All);
///
/// Classify a file path to a facet.
///
/// The file path to classify.
/// The matching facet or null if no match.
public IFacet? Classify(string path)
{
ArgumentNullException.ThrowIfNull(path);
// First matching facet wins (ordered by priority)
foreach (var (facet, matcher) in _facetMatchers)
{
if (matcher.IsMatch(path))
{
return facet;
}
}
return null;
}
///
/// Classify a file and return the facet ID.
///
/// The file path to classify.
/// The facet ID or null if no match.
public string? ClassifyToId(string path)
=> Classify(path)?.FacetId;
///
/// Classify multiple files efficiently.
///
/// The file paths to classify.
/// Dictionary from facet ID to matched paths.
public Dictionary> ClassifyMany(IEnumerable paths)
{
ArgumentNullException.ThrowIfNull(paths);
var result = new Dictionary>();
foreach (var path in paths)
{
var facet = Classify(path);
if (facet is not null)
{
if (!result.TryGetValue(facet.FacetId, out var list))
{
list = [];
result[facet.FacetId] = list;
}
list.Add(path);
}
}
return result;
}
}