TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

JSDoc unexpected leading whitespace behaviour with `@example` and `<caption>`

Open davwheat opened this issue 4 years ago • 6 comments

Bug Report

🔎 Search Terms

#15749 matches, but was last updated in June 2020 -- was informed to make a new issue

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about JSDoc and leading whitespace

⏯ Playground Link

Playground link with relevant code

💻 Code

// In the code block below, `sum(answer, 5)` is NOT indented, but it should be.
// `sum2(answer, 5)` is indented.


/**
 * Adds two numbers
 * 
 * @param a number one
 * @param b number two
 * @returns sum of number one and number two
 * 
 * @example <caption>Add 1 and 3. If answer is >0, sums result and 5.</caption>
 * ```
 * const answer = sum(1, 3); // returns 4
 * 
 * if (answer > 0) {
 *   sum(answer, 5)
 * }
 * ```
 */
function sum(a: number, b: number): number {
  return a + b
}


/**
 * Adds two numbers
 * 
 * @param a number one
 * @param b number two
 * @returns sum of number one and number two
 * 
 * @example <caption>Add 1 and 3. If answer is >0, sums result and 5.</caption>
 * ```
 *          const answer = sum2(1, 3); // returns 4
 * 
 *          if (answer > 0) {
 *            sum2(answer, 5)
 *          }
 * ```
 */
function sum2(a: number, b: number): number {
  return a + b
}

🙁 Actual behavior

The JSDoc produced for sum() has the example without any indentation, despite there being preceding whitespace.

This only happens when there is a <caption> tag present.

image

🙂 Expected behavior

The result should have the same indentation as present in the comment, preferably determined from the indentation of the code block backticks.

image

davwheat avatar May 04 '21 22:05 davwheat

I came across this working on a custom elements library. I'd like to be able to document examples for custom element classes, but without indentation it's not as helpful as it could be.

https://astexplorer.net/#/gist/5f17f411fcd556f8292a46b66ec952be/latest

for example, after I convert the typescript source to a custom-elements.json, then load that manifest into a page, I get this:

Screen Shot displays an HTML snippet without any indentation

Where the source (abbreviated) is

/**
 * @element polymer-apollo-query
 *
 * `<polymer-apollo-query>` fires Polymer-style prop-changed events
 * when its `data`, `error`, `loading` or `networkStatus`
 * properties change.
 *
 * See [ApolloQueryInterface](/api/core/interfaces/query/) for more information.
 *
 * @example Querying for Data
 * ```html
 * <polymer-apollo-query
 *     data="{{data}}"
 *     variables="[[variables]]"
 *     query="[[UserQuery]]"
 * ></polymer-apollo-query>
 *
 * <paper-icon-item>
 *   <iron-image slot="item-icon">[[data.user.picture]]</iron-image>
 *   [[data.user.name]]
 * </paper-icon-item>
 * ```
 *
 * @fires data-changed
 * @fires error-changed
 * @fires errors-changed
 * @fires loading-changed
 * @fires network-status-changed
 */
export class PolymerApolloQuery<D, V> extends Super {/*...*/}

bennypowers avatar Jul 19 '21 20:07 bennypowers

Eek, this is still an issue. My current workaround for this is:

/**
 * @example
 * <caption>Adding a new child to a discussion list item title</caption>
 *
 * ```
 * extend(DiscussionListItem.prototype, 'view', function (vnode) {
 *   findFirstVdomChild(vnode, '.DiscussionListItem-title', (vnode) => {
 *     // ...
 *   });
 * });
 * ```
 */

Which does render correctly inside the doc pop-ups in VS Code.

image

davwheat avatar Jun 08 '22 14:06 davwheat

The above workaround will only work if you do not have a language specified.

This works, sort of, and it will let you add indentations. But its not preferred as now the entire codeblock starts after one indentation.

 * @description Using blockquote to fix indentation of code examples
 *  @example Correct Usage:
 * > ```ts 
 * > type SourceType = { required: string; optional1: string; optional2: string; omit: string };
 * > // Require and Omit keys from a SourceType:
 * > const requiredAndOptional: PickRequiredOmit<SourceType, 'required', 'omit'> = {
 * >   required: 'This value is required.',
 * >   optional1: 'This value is optional.',
 * >   // omit: 'This value cannot be provided.'
 * > };
 * > 
 * > // Omit specified keys from SourceType while making all others optional. (<R> = undefined).
 * > const omitAndOptional: PickRequiredOmit<SourceType, undefined, 'omit'> = {
 * >   optional1: 'This value is optional.',
 * >   optional2: 'This value is also optional',
 * >   // required: 'This value is technically optional, too.'
 * >   // omit: 'This value cannot be provided.'
 * > }
 * ```
 */

The final closing back ticks need to be on its own line for it to work. image

eqprog avatar Aug 15 '23 18:08 eqprog

Let me know if this is off-topic or should go in another issue, but I experience this without @example:

export class Heap<T> {
  arr: T[];
  compareFn: (first: T, second: T) => number;

  /**
   * @constructor
   * @param arr An array of type T
   * @param compareFn A comparator function. Examples:
   *
   * ```ts
   * // Min Comparator
   * [5, 4, 3, 2, 1].sort((a, b) => {
   *     return a - b;
   * }) === [1, 2, 3, 4, 5]
   *
   * // Max Comparator
   * [1, 2, 3, 4, 5].sort((a, b) => {
   *     return b - a;
   * }) === [5, 4, 3, 2, 1]
   * ```
   */
  constructor(arr: T[], compareFn: (first: T, second: T) => number) {
    this.arr = arr.sort(compareFn);
    this.compareFn = compareFn;
  }
// ...

When I hover over the constructor keyword: image

DanKaplanSES avatar Nov 20 '23 22:11 DanKaplanSES

related:

  • https://github.com/microsoft/TypeScript/issues/56583

trusktr avatar Jan 03 '24 07:01 trusktr