npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@homer0/prettier-plugin-jsdoc

v9.1.0

Published

A Prettier plugin to format JSDoc blocks

Downloads

2,192

Readme

𝍌 JSDoc plugin for Prettier

GitHub Workflow Status (main) Coveralls github Dependencies status

A Prettier plugin to format JSDoc blocks.

🍿 Usage

If you are wondering why I built this, go to the Motivation section.

⚙️ Options

@description tag

Allow the @description tag

| Option | Type | Default | | -------------------------- | ------- | ------- | | jsdocAllowDescriptionTag | boolean | false |

Whether or not the @description tag can be used on JSDoc blocks. When disabled, if a @description tag is found, its contents will be moved to the block body:

// jsdocAllowDescriptionTag: false

/**
 * @typedef {Object} MyType
 * @description Lorem ipsum description.
 */

// ->

/**
 * Lorem ipsum description.
 *
 * @typedef {Object} MyType
 */
Use the @description tag

| Option | Type | Default | | ------------------------ | ------- | ------- | | jsdocUseDescriptionTag | boolean | false |

Whether or not to use the @description tag when a description is found on the block body or following a type/callback definition.

// jsdocUseDescriptionTag: true

/**
 * Lorem ipsum description.
 *
 * @typedef {Object} MyType
 */

// ->

/**
 * @typedef {Object} MyType
 * @description Lorem ipsum description.
 */

@example tag

Format @example tags

| Option | Type | Default | | --------------------- | ------- | ------- | | jsdocFormatExamples | boolean | true |

Whether or not to attempt to format the @example tags using Prettier itself.

// jsdocFormatExamples: true

/**
 * @example
 * ensureArray([
 * 'x', 'y',
 * ])
 */

// ->

/**
 * @example
 *
 *   ensureArray(['x', 'y'])
 */
Add lines around @example tags' content

| Option | Type | Default | | ------------------------------------ | ---- | ------- | | jsdocLinesBetweenExampleTagAndCode | int | 1 |

How many lines should there be between an @example tag and its code.

// jsdocLinesBetweenExampleTagAndCode: 0

/**
 * @example
 * ensureArray([
 * 'x', 'y',
 * ])
 */

// ->

/**
 * @example
 *   ensureArray(['x', 'y'])
 */
Manage indentation on formatted examples

| Option | Type | Default | | ------------------------------ | ------- | ------- | | jsdocIndentFormattedExamples | boolean | true |

Whether or not to add an indentation level to the code snippets of @example tags. The indentation space will be taken from the tabWidth option.

// jsdocIndentFormattedExamples: false

/**
 * @example
 * ensureArray([
 * 'x', 'y',
 * ])
 */

// ->

/**
 * @example
 *
 * ensureArray(['x', 'y'])
 */
Manage indentation for pseudo code examples

| Option | Type | Default | | -------------------------------- | ------- | ------- | | jsdocIndentUnformattedExamples | boolean | false |

Whether or not to add an indentation level to the code snippets of @example tags that couldn't be formatted with Prettier. This is only valid if jsdocFormatExamples is true.

// jsdocIndentUnformattedExamples: true

/**
 * @example
 * instance -> handler -> middlewares
 */

// ->

/**
 * @example
 *
 *   instance -> handler -> middlewares
 */

@access tag

Allow @access tag

| Option | Type | Default | | --------------------- | ------- | ------- | | jsdocAllowAccessTag | boolean | true |

Whether or not the @access tag can be used; if false, when a tag is found, it will replaced with a tag of its value:

// jsdocAllowAccessTag: false

/**
 * @access public
 */

// ->

/**
 * @public
 */
Enfore the use of the @access tag

| Option | Type | Default | | ----------------------- | ------- | ------- | | jsdocEnforceAccessTag | boolean | true |

Whether or not to transform the tags @private, @public and @protected into @access [type] tags:

// jsdocEnforceAccessTag: true

/**
 * @private
 */

// ->

/**
 * @access private
 */

Types with string literals

Format types with string literals

| Option | Type | Default | | --------------------------- | ------- | ------- | | jsdocFormatStringLiterals | boolean | true |

Whether or not to apply transformations to string literal types.

// jsdocFormatStringLiterals: true

/**
 * @type {'a'| "b"  |  'c'} MyType
 */

// ->

