// Creates a command setup with the args for "new", plus args for the input template parameters.
        public static Command CreateNewCommandWithArgsForTemplate(string commandName, string templateName,
                                                                  IReadOnlyList <ITemplateParameter> parameterDefinitions,
                                                                  IDictionary <string, string> longNameOverrides,
                                                                  IDictionary <string, string> shortNameOverrides,
                                                                  out IReadOnlyDictionary <string, IReadOnlyList <string> > templateParamMap)
        {
            IList <Option>   paramOptionList       = new List <Option>();
            HashSet <string> initiallyTakenAliases = ArgsForBuiltInCommands;

            Dictionary <string, IReadOnlyList <string> > canonicalToVariantMap = new Dictionary <string, IReadOnlyList <string> >();
            AliasAssignmentCoordinator assignmentCoordinator = new AliasAssignmentCoordinator(parameterDefinitions, longNameOverrides, shortNameOverrides, initiallyTakenAliases);

            if (assignmentCoordinator.InvalidParams.Count > 0)
            {
                string unusableDisplayList = string.Join(", ", assignmentCoordinator.InvalidParams);
                throw new Exception($"Template is malformed. The following parameter names are invalid: {unusableDisplayList}");
            }

            foreach (ITemplateParameter parameter in parameterDefinitions.Where(x => x.Priority != TemplateParameterPriority.Implicit))
            {
                Option         option;
                IList <string> aliasesForParam = new List <string>();

                if (assignmentCoordinator.LongNameAssignments.TryGetValue(parameter.Name, out string longVersion))
                {
                    aliasesForParam.Add(longVersion);
                }

                if (assignmentCoordinator.ShortNameAssignments.TryGetValue(parameter.Name, out string shortVersion))
                {
                    aliasesForParam.Add(shortVersion);
                }

                if (string.Equals(parameter.DataType, "choice", StringComparison.OrdinalIgnoreCase))
                {
                    option = Create.Option(string.Join("|", aliasesForParam), parameter.Documentation,
                                           Accept.ExactlyOneArgument());
                    //.WithSuggestionsFrom(parameter.Choices.Keys.ToArray())
                    // Don't give this a default value, otherwise the switch without a value is valid (gets set to the default)
                    // User should have to give a value, or not specify the switch - which causes the default to be applied.
                }
                else if (string.Equals(parameter.DataType, "bool", StringComparison.OrdinalIgnoreCase))
                {
                    option = Create.Option(string.Join("|", aliasesForParam), parameter.Documentation,
                                           Accept.ZeroOrOneArgument()
                                           .WithSuggestionsFrom(new[] { "true", "false" }));
                }
                else
                {
                    option = Create.Option(string.Join("|", aliasesForParam), parameter.Documentation,
                                           Accept.ExactlyOneArgument());
                }

                paramOptionList.Add(option);                                         // add the option
                canonicalToVariantMap.Add(parameter.Name, aliasesForParam.ToList()); // map the template canonical name to its aliases.
            }

            templateParamMap = canonicalToVariantMap;
            return(GetNewCommandForTemplate(commandName, templateName, NewCommandVisibleArgs, NewCommandHiddenArgs, DebuggingCommandArgs, paramOptionList.ToArray()));
        }
        // Creates a command setup with the args for "new", plus args for the input template parameters.
        internal static Command CreateNewCommandWithArgsForTemplate(
            string commandName,
            string templateName,
            IReadOnlyList <ITemplateParameter> parameterDefinitions,
            IDictionary <string, string> longNameOverrides,
            IDictionary <string, string> shortNameOverrides,
            out IReadOnlyDictionary <string, IReadOnlyList <string> > templateParamMap)
        {
            IList <Option>   paramOptionList       = new List <Option>();
            HashSet <string> initiallyTakenAliases = ArgsForBuiltInCommands;

            Dictionary <string, IReadOnlyList <string> > canonicalToVariantMap = new Dictionary <string, IReadOnlyList <string> >();
            AliasAssignmentCoordinator assignmentCoordinator = new AliasAssignmentCoordinator(parameterDefinitions, longNameOverrides, shortNameOverrides, initiallyTakenAliases);

            if (assignmentCoordinator.InvalidParams.Count > 0)
            {
                string unusableDisplayList = string.Join(", ", assignmentCoordinator.InvalidParams);
                throw new Exception($"Template is malformed. The following parameter names are invalid: {unusableDisplayList}");
            }

            foreach (ITemplateParameter parameter in parameterDefinitions.Where(x => x.Priority != TemplateParameterPriority.Implicit))
            {
                Option         option;
                IList <string> aliasesForParam = new List <string>();

                if (assignmentCoordinator.LongNameAssignments.TryGetValue(parameter.Name, out string longVersion))
                {
                    aliasesForParam.Add(longVersion);
                }

                if (assignmentCoordinator.ShortNameAssignments.TryGetValue(parameter.Name, out string shortVersion))
                {
                    aliasesForParam.Add(shortVersion);
                }

                if (parameter is IAllowDefaultIfOptionWithoutValue parameterWithNoValueDefault &&
                    !string.IsNullOrEmpty(parameterWithNoValueDefault.DefaultIfOptionWithoutValue))
                {
                    // This switch can be provided with or without a value.
                    // If the user doesn't specify a value, it gets the value of DefaultIfOptionWithoutValue
                    option = Create.Option(string.Join("|", aliasesForParam), parameter.Documentation, Accept.ZeroOrOneArgument());
                }