Merge branch 'develop' of github.com:showdownjs/showdown into develop

This commit is contained in:
Estevão Soares dos Santos 2022-03-31 02:44:42 +01:00
commit a9ee330ac2
10 changed files with 1372 additions and 1 deletions

773
docs/available-options.md Normal file
View 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>&lt;div&gt;foo&lt;/div&gt;</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="&#109;&#97;&#105;&#108;t&#x6f;&#x3a;&#109;&#x79;s&#x65;&#x6c;&#102;&#64;&#x65;xa&#109;&#112;&#108;&#101;&#x2e;c&#x6f;&#109;">&#x6d;&#121;s&#101;&#108;f&#x40;&#x65;&#120;a&#x6d;&#x70;&#108;&#x65;&#x2e;&#99;&#x6f;&#109;</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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -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
View 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 users cookies and do other malicious actions (like steal credentials). As a countermeasure, you should always filter user input for suspicious content. Showdown doesnt 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, youve 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 couldnt catch it because the input doesnt follow HTML rules: its a mix of Markdown and HTML, and the filter doesnt 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 Markdowns 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

View File

@ -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