# mdast-util-tight-comments

> mdast-util-to-markdown extension to selectively remove newlines around mdast comment nodes

Latest version **3.0.0** (published 2025-09-02) · MIT license · 0 weekly downloads

## Install

```sh
npm install mdast-util-tight-comments
pnpm add mdast-util-tight-comments
yarn add mdast-util-tight-comments
bun add mdast-util-tight-comments
```

## Health

**Score 40/100 (D)** — status: stable.

Positive: esm support; no vulnerabilities.

Warnings: low downloads; no types.

Negative: stale.

## Facts

| | |
|---|---|
| Version | 3.0.0 |
| Published | 2025-09-02 |
| First published | 2022-10-21 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | ESM |
| Node | ^20.18.0 \|\| >=22.12.0 |
| Dependencies | 1 |
| Unpacked size | 19.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 7 |
| Author | Xunnamius |
| Maintainers | xunnamius |
| Keywords | unist, mdast, mdast-util, util, utility, extension, mdast-util-to-markdown, markdown, comment, space, node, newline, remove, selective, syntax, tree, ast |

## Links

- npm: https://www.npmjs.com/package/mdast-util-tight-comments
- Repository: https://github.com/Xunnamius/unified-utils
- Homepage: https://github.com/Xunnamius/unified-utils/tree/main/packages/mdast-util-tight-comments#readme
- Issues: https://github.com/Xunnamius/unified-utils/issues
- npm.io page: https://npm.io/package/mdast-util-tight-comments

## Dependencies (1)

