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

RFC: @throws tag for documenting exceptions #171

Open
octogonz opened this issue Jul 12, 2019 · 8 comments
Open

RFC: @throws tag for documenting exceptions #171

octogonz opened this issue Jul 12, 2019 · 8 comments

Comments

@octogonz
Copy link
Collaborator

In #8 (comment) @bookmoons said:

I vote for @throws, or some other way to document exceptions. Really useful when coding against a procedure to know which kind of errors I should be handling.

I've opened this issue so we can have a more focused discussion.

@octogonz
Copy link
Collaborator Author

(BTW this came up earlier in #63 (comment). In that discussion, I was proposing that @throws should not be interpreted as an exhaustive list of all possible errors. Instead, it should merely be a way for a documentation author to talk about certain exceptions if they are very interesting to the API contract. If someone disagrees with that position, we could discuss it further.)

@octogonz
Copy link
Collaborator Author

octogonz commented Jul 12, 2019

Whenever TSDoc refers to a type, it needs to be a rigorous syntax that is able to express any possible API type.

JSDoc uses something called name paths for this. Since JavaScript types are simple, their syntax is relatively simple.

The TSDoc equivalent is called declaration references. It's fairly different because TypeScript's type system is much more challenging to model. We need to distinguish stuff like function overloads, merged declarations, etc. We also support some weird stuff like ECMAScript symbols and quoted identifiers.

In TSDoc, your proposed format @throws MyError - my description has an ambiguity problem: The - character can be part of a declaration reference. For example, if core-library is an NPM package that exports a class MyError, then we want to write:

/**
 * @throws core-library#MyError - my description
 */
export function doSomething(): void;

But is the type core, or is it core-library#MyError? A human can tell from context, but a parser cannot be sure. The grammar is ambiguous and would need some special way to distinguish them.

We could solve it by using { and } like JSDoc does:

/**
 * @throws {core-library#MyError} a description of when it happens
 */
export function doSomething(): void;

But what if the NPM package is called @microsoft/core-library? Now we want to write:

/**
 * @throws {@microsoft/core-library#MyError} a description of when it happens
 */
export function doSomething(): void;

But {@microsoft/core-library#MyError} looks a lot like an inline tag {@microsoft} whose content is /core-library#MyError. We would need some rule to disambiguate them.

If I remember right, JSDoc doesn't have this problem because they use a module: prefix to indicate a module:

/**
 * @throws {module:@microsoft/core-library.MyError} a description of when it happens
 */
export function doSomething(): void;

TSDoc chose not to use : as a prefix operator because : pervasively appears in TypeScript code as a postfix operator. It would be fairly confusing to reinterpret it.

There's lots of creative ways to resolve ambiguities. The pros/cons tend to be very deep discussions. This case with @throws is interesting, as it's the first TSDoc block tag that ever needed to embed a declaration reference.

My main input would be to push our discussion towards a /general/ mechanism that can be used by custom tags as well. A major goal of TSDoc is to be extensible: If users invent custom tags and add them to their docs, this should not prevent other tools from being able to correctly parse the content. (For example, XML is perfectly extensible. Whereas Markdown is not extensible at all -- it's effectively impossible to write content that is portable between implementations.)

So I think we could handle this by introducing a general way to embed declaration references in arbitrary content. And then we would say that for @throws, the error type should simply appear at the start of the block. Then someone can invent a custom block tag like @isAFactoryFor or @canContain that refers to other types in the same way.

@rbuckton who recently put a lot of thought into declaration reference grammar.

@octogonz
Copy link
Collaborator Author

Heh, I suppose a super simple option is like this:

/**
 * @throws {@link @microsoft/core-library#MyError} a description of when it happens
 */
export function doSomething(): void;

@octogonz
Copy link
Collaborator Author

Are you proposing an informal convention that would be proprietary to your tool? In other words, TSDoc should treat @throws as a generic rich text block, but specific implementations can choose to parse stuff out of there if they want to?

@aciccarello
Copy link

I think it makes sense to leave it as a generic text block. That is how it is currently handled in typedoc. Making it special has been requested in TypeStrong/typedoc#1045 but even that wouldn't require any special parsing (just a rendering change).

@octogonz
Copy link
Collaborator Author

I created PR 175 to add support for this tag.

@vidartf
Copy link

vidartf commented Nov 19, 2019

I think this issue is closed with the merge of #175?

@octogonz
Copy link
Collaborator Author

The RFCs will all get closed when we post the first draft of the spec document.

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

No branches or pull requests

3 participants