From 6a43da81f5e123b3abe98f7d4e8946d755a7c2e6 Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Wed, 13 Sep 2023 17:58:59 +0200 Subject: [PATCH] Refactor docs --- packages/remark-cli/readme.md | 105 ++++---- packages/remark-parse/index.d.ts | 25 +- packages/remark-parse/lib/index.js | 2 +- packages/remark-parse/readme.md | 205 ++++++++------- packages/remark-stringify/index.d.ts | 15 +- packages/remark-stringify/lib/index.js | 2 +- packages/remark-stringify/readme.md | 338 +++++++++++-------------- packages/remark/readme.md | 207 +++++++++------ readme.md | 266 ++++++++++--------- 9 files changed, 632 insertions(+), 533 deletions(-) diff --git a/packages/remark-cli/readme.md b/packages/remark-cli/readme.md index a127a84a..86cc0b4e 100644 --- a/packages/remark-cli/readme.md +++ b/packages/remark-cli/readme.md @@ -29,10 +29,9 @@ Command line interface to inspect and change markdown files with **[remark][]**. This package is a command line interface (CLI) that you can use in your terminal or in npm scripts and the like to inspect and change markdown files. -This CLI is built around remark, which is a very popular ecosystem of plugins -that work with markdown as structured data, specifically ASTs (abstract syntax -trees). -You can choose from the 150+ plugins that already exist or make your own. +This CLI is built around remark, which is an ecosystem of plugins that work with +markdown as structured data, specifically ASTs (abstract syntax trees). +You can choose from the 150+ existing plugins or make your own. See [the monorepo readme][remark] for info on what the remark ecosystem is. @@ -46,8 +45,8 @@ If not, you can always use [`remark`][remark-core] itself manually in a script. ## Install -This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). -In Node.js (version 14.14+, or 16.0+), install with [npm][]: +This package is [ESM only][esm]. +In Node.js (version 16+), install with [npm][]: ```sh npm install remark-cli @@ -58,7 +57,7 @@ npm install remark-cli Add a table of contents with [`remark-toc`][remark-toc] to `readme.md`: ```sh -remark readme.md --use remark-toc --output +remark readme.md --output --use remark-toc ``` Lint all markdown files in the current directory according to the markdown style @@ -80,31 +79,32 @@ Usage: remark [options] [path | glob ...] Options: + --[no-]color specify color in report (on by default) + --[no-]config search for configuration files (on by default) + -e --ext specify extensions + --file-path specify path to process as + -f --frail exit with 1 on warnings -h --help output usage information - -v --version output version number + --[no-]ignore search for ignore files (on by default) + -i --ignore-path specify ignore file + --ignore-path-resolve-from cwd|dir resolve patterns in `ignore-path` from its directory or cwd + --ignore-pattern specify ignore patterns + --inspect output formatted syntax tree -o --output [path] specify output location + -q --quiet output only warnings and errors -r --rc-path specify configuration file - -i --ignore-path specify ignore file + --report specify reporter -s --setting specify settings - -e --ext specify extensions - -u --use use plugins - -w --watch watch for changes and reprocess - -q --quiet output only warnings and errors -S --silent output only errors - -f --frail exit with 1 on warnings - -t --tree specify input and output as syntax tree - --report specify reporter - --file-path specify path to process as - --ignore-path-resolve-from dir|cwd resolve patterns in `ignore-path` from its directory or cwd - --ignore-pattern specify ignore patterns --silently-ignore do not fail when given ignored files + --[no-]stdout specify writing to stdout (on by default) + -t --tree specify input and output as syntax tree --tree-in specify input as syntax tree --tree-out output syntax tree - --inspect output formatted syntax tree - --[no-]stdout specify writing to stdout (on by default) - --[no-]color specify color in report (on by default) - --[no-]config search for configuration files (on by default) - --[no-]ignore search for ignore files (on by default) + -u --use use plugins + --verbose report extra info for messages + -v --version output version number + -w --watch watch for changes and reprocess Examples: @@ -118,17 +118,17 @@ Examples: $ remark . -o ``` -More information on all these options is available at -[`unified-args`][unified-args], which does the work. +More info on all these options is available at [`unified-args`][unified-args], +which does the work. `remark-cli` is `unified-args` preconfigured to: -* Load `remark-` plugins -* Search for markdown extensions +* load `remark-` plugins +* search for markdown extensions ([`.md`, `.markdown`, etc][markdown-extensions]) -* Ignore paths found in [`.remarkignore` files][ignore-file] -* Load configuration from +* ignore paths found in [`.remarkignore` files][ignore-file] +* load configuration from [`.remarkrc`, `.remarkrc.js`, etc files][config-file] -* Use configuration from +* use configuration from [`remarkConfig` fields in `package.json` files][config-file] ## Examples @@ -138,13 +138,13 @@ More information on all these options is available at This example checks and formats markdown with `remark-cli`. It assumes you’re in a Node.js package. -First, install the CLI and plugins: +Install the CLI and plugins: ```sh -npm install remark-cli remark-toc remark-preset-lint-consistent remark-preset-lint-recommended --save-dev +npm install remark-cli remark-preset-lint-consistent remark-preset-lint-recommended remark-toc --save-dev ``` -Now, add an npm script in your `package.json`: +…then add an npm script in your `package.json`: ```js /* … */ @@ -158,7 +158,7 @@ Now, add an npm script in your `package.json`: > 💡 **Tip**: add ESLint and such in the `format` script too. -Observe that the above change adds a `format` script, which can be run with +The above change adds a `format` script, which can be run with `npm run format`. It runs remark on all markdown files (`.`) and rewrites them (`--output`). Run `./node_modules/.bin/remark --help` for more info on the CLI. @@ -188,7 +188,7 @@ Then, add a `remarkConfig` to your `package.json` to configure remark: ``` > 👉 **Note**: you must remove the comments in the above examples when -> copy/pasting them, as comments are not supported in `package.json` files. +> copy/pasting them as comments are not supported in `package.json` files. Finally, you can run the npm script to check and format markdown files in your project: @@ -269,20 +269,23 @@ Earlier wins (so in the above file structure `folder/.remarkrc.js` wins over `folder/package.json`): 1. `.remarkrc` (JSON) -2. `.remarkrc.json` (JSON) 3. `.remarkrc.cjs` (CJS) -4. `.remarkrc.mjs` (ESM) 5. `.remarkrc.js` (CJS or ESM, depending on `type: 'module'` in `package.json`) +2. `.remarkrc.json` (JSON) +4. `.remarkrc.mjs` (ESM) 6. `.remarkrc.yaml` (YAML) 7. `.remarkrc.yml` (YAML) 8. `package.json` with `remarkConfig` field ## Compatibility -Projects maintained by the unified collective are compatible with all maintained +Projects maintained by the unified collective are compatible with maintained versions of Node.js. -As of now, that is Node.js 14.14+, and 16.0+. -Our projects sometimes work with older versions, but this is not guaranteed. + +When we cut a new major release, we drop support for unmaintained versions of +Node. +This means we try to keep the current release line, `remark-cli@^11`, +compatible with Node.js 12. ## Security @@ -311,8 +314,6 @@ abide by its terms. Support this effort and give back by sponsoring on [OpenCollective][collective]! - -
@@ -424,7 +425,9 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [npm]: https://docs.npmjs.com/cli/install -[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting +[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c + +[markdown-extensions]: https://github.com/sindresorhus/markdown-extensions [rehype]: https://github.com/rehypejs/rehype @@ -432,16 +435,16 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [remark]: https://github.com/remarkjs/remark -[markdown-extensions]: https://github.com/sindresorhus/markdown-extensions - -[config-file]: https://github.com/unifiedjs/unified-engine/blob/main/doc/configure.md +[remark-core]: ../remark/ -[ignore-file]: https://github.com/unifiedjs/unified-engine/blob/main/doc/ignore.md +[remark-toc]: https://github.com/remarkjs/remark-toc -[unified-args]: https://github.com/unifiedjs/unified-args#cli +[config-file]: https://github.com/unifiedjs/unified-engine#config-files -[remark-core]: ../remark +[ignore-file]: https://github.com/unifiedjs/unified-engine#ignore-files -[remark-toc]: https://github.com/remarkjs/remark-toc +[unified-args]: https://github.com/unifiedjs/unified-args#cli [markdown-style-guide]: https://github.com/remarkjs/remark-lint/tree/main/packages/remark-preset-lint-markdown-style-guide + +[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting diff --git a/packages/remark-parse/index.d.ts b/packages/remark-parse/index.d.ts index 867f8127..c74ec656 100644 --- a/packages/remark-parse/index.d.ts +++ b/packages/remark-parse/index.d.ts @@ -1,5 +1,5 @@ import type {Root} from 'mdast' -import type {Extension} from 'mdast-util-from-markdown' +import type {Extension as FromMarkdownExtension} from 'mdast-util-from-markdown' import type {Extension as MicromarkExtension} from 'micromark-util-types' import type {Plugin} from 'unified' import type {Options} from './lib/index.js' @@ -28,7 +28,28 @@ declare module 'unified' { interface Settings extends Options {} interface Data { + /** + * List of `micromark` extensions to use. + * + * This type is registered by `remark-parse`. + * Values can be registered by remark plugins that extend `micromark` and + * `mdast-util-from-markdown`. + * See {@link MicromarkExtension | `Extension`} from + * {@link https://github.com/micromark/micromark/tree/main/packages/micromark-util-types | `micromark-util-types`}. + */ micromarkExtensions?: MicromarkExtension[] - fromMarkdownExtensions?: Array + + /** + * List of `mdast-util-from-markdown` extensions to use. + * + * This type is registered by `remark-parse`. + * Values can be registered by remark plugins that extend `micromark` and + * `mdast-util-from-markdown`. + * See {@link FromMarkdownExtension | `Extension`} from + * {@link https://github.com/syntax-tree/mdast-util-from-markdown#extension | `mdast-util-from-markdown`}. + */ + fromMarkdownExtensions?: Array< + FromMarkdownExtension[] | FromMarkdownExtension + > } } diff --git a/packages/remark-parse/lib/index.js b/packages/remark-parse/lib/index.js index 6461409b..f4edbf33 100644 --- a/packages/remark-parse/lib/index.js +++ b/packages/remark-parse/lib/index.js @@ -6,7 +6,7 @@ */ /** - * @typedef {Omit} Options + * @typedef {Omit} Options */ import {fromMarkdown} from 'mdast-util-from-markdown' diff --git a/packages/remark-parse/readme.md b/packages/remark-parse/readme.md index 013ccb11..b889b188 100644 --- a/packages/remark-parse/readme.md +++ b/packages/remark-parse/readme.md @@ -8,7 +8,7 @@ [![Backers][backers-badge]][collective] [![Chat][chat-badge]][chat] -**[remark][]** plugin to add support for parsing markdown input. +**[remark][]** plugin to add support for parsing from markdown. ## Contents @@ -35,24 +35,21 @@ This package is a [unified][] ([remark][]) plugin that defines how to take markdown as input and turn it into a syntax tree. -This plugin is built on [`mdast-util-from-markdown`][mdast-util-from-markdown], -which in turn uses [`micromark`][micromark] for parsing markdown into tokens and -turns those into [mdast][] syntax trees. -remark focusses on making it easier to transform content by abstracting such -internals away. - -**unified** is a project that transforms content with abstract syntax trees -(ASTs). -**remark** adds support for markdown to unified. -**mdast** is the markdown AST that remark uses. -**micromark** is the markdown parser we use. -This is a remark plugin that defines how input markdown is turned into mdast. +See [the monorepo readme][remark] for info on what the remark ecosystem is. ## When should I use this? This plugin adds support to unified for parsing markdown. -You can alternatively use [`remark`][remark-core] instead, which combines -unified, this plugin, and [`remark-stringify`][remark-stringify]. +If you also need to serialize markdown, you can alternatively use +[`remark`][remark-core], which combines unified, this plugin, and +[`remark-stringify`][remark-stringify]. + +If you *just* want to turn markdown into HTML (with maybe a few extensions), +we recommend [`micromark`][micromark] instead. +If you don’t use plugins and want to access the syntax tree, you can directly +use [`mdast-util-from-markdown`][mdast-util-from-markdown]. +remark focusses on making it easier to transform content by abstracting these +internals away. You can combine this plugin with other plugins to add syntax extensions. Notable examples that deeply integrate with it are @@ -61,17 +58,12 @@ Notable examples that deeply integrate with it are [`remark-frontmatter`][remark-frontmatter], [`remark-math`][remark-math], and [`remark-directive`][remark-directive]. -You can also use any other [remark plugin][plugin] after `remark-parse`. - -If you *just* want to turn markdown into HTML (with maybe a few extensions), -we recommend [`micromark`][micromark] instead. -If you want to handle syntax trees manually, you can use -[`mdast-util-from-markdown`][mdast-util-from-markdown]. +You can also use any other [remark plugin][remark-plugin] after `remark-parse`. ## Install -This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). -In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: +This package is [ESM only][esm]. +In Node.js (version 16+), install with [npm][]: ```sh npm install remark-parse @@ -96,42 +88,53 @@ In browsers with [`esm.sh`][esmsh]: Say we have the following module `example.js`: ```js -import {unified} from 'unified' -import remarkParse from 'remark-parse' +import rehypeStringify from 'rehype-stringify' import remarkGfm from 'remark-gfm' +import remarkParse from 'remark-parse' import remarkRehype from 'remark-rehype' -import rehypeStringify from 'rehype-stringify' +import {unified} from 'unified' -main() +const doc = ` +# Mercury -async function main() { - const file = await unified() - .use(remarkParse) - .use(remarkGfm) - .use(remarkRehype) - .use(rehypeStringify) - .process('# Hi\n\n*Hello*, world!') +**Mercury** is the first planet from the [Sun](https://en.wikipedia.org/wiki/Sun) +and the smallest planet in the Solar System. +` - console.log(String(file)) -} +const file = await unified() + .use(remarkParse) + .use(remarkGfm) + .use(remarkRehype) + .use(rehypeStringify) + .process(doc) + +console.log(String(file)) ``` -Running that with `node example.js` yields: +…then running `node example.js` yields: ```html -