- [mdast-util-to-markdown](https://npm.io/package/mdast-util-to-markdown.md) ^2.1.2

## Alternatives

- [update-check](https://npm.io/package/update-check.md) — 4.0M weekly downloads
- [react-native-onesignal](https://npm.io/package/react-native-onesignal.md) — 134.5K weekly downloads
- [react-redux-toastr](https://npm.io/package/react-redux-toastr.md) — 33.7K weekly downloads
- [@nocobase/plugin-notification-manager](https://npm.io/package/@nocobase/plugin-notification-manager.md) — 2.0K weekly downloads
- [react-simple-toasts](https://npm.io/package/react-simple-toasts.md) — 1.9K weekly downloads

## Recent versions

- 3.0.0 (latest) — 2025-09-02
- 2.0.0 — 2023-11-30
- 1.0.6 — 2023-01-29
- 1.0.5 — 2023-01-04
- 1.0.4 — 2022-12-21
- 1.0.3 — 2022-10-28
- 1.0.2 — 2022-10-22
- 1.0.1 — 2022-10-22
- 1.0.0 — 2022-10-21

## README

<!-- symbiote-template-region-start 1 -->

<p align="center" width="100%">
  <img width="300" src="https://raw.githubusercontent.com/Xunnamius/unified-utils/refs/heads/main/packages/mdast-util-tight-comments/logo.png">
</p>

<p align="center" width="100%">
<!-- symbiote-template-region-end -->
mdast-util-to-markdown extension to selectively remove newlines around mdast comment nodes
<!-- symbiote-template-region-start 2 -->
</p>

<hr />

<div align="center">

[![Black Lives Matter!][x-badge-blm-image]][x-badge-blm-link]
[![Last commit timestamp][x-badge-lastcommit-image]][x-badge-repo-link]
[![Codecov][x-badge-codecov-image]][x-badge-codecov-link]
[![Source license][x-badge-license-image]][x-badge-license-link]
[![Uses Semantic Release!][x-badge-semanticrelease-image]][x-badge-semanticrelease-link]

[![NPM version][x-badge-npm-image]][x-badge-npm-link]
[![Monthly Downloads][x-badge-downloads-image]][x-badge-downloads-link]

</div>

<br />

# mdast-util-tight-comments

<!-- symbiote-template-region-end -->

This is a small [mdast][1] utility that extends [mdast-util-to-markdown][2]
allowing for the selective removal of newlines around certain mdast comment
nodes.

This is a low level project used by [remark-tight-comments][3], which is a
companion package to [remark-ignore][4].

<!-- symbiote-template-region-start 3 -->

---

<!-- remark-ignore-start -->
<!-- symbiote-template-region-end -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Install](#install)
- [Usage](#usage)
- [API](#api)
- [Related](#related)
- [Appendix](#appendix)
  - [Published Package Details](#published-package-details)
  - [License](#license)
- [Contributing and Support](#contributing-and-support)
  - [Contributors](#contributors)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- symbiote-template-region-start 4 -->
<!-- remark-ignore-end -->

<br />

## Install

> Due to the nature of the unified ecosystem, this package is ESM only and
> cannot be `require`'d.

<!-- symbiote-template-region-end -->

To install:

```shell
npm install mdast-util-tight-comments
```

## Usage

Suppose we have the following Markdown file `example.md`:

```markdown
<!-- prettier-ignore-start -->
<!-- remark-ignore-start -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Install remark](#install)
- [Usage](#usage)
- [API](#api)
- [Related](#related)
- [Contributing and Support](#contributing-and-support)
  - [Contributors](#contributors)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- remark-ignore-end -->
<!-- prettier-ignore-end -->

<!-- Begin the documentation section -->

<!-- TODO: add another section here -->

<!-- remark-ignore -->

# Install [remark](https://npm.im/remark)
```

Notice how the `<!-- START doctoc…` and `<!-- DON'T EDIT…` comments are
_tightly_ positioned such that there is no newline between them. This is
required by [doctoc][5].

Now, running the following JavaScript:

```typescript
import fs from 'node:fs';
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import { toMarkdown } from 'mdast-util-to-markdown';

const doc = fs.readFileSync('example.md');
const tree = unified().use(remarkParse).parse(doc);

console.log(toMarkdown(tree));
```

Would output the following (assuming remark is [configured][6] for dash bullets
and singular list item indents):

```markdown
<!-- prettier-ignore-start -->

<!-- remark-ignore-start -->

<!-- START doctoc generated TOC please keep comment here to allow auto update -->

<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Install remark](#install)
- [Usage](#usage)
- [API](#api)
- [Related](#related)
- [Contributing and Support](#contributing-and-support)
  - [Contributors](#contributors)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

<!-- remark-ignore-end -->

<!-- prettier-ignore-end -->

<!-- Begin the documentation section -->

<!-- TODO: add another section here -->

<!-- remark-ignore -->

# Install [remark](https://npm.im/remark)
```

Notice how the `<!-- START doctoc…` and `<!-- DON'T EDIT…` comments are now
separated by a newline, which will cause erroneous behavior when running doctoc.
~~Additionally, all the unnecessary newlines around the comments are very
ugly.~~

Suppose instead we ran the following JavaScript:

```typescript
import fs from 'node:fs';
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import { toMarkdown } from 'mdast-util-to-markdown';
import { joinTightComments } from 'mdast-util-tight-comments';

const doc = fs.readFileSync('example.md');
const tree = unified().use(remarkParse).parse(doc);

console.log(toMarkdown(tree, { join: [joinTightComments] }));
```

Then we would get the following output:

```markdown
<!-- prettier-ignore-start -->
<!-- remark-ignore-start -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Install](#install)
- [Usage](#usage)
- [API](#api)
- [Related](#related)
- [Contributing and Support](#contributing-and-support)
  - [Contributors](#contributors)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- remark-ignore-end -->
<!-- prettier-ignore-end -->

<!-- Begin the documentation section -->
<!-- TODO: add another section here -->

<!-- remark-ignore -->

# Install [remark](https://npm.im/remark)
```

That's better! But not perfect. What if we want to preserve the default spacing
around the `<!-- Begin the…` comment? Specifically, we want to maintain the
newline _before_ and _after_ this comment.

To preserve newlines before a comment, affix the opening tag with a `|`. To
preserve newlines after a comment, prefix the closing tag with a `|`. These can
be combined to preserve a newline both before and after a comment.

For example, suppose we edited `example.md` to contain the following:

```markdown
<!-- prettier-ignore-start -->
<!-- remark-ignore-start -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Install remark](#install)
- [Usage](#usage)
- [API](#api)
- [Related](#related)
- [Contributing and Support](#contributing-and-support)
  - [Contributors](#contributors)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- remark-ignore-end -->
<!-- prettier-ignore-end -->

<!--| Begin the documentation section |-->

<!-- TODO: add another section here -->

<!-- remark-ignore -->

# Install [remark](https://npm.im/remark)
```

Notice the `<!--| Begin the documentation section |-->` line. Since there aren't
any other remark plugins being used, running the above JavaScript with this new
`readme.md` file would output the contents of the file unchanged.

Also notice the `<!-- remark-ignore -->` line. This specific comment receives
special consideration in that:

1. There will never be a newline between it and the next node.
2. There will always be a newline between it and the previous node.

> If you're running prettier _after_ remark, you must surround the comments
> around which you want to preserve tightened spacing with
> `<!-- prettier-ignore-start -->` and `<!-- prettier-ignore-end -->`.

## API

Detailed interface information can be found under [`docs/`][x-repo-docs].

## Related

- [remark-tight-comments][7] — remove unnecessary newlines around comments.

<!-- symbiote-template-region-start 5 -->

## Appendix

<!-- symbiote-template-region-end -->

Further documentation can be found under [`docs/`][x-repo-docs].

<!-- TODO: additional appendix sections here -->
<!-- symbiote-template-region-start 6 -->

### Published Package Details

This is an [ESM-only package][x-pkg-esm-wine] built by Babel for use in Node.js
versions that are not end-of-life. For TypeScript users, this package supports
both `"Node10"` and `"Node16"` module resolution strategies.

<!-- symbiote-template-region-end -->
<!-- TODO: additional package details here -->
<!-- symbiote-template-region-start 7 -->

<details><summary>Expand details</summary>

That means ESM source will load this package via `import { ... } from ...` or
`await import(...)` and CJS source will load this package via dynamic
`import()`. This has several benefits, the foremost being: less code
shipped/smaller package size, avoiding [dual package
hazard][x-pkg-dual-package-hazard] entirely, distributables are not
packed/bundled/uglified, and a drastically less complex build process.

The glaring downside, which may or may not be relevant, is that CJS consumers
cannot `require()` this package and can only use `import()` in an asynchronous
context. This means, in effect, CJS consumers may not be able to use this
package at all.

Each entry point (i.e. `ENTRY`) in [`package.json`'s
`exports[ENTRY]`][x-repo-package-json] object includes one or more [export
conditions][x-pkg-exports-conditions]. These entries may or may not include: an
[`exports[ENTRY].types`][x-pkg-exports-types-key] condition pointing to a type
declaration file for TypeScript and IDEs, a
[`exports[ENTRY].module`][x-pkg-exports-module-key] condition pointing to
(usually ESM) source for Webpack/Rollup, a `exports[ENTRY].node` and/or
`exports[ENTRY].default` condition pointing to (usually CJS2) source for Node.js
`require`/`import` and for browsers and other environments, and [other
conditions][x-pkg-exports-conditions] not enumerated here. Check the
[package.json][x-repo-package-json] file to see which export conditions are
supported.

Note that, regardless of the [`{ "type": "..." }`][x-pkg-type] specified in
[`package.json`][x-repo-package-json], any JavaScript files written in ESM
syntax (including distributables) will always have the `.mjs` extension. Note
also that [`package.json`][x-repo-package-json] may include the
[`sideEffects`][x-pkg-side-effects-key] key, which is almost always `false` for
optimal [tree shaking][x-pkg-tree-shaking] where appropriate.

<!-- symbiote-template-region-end -->
<!-- TODO: additional package details here -->
<!-- symbiote-template-region-start 8 -->

</details>

### License

<!-- symbiote-template-region-end -->

See [LICENSE][x-repo-license].

<!-- TODO: additional license information and/or sections here -->
<!-- symbiote-template-region-start 9 -->

## Contributing and Support

**[New issues][x-repo-choose-new-issue] and [pull requests][x-repo-pr-compare]
are always welcome and greatly appreciated! 🤩** Just as well, you can [star 🌟
this project][x-badge-repo-link] to let me know you found it useful! ✊🏿 Or [buy
me a beer][x-repo-sponsor], I'd appreciate it. Thank you!

See [CONTRIBUTING.md][x-repo-contributing] and [SUPPORT.md][x-repo-support] for
more information.

<!-- symbiote-template-region-end -->
<!-- TODO: additional contribution/support sections here -->
<!-- symbiote-template-region-start 10 -->

### Contributors

<!-- symbiote-template-region-end -->
<!-- symbiote-template-region-start root-package-only -->
<!-- (section elided by symbiote) -->
<!-- symbiote-template-region-end -->
<!-- symbiote-template-region-start workspace-package-only -->

See the [table of contributors][x-repo-contributors].

<!-- symbiote-template-region-end -->

[x-badge-blm-image]: https://xunn.at/badge-blm 'Join the movement!'
[x-badge-blm-link]: https://xunn.at/donate-blm
[x-badge-codecov-image]:
  https://img.shields.io/codecov/c/github/Xunnamius/unified-utils/main?style=flat-square&token=HWRIOBAAPW&flag=package.main_mdast-util-tight-comments
  'Is this package well-tested?'
[x-badge-codecov-link]: https://codecov.io/gh/Xunnamius/unified-utils
[x-badge-downloads-image]:
  https://img.shields.io/npm/dm/mdast-util-tight-comments?style=flat-square
  'Number of times this package has been downloaded per month'
[x-badge-downloads-link]: https://npmtrends.com/mdast-util-tight-comments
[x-badge-lastcommit-image]:
  https://img.shields.io/github/last-commit/Xunnamius/unified-utils?style=flat-square
  'Latest commit timestamp'
[x-badge-license-image]:
  https://img.shields.io/npm/l/mdast-util-tight-comments?style=flat-square
  "This package's source license"
[x-badge-license-link]:
  https://github.com/Xunnamius/unified-utils/blob/main/LICENSE
[x-badge-npm-image]:
  https://xunn.at/npm-pkg-version/mdast-util-tight-comments
  'Install this package using npm or yarn!'
[x-badge-npm-link]: https://npm.im/mdast-util-tight-comments
[x-badge-repo-link]: https://github.com/Xunnamius/unified-utils
[x-badge-semanticrelease-image]:
  https://xunn.at/badge-semantic-release
  'This repo practices continuous integration and deployment!'
[x-badge-semanticrelease-link]:
  https://github.com/semantic-release/semantic-release
[x-pkg-dual-package-hazard]:
  https://nodejs.org/api/packages.html#dual-package-hazard
[x-pkg-esm-wine]:
  https://dev.to/jakobjingleheimer/configuring-commonjs-es-modules-for-nodejs-12ed#esm-source-and-distribution
[x-pkg-exports-conditions]:
  https://webpack.js.org/guides/package-exports#reference-syntax
[x-pkg-exports-module-key]:
  https://webpack.js.org/guides/package-exports#providing-commonjs-and-esm-version-stateless
[x-pkg-exports-types-key]:
  https://devblogs.microsoft.com/typescript/announcing-typescript-4-5-beta#packagejson-exports-imports-and-self-referencing
[x-pkg-side-effects-key]:
  https://webpack.js.org/guides/tree-shaking#mark-the-file-as-side-effect-free
[x-pkg-tree-shaking]: https://webpack.js.org/guides/tree-shaking
[x-pkg-type]:
  https://github.com/nodejs/node/blob/8d8e06a345043bec787e904edc9a2f5c5e9c275f/doc/api/packages.md#type
[x-repo-choose-new-issue]:
  https://github.com/Xunnamius/unified-utils/issues/new/choose
[x-repo-contributing]: /CONTRIBUTING.md
[x-repo-contributors]: /README.md#contributors
[x-repo-docs]: docs
[x-repo-license]: ./LICENSE
[x-repo-package-json]: package.json
[x-repo-pr-compare]: https://github.com/Xunnamius/unified-utils/compare
[x-repo-sponsor]: https://github.com/sponsors/Xunnamius
[x-repo-support]: /.github/SUPPORT.md
[1]: https://github.com/thlorenz/doctoc
[2]: https://github.com/syntax-tree/mdast-util-to-markdown
[3]:
  https://github.com/xunnamius/unified-utils/blob/main/packages/remark-tight-comments
[4]: https://github.com/xunnamius/unified-utils/blob/main/packages/remark-ignore
[5]: https://github.com/thlorenz/doctoc#update-existing-doctoc-tocs-effortlessly
[6]: /.remarkrc.mjs
[7]: /packages/remark-tight-comments

---
_Source: https://npm.io/package/mdast-util-tight-comments · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
