mdast-util-gfm-footnote
Advanced tools
Comparing version 1.0.1 to 1.0.2
@@ -1,15 +0,26 @@ | ||
/** | ||
* @returns {FromMarkdownExtension} | ||
*/ | ||
export function gfmFootnoteFromMarkdown(): FromMarkdownExtension | ||
/** | ||
* @returns {ToMarkdownExtension} | ||
*/ | ||
export function gfmFootnoteToMarkdown(): ToMarkdownExtension | ||
export type FootnoteReference = import('mdast').FootnoteReference | ||
export type FootnoteDefinition = import('mdast').FootnoteDefinition | ||
export type FromMarkdownExtension = import('mdast-util-from-markdown').Extension | ||
export type FromMarkdownHandle = import('mdast-util-from-markdown').Handle | ||
export type ToMarkdownExtension = import('mdast-util-to-markdown').Options | ||
export type ToMarkdownHandle = import('mdast-util-to-markdown').Handle | ||
export type Map = import('mdast-util-to-markdown').Map | ||
export {gfmFootnoteFromMarkdown, gfmFootnoteToMarkdown} from './lib/index.js' | ||
declare module 'mdast-util-to-markdown' { | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions | ||
interface ConstructNameMap { | ||
/** | ||
* Footnote reference. | ||
* | ||
* ```markdown | ||
* > | A[^b]. | ||
* ^^^^ | ||
* ``` | ||
*/ | ||
footnoteReference: 'footnoteReference' | ||
/** | ||
* Footnote definition. | ||
* | ||
* ```markdown | ||
* > | [^a]: B. | ||
* ^^^^^^^^ | ||
* ``` | ||
*/ | ||
footnoteDefinition: 'footnoteDefinition' | ||
} | ||
} |
173
index.js
@@ -1,171 +0,2 @@ | ||
/** | ||
* @typedef {import('mdast').FootnoteReference} FootnoteReference | ||
* @typedef {import('mdast').FootnoteDefinition} FootnoteDefinition | ||
* @typedef {import('mdast-util-from-markdown').Extension} FromMarkdownExtension | ||
* @typedef {import('mdast-util-from-markdown').Handle} FromMarkdownHandle | ||
* @typedef {import('mdast-util-to-markdown').Options} ToMarkdownExtension | ||
* @typedef {import('mdast-util-to-markdown').Handle} ToMarkdownHandle | ||
* @typedef {import('mdast-util-to-markdown').Map} Map | ||
*/ | ||
import {normalizeIdentifier} from 'micromark-util-normalize-identifier' | ||
import {association} from 'mdast-util-to-markdown/lib/util/association.js' | ||
import {containerFlow} from 'mdast-util-to-markdown/lib/util/container-flow.js' | ||
import {indentLines} from 'mdast-util-to-markdown/lib/util/indent-lines.js' | ||
import {safe} from 'mdast-util-to-markdown/lib/util/safe.js' | ||
import {track} from 'mdast-util-to-markdown/lib/util/track.js' | ||
/** | ||
* @returns {FromMarkdownExtension} | ||
*/ | ||
export function gfmFootnoteFromMarkdown() { | ||
return { | ||
enter: { | ||
gfmFootnoteDefinition: enterFootnoteDefinition, | ||
gfmFootnoteDefinitionLabelString: enterFootnoteDefinitionLabelString, | ||
gfmFootnoteCall: enterFootnoteCall, | ||
gfmFootnoteCallString: enterFootnoteCallString | ||
}, | ||
exit: { | ||
gfmFootnoteDefinition: exitFootnoteDefinition, | ||
gfmFootnoteDefinitionLabelString: exitFootnoteDefinitionLabelString, | ||
gfmFootnoteCall: exitFootnoteCall, | ||
gfmFootnoteCallString: exitFootnoteCallString | ||
} | ||
} | ||
/** @type {FromMarkdownHandle} */ | ||
function enterFootnoteDefinition(token) { | ||
this.enter( | ||
{type: 'footnoteDefinition', identifier: '', label: '', children: []}, | ||
token | ||
) | ||
} | ||
/** @type {FromMarkdownHandle} */ | ||
function enterFootnoteDefinitionLabelString() { | ||
this.buffer() | ||
} | ||
/** @type {FromMarkdownHandle} */ | ||
function exitFootnoteDefinitionLabelString(token) { | ||
const label = this.resume() | ||
const node = /** @type {FootnoteDefinition} */ ( | ||
this.stack[this.stack.length - 1] | ||
) | ||
node.label = label | ||
node.identifier = normalizeIdentifier( | ||
this.sliceSerialize(token) | ||
).toLowerCase() | ||
} | ||
/** @type {FromMarkdownHandle} */ | ||
function exitFootnoteDefinition(token) { | ||
this.exit(token) | ||
} | ||
/** @type {FromMarkdownHandle} */ | ||
function enterFootnoteCall(token) { | ||
this.enter({type: 'footnoteReference', identifier: '', label: ''}, token) | ||
} | ||
/** @type {FromMarkdownHandle} */ | ||
function enterFootnoteCallString() { | ||
this.buffer() | ||
} | ||
/** @type {FromMarkdownHandle} */ | ||
function exitFootnoteCallString(token) { | ||
const label = this.resume() | ||
const node = /** @type {FootnoteDefinition} */ ( | ||
this.stack[this.stack.length - 1] | ||
) | ||
node.label = label | ||
node.identifier = normalizeIdentifier( | ||
this.sliceSerialize(token) | ||
).toLowerCase() | ||
} | ||
/** @type {FromMarkdownHandle} */ | ||
function exitFootnoteCall(token) { | ||
this.exit(token) | ||
} | ||
} | ||
/** | ||
* @returns {ToMarkdownExtension} | ||
*/ | ||
export function gfmFootnoteToMarkdown() { | ||
footnoteReference.peek = footnoteReferencePeek | ||
return { | ||
// This is on by default already. | ||
unsafe: [{character: '[', inConstruct: ['phrasing', 'label', 'reference']}], | ||
handlers: {footnoteDefinition, footnoteReference} | ||
} | ||
/** | ||
* @type {ToMarkdownHandle} | ||
* @param {FootnoteReference} node | ||
*/ | ||
function footnoteReference(node, _, context, safeOptions) { | ||
const tracker = track(safeOptions) | ||
let value = tracker.move('[^') | ||
const exit = context.enter('footnoteReference') | ||
const subexit = context.enter('reference') | ||
value += tracker.move( | ||
safe(context, association(node), { | ||
...tracker.current(), | ||
before: value, | ||
after: ']' | ||
}) | ||
) | ||
subexit() | ||
exit() | ||
value += tracker.move(']') | ||
return value | ||
} | ||
/** @type {ToMarkdownHandle} */ | ||
function footnoteReferencePeek() { | ||
return '[' | ||
} | ||
/** | ||
* @type {ToMarkdownHandle} | ||
* @param {FootnoteDefinition} node | ||
*/ | ||
function footnoteDefinition(node, _, context, safeOptions) { | ||
const tracker = track(safeOptions) | ||
let value = tracker.move('[^') | ||
const exit = context.enter('footnoteDefinition') | ||
const subexit = context.enter('label') | ||
value += tracker.move( | ||
safe(context, association(node), { | ||
...tracker.current(), | ||
before: value, | ||
after: ']' | ||
}) | ||
) | ||
subexit() | ||
value += tracker.move( | ||
']:' + (node.children && node.children.length > 0 ? ' ' : '') | ||
) | ||
tracker.shift(4) | ||
value += tracker.move( | ||
indentLines(containerFlow(node, context, tracker.current()), map) | ||
) | ||
exit() | ||
return value | ||
/** @type {Map} */ | ||
function map(line, index, blank) { | ||
if (index) { | ||
return (blank ? '' : ' ') + line | ||
} | ||
return line | ||
} | ||
} | ||
} | ||
// Note: extra types exported from `index.d.ts`. | ||
export {gfmFootnoteFromMarkdown, gfmFootnoteToMarkdown} from './lib/index.js' |
{ | ||
"name": "mdast-util-gfm-footnote", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "mdast extension to parse and serialize GFM footnotes", | ||
@@ -33,2 +33,3 @@ "license": "MIT", | ||
"files": [ | ||
"lib/", | ||
"index.d.ts", | ||
@@ -43,3 +44,3 @@ "index.js" | ||
"devDependencies": { | ||
"@types/tape": "^4.0.0", | ||
"@types/node": "^18.0.0", | ||
"c8": "^7.0.0", | ||
@@ -49,15 +50,14 @@ "mdast-util-from-markdown": "^1.0.0", | ||
"prettier": "^2.0.0", | ||
"remark-cli": "^10.0.0", | ||
"remark-cli": "^11.0.0", | ||
"remark-preset-wooorm": "^9.0.0", | ||
"rimraf": "^3.0.0", | ||
"tape": "^5.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"xo": "^0.47.0" | ||
"xo": "^0.53.0" | ||
}, | ||
"scripts": { | ||
"build": "rimraf \"*.d.ts\" && tsc && type-coverage", | ||
"prepack": "npm run build && npm run format", | ||
"build": "tsc --build --clean && tsc --build && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"test-api": "node --conditions development test.js", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node --conditions development test.js", | ||
"test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
@@ -64,0 +64,0 @@ }, |
330
readme.md
@@ -11,27 +11,65 @@ # mdast-util-gfm-footnote | ||
Extension for [`mdast-util-from-markdown`][from-markdown] and/or | ||
[`mdast-util-to-markdown`][to-markdown] to support GitHub flavored markdown | ||
(GFM) footnotes in **[mdast][]**. | ||
When parsing (`from-markdown`), must be combined with | ||
[`micromark-extension-gfm-footnote`][extension]. | ||
[mdast][] extensions to parse and serialize [GFM][] footnotes. | ||
GFM footnotes were [announced September 30, 2021][post] but are neither | ||
specified nor supported in all their products (e.g., Gists). | ||
Their implementation on github.com is currently quite buggy. | ||
The bugs have been reported on | ||
[`cmark-gfm`](https://github.com/github/cmark-gfm). | ||
This micromark extension matches github.com except for its bugs. | ||
## Contents | ||
* [What is this?](#what-is-this) | ||
* [When to use this](#when-to-use-this) | ||
* [Install](#install) | ||
* [Use](#use) | ||
* [API](#api) | ||
* [`gfmFootnoteFromMarkdown()`](#gfmfootnotefrommarkdown) | ||
* [`gfmFootnoteToMarkdown()`](#gfmfootnotetomarkdown) | ||
* [HTML](#html) | ||
* [Syntax](#syntax) | ||
* [Syntax tree](#syntax-tree) | ||
* [Nodes](#nodes) | ||
* [Content model](#content-model) | ||
* [Types](#types) | ||
* [Compatibility](#compatibility) | ||
* [Related](#related) | ||
* [Contribute](#contribute) | ||
* [License](#license) | ||
## What is this? | ||
This package contains two extensions that add support for GFM footnote syntax | ||
in markdown to [mdast][]. | ||
These extensions plug into | ||
[`mdast-util-from-markdown`][mdast-util-from-markdown] (to support parsing | ||
footnotes in markdown into a syntax tree) and | ||
[`mdast-util-to-markdown`][mdast-util-to-markdown] (to support serializing | ||
footnotes in syntax trees to markdown). | ||
GFM footnotes were [announced September 30, 2021][post] but are not specified. | ||
Their implementation on github.com is currently buggy. | ||
The bugs have been reported on [`cmark-gfm`][cmark-gfm]. | ||
## When to use this | ||
Use [`mdast-util-gfm`][mdast-util-gfm] if you want all of GFM. | ||
Use this otherwise. | ||
You can use these extensions when you are working with | ||
`mdast-util-from-markdown` and `mdast-util-to-markdown` already. | ||
When working with `mdast-util-from-markdown`, you must combine this package | ||
with [`micromark-extension-gfm-footnote`][micromark-extension-gfm-footnote]. | ||
When you don’t need a syntax tree, you can use [`micromark`][micromark] | ||
directly with `micromark-extension-gfm-footnote`. | ||
When you are working with syntax trees and want all of GFM, use | ||
[`mdast-util-gfm`][mdast-util-gfm] instead. | ||
All these packages are used [`remark-gfm`][remark-gfm], which | ||
focusses on making it easier to transform content by abstracting these | ||
internals away. | ||
This utility does not handle how markdown is turned to HTML. | ||
That’s done by [`mdast-util-to-hast`][mdast-util-to-hast]. | ||
If your content is not in English, you should configure that utility. | ||
## Install | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c): | ||
Node 12+ is needed to use it and it must be `import`ed instead of `require`d. | ||
This package is [ESM only][esm]. | ||
In Node.js (version 14.14+ and 16.0+), install with [npm][]: | ||
[npm][]: | ||
```sh | ||
@@ -41,7 +79,30 @@ npm install mdast-util-gfm-footnote | ||
In Deno with [`esm.sh`][esmsh]: | ||
```js | ||
import {gfmFootnoteFromMarkdown, gfmFootnoteToMarkdown} from 'https://esm.sh/mdast-util-gfm-footnote@1' | ||
``` | ||
In browsers with [`esm.sh`][esmsh]: | ||
```html | ||
<script type="module"> | ||
import {gfmFootnoteFromMarkdown, gfmFootnoteToMarkdown} from 'https://esm.sh/mdast-util-gfm-footnote@1?bundle' | ||
</script> | ||
``` | ||
## Use | ||
Say our module, `example.js`, looks as follows: | ||
Say our document `example.md` contains: | ||
```markdown | ||
Hi![^1] | ||
[^1]: big note | ||
``` | ||
…and our module `example.js` looks as follows: | ||
```js | ||
import fs from 'node:fs/promises' | ||
import {fromMarkdown} from 'mdast-util-from-markdown' | ||
@@ -52,3 +113,3 @@ import {toMarkdown} from 'mdast-util-to-markdown' | ||
const doc = 'Hi![^1]\n\n[^1]: big note' | ||
const doc = await fs.readFile('example.md') | ||
@@ -67,3 +128,3 @@ const tree = fromMarkdown(doc, { | ||
Now, running `node example` yields: | ||
…now running `node example.js` yields (positional info removed for brevity): | ||
@@ -101,30 +162,173 @@ ```js | ||
This package exports the identifiers | ||
[`gfmFootnoteFromMarkdown`][api-gfmfootnotefrommarkdown] and | ||
[`gfmFootnoteToMarkdown`][api-gfmfootnotetomarkdown]. | ||
There is no default export. | ||
### `gfmFootnoteFromMarkdown()` | ||
Create an extension for | ||
[`mdast-util-from-markdown`][mdast-util-from-markdown] | ||
to enable GFM footnotes in markdown. | ||
###### Returns | ||
Extension for `mdast-util-from-markdown` | ||
([`FromMarkdownExtension`][frommarkdownextension]). | ||
### `gfmFootnoteToMarkdown()` | ||
Support footnotes. | ||
The exports are functions that can be called to get extensions, respectively | ||
for [`mdast-util-from-markdown`][from-markdown] and | ||
[`mdast-util-to-markdown`][to-markdown]. | ||
Create an extension for | ||
[`mdast-util-to-markdown`][mdast-util-to-markdown] | ||
to enable GFM footnotes in markdown. | ||
###### Returns | ||
Extension for `mdast-util-to-markdown` | ||
([`ToMarkdownExtension`][tomarkdownextension]). | ||
## HTML | ||
This utility does not handle how markdown is turned to HTML. | ||
That’s done by [`mdast-util-to-hast`][mdast-util-to-hast]. | ||
If your content is not in English, you should configure that utility. | ||
## Syntax | ||
See [Syntax in `micromark-extension-frontmatter`][syntax]. | ||
## Syntax tree | ||
The following interfaces are added to **[mdast][]** by this utility. | ||
### Nodes | ||
#### `FootnoteDefinition` | ||
```idl | ||
interface FootnoteDefinition <: Parent { | ||
type: 'footnoteDefinition' | ||
children: [FlowContent] | ||
} | ||
FootnoteDefinition includes Association | ||
``` | ||
**FootnoteDefinition** (**[Parent][dfn-parent]**) represents content relating | ||
to the document that is outside its flow. | ||
**FootnoteDefinition** can be used where **[flow][dfn-flow-content]** content | ||
is expected. | ||
Its content model is also **[flow][dfn-flow-content]** content. | ||
**FootnoteDefinition** includes the mixin | ||
**[Association][dfn-mxn-association]**. | ||
**FootnoteDefinition** should be associated with | ||
**[FootnoteReferences][dfn-footnote-reference]**. | ||
For example, the following markdown: | ||
```markdown | ||
[^alpha]: bravo and charlie. | ||
``` | ||
Yields: | ||
```js | ||
{ | ||
type: 'footnoteDefinition', | ||
identifier: 'alpha', | ||
label: 'alpha', | ||
children: [{ | ||
type: 'paragraph', | ||
children: [{type: 'text', value: 'bravo and charlie.'}] | ||
}] | ||
} | ||
``` | ||
#### `FootnoteReference` | ||
```idl | ||
interface FootnoteReference <: Node { | ||
type: 'footnoteReference' | ||
} | ||
FootnoteReference includes Association | ||
``` | ||
**FootnoteReference** (**[Node][dfn-node]**) represents a marker through | ||
association. | ||
**FootnoteReference** can be used where | ||
**[static phrasing][dfn-static-phrasing-content]** content is expected. | ||
It has no content model. | ||
**FootnoteReference** includes the mixin **[Association][dfn-mxn-association]**. | ||
**FootnoteReference** should be associated with a | ||
**[FootnoteDefinition][dfn-footnote-definition]**. | ||
For example, the following markdown: | ||
```markdown | ||
[^alpha] | ||
``` | ||
Yields: | ||
```js | ||
{ | ||
type: 'footnoteReference', | ||
identifier: 'alpha', | ||
label: 'alpha' | ||
} | ||
``` | ||
### Content model | ||
#### `FlowContent` (GFM footnotes) | ||
```idl | ||
type FlowContentGfm = FootnoteDefinition | FlowContent | ||
``` | ||
#### `StaticPhrasingContent` (GFM footnotes) | ||
```idl | ||
type StaticPhrasingContentGfm = FootnoteReference | StaticPhrasingContent | ||
``` | ||
## Types | ||
This package is fully typed with [TypeScript][]. | ||
It does not export additional types. | ||
The `FootnoteDefinition` and `FootnoteReference` types of the mdast nodes are | ||
exposed from `@types/mdast`. | ||
## Compatibility | ||
Projects maintained by the unified collective are compatible with all 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. | ||
This plugin works with `mdast-util-from-markdown` version 1+ and | ||
`mdast-util-to-markdown` version 1+. | ||
## Related | ||
* [`remarkjs/remark`][remark] | ||
— markdown processor powered by plugins | ||
* [`remarkjs/remark-gfm`][remark-gfm] | ||
* [`remark-gfm`][remark-gfm] | ||
— remark plugin to support GFM | ||
* [`micromark/micromark`][micromark] | ||
— the smallest commonmark-compliant markdown parser that exists | ||
* [`micromark/micromark-extension-gfm-footnote`][extension] | ||
* [`mdast-util-gfm`][mdast-util-gfm] | ||
— same but all of GFM (autolink literals, footnotes, strikethrough, tables, | ||
tasklists) | ||
* [`micromark-extension-gfm-footnote`][micromark-extension-gfm-footnote] | ||
— micromark extension to parse GFM footnotes | ||
* [`syntax-tree/mdast-util-from-markdown`][from-markdown] | ||
— mdast parser using `micromark` to create mdast from markdown | ||
* [`syntax-tree/mdast-util-to-markdown`][to-markdown] | ||
— mdast serializer to create markdown from mdast | ||
## Contribute | ||
See [`contributing.md` in `syntax-tree/.github`][contributing] for ways to get | ||
started. | ||
See [`contributing.md`][contributing] in [`syntax-tree/.github`][health] for | ||
ways to get started. | ||
See [`support.md`][support] for ways to get help. | ||
@@ -170,2 +374,8 @@ | ||
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c | ||
[esmsh]: https://esm.sh | ||
[typescript]: https://www.typescriptlang.org | ||
[license]: license | ||
@@ -175,8 +385,10 @@ | ||
[contributing]: https://github.com/syntax-tree/.github/blob/HEAD/contributing.md | ||
[health]: https://github.com/syntax-tree/.github | ||
[support]: https://github.com/syntax-tree/.github/blob/HEAD/support.md | ||
[contributing]: https://github.com/syntax-tree/.github/blob/main/contributing.md | ||
[coc]: https://github.com/syntax-tree/.github/blob/HEAD/code-of-conduct.md | ||
[support]: https://github.com/syntax-tree/.github/blob/main/support.md | ||
[coc]: https://github.com/syntax-tree/.github/blob/main/code-of-conduct.md | ||
[mdast]: https://github.com/syntax-tree/mdast | ||
@@ -186,14 +398,42 @@ | ||
[remark]: https://github.com/remarkjs/remark | ||
[remark-gfm]: https://github.com/remarkjs/remark-gfm | ||
[from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown | ||
[micromark]: https://github.com/micromark/micromark | ||
[to-markdown]: https://github.com/syntax-tree/mdast-util-to-markdown | ||
[micromark-extension-gfm-footnote]: https://github.com/micromark/micromark-extension-gfm-footnote | ||
[micromark]: https://github.com/micromark/micromark | ||
[syntax]: https://github.com/micromark/micromark-extension-gfm-footnote#syntax | ||
[extension]: https://github.com/micromark/micromark-extension-gfm-footnote | ||
[gfm]: https://github.github.com/gfm/ | ||
[cmark-gfm]: https://github.com/github/cmark-gfm | ||
[post]: https://github.blog/changelog/2021-09-30-footnotes-now-supported-in-markdown-fields/ | ||
[mdast-util-from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown | ||
[mdast-util-to-markdown]: https://github.com/syntax-tree/mdast-util-to-markdown | ||
[mdast-util-to-hast]: https://github.com/syntax-tree/mdast-util-to-hast | ||
[dfn-parent]: https://github.com/syntax-tree/mdast#parent | ||
[dfn-mxn-association]: https://github.com/syntax-tree/mdast#association | ||
[dfn-node]: https://github.com/syntax-tree/unist#node | ||
[frommarkdownextension]: https://github.com/syntax-tree/mdast-util-from-markdown#extension | ||
[tomarkdownextension]: https://github.com/syntax-tree/mdast-util-to-markdown#options | ||
[dfn-flow-content]: #flowcontent-gfm-footnotes | ||
[dfn-static-phrasing-content]: #staticphrasingcontent-gfm-footnotes | ||
[dfn-footnote-reference]: #footnotereference | ||
[dfn-footnote-definition]: #footnotedefinition | ||
[api-gfmfootnotefrommarkdown]: #gfmfootnotefrommarkdown | ||
[api-gfmfootnotetomarkdown]: #gfmfootnotetomarkdown |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
21598
10
7
238
432
1