mirror of
https://github.com/showdownjs/showdown.git
synced 2024-03-22 13:30:55 +08:00
Merge branch 'develop' of github.com:showdownjs/showdown into develop
This commit is contained in:
commit
a9ee330ac2
773
docs/available-options.md
Normal file
773
docs/available-options.md
Normal file
|
@ -0,0 +1,773 @@
|
|||
!!! warning ""
|
||||
Starting from the version `1.6.0` and earlier, all the options are `disabled` by default in the cli tool.
|
||||
|
||||
### backslashEscapesHTMLTags
|
||||
|
||||
Support escaping of HTML tags.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.7.2`
|
||||
|
||||
=== "input"
|
||||
|
||||
```html
|
||||
\<div>foo\</div>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<p><div>foo</div></p>
|
||||
```
|
||||
|
||||
### completeHTMLDocument
|
||||
|
||||
Output a complete HTML document, including `<html>`, `<head>`, and `<body>` tags instead of an HTML fragment.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.8.5`
|
||||
|
||||
### customizedHeaderId
|
||||
|
||||
Set custom ID for a heading.
|
||||
|
||||
!!! warning ""
|
||||
This option can be overridden with the [`noHeaderId`](#noheaderid) option.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.7.0`
|
||||
|
||||
=== "code"
|
||||
|
||||
```html
|
||||
## Sample heading {mycustomid}
|
||||
```
|
||||
|
||||
=== "output"
|
||||
|
||||
```html
|
||||
<h1 id="mycustomid">This is a heading</h1>
|
||||
```
|
||||
|
||||
!!! hint ""
|
||||
For better readability and human-friendliness of the heading IDs, it is also recommended to set the [`ghCompatibleHeaderId`](#ghcompatibleheaderid) option to `true`.
|
||||
|
||||
### disableForced4SpacesIndentedSublists
|
||||
|
||||
Disable the rule of 4 spaces to indent sub-lists. If enabled, this option effectively reverts to the old behavior where you can indent sub-lists with 2 or 3 spaces.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.5.0`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
- one
|
||||
- two
|
||||
|
||||
...
|
||||
|
||||
- one
|
||||
- two
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li>one</li>
|
||||
<li>two</li>
|
||||
</ul>
|
||||
<p>...</p>
|
||||
<ul>
|
||||
<li>one
|
||||
<ul>
|
||||
<li>two</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li>one
|
||||
<ul>
|
||||
<li>two</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>...</p>
|
||||
<ul>
|
||||
<li>one
|
||||
<ul>
|
||||
<li>two</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
### emoji
|
||||
|
||||
Enable emoji support. For more info on available emojis, see https://github.com/showdownjs/showdown/wiki/Emojis (since v.1.8.0)
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.8.0`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
this is a :smile: emoji
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<p>this is a :smile: emoji</p>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<p>this is a 😄 emoji</p>
|
||||
```
|
||||
|
||||
!!! hint "Full list of supported emojies"
|
||||
|
||||
Check the [Showdown Wiki](https://github.com/showdownjs/showdown/wiki/Emojis#emoji-list) for a full list of supported emojies.
|
||||
|
||||
### encodeEmails
|
||||
|
||||
Enable automatic obfuscation of email addresses. During this process, email addresses are encoded via Character Entities, transforming ASCII email addresses into their equivalent decimal entities.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.6.1`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
<myself@example.com>
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<a href="mailto:myself@example.com">myself@example.com</a>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<a href="mailto:myself@example.com">myself@example.com</a>
|
||||
```
|
||||
|
||||
### excludeTrailingPunctuationFromURLs
|
||||
|
||||
Exclude trailing punctuation from autolinked URLs: `.` `!` `?` `(` `)`
|
||||
|
||||
This option applies only to links generated by [`simplifiedAutoLink`](#simplifiedautolink).
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.5.1`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
check this link www.google.com.
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<p>check this link <a href="www.google.com">www.google.com.</a></p>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<p>check this link <a href="www.google.com">www.google.com</a>.</p>
|
||||
```
|
||||
|
||||
### ghCodeBlocks
|
||||
|
||||
Enable support for GFM code block style syntax (fenced codeblocks).
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `true`
|
||||
* introduced in: `0.3.1`
|
||||
|
||||
=== "example"
|
||||
|
||||
```
|
||||
```
|
||||
some code here
|
||||
```
|
||||
```
|
||||
|
||||
### ghCompatibleHeaderId
|
||||
|
||||
Generate heading IDs compatible with GitHub style: spaces are replaced with dashes, and certain non-alphanumeric chars are removed.
|
||||
|
||||
!!! warning ""
|
||||
This option can be overridden with the [`noHeaderId`](#noheaderid) option.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.5.5`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
# This is a heading with @#$%
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<h1 id="thisisaheading">This is a heading</h1>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<h1 id="this-is-a-heading-with-">This is a heading with @#$%</h1>
|
||||
```
|
||||
|
||||
### ghMentions
|
||||
|
||||
Enables support for GitHub `@mentions` that allows you to link to the GitHub profile page of the mentioned username.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.6.0`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
hello there @tivie
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<p>hello there @tivie</p>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<p>hello there <a href="https://www.github.com/tivie">@tivie</a></p>
|
||||
```
|
||||
|
||||
### ghMentionsLink
|
||||
|
||||
Specify where the link generated by `@mentions` should point to. Works only when [`ghMentions: true`](#ghmentions).
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `https://github.com/{u}`
|
||||
* introduced in: `1.6.2`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
hello there @tivie
|
||||
```
|
||||
|
||||
=== "output (value is `https://github.com/{u}`)"
|
||||
|
||||
```html
|
||||
<p>hello there <a href="https://www.github.com/tivie">@tivie</a></p>
|
||||
```
|
||||
|
||||
=== "output (value is `http://mysite.com/{u}/profile`)"
|
||||
|
||||
```html
|
||||
<p>hello there <a href="//mysite.com/tivie/profile">@tivie</a></p>
|
||||
```
|
||||
|
||||
### headerLevelStart
|
||||
|
||||
Set starting level for the heading tags.
|
||||
|
||||
* type: `integer`
|
||||
* default value: `1`
|
||||
* introduced in: `1.1.0`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
# This is a heading
|
||||
```
|
||||
|
||||
=== "output (value is `1`)"
|
||||
|
||||
```html
|
||||
<h1>This is a heading</h1>
|
||||
```
|
||||
|
||||
=== "output (value is `3`)"
|
||||
|
||||
```html
|
||||
<h3>This is a heading</h3>
|
||||
```
|
||||
|
||||
### literalMidWordUnderscores
|
||||
|
||||
Treat underscores in the middle of words as literal characters.
|
||||
|
||||
Underscores allow you to specify the words that should be emphasized. However, in some cases, this may be unwanted behavior. With this option enabled, underscores in the middle of words will no longer be interpreted as `<em>` and `<strong>`, but as literal underscores.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.2.0`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
some text with__underscores__in the middle
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<p>some text with<strong>underscores</strong>in the middle</p>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<p>some text with__underscores__in the middle</p>
|
||||
```
|
||||
|
||||
### metadata
|
||||
|
||||
Enable support for document metadata (front-matter). You can define metadata at the top of a document between `««« »»»` or `--- ---` symbols.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.8.5`
|
||||
|
||||
=== "input"
|
||||
|
||||
```js
|
||||
let ref = `referenced value`;
|
||||
|
||||
var markdown = `
|
||||
---
|
||||
first: Lorem
|
||||
second: Ipsum
|
||||
ref_variable: ${ref}
|
||||
---
|
||||
`
|
||||
|
||||
var conv = new showdown.Converter({metadata: true});
|
||||
var html = conv.makeHtml(markdown);
|
||||
var metadata = conv.getMetadata();
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```js
|
||||
// console.log(metadata)
|
||||
{
|
||||
first: 'Lorem',
|
||||
second: 'Ipsum',
|
||||
ref_variable: 'referenced value'
|
||||
}
|
||||
```
|
||||
|
||||
### noHeaderId
|
||||
|
||||
Disable automatic generation of heading IDs.
|
||||
|
||||
!!! warning ""
|
||||
Setting the option to `true` overrides the following options:
|
||||
|
||||
* [`prefixHeaderId`](#prefixheaderid)
|
||||
* [`customizedHeaderId`](#customizedheaderid)
|
||||
* [`ghCompatibleHeaderId`](#ghcompatibleheaderid)
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.1.0`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
# This is a heading
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<h1 id="thisisaheading">This is a heading</h1>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<h1>This is a heading</h1>
|
||||
```
|
||||
|
||||
### omitExtraWLInCodeBlocks
|
||||
|
||||
Omit trailing newline in code blocks (which is set by default before the closing tag). This option affects both indented and fenced (gfm style) code blocks.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.0.0`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
var foo = 'bar';
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<code><pre>var foo = 'bar';
|
||||
</pre></code>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<code><pre>var foo = 'bar';</pre></code>
|
||||
```
|
||||
|
||||
### openLinksInNewWindow
|
||||
|
||||
Open links in new windows.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.7.0`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
[link](https://google.com)
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<a href="https://google.com">link</a>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<a href="https://google.com" rel="noopener noreferrer" target="_blank">link</a>
|
||||
```
|
||||
|
||||
### parseImgDimensions
|
||||
|
||||
Set image dimensions from within Markdown syntax.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.1.0`
|
||||
|
||||
=== "example"
|
||||
|
||||
```
|
||||
![foo](foo.jpg =100x80) set width to 100px and height to 80px
|
||||
![bar](bar.jpg =100x*) set width to 100px and height to "auto"
|
||||
![baz](baz.jpg =80%x5em) set width to 80% and height to 5em
|
||||
```
|
||||
|
||||
### prefixHeaderId
|
||||
|
||||
Add a prefix to the generated heading ID:
|
||||
|
||||
* Passing a string will add that string to the heading ID.
|
||||
* Passing `true` will add a generic `section` prefix.
|
||||
|
||||
!!! warning ""
|
||||
This option can be overridden with the [`noHeaderId`](#noheaderid) option.
|
||||
|
||||
* type: `string / boolean`
|
||||
* default value: `false`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
# This is a heading
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<h1 id="thisisaheading">This is a heading</h1>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<h1 id="sectionthisisaheading">This is a heading</h1>
|
||||
```
|
||||
|
||||
=== "output (value is `showdown`)"
|
||||
|
||||
```html
|
||||
<h1 id="showdownthisisaheading">This is a heading</h1>
|
||||
```
|
||||
|
||||
### rawHeaderId
|
||||
|
||||
Replace ` ` (space), `'` (single quote), and `"` (double quote) with `-` (dash) in the generated heading IDs, including prefixes.
|
||||
|
||||
!!! danger ""
|
||||
**Use with caution** as it might result in malformed IDs.
|
||||
|
||||
* type:
|
||||
* default value:
|
||||
* introduced in: `1.7.3`
|
||||
|
||||
### rawPrefixHeaderId
|
||||
|
||||
Prevent Showndown from modifying the prefix. Works only when [`prefixHeaderId`](#prefixheaderid) is set to a string value.
|
||||
|
||||
!!! danger ""
|
||||
**Use with caution** as it might result in malformed IDs. For example, when the prefix contains special characters like `"` `\` `/` or others.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.7.3`
|
||||
|
||||
### requireSpaceBeforeHeadingText
|
||||
|
||||
Require a space between a heading `#` and the heading text.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.5.3`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
#heading
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<h1 id="heading">heading</h1>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<p>#heading</p>
|
||||
```
|
||||
|
||||
### simpleLineBreaks
|
||||
|
||||
Parse line breaks as `<br/>` in paragraphs (GitHub-style behavior).
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.5.1`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
a line
|
||||
wrapped in two
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<p>a line
|
||||
wrapped in two</p>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<p>a line<br>
|
||||
wrapped in two</p>
|
||||
```
|
||||
|
||||
### simplifiedAutoLink
|
||||
|
||||
Enable automatic linking for plain text URLs.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.2.0`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
Lorem ipsum www.google.com
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<p>Lorem ipsum www.google.com</p>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<p>Lorem ipsum <a href="www.google.com">www.google.com</a></p>
|
||||
```
|
||||
|
||||
### smartIndentationFix
|
||||
|
||||
Resolve indentation problems related to ES6 template strings in the midst of indented code.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.4.2`
|
||||
|
||||
### smoothLivePreview
|
||||
|
||||
Resolve an awkward effect when a paragraph is followed by a list. This effect appears on some circumstances, in live preview editors.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.2.1`
|
||||
|
||||
!!! example "awkward effect"
|
||||
|
||||
![](http://i.imgur.com/YQ9iHTL.gif)
|
||||
|
||||
### splitAdjacentBlockquotes
|
||||
|
||||
Split adjacent blockquote blocks.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.8.6`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
> Quote #1
|
||||
>> Sub-quote 1
|
||||
|
||||
> Quote #2
|
||||
>> Sub-quote 2
|
||||
```
|
||||
|
||||
=== "output (value is `false`)"
|
||||
|
||||
```html
|
||||
<blockquote>
|
||||
<p>Quote #1</p>
|
||||
<blockquote>
|
||||
<p>Sub-quote 1</p>
|
||||
</blockquote>
|
||||
<p>Quote #2</p>
|
||||
<blockquote>
|
||||
<p>Sub-quote 2</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<blockquote>
|
||||
<p>Quote #1</p>
|
||||
<blockquote>
|
||||
<p>Sub-quote 1</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>Quote #2</p>
|
||||
<blockquote>
|
||||
<p>Sub-quote 2</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
```
|
||||
|
||||
### strikethrough
|
||||
|
||||
Enable support for strikethrough (`<del>`).
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.2.0`
|
||||
|
||||
=== "input"
|
||||
|
||||
```
|
||||
~~strikethrough~~
|
||||
```
|
||||
|
||||
=== "output (value is `true`)"
|
||||
|
||||
```html
|
||||
<del>strikethrough</del>
|
||||
```
|
||||
|
||||
### tables
|
||||
|
||||
Enable support for tables syntax.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.2.0`
|
||||
|
||||
=== "example"
|
||||
|
||||
```
|
||||
| h1 | h2 | h3 |
|
||||
|:------|:-------:|--------:|
|
||||
| 100 | [a][1] | ![b][2] |
|
||||
| *foo* | **bar** | ~~baz~~ |
|
||||
```
|
||||
|
||||
### tablesHeaderId
|
||||
|
||||
Generate automatic IDs for table headings. Works only when [`tables: true`](#tables).
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.2.0`
|
||||
|
||||
### tasklists
|
||||
|
||||
Enable support for GitHub style tasklists.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* introduced in: `1.2.0`
|
||||
|
||||
=== "example"
|
||||
|
||||
```
|
||||
- [x] This task is done
|
||||
- [ ] This task is still pending
|
||||
```
|
||||
|
||||
### underline
|
||||
|
||||
Enable support for underline. If enabled, underscores will no longer be parsed as `<em>` and `<strong>`.
|
||||
|
||||
* type: `boolean`
|
||||
* default value: `false`
|
||||
* status: `Experimental`
|
||||
|
||||
=== "example"
|
||||
|
||||
```
|
||||
__underlined word__ // double underscores
|
||||
|
||||
___underlined word___ // triple underscores
|
||||
```
|
153
docs/cli.md
Normal file
153
docs/cli.md
Normal file
|
@ -0,0 +1,153 @@
|
|||
Showdown comes bundled with a Command-line interface (CLI) tool that allows you to run Showdown converter from the command line.
|
||||
|
||||
## Requirements
|
||||
|
||||
* [Node.js](https://nodejs.org/en/)
|
||||
|
||||
## Quick start guide
|
||||
|
||||
1. Check that Showdown CLI is accessible.
|
||||
|
||||
* If you installed Showdown globally via `npm install showdown -g`, you can access the CLI tool help by typing `showdown -h` in the command line:
|
||||
|
||||
=== "input"
|
||||
|
||||
```sh
|
||||
showdown -h
|
||||
```
|
||||
|
||||
=== "output"
|
||||
|
||||
```
|
||||
Usage: showdown <command> [options]
|
||||
|
||||
CLI to Showdownjs markdown parser v3.0.0-alpha
|
||||
|
||||
Options:
|
||||
-V, --version output the version number
|
||||
-q, --quiet Quiet mode. Only print errors
|
||||
-m, --mute Mute mode. Does not print anything
|
||||
-h, --help display help for command
|
||||
|
||||
Commands:
|
||||
makehtml [options] Converts markdown into html
|
||||
help [command] display help for command
|
||||
```
|
||||
|
||||
* If you installed Showdown locally via `npm install showdown`, open the folder where Showdown is installed, and type `node ./bin/showdown.js -h` in the command line:
|
||||
|
||||
=== "input"
|
||||
|
||||
```sh
|
||||
node ./bin/showdown.js -h
|
||||
```
|
||||
|
||||
=== "output"
|
||||
|
||||
```
|
||||
Usage: showdown <command> [options]
|
||||
|
||||
CLI to Showdownjs markdown parser v3.0.0-alpha
|
||||
|
||||
Options:
|
||||
-V, --version output the version number
|
||||
-q, --quiet Quiet mode. Only print errors
|
||||
-m, --mute Mute mode. Does not print anything
|
||||
-h, --help display help for command
|
||||
|
||||
Commands:
|
||||
makehtml [options] Converts markdown into html
|
||||
help [command] display help for command
|
||||
```
|
||||
|
||||
1. Use `makehtml` command to convert your document to HTML. For example:
|
||||
|
||||
!!! example "Convert `foo.md` into `bar.html`"
|
||||
|
||||
```sh
|
||||
showdown makehtml -i foo.md -o bar.html
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### `makehtml`
|
||||
|
||||
Convert a Markdown input into HTML.
|
||||
|
||||
**Usage**
|
||||
|
||||
```sh
|
||||
showdown makehtml [options]
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
###### `-i / --input`
|
||||
|
||||
* Short format: `-i`
|
||||
* Alias: `--input`
|
||||
* Description: Input source. Usually a `.md` file. If omitted or empty, reads from `stdin`.
|
||||
* Examples:
|
||||
|
||||
!!! example ""
|
||||
|
||||
```sh
|
||||
// Read from stdin and output to stdout
|
||||
showdown makehtml -i
|
||||
|
||||
// Read from the foo.md file and output to stdout
|
||||
showdown makehtml --input foo.md
|
||||
```
|
||||
|
||||
###### `-o/--output`
|
||||
|
||||
* Short format: `-o`
|
||||
* Alias: `--output`
|
||||
* Description: Output target. Usually a `.html` file. If omitted or empty, writes to `stdout`.
|
||||
* Example:
|
||||
|
||||
!!! example ""
|
||||
|
||||
```sh
|
||||
// Read from the foo.md file and output to bar.html
|
||||
showdown makehtml -i foo.md -o bar.html
|
||||
```
|
||||
|
||||
###### `-a/--append`
|
||||
|
||||
* Short format: `-a`
|
||||
* Alias: `--append`
|
||||
* Description: Append data to output instead of overwriting.
|
||||
* Example:
|
||||
|
||||
!!! example ""
|
||||
|
||||
```sh
|
||||
showdown makehtml -a
|
||||
```
|
||||
|
||||
###### `-u/--encoding`
|
||||
|
||||
* Short format: `-u`
|
||||
* Alias: `--encoding`
|
||||
* Description: Specify the input encoding.
|
||||
* Example:
|
||||
|
||||
!!! example ""
|
||||
|
||||
```sh
|
||||
showdown makehtml -u UTF8
|
||||
```
|
||||
|
||||
###### `-e/--extensions`
|
||||
|
||||
* Short format: `-e`
|
||||
* Alias: `--extension`
|
||||
* Description: Load the specified extension(s). Should be valid path(s) to Node-compatible extensions.
|
||||
* Example:
|
||||
|
||||
!!! example ""
|
||||
|
||||
```sh
|
||||
showdown makehtml -e ~/twitter.js -e ~/youtube.js
|
||||
```
|
60
docs/configuration.md
Normal file
60
docs/configuration.md
Normal file
|
@ -0,0 +1,60 @@
|
|||
You can change Showdown's default behavior via options.
|
||||
|
||||
## Set option
|
||||
|
||||
### Globally
|
||||
|
||||
Setting an option globally affects all Showdown instances.
|
||||
|
||||
```js
|
||||
showdown.setOption('optionKey', 'value');
|
||||
```
|
||||
|
||||
### Locally
|
||||
|
||||
Setting an option locally affects the specified Converter object only. You can set local options via:
|
||||
|
||||
=== "Constructor"
|
||||
|
||||
```js
|
||||
var converter = new showdown.Converter({optionKey: 'value'});
|
||||
```
|
||||
|
||||
=== "setOption() method"
|
||||
|
||||
```js
|
||||
var converter = new showdown.Converter();
|
||||
converter.setOption('optionKey', 'value');
|
||||
```
|
||||
|
||||
## Get option
|
||||
|
||||
Showdown provides both local and global methods to retrieve previously set options:
|
||||
|
||||
=== "getOption()"
|
||||
|
||||
```js
|
||||
// Global
|
||||
var myOption = showdown.getOption('optionKey');
|
||||
|
||||
//Local
|
||||
var myOption = converter.getOption('optionKey');
|
||||
```
|
||||
|
||||
=== "getOptions()"
|
||||
|
||||
```js
|
||||
// Global
|
||||
var showdownGlobalOptions = showdown.getOptions();
|
||||
|
||||
//Local
|
||||
var thisConverterSpecificOptions = converter.getOptions();
|
||||
```
|
||||
|
||||
### Get default options
|
||||
|
||||
You can get Showdown's default options with:
|
||||
|
||||
```js
|
||||
var defaultOptions = showdown.getDefaultOptions();
|
||||
```
|
182
docs/create-extension.md
Normal file
182
docs/create-extension.md
Normal file
|
@ -0,0 +1,182 @@
|
|||
A Showdown extension is a function that returns an array of language or outputs extensions (henceforth called "sub-extensions").
|
||||
|
||||
```js
|
||||
var myext = function () {
|
||||
var myext1 = {
|
||||
type: 'lang',
|
||||
regex: /markdown/g,
|
||||
replace: 'showdown'
|
||||
};
|
||||
var myext2 = {
|
||||
/* extension code */
|
||||
};
|
||||
return [myext1, myext2];
|
||||
}
|
||||
```
|
||||
|
||||
Each sub-extension (`myext1` and `myext2` in the example above) should be an object that defines the behavior of the corresponding sub-extension.
|
||||
|
||||
## Sub-extension object properties
|
||||
|
||||
A sub-extension object should have a [`type` property](#type) that defines the type of the sub-extension, and either [`regex` and `replace` properties](#regex-and-replace) or a [`filter` property](#filter).
|
||||
|
||||
### Type
|
||||
|
||||
**Type** is a **required** property that defines the nature of the corresponding sub-extensions. It takes one of the two values:
|
||||
|
||||
* **`lang`**: language extension to add new Markdown syntax to Showdown.
|
||||
|
||||
`lang` extensions have the **highest priority** in the subparser order, so they are called after [escaping and normalizing](#escape-and-normalization) the input text and before calling any other subparser (or extension).
|
||||
|
||||
!!! example "When to use `lang` type"
|
||||
|
||||
For example, if you want the `^^youtube http://www.youtube.com/watch?v=oHg5SJYRHA0` syntax to automatically be rendered as an embedded YouTube video.
|
||||
|
||||
* **`output`**: output extension (or modifier) to alter the HTML output generated by Showdown.
|
||||
|
||||
`output` extensions have the **lowest priority** in the subparser order, so they are called right before the cleanup step and after calling all other subparsers.
|
||||
|
||||
!!! example "When to use `output` type"
|
||||
|
||||
For example, if you want the `<div class="header">` to become `<header>`.
|
||||
|
||||
### Regex and replace
|
||||
|
||||
`regex`/`replace` properties are similar to the Javascript's `string.replace` function and work the same way:
|
||||
|
||||
* `regex`: a `string` or a `RegExp` object.
|
||||
|
||||
If `regex` is a `string`, it will automatically be assigned a `g` (global) modifier, that is, all matches of that string will be replaced.
|
||||
|
||||
* `replace` a `string` or a `function`.
|
||||
|
||||
If `replace` is a `string`, you can use the `$1` syntax for group substitution, exactly as if it were making use of `string.replace`.
|
||||
|
||||
!!! example "Regex and replace example"
|
||||
|
||||
In this example, all the occurrences of `markdown` will be replaced with `showndown`.
|
||||
|
||||
```js
|
||||
var myext = {
|
||||
type: 'lang',
|
||||
regex: /markdown/g,
|
||||
replace: 'showdown'
|
||||
};
|
||||
```
|
||||
|
||||
### Filter
|
||||
|
||||
Alternately, if you'd like to have more control over the modification process, you can use `filter` property.
|
||||
|
||||
This property should be used as a function that acts as a callback. The callback should receive the following parameters:
|
||||
|
||||
1. `text`: the source text within the Showdown's engine.
|
||||
1. `converter`: the full instance of the current Showdown's converter object.
|
||||
1. `options`: the options used to initialize the converter
|
||||
|
||||
!!! warning ""
|
||||
The filter function **should return the transformed text**. If it doesn't, it will fail **silently** and return an empty output.
|
||||
|
||||
!!! example "Filter example"
|
||||
|
||||
```js
|
||||
var myext = {
|
||||
type: 'lang',
|
||||
filter: function (text, converter, options) {
|
||||
// ... do stuff to text ...
|
||||
return text;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
!!! warning "Use `filter` with care"
|
||||
|
||||
Although Filter extensions are more powerful, they have a few pitfalls that you should keep in mind before using them, especially regarding the `converter` parameter.
|
||||
|
||||
Since the `converter` parameter passed to the filter function is the fully initialized instance, any change made to it will be propagated outside the scope of the filter function and will remain there until a new converter instance is created. So, **it is not recommended to make ANY change to the converter object**.
|
||||
|
||||
Another aspect is that if you call the `converter` recursively, it will call your extension itself at some point. It may lead to infinite recursion in some circumstances, and it's up to you to prevent this. A simple solution is to place a kind of safeguard to disable your extension if it's called more than x times:
|
||||
|
||||
```js
|
||||
var x = 0;
|
||||
var myext = {
|
||||
type: 'lang',
|
||||
filter: function (text, converter) {
|
||||
if (x < 3) {
|
||||
++x;
|
||||
someSubText = converter.makeHtml(someSubText);
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Register an extension
|
||||
|
||||
|
||||
To let Showdown know what extensions are available, you need to register them in the Showdown global object.
|
||||
|
||||
To register an extension, call the `showdown.extension` function with two parameters: the first one is the extension name; the second one is the actual extension.
|
||||
|
||||
```js
|
||||
showdown.extension('myext', myext);
|
||||
```
|
||||
|
||||
## Test an extension
|
||||
|
||||
The Showdown test runner is configured to automatically test cases for extensions.
|
||||
|
||||
To add test cases for an extension:
|
||||
|
||||
1. Create a new folder under `./test/extensions` that matches with the name of the `.js` file in `./src/extensions`.
|
||||
1. Place any test cases into the filter using the `md/html` format. These cases will automatically be executed when running tests.
|
||||
|
||||
## Additional information
|
||||
|
||||
### Escape and normalization
|
||||
|
||||
Showdown performs the following escape/normalization:
|
||||
|
||||
* Replaces `¨` (trema) with `¨T`
|
||||
* Replaces `$` (dollar sign) with `¨D`
|
||||
* Normalizes line endings (`\r`, `\r\n` are converted into `\n`)
|
||||
* Uses `\r` as a char placeholder
|
||||
|
||||
!!! note ""
|
||||
This only applies to **language extensions** since these chars are unescaped before output extensions are run.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
Keep in mind that these modifications happen **before language extensions** are run, so if your extension relies on any of those chars, you have to make the appropriate adjustments.
|
||||
|
||||
|
||||
### Implementation concerns
|
||||
|
||||
One of the concerns is maintaining both client-side and server-side compatibility. You can do this with a few lines of boilerplate code.:
|
||||
|
||||
```js
|
||||
(function (extension) {
|
||||
if (typeof showdown !== 'undefined') {
|
||||
// global (browser or node.js global)
|
||||
extension(showdown);
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
// AMD
|
||||
define(['showdown'], extension);
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node, CommonJS-like
|
||||
module.exports = extension(require('showdown'));
|
||||
} else {
|
||||
// showdown was not found so an error is thrown
|
||||
throw Error('Could not find showdown library');
|
||||
}
|
||||
}(function (showdown) {
|
||||
// loading extension into showdown
|
||||
showdown.extension('myext', function () {
|
||||
var myext = { /* ... actual extension code ... */ };
|
||||
return [myext];
|
||||
});
|
||||
}));
|
||||
```
|
||||
|
||||
In the code above, the extension definition is wrapped in a self-executing function to prevent pollution of the global scope. It has another benefit of creating several scope layers that can be useful for interaction between sub-extensions global-wise or local-wise.
|
||||
|
||||
It is also loaded conditionally to make it compatible with different loading mechanisms (such as browser, CommonJS, or AMD).
|
36
docs/extensions.md
Normal file
36
docs/extensions.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
Showdown allows you to load additional functionality via extensions. You can find a list of known Showdown extensions [here][ext-wiki].
|
||||
|
||||
You can also check the [boilerplate repo][boilerplate-repo], to create your own extension(s).
|
||||
|
||||
## Usage
|
||||
|
||||
=== "Server-side"
|
||||
|
||||
```js
|
||||
// Using a bundled extension
|
||||
var showdown = require('showdown');
|
||||
var converter = new showdown.Converter({ extensions: ['twitter'] });
|
||||
|
||||
// Using a custom extension
|
||||
var mine = require('./custom-extensions/mine');
|
||||
var converter = new showdown.Converter({ extensions: ['twitter', mine] });
|
||||
```
|
||||
|
||||
=== "Client-side"
|
||||
|
||||
```js
|
||||
<script src="src/showdown.js"></script>
|
||||
<script src="src/extensions/twitter.js"></script>
|
||||
<script>var converter = new showdown.Converter({ extensions: ['twitter'] });</script>
|
||||
```
|
||||
|
||||
=== "CLI"
|
||||
|
||||
In the CLI tool, use the [`-e` flag](/cli/#-e-extensions) to load an extension.
|
||||
|
||||
```sh
|
||||
showdown -e twitter -i foo.md -o bar.html
|
||||
```
|
||||
|
||||
[ext-wiki]: https://github.com/showdownjs/showdown/wiki/extensions
|
||||
[boilerplate-repo]: https://github.com/showdownjs/extension-boilerplate
|
23
docs/flavors.md
Normal file
23
docs/flavors.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
## Overview
|
||||
|
||||
You can use _flavors_ (or presets) to set the preferred options automatically. In this way, Showdown behaves like popular Markdown flavors.
|
||||
|
||||
Currently, the following flavors are available:
|
||||
|
||||
* `original`: Original Markdown flavor as in [John Gruber's spec](https://daringfireball.net/projects/markdown/)
|
||||
* `vanilla`: Showdown base flavor (v1.3.1 onwards)
|
||||
* `github`: [GitHub Flavored Markdown, or GFM](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax)
|
||||
|
||||
## Set flavor
|
||||
|
||||
=== "Globally"
|
||||
|
||||
```js
|
||||
showdown.setFlavor('github');
|
||||
```
|
||||
|
||||
=== "Locally"
|
||||
|
||||
```js
|
||||
converter.setFlavor('github');
|
||||
```
|
20
docs/integrations.md
Normal file
20
docs/integrations.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
## AngularJS
|
||||
|
||||
ShowdownJS project provides seamless integration with AngularJS via a plugin.
|
||||
|
||||
Check [`ng-showdown`](https://github.com/showdownjs/ngShowdown) repository for more information.
|
||||
|
||||
## TypeScript
|
||||
|
||||
If you're using TypeScript, you may want to use the types from the [DefinitelyTyped][definitely-typed] repository.
|
||||
|
||||
## SystemJS/JSPM
|
||||
|
||||
To integrate ShowdownJS with SystemJS, you can use a third-party [system-md plugin](https://github.com/guybedford/system-md).
|
||||
|
||||
## Vue.js
|
||||
|
||||
To use ShowdownJS as a Vue component, you can check [vue-showdown](https://vue-showdown.js.org/).
|
||||
|
||||
|
||||
[definitely-typed]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/showdown
|
|
@ -94,6 +94,11 @@ Once installed, you can use Showndown according to the chosen method:
|
|||
<h1 id="hellomarkdown">hello, markdown!</h1>
|
||||
```
|
||||
|
||||
!!! warning "Potential XSS vulnerabilities"
|
||||
Showdown doesn't sanitize the input since Markdown relies on it to parse certain features correctly into HTML. As a result, this may lead to potential XSS injection vulnerabilities.
|
||||
|
||||
Please refer to the [Markdown's XSS vulnerability](xss.md) page for more information.
|
||||
|
||||
## Other installation methods
|
||||
|
||||
### Tarball
|
||||
|
|
110
docs/xss.md
Normal file
110
docs/xss.md
Normal file
|
@ -0,0 +1,110 @@
|
|||
# Markdown's XSS vulnerability
|
||||
|
||||
## Introduction
|
||||
|
||||
Cross-Site Scripting (XSS) is a well-known technique to gain access to the private information of users on a website. The attacker injects spurious HTML content (a script) on the web page. This script can read the user’s cookies and do other malicious actions (like steal credentials). As a countermeasure, you should always filter user input for suspicious content. Showdown doesn’t include an XSS filter, so you must provide your own. But be careful in how you do it.
|
||||
|
||||
## Markdown is inherently unsafe
|
||||
|
||||
Markdown syntax allows the inclusion of arbitrary HTML. For example, below is a perfectly valid Markdown:
|
||||
|
||||
```md
|
||||
This is a regular paragraph.
|
||||
|
||||
<table>
|
||||
<tr><td>Foo</td></tr>
|
||||
</table>
|
||||
|
||||
This is another regular paragraph.
|
||||
```
|
||||
|
||||
This means that an attacker could do something like this:
|
||||
|
||||
```md
|
||||
This is a regular paragraph.
|
||||
|
||||
<script>alert('xss');</script>
|
||||
|
||||
This is another regular paragraph.
|
||||
```
|
||||
|
||||
While `alert('xss');` is hardly problematic (maybe just annoying) a real-world scenario might be a lot worse. Obviously, you can easily prevent this kind of this straightforward attack. For example, you can define a whitelist for Showdown that will contain a limited set of allowed HTML tags. However, an attacker can easily circumvent this "defense".
|
||||
|
||||
## Whitelist / blacklist can't prevent XSS
|
||||
|
||||
Consider the following Markdown content:
|
||||
|
||||
```md
|
||||
hello <a href="www.google.com">*you*</a>
|
||||
```
|
||||
|
||||
As you can see, it's a link, nothing malicious about this. And `<a>` tags are pretty innocuous, right? Showdown should definitely allow them. But what if the content is slightly altered, like this:
|
||||
|
||||
```md
|
||||
hello <a name="n" href="javascript:alert('xss')">*you*</a>
|
||||
```
|
||||
|
||||
Now this is a lot more problematic. Once again, it's not that hard to filter Showdown's input to expunge problematic attributes (such as `href` in `<a>` tags) of scripting attacks. In fact, a regular HTML XSS prevention library should catch this kind of straightforward attack.
|
||||
|
||||
At this point you're probably thinking that the best way is to follow Stackoverflow's cue and disallow embedded HTML in Markdown. Unfortunately it's still not enough.
|
||||
|
||||
## Strip HTML tags is not enough
|
||||
|
||||
Consider the following Markdown input:
|
||||
|
||||
```md
|
||||
[some text](javascript:alert('xss'))
|
||||
```
|
||||
|
||||
Showdown will correctly parse this piece of Markdown input as:
|
||||
|
||||
```html
|
||||
<a href="javascript:alert('xss')">some text</a>
|
||||
```
|
||||
|
||||
In this case, it was Markdown's syntax itself to create the dangerous link. HTML XSS filter cannot catch this. And unless you start striping dangerous words like *javascript* (which would make this article extremely hard to write), there's nothing you can really do to filter XSS attacks from your input. Things get even harder when you tightly mix HTML with Markdown.
|
||||
|
||||
## Mixed HTML/Markdown XSS attack
|
||||
|
||||
Consider the following piece of Markdown:
|
||||
|
||||
```md
|
||||
> hello <a name="n"
|
||||
> href="javascript:alert('xss')">*you*</a>
|
||||
```
|
||||
|
||||
If you apply an XSS filter to filter bad HTML in this Markdown input, the XSS filter, expecting HTML, will likely think the `<a>` tag ends with the first character on the second line and will leave the text snippet untouched. It will probably fail to see that the `href="javascript:…"` is part of the `<a>` element and leave it alone. But when Markdown converts this to HTML, you get this:
|
||||
|
||||
```html
|
||||
<blockquote>
|
||||
<p>hello <a name="n"
|
||||
href="javascript:alert('xss')"><em>you</em></a></p>
|
||||
</blockquote>
|
||||
```
|
||||
|
||||
After parsing with Markdown, the first `>` on the second line disappears because it was the blockquote marker in the Markdown blockquote syntax. As a result, you’ve got a link containing an XSS attack!
|
||||
|
||||
Did Markdown generate the HTML? No, the HTML was already in plain sight in the input. The XSS filter couldn’t catch it because the input doesn’t follow HTML rules: it’s a mix of Markdown and HTML, and the filter doesn’t know a dime about Markdown.
|
||||
|
||||
## Mitigate XSS
|
||||
|
||||
So, is it all lost? Not really. The answer is not to filter the *input* but rather the *output*. After the *input* text is converted into full-fledged HTML, you can reliably apply the correct XSS filters to remove any dangerous or malicious content.
|
||||
|
||||
Also, client-side validations are not reliable. It should be a given, but in case you're wondering, you should (almost) never trust data sent by the client. If there's some critical operation you must perform on the data (such as XSS filtering), you should do it *SERVER-SIDE* not client-side.
|
||||
|
||||
HTML XSS filtering libraries are useful here since they prevent most of the attacks. However, you should not use them blindly: a library can't predict all the contexts and situations your application may face.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Showdown tries to convert the input text as closely as possible, without any concerns for XSS attacks or malicious intent. So, the basic rules are:
|
||||
|
||||
* **removing HTML entities from Markdown does not prevent XSS**. Markdown syntax can generate XSS attacks.
|
||||
* **XSS filtering should be done after Showdown has processed input, not before or during**. If you filter before, it will break some of Markdown’s features and will leave security holes.
|
||||
* **perform the necessary filtering server-side, not client-side**. XSS filtering libraries are useful but should not be used blindly.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This page is based on the excellent article: ["Markdown and XSS"][1] by [Michel Fortin][2]
|
||||
|
||||
[1]: https://michelf.ca/blog/2010/markdown-and-xss/
|
||||
[2]: https://github.com/michelf
|
|
@ -33,3 +33,12 @@ nav:
|
|||
- Quickstart:
|
||||
- Quickstart: quickstart.md
|
||||
- Compatibility: compatibility.md
|
||||
- Configuration:
|
||||
- Showdown options: configuration.md
|
||||
- Available options: available-options.md
|
||||
- Flavors: flavors.md
|
||||
- CLI: cli.md
|
||||
- Integrations: integrations.md
|
||||
- Extensions:
|
||||
- Overview: extensions.md
|
||||
- Create an extension: create-extension.md
|
Loading…
Reference in New Issue
Block a user