Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[api-extractor] Adds package-defined TSDoc tag support #1950

Merged
merged 24 commits into from
Apr 17, 2021

Conversation

nicholasrice
Copy link
Contributor

@nicholasrice nicholasrice commented Jun 20, 2020

I took a shot at implementing #519 based on the feedback of #1628. I'm new to this code-base so very open to feedback on any of this. I also tried to implement this without causing any breaking changes but please call out any issues I may have missed.

This change involves removing AedocDefinitions references from api-extractor and api-extractor-model. The ExtractorConfig has been updated to construct the tsdocConfiguration for the Extractor process. The tsdocConfiguration is configured from one of two source tsdoc.json files:

  1. The tsdoc.json file in the project folder, if it exists
  2. otherwise from the api-extractor's tsdoc.json

Once configured, the configuration is provided to parts of the process requiring a tsdocConfiguration.

api-extractor-model was also changed to remove it's dependency on AedocDefintions - instead expecting any non-standard TSDoc tags for a given package to be enumerated in the metadata field of the model.

I made a few decisions that I'm unsure about and also had a few questions:

  1. Any non-standard tsdoc tag defined by the package is output by API Extractor to the metadata property of the produced {package}.api.json . This is so that tags can be ingested by the ApiPackage implementation and so that any non-standard tags can exist per package. This deviates from API Extractor: Add support for custom TSDoc tags #1628, where tags are provided to as part of the options config to the ApiModel implementation. If API Extractor: Add support for custom TSDoc tags #1628 is the preferred implementation (or if there is any other preferred implementation) please let me know and I'll adjust.
  2. I've tagged the AedocDefinitions implementation as @deprecated . I believe it is technically internal though, so should it be removed entirely?
  3. Where should this change be documented? Anything I need to do for documentation?
  4. I didn't add any explicit tests for this because I'm unsure how exactly I should do that. Should I add a package in build-tests that contains custom TSDoc tags?
  5. This doesn't change anything in api-documenter - should it to fully address [api-extractor] Support extensible AEDoc tags #519?

As always, open to any and all feedback.

closes #519

