Refactor routing in App component to enhance navigation and improve error handling by integrating dynamic routes and updating the NotFound route.

This commit is contained in:
becarta
2025-05-23 12:43:00 +02:00
parent f40db0f5c9
commit a544759a3b
11127 changed files with 1647032 additions and 0 deletions

4
node_modules/retext-smartypants/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
export { default } from "./lib/index.js";
export type Options = import("./lib/index.js").Options;
export type QuoteCharacterMap = import("./lib/index.js").QuoteCharacterMap;
//# sourceMappingURL=index.d.ts.map

1
node_modules/retext-smartypants/index.d.ts.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":";sBACa,OAAO,gBAAgB,EAAE,OAAO;gCAChC,OAAO,gBAAgB,EAAE,iBAAiB"}

6
node_modules/retext-smartypants/index.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
/**
* @typedef {import('./lib/index.js').Options} Options
* @typedef {import('./lib/index.js').QuoteCharacterMap} QuoteCharacterMap
*/
export {default} from './lib/index.js'

90
node_modules/retext-smartypants/lib/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,90 @@
/**
* Replace straight punctuation marks with curly ones.
*
* @param {Readonly<Options> | null | undefined} [options]
* Configuration (optional).
* @returns
* Transform.
*/
export default function retextSmartypants(options?: Readonly<Options> | null | undefined): (tree: Root) => undefined;
/**
* Transform.
*/
export type Method = (state: State, node: Punctuation | Symbol, index: number, parent: Parents) => boolean | undefined | void;
/**
* Configuration.
*/
export type Options = {
/**
* Transform backticks (default: `true`); when `true`, turns double
* backticks into an opening double quote and double straight single quotes
* into a closing double quote; when `'all'`, does that and turns single
* backticks into an opening single quote and a straight single quotes into
* a closing single smart quote; `quotes: false` must be used with
* `backticks: 'all'`.
*/
backticks?: "all" | boolean | null | undefined;
/**
* Closing quotes to use (default: `{double: '”', single: ''}`).
*/
closingQuotes?: QuoteCharacterMap | null | undefined;
/**
* Transform dashes (default: `true`);
* when `true`, turns two dashes into an em dash character;
* when `'oldschool'`, turns three dashes into an em dash and two into an en
* dash;
* when `'inverted'`, turns three dashes into an en dash and two into an em
* dash.
*/
dashes?: "inverted" | "oldschool" | boolean | null | undefined;
/**
* Transform triple dots (default: `true`).
* when `'spaced'`, turns triple dots with spaces into ellipses;
* when `'unspaced'`, turns triple dots without spaces into ellipses;
* when `true`, turns triple dots with or without spaces into ellipses.
*/
ellipses?: "spaced" | "unspaced" | boolean | null | undefined;
/**
* Opening quotes to use (default: `{double: '“', single: ''}`).
*/
openingQuotes?: QuoteCharacterMap | null | undefined;
/**
* Transform straight quotes into smart quotes (default: `true`).
*/
quotes?: boolean | null | undefined;
};
/**
* Info passed around.
*/
export type State = {
/**
* Closing quotes.
*/
close: Quotes;
/**
* Opening quotes.
*/
open: Quotes;
};
/**
* Quote characters.
*/
export type QuoteCharacterMap = {
/**
* Character to use for double quotes.
*/
double: string;
/**
* Character to use for single quotes.
*/
single: string;
};
/**
* Quotes.
*/
export type Quotes = [string, string];
import type { Root } from 'nlcst';
import type { Punctuation } from 'nlcst';
import type { Symbol } from 'nlcst';
import type { Parents } from 'nlcst';
//# sourceMappingURL=index.d.ts.map

1
node_modules/retext-smartypants/lib/index.d.ts.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":"AA2EA;;;;;;;GAOG;AACH,oDALW,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,UAqDlC,IAAI,KAEF,SAAS,CAuBvB;;;;6BArJU,KAAK,QAEL,WAAW,GAAG,MAAM,SAEpB,MAAM,UAEN,OAAO,KAEL,OAAO,GAAG,SAAS,GAAG,IAAI;;;;;;;;;;;;;gBAKzB,KAAK,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS;;;;oBAOlC,iBAAiB,GAAG,IAAI,GAAG,SAAS;;;;;;;;;aAEpC,UAAU,GAAG,WAAW,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS;;;;;;;eAOrD,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS;;;;oBAKlD,iBAAiB,GAAG,IAAI,GAAG,SAAS;;;;aAEpC,OAAO,GAAG,IAAI,GAAG,SAAS;;;;;;;;;WAK1B,MAAM;;;;UAEN,MAAM;;;;;;;;;YAKN,MAAM;;;;YAEN,MAAM;;;;;qBAGP,CAAC,MAAM,EAAE,MAAM,CAAC;0BA3DyC,OAAO;iCAAP,OAAO;4BAAP,OAAO;6BAAP,OAAO"}

