Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -85,42 +85,30 @@ public static class New
];

internal static readonly IEnumerable<Option> LegacyOptions;
internal static readonly IEnumerable<Option> LegacyFilterOptions;

private static readonly IReadOnlyDictionary<FilterOptionDefinition, Option> s_legacyFilters;
private static readonly Lazy<CommandDefinition> s_lazyCommand = new(Create);

static New()
{
IReadOnlyList<FilterOptionDefinition> legacyFilterDefinitions =
LegacyFilterOptions =
[
FilterOptionDefinition.AuthorFilter,
FilterOptionDefinition.BaselineFilter,
FilterOptionDefinition.LanguageFilter,
FilterOptionDefinition.TypeFilter,
FilterOptionDefinition.TagFilter,
FilterOptionDefinition.PackageFilter
SharedOptionsFactory.CreateAuthorOption().AsHidden(),
SharedOptionsFactory.CreateBaselineOption().AsHidden(),
SharedOptionsFactory.CreateLanguageOption().AsHidden(),
SharedOptionsFactory.CreateTypeOption().AsHidden(),
SharedOptionsFactory.CreateTagOption().AsHidden(),
SharedOptionsFactory.CreatePackageOption().AsHidden()
];

var filterOptionsMap = new Dictionary<FilterOptionDefinition, Option>();
var filterOptions = new List<Option>();

foreach (var filterDef in legacyFilterDefinitions)
{
var option = filterDef.OptionFactory().AsHidden();
filterOptionsMap.Add(filterDef, option);
filterOptions.Add(option);
}

LegacyOptions =
[
InteractiveOption,
AddSourceOption,
ColumnsAllOption,
ColumnsOption,
.. filterOptions,
.. LegacyFilterOptions
];

s_legacyFilters = filterOptionsMap;
}

public static CommandDefinition Command => s_lazyCommand.Value;
Expand Down Expand Up @@ -176,18 +164,6 @@ private static CommandDefinition Create()
command.Options.AddRange(LegacyOptions);
return command;
}

internal static OrderedDictionary<FilterOptionDefinition, Option> CreateFilterOptions(IEnumerable<FilterOptionDefinition> supportedFilters, bool isLegacy)
{
var filterOptionsMap = new OrderedDictionary<FilterOptionDefinition, Option>();

foreach (var filterDef in supportedFilters)
{
filterOptionsMap.Add(filterDef, isLegacy ? s_legacyFilters[filterDef] : filterDef.OptionFactory());
}

return filterOptionsMap;
}
}

public static class Alias
Expand Down Expand Up @@ -368,13 +344,13 @@ public Uninstall(string name, bool isLegacy)

public sealed class List : CommandDefinition
{
public static readonly IEnumerable<FilterOptionDefinition> SupportedFilters =
public static readonly IEnumerable<Option> SupportedFilterOptions =
[
FilterOptionDefinition.AuthorFilter,
FilterOptionDefinition.BaselineFilter,
FilterOptionDefinition.LanguageFilter,
FilterOptionDefinition.TypeFilter,
FilterOptionDefinition.TagFilter
SharedOptions.AuthorOption,
SharedOptions.BaselineOption,
SharedOptions.LanguageOption,
SharedOptions.TypeOption,
SharedOptions.TagOption,
];

public static readonly Argument<string> NameArgument = new("template-name")
Expand All @@ -399,19 +375,19 @@ public sealed class List : CommandDefinition
public Option<bool> ColumnsAllOption { get; }
public Option<string[]> ColumnsOption { get; }

public OrderedDictionary<FilterOptionDefinition, Option> Filters { get; }
public IEnumerable<Option> FilterOptions { get; }

public List(string name, bool isLegacy)
: base(name, SymbolStrings.Command_List_Description)
{
Hidden = isLegacy;
ColumnsAllOption = isLegacy ? New.ColumnsAllOption : SharedOptions.ColumnsAllOption;
ColumnsOption = isLegacy ? New.ColumnsOption : SharedOptions.ColumnsOption;
Filters = New.CreateFilterOptions(SupportedFilters, isLegacy);
FilterOptions = isLegacy ? New.LegacyFilterOptions : SupportedFilterOptions;

Arguments.Add(NameArgument);

Options.AddRange(Filters.Values);
Options.AddRange(FilterOptions);

Options.AddRange(
[
Expand All @@ -422,20 +398,20 @@ public List(string name, bool isLegacy)
ColumnsOption,
]);

this.AddNoLegacyUsageValidators(isLegacy ? [.. Filters.Values, ColumnsAllOption, ColumnsOption, New.ShortNameArgument] : []);
this.AddNoLegacyUsageValidators(isLegacy ? [.. FilterOptions, ColumnsAllOption, ColumnsOption, New.ShortNameArgument] : []);
}
}