Hi

-

Hello, world!

+

Mercury

+

Mercury is the first planet from the Sun +and the smallest planet in the Solar System.

``` ## API This package exports no identifiers. -The default export is `remarkParse`. +The default export is [`remarkParse`][api-remark-parse]. ### `unified().use(remarkParse)` -Add support for parsing markdown input. -There are no options. +Add support for parsing from markdown. + +###### Parameters + +There are no parameters. + +###### Returns + +Nothing (`undefined`). ## Examples @@ -139,30 +142,34 @@ There are no options. We support CommonMark by default. Non-standard markdown extensions can be enabled with plugins. -The following example adds support for GFM features (autolink literals, + +This example shows how to support GFM features (autolink literals, footnotes, strikethrough, tables, tasklists) and frontmatter (YAML): ```js -import {unified} from 'unified' -import remarkParse from 'remark-parse' +import rehypeStringify from 'rehype-stringify' import remarkFrontmatter from 'remark-frontmatter' import remarkGfm from 'remark-gfm' +import remarkParse from 'remark-parse' import remarkRehype from 'remark-rehype' -import rehypeStringify from 'rehype-stringify' +import {unified} from 'unified' + +const doc = `--- +layout: solar-system +--- -main() +# Hi ~~Mars~~Venus! +` -async function main() { - const file = await unified() - .use(remarkParse) - .use(remarkFrontmatter) - .use(remarkGfm) - .use(remarkRehype) - .use(rehypeStringify) - .process('---\nlayout: home\n---\n\n# Hi ~~Mars~~Venus!') +const file = await unified() + .use(remarkParse) + .use(remarkFrontmatter) + .use(remarkGfm) + .use(remarkRehype) + .use(rehypeStringify) + .process(doc) - console.log(String(file)) -} +console.log(String(file)) ``` Yields: @@ -176,31 +183,32 @@ Yields: Man pages (short for manual pages) are a way to document CLIs (example: type `man git-log` in your terminal). They use an old markup format called roff. -There’s a remark plugin, [`remark-man`][remark-man], that can serialize as roff. -The following example turns markdown into man pages by using unified with +There’s a remark plugin, [`remark-man`][remark-man], that can serialize as +roff. + +This example shows how to turn markdown into man pages by using unified with `remark-parse` and `remark-man`: ```js -import {unified} from 'unified' -import remarkParse from 'remark-parse' import remarkMan from 'remark-man' +import remarkParse from 'remark-parse' +import {unified} from 'unified' -main() +const doc = ` +# titan(7) -- largest moon of saturn -async function main() { - const file = await unified() - .use(remarkParse) - .use(remarkMan) - .process('# titan(7) -- largest moon of saturn\n\nTitan is the largest moon…') +Titan is the largest moon… +` - console.log(String(file)) -} +const file = await unified().use(remarkParse).use(remarkMan).process(doc) + +console.log(String(file)) ``` Yields: ```roff -.TH "TITAN" "7" "November 2021" "" "" +.TH "TITAN" "7" "September 2023" "" "" .SH "NAME" \fBtitan\fR - largest moon of saturn .P @@ -216,26 +224,29 @@ If you’re interested in extending markdown, ## Syntax tree -The syntax tree format used in remark is [mdast][]. +The syntax tree used in remark is [mdast][]. ## Types This package is fully typed with [TypeScript][]. -There are no extra exported types. +It exports the additional type `Options` (which is currently empty). ## Compatibility -Projects maintained by the unified collective are compatible with all maintained +Projects maintained by the unified collective are compatible with maintained versions of Node.js. -As of now, that is Node.js 12.20+, 14.14+, and 16.0+. -Our projects sometimes work with older versions, but this is not guaranteed. + +When we cut a new major release, we drop support for unmaintained versions of +Node. +This means we try to keep the current release line, `remark-parse@^10`, +compatible with Node.js 12. ## Security As markdown can be turned into HTML and improper use of HTML can open you up to [cross-site scripting (XSS)][xss] attacks, use of remark can be unsafe. -When going to HTML, you will likely combine remark with **[rehype][]**, in which -case you should use [`rehype-sanitize`][rehype-sanitize]. +When going to HTML, you will combine remark with **[rehype][]**, in which case +you should use [`rehype-sanitize`][rehype-sanitize]. Use of remark plugins could also open you up to other attacks. Carefully assess each plugin and the risks involved in using them. @@ -257,8 +268,6 @@ abide by its terms. Support this effort and give back by sponsoring on [OpenCollective][collective]! - -
@@ -344,9 +353,9 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [downloads]: https://www.npmjs.com/package/remark-parse -[size-badge]: https://img.shields.io/bundlephobia/minzip/remark-parse.svg +[size-badge]: https://img.shields.io/bundlejs/size/remark-parse -[size]: https://bundlephobia.com/result?p=remark-parse +[size]: https://bundlejs.com/?q=remark-parse [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg @@ -374,42 +383,46 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [npm]: https://docs.npmjs.com/cli/install -[esmsh]: https://esm.sh +[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c -[unified]: https://github.com/unifiedjs/unified - -[remark]: https://github.com/remarkjs/remark +[esmsh]: https://esm.sh [mdast]: https://github.com/syntax-tree/mdast -[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting +[mdast-util-from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown -[typescript]: https://www.typescriptlang.org +[micromark]: https://github.com/micromark/micromark + +[micromark-extend]: https://github.com/micromark/micromark#extensions [rehype]: https://github.com/rehypejs/rehype [rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize -[mdast-util-from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown +[remark]: https://github.com/remarkjs/remark -[micromark]: https://github.com/micromark/micromark +[remark-core]: ../remark/ -[micromark-extend]: https://github.com/micromark/micromark#extensions +[remark-directive]: https://github.com/remarkjs/remark-directive + +[remark-frontmatter]: https://github.com/remarkjs/remark-frontmatter [remark-gfm]: https://github.com/remarkjs/remark-gfm [remark-mdx]: https://github.com/mdx-js/mdx/tree/main/packages/remark-mdx -[remark-frontmatter]: https://github.com/remarkjs/remark-frontmatter +[remark-man]: https://github.com/remarkjs/remark-man [remark-math]: https://github.com/remarkjs/remark-math -[remark-man]: https://github.com/remarkjs/remark-man - -[remark-directive]: https://github.com/remarkjs/remark-directive +[remark-plugin]: https://github.com/remarkjs/remark#plugin [remark-stringify]: ../remark-stringify/ -[remark-core]: ../remark/ +[typescript]: https://www.typescriptlang.org + +[unified]: https://github.com/unifiedjs/unified + +[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting -[plugin]: https://github.com/remarkjs/remark#plugin +[api-remark-parse]: #unifieduseremarkparse diff --git a/packages/remark-stringify/index.d.ts b/packages/remark-stringify/index.d.ts index c219ef38..0b266fce 100644 --- a/packages/remark-stringify/index.d.ts +++ b/packages/remark-stringify/index.d.ts @@ -1,12 +1,12 @@ import type {Root} from 'mdast' -import type {Options as Extension} from 'mdast-util-to-markdown' +import type {Options as ToMarkdownExtension} from 'mdast-util-to-markdown' import type {Plugin} from 'unified' import type {Options} from './lib/index.js' export type {Options} from './lib/index.js' /** - * Add support for serializing as HTML. + * Add support for serializing to markdown. * * @this * Unified processor. @@ -27,6 +27,15 @@ declare module 'unified' { interface Settings extends Options {} interface Data { - toMarkdownExtensions?: Extension[] + /** + * List of `mdast-util-to-markdown` extensions to use. + * + * This type is registered by `remark-stringify`. + * Values can be registered by remark plugins that extend + * `mdast-util-to-markdown`. + * See {@link ToMarkdownExtension | `Options`} from + * {@link https://github.com/syntax-tree/mdast-util-to-markdown#options | `mdast-util-to-markdown`}. + */ + toMarkdownExtensions?: ToMarkdownExtension[] } } diff --git a/packages/remark-stringify/lib/index.js b/packages/remark-stringify/lib/index.js index 7f71538f..d1a268af 100644 --- a/packages/remark-stringify/lib/index.js +++ b/packages/remark-stringify/lib/index.js @@ -12,7 +12,7 @@ import {toMarkdown} from 'mdast-util-to-markdown' /** - * Add support for serializing as markdown. + * Add support for serializing to markdown. * * @param {Readonly | null | undefined} [options] * Configuration (optional). diff --git a/packages/remark-stringify/readme.md b/packages/remark-stringify/readme.md index 4fb658bc..f436bf9e 100644 --- a/packages/remark-stringify/readme.md +++ b/packages/remark-stringify/readme.md @@ -8,7 +8,7 @@ [![Backers][backers-badge]][collective] [![Chat][chat-badge]][chat] -**[remark][]** plugin to add support for serializing markdown. +**[remark][]** plugin to add support for serializing to markdown. ## Contents @@ -30,23 +30,22 @@ This package is a [unified][] ([remark][]) plugin that defines how to take a syntax tree as input and turn it into serialized markdown. +When it’s used, markdown is serialized as the final result. -This plugin is built on [`mdast-util-to-markdown`][mdast-util-to-markdown], -which turns [mdast][] syntax trees into a string. -remark focusses on making it easier to transform content by abstracting such -internals away. - -**unified** is a project that transforms content with abstract syntax trees -(ASTs). -**remark** adds support for markdown to unified. -**mdast** is the markdown AST that remark uses. -This is a remark plugin that defines how mdast is turned into markdown. +See [the monorepo readme][remark] for info on what the remark ecosystem is. ## When should I use this? This plugin adds support to unified for serializing markdown. -You can alternatively use [`remark`][remark-core] instead, which combines -unified, [`remark-parse`][remark-parse], and this plugin. +If you also need to parse markdown, you can alternatively use +[`remark`][remark-core], which combines unified, +[`remark-parse`][remark-parse], and this plugin. + +If you don’t use plugins and have access to a syntax tree, you can directly use +[`mdast-util-to-markdown`][mdast-util-to-markdown], which is used inside this +plugin. +remark focusses on making it easier to transform content by abstracting these +internals away. You can combine this plugin with other plugins to add syntax extensions. Notable examples that deeply integrate with it are @@ -55,15 +54,13 @@ Notable examples that deeply integrate with it are [`remark-frontmatter`][remark-frontmatter], [`remark-math`][remark-math], and [`remark-directive`][remark-directive]. -You can also use any other [remark plugin][plugin] before `remark-stringify`. - -If you want to handle syntax trees manually, you can use -[`mdast-util-to-markdown`][mdast-util-to-markdown]. +You can also use any other [remark plugin][remark-plugin] before +`remark-stringify`. ## Install -This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). -In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: +This package is [ESM only][esm]. +In Node.js (version 16+), install with [npm][]: ```sh npm install remark-stringify @@ -88,186 +85,159 @@ In browsers with [`esm.sh`][esmsh]: Say we have the following module `example.js`: ```js -import {unified} from 'unified' import rehypeParse from 'rehype-parse' import rehypeRemark from 'rehype-remark' import remarkStringify from 'remark-stringify' +import {unified} from 'unified' -main() - -async function main() { - const file = await unified() - .use(rehypeParse) - .use(rehypeRemark) - .use(remarkStringify, { - bullet: '*', - fence: '~', - fences: true, - incrementListMarker: false - }) - .process('