395
node_modules/retext-smartypants/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,395 @@
/**
* @import {Parents, Punctuation, Root, SentenceContent, Symbol} from 'nlcst'
*/
/**
* @callback Method
* Transform.
* @param {State} state
* Info passed around.
* @param {Punctuation | Symbol} node
* Node.
* @param {number} index
* Position of `node` in `parent`.
* @param {Parents} parent
* Parent of `node`.
* @returns {boolean | undefined | void}
* Whether to remove the node (`true`); or not (otherwise).
*
* @typedef Options
* Configuration.
* @property {'all' | boolean | null | undefined} [backticks=true]
* Transform backticks (default: `true`); when `true`, turns double
* backticks into an opening double quote and double straight single quotes
* into a closing double quote; when `'all'`, does that and turns single
* backticks into an opening single quote and a straight single quotes into
* a closing single smart quote; `quotes: false` must be used with
* `backticks: 'all'`.
* @property {QuoteCharacterMap | null | undefined} [closingQuotes]
* Closing quotes to use (default: `{double: '”', single: ''}`).
* @property {'inverted' | 'oldschool' | boolean | null | undefined} [dashes=true]
* Transform dashes (default: `true`);
* when `true`, turns two dashes into an em dash character;
* when `'oldschool'`, turns three dashes into an em dash and two into an en
* dash;
* when `'inverted'`, turns three dashes into an en dash and two into an em
* dash.
* @property {'spaced' | 'unspaced' | boolean | null | undefined} [ellipses=true]
* Transform triple dots (default: `true`).
* when `'spaced'`, turns triple dots with spaces into ellipses;
* when `'unspaced'`, turns triple dots without spaces into ellipses;
* when `true`, turns triple dots with or without spaces into ellipses.
* @property {QuoteCharacterMap | null | undefined} [openingQuotes]
* Opening quotes to use (default: `{double: '“', single: ''}`).
* @property {boolean | null | undefined} [quotes=true]
* Transform straight quotes into smart quotes (default: `true`).
*
* @typedef State
* Info passed around.
* @property {Quotes} close
* Closing quotes.
* @property {Quotes} open
* Opening quotes.
*
* @typedef QuoteCharacterMap
* Quote characters.
* @property {string} double
* Character to use for double quotes.
* @property {string} single
* Character to use for single quotes.
*
* @typedef {[string, string]} Quotes
* Quotes.
*/
import {visit} from 'unist-util-visit'
import {toString} from 'nlcst-to-string'
/** @type {Quotes} */
const defaultClosingQuotes = ['”', '']
/** @type {Quotes} */
const defaultOpeningQuotes = ['“', '']
/** @type {Readonly<Options>} */
const emptyOptions = {}
/**
* Replace straight punctuation marks with curly ones.
*
* @param {Readonly<Options> | null | undefined} [options]
* Configuration (optional).
* @returns
* Transform.
*/
export default function retextSmartypants(options) {
const settings = options || emptyOptions
/** @type {Array<Method>} */
const methods = []
if (settings.quotes !== false) {
methods.push(quotesDefault)
}
if (settings.ellipses === 'spaced') {
methods.push(ellipsesSpaced)
} else if (settings.ellipses === 'unspaced') {
methods.push(ellipsesUnspaced)
} else if (settings.ellipses !== false) {
methods.push(ellipsesDefault)
}
if (settings.backticks === 'all') {
if (settings.quotes !== false) {
throw new Error("Cannot accept `backticks: 'all'` with `quotes: true`")
}
methods.push(backticksAll)
} else if (settings.backticks !== false) {
methods.push(backticksDefault)
}
if (settings.dashes === 'inverted') {
methods.push(dashesInverted)
} else if (settings.dashes === 'oldschool') {
methods.push(dashesOldschool)
} else if (settings.dashes !== false) {
methods.push(dashesDefault)
}
/** @type {State} */
const state = {
close: settings.closingQuotes
? [settings.closingQuotes.double, settings.closingQuotes.single]
: defaultClosingQuotes,
open: settings.openingQuotes
? [settings.openingQuotes.double, settings.openingQuotes.single]
: defaultOpeningQuotes
}
/**
* Transform.
*
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
return function (tree) {
visit(tree, function (node, position, parent) {
let index = -1
if (
parent &&
position !== undefined &&
(node.type === 'PunctuationNode' || node.type === 'SymbolNode')
) {
while (++index < methods.length) {
const result = methods[index](state, node, position, parent)
if (result === true) {
console.log('drop', node)
parent.children.splice(position, 1)
return position
}
}
}
})
}
}
/**
* Transform single and double backticks and single quotes into smart quotes.
*
* @type {Method}
*/
function backticksAll(state, node, index, parent) {
backticksDefault(state, node, index, parent)
if (node.value === '`') {
node.value = ''
} else if (node.value === "'") {
node.value = ''
}
}
/**
* Transform double backticks and single quotes into smart quotes.
*
* @type {Method}
*/
function backticksDefault(_, node) {
if (node.value === '``') {
node.value = '“'
} else if (node.value === "''") {
node.value = '”'
}
}
/**
* Transform two dashes into an em dash.
*
* @type {Method}
*/
function dashesDefault(_, node) {
if (node.value === '--') {
node.value = '—'
}
}
/**
* Transform three dashes into an en dash, and two into an em dash.
*
* @type {Method}
*/
function dashesInverted(_, node, index, parent) {
const next = parent.children[index + 1]
if (
node.value === '—' &&
next &&
next.type === 'PunctuationNode' &&
next.value === '-'
) {
next.value = ''
return true
}
if (node.value === '---') {
node.value = ''
} else if (node.value === '--') {
node.value = '—'
}
}
/**
* Transform three dashes into an em dash, and two into an en dash.
*
* @type {Method}
*/
function dashesOldschool(_, node, index, parent) {
const next = parent.children[index + 1]
if (
node.value === '' &&
next &&
next.type === 'PunctuationNode' &&
next.value === '-'
) {
next.value = '—'
return true
}
if (node.value === '---') {
node.value = '—'
} else if (node.value === '--') {
node.value = ''
}
}
/**
* Transform multiple dots into unicode ellipses.
*
* @type {Method}
*/
function ellipsesDefault(_, node, index, parent) {
ellipsesSpaced(_, node, index, parent)
ellipsesUnspaced(_, node, index, parent)
}
/**
* Transform multiple dots with spaces into unicode ellipses.
*
* @type {Method}
*/
function ellipsesSpaced(_, node, index, parent) {
const value = node.value
const siblings = parent.children
if (!/^\.+$/.test(value)) {
return
}
// Search for dot-nodes with whitespace between.
/** @type {Array<SentenceContent>} */
const nodes = []
let position = index
let count = 1
// Its possible that the node is merged with an adjacent word-node. In that
// code, we cannot transform it because theres no reference to the
// grandparent.
while (--position > 0) {
let sibling = siblings[position]
if (sibling.type !== 'WhiteSpaceNode') {
break
}
const queue = sibling
sibling = siblings[--position]
if (
sibling &&
(sibling.type === 'PunctuationNode' || sibling.type === 'SymbolNode') &&
/^\.+$/.test(sibling.value)
) {
nodes.push(queue, sibling)
count++
continue
}
break
}
if (count < 3) {
return
}
siblings.splice(index - nodes.length, nodes.length)
node.value = '…'
}
/**
* Transform multiple dots without spaces into unicode ellipses.
*
* @type {Method}
*/
function ellipsesUnspaced(_, node) {
// Simple node with three dots and without whitespace.
if (/^\.{3,}$/.test(node.value)) {
node.value = '…'
}
}
/**
* Transform straight single- and double quotes into smart quotes.
*
* @type {Method}
*/
// eslint-disable-next-line complexity
function quotesDefault(state, node, index, parent) {
const siblings = parent.children
const value = node.value
if (value !== '"' && value !== "'") {
return
}
const quoteIndex = value === '"' ? 0 : 1
const previous = siblings[index - 1]
const next = siblings[index + 1]
const nextNext = siblings[index + 2]
const nextValue = next ? toString(next) : ''
if (
next &&
(next.type === 'PunctuationNode' || next.type === 'SymbolNode') &&
(!nextNext || nextNext.type !== 'WordNode')
) {
// Special case if the very first character is a quote followed by
// punctuation at a non-word-break. Close the quotes by brute force.
node.value = state.close[quoteIndex]
} else if (
next &&
(next.type === 'PunctuationNode' || next.type === 'SymbolNode') &&
(nextValue === '"' || nextValue === "'") &&
nextNext &&
nextNext.type === 'WordNode'
) {
// Special case for double sets of quotes:
// `He said, "'Quoted' words in a larger quote."`
node.value = state.open[quoteIndex]
next.value = state.open[nextValue === '"' ? 0 : 1]
} else if (next && /^\d\ds$/.test(nextValue)) {
// Special case for decade abbreviations: `the '80s`
node.value = state.close[quoteIndex]
} else if (
previous &&
(previous.type === 'WhiteSpaceNode' ||
previous.type === 'PunctuationNode' ||
previous.type === 'SymbolNode') &&
next &&
next.type === 'WordNode'
) {
// Get most opening single quotes.
node.value = state.open[quoteIndex]
} else if (
previous &&
previous.type !== 'WhiteSpaceNode' &&
previous.type !== 'SymbolNode' &&
previous.type !== 'PunctuationNode'
) {
// Closing quotes.
node.value = state.close[quoteIndex]
} else if (
!next ||
next.type === 'WhiteSpaceNode' ||
(value === "'" && nextValue === 's')
) {
node.value = state.close[quoteIndex]
} else {
node.value = state.open[quoteIndex]
}
}

22
node_modules/retext-smartypants/license generated vendored Normal file
View File

@@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) Titus Wormer <tituswormer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

