Guides / GitHub flavored markdown (GFM)
This guide explores how to support GFM features such as autolink literals, footnotes, strikethrough, tables, and task lists. MDX supports standard markdown syntax (CommonMark). That means GitHub flavored markdown (GFM) extensions are not supported by default. They can be enabled by using a remark plugin: remark-gfm
. That plugin, like all remark plugins, can be passed in remarkPlugins
in ProcessorOptions
. More info on plugins is available in § Extending MDX
Say we have an MDX file like this:
# GFM
## Autolink literals
www.example.com, https://example.com, and contact@example.com.
## Footnote
A note[^1]
[^1]: Big note.
## Strikethrough
~one~ or ~~two~~ tildes.
## Table
| a | b | c | d |
| - | :- | -: | :-: |
## Tasklist
* [ ] to do
* [x] done
The above MDX with GFM can be transformed with the following module:
import fs from 'node:fs/promises'
import {compile} from '@mdx-js/mdx'
import remarkGfm from 'remark-gfm'
console.log(
String(
await compile(await fs.readFile('example.mdx'), {remarkPlugins: [remarkGfm]})
)
)
(alias) module "node:fs/promises"
import fs
(alias) function compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compile
Compile MDX to JS.
(alias) function remarkGfm(options?: Options | null | undefined): undefined
import remarkGfm
Add support GFM (autolink literals, footnotes, strikethrough, tables, tasklists).
namespace console
var console: Console
The console
module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.
The module exports two specific components:
Console
class with methods such as console.log()
, console.error()
and console.warn()
that can be used to write to any Node.js stream.console
instance configured to write to process.stdout
and process.stderr
. The global console
can be used without calling require('console')
.Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O
for more information.
Example using the global console
:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console
class:
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void
Prints to stdout
with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3)
(the arguments are all passed to util.format()
).
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
See util.format()
for more information.
var String: StringConstructor
(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
(alias) compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compile
Compile MDX to JS.
(alias) module "node:fs/promises"
import fs
function readFile(path: PathLike | fs.FileHandle, options?: ({
encoding?: null | undefined;
flag?: OpenMode | undefined;
} & EventEmitter<T extends EventMap<T> = DefaultEventMap>.Abortable) | null): Promise<Buffer> (+2 overloads)
Asynchronously reads the entire contents of a file.
If no encoding is specified (using options.encoding
), the data is returned as a Buffer
object. Otherwise, the data will be a string.
If options
is a string, then it specifies the encoding.
When the path
is a directory, the behavior of fsPromises.readFile()
is platform-specific. On macOS, Linux, and Windows, the promise will be rejected with an error. On FreeBSD, a representation of the directory's contents will be returned.
An example of reading a package.json
file located in the same directory of the running code:
import { readFile } from 'node:fs/promises';
try {
const filePath = new URL('./package.json', import.meta.url);
const contents = await readFile(filePath, { encoding: 'utf8' });
console.log(contents);
} catch (err) {
console.error(err.message);
}
It is possible to abort an ongoing readFile
using an AbortSignal
. If a request is aborted the promise returned is rejected with an AbortError
:
import { readFile } from 'node:fs/promises';
try {
const controller = new AbortController();
const { signal } = controller;
const promise = readFile(fileName, { signal });
// Abort the request before the promise settles.
controller.abort();
await promise;
} catch (err) {
// When a request is aborted - err is an AbortError
console.error(err);
}
Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.readFile
performs.
Any specified FileHandle
has to support reading.
FileHandle
(property) remarkPlugins?: PluggableList | null | undefined
List of remark plugins (optional).
(alias) function remarkGfm(options?: Options | null | undefined): undefined
import remarkGfm
Add support GFM (autolink literals, footnotes, strikethrough, tables, tasklists).
<>
<h1>GFM</h1>
<h2>Autolink literals</h2>
<p>
<a href="http://www.example.com">www.example.com</a>,{' '}
<a href="https://example.com">https://example.com</a>, and{' '}
<a href="mailto:contact@example.com">contact@example.com</a>.
</p>
<h2>Footnote</h2>
<p>
A note
<sup>
<a
href="#user-content-fn-1"
id="user-content-fnref-1"
data-footnote-ref="true"
aria-describedby="footnote-label"
>
1
</a>
</sup>
</p>
<h2>Strikethrough</h2>
<p>
<del>one</del> or <del>two</del> tildes.
</p>
<h2>Table</h2>
<table>
<thead>
<tr>
<th>a</th>
<th style={{textAlign: 'left'}}>b</th>
<th style={{textAlign: 'right'}}>c</th>
<th style={{textAlign: 'center'}}>d</th>
</tr>
</thead>
</table>
<h2>Tasklist</h2>
<ul className="contains-task-list">
<li className="task-list-item">
<input type="checkbox" disabled /> to do
</li>
<li className="task-list-item">
<input type="checkbox" disabled checked />
done
</li>
</ul>
<section data-footnotes="true" className="footnotes">
<h2 className="sr-only" id="footnote-label">
Footnotes
</h2>
<ol>
<li id="user-content-fn-1">
<p>
Big note.{' '}
<a
href="#user-content-fnref-1"
data-footnote-backref=""
aria-label="Back to reference 1"
className="data-footnote-backref"
>
↩
</a>
</p>
</li>
</ol>
</section>
</>