@@ -47,7 +46,21 @@ export class ApiDocumentedItem extends ApiItem {
const documentedJson: IApiDocumentedItemJson = jsonObject as IApiDocumentedItemJson;

if (documentedJson.docComment) {
const tsdocParser: tsdoc.TSDocParser = new tsdoc.TSDocParser(AedocDefinitions.tsdocConfiguration);
const tsdocConfiguration: tsdoc.TSDocConfiguration = new tsdoc.TSDocConfiguration();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a performance concern, since it will initialize a new TSDocConfiguration for every single doc comment.

Instead, we should construct it once and share it. The DeserializerContext could be used to store it:

const context: DeserializerContext = new DeserializerContext({
apiJsonFilename,
toolPackage: jsonObject.metadata.toolPackage,
toolVersion: jsonObject.metadata.toolVersion,
versionToDeserialize: versionToDeserialize
});
return ApiItem.deserialize(jsonObject, context) as ApiPackage;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call - DeserializerContext now stores the TSDocConfiguration and non-standard tags now configured in ApiPackage.loadFromJsonFile()

@nicholasrice nicholasrice force-pushed the users/nirice/custom-tags branch from 545836f to 4e8dd5c Compare July 10, 2020 16:38
@nicholasrice nicholasrice force-pushed the users/nirice/custom-tags branch from 4e8dd5c to 0546564 Compare July 22, 2020 16:12
@nicholasrice
Copy link
Contributor Author

@octogonz any chance you have some time to take another look at this? We're really looking forward to using this feature. Thanks in advance!

@octogonz
Copy link
Collaborator

I apologize -- I recently got sandbagged by a bunch of high priority work for the Heft and Rush projects, and have not been able to give much time to API Extractor. The pressure should hopefully be off by end of next week at the latest. This is a cool PR and I feel bad for delaying it!

@nicholasrice
Copy link
Contributor Author

No worries - I totally understand ;) Thanks @octogonz!

@nicholasrice nicholasrice force-pushed the users/nirice/custom-tags branch from 0546564 to a1f3c2e Compare July 29, 2020 21:47
@kazupon
Copy link

kazupon commented Nov 22, 2020

Is there any update?
I need this feature.

@EisenbergEffect
Copy link

Pinging @octogonz Not having this is really causing an issue for our open source efforts. Is there anything we need to do to help get this PR merged? I have engineering resources I can commit to seeing this PR through.

@octogonz
Copy link
Collaborator

Pinging @octogonz Not having this is really causing an issue for our open source efforts. Is there anything we need to do to help get this PR merged? I have engineering resources I can commit to seeing this PR through.

@EisenbergEffect I'll take a look at this today and follow up.

@octogonz
Copy link
Collaborator

Okay @EisenbergEffect I've merged master into this branch and read over the design discussion again.

Some thoughts:

  1. The main idea is to move the AedocDefinitions.ts config into tsdoc.json file so that it is visible to other tools. The tsdoc.json schema currently can represent this data:

       configuration.addTagDefinitions(
         [
           AedocDefinitions.betaDocumentation,
           AedocDefinitions.internalRemarks,
           AedocDefinitions.preapprovedTag
         ],
         true
       );

    ...but it seems not able to represent this data:

       configuration.setSupportForTags(
         [
           StandardTags.alpha,
           StandardTags.beta,
           StandardTags.decorator,
           StandardTags.defaultValue,
           StandardTags.deprecated,
           StandardTags.eventProperty,
           StandardTags.example,
       . . .

    Thus I think we need to add a "supportedTags" section to the tsdoc.json schema. That should be pretty easy.

  2. This PR updates the .api.json file format to serialize the tsdoc.json config as part of ApiPackage. Since nothing about this serialization is unique to API Extractor, it seems better to implement the serialization in the @microsoft/tsdoc-config package rather than in @microsoft/api-extractor-model. This way it can more easily stay in sync with the tsdoc.json data model. (The data can still be embedded in API Extractor's .api.json file -- merely the serialization format will be owned by @microsoft/tsdoc-config. Maybe it is exactly the same JSON structure as tsdoc.json.)

  3. When custom tags are defined, they need to inherit from API Extractor's tsdoc.json file using the "extends" field. I suspect this is already working, but we need to add a test to demonstrate how it works and validate the implementation.

I think we can implement all these things pretty quickly. Lemme see if I can make some PRs over the weekend.

@octogonz
Copy link
Collaborator

I think we can implement all these things pretty quickly.

Here's an upstream PR that adds the missing features: microsoft/tsdoc#277

@EisenbergEffect
Copy link

Thanks @octogonz !
@nicholasrice Can you continue to follow-up as needed? Thanks!

@octogonz
Copy link
Collaborator

Here's a second PR that sorts out a problem where the serialized TSDoc config includes the predefined standard tags, which would then conflict with the tags that are predefined when api-extractor-model deserializes that data: microsoft/tsdoc#279

Once that's published, I think we'll have all the pieces necessary to finally complete this PR. 😊🤞

@nicholasrice
Copy link
Contributor Author

Thanks @octogonz! This is awesome to see; we're really looking forward to this feature.

@nicholasrice
Copy link
Contributor Author

Hey @octogonz! I'm in the process of working in the tsdoc and tsdoc-config package updates and implementing your feedback and I have a question for you. I see you implemented a saveToObject(), which I'm using to serialize the configuration state to the .api.json files.

To build up the TSDocConfiguration from the .api.json, I'm having to re-wind the syntaxKind fields from their friendly name (calculated in TSDocConfigFile._serializeTagDefinition) into the corresponding TSDocTagSyntaxKind, which doesn't seem like api-extractor-model's responsibility. Is there a way to re-construct the the TSDocTagDefinition objects from the output of saveToObject() that doesn't involve switching friendly-name values for TSDocTagSyntaxKind values myself? Or paraphs there is a different approach I should be taking to hydrate the configuration in api-extractor-model?

@nicholasrice nicholasrice force-pushed the users/nirice/custom-tags branch from 0bb6a89 to 52829d8 Compare March 23, 2021 18:22
@@ -14,6 +14,18 @@ import { ApiDocumentedItem, IApiDocumentedItemOptions } from '../items/ApiDocume
import { ApiEntryPoint } from './ApiEntryPoint';
import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin';
import { DeserializerContext, ApiJsonSchemaVersion } from './DeserializerContext';
import { TSDocConfiguration, TSDocTagDefinition, TSDocTagSyntaxKind } from '@microsoft/tsdoc';

interface ITagConfigJson {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@octogonz defining these here is odd to me because they're essentially a copy of the interfaces defined in tsdoc-config and are the product of saveToObject(), but saveToObject() returns unknown. Should I do something to address this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was easy, so I went ahead and implemented the missing loadFromObject() operation in microsoft/tsdoc#288

tsdocConfiguration.addTagDefinitions(
tagDefinitions.map((definition) => {
const { syntaxKind } = definition;
const formattedSyntaxKind: TSDocTagSyntaxKind =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the re-mapping I am referring to in my previous comment. Should there be a mechanism from tsdoc-config to build up a TSDocConfigFile from the product of TSDocConfigFile.saveToObject()?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicholasrice The right solution would be to implement a corresponding TSDocConfigFile.loadFromObject() to handle loading of the object. Ideally it would be integrated with the TSDocConfigFile.loadFile() implementation, although there is an interesting nuance that loadFile() considers file paths and "extends" resolution which assume that the objects have meaningful file paths. So a bit of abstraction might be needed to handle that. (Perhaps that is why I procrastinated it?)

If you want to make a PR for TSDoc that would be great. However your PR has been open for a very long time, so if it helps speed things along, I would also be okay with merging a less ideal solution to get you unblocked. And then we could come back later and improve the tsdoc-config API.

I am away on vacation right now, but I will review this PR as soon as I get back. Sorry about the delays.

For future reference if you need help getting PRs merged @iclanton's team at Microsoft is a good point of contact, and also we now have a #contributor-helpline chatroom for getting attention of the maintainers. Thanks!

@EisenbergEffect
Copy link

Hey @octogonz 😄 Thanks for working with us on this. I think we're ready for another round of review from you. Nick had a few questions that he dropped above. Would be great to get these last few things wrapped, merged, and released. We're pretty excited for this work as we'll be able to make some huge improvements to our documentation and it will also enable some other teams we're working with as well. 🎊

@octogonz
Copy link
Collaborator

@EisenbergEffect I apologize for the delay. I'm on vacation -- will be back next week.

…e/custom-tags

# Conflicts:
#	common/config/rush/nonbrowser-approved-packages.json
#	common/config/rush/pnpm-lock.yaml
#	common/config/rush/repo-state.json
@octogonz octogonz enabled auto-merge April 17, 2021 16:26
@octogonz octogonz merged commit 87f2647 into microsoft:master Apr 17, 2021
@octogonz
Copy link
Collaborator

octogonz commented Apr 17, 2021

Okay @nicholasrice sorry again about the delays in getting this PR reviewed. I've updated your branch to use TSConfigFile.loadFromObject(), and also updated ApiJsonSchemaVersion to implement backwards compatibility for your change to the .api.json file format. I also moved api-extractor/tsdoc.json to api-extractor/extends/tsdoc-base.json to make it more clear that projects are expected to extend from this file.

After merging this PR we'll do a little more testing and then we should finally be ready to release this. After using it a bit, it is a pretty cool feature. I'm very excited about it! Thanks for all your work to make it happen.

@EisenbergEffect
Copy link

Awesome @octogonz ! Thank you so much for helping to move this through 😄

@nicholasrice
Copy link
Contributor Author

Thank you @octogonz! It's awesome to see this go through, thanks for working with me on it :)

@octogonz
Copy link
Collaborator

This was released with API Extractor 7.14.0.

Docs here: https://api-extractor.com/pages/configs/tsdoc_json/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[api-extractor] Support extensible AEDoc tags
4 participants