microsoft / rushstack

Monorepo for tools developed by the Rush Stack community
https://rushstack.io/
Other
5.96k stars 602 forks source link

[api-documenter] Suggestion: Improve YamlDocumenter support for namespaces #1325

Open rbuckton opened 5 years ago

rbuckton commented 5 years ago

Currently YamlDocumenter's _flattenNamespace completely elides namespaces, adding namespace members to the containing package. However, DocFX does (somewhat) support namespaces, just not nested namespaces.

I propose flattening the namespaces themselves to the containing package, and leaving their non-namespace children within the namespace.

The only problem is that DocFX doesn't quite properly handle namespaces in UniversalReference documents, but that can be fixed in a custom template or proposed as a PR to be fixed in the DocFX repo.

I experimented with this with good results:

If not the default behavior, if YamlDocumenter were easily customizable such that this output could be supported for custom templates, that would be an improvement.

octogonz commented 5 years ago

We should definitely improve this. Personally, none of the projects that I'm actively involved with use nested namespaces in their public API. Instead we generally rely on NPM packages as our organizational mechanism. This is partly for historical reasons; our team originally worked on SPFx which needed a dynamic linker, and thus could not benefit from "tree shaking" type optimizations (i.e. at the time when a bundle is compiled, we cannot predict which exports will be imported or not). Thus SPFx's optimization strategy was to incrementally load entire NPM package (bundles) on demand, versus e.g. Angular's approach of tree-shaking a statically-linked application bundle set.

<off-topic> We do encounter the need to group related functions together in a container, of course. But for this I actually prefer to avoid the namespace keyword, since you can usually accomplish the same thing with a class whose members are static. Although this is a not idiomatic TypeScript, it has several technical advantages:

  • A class can have private members, whereas a namespace can only have local variables that are trapped in a closure that generally cannot be inspected by a debugger
  • A class can have static property getters/setters, which are useful for validation or e.g. for a singleton that automatically initializes itself on first access. Namespaces don't support that.
  • A class can extend another base class, and the TypeScript language allows static methods to be overridden, which is sometimes useful (e.g. api-extractor-model relies on it for its deserializers)

</off-topic>

But these are just excuses why nested namespaces didn't get as much attention as other API Extractor features. Certainly we need to improve it. The current support for DocFX namespaces was mainly motivated by the Office Add-ins website. The result there is acceptable, but it could be better, and its owners would be very excited about any improvements. :-)

However, DocFX does (somewhat) support namespaces, just not nested namespaces.

What's up with that? DocFX is used for a large swath of nested non-TypeScript namespaces (for example System.IO.Ports). Are they working to improve it? Or maybe the designers liked the current representation? Or maybe improving it would be a lot of work? If we're designing a workaround in YamlDocumenter, it might be useful for us to understand the DocFX backstory.

If not the default behavior, if YamlDocumenter were easily customizable such that this output could be supported for custom templates, that would be an improvement.

FYI this summer we're putting together an api-documenter.json config file that would drive everything, and provide a natural way to specify such customizations.

However, my first inclination would be to implement your improvements in a general way that would benefit all consumers, rather than requiring special customizations. I believe the docs.microsoft.com owners have a similar goal of minimizing deviations from the default template, to ensure a consistent experience across all the different SDKs at Microsoft. In my experience, individual API owners want things to "just work", and if the output is reasonable and practical, they're not too opinionated about the design details. So we probably have a fair amount of freedom to propose improvements to the generated YAML.

Do you have an example of a nested namespace?

rbuckton commented 5 years ago

Do you have an example of a nested namespace?

Not in that repo, but the TypeScript compiler itself uses them.

rbuckton commented 5 years ago

What's up with that? DocFX is used for a large swath of nested non-TypeScript namespaces (for example System.IO.Ports). Are they working to improve it? Or maybe the designers liked the current representation? Or maybe improving it would be a lot of work? If we're designing a workaround in YamlDocumenter, it might be useful for us to understand the DocFX backstory.

I don't know the history, but I would guess that they just didn't have enough information yet on the story for how to use namespaces in a UniversalReference document. The problem is that namespaces in a UniversalReference document end up using the template for namespaces in a ManagedReference document, so they don't render correctly.