Hello, world!

') - - console.log(String(file)) -} +const doc = ` +

Uranus

+

Uranus is the seventh +planet from the Sun and is a gaseous +cyan ice giant.

+` + +const file = await unified() + .use(rehypeParse) + .use(rehypeRemark) + .use(remarkStringify) + .process(doc) + +console.log(String(file)) ``` -Running that with `node example.js` yields: +…then running `node example.js` yields: ```markdown -# Hello, world! +# Uranus + +**Uranus** is the seventh [planet](/wiki/Planet "Planet") from the Sun and is a gaseous cyan [ice giant](/wiki/Ice_giant "Ice giant"). ``` ## API This package exports no identifiers. -The default export is `remarkStringify`. +The default export is [`remarkStringify`][api-remark-stringify]. ### `unified().use(remarkStringify[, options])` -Add support for serializing markdown. -Options are passed to [`mdast-util-to-markdown`][mdast-util-to-markdown]: -all formatting options are supported. - -##### `options` - -Configuration (optional). - -###### `options.bullet` - -Marker to use for bullets of items in unordered lists (`'*'`, `'+'`, or `'-'`, -default: `'*'`). - -###### `options.bulletOther` - -Marker to use in certain cases where the primary bullet doesn’t work (`'*'`, -`'+'`, or `'-'`, default: depends). -See [`mdast-util-to-markdown`][mdast-util-to-markdown] for more information. - -###### `options.bulletOrdered` - -Marker to use for bullets of items in ordered lists (`'.'` or `')'`, default: -`'.'`). - -###### `options.bulletOrderedOther` - -Marker to use in certain cases where the primary bullet for ordered items -doesn’t work (`'.'` or `')'`, default: none). -See [`mdast-util-to-markdown`][mdast-util-to-markdown] for more information. - -###### `options.closeAtx` - -Whether to add the same number of number signs (`#`) at the end of an ATX -heading as the opening sequence (`boolean`, default: `false`). - -###### `options.emphasis` - -Marker to use for emphasis (`'*'` or `'_'`, default: `'*'`). - -###### `options.fence` - -Marker to use for fenced code (``'`'`` or `'~'`, default: ``'`'``). - -###### `options.fences` - -Whether to use fenced code always (`boolean`, default: `false`). -The default is to use fenced code if there is a language defined, if the code is -empty, or if it starts or ends in blank lines. - -###### `options.incrementListMarker` - -Whether to increment the counter of ordered lists items (`boolean`, default: -`true`). - -###### `options.listItemIndent` - -How to indent the content of list items (`'one'`, `'tab'`, or `'mixed'`, -default: `'tab'`). -Either with the size of the bullet plus one space (when `'one'`), a tab stop -(`'tab'`), or depending on the item and its parent list (`'mixed'`, uses `'one'` -if the item and list are tight and `'tab'` otherwise). - -###### `options.quote` - -Marker to use for titles (`'"'` or `"'"`, default: `'"'`). - -###### `options.resourceLink` - -Whether to always use resource links (`boolean`, default: `false`). -The default is to use autolinks (``) when possible -and resource links (`[text](url)`) otherwise. - -###### `options.rule` - -Marker to use for thematic breaks (`'*'`, `'-'`, or `'_'`, default: `'*'`). - -###### `options.ruleRepetition` - -Number of markers to use for thematic breaks (`number`, default: -`3`, min: `3`). - -###### `options.ruleSpaces` - -Whether to add spaces between markers in thematic breaks (`boolean`, default: -`false`). +Add support for serializing to markdown. + +###### Parameters + +* `options` ([`Options`][api-options], optional) + — configuration + +###### Returns + +Nothing (`undefined`). + +### `Options` + +Configuration (TypeScript type). + +###### Fields + +* `bullet` (`'*'`, `'+'`, or `'-'`, default: `'*'`) + — marker to use for bullets of items in unordered lists +* `bulletOther` (`'*'`, `'+'`, or `'-'`, default: `'-'` when `bullet` is + `'*'`, `'*'` otherwise) + — marker to use in certain cases where the primary bullet doesn’t work; + cannot be equal to `bullet` +* `bulletOrdered` (`'.'` or `')'`, default: `'.'`) + — marker to use for bullets of items in ordered lists +* `closeAtx` (`boolean`, default: `false`) + — add the same number of number signs (`#`) at the end of an ATX heading as + the opening sequence +* `emphasis` (`'*'` or `'_'`, default: `'*'`) + — marker to use for emphasis +* `fence` (``'`'`` or `'~'`, default: ``'`'``) + — marker to use for fenced code +* `fences` (`boolean`, default: `true`) + — use fenced code always; when `false`, uses fenced code if there is a + language defined, if the code is empty, or if it starts or ends in blank + lines +* `handlers` (`Handlers`, optional) + — handle particular nodes; + see [`mdast-util-to-markdown`][mdast-util-to-markdown] for more info +* `incrementListMarker` (`boolean`, default: `true`) + — increment the counter of ordered lists items +* `join` (`Array`, optional) + — how to join blocks; + see [`mdast-util-to-markdown`][mdast-util-to-markdown] for more info +* `listItemIndent` (`'mixed'`, `'one'`, or `'tab'`, default: `'one'`) + — how to indent the content of list items; + either with the size of the bullet plus one space (when `'one'`), a tab + stop (`'tab'`), or depending on the item and its parent list: `'mixed'` + uses `'one'` if the item and list are tight and `'tab'` otherwise +* `quote` (`'"'` or `"'"`, default: `'"'`) + — marker to use for titles +* `resourceLink` (`boolean`, default: `false`) + — always use resource links (`[text](url)`); + when `false`, uses autolinks (``) when possible +* `rule` (`'*'`, `'-'`, or `'_'`, default: `'*'`) + — marker to use for thematic breaks +* `ruleRepetition` (`number`, default: `3`, min: `3`) + — number of markers to use for thematic breaks +* `ruleSpaces` (`boolean`, default: `false`) + — add spaces between markers in thematic breaks +* `setext` (`boolean`, default: `false`) + — use setext headings when possible; + when `true`, uses setext headings (`heading\n=======`) for non-empty rank 1 + or 2 headings +* `strong` (`'*'` or `'_'`, default: `'*'`) + — marker to use for strong +* `tightDefinitions` (`boolean`, default: `false`) + — join definitions without a blank line +* `unsafe` (`Array`, optional) + — schemas that define when characters cannot occur; + see [`mdast-util-to-markdown`][mdast-util-to-markdown] for more info + + -###### `options.setext` - -Whether to use setext headings when possible (`boolean`, default: `false`). -The default is to always use ATX headings (`# heading`) instead of setext -headings (`heading\n=======`). -Setext headings can’t be used for empty headings or headings with a rank of -three or more. - -###### `options.strong` - -Marker to use for strong (`'*'` or `'_'`, default: `'*'`). - -###### `options.tightDefinitions` - -Whether to join definitions without a blank line (`boolean`, default: `false`). -The default is to add blank lines between any flow (“block”) construct. +## Syntax -###### `options.handlers` +Markdown is serialized according to CommonMark but care is taken to format in a +way that works with most markdown parsers. +Other plugins can add support for syntax extensions. -This option is a bit advanced as it requires knowledge of ASTs, so we defer -to the documentation available in -[`mdast-util-to-markdown`][mdast-util-to-markdown]. +## Syntax tree -###### `options.join` +The syntax tree used in remark is [mdast][]. -This option is a bit advanced as it requires knowledge of ASTs, so we defer -to the documentation available in -[`mdast-util-to-markdown`][mdast-util-to-markdown]. +## Types -###### `options.unsafe` +This package is fully typed with [TypeScript][]. +It exports the additional type [`Options`][api-options]. -This option is a bit advanced as it requires deep knowledge of markdown, so we -defer to the documentation available in -[`mdast-util-to-markdown`][mdast-util-to-markdown]. +It also registers `Settings` with `unified`. +If you’re passing options with `.data('settings', …)`, make sure to import this +package somewhere in your types, as that registers the fields. -## Syntax +```js +/// -Markdown is serialized according to CommonMark but care is taken to format in -such a way that the resulting markdown should work with most markdown parsers. -Other plugins can add support for syntax extensions. +import {unified} from 'unified' -## Syntax tree +// @ts-expect-error: `thisDoesNotExist` is not a valid option. +unified().data('settings', {thisDoesNotExist: false}) +``` -The syntax tree format used in remark is [mdast][]. +## Compatibility -## Types +Projects maintained by the unified collective are compatible with maintained +versions of Node.js. -This package is fully typed with [TypeScript][]. -An `Options` type is exported, which models the interface of accepted options. +When we cut a new major release, we drop support for unmaintained versions of +Node. +This means we try to keep the current release line, `remark-stringify@^10`, +compatible with Node.js 12. ## Security -As markdown can be turned into HTML and improper use of HTML can open you up to -[cross-site scripting (XSS)][xss] attacks, use of remark can be unsafe. -When going to HTML, you will likely combine remark with **[rehype][]**, in which -case you should use [`rehype-sanitize`][rehype-sanitize]. +Use of `remark-stringify` is safe. -Use of remark plugins could also open you up to other attacks. +Use of remark plugins can open you up to attacks. Carefully assess each plugin and the risks involved in using them. For info on how to submit a report, see our [security policy][security]. @@ -287,8 +257,6 @@ abide by its terms. Support this effort and give back by sponsoring on [OpenCollective][collective]! - -
@@ -374,9 +342,9 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [downloads]: https://www.npmjs.com/package/remark-stringify -[size-badge]: https://img.shields.io/bundlephobia/minzip/remark-stringify.svg +[size-badge]: https://img.shields.io/bundlejs/size/remark-stringify -[size]: https://bundlephobia.com/result?p=remark-stringify +[size]: https://bundlejs.com/?q=remark-stringify [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg @@ -404,36 +372,36 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [npm]: https://docs.npmjs.com/cli/install -[esmsh]: https://esm.sh +[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c -[unified]: https://github.com/unifiedjs/unified - -[remark]: https://github.com/remarkjs/remark +[esmsh]: https://esm.sh [mdast]: https://github.com/syntax-tree/mdast -[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting +[mdast-util-to-markdown]: https://github.com/syntax-tree/mdast-util-to-markdown -[typescript]: https://www.typescriptlang.org +[remark]: https://github.com/remarkjs/remark -[rehype]: https://github.com/rehypejs/rehype +[remark-core]: ../remark/ -[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize +[remark-directive]: https://github.com/remarkjs/remark-directive -[mdast-util-to-markdown]: https://github.com/syntax-tree/mdast-util-to-markdown +[remark-frontmatter]: https://github.com/remarkjs/remark-frontmatter [remark-gfm]: https://github.com/remarkjs/remark-gfm +[remark-math]: https://github.com/remarkjs/remark-math + [remark-mdx]: https://github.com/mdx-js/mdx/tree/main/packages/remark-mdx -[remark-frontmatter]: https://github.com/remarkjs/remark-frontmatter +[remark-parse]: ../remark-parse/ -[remark-math]: https://github.com/remarkjs/remark-math +[remark-plugin]: https://github.com/remarkjs/remark#plugin -[remark-directive]: https://github.com/remarkjs/remark-directive +[typescript]: https://www.typescriptlang.org -[remark-parse]: ../remark-parse/ +[unified]: https://github.com/unifiedjs/unified -[remark-core]: ../remark/ +[api-options]: #options -[plugin]: https://github.com/remarkjs/remark#plugin +[api-remark-stringify]: #unifieduseremarkstringify-options diff --git a/packages/remark/readme.md b/packages/remark/readme.md index 54667069..a5339a1c 100644 --- a/packages/remark/readme.md +++ b/packages/remark/readme.md @@ -8,8 +8,8 @@ [![Backers][backers-badge]][collective] [![Chat][chat-badge]][chat] -**[unified][]** processor with support for parsing markdown input and -serializing markdown as output. +**[unified][]** processor with support for parsing from markdown and +serializing to markdown. ## Contents @@ -33,15 +33,11 @@ serializing markdown as output. ## What is this? -This package is a [unified][] processor with support for parsing markdown input -and serializing markdown as output by using unified with +This package is a [unified][] processor with support for parsing markdown as +input and serializing markdown as output by using unified with [`remark-parse`][remark-parse] and [`remark-stringify`][remark-stringify]. -**unified** is a project that transforms content with abstract syntax trees -(ASTs). -**remark** adds support for markdown to unified. -**mdast** is the markdown AST that remark uses. -Please see [the monorepo readme][remark] for what the remark ecosystem is. +See [the monorepo readme][remark] for info on what the remark ecosystem is. ## When should I use this? @@ -51,15 +47,15 @@ This package is a shortcut for `unified().use(remarkParse).use(remarkStringify)`. When the input isn’t markdown (meaning you don’t need `remark-parse`) or the output is not markdown (you don’t need `remark-stringify`), it’s recommended to -use unified directly. +use `unified` directly. When you want to inspect and format markdown files in a project on the command line, you can use [`remark-cli`][remark-cli]. ## Install -This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). -In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: +This package is [ESM only][esm]. +In Node.js (version 16+), install with [npm][]: ```sh npm install remark @@ -85,44 +81,86 @@ Say we have the following module `example.js`: ```js import {remark} from 'remark' -import remarkGfm from 'remark-gfm' import remarkToc from 'remark-toc' -main() +const doc = ` +# Pluto -async function main() { - const file = await remark() - .use(remarkGfm) - .use(remarkToc) - .process('# Hi\n\n## Table of contents\n\n## Hello\n\n*Some* ~more~ _things_.') +Pluto is a dwarf planet in the Kuiper belt. - console.error(String(file)) -} +## Contents + +## History + +### Discovery + +In the 1840s, Urbain Le Verrier used Newtonian mechanics to predict the position of… + +### Name and symbol + +The name Pluto is for the Roman god of the underworld, from a Greek epithet for Hades… + +### Planet X disproved + +Once Pluto was found, its faintness and lack of a viewable disc cast doubt… + +## Orbit + +Pluto's orbital period is about 248 years… +` + +const file = await remark() + .use(remarkToc, {heading: 'contents', tight: true}) + .process(doc) + +console.error(String(file)) ``` -Running that with `node example.js` yields: +…running that with `node example.js` yields: ```markdown -# Hi +# Pluto + +Pluto is a dwarf planet in the Kuiper belt. -## Table of contents +## Contents -* [Hello](#hello) +* [History](#history) + * [Discovery](#discovery) + * [Name and symbol](#name-and-symbol) + * [Planet X disproved](#planet-x-disproved) +* [Orbit](#orbit) -## Hello +## History -*Some* ~~more~~ *things*. +### Discovery + +In the 1840s, Urbain Le Verrier used Newtonian mechanics to predict the position of… + +### Name and symbol + +The name Pluto is for the Roman god of the underworld, from a Greek epithet for Hades… + +### Planet X disproved + +Once Pluto was found, its faintness and lack of a viewable disc cast doubt… + +## Orbit + +Pluto's orbital period is about 248 years… ``` ## API -This package exports the following identifier: `remark`. +This package exports the identifier [`remark`][api-remark]. There is no default export. ### `remark()` -Create a new (unfrozen) unified processor that already uses `remark-parse` and -`remark-stringify` and you can add more plugins to. +Create a new unified processor that already uses +[`remark-parse`][remark-parse] and [`remark-stringify`][remark-stringify]. + +You can add more plugins with `use`. See [`unified`][unified] for more information. ## Examples @@ -133,30 +171,26 @@ The following example checks that markdown code style is consistent and follows some best practices: ```js -import {reporter} from 'vfile-reporter' import {remark} from 'remark' import remarkPresetLintConsistent from 'remark-preset-lint-consistent' import remarkPresetLintRecommended from 'remark-preset-lint-recommended' +import {reporter} from 'vfile-reporter' -main() - -async function main() { - const file = await remark() - .use(remarkPresetLintConsistent) - .use(remarkPresetLintRecommended) - .process('1) Hello, _Jupiter_ and *Neptune*!') +const file = await remark() + .use(remarkPresetLintConsistent) + .use(remarkPresetLintRecommended) + .process('1) Hello, _Jupiter_ and *Neptune*!') - console.error(reporter(file)) -} +console.error(reporter(file)) ``` Yields: ```txt - 1:1 warning Missing newline character at end of file final-newline remark-lint - 1:1-1:35 warning Marker style should be `.` ordered-list-marker-style remark-lint - 1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint - 1:25-1:34 warning Emphasis should use `_` as a marker emphasis-marker remark-lint + warning Missing newline character at end of file final-newline remark-lint +1:1-1:35 warning Marker style should be `.` ordered-list-marker-style remark-lint +1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint +1:25-1:34 warning Emphasis should use `_` as a marker emphasis-marker remark-lint ⚠ 4 warnings ``` @@ -171,15 +205,24 @@ To define options for `remark-stringify`, you can instead pass options to ```js import {remark} from 'remark' -main() +const doc = ` +# Moons of Neptune + +1. Naiad +2. Thalassa +3. Despine +4. … +` -async function main() { - const file = await remark() - .data('settings', {bullet: '*', listItemIndent: 'one', setext: true}) - .process('# Moons of Neptune\n\n- Naiad\n- Thalassa\n- Despine\n- …') +const file = await remark() + .data('settings', { + bulletOrdered: ')', + incrementListMarker: false, + setext: true + }) + .process(doc) - console.log(String(file)) -} +console.log(String(file)) ``` Yields: @@ -188,10 +231,10 @@ Yields: Moons of Neptune ================ -* Naiad -* Thalassa -* Despine -* … +1) Naiad +1) Thalassa +1) Despine +1) … ``` ## Syntax @@ -201,26 +244,42 @@ Other plugins can add support for syntax extensions. ## Syntax tree -The syntax tree format used in remark is [mdast][]. +The syntax tree used in remark is [mdast][]. ## Types This package is fully typed with [TypeScript][]. There are no extra exported types. +It also registers `Settings` with `unified`. +If you’re passing options with `.data('settings', …)`, make sure to import this +package somewhere in your types, as that registers the fields. + +```js +/// + +import {unified} from 'unified' + +// @ts-expect-error: `thisDoesNotExist` is not a valid option. +unified().data('settings', {thisDoesNotExist: false}) +``` + ## Compatibility -Projects maintained by the unified collective are compatible with all maintained +Projects maintained by the unified collective are compatible with maintained versions of Node.js. -As of now, that is Node.js 12.20+, 14.14+, and 16.0+. -Our projects sometimes work with older versions, but this is not guaranteed. + +When we cut a new major release, we drop support for unmaintained versions of +Node. +This means we try to keep the current release line, `remark@^14`, compatible +with Node.js 12. ## Security As markdown can be turned into HTML and improper use of HTML can open you up to [cross-site scripting (XSS)][xss] attacks, use of remark can be unsafe. -When going to HTML, you will likely combine remark with **[rehype][]**, in which -case you should use [`rehype-sanitize`][rehype-sanitize]. +When going to HTML, you will combine remark with **[rehype][]**, in which case +you should use [`rehype-sanitize`][rehype-sanitize]. Use of remark plugins could also open you up to other attacks. Carefully assess each plugin and the risks involved in using them. @@ -242,8 +301,6 @@ abide by its terms. Support this effort and give back by sponsoring on [OpenCollective][collective]! - -
@@ -329,9 +386,9 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [downloads]: https://www.npmjs.com/package/remark -[size-badge]: https://img.shields.io/bundlephobia/minzip/remark.svg +[size-badge]: https://img.shields.io/bundlejs/size/remark -[size]: https://bundlephobia.com/result?p=remark +[size]: https://bundlejs.com/?q=remark [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg @@ -359,24 +416,28 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [npm]: https://docs.npmjs.com/cli/install -[esmsh]: https://esm.sh +[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c -[unified]: https://github.com/unifiedjs/unified +[esmsh]: https://esm.sh [mdast]: https://github.com/syntax-tree/mdast -[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting - -[typescript]: https://www.typescriptlang.org - [rehype]: https://github.com/rehypejs/rehype -[remark]: https://github.com/remarkjs/remark - [rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize +[remark]: https://github.com/remarkjs/remark + [remark-parse]: ../remark-parse [remark-stringify]: ../remark-stringify [remark-cli]: ../remark-cli + +[typescript]: https://www.typescriptlang.org + +[unified]: https://github.com/unifiedjs/unified + +[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting + +[api-remark]: #remark-1 diff --git a/readme.md b/readme.md index 10f8f8e5..d086946d 100644 --- a/readme.md +++ b/readme.md @@ -14,15 +14,19 @@ You can use remark on the server, the client, CLIs, deno, etc. ## Feature highlights -* [x] **[popular][]** (world’s most popular markdown parser) -* [x] **[compliant][syntax]** (100% to CommonMark, 100% to GFM with a plugin) -* [x] **[plugins][]** (150+ plugins you can pick and choose from) -* [x] **[ASTs][syntax-tree]** (inspecting and changing content made easy) +* [x] **[compliant][syntax]** + — 100% to CommonMark, 100% to GFM or MDX with a plugin +* [x] **[ASTs][syntax-tree]** + — inspecting and changing content made easy +* [x] **[popular][]** + — world’s most popular markdown parser +* [x] **[plugins][]** + — 150+ plugins you can pick and choose from ## Intro -remark is a very popular ecosystem of plugins that work with markdown as -structured data, specifically ASTs (abstract syntax trees). +remark is an ecosystem of plugins that work with markdown as structured data, +specifically ASTs (abstract syntax trees). ASTs make it easy for programs to deal with markdown. We call those programs plugins. Plugins inspect and change trees. @@ -70,14 +74,16 @@ With this project and a plugin, you can turn this markdown:
Show example code ```js -import {unified} from 'unified' +import rehypeStringify from 'rehype-stringify' import remarkParse from 'remark-parse' -import remarkHtml from 'remark-html' +import remarkRehype from 'remark-rehype' +import {unified} from 'unified' const file = await unified() - .use(remarkParse) - .use(remarkHtml) - .process('# Hello, *Mercury*!') + .use(remarkParse) + .use(remarkRehype) + .use(rehypeStringify) + .process('# Hello, *Mercury*!') console.log(String(file)) // => '

Hello, Mercury!

' ``` @@ -99,21 +105,23 @@ With another plugin, you can turn this markdown:
Show example code ```js -import {unified} from 'unified' import remarkParse from 'remark-parse' import remarkStringify from 'remark-stringify' +import {unified} from 'unified' import {visit} from 'unist-util-visit' const file = await unified() - .use(remarkParse) - .use(myRemarkPluginToIncreaseHeadings) - .use(remarkStringify) - .process('# Hi, Saturn!') + .use(remarkParse) + .use(myRemarkPluginToIncreaseHeadings) + .use(remarkStringify) + .process('# Hi, Saturn!') console.log(String(file)) // => '## Hi, Saturn!' -/** @type {import('unified').Plugin<[], import('mdast').Root>} */ function myRemarkPluginToIncreaseHeadings() { + /** + * @param {import('mdast').Root} tree + */ return function (tree) { visit(tree, function (node) { if (node.type === 'heading') { @@ -138,26 +146,28 @@ This GitHub repository is a monorepo that contains the following packages: * [`remark-stringify`][remark-stringify] — plugin to take a syntax tree (mdast) and turn it into markdown as output * [`remark`][remark-core] - — unified, `remark-parse`, and `remark-stringify`, useful when input and + — `unified`, `remark-parse`, and `remark-stringify`, useful when input and output are markdown * [`remark-cli`][remark-cli] — CLI around `remark` to inspect and format markdown in scripts ## When should I use this? -If you *just* want to turn markdown into HTML (with maybe a few extensions), -we recommend [`micromark`][micromark] instead. -remark can also do that but it focusses on ASTs and providing an interface for -plugins to transform them. - -Depending on the input you have and output you want, you can use different parts -of remark. +Depending on the input you have and output you want, you can use different +parts of remark. If the input is markdown, you can use `remark-parse` with `unified`. If the output is markdown, you can use `remark-stringify` with `unified` If both the input and output are markdown, you can use `remark` on its own. When you want to inspect and format markdown files in a project, you can use `remark-cli`. +If you *just* want to turn markdown into HTML (with maybe a few extensions), +we recommend [`micromark`][micromark] instead. + +If you don’t use plugins and want to deal with syntax trees manually, you can +use [`mdast-util-from-markdown`][mdast-util-from-markdown] and +[`mdast-util-to-markdown`][mdast-util-to-markdown]. + ## Plugins remark plugins deal with markdown. @@ -169,12 +179,12 @@ Some popular examples are: — inspect markdown and warn about inconsistencies * [`remark-toc`][remark-toc] — generate a table of contents -* [`remark-html`][remark-html] - — turn the syntax tree into serialized HTML +* [`remark-rehype`][remark-rehype] + — turn markdown into HTML These plugins are exemplary because what they do and how they do it is quite different, respectively to extend markdown syntax, inspect trees, change trees, -and define other output formats. +and transform to other syntax trees. You can choose from the 150+ plugins that already exist. Here are three good ways to find plugins: @@ -202,24 +212,20 @@ The following example turns markdown into HTML by combining both ecosystems with [`remark-rehype`][remark-rehype]: ```js -import {unified} from 'unified' -import remarkParse from 'remark-parse' -import remarkRehype from 'remark-rehype' import rehypeSanitize from 'rehype-sanitize' import rehypeStringify from 'rehype-stringify' +import remarkParse from 'remark-parse' +import remarkRehype from 'remark-rehype' +import {unified} from 'unified' -main() - -async function main() { - const file = await unified() - .use(remarkParse) - .use(remarkRehype) - .use(rehypeSanitize) - .use(rehypeStringify) - .process('# Hello, Neptune!') +const file = await unified() + .use(remarkParse) + .use(remarkRehype) + .use(rehypeSanitize) + .use(rehypeStringify) + .process('# Hello, Neptune!') - console.log(String(file)) -} +console.log(String(file)) ``` Yields: @@ -236,26 +242,29 @@ The following example adds support for GFM (autolink literals, footnotes, strikethrough, tables, tasklists) and frontmatter (YAML): ```js -import {unified} from 'unified' -import remarkParse from 'remark-parse' +import rehypeStringify from 'rehype-stringify' import remarkFrontmatter from 'remark-frontmatter' import remarkGfm from 'remark-gfm' +import remarkParse from 'remark-parse' import remarkRehype from 'remark-rehype' -import rehypeStringify from 'rehype-stringify' +import {unified} from 'unified' -main() +const doc = `--- +layout: solar-system +--- -async function main() { - const file = await unified() - .use(remarkParse) - .use(remarkFrontmatter) - .use(remarkGfm) - .use(remarkRehype) - .use(rehypeStringify) - .process('---\nlayout: home\n---\n\n# Hi ~~Mars~~Venus!') +# Hi ~~Mars~~Venus! +` - console.log(String(file)) -} +const file = await unified() + .use(remarkParse) + .use(remarkFrontmatter) + .use(remarkGfm) + .use(remarkRehype) + .use(rehypeStringify) + .process(doc) + +console.log(String(file)) ``` Yields: @@ -270,30 +279,26 @@ The following example checks that markdown code style is consistent and follows recommended best practices: ```js -import {reporter} from 'vfile-reporter' import {remark} from 'remark' import remarkPresetLintConsistent from 'remark-preset-lint-consistent' import remarkPresetLintRecommended from 'remark-preset-lint-recommended' +import {reporter} from 'vfile-reporter' -main() - -async function main() { - const file = await remark() - .use(remarkPresetLintConsistent) - .use(remarkPresetLintRecommended) - .process('1) Hello, _Jupiter_ and *Neptune*!') +const file = await remark() + .use(remarkPresetLintConsistent) + .use(remarkPresetLintRecommended) + .process('1) Hello, _Jupiter_ and *Neptune*!') - console.error(reporter(file)) -} +console.error(reporter(file)) ``` Yields: ```txt - 1:1 warning Missing newline character at end of file final-newline remark-lint - 1:1-1:35 warning Marker style should be `.` ordered-list-marker-style remark-lint - 1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint - 1:25-1:34 warning Emphasis should use `_` as a marker emphasis-marker remark-lint + warning Missing newline character at end of file final-newline remark-lint +1:1-1:35 warning Marker style should be `.` ordered-list-marker-style remark-lint +1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint +1:25-1:34 warning Emphasis should use `_` as a marker emphasis-marker remark-lint ⚠ 4 warnings ``` @@ -307,10 +312,10 @@ This example assumes you’re in a Node.js package. First, install the CLI and plugins: ```sh -npm install remark-cli remark-toc remark-preset-lint-consistent remark-preset-lint-recommended --save-dev +npm install remark-cli remark-preset-lint-consistent remark-preset-lint-recommended remark-toc --save-dev ``` -Now, add an npm script in your `package.json`: +…then add an npm script in your `package.json`: ```js /* … */ @@ -324,7 +329,7 @@ Now, add an npm script in your `package.json`: > 💡 **Tip**: add ESLint and such in the `format` script too. -Observe that the above change adds a `format` script, which can be run with +The above change adds a `format` script, which can be run with `npm run format`. It runs remark on all markdown files (`.`) and rewrites them (`--output`). Run `./node_modules/.bin/remark --help` for more info on the CLI. @@ -354,7 +359,7 @@ Then, add a `remarkConfig` to your `package.json` to configure remark: ``` > 👉 **Note**: you must remove the comments in the above examples when -> copy/pasting them, as comments are not supported in `package.json` files. +> copy/pasting them as comments are not supported in `package.json` files. Finally, you can run the npm script to check and format markdown files in your project: @@ -365,9 +370,8 @@ npm run format ## Syntax -remark follows CommonMark, which standardizes the differences between markdown -implementations, by default. -Some syntax extensions are supported through plugins. +Markdown is parsed and serialized according to CommonMark. +Other plugins can add support for syntax extensions. We use [`micromark`][micromark] for our parsing. See its documentation for more information on markdown, CommonMark, and @@ -375,7 +379,7 @@ extensions. ## Syntax tree -The syntax tree format used in remark is [mdast][]. +The syntax tree used in remark is [mdast][]. It represents markdown constructs as JSON objects. This markdown: @@ -384,7 +388,7 @@ This markdown: ## Hello *Pluto*! ``` -yields the following tree: +…yields the following tree (positional info remove for brevity): ```js { @@ -404,44 +408,62 @@ The remark organization and the unified collective as a whole is fully typed with [TypeScript][]. Types for mdast are available in [`@types/mdast`][types-mdast]. -For TypeScript to work, it is particularly important to type your plugins -correctly. -We strongly recommend using the `Plugin` type from `unified` with its generics -and to use the node types for the syntax trees provided by `@types/mdast`. +For TypeScript to work, it is important to type your plugins. +For example: ```js /** * @typedef {import('mdast').Root} Root - * + * @typedef {import('vfile').VFile} VFile + */ + +/** * @typedef Options - * Configuration (optional). - * @property {boolean} [someField] - * Some option. + * Configuration. + * @property {boolean | null | undefined} [someField] + * Some option (optional). */ -// To type options and that the it works with `mdast`: -/** @type {import('unified').Plugin<[Options?], Root>} */ +/** + * My plugin. + * + * @param {Options | null | undefined} [options] + * Configuration (optional). + * @returns + * Transform. + */ export function myRemarkPluginAcceptingOptions(options) { - // `options` is `Options?`. + /** + * Transform. + * + * @param {Root} tree + * Tree. + * @param {VFile} file + * File + * @returns {undefined} + * Nothing. + */ return function (tree, file) { - // `tree` is `Root`. + // Do things. } } ``` ## Compatibility -Projects maintained by the unified collective are compatible with all maintained +Projects maintained by the unified collective are compatible with maintained versions of Node.js. -As of now, that is Node.js 12.20+, 14.14+, and 16.0+. -Our projects sometimes work with older versions, but this is not guaranteed. + +When we cut a new major release, we drop support for unmaintained versions of +Node. +This means we try to keep the current release line compatible with Node.js 12. ## Security As markdown can be turned into HTML and improper use of HTML can open you up to [cross-site scripting (XSS)][xss] attacks, use of remark can be unsafe. -When going to HTML, you will likely combine remark with **[rehype][]**, in which -case you should use [`rehype-sanitize`][rehype-sanitize]. +When going to HTML, you will combine remark with **[rehype][]**, in which case +you should use [`rehype-sanitize`][rehype-sanitize]. Use of remark plugins could also open you up to other attacks. Carefully assess each plugin and the risks involved in using them. @@ -463,8 +485,6 @@ abide by its terms. Support this effort and give back by sponsoring on [OpenCollective][collective]! - -
@@ -552,18 +572,20 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [downloads]: https://www.npmjs.com/package/remark -[size-badge]: https://img.shields.io/bundlephobia/minzip/remark.svg +[size-badge]: https://img.shields.io/bundlejs/size/remark -[size]: https://bundlephobia.com/result?p=remark - -[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg - -[chat]: https://github.com/remarkjs/remark/discussions +[size]: https://bundlejs.com/?q=remark [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg [backers-badge]: https://opencollective.com/unified/backers/badge.svg +[collective]: https://opencollective.com/unified + +[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg + +[chat]: https://github.com/remarkjs/remark/discussions + [security]: https://github.com/remarkjs/.github/blob/main/security.md [health]: https://github.com/remarkjs/.github @@ -574,10 +596,6 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md -[collective]: https://opencollective.com/unified - -[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting - [typescript]: https://www.typescriptlang.org [cheat]: https://commonmark.org/help/ @@ -592,35 +610,41 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [types-mdast]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/mdast -[unified]: https://github.com/unifiedjs/unified +[mdast]: https://github.com/syntax-tree/mdast -[remark-gfm]: https://github.com/remarkjs/remark-gfm +[mdast-util-from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown -[remark-toc]: https://github.com/remarkjs/remark-toc +[mdast-util-to-markdown]: https://github.com/syntax-tree/mdast-util-to-markdown -[remark-rehype]: https://github.com/remarkjs/remark-rehype +[micromark]: https://github.com/micromark/micromark -[remark-html]: https://github.com/remarkjs/remark-html +[rehype]: https://github.com/rehypejs/rehype -[remark-lint]: https://github.com/remarkjs/remark-lint +[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize -[awesome-remark]: https://github.com/remarkjs/awesome-remark +[remark-cli]: packages/remark-cli/ -[rehype]: https://github.com/rehypejs/rehype +[remark-core]: packages/remark/ -[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize +[remark-gfm]: https://github.com/remarkjs/remark-gfm -[mdast]: https://github.com/syntax-tree/mdast +[remark-html]: https://github.com/remarkjs/remark-html -[micromark]: https://github.com/micromark/micromark +[remark-lint]: https://github.com/remarkjs/remark-lint [remark-parse]: packages/remark-parse/ +[remark-rehype]: https://github.com/remarkjs/remark-rehype + [remark-stringify]: packages/remark-stringify/ -[remark-core]: packages/remark/ +[remark-toc]: https://github.com/remarkjs/remark-toc -[remark-cli]: packages/remark-cli/ +[awesome-remark]: https://github.com/remarkjs/awesome-remark + +[unified]: https://github.com/unifiedjs/unified + +[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting [list-of-plugins]: doc/plugins.md#list-of-plugins