/**
 * @type {'a' | 'b' | 'c'} MyType
 */
Specify quotes types for string literals

| Option | Type | Default | | --------------------------------------- | ------- | ------- | | jsdocUseSingleQuotesForStringLiterals | boolean | true |

Whether or not to use single quotes for string literals' types.

// jsdocUseSingleQuotesForStringLiterals: false

/**
 * @type {'a'| "b"  |  'c'} MyType
 */

// ->

/**
 * @type {"a" | "b" | "c"} MyType
 */
Specify space around string literals

| Option | Type | Default | | ---------------------------------- | ---- | ------- | | jsdocSpacesBetweenStringLiterals | int | 1 |

How many spaces should there be between string literals on a type.

// jsdocSpacesBetweenStringLiterals: 0

/**
 * @type {'a'| "b"  |  'c'} MyType
 */

// ->

/**
 * @type {'a'|'b'|'c'} MyType
 */

TypeScript types

Use TypeScript casing for basic types

| Option | Type | Default | | ------------------------------- | ------- | ------- | | jsdocUseTypeScriptTypesCasing | boolean | true |

Whether or not to transform the casing of the basic types to make them compatible with TypeScript. This applies to string, number, boolean, Object and Array.

// jsdocUseTypeScriptTypesCasing: true

/**
 * @typedef {object} Person
 * @property {String}        name    ...
 * @property {Number}        age     ...
 * @property {Boolean}       single  ...
 * @property {array<String>} pets    ...
 */

// ->

/**
 * @typedef {Object} Person
 * @property {string}        name    ...
 * @property {number}        age     ...
 * @property {boolean}       single  ...
 * @property {Array<string>} pets    ...
 */
Format complex types with Prettier as TypeScript

| Option | Type | Default | | ------------------------------------- | ------- | ------- | | jsdocFormatComplexTypesWithPrettier | boolean | true |

Whether or not to format complex type definitions (compatibles with TypeScript) using Prettier.

// jsdocFormatComplexTypesWithPrettier: true

/**
 * @typedef {{ name:string,age:number,pets:Array<string>}} Person
 */

// ->

/**
 * @typedef {{
 *   name: string,
 *   age: number,
 *   pets: string[],
 * }} Person
 */

Arrays and objects

Transform arrays into their shorter form

| Option | Type | Default | | --------------------- | ------- | ------- | | jsdocUseShortArrays | boolean | true |

Whether or not to transform the type Array<type> into type[] when possible. If inside the symbols there's more than a type, the transformation won't happen:

// jsdocUseShortArrays: true

/**
 * @typedef {Array<Array<string>>} ListOfLists
 * @typedef {Array<ListOfLists>} ListOfListsOfLists
 */

// ->

/**
 * @typedef {Array<string[]>} ListOfLists
 * @typedef {ListOfLists[]} ListOfListsOfLists
 */
Modify the dot used for the generics of arrays and objects

| Option | Type | Default | | ----------------------------------- | ------- | ------- | | jsdocFormatDotForArraysAndObjects | boolean | true |

Whether or not to apply transformations regarding the dot Array and Object types can have before their generics (Array.<...):

// jsdocFormatDotForArraysAndObjects: true

/**
 * @typedef {Array<Array<string>>} ListOfLists
 */

// ->

/**
 * @typedef {Array.<string[]>} ListOfLists
 */
Ensure the use or not of the dot for the generics of arrays and objects

| Option | Type | Default | | -------------------------------- | ------- | ------- | | jsdocUseDotForArraysAndObjects | boolean | true |

If the formatting for dots is enabled, this options will specify whether the dot is added or removed.

// jsdocUseDotForArraysAndObjects: false

/**
 * @typedef {Array.<Array.<string>>} ListOfLists
 */

// ->

/**
 * @typedef {Array<string[]>} ListOfLists
 */

Tags

Replace tags synonyms

| Option | Type | Default | | -------------------------- | ------- | ------- | | jsdocReplaceTagsSynonyms | boolean | true |

Whether or not to replace tags synonyms with their official tag.

// jsdocReplaceTagsSynonyms: true

/**
 * @extends Something
 * @arg {string} name  ...
 * @virtual
 * ...
 */

// ->

/**
 * @augments Something
 * @param {string} name  ...
 * @abstract
 * ...
 */
Sort tags

