Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/medfreeman/remark-generic-extensions
!Extension[Content](Argument){Properties} -> :tada: — commonmark generic directive extension for remark
https://github.com/medfreeman/remark-generic-extensions
commonmark html markdown react remark remark-plugin
Last synced: about 2 months ago
JSON representation
!Extension[Content](Argument){Properties} -> :tada: — commonmark generic directive extension for remark
- Host: GitHub
- URL: https://github.com/medfreeman/remark-generic-extensions
- Owner: medfreeman
- License: apache-2.0
- Created: 2017-05-11T23:45:31.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2020-05-31T00:30:33.000Z (over 4 years ago)
- Last Synced: 2024-10-10T16:41:53.846Z (2 months ago)
- Topics: commonmark, html, markdown, react, remark, remark-plugin
- Language: JavaScript
- Homepage:
- Size: 7 MB
- Stars: 24
- Watchers: 3
- Forks: 5
- Open Issues: 39
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# remark-generic-extensions
[![npm version](https://img.shields.io/npm/v/remark-generic-extensions.svg)](https://www.npmjs.com/package/remark-generic-extensions)
[![npm](https://img.shields.io/npm/dt/remark-generic-extensions.svg?style=flat-square)](https://npmjs.com/package/remark-generic-extensions)
[![CircleCI](https://img.shields.io/circleci/project/github/medfreeman/remark-generic-extensions/master.svg)](https://circleci.com/gh/medfreeman/remark-generic-extensions)
[![Coverage Status](https://img.shields.io/coveralls/medfreeman/remark-generic-extensions/master.svg)](https://coveralls.io/github/medfreeman/remark-generic-extensions?branch=master)
[![Greenkeeper badge](https://badges.greenkeeper.io/medfreeman/remark-generic-extensions.svg)](https://greenkeeper.io/)
[![dependencies Status](https://img.shields.io/david/medfreeman/remark-generic-extensions.svg)](https://david-dm.org/medfreeman/remark-generic-extensions)
[![devDependencies Status](https://img.shields.io/david/dev/medfreeman/remark-generic-extensions.svg)](https://david-dm.org/medfreeman/remark-generic-extensions?type=dev)[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
Allows the use of [commonmark generic directive extension](https://github.com/jgm/CommonMark/wiki/Generic-Directive-Extension-List) in markdown,
generating components through [remark-html](https://github.com/wooorm/remark-html) or [remark-react](https://github.com/mapbox/remark-react).This module also works in browser environments.
[📖 **Release Notes**](./CHANGELOG.md)
### Demo
Here's a demo using [remark-react](https://github.com/mapbox/remark-react) and [react-toolbox](https://github.com/react-toolbox/react-toolbox).
It is made using [create-react-app](https://github.com/facebookincubator/create-react-app), the [source is here](https://github.com/medfreeman/remark-generic-extensions/tree/master/examples/react-toolbox-icon) and can also be run locally.[![Edit medfreeman/remark-generic-extensions: react-toolbox-icon](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/medfreeman/remark-generic-extensions/tree/master/examples/react-toolbox-icon)
## Disclaimer
Remember that the following syntax is experimental in regards to the commonmark spec, and will perhaps never be supported officialy.
```
Generic Directives is still in active discussion in http://talk.commonmark.org/t/generic-directives-plugins-syntax . But for brainstorming purposes, here is some possible extensions to support, or at least adhere to if not included.It might look like !extensionName[](){} for inline
and for block (Current talk page at http://talk.commonmark.org/t/block-directives/802 )
extentionNames: argumentField
:::
...BlockContent...
:::
{ #id .class key1=value key2=value }
```There is a [known bug in remark-react < 4.0.1](https://github.com/mapbox/remark-react/issues/41), that wrongly coerces non-string values to strings.
Make sure to use at least v4.0.1.
## Syntax
### Inline extensions
`!Extension[Content](Argument){Properties}`
:information_source: The extension syntax is validated through [regexes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp), that you can inspect [here](https://github.com/medfreeman/remark-generic-extensions/blob/master/src/utils/regexes.js) if needed
- `Extension` defines the element you want to use
It matches the `\w` character class.
```
Matches any alphanumeric character from the basic Latin alphabet, including the underscore. Equivalent to [A-Za-z0-9_].
```- `Content` defines the element content
It matches everything but the `]` character.
It can be mapped to any hast element property or value, see [placeholders](#placeholders).- `Argument` defines the element argument
It matches everything but the `)` character.
It can be mapped to any hast element property or value, see [placeholders](#placeholders).- `Properties` defines the element properties
They can have leading and / or trailing spaces before / after the opening / closing braces.
The different properties are separated by spaces, and so each of them match any character but spaces, except for quoted properties.### Block extensions
```
Extension: Argument
:::
[Content]
:::
{Properties}
```:information_source: The extension syntax is validated through [regexes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp), that you can inspect [here](https://github.com/medfreeman/remark-generic-extensions/blob/master/src/utils/regexes.js) if needed
- `Extension` defines the element you want to use
It matches the `\w` character class.
```
Matches any alphanumeric character from the basic Latin alphabet, including the underscore. Equivalent to [A-Za-z0-9_].
```- `Argument` defines the element argument
It matches everything but a line break.
It can be mapped to any hast element property or value, see [placeholders](#placeholders).- `Content` defines the element content
It matches everything, and stops at the next `:::` occurence.
Leading and trailing line breaks will be stripped.
It can be mapped to any hast element property or value, see [placeholders](#placeholders).- `Properties` defines the element properties
They can have leading and / or trailing spaces before / after the opening / closing braces.
The different properties are separated by spaces, and so each of them match any character but spaces, except for quoted properties.### Available properties
- id: `#my-id`
It will be applied to the top-level hast element.
- class: `.my-class .my-other-class`It will be applied to the top-level hast element.
- key / value property: `my-prop=my-value`It can be mapped to any hast element property or value, see [placeholders](#placeholders).
- key / value quoted property: `my-other-prop="my value with spaces"`It can be mapped to any hast element property or value, see [placeholders](#placeholders).
- lone property: `my-alone-prop`It can be mapped to any hast element property or value, see [placeholders](#placeholders).
## Installation
```bash
npm install remark-generic-extensions
```OR
```bash
yarn add remark-generic-extensions
```## Usage (es6)
### *with [`remark-react`](https://github.com/mapbox/remark-react)*
See [demo](#demo)
### *with [`remark-html`](https://github.com/wooorm/remark-html)*
Say we have the following file, `example.md`:
```markdown
# Alpha!alert[My message!](my subtext is rad){ #my-alert .custom-alert }
youtube: C8NAYW-Z54o
:::
My featured video!
:::
{ #my-video .custom-video-style spanClassName=custom-span-class }## Bravo
## Delta
```And our script, `example.js`, looks as follows:
```javascript
import vfile from "to-vfile"
import remark from "remark"
import genericExtensions from "remark-generic-extensions"
import html from "remark-html"remark()
.use(genericExtensions,
{
elements: {
alert: {
html: {
tagName: "span",
children: [
{
type: "element",
tagName: "i",
properties: {
className: "fa fa-exclamation",
ariaHidden: true
}
},
{
type: "element",
tagName: "span",
children: [
{
type: "text",
value: "::content::"
}
]
},
{
type: "element",
tagName: "span",
properties: {
className: "subtext"
},
children: [
{
type: "text",
value: "::argument::"
}
]
}
]
}
}
},
youtube: {
html: {
tagName: "div",
children: [
{
type: "element",
tagName: "iframe",
properties: {
width: 420,
height: 315,
src: "https://www.youtube.com/embed/::argument::"
}
},
{
tagName: "span",
properties: {
className: "::prop::spanClassName::"
},
children: [
{
type: "text",
value: "::content::"
}
]
}
]
}
}
}
)
.use(html)
.process(vfile.readSync('example.md'), (err, file) => {
if (err) throw err
console.log(String(file))
})
```Now, running `node example` yields (indented):
```html
Alpha
My message!
my subtext is rad
My featured video!Bravo
Delta
```## API
### `remark().use(genericExtensions[, options])`
Convert generic extensions in a markdown document to an [hast](https://github.com/syntax-tree/hast) syntax tree,
suitable for rendering to html / react.* Looks for all inline extensions (if providing elements configuration the extension names are case sensitive)
* Tells remark how to interpret them according to the options#### `options` (object)
All options are validated through [joi](https://github.com/hapijs/joi).
You can find the schema [here](https://github.com/medfreeman/remark-generic-extensions/blob/master/src/utils/optionsSchema.js).
In case of error, it will be logged to the console and this module bypassed by remark.##### Properties
- elements ([`Elements`](#elements-object), optional, default `{}`) - A list of inline elements to support
along with their configuration- placeholderAffix (string, optional, default `"::"`) - String that encloses `content`,
`argument` and `prop` tokens in properties
of the `elements` option, for dynamic replacement with properties specified in the markdown element.See [`HastProperties`](#hastproperties-object) for more information.
- debug (boolean, default: `false`) - Whether to show debug messages
through [vfile-reporter](https://github.com/vfile/vfile-reporter)
See [Logging](#logging) for more information.---
#### `Elements` (object)
This object defines the extensions configuration.
The keys are strings corresponding to the inline extension names (i.e. `Icon`).
You can define one or more extensions if needed.
##### Properties
- *extensionName* (string): (object)
- propsDefaultValues (object, optional)
- *propertyName* (string): (any) - default value of the property
It will be applied to items that specify
the corresponding property without a defined value, i.e.example with `highlight` property on `icon` extension (es6)
```javascript
import remark from "remark"
import genericExtensions "remark-generic-extensions"
import html from "remark-html"remark()
.use(genericExtensions,
{
elements: {
icon: {
propsDefaultValues: {
highlight: true,
}
}
}
}
)
.use(html)
.process("!icon{highlight}", (err, file) => {
if (err) throw err
console.log(String(file))
})
```Running this example would yield `
`
- html (object, optional, mutually exclusive with `replace`) - html element representation used for rendering the extension
- tagName (string, optional, defaults to the extension name) - html5 element tag name
- children ([`Hast`](#hast-arrayobject), optional) - the element children
- properties ([`HastProperties`](#hastproperties-object), optional) - the element properties- replace (function, optional, mutually exclusive with `html`) - function whose return value will be used for rendering the extension
arguments:
- type (enum[string], "inline-extension" OR "block-extension")
- element (object)
- *extensionName* (string) - same as above
- content (string) - the element content
- argument (string) - the element argument
- properties (object) - A map of computed properties names / values
- warning (function(string)) - VFile warning function
- debug (function(string)) - VFile debug function---
#### `Hast` (array[object])
This structure is a [hast](https://github.com/syntax-tree/hast) tree, with a few restrictions.
It is recursive, the `children` property also being of `Hast` type.
##### Properties
- type (enum[string], optional, default `"element"`) - hast node type
- element
- comment
- text
- tagName (string, required when type === "element") - html5 element tag name
- value (string, required when type === ("comment" || "text")) - comment or text content, supports [placeholders](#placeholders)
- children ([`Hast`](#hast-arrayobject), optional) - the element children
- properties ([`HastProperties`](#hastproperties-object)) - the element properties---
#### `HastProperties` (object)
This object pairs are mapped to [hast properties](https://github.com/syntax-tree/hast#properties), and thus follow the same rules.
##### Properties
- *propertyName* (string, except "class" && "for"): (enum)
- (string) - When a property value is a string,
it supports [placeholders](#placeholders) that will be replaced by their corresponding value.- (any) - A property value can also be of any other type
:information_source: Any property present in a markdown extension and not referenced by a placeholder will be applied to the top-level element.
:information_source: If the `content` property is not referenced on a block element, it will be applied to a child `text` node of the top-level element.
## Placeholders
The `value` property and all `properties` members in [`Hast`](#hast-arrayobject) children support placeholders.
The available placeholders are:
- "::content::" -> will be replaced by the `content` part of the extension in markdown (the part between `[]`)
- "::argument::" -> will be replaced by the `argument` part of the extension in markdown (the part between `()`)
- "::prop::*property*::" -> will be replaced by the corresponding `property` value present in the extension in markdown (in the part between `{}`):information_source: the available properties are `id`, `className` or any other property defined in your markdown.
Specifying the [`placeholderAffix` option](#properties) allows changing the placeholders.
For example, using "||" would make the available placeholders become "||content||", "||argument||" and "||prop||*property*||".## Logging
All logging, except the [options validation](#options-object) that is directly logged to the console, takes place through [vfile-reporter](https://github.com/vfile/vfile-reporter).
It allows having nice error messages with positional information, and is also the standard way of logging with [unifiedjs](https://github.com/unifiedjs/unified).
By default, this module logs warnings, but enabling the [`debug` option](#properties) will also log debug messages, useful for troubleshooting.
logging example (es6)
```javascript
import remark from "remark"
import genericExtensions "remark-generic-extensions"
import html from "remark-html"
import report from "vfile-reporter"remark()
.use(genericExtensions, {})
.use(html)
.process(input, function(err, file) {
console.log(report(err || file))
})
```debugging example (es6)
```javascript
import remark from "remark"
import genericExtensions "remark-generic-extensions"
import html from "remark-html"
import report from "vfile-reporter"remark()
.use(genericExtensions, { debug: true })
.use(html)
.process(input, function(err, file) {
console.log(report(err || file))
})
```---
## CONTRIBUTING
* ⇄ Pull requests and ★ Stars are always welcome.
* For bugs and feature requests, please create an issue.
* Pull requests must be accompanied by passing automated tests (`$ yarn test`).## LICENSE
[Apache License 2.0](./LICENSE)
Copyright (c) Mehdi Lahlou