81
node_modules/retext-smartypants/package.json generated vendored Normal file
View File

@@ -0,0 +1,81 @@
{
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
"bugs": "https://github.com/retextjs/retext-smartypants/issues",
"contributors": [
"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)"
],
"dependencies": {
"@types/nlcst": "^2.0.0",
"nlcst-to-string": "^4.0.0",
"unist-util-visit": "^5.0.0"
},
"description": "retext plugin to implement SmartyPants",
"devDependencies": {
"@types/node": "^22.0.0",
"c8": "^10.0.0",
"prettier": "^3.0.0",
"remark-cli": "^12.0.0",
"remark-preset-wooorm": "^10.0.0",
"retext": "^9.0.0",
"type-coverage": "^2.0.0",
"typescript": "^5.0.0",
"xo": "^0.59.0"
},
"exports": "./index.js",
"files": [
"lib/",
"index.d.ts.map",
"index.d.ts",
"index.js"
],
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
},
"keywords": [
"dashes",
"ellipses",
"quotes",
"retext",
"retext-plugin",
"smartypants",
"typography",
"unified"
],
"license": "MIT",
"name": "retext-smartypants",
"prettier": {
"bracketSpacing": false,
"singleQuote": true,
"semi": false,
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false
},
"remarkConfig": {
"plugins": [
"remark-preset-wooorm"
]
},
"repository": "retextjs/retext-smartypants",
"scripts": {
"build": "tsc --build --clean && tsc --build && type-coverage",
"format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix",
"prepack": "npm run build && npm run format",
"test-api": "node --conditions development test.js",
"test-coverage": "c8 --100 --check-coverage --reporter lcov npm run test-api",
"test": "npm run build && npm run format && npm run test-coverage"
},
"sideEffects": false,
"typeCoverage": {
"atLeast": 100,
"detail": true,
"ignoreCatch": true,
"strict": true
},
"type": "module",
"version": "6.2.0",
"xo": {
"prettier": true
}
}

