Giter Club home page Giter Club logo

tsdoc's Introduction

https://tsdoc.org/

#tsdoc chat room   Build Status

Documentation Links

Projects in this monorepo

Folder Version Changelog Description
/api-demo (local project) Code samples illustrating how to use the @microsoft/tsdoc parser
/eslint-plugin npm version changelog eslint-plugin-tsdoc plugin for ESLint
/playground (local project) Source code for the TSDoc Playground web app
/tsdoc npm version changelog @microsoft/tsdoc parser library
/tsdoc-config npm version changelog @microsoft/tsdoc-config loader for tsdoc.json

Contributor Notice

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.

When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

tsdoc's People

Contributors

0xclarity avatar 72636c avatar airman5573 avatar apostolisms avatar arnog avatar bafolts avatar bitjson avatar eisenbergeffect avatar hashimshah avatar iclanton avatar jginsburgn avatar josephjunker avatar kevintcoughlin avatar luchanso avatar magic-akari avatar martynaszilinskas avatar microsoft-github-policy-service[bot] avatar microsoftopensource avatar msftgits avatar noahbuscher avatar octogonz avatar olli-lauhaa avatar pgonzal avatar pissedcapslock avatar qz2017 avatar rbuckton avatar rushbot avatar samisayegh avatar sebastianhaas avatar trivikr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tsdoc's Issues

RFC: TSDoc-flavored-Markdown (TSFM) instead of CommonMark

Based on the issues encountered in the issue #12 thread, we are concluding that TSDoc cannot reasonably be based directly on the CommonMark spec. The goals are conflicting:

  • CommonMark goal: ("common" = union) Provide a standardized algorithm for parsing every familiar markup notation. It's okay if the resulting syntax rules are impossible for humans to memorize, because mistakes can be easily corrected using the editor's interactive preview. If a syntax is occasionally misinterpreted, the consequence is incorrect formatting on the web site, which is a relatively minor issue.

  • TSFM goal: ("common" = intersection) Provide a familiar syntax that is very easy for humans to memorize, so that a layperson can predict exactly how their markup will be rendered (by every possible downstream doc pipeline). Computer source code is handled by many different viewers which may not support interactive preview. If a syntax is occasionally misinterpreted, the consequence is that a tag such as @beta or @internal may be ignored by the parser, which could potentially cause a serious issue (e.g. an escalation from an enterprise customer whose service was interrupted because of a broken API contract).

Hypothesis: For every TSFM construct, there exists a normalized form that will be parsed identically by CommonMark and TSDoc. In "strict mode" the TSDoc library can issue warnings for expressions that are not in normalized form. Assuming the author eliminates all such warnings, then a documentation pipeline can passthrough unmodified TSDoc content to a backend CommonMark engine, and have confidence that the rendered output will be correct.

Below are some proposed TSFM restrictions:

Whitespace generally doesn't matter

This principle is very easy for people to remember, and eliminates a ton of edge cases.

Example 1:

/**
 * TSFM considers this to be an HTML element, whereas CommonMark does not:
 * <element attribute="@tag"
 *
 * />
 */

Example 1 converted to normalized form (so CommonMark interprets it the same as TSDoc):

/**
 * TSFM considers this to be an HTML element, whereas CommonMark does not:
 * <element attribute="@tag"
 * />
 */

Example 2:

/**
 * CommonMark interprets this indentation to make a code block, TSFM sees rich markup:
 * 
 *     **bold** @tag
 */

Example 2 converted to normalized form (so CommonMark interprets it the same as TSDoc):

/**
 * CommonMark interprets this indentation to make a code block, TSFM sees rich markup:
 * 
 * **bold** @tag
 */

Stars cannot be nested arbitrarily

TSDoc will support stars for bold/italics, based on 6 types of tokens that can be recognized by the lexical analyzer with minimal lookahead:

  • Opening italics single-star, e.g. *text is interpreted as <i>text
  • Closing italics single-star, e.g. text* is interpreted as text</i>
  • Opening bold double-star, e.g. **text is interpreted as <b>text
  • Closing bold double-star, e.g. text** is interpreted as text</b>
  • Opening bold+italics triple-star, e.g. ***text is interpreted as if <b+i>text
  • Closing bold+italics triple-star, e.g. text*** is interpreted as if text</b+i>

Other patterns are NOT interpreted as star tokens, e.g. text * text * contains literal asterisks, as does ****a****. A letter in the middle of a word can never be styled using stars, e.g. Toys*R*Us contains literal asterisk characters. A single-star followed by a double-star can be closed by a triple-star (e.g. *italics **bold+italics*** is seen as <i>italics<b>bold+italics</b+i>). Star markup is prohibited from spanning multiple lines.

Other characters (e.g. underscore) are NOT supported by TSDoc as synonyms for bold/italics.

Example 3:

/**
 * *CommonMark sees italics, but TSDoc does not because
 * its stars cannot span lines.*
 *
 * CommonMark sees italics here: __proto__
 *
 * Common**M**ark sees a boldfaced M, but TSDoc sees literal stars.
 */

Example 3 normalized form:

/**
 * \*CommonMark sees italics, but TSDoc does not because
 * its stars cannot span lines.\*
 *
 * CommonMark sees italics here: \_\_proto\_\_ (or better to use `__proto__`)
 *
 * Common\*\*M\*\*ark sees a boldfaced M, but TSDoc sees literal stars.
 *
 * If you really need to boldface a letter, use HTML elements: Common<b>M</b>ark.
 */

Example 4:

/**
 * For **A **B** C** the B is double-boldfaced according to CommonMark.
 * The TSDoc tokenizer sees `<b>A <b>B</b> C</b>` which the parser then flattens
 * to `<b>A **B</b> C**` because it doesn't allow nesting.
 *
 * Improper balancing also gets ignored, e.g. for **A *B** C* the TSDoc tokenizer
 * will see `<b>A <i>B</b> C</i>` which the parser flattens to `<b>A *B</b> C*`
 * Whereas CommonMark would counterintuitively see `<i><i>A<i>B</i></i>C</i>`.
 */

Example 4 normalized form:

/**
 * For **A \*\*B** C\*\* the B is double-boldfaced according to CommonMark.
 * The TSDoc tokenizer sees `<b>A <b>B</b> C</b>` which the parser then flattens
 * to `<b>A **B</b> C**` because it doesn't allow nesting.
 *
 * Improper balancing also gets ignored, e.g. for **A \*B** C\* the TSDoc tokenizer
 * will see `<b>A <i>B</b> C</i>` which the parser flattens to `<b>A *B</b> C*`
 * Whereas CommonMark would counterintuitively see `<i><i>A<i>B</i></i>C</i>`.
 */

