Compare commits

..

No commits in common. "main" and "1.0.0" have entirely different histories.
main ... 1.0.0

21 changed files with 280 additions and 725 deletions

View file

@ -1,9 +1,9 @@
root = true root = true
[*] [*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space indent_style = space
insert_final_newline = true indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = true

View file

@ -1,13 +0,0 @@
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: unifiedjs/beep-boop-beta@main
with:
repo-token: ${{secrets.GITHUB_TOKEN}}
name: bb
on:
issues:
types: [closed, edited, labeled, opened, reopened, unlabeled]
pull_request_target:
types: [closed, edited, labeled, opened, reopened, unlabeled]

View file

@ -1,21 +0,0 @@
jobs:
main:
name: ${{matrix.node}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{matrix.node}}
- run: npm install
- run: npm test
- uses: codecov/codecov-action@v5
strategy:
matrix:
node:
- lts/hydrogen
- node
name: main
on:
- pull_request
- push

7
.gitignore vendored
View file

@ -1,9 +1,6 @@
*.d.ts
*.log
*.map
*.tsbuildinfo
.DS_Store .DS_Store
*.log
.nyc_output/
coverage/ coverage/
node_modules/ node_modules/
yarn.lock yarn.lock
!/index.d.ts

1
.npmrc
View file

@ -1,2 +1 @@
ignore-scripts=true
package-lock=false package-lock=false

View file

@ -1,2 +1,3 @@
*.md
coverage/ coverage/
*.json
*.md

View file

@ -1 +0,0 @@
test/fixtures/

5
.travis.yml Normal file
View file

@ -0,0 +1,5 @@
language: node_js
node_js:
- lts/dubnium
- node
after_script: bash <(curl -s https://codecov.io/bash)

15
index.d.ts vendored
View file

@ -1,15 +0,0 @@
import type {ToMarkdownOptions} from 'mdast-util-directive'
export {default} from './lib/index.js'
/**
* Configuration for `remark-directive`.
*
* Currently supports
* `collapseEmptyAttributes`,
* `preferShortcut`,
* `preferUnquoted`,
* `quoteSmart`,
* and `quote` as serialization options.
*/
export interface Options extends ToMarkdownOptions {}

View file

@ -1,2 +1,39 @@
// Note: types exposed from `index.d.ts`. 'use strict'
export {default} from './lib/index.js'
var syntax = require('micromark-extension-directive')
var fromMarkdown = require('mdast-util-directive/from-markdown')
var toMarkdown = require('mdast-util-directive/to-markdown')
var warningIssued
module.exports = directive
function directive() {
var data = this.data()
/* istanbul ignore next - old remark. */
if (
!warningIssued &&
((this.Parser &&
this.Parser.prototype &&
this.Parser.prototype.blockTokenizers) ||
(this.Compiler &&
this.Compiler.prototype &&
this.Compiler.prototype.visitors))
) {
warningIssued = true
console.warn(
'[remark-directive] Warning: please upgrade to remark 13 to use this plugin'
)
}
add('micromarkExtensions', syntax())
add('fromMarkdownExtensions', fromMarkdown)
add('toMarkdownExtensions', toMarkdown)
function add(field, value) {
/* istanbul ignore if - other extensions. */
if (data[field]) data[field].push(value)
else data[field] = [value]
}
}

View file

@ -1,38 +0,0 @@
/**
* @import {} from 'mdast-util-directive'
* @import {Root} from 'mdast'
* @import {} from 'remark-arse'
* @import {} from 'remark-stringify'
* @import {Processor} from 'unified'
*/
import {
directiveFromMarkdown,
directiveToMarkdown,
} from "mdast-util-directive";
import { directive } from "micromark-extension-directive";
/**
* Add support for generic directives.
*
* ###### Notes
*
* Doesnt handle the directives: create your own plugin to do that.
*
* @returns {undefined}
* Nothing.
*/
export default function remarkDirective() {
const data = this.data();
const micromarkExtensions =
data.micromarkExtensions || (data.micromarkExtensions = []);
const fromMarkdownExtensions =
data.fromMarkdownExtensions || (data.fromMarkdownExtensions = []);
const toMarkdownExtensions =
data.toMarkdownExtensions || (data.toMarkdownExtensions = []);
micromarkExtensions.push(directive());
fromMarkdownExtensions.push(directiveFromMarkdown());
toMarkdownExtensions.push(directiveToMarkdown());
}

View file

@ -1,6 +1,6 @@
(The MIT License) (The MIT License)
Copyright (c) Titus Wormer <tituswormer@gmail.com> Copyright (c) 2020 Titus Wormer <tituswormer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the

View file

@ -1,106 +1,84 @@
{ {
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)", "name": "remark-directive",
"bugs": "https://github.com/remarkjs/remark-directive/issues", "version": "1.0.0",
"contributors": ["Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)"], "description": "remark plugin to support directives",
"dependencies": { "license": "MIT",
"@types/mdast": "^4.0.0", "keywords": [
"mdast-util-directive": "^3.0.0", "unified",
"micromark-extension-directive": "git+https://git.v-sli.me/HidemaruOwO/micromark-extension-directive.git#fix.1", "remark",
"unified": "^11.0.0" "remark-plugin",
}, "plugin",
"description": "remark plugin to support directives", "mdast",
"devDependencies": { "markdown",
"@types/node": "^22.0.0", "generic",
"c8": "^10.0.0", "directive",
"is-hidden": "^2.0.0", "container"
"prettier": "^3.0.0", ],
"remark": "^15.0.0", "repository": "remarkjs/remark-directive",
"remark-cli": "^12.0.0", "bugs": "https://github.com/remarkjs/remark-directive/issues",
"remark-preset-wooorm": "^10.0.0", "funding": {
"to-vfile": "^8.0.0", "type": "opencollective",
"type-coverage": "^2.0.0", "url": "https://opencollective.com/unified"
"typescript": "^5.0.0", },
"xo": "^0.60.0" "author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
}, "contributors": [
"exports": "./index.js", "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)"
"files": ["index.d.ts", "index.js", "lib/"], ],
"funding": { "types": "types/index.d.ts",
"type": "opencollective", "files": [
"url": "https://opencollective.com/unified" "types/index.d.ts",
}, "index.js"
"keywords": [ ],
"container", "dependencies": {
"directive", "mdast-util-directive": "^1.0.0",
"generic", "micromark-extension-directive": "^1.0.0"
"markdown", },
"mdast", "devDependencies": {
"plugin", "dtslint": "^4.0.0",
"remark-plugin", "is-hidden": "^1.0.0",
"remark", "not": "^0.1.0",
"unified" "nyc": "^15.0.0",
], "prettier": "^2.0.0",
"license": "MIT", "remark": "^13.0.0",
"name": "remark-directive", "remark-cli": "^9.0.0",
"prettier": { "remark-preset-wooorm": "^8.0.0",
"bracketSpacing": false, "tape": "^5.0.0",
"singleQuote": true, "to-vfile": "^6.0.0",
"semi": false, "unified": "^9.0.0",
"tabWidth": 2, "xo": "^0.34.0"
"trailingComma": "none", },
"useTabs": false "scripts": {
}, "format": "remark . -qfo --ignore-pattern test/ && prettier . -w --loglevel warn && xo --fix",
"remarkConfig": { "test-api": "node test",
"plugins": ["remark-preset-wooorm"] "test-coverage": "nyc --reporter lcov tape test/index.js",
}, "test-types": "dtslint types",
"repository": "remarkjs/remark-directive", "test": "npm run format && npm run test-coverage && npm run test-types"
"scripts": { },
"build": "tsc --build --clean && tsc --build && type-coverage", "nyc": {
"format": "remark --frail --output --quiet -- . && prettier --log-level warn --write -- . && xo --fix", "check-coverage": true,
"prepack": "npm run build && npm run format", "lines": 100,
"test-api": "node --conditions development test/index.js", "functions": 100,
"test-coverage": "c8 --100 --reporter lcov -- npm run test-api", "branches": 100
"test": "npm run build && npm run format && npm run test-coverage" },
}, "prettier": {
"sideEffects": false, "tabWidth": 2,
"typeCoverage": { "useTabs": false,
"atLeast": 100, "singleQuote": true,
"strict": true "bracketSpacing": false,
}, "semi": false,
"type": "module", "trailingComma": "none"
"version": "3.0.1", },
"xo": { "xo": {
"overrides": [ "prettier": true,
{ "esnext": false,
"files": ["**/*.d.ts"], "rules": {
"rules": { "unicorn/no-fn-reference-in-iterator": "off",
"@typescript-eslint/array-type": [ "unicorn/prefer-optional-catch-binding": "off"
"error", }
{ },
"default": "generic" "remarkConfig": {
} "plugins": [
], "preset-wooorm"
"@typescript-eslint/ban-types": [ ]
"error", }
{
"extendDefaults": true
}
],
"@typescript-eslint/consistent-type-definitions": [
"error",
"interface"
]
}
},
{
"files": ["test/**/*.js"],
"rules": {
"no-await-in-loop": "off"
}
}
],
"prettier": true,
"rules": {
"logical-assignment-operators": "off"
}
}
} }

502
readme.md
View file

@ -8,448 +8,86 @@
[![Backers][backers-badge]][collective] [![Backers][backers-badge]][collective]
[![Chat][chat-badge]][chat] [![Chat][chat-badge]][chat]
**[remark][]** plugin to support the [generic directives [**remark**][remark] plugin to support the [generic directives proposal][prop]
proposal][commonmark-prop] (`:cite[smith04]`, (`:cite[smith04]`, `::youtube[Video of a cat in a box]{v=01ab2cd3efg}`, and
`::youtube[Video of a cat in a box]{v=01ab2cd3efg}`, and such). such).
## Contents ## Important!
* [What is this?](#what-is-this) This plugin is made for the new parser in remark
* [When should I use this?](#when-should-i-use-this) ([`micromark`](https://github.com/micromark/micromark),
* [Install](#install) see [`remarkjs/remark#536`](https://github.com/remarkjs/remark/pull/536)).
* [Use](#use) Use this plugin for remark 13+.
* [API](#api)
* [`unified().use(remarkDirective[, options])`](#unifieduseremarkdirective-options)
* [`Options`](#options)
* [Examples](#examples)
* [Example: YouTube](#example-youtube)
* [Example: Styled blocks](#example-styled-blocks)
* [Authoring](#authoring)
* [HTML](#html)
* [CSS](#css)
* [Syntax](#syntax)
* [Syntax tree](#syntax-tree)
* [Types](#types)
* [Compatibility](#compatibility)
* [Security](#security)
* [Related](#related)
* [Contribute](#contribute)
* [License](#license)
## What is this?
This package is a [unified][] ([remark][]) plugin to add support for directives:
one syntax for arbitrary extensions in markdown.
## When should I use this?
Directives are one of the four ways to extend markdown: an arbitrary extension
syntax (see [Extending markdown][micromark-extending-markdown] in micromarks
docs for the alternatives and more info).
This mechanism works well when you control the content: who authors it, what
tools handle it, and where its displayed.
When authors can read a guide on how to embed a tweet but are not expected to
know the ins and outs of HTML or JavaScript.
Directives dont work well if you dont know who authors content, what tools
handle it, and where it ends up.
Example use cases are a docs website for a project or product, or blogging
tools and static site generators.
If you *just* want to turn markdown into HTML (with maybe a few extensions such
as this one), we recommend [`micromark`][micromark] with
[`micromark-extension-directive`][micromark-extension-directive] instead.
If you dont use plugins and want to access the syntax tree, you can use
[`mdast-util-from-markdown`][mdast-util-from-markdown] with
[`mdast-util-directive`][mdast-util-directive].
## Install ## Install
This package is [ESM only][esm]. [npm][]:
In Node.js (version 16+), install with [npm][]:
```sh ```sh
npm install remark-directive npm install remark-directive
``` ```
In Deno with [`esm.sh`][esmsh]:
```js
import remarkDirective from 'https://esm.sh/remark-directive@3'
```
In browsers with [`esm.sh`][esmsh]:
```html
<script type="module">
import remarkDirective from 'https://esm.sh/remark-directive@3?bundle'
</script>
```
## Use ## Use
Say our document `example.md` contains: Say we have the following file, `example.md`:
```markdown ```markdown
:::main{#readme}
Lorem:br
ipsum.
::hr{.red}
A :i[lovely] language know as :abbr[HTML]{title="HyperText Markup Language"}.
:::
``` ```
…and our module `example.js` contains: And our script, `example.js`, looks as follows:
```js ```js
/** var vfile = require('to-vfile')
* @import {} from 'mdast-util-directive' var report = require('vfile-reporter')
* @import {} from 'mdast-util-to-hast' var unified = require('unified')
* @import {Root} from 'mdast' var parse = require('remark-parse')
*/ var directive = require('remark-directive')
var stringify = require('rehype-stringify')
import {h} from 'hastscript' unified()
import rehypeFormat from 'rehype-format' .use(parse)
import rehypeStringify from 'rehype-stringify' .use(directive)
import remarkDirective from 'remark-directive' .use(remark2rehype)
import remarkParse from 'remark-parse' .use(stringify)
import remarkRehype from 'remark-rehype' .process(vfile.readSync('example.md'), function (err, file) {
import {read} from 'to-vfile' console.error(report(err || file))
import {unified} from 'unified' console.log(String(file))
import {visit} from 'unist-util-visit' })
const file = await unified()
.use(remarkParse)
.use(remarkDirective)
.use(myRemarkPlugin)
.use(remarkRehype)
.use(rehypeFormat)
.use(rehypeStringify)
.process(await read('example.md'))
console.log(String(file))
// This plugin is an example to let users write HTML with directives.
// Its informative but rather useless.
// See below for others examples.
function myRemarkPlugin() {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
return function (tree) {
visit(tree, function (node) {
if (
node.type === 'containerDirective' ||
node.type === 'leafDirective' ||
node.type === 'textDirective'
) {
const data = node.data || (node.data = {})
const hast = h(node.name, node.attributes || {})
data.hName = hast.tagName
data.hProperties = hast.properties
}
})
}
}
``` ```
…then running `node example.js` yields: Now, running `node example` yields:
```html ```html
<main id="readme">
<p>Lorem<br>ipsum.</p>
<hr class="red">
<p>A <i>lovely</i> language know as <abbr title="HyperText Markup Language">HTML</abbr>.</p>
</main>
``` ```
## API ## API
This package exports no identifiers. ### `remark().use(directive)`
The default export is [`remarkDirective`][api-remark-directive].
### `unified().use(remarkDirective[, options])` Configures remark so that it can parse and serialize directives.
Doesnt handle the directives: [create your own plugin][create-plugin] to do
Add support for generic directives. that.
See the [micromark extension for the syntax][syntax] and the
###### Parameters [mdast utility for the syntax tree][syntax-tree].
* `options` ([`Options`][api-options], optional)
— configuration
###### Returns
Nothing (`undefined`).
###### Notes
Doesnt handle the directives:
[create your own plugin][unified-create-plugin] to do that.
### `Options`
Configuration (TypeScript type).
###### Fields
* `collapseEmptyAttributes`
(`boolean`, default: `true`)
— collapse empty attributes: get `title` instead of `title=""`
* `preferShortcut`
(`boolean`, default: `true`)
— prefer `#` and `.` shortcuts for `id` and `class`
* `preferUnquoted`
(`boolean`, default: `false`)
— leave attributes unquoted if that results in less bytes
* `quoteSmart`
(`boolean`, default: `false`)
— use the other quote if that results in less bytes
* `quote`
(`'"'` or `"'"`,
default: the [`quote`][quote] used by `remark-stringify` for titles)
— preferred quote to use around attribute values
## Examples
### Example: YouTube
This example shows how directives can be used for YouTube embeds.
Its based on the example in Use above.
If `myRemarkPlugin` was replaced with this function:
```js
/**
* @import {} from 'mdast-util-directive'
* @import {} from 'mdast-util-to-hast'
* @import {Root} from 'mdast'
* @import {VFile} from 'vfile'
*/
import {visit} from 'unist-util-visit'
// This plugin is an example to turn `::youtube` into iframes.
function myRemarkPlugin() {
/**
* @param {Root} tree
* Tree.
* @param {VFile} file
* File.
* @returns {undefined}
* Nothing.
*/
return (tree, file) => {
visit(tree, function (node) {
if (
node.type === 'containerDirective' ||
node.type === 'leafDirective' ||
node.type === 'textDirective'
) {
if (node.name !== 'youtube') return
const data = node.data || (node.data = {})
const attributes = node.attributes || {}
const id = attributes.id
if (node.type === 'textDirective') {
file.fail(
'Unexpected `:youtube` text directive, use two colons for a leaf directive',
node
)
}
if (!id) {
file.fail('Unexpected missing `id` on `youtube` directive', node)
}
data.hName = 'iframe'
data.hProperties = {
src: 'https://www.youtube.com/embed/' + id,
width: 200,
height: 200,
frameBorder: 0,
allow: 'picture-in-picture',
allowFullScreen: true
}
}
})
}
}
```
…and `example.md` contains:
```markdown
# Cat videos
::youtube[Video of a cat in a box]{#01ab2cd3efg}
```
…then running `node example.js` yields:
```html
<h1>Cat videos</h1>
<iframe src="https://www.youtube.com/embed/01ab2cd3efg" width="200" height="200" frameborder="0" allow="picture-in-picture" allowfullscreen>Video of a cat in a box</iframe>
```
### Example: Styled blocks
> 👉 **Note**: This is sometimes called admonitions, callouts, etc.
This example shows how directives can be used to style blocks.
Its based on the example in Use above.
If `myRemarkPlugin` was replaced with this function:
```js
/**
* @import {} from 'mdast-util-directive'
* @import {} from 'mdast-util-to-hast'
* @import {Root} from 'mdast'
*/
import {h} from 'hastscript'
import {visit} from 'unist-util-visit'
// This plugin is an example to turn `::note` into divs, passing arbitrary
// attributes.
function myRemarkPlugin() {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
return (tree) => {
visit(tree, (node) => {
if (
node.type === 'containerDirective' ||
node.type === 'leafDirective' ||
node.type === 'textDirective'
) {
if (node.name !== 'note') return
const data = node.data || (node.data = {})
const tagName = node.type === 'textDirective' ? 'span' : 'div'
data.hName = tagName
data.hProperties = h(tagName, node.attributes || {}).properties
}
})
}
}
```
…and `example.md` contains:
```markdown
# How to use xxx
You can use xxx.
:::note{.warning}
if you chose xxx, you should also use yyy somewhere…
:::
```
…then running `node example` yields:
```html
<h1>How to use xxx</h1>
<p>You can use xxx.</p>
<div class="warning">
<p>if you chose xxx, you should also use yyy somewhere…</p>
</div>
```
## Authoring
When authoring markdown with directives, keep in mind that they dont work in
most places.
On your own site it can be great!
## HTML
You can define how directives are turned into HTML.
If directives are not handled, they do not emit anything.
## CSS
How to display directives is left as an exercise for the reader.
## Syntax
See [*Syntax* in
`micromark-extension-directive`](https://github.com/micromark/micromark-extension-directive#syntax).
## Syntax tree
See [*Syntax tree* in
`mdast-util-directive`](https://github.com/syntax-tree/mdast-util-directive#syntax-tree).
## Types
This package is fully typed with [TypeScript][].
It exports no additional options.
If youre working with the syntax tree, you can register the new node types
with `@types/mdast` by adding a reference:
```js
/**
* @import {} from 'mdast-util-directive'
* @import {Root} from 'mdast'
*/
import {visit} from 'unist-util-visit'
function myRemarkPlugin() {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
return (tree) => {
visit(tree, function (node) {
console.log(node) // `node` can now be one of the nodes for directives.
})
}
}
```
## 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, `remark-directive@^3`,
compatible with Node.js 16.
## Security ## Security
Use of `remark-directive` does not involve **[rehype][]** ([hast][]) or user Use of `remark-directive` does not involve [**rehype**][rehype]
content so there are no openings for [cross-site scripting (XSS)][wiki-xss] ([**hast**][hast]) or user content so there are no openings for [cross-site
attacks. scripting (XSS)][xss] attacks.
## Related ## Related
* [`remark-gfm`](https://github.com/remarkjs/remark-gfm) * [`remark-gfm`](https://github.com/remarkjs/remark-gfm)
— support GFM (autolink literals, footnotes, strikethrough, tables, — GFM
tasklists) * [`remark-github`](https://github.com/remarkjs/remark-github)
* [`remark-frontmatter`](https://github.com/remarkjs/remark-frontmatter) — Autolink references like in GitHub issues, PRs, and comments
— support frontmatter (YAML, TOML, and more) * [`remark-footnotes`](https://github.com/remarkjs/remark-footnotes)
* [`remark-math`](https://github.com/remarkjs/remark-math) — Footnotes
— support math * [`remark-frontmatter`](https://github.com/remarkjs/remark-frontmatter)
* [`remark-mdx`](https://github.com/mdx-js/mdx/tree/main/packages/remark-mdx) — Frontmatter (YAML, TOML, and more)
— support MDX (ESM, JSX, expressions) * [`remark-math`](https://github.com/remarkjs/remark-math)
— Math
## Contribute ## Contribute
@ -467,9 +105,9 @@ abide by its terms.
<!-- Definitions --> <!-- Definitions -->
[build-badge]: https://github.com/remarkjs/remark-directive/workflows/main/badge.svg [build-badge]: https://img.shields.io/travis/remarkjs/remark-directive/main.svg
[build]: https://github.com/remarkjs/remark-directive/actions [build]: https://travis-ci.org/remarkjs/remark-directive
[coverage-badge]: https://img.shields.io/codecov/c/github/remarkjs/remark-directive.svg [coverage-badge]: https://img.shields.io/codecov/c/github/remarkjs/remark-directive.svg
@ -479,9 +117,9 @@ abide by its terms.
[downloads]: https://www.npmjs.com/package/remark-directive [downloads]: https://www.npmjs.com/package/remark-directive
[size-badge]: https://img.shields.io/bundlejs/size/remark-directive [size-badge]: https://img.shields.io/bundlephobia/minzip/remark-directive.svg
[size]: https://bundlejs.com/?q=remark-directive [size]: https://bundlephobia.com/result?p=remark-directive
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
@ -495,50 +133,30 @@ abide by its terms.
[npm]: https://docs.npmjs.com/cli/install [npm]: https://docs.npmjs.com/cli/install
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[esmsh]: https://esm.sh
[health]: https://github.com/remarkjs/.github [health]: https://github.com/remarkjs/.github
[contributing]: https://github.com/remarkjs/.github/blob/main/contributing.md [contributing]: https://github.com/remarkjs/.github/blob/HEAD/contributing.md
[support]: https://github.com/remarkjs/.github/blob/main/support.md [support]: https://github.com/remarkjs/.github/blob/HEAD/support.md
[coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md [coc]: https://github.com/remarkjs/.github/blob/HEAD/code-of-conduct.md
[license]: license [license]: license
[author]: https://wooorm.com [author]: https://wooorm.com
[commonmark-prop]: https://talk.commonmark.org/t/generic-directives-plugins-syntax/444 [remark]: https://github.com/remarkjs/remark
[hast]: https://github.com/syntax-tree/hast [xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
[mdast-util-directive]: https://github.com/syntax-tree/mdast-util-directive
[mdast-util-from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown
[micromark]: https://github.com/micromark/micromark
[micromark-extension-directive]: https://github.com/micromark/micromark-extension-directive
[micromark-extending-markdown]: https://github.com/micromark/micromark#extending-markdown
[quote]: https://github.com/remarkjs/remark/tree/main/packages/remark-stringify#options
[rehype]: https://github.com/rehypejs/rehype [rehype]: https://github.com/rehypejs/rehype
[remark]: https://github.com/remarkjs/remark [hast]: https://github.com/syntax-tree/hast
[typescript]: https://www.typescriptlang.org [prop]: https://talk.commonmark.org/t/generic-directives-plugins-syntax/444
[unified]: https://github.com/unifiedjs/unified [create-plugin]: https://unifiedjs.com/learn/guide/create-a-plugin/
[unified-create-plugin]: https://unifiedjs.com/learn/guide/create-a-plugin/ [syntax]: https://github.com/micromark/micromark-extension-directive#syntax
[wiki-xss]: https://en.wikipedia.org/wiki/Cross-site_scripting [syntax-tree]: https://github.com/syntax-tree/mdast-util-directive#syntax-tree
[api-remark-directive]: #unifieduseremarkdirective-options
[api-options]: #options

View file

@ -30,7 +30,7 @@ b
d d
:::e :::e
* * f * * f
::: :::
> g h > g h

View file

@ -1,78 +1,67 @@
/** 'use strict'
* @typedef {import('mdast').Root} Root
*/
import assert from 'node:assert/strict' var fs = require('fs')
import fs from 'node:fs/promises' var path = require('path')
import process from 'node:process' var test = require('tape')
import test from 'node:test' var vfile = require('to-vfile')
import {isHidden} from 'is-hidden' var unified = require('unified')
import {remark} from 'remark' var remark = require('remark')
import remarkDirective from 'remark-directive' var not = require('not')
var hidden = require('is-hidden')
var directive = require('..')
test('remarkDirective', async function (t) { test('directive()', function (t) {
await t.test('should expose the public api', async function () { t.doesNotThrow(function () {
assert.deepEqual(Object.keys(await import('remark-directive')).sort(), [ remark().use(directive).freeze()
'default' }, 'should not throw if not passed options')
])
})
await t.test('should not throw if not passed options', async function () { t.doesNotThrow(function () {
assert.doesNotThrow(function () { unified().use(directive).freeze()
remark().use(remarkDirective).freeze() }, 'should not throw if without parser or compiler')
})
}) t.end()
}) })
test('fixtures', async function (t) { test('fixtures', function (t) {
const base = new URL('fixtures/', import.meta.url) var base = path.join(__dirname, 'fixtures')
const folders = await fs.readdir(base) var entries = fs.readdirSync(base).filter(not(hidden))
let index = -1 t.plan(entries.length)
while (++index < folders.length) { entries.forEach(each)
const folder = folders[index]
if (isHidden(folder)) continue function each(fixture) {
t.test(fixture, function (st) {
var file = vfile.readSync(path.join(base, fixture, 'input.md'))
var input = String(file.contents)
var outputPath = path.join(base, fixture, 'output.md')
var treePath = path.join(base, fixture, 'tree.json')
var proc
var actual
var output
var expected
await t.test(folder, async function () { proc = remark().use(directive).freeze()
const folderUrl = new URL(folder + '/', base) actual = proc.parse(file)
const inputUrl = new URL('input.md', folderUrl)
const outputUrl = new URL('output.md', folderUrl)
const treeUrl = new URL('tree.json', folderUrl)
const input = String(await fs.readFile(inputUrl))
/** @type {Root} */
let expected
/** @type {string} */
let output
const processor = remark().use(remarkDirective)
const actual = processor.parse(input)
try { try {
output = String(await fs.readFile(outputUrl)) expected = JSON.parse(fs.readFileSync(treePath))
} catch { } catch (_) {
// New fixture.
fs.writeFileSync(treePath, JSON.stringify(actual, 0, 2) + '\n')
expected = actual
}
try {
output = fs.readFileSync(outputPath, 'utf8')
} catch (_) {
output = input output = input
} }
try { st.deepEqual(actual, expected, 'tree')
if ('UPDATE' in process.env) { st.equal(String(proc.processSync(file)), output, 'process')
throw new Error('Updating…')
}
expected = JSON.parse(String(await fs.readFile(treeUrl))) st.end()
} catch {
expected = actual
// New fixture.
await fs.writeFile(treeUrl, JSON.stringify(actual, undefined, 2) + '\n')
}
assert.deepEqual(actual, expected)
assert.equal(String(await processor.process(input)), String(output))
}) })
} }
}) })

View file

@ -1,16 +0,0 @@
{
"compilerOptions": {
"checkJs": true,
"customConditions": ["development"],
"declarationMap": true,
"declaration": true,
"emitDeclarationOnly": true,
"exactOptionalPropertyTypes": true,
"lib": ["es2022"],
"module": "node16",
"strict": true,
"target": "es2022"
},
"exclude": ["coverage/", "node_modules/"],
"include": ["**/*.js", "index.d.ts"]
}

11
types/index.d.ts vendored Normal file
View file

@ -0,0 +1,11 @@
// TypeScript Version: 3.4
import {Plugin} from 'unified'
declare namespace remarkDirective {
type Directive = Plugin<[]>
}
declare const remarkDirective: remarkDirective.Directive
export = remarkDirective

7
types/test.ts Normal file
View file

@ -0,0 +1,7 @@
import unified = require('unified')
import directive = require('remark-directive')
unified().use(directive)
unified().use(directive)
unified().use(directive, {weird: true}) // $ExpectError

10
types/tsconfig.json Normal file
View file

@ -0,0 +1,10 @@
{
"compilerOptions": {
"lib": ["es2015"],
"strict": true,
"baseUrl": ".",
"paths": {
"remark-directive": ["index.d.ts"]
}
}
}

7
types/tslint.json Normal file
View file

@ -0,0 +1,7 @@
{
"extends": "dtslint/dtslint.json",
"rules": {
"semicolon": false,
"whitespace": false
}
}