| Option | Type | Default | | --------------- | ------- | ------- | | jsdocSortTags | boolean | true |

Whether or not to sort the tags of a JSDoc block.

// jsdocSortTags: true

/**
 * @param {string} name  ...
 * @throws {Error} if ...
 * @callback CreatePerson
 * @returns {Person}
 */

// ->

/**
 * @callback CreatePerson
 * @param {string} name  ...
 * @returns {Person}
 * @throws {Error} if ...
 */
Tags order

| Option | Type | Default | | ---------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | jsdocTagsOrder | array | typetypedefcallbackfunctionmethodclassfileconstantdescriptionclassdescexampleparampropertyreturnstemplateaugmentsextendsthrowsyieldsfireslistensasyncabstractoverrideprivateprotectedpublicaccessdesprecatedauthorversionsincemembermemberofcategoryexternalseeothertodo |

A list specifing the order in which the the tags of a JSDoc block should be sorted. It supports an other item to place tags that are not on the list.

Rendering

Use columns

| Option | Type | Default | | ----------------- | ------- | ------- | | jsdocUseColumns | boolean | true |

Whether or not to try to use columns for type, name and description when possible; if false, the descriptions will be moved to a new line.

// jsdocUseColumns: true

/**
 * @callback CreatePerson
 * @param {string} name The name of the person.
 * @param {number} age The age of the person.
 * @param {string[]} pets A list of the person's pets.
 * @returns {Person}
 * @throws {Error} if something goes wrong
 * @throws {AnotherTypeOfError} If something else goes wrong.
 */

// ->

/**
 * @callback CreatePerson
 * @param {string}   name  The name of the person.
 * @param {number}   age   The age of the person.
 * @param {string[]} pets  A list of the person's pets.
 * @returns {Person}
 * @throws {Error}              if something goes wrong
 * @throws {AnotherTypeOfError} If something else goes wrong.
 */

The alternative:

// jsdocUseColumns: false

/**
 * @callback CreatePerson
 * @param {string} name The name of the person.
 * @param {number} age The age of the person.
 * @param {string[]} pets A list of the person's pets.
 * @returns {Person}
 * @throws {Error} if something goes wrong
 * @throws {AnotherTypeOfError} If something else goes wrong.
 */

// ->

/**
 * @callback CreatePerson
 * @param {string} name
 * The name of the person.
 * @param {number} age
 * The age of the person.
 * @param {string[]} pets
 * A list of the person's pets.
 * @returns {Person}
 * @throws {Error}
 * if something goes wrong
 * @throws {AnotherTypeOfError}
 * If something else goes wrong.
 */
Group columns

| Option | Type | Default | | ------------------------ | ------- | ------- | | jsdocGroupColumnsByTag | boolean | true |

Whether to respect column alignment within the same tag. For example: all @param tags are agligned with eachother, but not with all the @throws tags.

// jsdocGroupColumnsByTag: false

/**
 * @callback CreatePerson
 * @param {string} name The name of the person.
 * @param {number} age The age of the person.
 * @param {string[]} pets A list of the person's pets.
 * @returns {Person}
 * @throws {Error} if something goes wrong
 * @throws {AnotherTypeOfError} If something else goes wrong.
 */

// ->

/**
 * @callback CreatePerson
 * @param   {string}             name  The name of the person.
 * @param   {number}             age   The age of the person.
 * @param   {string[]}           pets  A list of the person's pets.
 * @returns {Person}
 * @throws  {Error}              if something goes wrong
 * @throws  {AnotherTypeOfError} If something else goes wrong.
 */
Consistent columns

| Option | Type | Default | | ------------------------ | ------- | ------- | | jsdocConsistentColumns | boolean | true |

This is for when the columns are algined by tags; if true and one tag can't use columns, no other tag will use them either.

// jsdocConsistentColumns: true

/**
 * @callback CreatePerson
 * @param {string} name The name of the person.
 * @param {number} extraLongTypeThatWillTakeTheMinSpaceForADescription The age of the person.
 * @param {string[]} pets A list of the person's pets.
 * @returns {Person}
 * @throws {Error} if something goes wrong
 * @throws {AnotherTypeOfError} If something else goes wrong.
 */

// ->