236
node_modules/retext-smartypants/readme.md generated vendored Normal file
View File

@@ -0,0 +1,236 @@
# retext-smartypants
[![Build][build-badge]][build]
[![Coverage][coverage-badge]][coverage]
[![Downloads][downloads-badge]][downloads]
[![Size][size-badge]][size]
[![Sponsors][sponsors-badge]][collective]
[![Backers][backers-badge]][collective]
[![Chat][chat-badge]][chat]
**[retext][]** plugin to apply [SmartyPants][].
## Contents
* [What is this?](#what-is-this)
* [When should I use this?](#when-should-i-use-this)
* [Install](#install)
* [Use](#use)
* [API](#api)
* [`unified().use(retextSmartypants[, options])`](#unifieduseretextsmartypants-options)
* [`Options`](#options)
* [`QuoteCharacterMap`](#quotecharactermap)
* [Types](#types)
* [Compatibility](#compatibility)
* [Contribute](#contribute)
* [License](#license)
## What is this?
This package is a [unified][] ([retext][]) plugin to apply [SmartyPants][] to
the syntax tree.
It replaces straight/typewriter punctuation marks and symbols with smart/curly
marks and symbols.
## When should I use this?
You can use this plugin any time there straight marks and symbols in prose,
but you want to use smart ones instead.
## Install
This package is [ESM only][esm].
In Node.js (version 16+), install with [npm][]:
```sh
npm install retext-smartypants
```
In Deno with [`esm.sh`][esmsh]:
```js
import retextSmartypants from 'https://esm.sh/retext-smartypants@6'
```
In browsers with [`esm.sh`][esmsh]:
```html
<script type="module">
import retextSmartypants from 'https://esm.sh/retext-smartypants@6?bundle'
</script>
```
## Use
```js
import {retext} from 'retext'
import retextSmartypants from 'retext-smartypants'
const file = await retext()
.use(retextSmartypants)
.process('He said, "A \'simple\' english sentence. . ."')
console.log(String(file))
```
Yields:
```txt
He said, “A simple english sentence…”
```
## API
This package exports no identifiers.
The default export is [`retextSmartypants`][api-retext-smartypants].
### `unified().use(retextSmartypants[, options])`
Replace straight punctuation marks with curly ones.
###### Parameters
* `options` ([`Options`][api-options], optional)
— configuration
###### Returns
Transform ([`Transformer`][unified-transformer]).
### `Options`
Configuration (TypeScript type).
###### Fields
* `backticks` (`boolean` or `'all'`, default: `true`)
— transform backticks;
when `true`, turns double backticks into an opening double quote and
double straight single quotes into a closing double quote;
when `'all'`, does that and turns single backticks into an opening
single quote and a straight single quotes into a closing single smart
quote;
`quotes: false` must be used with `backticks: 'all'`
* `closingQuotes` ([`QuoteCharacterMap`][api-quote-character-map], default:
`{double: '”', single: ''}`)
— closing quotes to use
* `dashes` (`'inverted'` or `'oldschool'` or `boolean`, default: `true`)
— transform dashes;
when `true`, turns two dashes into an em dash character;
when `'oldschool'`, turns three dashes into an em dash and two into an en
dash;
when `'inverted'`, turns three dashes into an en dash and two into an em
dash
* `ellipses` (`'spaced'` or `'unspaced'` or `boolean`, default: `true`)
— transform triple dots;
when `'spaced'`, turns triple dots with spaces into ellipses;
when `'unspaced'`, turns triple dots without spaces into ellipses;
when `true`, turns triple dots with or without spaces into ellipses
* `openingQuotes` ([`QuoteCharacterMap`][api-quote-character-map], default:
`{double: '“', single: ''}`)
— opening quotes to use
* `quotes` (`boolean`, default: `true`)
— transform straight quotes into smart quotes
### `QuoteCharacterMap`
Quote characters (TypeScript type).
###### Fields
* `double` (`string`)
— character to use for double quotes
* `single` (`string`)
— character to use for single quotes
## Types
This package is fully typed with [TypeScript][].
It exports the additional types [`Options`][api-options] and
[`QuoteCharacterMap`][api-quote-character-map].
## Compatibility
Projects maintained by the unified collective are compatible with maintained
versions of Node.js.
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, `retext-smartypants@^6`,
compatible with Node.js 16.
## Contribute
See [`contributing.md`][contributing] in [`retextjs/.github`][health] for ways
to get started.
See [`support.md`][support] for ways to get help.
This project has a [code of conduct][coc].
By interacting with this repository, organization, or community you agree to
abide by its terms.
## License
[MIT][license] © [Titus Wormer][author]
<!-- Definitions -->
[build-badge]: https://github.com/retextjs/retext-smartypants/workflows/main/badge.svg
[build]: https://github.com/retextjs/retext-smartypants/actions
[coverage-badge]: https://img.shields.io/codecov/c/github/retextjs/retext-smartypants.svg
[coverage]: https://codecov.io/github/retextjs/retext-smartypants
[downloads-badge]: https://img.shields.io/npm/dm/retext-smartypants.svg
[downloads]: https://www.npmjs.com/package/retext-smartypants
[size-badge]: https://img.shields.io/bundlejs/size/retext-smartypants
[size]: https://bundlejs.com/?q=retext-smartypants
[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/retextjs/retext/discussions
[npm]: https://docs.npmjs.com/cli/install
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[esmsh]: https://esm.sh
[typescript]: https://www.typescriptlang.org
[health]: https://github.com/retextjs/.github
[contributing]: https://github.com/retextjs/.github/blob/main/contributing.md
[support]: https://github.com/retextjs/.github/blob/main/support.md
[coc]: https://github.com/retextjs/.github/blob/main/code-of-conduct.md
[license]: license
[author]: https://wooorm.com
[smartypants]: https://daringfireball.net/projects/smartypants
[retext]: https://github.com/retextjs/retext
[unified]: https://github.com/unifiedjs/unified
[unified-transformer]: https://github.com/unifiedjs/unified#transformer
[api-options]: #options
[api-quote-character-map]: #quotecharactermap
[api-retext-smartypants]: #unifieduseretextsmartypants-options