Code spans are simplified

For TSFM, a nonescaped backtick will always start a code span and end with the next backtick. Whitespace doesn't matter.

Example 5:

/**
 * `Both TSDoc and CommonMark
 * agree this is code.`
 *
 * before `CommonMark disagrees
 *
 * if a line is skipped, though.` after
 *
 * `But this is not code because the backtick is unterminated
 */

Example 5 normalized form:

/**
 * `Both TSDoc and CommonMark
 * agree this is code.`
 *
 * before `CommonMark disagrees
 * if a line is skipped, though.` after
 *
 * \`But this is not code because the backtick is unterminated
 */

Blocks don't nest

I want to say that ">" blockquotes should not be supported at all, since the whitespace handling for these constructs is highly counterintuitive. Instead we would recommend <blockquote> HTML tags for this scenario.

Lists are a very useful and common scenario. However, CommonMark lists also have a lot of counterintuitive rules regarding handling of whitespace.

A simplification would be to say that TSFM interprets any line that starts with "-" as being a list item, and the list ends with the first blank line. No other character (e.g. "*" or "+") can be used to create lists. If complicated nesting is required, then HTML tags such as <ul> and <li> should be used to avoid any confusion.

Example 6:

/**
 * A list with 3 things
 * - item 1
 *              - item 2
 * spans several
 *      lines
 * - item 3
 *
 * Two lists separated by a newline
 * -  list 1 with one item
 *
 * - list 2 with one item
 *
 * + not a list item
 * + not a list item
 *
 * CommonMark surprisingly considers this to be a list whose first item is another list,
 * whereas TSDoc sees a minus character as the first item:
 * - - foo
 */

Example 6 normalized form:

/**
 * A list with 3 things
 * - item 1
 * - item 2
 *   spans several
 *   lines
 * - item 3
 *
 * Two lists separated by a newline
 * -  list 1 with one item
 * <!-- CommonMark requires an HTML comment to separate two lists -->
 * - list 2 with one item
 *
 * \+ not a list item
 * \+ not a list item
 * 
 * CommonMark surprisingly considers this to be a list whose first item is another list,
 * whereas TSDoc sees a minus character as the first item:
 * - \- foo
 */

RFC: Handling of ambiguous comment blocks

Consider the following TypeScript source file:

/** [1]
 * @file Copyright (c) Example Corporation
 */

/** [2]
 * The Widget class
 */
// [3] TODO: This class needs to be refactored
export class Widget {
  /** [4]
   * The width of the Widget class
   */
  // [5] private width: string;

  /* [6] Renders the class */
  public render(): void {
  }

  /**
   * [7] The height of the widget
   */
  public get height(): number {
  }

  // [8] This is a setter for the above getter
  /**
   * [9] Sets the height
   */
  public set height(value: number) {
  }
}

Which comments are associated with which API items?

We might expect a documentation tool to associate the comments as follows:

  • Widget: Uses [2] as its doc comment
  • Widget.render: No doc comment, but warn that [6] looks like it was intended to be JSDoc, and warn that [4] doesn't seem to be attached to anything
  • Widget.height: Normally setters/getters are documented as one API item, so use [7] and report a warning for [9]

Does this make sense? Is there an unambiguous algorithm for selecting the right comment?

IStringBuilder and StringBuilder usage

In JavaScript usually there is no need for a StringBuilder. Are you sure it helps the performance? AFAIK += for strings is fast in every browser, it's only necessary if you implement batch operations, eg. a batchAppend(string[]) method.

Less strict parsing for @param tags

@pgonzal and I were talking in an email thread about parsing params in api-extractor/tsdoc, and suggested I log an issue here to track the param parsing concerns.

Goals for param parsing should be;

  1. Public exported classes/functions have correct jsdoc comments describing the thing.
  2. If param comments are missing, api-extractor catches them and throws an error.
  3. If params are out of order, also worthy of throwing an error.
  4. If the params have types in them, api-extractor ignores them and parses the types from typescript typings if available.
  5. If the params have dashes in them, api-extractor ignores the dashes. If they are missing dashes, api-extractor ignores that. (The purpose is to extract the docs and api surface, not be nit picky about unimportant things, especially when VSCode jsdoc formatting defaults to having types AND no dashes.)

Examples that should work:

  /**
   * @param foo This is fine.
   * @param foo {boolean} This is fine.
   * @param foo - This is fine.
   * @param foo {boolean} - This is fine.
   * @param foo - {boolean} This is fine.
   */

It is nice to stay consistent with param documentation, but the tools should also be resilient in the parsing and let formatting cleanup be the duty of tools like Prettier.

There might be a strict mode which enforces the VSCode default jsdoc comments. but please do not deviate from what most other open source projects snap to (the second example above.)

See Airbnb specs for their guidance as an example. Look at React jsdoc comments. etc

https://github.com/airbnb/javascript#comments

How to deprecate a single parameter

palantir/tslint#4281 is an example of a scenario where a single parameter is deprecated: moving from multiple standalone arguments to a single arguments object, while maintaining backwards compatibility.

Can we mark just that parameter as deprecated? Something like:

export interface IFormatter {
    /**
     * Formats linter results
     * @param failures - Linter failures that were not fixed
     * @param @deprecated fixes - Fixed linter failures. Available when the `--fix` argument is used on the command line. 
     */
    format(failures: RuleFailure[], fixes?: RuleFailure[]): string;
}

Callable variables and class properties