/**
 * @callback CreatePerson
 * @param {string} name
 * The name of the person.
 * @param {number} extraLongTypeThatWillTakeTheMinSpaceForADescription
 * The age of the person.
 * @param {string[]} pets
 * A list of the person's pets.
 * @returns {Person}
 * @throws {Error}              if something goes wrong
 * @throws {AnotherTypeOfError} If something else goes wrong.
 */
Avoid small columns for descriptions

| Option | Type | Default | | --------------------------------- | ---- | ------- | | jsdocDescriptionColumnMinLength | int | 35 |

When using columns, this is the minimum available space the description column must have; if it's less, the description will be moved to a new line and columns will be disabled for the tag, and if consistent columns are enabled, for the entire block.

Tag spacing: Between tag and type

| Option | Type | Default | | --------------------------------- | ---- | ------- | | jsdocMinSpacesBetweenTagAndType | int | 1 |

How many spaces should there be between a tag and a type:

 * @[tag][<--this-->]{[type]} [name] [description]
Tag spacing: Between type and name

| Option | Type | Default | | ---------------------------------- | ---- | ------- | | jsdocMinSpacesBetweenTypeAndName | int | 1 |

How many spaces should there be between a type and a name:

 * @[tag] {[type]}[<--this-->][name] [description]
Tag spacing: Between name and description

| Option | Type | Default | | ----------------------------------------- | ---- | ------- | | jsdocMinSpacesBetweenNameAndDescription | int | 2 |

How many spaces should there be between a name and a description column.

 * @[tag] {[type]} [name][<--this-->][description]
Space between description body and tags

| Option | Type | Default | | ------------------------------------- | ---- | ------- | | jsdocLinesBetweenDescriptionAndTags | int | 1 |

How many lines should there be between a description body and the tags.

// jsdocLinesBetweenDescriptionAndTags: 1

/**
 * My type description.
 * @typedef {Object} MyType
 */

// ->

/**
 * My type description.
 *
 * @typedef {Object} MyType
 */
Make sure descriptions are valid sentences

| Option | Type | Default | | ------------------------------------- | ------- | ------- | | jsdocEnsureDescriptionsAreSentences | boolean | true |

If enabled, it will make sure descriptions start with an upper case letter and end with a period.

// jsdocEnsureDescriptionsAreSentences: true

/**
 * my type description
 *
 * @typedef {Object} MyType
 */

// ->

/**
 * My type description.
 *
 * @typedef {Object} MyType
 */
Allow descriptions to be on different lines

| Option | Type | Default | | ---------------------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | jsdocAllowDescriptionOnNewLinesForTags | array | classdesclicensedescdescriptionfilefileoverviewoverviewsummary |

A list of tags that are allowed to have their description on a new line.

// jsdocUseColumns: true

/**
 * @callback CreatePerson
 * @param {string} name The name of the person.
 * @param {number} age The age of the person.
 * @param {string[]} pets A list of the person's pets.
 * @returns {Person}
 * @license
 * Some license.
 */

// ->

/**
 * @callback CreatePerson
 * @param {string}   name  The name of the person.
 * @param {number}   age   The age of the person.
 * @param {string[]} pets  A list of the person's pets.
 * @returns {Person}
 * @license
 * Some license.
 */
Ignore tags for consistent columns

| Option | Type | Default | | ---------------------------------------------------- | ------- | ------- | | jsdocIgnoreNewLineDescriptionsForConsistentColumns | boolean | true |

If enabled, when evaluating the rule for consistent columns, tags with description on a new line, allowed by jsdocAllowDescriptionOnNewLinesForTags, will be ignored.

Use an inline block for a single tag

| Option | Type | Default | | ----------------------------------------- | ------- | ------- | | jsdocUseInlineCommentForASingleTagBlock | boolean | false |

Whether or not to use a single line JSDoc block when there's only one tag.

// jsdocUseInlineCommentForASingleTagBlock: true

/**
 * @type {string}
 */

// ->

/** @type {string} */
Ignore specific tags

| Option | Type | Default | | ----------------- | ----- | ------- | | jsdocIgnoreTags | array | empty |

A list of tags that should be ignored when formatting JSDoc comments.

Extras

Custom width

| Option | Type | Default | | ----------------- | ---- | ----------------------- | | jsdocPrintWidth | int | 0 (uses printWidth) |

This is an override for the printWidth option, in case the length of the documentation lines needs to be different.

Turn the plugin on and off