public sealed class Search : CommandDefinition
{
public static readonly IEnumerable<FilterOptionDefinition> SupportedFilters =
public static readonly IEnumerable<Option> SupportedFilterOptions =
[
FilterOptionDefinition.AuthorFilter,
FilterOptionDefinition.BaselineFilter,
FilterOptionDefinition.LanguageFilter,
FilterOptionDefinition.TypeFilter,
FilterOptionDefinition.TagFilter,
FilterOptionDefinition.PackageFilter
SharedOptions.AuthorOption,
SharedOptions.BaselineOption,
SharedOptions.LanguageOption,
SharedOptions.TypeOption,
SharedOptions.TagOption,
SharedOptions.PackageOption
];

public static readonly Argument<string> NameArgument = new("template-name")
Expand All @@ -456,27 +432,27 @@ public sealed class Search : CommandDefinition
public Option<bool> ColumnsAllOption { get; }
public Option<string[]> ColumnsOption { get; }

public OrderedDictionary<FilterOptionDefinition, Option> Filters { get; }
public IEnumerable<Option> FilterOptions { get; }

public Search(string name, bool isLegacy)
: base(name, SymbolStrings.Command_Search_Description)
{
Hidden = isLegacy;
ColumnsAllOption = isLegacy ? New.ColumnsAllOption : SharedOptions.ColumnsAllOption;
ColumnsOption = isLegacy ? New.ColumnsOption : SharedOptions.ColumnsOption;
Filters = New.CreateFilterOptions(SupportedFilters, isLegacy);
FilterOptions = isLegacy ? New.LegacyFilterOptions : SupportedFilterOptions;

Arguments.Add(NameArgument);

Options.AddRange(Filters.Values);
Options.AddRange(FilterOptions);

Options.AddRange(
[
ColumnsAllOption,
ColumnsOption,
]);

this.AddNoLegacyUsageValidators(isLegacy ? [.. Filters.Values, ColumnsAllOption, ColumnsOption, New.ShortNameArgument] : []);
this.AddNoLegacyUsageValidators(isLegacy ? [.. FilterOptions, ColumnsAllOption, ColumnsOption, New.ShortNameArgument] : []);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ namespace Microsoft.TemplateEngine.Cli.Commands
{
public static class SharedOptions
{
// fitler options:
public static Option<string> AuthorOption { get; } = SharedOptionsFactory.CreateAuthorOption();
public static Option<string> BaselineOption { get; } = SharedOptionsFactory.CreateBaselineOption();
public static Option<string> LanguageOption { get; } = SharedOptionsFactory.CreateLanguageOption();
public static Option<string> TypeOption { get; } = SharedOptionsFactory.CreateTypeOption();
public static Option<string> TagOption { get; } = SharedOptionsFactory.CreateTagOption();
public static Option<string> PackageOption { get; } = SharedOptionsFactory.CreatePackageOption();

public static Option<FileInfo> OutputOption { get; } = new("--output", "-o")
{
Description = SymbolStrings.Option_Output,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ internal string GetFilterValue(FilterOptionDefinition filter)
private static IReadOnlyDictionary<FilterOptionDefinition, OptionResult> ParseFilters(IFilterableCommand filterableCommand, ParseResult parseResult)
{
Dictionary<FilterOptionDefinition, OptionResult> filterValues = new();
foreach (var filter in filterableCommand.Filters)
foreach (var option in filterableCommand.FilterOptions)
{
OptionResult? value = parseResult.GetResult(filter.Value);
OptionResult? value = parseResult.GetResult(option);
if (value != null)
{
filterValues[filter.Key] = value;
filterValues[FilterOptionDefinition.AllDefinitions[option.Name]] = value;
}
}
return filterValues;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.CommandLine;
using Microsoft.TemplateEngine.Abstractions;
using Microsoft.TemplateEngine.Abstractions.TemplateFiltering;
using Microsoft.TemplateEngine.Cli.TemplateResolution;
Expand All @@ -16,55 +15,52 @@ namespace Microsoft.TemplateEngine.Cli.Commands
/// </summary>
internal class FilterOptionDefinition
{
internal FilterOptionDefinition(Func<Option> optionFactory)
{
OptionFactory = optionFactory ?? throw new ArgumentNullException(nameof(optionFactory));
}

internal static FilterOptionDefinition AuthorFilter { get; } =
new TemplateFilterOptionDefinition(
optionFactory: () => SharedOptionsFactory.CreateAuthorOption(),
matchFilter: authorArg => WellKnownSearchFilters.AuthorFilter(authorArg),
mismatchCriteria: resolutionResult => resolutionResult.HasAuthorMismatch,
matchInfoName: MatchInfo.BuiltIn.Author);

internal static FilterOptionDefinition BaselineFilter { get; } =
new TemplateFilterOptionDefinition(
optionFactory: () => SharedOptionsFactory.CreateBaselineOption(),
matchFilter: baselineArg => WellKnownSearchFilters.BaselineFilter(baselineArg),
mismatchCriteria: resolutionResult => resolutionResult.HasBaselineMismatch,
matchInfoName: MatchInfo.BuiltIn.Baseline);

internal static FilterOptionDefinition LanguageFilter { get; } =
new TemplateFilterOptionDefinition(
optionFactory: () => SharedOptionsFactory.CreateLanguageOption(),
matchFilter: languageArg => WellKnownSearchFilters.LanguageFilter(languageArg),
mismatchCriteria: resolutionResult => resolutionResult.HasLanguageMismatch,
matchInfoName: MatchInfo.BuiltIn.Language);

internal static FilterOptionDefinition TagFilter { get; } =
new TemplateFilterOptionDefinition(
optionFactory: () => SharedOptionsFactory.CreateTagOption(),
matchFilter: tagArg => WellKnownSearchFilters.ClassificationFilter(tagArg),
mismatchCriteria: resolutionResult => resolutionResult.HasClassificationMismatch,
matchInfoName: MatchInfo.BuiltIn.Classification);

internal static FilterOptionDefinition TypeFilter { get; } =
new TemplateFilterOptionDefinition(
optionFactory: () => SharedOptionsFactory.CreateTypeOption(),
matchFilter: typeArg => WellKnownSearchFilters.TypeFilter(typeArg),
mismatchCriteria: resolutionResult => resolutionResult.HasTypeMismatch,
matchInfoName: MatchInfo.BuiltIn.Type);

internal static FilterOptionDefinition PackageFilter { get; } =
new PackageFilterOptionDefinition(
optionFactory: () => SharedOptionsFactory.CreatePackageOption(),
matchFilter: PackageMatchFilter);

/// <summary>
/// A predicate that creates instance of option.
/// Maps option name to the corresponding filter definition.
/// </summary>
internal Func<Option> OptionFactory { get; }
public static readonly IReadOnlyDictionary<string, FilterOptionDefinition> AllDefinitions = new Dictionary<string, FilterOptionDefinition>()
{
{ SharedOptions.AuthorOption.Name, AuthorFilter },
{ SharedOptions.BaselineOption.Name, BaselineFilter },
{ SharedOptions.LanguageOption.Name, LanguageFilter },
{ SharedOptions.TagOption.Name, TagFilter },
{ SharedOptions.TypeOption.Name, TypeFilter },
{ SharedOptions.PackageOption.Name, PackageFilter }
};

private static Func<ITemplatePackageInfo, bool> PackageMatchFilter(string? packageArg)
{
Expand All @@ -82,55 +78,40 @@ private static Func<ITemplatePackageInfo, bool> PackageMatchFilter(string? packa
/// <summary>
/// Defines supported dotnet new command filter option applicable to the template.
/// </summary>
internal class TemplateFilterOptionDefinition : FilterOptionDefinition
internal sealed class TemplateFilterOptionDefinition(
Func<string?, Func<ITemplateInfo, MatchInfo?>> matchFilter,
Func<TemplateResolutionResult, bool> mismatchCriteria,
string matchInfoName) : FilterOptionDefinition
{
internal TemplateFilterOptionDefinition(
Func<Option> optionFactory,
Func<string?, Func<ITemplateInfo, MatchInfo?>> matchFilter,
Func<TemplateResolutionResult, bool> mismatchCriteria,
string matchInfoName) : base(optionFactory)
{
TemplateMatchFilter = matchFilter ?? throw new ArgumentNullException(nameof(matchFilter));
MismatchCriteria = mismatchCriteria ?? throw new ArgumentNullException(nameof(mismatchCriteria));
MatchInfoName = matchInfoName ?? throw new ArgumentNullException(nameof(matchInfoName));
}

/// <summary>
/// A predicate that returns the template match filter for the filter option.
/// Template match filter should return the MatchInfo for the given template based on filter value.
/// </summary>
/// <remarks>
/// Common template match filters are defined in Microsoft.TemplateEngine.Utils.WellKnonwnSearchFilter class.
/// </remarks>
internal Func<string?, Func<ITemplateInfo, MatchInfo?>> TemplateMatchFilter { get; set; }
internal Func<string?, Func<ITemplateInfo, MatchInfo?>> TemplateMatchFilter { get; } = matchFilter;

/// <summary>
/// A predicate that returns if the filter option caused a mismatch in <see cref="TemplateResolutionResult"/> in case of partial match.
/// </summary>
internal Func<TemplateResolutionResult, bool> MismatchCriteria { get; set; }
internal Func<TemplateResolutionResult, bool> MismatchCriteria { get; } = mismatchCriteria;

/// <summary>
/// A <see cref="MatchInfo"/> name used in match dispositions.
/// </summary>
internal string MatchInfoName { get; set; }
internal string MatchInfoName { get; } = matchInfoName;
}

/// <summary>
/// Defines supported dotnet new command filter option applicable to the package.
/// </summary>
internal class PackageFilterOptionDefinition : FilterOptionDefinition
internal sealed class PackageFilterOptionDefinition(Func<string?, Func<ITemplatePackageInfo, bool>> matchFilter) : FilterOptionDefinition
{
internal PackageFilterOptionDefinition(
Func<Option> optionFactory,
Func<string?, Func<ITemplatePackageInfo, bool>> matchFilter) : base(optionFactory)
{
PackageMatchFilter = matchFilter ?? throw new ArgumentNullException(nameof(matchFilter));
}

/// <summary>
/// A predicate that returns the package match filter for the filter option
/// Package match filter should if package is a match based on filter value.
/// </summary>
internal Func<string?, Func<ITemplatePackageInfo, bool>> PackageMatchFilter { get; set; }
internal Func<string?, Func<ITemplatePackageInfo, bool>> PackageMatchFilter { get; } = matchFilter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ namespace Microsoft.TemplateEngine.Cli.Commands
{
internal interface IFilterableCommand
{
IReadOnlyDictionary<FilterOptionDefinition, Option> Filters { get; }
IEnumerable<Option> FilterOptions { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal BaseListCommand(
_definition = definition;
}

public IReadOnlyDictionary<FilterOptionDefinition, Option> Filters => _definition.Filters;
public IEnumerable<Option> FilterOptions => _definition.FilterOptions;

public Option<bool> ColumnsAllOption => _definition.ColumnsAllOption;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal BaseSearchCommand(Func<ParseResult, ITemplateEngineHost> hostBuilder, C
_definition = definition;
}

public IReadOnlyDictionary<FilterOptionDefinition, Option> Filters => _definition.Filters;
public IEnumerable<Option> FilterOptions => _definition.FilterOptions;

public Option<bool> ColumnsAllOption => _definition.ColumnsAllOption;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ internal static bool HasMismatchOnConstraints(this ITemplateMatchInfo templateMa

internal static bool HasMismatchOnListFilters(this ITemplateMatchInfo templateMatchInfo)
{
IEnumerable<string> supportedFilters = CommandDefinition.List.SupportedFilters.OfType<TemplateFilterOptionDefinition>().Select(f => f.MatchInfoName);
var supportedFilters = CommandDefinition.List.SupportedFilterOptions
.Select(option => FilterOptionDefinition.AllDefinitions[option.Name])
.OfType<TemplateFilterOptionDefinition>()
.Select(f => f.MatchInfoName);

var filterMatches = templateMatchInfo.MatchDisposition.Where(mi => supportedFilters.Any(f => f == mi.Name));
var otherMatches = templateMatchInfo.MatchDisposition.Where(mi => !supportedFilters.Any(f => f == mi.Name));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ private static bool ValidateCommandInput(SearchCommandArgs commandArgs)
// && !commandInput.RemainingParameters.Any())
{
Reporter.Error.WriteLine(LocalizableStrings.CliTemplateSearchCoordinator_Error_NoTemplateName.Red().Bold());
Reporter.Error.WriteLine(LocalizableStrings.CliTemplateSearchCoordinator_Info_SearchHelp, string.Join(", ", CommandDefinition.Search.SupportedFilters.Select(f => $"'{f.OptionFactory().Name}'")));
Reporter.Error.WriteLine(LocalizableStrings.CliTemplateSearchCoordinator_Info_SearchHelp, string.Join(", ", CommandDefinition.Search.SupportedFilterOptions.Select(static option => $"'{option.Name}'")));
Reporter.Error.WriteLine(LocalizableStrings.Generic_ExamplesHeader);
Reporter.Error.WriteCommand(
Example
Expand Down
Loading