An interesting use-case came up in the TypeDoc repo (TypeStrong/typedoc#858). Would it be reasonable to define the following as a function rather than a variable? JSDoc users can use @function but from discussions in #8 I don't know if that would be a good thing to carryover.

/**
 * Promisified version of fs.writeFile().
 * @function writeFileAsync
 */
export const writeFileAsync: Function = util.promisify(fs.writeFile);

A similar use case is instance methods. I know that tslint has made changes to view these the same as methods for the purpose of grouping properties and methods.

class Foo {
  constuctor(events: EventService) {
    events.on('someevent', this.bar);
  }


  /**
   * This acts like a method and can be passed as a callback without losing context of `this`.
   * @param param - new value of prop
   */
  bar = (param: String) => {
    console.log('Am I a method?');
    this.prop = param;
  }
}

New documentation generator for typescript

Hello! While discussing microsoft/TypeScript#23772 @mhegazy pointed me to your project.

I'm development a new TypeScript documentation generator based on the latest TypeScript and ReactJS + a central documentation portal like docs.rs. There is a lot of work should be done still, but you can take a look how it works at http://tsdoc.io/typescript/2.8.3 (yes, I accidently picked the same domain as your project name :-))

I'm not sure that we're doing the same thing here, but I'm ready to collaborate and incorporate your ideas.

[playground] No parsing of TypeScript type information?

I'm experimenting with the TSDoc Playground and I can't seem to make it parse TypeScript type information. Here's a sample:

/**
 * Returns the average of two numbers.
 *
 * @remarks
 * This method is part of the {@link core-library#Statistics | Statistics subsystem}.
 *
 * @param x - The first input number
 * @param y - The second input number
 * @returns The arithmetic mean of `x` and `y`
 *
 * @beta
 */
function getAverage(x: number, y: number) {
    return (x + y) / 2.0;
}

As you can see, the ParamBlocks in the AST don't include any type annotations for x and y.

  - ParamBlock
    - BlockTag
      * BlockTag="@param"
    * Spacing=" "
    * ParamBlock_ParameterName="x"
    * Spacing=" "
    * ParamBlock_Hyphen="-"
    * Spacing=" "
    - Section
      - Paragraph
        - PlainText
          * PlainText="The first input number"
        - SoftBreak
          * SoftBreak="\n"
  - ParamBlock
    - BlockTag
      * BlockTag="@param"
    * Spacing=" "
    * ParamBlock_ParameterName="y"
    * Spacing=" "
    * ParamBlock_Hyphen="-"
    * Spacing=" "
    - Section
      - Paragraph
        - PlainText
          * PlainText="The second input number"
        - SoftBreak
          * SoftBreak="\n"

Thoughts?

Handling/documenting merged declarations

Pete and I were discussing ways that TSDoc can handle merged declarations, and wanted to summarize a couple ideas here.

Say you have a scenario where you want to export the same API with a different name. You could have something like

export { X as Y } from '...'

where Y is an enum. For certain reasons, we are considering splitting it up into something like the following instead:

export enum Y {
...
}

export type X = Y;
export const X = Y;

We likely still want both X's to be documented together. We have two tags in mind to solve this: @documentAs and @partOf.

@documentAs would be used to tell the documentation system how to present this API, for example grouping it under the "Enums" section even though it isn't technically an enum.

@partOf would be used to group the second definition with the first.

Using the example above, we might have something like the following:

/**
 * Another name for {@link Y}.
 * {@documentAs enum}
 */
export type X = Y;

/**
 * {@partOf (X:type)}
 */
export const X = Y;

I'm curious to see if anyone else has thought about this much and/or has any other ideas or suggestions.

RFC: Normalized form for standard TSDoc tags

Consider this example:

/**
 * Adds two numbers together.
 *
 * @remarks
 * This method is part of the {@link core-libary/Math | Math subsystem}.
 *
 * @param x - The first number to add
 * @param y - The second number to add
 * @returns The sum of `x` and `y`
 *
 * @beta
 */
function add(x: number, y: number): number;

Is the ordering of tags important? Would this be legal:

/**
 * @beta
 * @returns The sum of `x` and `y`
 * @param y - The second number to add
 * @param x - The first number to add
 * Adds two numbers together.
 *
 * @remarks
 * This method is part of the {@link core-libary/Math | Math subsystem}.
 */
function add(x: number, y: number): number;

What about this?

/**
 * @beta @returns The sum of `x` and `y`
 * @param y - The second number to add @param x - The first number to add
 * Adds two numbers together. @remarks This method is part of 
 * the {@link core-libary/Math | Math subsystem}.
 */
function add(x: number, y: number): number;

Some questions:

  1. If it's not legal, what's the best way to specify which orders are allowable?
  2. What should the parser do with ambiguous orderings?
  3. Should the TSDoc library include an operation for normalizing an AST?

RFC: @defaultValue to indicate a default value

In API Extractor issue #720 @RueDeRennes asked about supporting @default to indicate a default value.

Some questions:

  • Should this be part of core TSDoc?
  • Should the tag be @default or @defaultValue?
  • Should it apply only to properties and fields? What about function parameters?

tsickle's JSDoc parser / Closure Compiler syntax

[feel free to just close this if not relevant, but I noticed other bugs similar to this]

tsickle is our glue from TypeScript syntax into Closure Compiler syntax. Closure uses JSDoc annotations heavily with its own interpretations and parser, and tsickle understands a subset of that syntax so we can write TypeScript code and pass modified JSDoc comments through to Closure Compiler. (This also relates to issue #23 a bit.)

I don't know if any of this is relevant to your project, but if you're looking to answer any questions about which tags are allowed by Closure Compiler, or our what best guesses at how to parse patterns found in actual source text, you might find https://github.com/angular/tsickle/blob/master/src/jsdoc.ts interesting.

Also, I'd be happy to answer any questions you have in this area. We (tsickle) would be happy to outsource our JSDoc parsing to a standard library like this as long as it parsed all the syntaxes we care about.

With only a few minutes of thought I think the main points worth mentioning are:

  1. Closure Compiler uses curly braces in some places to mark parameterized tags, such as
/**
 * @suppress {checkFoo,checkBar} plain text goes here
 */

Where we want to be able to get at the list of ['checkFoo', 'checkBar'] programmatically.

  1. Closure Compiler has special handling of @license, in that
/**
 * @license text that spans
 * multiple lines
 */

parses as a multi-line @license tag.

[playground] Documenting object/class methods

I'm experimenting with the TSDoc Playground and I can't seem to make it parse comments for methods defined within a class or object. Here's a sample:

/**
 * Some sample class
 */
export class MyClass {
    /**
     * Returns the average of two numbers.
     */
    getAverage(x, y) {
        return (x + y) / 2.0;
    }
}

The method documentation isn't part of the generated AST. Here is the AST output:

- Comment
  - Section
    - Paragraph
      - PlainText
        * PlainText="Some sample class"
      - SoftBreak
        * SoftBreak="\n"

DocCodeFence is a technically incorrect name

I realize that CommonMark uses "code fence" to mean the delimiter ``` only. They refer to the entire block of code (including delimiters) as a "fenced code block". There's also an "indented code block" (which TSDoc doesn't support due to our whitespace policy.)

Perhaps DocFencedCode is a better name than DocCodeFence.

Current state of the project?

Hello everyone!
Super excited about this project. I'd love to get involved in any way I can.

I tried to install & run tsdoc locally, and ran into issues. So, I wanted to know - is there a roadmap available with planned features / support + implemented features / support? I'm asking both so I can debug the issue I ran into, and so I can reference it when looking for ways to contribute =)

Thanks for the hard work everyone!

Using TSDoc in JS files?

Sorry if this question was raised earlier in other issues, but I haven't found definitive answer.

Question is: are there any plans to support comments in TSDoc format inside JS files?

It is clearly mentioned that TSDoc comments will have benefits for TS files, but there were no clear message that they cannot be used in JS files. However there are no type info in examples of TSDoc comments (since they should be already defined in function signature) which makes it not clear if it can be supported.

It would be great to have same doc generator that will be able to process both JS and TS files as well as unify format of comments which will be used across project.

Another point pain point that can be addressed by upcoming standard for JS files - standardized way to write docs for function overloads. I've tried couple of examples, but non of them provided any meaningful info in VS Code or WebStorm editors.
Even if project can't migrate to TS at some point, but TS LanguageService will handle comments with overrides - devs will benefit from it.

Eliminate API reliance on Object.toString()

Overloading Object.toString() seemed like a sensible way to provide functions for rendering various objects as strings. However, in practice this is confusing because every object has this method, so you never know whether it will actually work or not.

If we used some other method name (e.g. toText()) then IntelliSense would tell you whether there is a converter or not.

See microsoft/rushstack#901 for an example

Coexistence with the compiler's JSDoc-in-JavaScript feature

I'm moving @seanpoulter 's question into its own issue:

What's the long term plan for TSDoc? Will we be able to use it to annotate vanilla JavaScript like the current JSDoc support? In those cases the it's crucial to be able to declare an interface in the comments or document @param properties.

Some background: The TypeScript compiler allows plain *.js files to be compiled alongside with *.ts files, and it will parse certain JSDoc type annotations and incorporate them into the type system.

Some design questions:

  • Beyond the TSDoc design goal of maintaining the look+feel of JSDoc (and CommonMark), does JSDoc-in-JavaScript imply any special considerations for TSDoc syntax?

  • Would TSDoc and JSDoc-in-JavaScript really need to be parsed by the same documentation pipeline?
    (Or are will the *.js files generally be legacy libraries or third-party dependencies?)

RFC: @version tag

Customer often need to know the versions of particular classes, methods, and properties so they can target specific releases. While this information can be passed through the description, it would be beneficial for downstream tooling to avoid parsing extra text.

My request would be to let this field be an arbitrary string. So @version 1.1 and @version Excel API 1.4 both work.

TypeDoc comment parsing

As a reference for a possible TSDoc spec, here is how TypeDoc currently parses comments. The short version is that the text content of comments is as markdown. When a tag is encountered, the following text is still parsed as markdown, but tied to the tag name. Inline links are allowed in the body and in tag text.

TypeDoc starts by using TypeScript's getJSDocCommentRanges() method to get the comment string. It parses the comment line by line. If the line starts with an @ symbol, the line is read as a tag. The word following the @ symbol is considered the tag name. @return tags are normalized to @returns. The word following an @param or @typeparam tag is considered the param name and the rest of the line is left as the line content. A hyphen delimiter after the param name is optional. All other tags are stored with the contents of the rest of the line and any following lines until another tag is found. I would recommend changing this parsing to have special handing for tags without any text on the same line as it is often unexpected that text is parsed as part of the previous tag (see the single-line-tags plugin). If there is a three backtick code fence it will not parse for tags until another code fence is found. For this source code, see typedoc/src/lib/converter/factories/comment.ts.

TypeDoc will allow anything to be used as a tag name. There are some special cases though. An @private, @protected, or @public tag will modify a reflection, overriding the modifier on the TypeDoc reflection. An @event tag will change the reflection to an Event kind. The @hidden tag will hide the reflection. We are considering adding @ignore as an alias of @hidden (see TypeStrong/typedoc#198). There is also an @category (see TypeStrong/typedoc#564) though its use is limited.

Within comment text (either the main comment body or in the text of a tag), links are converted into links. The two types of link syntax that TypeDoc supports are [[ReflectionName]] and {@link ReflectionName}. Inline links can alternatively use the @linkcode or @linkplane tag names to indicate whether or not a link should be displayed in monospace. Reflection names are looked up in the project Links can be split by a | or space character to specify a target and a custom caption.

Parsing aspects still to specifiy

  • How are the targets of inline links looked up
  • defining property descriptions in config objects (i.e. @param config.aProp config property description)

build Error

npm run build output error message:

> [email protected] build /Users/xiangwenwen/github/tsdoc/api-demo
> rimraf ./lib/ && echo -- TYPESCRIPT -- && tsc && echo -- TSLINT -- && tslint --config tslint.json --project . --rules-dir node_modules/tslint-microsoft-contrib

-- TYPESCRIPT --
src/Formatter.ts:1:25 - error TS2307: Cannot find module '@microsoft/tsdoc'.

1 import { DocNode } from '@microsoft/tsdoc';
                          ~~~~~~~~~~~~~~~~~~

src/start.ts:5:56 - error TS2307: Cannot find module '@microsoft/tsdoc'.

5 import { TSDocParser, ParserContext, DocComment } from '@microsoft/tsdoc';
                                                         ~~~~~~~~~~~~~~~~~~

src/start.ts:25:52 - error TS7006: Parameter 'x' implicitly has an 'any' type.

25 console.log(JSON.stringify(parserContext.lines.map(x => x.toString()), undefined, '  '));
                                                      ~

src/start.ts:32:56 - error TS7006: Parameter 'x' implicitly has an 'any' type.

32   for (const message of parserContext.log.messages.map(x => x.toString())) {
                                                          ~

src/start.ts:60:41 - error TS7006: Parameter 'x' implicitly has an 'any' type.

60   + docComment.modifierTagSet.nodes.map(x => x.tagName).join(', '));

npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! [email protected] build: `rimraf ./lib/ && echo -- TYPESCRIPT -- && tsc && echo -- TSLINT -- && tslint --config tslint.json --project . --rules-dir node_modules/tslint-microsoft-contrib`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the [email protected] build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/xiangwenwen/.npm/_logs/2018-08-20T08_36_19_243Z-debug.log

Injecting external content into a doc comment ("@include" tag?)

In RFC: Core set of tags for TSDoc, @EisenbergEffect brought up the topic of a TSDoc tag that would inject content from an external source. I've already seen a couple of examples of this internally. Sometimes the Markdown engine itself is used for this purpose.

Is there a way that this could be done generically using a TSDoc core tag (e.g. @include)? Or will this always be proprietary to the particular documentation pipeline, in which case we should treat it as a custom tag?

@dend

Repo is unlicensed

Pretty much what the title says; the repo has no LICENSE or COPYING file and the README doesn't say anything about it either, from a quick skim.

Consider a more human readable style like markdown or rst rather than just repeating JavaDoc

export class Statistics {
  /**
  Returns the average of two numbers.

  Remarks
  ------- 
  This method is part of the {@link core-library#Statistics | Statistics subsystem}.
   
  Parameters
  ---------- 
  x - The first input number
  y - The second input number
   
  Returns
  ----------- 
  The arithmetic mean of `x` and `y`
  
   */
  public static getAverage(x: number, y: number): number {
    return (x + y) / 2.0;
  }
}

An implementation of this would be numpydoc.

Nevermind.

RFC: Support for custom TSDoc tags

In RFC: Core set of tags for TSDoc, @karol-majewski brought up the topic of custom tags. Extensiblity is a primary goal of TSDoc. The challenge is that JSDoc's tags have inconsistent tag-specific syntaxes, whereas a custom tag needs to be safely skippable by parsers that are unaware of the tag.

Kinds of tags

Here's some proposed core tags that we already discussed supporting, grouped by their type of syntax:

Standalone tags

These act as simple on/off switches. In terms of parser ambiguity, it doesn't matter too much where they appear inside the doc comment:

  • @readonly
  • @public
  • @internal
  • @alpha
  • @beta
  • @ignore

Section-starter tags

These probably will act as delimiters that start blocks of rich text content (which possibly may include inline tags). Probably they should appear at the start of their line. Their captured content will probably terminate with the first TSDoc tag that is not an inline tag:

  • @remarks
  • @returns
  • @deprecated

Tags with unusual syntax

These are like section starter tags, but with special meaning for the "-" delimiter:

  • @param variable.member - description
  • @template TThing - description

These act like bullet items, so they must appear at the start of the line and must appear as a group. Otherwise they are like section-starter tags:

  • @see {@link <https://domain.com>} and other resources

Inline tags

These use curly braces to delimit their content. Within the curly braces, highly specialized parsing rules apply:

  • {@inheritdoc @scope/my-package/components:Foo.member}
  • {@link @scope/my-package/components:Foo.member | the thing}

{@link http://blarg | the thing}

Custom tag syntaxes

Custom inline tags should be fairly easy to support. Some interesting design questions:

  • Should we assume that unrecognized tags are standalone tags by default?

  • If we want to support custom section-starter tags, what would the notation look like?

  • For an unrecognized tag, should its content be included in the API documentation? Or should it be omitted? Is the answer different for different custom tag kinds?

Ways for pure JavaScript consumers to obtain type information from TypeScript libraries

@liamross brought up an interesting scenario in #115:

However, the fact that my documentation will have zero indication of the type of a parameter means that this could never serve as a replacement for JSDoc for me personally. If I write a library in TypeScript and it is consumed by a JavaScript application, I would like for there to be typings in the documentation, and not require that people are relying on IDE tooling or digging into the package to find types.

The first thing that drew me to this was the idea of it parsing types from the code to save the redundant declarations in the documentation.

If you build a library in TypeScript, the output includes declaration files (*.d.ts) that provide very accurate type information. (Arguably the best in the world! :-) ) However many JavaScript tools perform static type analysis based on .js files, and ignore the .d.ts files.

These tools generally expect to obtain their type information from JSDoc tags such as this sample that I pulled from a random blog post:

    /** @namespace */
    var util = {
        /**
         * Repeat <tt>str</tt> several times.
         * @param {string} str The string to repeat.
         * @param {number} [times=1] How many times to repeat the string.
         * @returns {string}
         */
        repeat: function(str, times) {
            if (times === undefined || times < 1) {
                times = 1;
            }
            return new Array(times+1).join(str);
        }
    };

The TypeScript equivalent would look like this:

/** @namespace */
export namespace util {
  /**
   * Repeat <tt>str</tt> several times.
   * @param {string} str - The string to repeat.
   * @param {number} [times=1] - How many times to repeat the string.
   * @returns {string}
   */
  export function repeat(str: string, times: number = 1): string {
    if (times === undefined || times < 1) {
      times = 1;
    }
    return new Array(times + 1).join(str);
  }
}

The JSDoc annotations such as @namespace, {string}, [times=1] are redundant because we already expressed all those things using type declarations. It would be annoying for developers to have to declare everything twice. And it would be error-prone because TypeScript developers generally don't rely on the JSDoc tags themselves, so they won't notice mistakes. (In my own anecdotal experience migrating code bases, I've found that these redundant tags are very frequently incorrect or inconsistent with the TypeScript types.)

The compiler does support JSDoc type annotations, so one possible idea would be for people to use JSDoc annotations instead of type declarations for the public parts of their API, since these annotations do end up in the emitted .js files. However this would be limiting, since JSDoc's type expressions are quite limited compared to all the things you can express in TypeScript. And it would be an awkward developer experience.

The "ideal" solution would be to improve the JavaScript tools to support .d.ts files when they consume a TypeScript library. But let's assume that's impractical for various reasons. What other approaches could we use, and can TSDoc help somehow?

Parameter names using Finnish notation (trailing $) are not supported

The following function declaration:

/**
 * Doc of my exported function
 *
 * @param aParam - first parameter
 * @param aObs$ - second parameter
 * @returns the return value
 */
export function myFunction(aParam: string, aObs$: Observable<string>): string {
  return '';
}

causes the "aObs$" parameter to not be recognized. On https://microsoft.github.io/tsdoc/# the second parameter is not documented, but will be documented when I leave out the trailing $.

Trailing $ names are common in Finnish notation to document observables.

This is related to microsoft/rushstack#1055

RFC: Core set of tags for TSDoc

TSDoc should define a core set of tags for very common scenarios, so their semantics can be standardized across all tools.

Ignoring the syntax details for a moment, which tags should be included in this list?

Here's some suggestions from AEDoc:

  • @param
  • @returns
  • {@link}
  • {@inheritdoc}
  • @remarks

Any others?

Is tsdoc going to support generating React component API?

Say there is a file like this

interface IProps {
   /**
    * Some description
    */
    name: string;
}
class Something extends React.Component<IProps, {}> {
    // code
}

Is tsdoc going to support generating React component API doc (eg, a markdown table)?

RFC: Support for dot syntax on @param

I'm currently working with d.ts files where methods taking object parameters are documented with the following approach:

/**
* Method description.
* @param options addItemOptions - e.g. { id: 1234, title: "someTitle" }
*             id: The unique identifier.
*             title: The title to assign.
**/

It's challenging to parse and auto-generate documentation for these parameters given this approach. Ideally there'd be support for dot syntax e.g.:

@param options.id - The unique identifier.
@param options.title - The title to assign.

RFC: Support for @typeparam or @template for documenting generic parameters

In #8 (comment) @aciccarello wrote:

For a generic type definition, it can be helpful to document what the generic type is used for. Using @template was mentioned in some previous comments but I wonder if @typeparam would be better. Either way, I think this would be a good candidate for inclusion of the standard tags.

VS Code already has some support for @template and there has been a request for TypeDoc to support that as well (TypeStrong/typedoc#860). TypeDoc currently supports @typeparam T - Description and @param <T> - Description.

/**
 * Alias for array
 * 
 * @typeparam T - Type of objects the list contains
 */
type List<T> = Array<T>;

/**
 * Wrapper for an HTTP Response
 * @typeparam B - Response body
 * @param <H> - Headers
 */
interface HttpResponse<B, H> {
    body: B;
    headers: H;
    statusCode: number;
}

Handling multiple comments per symbol

TypeScript allows multiple comments to be attached to a symbol. Consider:

/** Comment one **/
enum A { a }
/** Comment two **/
enum A { b = 1 }

This presents a problem for documentation generators parsing the comments as they must either pick one of the comments, or take both comments and combine them. I believe tsdoc should either provide a function to merge comments, or should provide guidance on how to choose the comment to keep.

For reference, TypeDoc supports an @preferred tag which tells the generator which comment to use. If no @preferred tag is present, it will take the longest comment. VSCode (ts language service?) appears to simply concatenate any comment summaries and lists any @remarks blocks separately.

Related to the above, it might be worth standardizing what should happen if multiple comments are attached to a node, for example:

/** Comment one **/
/** Comment two **/
enum A { a }

In TypeDoc, only comment two would be used to document A. However, in VSCode, I again see that the summaries have been joined.

I understand this isn't directly related to the parsing of an actual comment, which is tsdoc's focus. However, it is a closely related issue which would benefit from a standard.

RFC: Detecting whether a dependency implements TSDoc

Consider this example from API Extractor:

/** @beta */
export interface IPrepareOptions {
  target: string;
}

/** @public */
export interface IWidget {
  /** Renders the widget */
  render(): void;
}

/** @public */
export class Widget implements IWidget {
  /** {@inheritdoc IWidget.render} */  // <-- inherited doc comment
  render(): void;

  prepare(options: IPrepareOptions): void;  // <-- inconsistent visibility error
}

This illustrates a couple kinds of cross references:

  1. Documentation inheritance: The Widget.render docs are copied from IWidget.render using the {@inheritdoc} tag. This avoids having to write duplicate documentation.
  2. Visibility checking: API Extractor allows API items to be marked with a "release tag" such as @beta. For a public release, only the @public definitions will be included in the generated *.d.ts rollup file; the other definitions are trimmed out. In the above example, the analyzer must report an error because if IPrepareOptions gets trimmed, then Widget.prepare won't be able to consumer that interface.

Now, suppose that IWidget and IPrepareOptions are imported from a separate NPM package called widget-lib. This is no problem -- API Extractor can simply parse the TSDoc comments from this file:

./node_modules/widget-lib/lib/index.d.ts

This seems fine on the surface, but the node_modules folder is full of *.d.ts files that have no awareness of API Extractor. Their doc comments might randomly contain a string such as @beta, or they might simply have malformed comments that would normally be reported as a TSDoc error.

We need a way to determine whether a given NPM package actually implements TSDoc or not.

Our proposal is to add a custom field tsdoc to the package.json file format like this:

{
  "name": "widget-lib",
  "version": "1.0.0",
  "main": "lib/index.d.ts",
  "typings": "lib/index.js",
  "tsdoc": {
    "tsdocFlavor": "AEDoc"
  }
}

(Note that the CommonJS spec specifically allows for custom fields.)

Initially, the tsdoc block would support a single field tsdocFlavor that helps tooling to recognize custom extensions to the core TSDoc tags. In the future it might include other fields such as a version number. See this file for a real world prototype of this convention.

Does this seem like a good design?

RFC: Syntax for "declaration references" (hyperlinks)

Certain tags such as {@inheritdoc} contain references to other API items. AEDoc supports two notations for API item references:

  • For internal references, we use: exportName.memberName

    Example: {@inheritdoc BaseWidget.draw}

    The ".memberName" is optional and included e.g. if the API item is a member of a class or interface.

  • For external references, we use: @scopeName/packageName:exportName.memberName

    Example: {@inheritdoc @microsoft/widget-lib:BaseWidget.draw}

    The "@scopeName/" and ".memberName" are optional. The "@scopeName/" is used for scoped NPM packages.

This might be a reasonable starting point. However, it doesn't consider nesting members such as namespaces (which has turned out to be surprisingly common for legacy SDKs, despite all the downsides and attempts to deprecate them).

Also, AEDoc today overlooks an interesting edge case:

export class A {
    public b: string = 'hello';
}

export namespace A {
    export let b: number = 123;
}

let a = new A();

// a.b is a string
// A.b is a number

In this example, an expression such as {@link A.b} would be ambiguous. Which declaration is it referring to? How to handle this?

Pain around building with different versions of NPM.

I've started to notice that this repo is fairly painful to build if there are inconsistencies between versions of NPM in build environments. For example, the Travis build uses NPM 5.6.0, but my dev box had NPM 6.4.1 and another CI box I'm using has NPM 3.10.8. The issues I've been fighting with are incompatibilities between package-lock files generated by different versions of NPM, and the lack of support for path-based references in package.json files.

Additionally, because this repo now contains three projects, to build everything we have to install some dependencies multiple times.

What are people's thoughts about converting this repo to use a monorepo manager (ideally one that controls the version of the package manager) like Rush? That would eliminate a lot of the inconsistencies between build environments, simplify build, and speed up install times.

Count Us In

Just dropping a quick note here to let the project leads know that the Aurelia team would love to support this effort and help out in any way we can. I've built our doc/site generator on TypeDoc and would love to align with this new effort. I'm working on Aurelia vNext now and I'd love to leverage TSDoc as early as possible in that process as well. Feel free to close this issue once you've let me know how we can get involved :) Thanks!

RFC: Syntax for @example tag

RFC: Core set of tags for TSDoc brought up the question of the @example tag that could be used to identify examples. I'm forking it into a separate issue since @c69 pointed out that the design is unclear.

Can anyone find samples of its usage in existing documentation systems?

Since TSDoc will support Markdown, how would it interact with that? Maybe something like this?

/**
 * Adds two numbers together.
 * @example
 * Here's a simple example:
 * ```
 * // Prints "2":
 * console.log(add(1,1));
 * ```
 * @example
 * Here's an example with negative numbers:
 * ```
 * // Prints "0":
 * console.log(add(1,-1));
 * ```
 */
export function add(x: number, y: number): number {
}

How would an API reference web site leverage these directives?

@aciccarello

RFC: IntelliSense completion for custom TSDoc tags

@evanargelion has been asking about defining custom TSDoc tags for toolchain directives. A build task would use the compiler API to extract the comments, invoke the TSDoc parser, and then use this information to affect the build output. For example:

/**
 * @clientCallable(excludedFromRest = true)
 * @apiSet(version = PolyfillableDownTo1_1, IntroducedInVersion = 1.3)
 */
export class BindingSelectionChangedEventArgs {
  . . .
}

He'd like for IntelliSense to help developers write these tags correctly, but without having to implement a custom VS Code extension.

One idea would be to rely on the compiler type system, e.g. define clientCallable and apiSet as a TypeScript interface (similar to how JavaScript decorators or .NET attributes work). However in TypeScript that would probably require the definitions to be imported into the TypeScript source file. It also means the IntelliSense requires a compiler analysis and source code that compilers (maybe as a separate NPM package that would be a dev dependency?).

Another idea would be to define a simpler data file where these definitions can be found, something like a JSON schema. This has the advantage that TSDoc itself could validate these schemas while remaining decoupled from the TypeScript compiler.

Is this an important developer scenario for anyone else? How would you design it?

(removed)

Consider this scenario:

$ rush install
$ cd ./my-project
$ npm install  # Oops!

After this command, both common/temp and my-project/node_modules will be corrupted. The only reliable solution is two commands:

$ rush unlink
$ rush purge

If rush purge automatically included rush unlink, then the solution would be easier to explain.

API Contract Tags

As I've review the TypeDoc and AEDoc supported tags, there emerged a special type of tag. These modifier tags override the TypeScript definition for external documentation purposes.

@readonly (supported by AEDoc)
@private, @protected, and @public (supported by TypeDoc, AEDoc has a different @public)

Should this pattern be expanded or discouraged? In what cases does it make sense to have documentation deviate from implementation?

RFC: Marking events using @eventClass and/or @eventProperty

We have two different API Extractor consumers who define class "events". In C# this is formalized via an event keyword. Although the TypeScript language doesn't model events, it's fairly easy to simulate.

You define an "event class" (e.g. SPEvent) that allows adding/removing handlers:

class FrameworkEvent<TEventArgs extends FrameworkEventArgs> {
  public add(eventHandler: (eventArgs: TEventArgs) => void): void {
     // ...
  }
  public remove(eventHandler: (eventArgs: TEventArgs) => void): void {
     // ...
  }
}

And then you expose readonly-properties (e.g. ApplicationAccessor.navigatedEvent) returning this object:

class MyClass {
  public readonly navigatedEvent: FrameworkEvent<NavigatedEventArgs>;
}

And then users can attach an event handler like this:

const myClass = new MyClass();
myClass.navigatedEvent.add((eventArgs: NavigatedEventArgs) => {
  console.log('Navigated to:' + eventArgs.destinationUrl);
});

The feature request is for the documentation tool to group members like navigatedEvent under an "Events" heading, instead of the usual "Properties" headings.

Proposed Solutions

We're proposing three approaches to support this:

1. Mark up the class: Define a TSDoc tag @eventClass for the class:

/**
 * This is the class used to represent API events.
 * @eventClass
 */
class FrameworkEvent<TEventArgs extends FrameworkEventArgs> {
  public add(eventHandler: (eventArgs: TEventArgs) => void): void {
     // ...
  }
  public remove(eventHandler: (eventArgs: TEventArgs) => void): void {
     // ...
  }
}

Based on this, ideally a tool like API Extractor would recognize any readonly property that returns FrameworkEvent, and automatically classify that as an “event” in the documentation.

2. Mark up each event property: Define a TSDoc tag @eventProperty which needs to be applied to each individual property. This more work for API owners, but it has the benefit of being more obvious to API users who will see these comments in the *.d.ts files. Also it can handle edge cases where something has a signature that looks like an event, but wasn't intended to be. Example:

class MyClass {
  /**
    * This event is fired whenever the application navigates to a new page.
    * @eventProperty 
    */
  public readonly navigatedEvent: FrameworkEvent<NavigatedEventArgs>;
}

3. Both: If we supported both tags, then you would manually mark individual properties as in #2, but a tool like API Extractor can use the information from #1 to find places where @eventProperty is missing or improperly added, and issue appropriate warnings in "strict mode".

NOTE: JSDoc already defines an @event tag with different meaning, so the proposed tags were chosen to avoid conflicts/confusion.

RFC: Two possibilities for integrating Markdown into TSDoc

Problem Statement

There are numerous incompatible Markdown flavors. For this discussion, let's assume "Markdown" means strict CommonMark unless otherwise specified.

Many people expect to use Markdown notations inside their JSDoc. Writing a Markdown parser is already somewhat tricky, since the grammar is highly sensitive to context (compared to other rich-text formats such as HTML). Extending it with JSDoc tags causes some interesting collisions and ambiguities. Some motivating examples:

1. Code fences that span tags

/**
 * I can use backticks to create a `code fence` that gets highlighted in a typewriter font.
 * 
 * This `@tag` is not a TSDoc tag, since it's inside a code fence.
 * 
 * This {@link MyClass | hyperlink to the `MyClass` base class} should get highlighting
 * in its target text.
 * 
 * This {@link MyClass | example of backtick (`)} has an unbalanced backtick (`)
 * inside a tag.
 */

Intuitively we'd expect it to be rendered like this:


I can use backticks to create a code fence that gets highlighted in a typewriter font.

This @tag is not a TSDoc tag, since it's inside a code fence.

This hyperlink to the MyClass base class should get highlighting in its target text.

This example of backtick (`) has an unbalanced backtick (`) inside a tag.


2. Stars

Stars have the same problems as backticks, but with even more special cases:

/**
 * Markdown would treat these as
 * * bullet
 * * items.
 *
 * Inside code comments, the left margin is sometimes ambiguous:
 ** bullet
 ** items?
 *
 * Markdown confusingly *allows a * inside an emphasis*.
 * Does a *{@link MyClass | * tag}* participate in this?
 */

Intuitively we'd expect it to be rendered like this:


Markdown would treat these as

  • bullet
  • items.

Inside code comments, the left margin is sometimes ambiguous:

  • bullet
  • items?

Markdown confusingly allows a * inside an emphasis.
Does a * tag participate in this?


3. Whitespace

Markdown assigns special meanings to whitespace indentation. For example, indenting 4 spaces is equivalent to a ``` block. Newlines also have lots of have special meanings.

This could be fairly confusing inside a code comment, particularly with weird cases like this:

/**     Is this indented? */

/** some junk
    Is this indented? */

/**
Is this okay at all? */

/**
Is this star part of the comment?
 * mystery
Or is it a Markdown bullet? 
 */

Perhaps TSDoc should issue warnings about malformed comment framing.

Perhaps we should try to disable some of Markdown's indentation rules. For example, the TSDoc parser could trim whitespace from the start of each line.

4. Markdown Links

Markdown supports these constructs:

[Regular Link](http://example.com)

[Cross-reference Link][1]
. . .
[1]: http://b.org

![Image Link](http://example.com/a.png)

Autolinks are handy:  http://example.com
However if you want an accurate URL-detector, it turns out to be a fairly big library dependency.

The Markdown link functionality partially overlaps with JSDoc's {@link} tag. But it's missing support for API item references.

5. Markdown Tables

Markdown tables have a ton of limitations. Many constructs aren't supported inside table cells. You can't even put a newline inside a table cell. CommonMark had a long discussion about this, but so far does not support the pipes-and-dashes table syntax at all. Instead it uses HTML tables. This seems pretty wise.

6. HTML elements

Most Markdown flavors allow HTML mixed into your content. The CommonMark spec has an entire section about this. This is convenient, although HTML is an entire separate grammar with its own complexities. For example, HTML has a completely distinct escaping mechanism from Markdown.

Here's a few interesting cases to show some interactions:

/**
 * Here's a <!-- @remarks --> tag inside an HTML comment.
 *
 * Here's a TSDoc tag that {@link MyClass | <!-- } seemingly starts --> an HTML comment.
 *
 * The `@remarks` tag normally separates two major TSDoc blocks.  Is it okay for that
 * to appear inside a table?
 *
 * <table><tr><td>
 * @remarks
 * </td></tr></table>
 */

Two Possible Solutions

Option 1: Extend an existing CommonMark library

The most natural approach would be for the TSDoc parser to include an integrated CommonMark parser. The two grammars would be mixed together. We definitely don't want to write a CommonMark parser from scratch, so instead the TSDoc library would need to extend an existing library. Markdown-it and Flavormark are possible choices that are both oriented towards custom extensions.

Possible downsides:

  • Incorporating full Markdown into the TSDoc AST nodes implies that our doc comment emitter would need to be a full Markdown emitter. (In my experience, correctly emitting Markdown is every bit as tricky as parsing Markdown.)
  • To support an entrenched backend with its own opinionated Markdown flavor, this approach wouldn't passthrough Markdown content from doc comments; instead the backend would have to parse AST nodes that were emitted back to Markdown. This can be good (if you're rigorous and writing a proper translator) or bad (if you're taking the naive route)
  • This approach couples our API contract (e.g. the AST structure) to an external project
  • Possibly increases friction for tools that are contemplating taking a dependency on @microsoft/tsdoc

Option 2: Treat full Markdown as a postprocess

A possible shortcut would be to say that TSDoc operates as a first pass that snips out the structures we care about, and returns everything else as plain text. We don't want to get tripped up by backticks, so we make a small list of core constructs that can easily screw up parsing:

  • code fences (backticks)
  • links
  • CommonMark escapes
  • HTML elements (but only as tokens, ignoring nesting)
  • HTML comments (?)

Anything else is treated as plain text for TSDoc, and gets passed through (to be possibly reinterpreted by another layer of the documentation pipeline).

/**
 * This is *bold*. Here's a {@link MyClass | link to `MyClass`}. <div>
 * @remarks
 * Here's some more stuff. </bad>
 */

Here's some pseudocode for a corresponding AST:

[
  {
    "nodeKind": "textNode",
    "content": "This is *bold*. Here's a "  // <-- we ignore the Markdown stars
  },
  {
    "nodeKind": "linkNode",
    "apiItemReference": {
      "itemPath": "MyClass"
    },
    "linkText": [
      {
        "nodeKind": "textNode",
        "content": "link to "
      },
      {
        "nodeKind": "codeFenceNode",  // <-- we parse the backticks though
        "children": [
          {
            "nodeKind": "textNode",
            "content": "MyClass"
          }
        ]
      },
      {
        "nodeKind": "textNode",
        "content": ". "
      },
      {
        "nodeKind": "htmlElementNode",
        "elementName": "div"
      }
    ]
  },
  {
    "nodeKind": "customTagNode",
    "tag": "@remarks"
  },
  {
    "nodeKind": "textNode",
    "content": "Here's some more stuff."
  },
  {
    "nodeKind": "htmlElementNode",
    "elementName": "bad", // <-- we care about HTML delimiters, but not HTML structure
    "isEndTag": true
  }
]

Possible downsides:

  • The resulting syntax would be fairly counterintuitive for people who assume they're writing real Markdown. All the weird little Markdown edge cases would be handled oddly.
  • This model invites a documentation pipeline to do nontrivial syntactic postprocessing. For content authors, the language wouldn't have a unified specification. (This isn't like a templating library that supports proprietary HTML tags. Instead, it's more like if one tool defined HTML without attributes, and then another tried to retrofit attributes on top of it.)
  • We might end up having to code a small CommonMark parser (although it would be a subset of the work involved for a parser that handles the full grammar)
  • How will the second stage Markdown parser accurately report line numbers for errors?

What do you think? Originally I was leaning towards #1 above, but now I'm wondering if #2 might be a better option.

RFC: "@suppress" tag for suppressing individual diagnostics

It's very useful for an API analysis tool to provide strict error checking and validation of best practices. But we frequently receive feedback that certain checks are too strict. For a particular project, they may be irrelevant or unhelpful. I'd like to provide a way for people to suppress a specific instance of a validation rule.

I'm thinking we will assign a name to each diagnostic message, similar to TSLint rule names. For example, a TSDoc error would be prefixed with tsdoc- like this:

Code: tsdoc-must-escape-gt
Message:  The ">" character should be escaped using a backslash to avoid confusion with an HTML tag

And for API Extractor (which uses TSDoc to parse the code comments, but then applies its own validation on top of that), the prefix would be ae-:

Code: ae-undocumented-link-target
Message: The {@link} tag references an @internal or @alpha API item, which will not appear in the generated documentation

In the api-extractor.json config file, we'll provide a way to suppress a warning for an entire project:

{
  . . .
  "diagnosticMessages": {
    "ae-undocumented-link-target": "disabled",
    "tsdoc-must-escape-gt": "disabled"
  }
}

But if you only want to suppress it for a particular instance, maybe you can do this by marking up the doc comment, like this:

/**
 * Prints a merger conflict chunk, delimited by 
 * "<<<<<<<", "======", and "<<<<<<<".
 * {@suppress tsdoc-must-escape-gt, tsdoc-must-escape-lt}
 */
export function writeMergeConflictChunk(output: Stream, diff: DiffChunk): void {
}

Does this feature seem useful to you? Would you use it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.