| File: Commands\Example.cs | Web Access |
| Project: src\sdk\src\Cli\Microsoft.TemplateEngine.Cli\Microsoft.TemplateEngine.Cli.csproj (Microsoft.TemplateEngine.Cli) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; using System.CommandLine; using System.CommandLine.Parsing; namespace Microsoft.TemplateEngine.Cli.Commands { internal abstract class Example { internal static Example<T> For<T>(ParseResult parseResult) where T : Command { var commandResult = parseResult.CommandResult; //check for parent commands first while (commandResult?.Command != null && commandResult.Command is not T) { commandResult = (commandResult.Parent as CommandResult); } if (commandResult?.Command is T typedCommand) { List<string> parentCommands = new(); while (commandResult?.Command != null) { parentCommands.Add(commandResult.Command.Name); commandResult = (commandResult.Parent as CommandResult); } parentCommands.Reverse(); return new Example<T>(typedCommand, [.. parentCommands]); } // if the command is not found in parents of command result, try to search it in the whole command tree T siblingCommand = SearchForSiblingCommand<T>(parseResult.CommandResult.Command); List<string> parentCommands2 = new(); Command? nextCommand = siblingCommand; while (nextCommand != null) { parentCommands2.Add(nextCommand.Name); nextCommand = nextCommand.Parents.OfType<Command>().FirstOrDefault(); } parentCommands2.Reverse(); return new Example<T>(siblingCommand, [.. parentCommands2]); } private static T SearchForSiblingCommand<T>(Command currentCommand) where T : Command { Command? next = currentCommand; Command root = currentCommand; while (next != null) { root = next; next = next?.Parents.OfType<Command>().FirstOrDefault(); } Queue<Command> probes = new(); probes.Enqueue(root); while (probes.Count > 0) { Command current = probes.Dequeue(); if (current is T typedCommand) { return typedCommand; } foreach (var child in current.Subcommands) { probes.Enqueue(child); } } throw new Exception($"Command structure is not correct: {nameof(T)} is not found."); } internal static Example<T> FromExistingTokens<T>(ParseResult parseResult) where T : Command { // root command name is not part of the tokens var commandParts = parseResult.Tokens.Select(t => t.Value).Prepend(parseResult.RootCommandResult.Command.Name); return new Example<T>((T)parseResult.CommandResult.Command, [.. commandParts]); } public static implicit operator string(Example e) => e.ToString()!; public Example WithHelpOption() => WithHelpOptionImpl(); protected abstract Example WithHelpOptionImpl(); } internal sealed class Example<T>(T currentCommand, ImmutableArray<string> commandParts) : Example where T : Command { public override string ToString() => string.Join(" ", commandParts); internal Example<T> WithOption(Func<T, Option> optionSelector, params string[] args) { var option = optionSelector(currentCommand); if (args.Any()) { return new(currentCommand, commandParts.Add(option.Name).AddRange(args.Select(a => a.Any(char.IsWhiteSpace) ? $"'{a}'" : a))); } if (option.Arity.MinimumNumberOfValues == 0) { return new(currentCommand, commandParts.Add(option.Name)); } return new(currentCommand, commandParts.AddRange(option.Name, CommandLineUtils.FormatArgumentUsage(option))); } protected override Example WithHelpOptionImpl() => WithHelpOption(); public new Example<T> WithHelpOption() => new(currentCommand, commandParts.Add(Constants.KnownHelpAliases.First())); public Example<T> WithArguments(params IEnumerable<string> args) => new(currentCommand, commandParts.AddRange(args.Select(a => a.Any(char.IsWhiteSpace) ? $"'{a}'" : a))); public Example<T> WithArgument(Func<T, Argument> argumentSelector) => new(currentCommand, commandParts.Add(CommandLineUtils.FormatArgumentUsage(argumentSelector(currentCommand)))); public Example<TSubcommand> WithSubcommand<TSubcommand>(Func<T, TSubcommand> subcommandSelector) where TSubcommand : Command { var subcommand = subcommandSelector(currentCommand); return new(subcommand, commandParts.Add(subcommand.Name)); } public Example<TSubcommand> WithSubcommand<TSubcommand>() where TSubcommand : Command { var subcommand = (TSubcommand?)currentCommand.Subcommands.FirstOrDefault(c => c is TSubcommand) ?? throw new ArgumentException($"Command {currentCommand.Name} does not have subcommand {typeof(TSubcommand).Name}"); return new(subcommand, commandParts.Add(subcommand.Name)); } internal Example<Command> WithSubcommand(string token) { var subcommand = currentCommand.Subcommands.FirstOrDefault(c => c.Name.Equals(token) || c.Aliases.Contains(token)) ?? throw new ArgumentException($"Command {currentCommand.Name} does not have subcommand '{token}'."); return new(subcommand, commandParts.Add(token)); } } }