diff --git a/src/Nullean.Argh.Generator/CliParserGenerator.Analysis.cs b/src/Nullean.Argh.Generator/CliParserGenerator.Analysis.cs index 225d1fe..d4cef2f 100644 --- a/src/Nullean.Argh.Generator/CliParserGenerator.Analysis.cs +++ b/src/Nullean.Argh.Generator/CliParserGenerator.Analysis.cs @@ -280,6 +280,9 @@ private static bool IsInvocationInsideMapNamespaceConfigure(InvocationExpression entryTypeSnapshot = BuildRegistryNodeSnapshot(entryNode); } + var (_nsHideHelp, _nsHideSchema) = namespaceEntryType is not null + ? GetHiddenFlags(namespaceEntryType) + : (false, false); return new AIMapNamespace( filePath, spanStart, @@ -294,7 +297,9 @@ private static bool IsInvocationInsideMapNamespaceConfigure(InvocationExpression HasEntryType: namespaceEntryType is not null, SourceSpanInfo.From(invocation.GetLocation()), ImmutableArray.Empty, - entryTypeSnapshot); + entryTypeSnapshot, + NsIsHiddenFromHelp: _nsHideHelp, + NsIsHiddenFromSchema: _nsHideSchema); } /// Recursively expands type registration using DiagnosticAccumulator (for Select-step analysis). @@ -318,12 +323,15 @@ private static void ExpandTypeRegistrationAcc( var wrapper = new RegistryNode(); var outerPrefix = AppendSegment(routePrefix, seg); ExpandTypeRegistrationAcc(acc, location, type, outerPrefix, mergeOuterTypeSegment: true, wrapper, parseOpts, compilation); + var (_typeHideHelp, _typeHideSchema) = GetHiddenFlags(type); attachTo.Children.Add(new RegistryNode.NamedCommandNamespaceChild { Segment = seg, Node = wrapper, SummaryOneLiner = GetTypeListingSummaryOneLiner(type), - Location = location + Location = location, + IsHidden = _typeHideHelp, + IsHiddenInSchema = _typeHideSchema }); } } @@ -333,7 +341,7 @@ private static RegistryNodeSnapshot BuildRegistryNodeSnapshot(RegistryNode node) { var children = ImmutableArray.CreateBuilder(node.Children.Count); foreach (var ch in node.Children) - children.Add(new ChildNamespaceSnapshot(ch.Segment, BuildRegistryNodeSnapshot(ch.Node), ch.SummaryOneLiner)); + children.Add(new ChildNamespaceSnapshot(ch.Segment, BuildRegistryNodeSnapshot(ch.Node), ch.SummaryOneLiner, ch.IsHidden, ch.IsHiddenInSchema)); return new RegistryNodeSnapshot( node.RootCommand, node.Commands.ToImmutableArray(), @@ -655,7 +663,9 @@ private static void ProcessAnalyzedMapNamespace( Segment = ns.SegmentName, Node = childNode, SummaryOneLiner = ns.NsSummary, - Location = ns.DiagnosticSpanInfo.ToLocation() + Location = ns.DiagnosticSpanInfo.ToLocation(), + IsHidden = ns.NsIsHiddenFromHelp, + IsHiddenInSchema = ns.NsIsHiddenFromSchema }); } @@ -717,7 +727,9 @@ private static void ApplyRegistryNodeSnapshot(RegistryNodeSnapshot snap, Registr Segment = childSnap.Segment, Node = childNode, SummaryOneLiner = childSnap.SummaryOneLiner, - Location = Location.None + Location = Location.None, + IsHidden = childSnap.IsHidden, + IsHiddenInSchema = childSnap.IsHiddenInSchema }); } target.SummaryInnerXml = snap.SummaryInnerXml; diff --git a/src/Nullean.Argh.Generator/CliParserGenerator.CommandModel.cs b/src/Nullean.Argh.Generator/CliParserGenerator.CommandModel.cs index 777b4a6..817a6d5 100644 --- a/src/Nullean.Argh.Generator/CliParserGenerator.CommandModel.cs +++ b/src/Nullean.Argh.Generator/CliParserGenerator.CommandModel.cs @@ -47,6 +47,7 @@ private sealed record CommandModel( bool IsIntrinsic = false, ImmutableArray CommandAliases = default, bool IsHidden = false, + bool IsHiddenInSchema = false, bool IsDeprecated = false, string? DeprecationMessage = null, CommandIntentData? Intent = null, @@ -121,7 +122,8 @@ public static CommandModel FromMethod( var hasParamlessCtor = method.ContainingType is INamedTypeSymbol namedCt && HasPublicParameterlessCtor(namedCt); var (retFq, retIsAsync, retIsVoid, handlerNoInj, handlerParams, handlerLoc, ctorParams, mwData, docId) = ExtractHandlerAnalysis(method); var (isDeprecated, deprecationMsg) = TryGetObsoleteAttribute(method); - return new CommandModel(routePrefix, commandName, runName, containingFq, method.Name, !method.IsStatic, hasParamlessCtor, retFq, retIsAsync, retIsVoid, withDocs, handlerNoInj, handlerParams, handlerLoc, ctorParams, docId, docs.SummaryOneLiner, docs.RemarksRendered, docs.SummaryInnerXml, docs.RemarksInnerXml, docs.ExamplesRendered, usage, mwData, IsIntrinsic: HasCommandIntrinsicAttribute(method), CommandAliases: TryGetCommandAliasesFromAttribute(method), IsHidden: HasHiddenAttribute(method), IsDeprecated: isDeprecated, DeprecationMessage: deprecationMsg, Intent: TryGetCommandIntentData(method), Output: BuildCommandOutputFromParameters(withDocs)); + var (_cmdHideHelp, _cmdHideSchema) = GetHiddenFlags(method); + return new CommandModel(routePrefix, commandName, runName, containingFq, method.Name, !method.IsStatic, hasParamlessCtor, retFq, retIsAsync, retIsVoid, withDocs, handlerNoInj, handlerParams, handlerLoc, ctorParams, docId, docs.SummaryOneLiner, docs.RemarksRendered, docs.SummaryInnerXml, docs.RemarksInnerXml, docs.ExamplesRendered, usage, mwData, IsIntrinsic: HasCommandIntrinsicAttribute(method), CommandAliases: TryGetCommandAliasesFromAttribute(method), IsHidden: _cmdHideHelp, IsHiddenInSchema: _cmdHideSchema, IsDeprecated: isDeprecated, DeprecationMessage: deprecationMsg, Intent: TryGetCommandIntentData(method), Output: BuildCommandOutputFromParameters(withDocs)); } private static ImmutableArray BuildParameterModels( diff --git a/src/Nullean.Argh.Generator/CliParserGenerator.Emit.Dispatch.cs b/src/Nullean.Argh.Generator/CliParserGenerator.Emit.Dispatch.cs index 20c1048..8b12505 100644 --- a/src/Nullean.Argh.Generator/CliParserGenerator.Emit.Dispatch.cs +++ b/src/Nullean.Argh.Generator/CliParserGenerator.Emit.Dispatch.cs @@ -647,7 +647,8 @@ private static void EmitPrintRootHelpHierarchical(StringBuilder sb, AppEmitModel var maxOptWidthRoot = Math.Min(widthCandidatesGlobalRoot.Max(), 40); maxOptWidthRoot = Math.Max(maxOptWidthRoot, "-h, --help".Length); - var maxNsListingW = app.Root.Children.Count == 0 ? 0 : app.Root.Children.Max(ch => ch.Segment.Length); + var visibleRootChildren = app.Root.Children.Where(static ch => !ch.IsHidden).ToList(); + var maxNsListingW = visibleRootChildren.Count == 0 ? 0 : visibleRootChildren.Max(ch => ch.Segment.Length); var visibleRootCmds = app.Root.Commands.Where(static c => !c.IsHidden).ToList(); var maxCmdListingW = visibleRootCmds.Count == 0 ? 0 : visibleRootCmds.Max(c => c.CommandName.Length); @@ -675,10 +676,10 @@ private static void EmitPrintRootHelpHierarchical(StringBuilder sb, AppEmitModel $"\t\t\tConsole.Out.WriteLine(\" \" + CliHelpFormatting.Placeholder(\"{Escape("--version".PadRight(maxOptWidthRoot))}\") + \" Show version.\");"); EmitHelpOptionRows(sb, rootGlobalFlags, maxOptWidthRoot); sb.AppendLine("\t\t\tConsole.Out.WriteLine();"); - if (app.Root.Children.Count > 0) + if (visibleRootChildren.Count > 0) { sb.AppendLine("\t\t\tConsole.Out.WriteLine(CliHelpFormatting.Section(\"Namespaces:\"));"); - foreach (var ch in app.Root.Children.OrderBy(ch => ch.Segment, StringComparer.OrdinalIgnoreCase).ThenBy(ch => ch.Segment, StringComparer.Ordinal)) + foreach (var ch in visibleRootChildren.OrderBy(ch => ch.Segment, StringComparer.OrdinalIgnoreCase).ThenBy(ch => ch.Segment, StringComparer.Ordinal)) { var sumArg = string.IsNullOrWhiteSpace(ch.SummaryOneLiner) ? "null" @@ -740,9 +741,8 @@ private static void EmitCommandNamespaceHelpPrinter(StringBuilder sb, ImmutableA var maxOptWidth = Math.Min(widthCandidatesNs.Max(), 40); maxOptWidth = Math.Max(maxOptWidth, "-h, --help".Length); - var maxChildNsListingW = 0; - if (node.Children.Count > 0) - maxChildNsListingW = node.Children.Max(ch => FormatQualifiedCliPath(path, ch.Segment).Length); + var visibleChildNamespaces = node.Children.Where(static ch => !ch.IsHidden).ToList(); + var maxChildNsListingW = visibleChildNamespaces.Count == 0 ? 0 : visibleChildNamespaces.Max(ch => FormatQualifiedCliPath(path, ch.Segment).Length); var maxChildCmdListingW = 0; var visibleNodeCmds = node.Commands.Where(static c => !c.IsHidden).ToList(); if (visibleNodeCmds.Count > 0) @@ -781,10 +781,10 @@ private static void EmitCommandNamespaceHelpPrinter(StringBuilder sb, ImmutableA } } - if (node.Children.Count > 0) + if (visibleChildNamespaces.Count > 0) { sb.AppendLine("\t\t\tConsole.Out.WriteLine(CliHelpFormatting.Section(\"Namespaces:\"));"); - foreach (var ch in node.Children.OrderBy(ch => ch.Segment, StringComparer.OrdinalIgnoreCase).ThenBy(ch => ch.Segment, StringComparer.Ordinal)) + foreach (var ch in visibleChildNamespaces.OrderBy(ch => ch.Segment, StringComparer.OrdinalIgnoreCase).ThenBy(ch => ch.Segment, StringComparer.Ordinal)) { var fullNs = FormatQualifiedCliPath(path, ch.Segment); var sumArg = string.IsNullOrWhiteSpace(ch.SummaryOneLiner) diff --git a/src/Nullean.Argh.Generator/CliParserGenerator.Models.cs b/src/Nullean.Argh.Generator/CliParserGenerator.Models.cs index cd2dfdb..9b5a717 100644 --- a/src/Nullean.Argh.Generator/CliParserGenerator.Models.cs +++ b/src/Nullean.Argh.Generator/CliParserGenerator.Models.cs @@ -37,6 +37,8 @@ public sealed class NamedCommandNamespaceChild /// First non-empty XML summary from the first generic Add handler type in this namespace block. public string SummaryOneLiner = ""; public Location Location = Location.None; + public bool IsHidden = false; + public bool IsHiddenInSchema = false; } } @@ -254,7 +256,9 @@ private sealed record AIMapNamespace( /// Contains root commands, regular commands, and nested children from ExpandTypeRegistration. /// Null when there is no entry type. /// - RegistryNodeSnapshot? EntryTypeSnapshot) + RegistryNodeSnapshot? EntryTypeSnapshot, + bool NsIsHiddenFromHelp = false, + bool NsIsHiddenFromSchema = false) : AnalyzedInvocation(FilePath, SpanStart); /// Symbol-free snapshot of a RegistryNode subtree produced during analysis. @@ -271,7 +275,9 @@ private sealed record RegistryNodeSnapshot( private sealed record ChildNamespaceSnapshot( string Segment, RegistryNodeSnapshot Node, - string SummaryOneLiner); + string SummaryOneLiner, + bool IsHidden = false, + bool IsHiddenInSchema = false); // ───────────────────────────────────────────────────────────────────────────── diff --git a/src/Nullean.Argh.Generator/CliParserGenerator.ParameterModel.cs b/src/Nullean.Argh.Generator/CliParserGenerator.ParameterModel.cs index c830183..93a15b8 100644 --- a/src/Nullean.Argh.Generator/CliParserGenerator.ParameterModel.cs +++ b/src/Nullean.Argh.Generator/CliParserGenerator.ParameterModel.cs @@ -59,6 +59,7 @@ private sealed record ParameterModel( bool ExpandUserProfileBeforeBind = false, ImmutableArray Validations = default, bool IsHidden = false, + bool IsHiddenInSchema = false, bool IsVariadic = false, /// /// True when the property is from a cross-assembly type (DeclaringSyntaxReferences empty) and has no @@ -151,6 +152,7 @@ private static ParameterModel BuildCollectionParameterModel( if (isVariadic) required = false; var (isOutputColl, outputFormatsColl) = TryGetCommandOutputAttribute(attributeHost); var (isDeprecatedColl, deprecationMsgColl) = TryGetObsoleteAttribute(attributeHost); + var (_colHideHelp, _colHideSchema) = GetHiddenFlags(attributeHost); return new ParameterModel( symbolName, localVarName, @@ -190,7 +192,8 @@ private static ParameterModel BuildCollectionParameterModel( AsParametersClrName: asParams?.ClrName, ExpandUserProfileBeforeBind: expandProfileElem, Validations: collValidations, - IsHidden: HasHiddenAttribute(attributeHost), + IsHidden: _colHideHelp, + IsHiddenInSchema: _colHideSchema, IsVariadic: isVariadic, IsConfirmationSkip: HasConfirmationSkipAttribute(attributeHost), IsDryRun: HasDryRunAttribute(attributeHost), @@ -252,6 +255,7 @@ public static ParameterModel From(IParameterSymbol p, DiagnosticAccumulator? rep var expandProf = TryReadExpandUserProfileBeforeBind(p, sk); var (isOutputP, outputFormatsP) = TryGetCommandOutputAttribute(p); var (isDeprecatedP, deprecationMsgP) = TryGetObsoleteAttribute(p); + var (_paramHideHelp, _paramHideSchema) = GetHiddenFlags(p); return new ParameterModel( p.Name, SafeLocalName(p.Name), @@ -273,7 +277,8 @@ public static ParameterModel From(IParameterSymbol p, DiagnosticAccumulator? rep EnumMemberDocs: enumDocs, ExpandUserProfileBeforeBind: expandProf, Validations: validations, - IsHidden: HasHiddenAttribute(p), + IsHidden: _paramHideHelp, + IsHiddenInSchema: _paramHideSchema, IsConfirmationSkip: HasConfirmationSkipAttribute(p), IsDryRun: HasDryRunAttribute(p), IsCommandOutput: isOutputP, @@ -310,6 +315,7 @@ public static ParameterModel FromOptionsProperty(IPropertySymbol prop, Compilati var validations = ReadValidationConstraints(prop, sk, typeName); var defLit = QualifyOptionsEnumDefaultLiteral(defaultValueLiteral, sk, enumFq, enumMembers); var expandProf = TryReadExpandUserProfileBeforeBind(prop, sk); + var (_propHideHelp, _propHideSchema) = GetHiddenFlags(prop); return new ParameterModel( prop.Name, SafeLocalName(prop.Name), @@ -331,7 +337,8 @@ public static ParameterModel FromOptionsProperty(IPropertySymbol prop, Compilati EnumMemberDocs: enumDocs, ExpandUserProfileBeforeBind: expandProf, Validations: validations, - IsHidden: HasHiddenAttribute(prop), + IsHidden: _propHideHelp, + IsHiddenInSchema: _propHideSchema, UsesRuntimeDefault: isCrossAssemblyDefault, IsNullableAnnotated: prop.Type.NullableAnnotation == NullableAnnotation.Annotated || prop.Type is INamedTypeSymbol { OriginalDefinition.SpecialType: SpecialType.System_Nullable_T }, @@ -367,6 +374,7 @@ public static ParameterModel FromOptionsField(IFieldSymbol field, Compilation? c var validations = ReadValidationConstraints(field, sk, typeName); var defLit = QualifyOptionsEnumDefaultLiteral(defaultValueLiteral, sk, enumFq, enumMembers); var expandProf = TryReadExpandUserProfileBeforeBind(field, sk); + var (_fieldHideHelp, _fieldHideSchema) = GetHiddenFlags(field); return new ParameterModel( field.Name, SafeLocalName(field.Name), @@ -387,7 +395,8 @@ public static ParameterModel FromOptionsField(IFieldSymbol field, Compilation? c EnumMemberCliNames: enumCliNames, ExpandUserProfileBeforeBind: expandProf, Validations: validations, - IsHidden: HasHiddenAttribute(field), + IsHidden: _fieldHideHelp, + IsHiddenInSchema: _fieldHideSchema, UsesRuntimeDefault: isCrossAssemblyDefault, IsNullableAnnotated: field.Type.NullableAnnotation == NullableAnnotation.Annotated || field.Type is INamedTypeSymbol { OriginalDefinition.SpecialType: SpecialType.System_Nullable_T }); diff --git a/src/Nullean.Argh.Generator/CliParserGenerator.Schema.cs b/src/Nullean.Argh.Generator/CliParserGenerator.Schema.cs index 17a6222..8c602bb 100644 --- a/src/Nullean.Argh.Generator/CliParserGenerator.Schema.cs +++ b/src/Nullean.Argh.Generator/CliParserGenerator.Schema.cs @@ -163,7 +163,7 @@ private static void EmitCliCommandSchemaBody(StringBuilder sb, CommandModel cmd, var aliasArr = string.Join(", ", cmd.CommandAliases.Select(a => $"\"{Escape(a)}\"")); sb.Append($"{indent}\tAliases: new string[] {{ {aliasArr} }}"); } - if (cmd.IsHidden) + if (cmd.IsHiddenInSchema) { sb.AppendLine(","); sb.Append($"{indent}\tHidden: true"); @@ -461,7 +461,7 @@ private static string EmitCliParameterSchemaNewExpression(ParameterModel p) sb.Append($", ElementType: \"{elemType}\""); } - if (p.IsHidden) + if (p.IsHiddenInSchema) sb.Append(", Hidden: true"); if (p.IsVariadic) diff --git a/src/Nullean.Argh.Generator/CliParserGenerator.SymbolReaders.cs b/src/Nullean.Argh.Generator/CliParserGenerator.SymbolReaders.cs index 748010e..d759713 100644 --- a/src/Nullean.Argh.Generator/CliParserGenerator.SymbolReaders.cs +++ b/src/Nullean.Argh.Generator/CliParserGenerator.SymbolReaders.cs @@ -40,16 +40,24 @@ private static bool HasCommandIntrinsicAttribute(IMethodSymbol method) return false; } - private static bool HasHiddenAttribute(ISymbol symbol) + private static (bool HideHelp, bool HideSchema) GetHiddenFlags(ISymbol symbol) { foreach (var ad in symbol.GetAttributes()) { if (ad.AttributeClass?.Name == "HiddenAttribute" && ad.AttributeClass.ContainingNamespace?.ToDisplayString() == "Nullean.Argh") - return true; + { + bool help = true, schema = false; + foreach (var na in ad.NamedArguments) + { + if (na.Key == "Help" && na.Value.Value is bool h) help = h; + if (na.Key == "Schema" && na.Value.Value is bool s) schema = s; + } + return (help, schema); + } } - return false; + return (false, false); } private static string? TryGetCommandNameAttribute(IMethodSymbol method) diff --git a/src/Nullean.Argh.Interfaces/Annotations/Attributes.cs b/src/Nullean.Argh.Interfaces/Annotations/Attributes.cs index 54db4a5..3343dbb 100644 --- a/src/Nullean.Argh.Interfaces/Annotations/Attributes.cs +++ b/src/Nullean.Argh.Interfaces/Annotations/Attributes.cs @@ -183,10 +183,18 @@ public sealed class EnumValueAttribute : Attribute } /// -/// Marks a command method or parameter as hidden from user-facing help and autocomplete suggestions. -/// The command or parameter still parses and works correctly, and appears in __schema output -/// with hidden: true so tooling can suppress it selectively. +/// Marks a command method, parameter, or namespace class as hidden from user-facing help and autocomplete. +/// By default (Help=true, Schema=false) the item is suppressed from help output but remains fully +/// visible in __schema output without any hidden marker. Set Schema=true to also mark it +/// with hidden: true in the schema so tooling can suppress it selectively. +/// The command or parameter still parses and works correctly regardless of these flags. /// -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property)] -public sealed class HiddenAttribute : Attribute; +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Class)] +public sealed class HiddenAttribute : Attribute +{ + /// When true (default), the item is suppressed from user-facing help listings. + public bool Help { get; set; } = true; + /// When true, the item is marked hidden: true in __schema output. Default is false. + public bool Schema { get; set; } = false; +} diff --git a/tests/Nullean.Argh.IntegrationTests/Completions/SchemaTests.cs b/tests/Nullean.Argh.IntegrationTests/Completions/SchemaTests.cs index 1933dd7..99f33cd 100644 --- a/tests/Nullean.Argh.IntegrationTests/Completions/SchemaTests.cs +++ b/tests/Nullean.Argh.IntegrationTests/Completions/SchemaTests.cs @@ -168,6 +168,21 @@ public void Schema_hidden_parameter_has_hidden_true() nameParam.TryGetProperty("hidden", out _).Should().BeFalse(); } + [Fact] + public void Schema_hidden_namespace_appears_in_schema_without_hidden_flag() + { + var result = CliHostRunner.Run("__schema"); + result.ExitCode.Should().Be(0); + using var doc = JsonDocument.Parse(CliHostRunner.StdoutText(result)); + var namespaces = doc.RootElement.GetProperty("namespaces"); + + // [Hidden] default: Help=true, Schema=false — namespace appears in schema, no hidden:true marker + var hiddenNs = namespaces.EnumerateArray() + .FirstOrDefault(n => n.GetProperty("segment").GetString() == "schema-hidden-ns"); + hiddenNs.ValueKind.Should().Be(JsonValueKind.Object); + hiddenNs.TryGetProperty("hidden", out _).Should().BeFalse(); + } + [Fact] public void Schema_default_value_is_emitted_for_parameters_with_defaults() { diff --git a/tests/Nullean.Argh.IntegrationTests/Help/RootAndNamespaceHelpTests.cs b/tests/Nullean.Argh.IntegrationTests/Help/RootAndNamespaceHelpTests.cs index 71244ec..b09c598 100644 --- a/tests/Nullean.Argh.IntegrationTests/Help/RootAndNamespaceHelpTests.cs +++ b/tests/Nullean.Argh.IntegrationTests/Help/RootAndNamespaceHelpTests.cs @@ -222,4 +222,24 @@ storage list TrimLines(text).Should().Be(TrimLines(expected)); text.Should().NotContain("hello"); } + + [Fact] + public void RootHelp_does_not_list_hidden_namespaces() + { + var result = CliHostRunner.Run( + new Dictionary(StringComparer.Ordinal) { ["NO_COLOR"] = "1" }, + "--help"); + result.ExitCode.Should().Be(0); + var text = ConsoleOutput.Normalize(CliHostRunner.StdoutText(result)); + text.Should().NotContain("schema-hidden-ns"); + text.Should().NotContain("schema-hidden-schema-ns"); + } + + [Fact] + public void Hidden_namespace_is_still_callable() + { + var result = CliHostRunner.Run("schema-hidden-ns", "internal-cmd"); + result.ExitCode.Should().Be(0); + CliHostRunner.StdoutText(result).Should().Contain("internal"); + } } diff --git a/tests/Nullean.Argh.Tests/CliRegistrationModule.cs b/tests/Nullean.Argh.Tests/CliRegistrationModule.cs index 136aa9d..354c719 100644 --- a/tests/Nullean.Argh.Tests/CliRegistrationModule.cs +++ b/tests/Nullean.Argh.Tests/CliRegistrationModule.cs @@ -93,6 +93,8 @@ internal static void RegisterCommands() app.Map("schema-intent-destructive", SchemaIntentHandlers.SchemaIntentDestructive); app.Map("schema-intent-read", SchemaIntentHandlers.SchemaIntentRead); app.Map("schema-output-formats", SchemaOutputHandlers.SchemaOutputFormats); + app.MapNamespace("schema-hidden-ns"); + app.MapNamespace("schema-hidden-schema-ns"); app.MapNamespace("storage", g => { g.UseNamespaceOptions(); diff --git a/tests/Nullean.Argh.Tests/Fixtures/SchemaSpecificHandlers.cs b/tests/Nullean.Argh.Tests/Fixtures/SchemaSpecificHandlers.cs index 439007f..8f7f4b3 100644 --- a/tests/Nullean.Argh.Tests/Fixtures/SchemaSpecificHandlers.cs +++ b/tests/Nullean.Argh.Tests/Fixtures/SchemaSpecificHandlers.cs @@ -22,7 +22,7 @@ public static void SchemaSeparatorList( /// Visible name flag. /// Internal ID (hidden). [NoOptionsInjection] - public static void SchemaHiddenParam(string name, [Hidden] string? internalId = null) => + public static void SchemaHiddenParam(string name, [Hidden(Schema = true)] string? internalId = null) => Console.Out.WriteLine($"name:{name}"); } @@ -34,7 +34,7 @@ internal sealed class SchemaHiddenCommands public static void VisibleCmd() => Console.Out.WriteLine("visible"); /// A command that is hidden from help and autocomplete. - [Hidden] + [Hidden(Schema = true)] [NoOptionsInjection] public static void HiddenCmd() => Console.Out.WriteLine("hidden"); } @@ -93,6 +93,24 @@ public static void SchemaIntentRead( Console.Out.WriteLine("list"); } +/// Schema test: a namespace hidden from help only (default [Hidden]). +[Hidden] +internal sealed class SchemaHiddenNamespace +{ + /// An internal command inside the hidden namespace. + [NoOptionsInjection] + public static void InternalCmd() => Console.Out.WriteLine("internal"); +} + +/// Schema test: a namespace hidden from both help and schema. +[Hidden(Schema = true)] +internal sealed class SchemaHiddenSchemaNamespace +{ + /// An internal command inside the hidden-from-schema namespace. + [NoOptionsInjection] + public static void InternalCmd() => Console.Out.WriteLine("internal-schema"); +} + /// Enum for output format selection. internal enum OutputFormat { Json, Table, Csv }