CLI Documentation with DocC

Fair warning - this is kind of a deeply nerdy how-it-works in the weeds kind of questions around DocC, SymbolKit, and extending that system.

(/cc @QuietMisdreavus @ronnqvist)

The core of what I'm after is some insight from the tooling authors as to when and where it's appropriate to add in additional "Symbol" kinds - building on the Symbol graph JSON format - to support integrating documentation from sources other than compilation.

I spent a bit of time digging around in the code to try and understand it a bit, and it looks like there's a pattern of extending the "Kind" of symbol to other inputs - bits and pieces of a data domain that looks like it was used for OpenAPI or REST kinds of symbols are in there.

The library Swift Argument Parser has a convenient function that dumps a JSON output from the help content for an executable, which exposes a structured view of "commands", "positional arguments", "options", and "flags" for an executable. A year or more ago, the argument parser tooling explored a little of this path, and ended up taking a simpler route (much less code lifting) to convert this JSON into a standard markdown output that we could include in a GitHub repository, or embed into a DocC catalog to present CLI documentation.

While I was working on the CLI documentation for Swift Package Manager, I used this extensively. In a few places, there were limitations where I really wanted to be able to use DocC's mechanism of being able to extend the basics provided about the arguments, flags, etc with some additional markdown. Primarily to provide context beyond what was included in the --help content in the presented docs about how and when to use various CLI arguments or commands.

That led me back to the discussions around extending the Symbol Graph or kinds of inputs, and setting things up to convert these CLI argument specific structures into something that DocC could import and embed, akin to other symbols.

@ronnqvist created a prototype a year or more ago that re-used existing symbol graph types and treated commands, options, flags, and positional arguments akin to methods and parameters - the specifics of which I didn't go back and dig up, but there's some additional metadata detail with options, arguments, and flags that aren't easily specified when you use this - so I wanted to see what options might exist to covert and extend the symbols and use that in DocC.

Are there any "gotcha" points with adding in a new domain for something like CLI into symbolkit? And is that effectively "the" declaration location for this format? (Are there other places I should be looking to understand this holistically?)

If I did run down this road, then DocC looks like it would handle these new types gracefully, but it looks like better rendering could supported with registering new "identifiers" for these CLI types, using some of the "mixin" structures to expose the CLI-specific options (long-name, short-name, repeating, etc) or generating RenderNodes that could present the information in a more specialized way, appropriate for a CLI option.

Then with this in place, extending DocC-Render with the few view components to display this specific CLI data in HTML, which would also allow us to add in icons or badges, or whatever additional styling makes sense, for CLI commands, argument, option, and flags.

Are there other tradeoffs (or pot-holes) that I might find or hit if I go to tackle something like this that you can see?

Does anything stand out as "Oh my gosh, don't do that!!" from this kind of plan?

Is there a shorter path that we should consider that takes the argument parser JSON output to use within DocC that still lets us add/overlay additional content into it?

(right now, I'm thinking I might try and prototype this in branches - in the background & my spare time - to see how far I can get with it - but before I started that effort, I wanted to double-check my thinking and exploration of what's needed to wrangle all that)

2 Likes

I don't know if other people share the same goals and ideas about this but the rough guideline that I have in my head about introducing new symbol kinds is this:

If DocC would also need to be updated with some special behaviors that only apply to this type of symbol, then we'd want to define a new "kind" for that in the symbol graph format.

If, on the other hand, all that's needed is to represent a hierarchy of elements (optionally displaying some declaration-like code block above the Overview) then finding some way to represent that information using existing symbol graph fields is probably sufficient and has the benefit that it requires no code changes (and may even work with existing DocC versions going back several releases).

The latter is how DocC itself produces the documentation for its various "directives" (for example @DisplayName or @TabNavigator).

Applying this reasoning to command line tools; it would be fine to represent commands as "symbol" elements in a symbol graph file. One could represent the hierarchy of subcommands using the memberOf relationships between commands. One could use the symbol's declarationFragments to display the "usage" text using different fragment kinds to "syntax highlight" flags differently from values. With commands being represented as symbols, one would automatically be able to add to or override their documentation in documentation extension files. DocC would also automatically display the symbol's kind's displayName above the symbol name on the page.

That's about the point where this starts to reach its limits. One could also represent individual arguments and flags as their own symbols with their own "symbol kind display names" and their own "declaration fragments". The upside would be that each argument and flag would be individually linkable. However, at the same time it may be harder to get an overview of the arguments and flags. Much of that could likely be remedied by organizing the arguments and flags into DocC "Topics" sections based on their Option Group configurations in Swift-Argument-Parser (or manual groups if the commands don't already organize the arguments into groups). This would display each flag and their one-line summary/abstract on the command's page but readers would need to go to the individual argument's pages to read further explanations, see default values, etc.

It's possible that this is all that's really needed for documenting the commands, arguments, and flags and that we don't really need to add custom behaviors into DocC to represent command line commands and their components.

However, it's also very possible that someone has a great idea of how to display documentation about command line tools on the page that require some custom behaviors in DocC itself.

Luckily, it's quite easy to start out with representing commands and their components as generic symbols in the symbol graph format and later introduce new dedicated symbol "kinds" with some custom behaviors when there's a specific use-case driving the need for it.

1 Like

I’m currently exploring the GSoC idea about improving CLI documentation for Swift Argument Parser, including generating symbol graphs for commands and flags.

I was planning to start by representing them as generic symbols and then experiment with different renderings to see which CLI-specific behaviors would actually improve the presentation.

In the case where new symbol kinds aren’t needed, I’m curious which CLI metadata (for example default values, option groups, or short/long names) could already be represented using the existing symbol graph fields.

should i first draft my idea for: how to go from “one flat markdown” to “structured, linkable CLI docs that DocC can consume.”. ?