| Option | Type | Default | | -------------------- | ------- | ------- | | jsdocPluginEnabled | boolean | true |

Whether or not the plugin will parse and transform JSDoc blocks.

Let the plugin know that it's being extended

| Option | Type | Default | | --------------------- | ------- | ------- | | jsdocPluginExtended | boolean | false |

This will prevent the plugin from running from the original package. The idea is for it to be enabled when the plugin is being extended on the implementation.

⚠️ Experimental

Parse comments without tags

| Option | Type | Default | | -------------------------------------------- | ------- | ------- | | jsdocExperimentalFormatCommentsWithoutTags | boolean | false |

By default, the plugin will only parse comments with tags. Use this option, at your own risk, if you want to format blocks without tags.

Ignore inline blocks for comments without tags

| Option | Type | Default | | ----------------------------------------------------- | ------- | ------- | | jsdocExperimentalIgnoreInlineForCommentsWithoutTags | boolean | false |

Whether or not to ignore the jsdocUseInlineCommentForASingleTagBlock option for comments without tags (when jsdocExperimentalFormatCommentsWithoutTags is enabled).

🚫 Ignoring blocks

If you have some blocks where you don't the plugin to make any modification, you can add the @prettierignore tag and it/they will be skipped:

/**
 * @type {Array<Something>}
 * @prettierignore
 */

⚡️ Modifying the functionality

While the plugin has enough options to cover most of the common cases, if you find that it doesn't handle some edge case and you don't think it would be a good idea to send a PR, you can easily modify the plugin functionality without having to fork/clone the original repository.

The entire plugin is (mostly) built around tiny functions inside a dependency injection container, so you could take the container and replace the function you want to modify.

First, we have to enable the option jsdocPluginExtended, as it will prevent it from running from the original package, and create a JS file to work:

.prettierrc:

{
  "jsdocPluginExtended": true,
  "plugins": ["./my-jsdoc-plugin.js"]
}

Now, on our JS file, we'll add the following snippet:

const { get, override } = require('@homer0/prettier-plugin-jsdoc/src/fns/app');
const { loadFns } = require('@homer0/prettier-plugin-jsdoc/src/loader');
const { getPlugin } = require('@homer0/prettier-plugin-jsdoc/src/fns/getPlugin');

loadFns();

module.exports = get(getPlugin)();

That's all that's needed in order to setup the plugin:

  1. get is the access to the dependency injection container, you pass the reference of an original function and it will return either the function or an override.
  2. loadFns is a utility function that requires all the functions of the plugin and loads them on the dependency injection container.
  3. getPlugin basically connects all the functions and returns the plugin definition.

Now, in order to modify a function we need to import the original and use override before the call to getPlugin.

Let's say you want to add the synonym params to param (if the plugin finds @params it will be converted to @param):

const { get, override } = require('@homer0/prettier-plugin-jsdoc/src/fns/app');
const { loadFns } = require('@homer0/prettier-plugin-jsdoc/src/loader');
const { getPlugin } = require('@homer0/prettier-plugin-jsdoc/src/fns/getPlugin');
// + We add the `require` for the original function.
const { getTagsSynonyms } = require('@homer0/prettier-plugin-jsdoc/src/fns/constants');

loadFns();

// + We create a custom `getTagsSynonyms`.
const customGetTagsSynonyms = () => ({
  ...getTagsSynonyms(),
  params: 'param',
});

// + We override the function on the container.
override(getTagsSynonyms, customGetTagsSynonyms);

module.exports = get(getPlugin)();

That's all, the plugin was successfully extended 🎉!

📖 Troubleshooting

Forcing new lines in paragraphs and lists

When writing multiple paragraphs or markdown lists, you might want to force new lines to be respected, for example:

/**
 * First paragraph
 * Second paragraph
 *
 * @type {Something}
 */

/**
 * A list:
 *
 * - First item
 * - Second item
 *
 * @type {Something}
 */

The problem is that the plugin will end up putting those lines together, as it will assume that they are all part of the same paragraph:

/**
 * First paragraph Second paragraph
 *
 * @type {Something}
 */

/**
 * A list:
 *
 * - First item - Second item
 *
 * @type {Something}
 */

It may look like a bug, but this is actually the functionality that formats the the descriptions in order to respect the printWidth/jsodcPrintWidth option.

The way you can solve this is by adding a period at the end of the line, which will tell the plugin that you ended the sentence and that it should respect the line break

/**
 * First paragraph.
 * Second paragraph.
 *
 * @type {Something}
 */

/**
 * A list:
 *
 * - First item.
 * - Second item.
 *
 * @type {Something}
 */

🤘 Development

Tasks

| Task | Description | | ----------- | ------------------------------ | | test:unit | Runs the unit tests. | | test:e2e | Runs the functional tests. | | test | Runs all tests. | | lint | Lint the modified files. | | lint:all | Lint the entire project code. | | todo | List all the pending to-do's. |

Repository hooks

I use husky to automatically install the repository hooks so...

  1. The code will be formatted and linted before any commit.
  2. The dependencies will be updated after every merge.
  3. The tests will run before pushing.

⚠️ When the linter and formatter runs for staged files, if the file is importing Prettier, it may fail due to Prettier being ESM. This is temporary, and the workaround for now is to run pnpm run lint:all and commit with -n.

Commits convention

I use conventional commits with commitlint in order to support semantic releases. The one that sets it up is actually husky, that installs a script that runs commitlint on the git commit command.

The configuration is on the commitlint property of the package.json.

Releases

I use semantic-release and a GitHub action to automatically release on NPM everything that gets merged to main.

The configuration for semantic-release is on ./releaserc and the workflow for the release is on ./.github/workflow/release.yml.

⚠️ semantic-release requires Node 18 to be installed, so I temporarily removed it form the package.json and it's only installed in the GitHub action, before being used.

Testing

I use Jest to test the project, both with unit tests and functional tests.

The configurations files are .jestrc-e2e and .jestrc-unit, and the test files are located on /tests.

In the case of the functional tests, there's a special environment on ./tests/utils that loads and parses a list of fixture files in order to save them on the global object. In reality, there's only one test file for the functional tests, the one that reads the global object and dynamically generates the it(...): index.e2e.js.

Linting && Formatting

I use ESlint with my own custom configuration to validate all the JS code. The configuration file for the project code is on ./.eslintrc and the one for the tests is on ./tests/.eslintrc. There's also an ./.eslintignore to exclude some files on the process. The script that runs it is on ./utils/scripts/lint-all.

For formatting I use Prettier with my custom configuration and this same plugin. The configuration file for the project code is on ./.prettierrc.

To-Dos

I use @todo comments to write all the pending improvements and fixes, and Leasot to generate a report. The script that runs it is on ./utils/scripts/todo.

🐞 Validating bugs

You can use the functional tests to validate a scenario in which the plugin is not behaving as you would expect.

Create a file issue.fixture.js in ./tests/e2e/fixtures and add the following code:

module.exports = { only: true, jsdocPrintWidth: 70 };

//# input

/**
 * @template{Something} [something]
 */

//# output

/**
 * @template {Something} [something]
 */
  • The module.exports specifiy the plugin options for that specific case.
  • only: true is not a plugin option, but will make the test runner ignore all the other tests, and only run the one you specify.
  • Below //# input you can put any number of comment blocks, in the state you would expect the plugin to pick them.
  • Below //# output you have to put the expected output after formatting the input with the plugin.
  • The "input" and "output" are handled as if they were different files, so you can even put functions and real code, they won't be executed though, just formatted.

Then, you can just run run the test for the fixture with pnpm run test:e2e.

Motivation

Let's start with the fact that I really like the functionality of Prettier, but I really dislike their philosophy. I understand what they are trying to achieve and it makes sense, but "just use it the way I tell you" doesn't seem like a valid solution to me.

Ok, there won't accept options requests? that's perfect, it doesn't make sense to just add "one more"... but it would be great if it could be open to be extended. The only way to do it is with a plugin, which means an extra parsing.

Enough rant; I started using Prettier a couple of weeks ago and being a huge fan of JSDoc, I wanted to use it to format JSDoc blocks too, something I've doing, for sometime now, using a Node script that I was trying to make into a VSCode plugin :P.

I found prettier-plugin-jsdoc by @hosseinmd, but it (currently) doesn't cover most of the cases I wanted (like columns creations), it's written in TypeScript (which I don't like very much) and if I were to fork and send PRs, it could've taken forever (you can see the commits for this package), and it seemed like the perfect oportunity to try Ramda and functional programming... so I started a new one.