├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github ├── FUNDING.yml └── contributing.md ├── .gitignore ├── .nojekyll ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── benchmark ├── fixtures │ ├── block-bq-flat.md │ ├── block-bq-nested.md │ ├── block-code.md │ ├── block-fences.md │ ├── block-heading.md │ ├── block-hr.md │ ├── block-html.md │ ├── block-lheading.md │ ├── block-list-flat.md │ ├── block-list-nested.md │ ├── block-ref-flat.md │ ├── block-ref-nested.md │ ├── block-tables-large.md │ ├── block-tables.md │ ├── inline-autolink.md │ ├── inline-backticks.md │ ├── inline-em-flat.md │ ├── inline-em-nested.md │ ├── inline-em-worst.md │ ├── inline-entity.md │ ├── inline-escape.md │ ├── inline-html.md │ ├── inline-links-flat.md │ ├── inline-links-nested.md │ ├── inline-newlines-large.md │ ├── inline-newlines.md │ ├── lorem1.txt │ ├── rawtabs.md │ └── spec.txt ├── implementations │ ├── commonmark-reference │ │ └── index.js │ ├── current-commonmark │ │ └── index.js │ ├── current │ │ └── index.js │ └── marked-0.3.2 │ │ └── index.js ├── index.js └── profile.js ├── bin └── remarkable.js ├── demo ├── .eslintrc ├── assets │ ├── index.css │ ├── index.js │ └── index.styl ├── example.js ├── example.md ├── index.html └── index.jade ├── docs ├── parser.md ├── parsing_block.md ├── parsing_core.md ├── parsing_inline.md ├── plugins.md └── renderer.md ├── lib ├── cli.js ├── common │ ├── entities.browser.js │ ├── entities.js │ ├── html_blocks.js │ ├── html_re.js │ ├── url_schemas.js │ └── utils.js ├── configs │ ├── commonmark.js │ ├── default.js │ └── full.js ├── helpers │ ├── normalize_link.js │ ├── normalize_reference.js │ ├── parse_link_destination.js │ ├── parse_link_label.js │ └── parse_link_title.js ├── index.js ├── linkify.js ├── parser_block.js ├── parser_core.js ├── parser_inline.js ├── renderer.js ├── ruler.js ├── rules.js ├── rules_block │ ├── blockquote.js │ ├── code.js │ ├── deflist.js │ ├── fences.js │ ├── footnote.js │ ├── heading.js │ ├── hr.js │ ├── htmlblock.js │ ├── lheading.js │ ├── list.js │ ├── paragraph.js │ ├── state_block.js │ └── table.js ├── rules_core │ ├── abbr.js │ ├── abbr2.js │ ├── block.js │ ├── footnote_tail.js │ ├── inline.js │ ├── references.js │ ├── replacements.js │ └── smartquotes.js ├── rules_inline │ ├── autolink.js │ ├── backticks.js │ ├── del.js │ ├── emphasis.js │ ├── entity.js │ ├── escape.js │ ├── footnote_inline.js │ ├── footnote_ref.js │ ├── htmltag.js │ ├── ins.js │ ├── links.js │ ├── mark.js │ ├── newline.js │ ├── state_inline.js │ ├── sub.js │ ├── sup.js │ └── text.js └── umd.js ├── linkify └── package.json ├── package.json ├── rollup.config.js ├── support ├── demodata.js ├── entities.js └── specsplit.js ├── test ├── cli.js ├── commonmark.js ├── fixtures │ ├── cli-input.md │ ├── commonmark │ │ ├── bad.txt │ │ ├── good.txt │ │ └── spec.txt │ ├── linkify.txt │ └── remarkable │ │ ├── abbr.txt │ │ ├── commonmark_extras.txt │ │ ├── deflist.txt │ │ ├── del.txt │ │ ├── footnotes.txt │ │ ├── ins.txt │ │ ├── mark.txt │ │ ├── proto.txt │ │ ├── redos.txt │ │ ├── smartquotes.txt │ │ ├── sub.txt │ │ ├── sup.txt │ │ ├── tables.txt │ │ ├── typographer.txt │ │ └── xss.txt ├── linkify.js ├── misc.js ├── remarkable.js ├── ruler.js ├── test-browser.js └── utils.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | end_of_line = lf 6 | charset = utf-8 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [{**/{actual,fixtures,expected,templates}/**,*.md}] 12 | trim_trailing_whitespace = false 13 | insert_final_newline = false -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | benchmark/implementations/ 2 | coverage/ 3 | demo/sample.js 4 | dist/ 5 | node_modules/ 6 | demo/ 7 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "sourceType": "module", 4 | "ecmaVersion": "2015" 5 | }, 6 | "extends": ["eslint:recommended"], 7 | "rules": { 8 | "no-extra-semi": "off", 9 | "no-unexpected-multiline": "off", 10 | "no-control-regex": "off", 11 | "no-empty": "off", 12 | "no-useless-escape": "off" 13 | }, 14 | "overrides": [ 15 | { 16 | "files": "lib/**/*.js", 17 | "env": { 18 | "browser": true 19 | }, 20 | "extends": ["plugin:es5/no-es2015", "plugin:es5/no-es2016"], 21 | "rules": { 22 | "es5/no-modules": "off" 23 | } 24 | }, 25 | { 26 | "files": ["benchmark/**/*.js", "support/**/*.js", "bin/**/*.js", "lib/cli.js"], 27 | "env": { 28 | "browser": false, 29 | "node": true 30 | } 31 | }, 32 | { 33 | "files": "test/**/*.js", 34 | "env": { 35 | "node": true, 36 | "mocha": true 37 | } 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [jonschlinkert] 2 | -------------------------------------------------------------------------------- /.github/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | > Before submitting a pull request to Remarkable: 4 | 5 | 1. Run `npm test` to be sure that all tests are passing. 6 | 2. Run `node benchmark` to ensure that performance has not degraded. 7 | 3. DO NOT include any auto-generated browser or demo files in your commit. 8 | 4. Commit to the [dev](https://github.com/jonschlinkert/remarkable/tree/dev) branch, never master. 9 | 10 | Thanks! 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # always ignore files 2 | *.DS_Store 3 | *.sublime-* 4 | 5 | # test related, or directories generated by tests 6 | test/actual 7 | actual 8 | coverage 9 | .nyc_output 10 | 11 | # npm 12 | node_modules 13 | npm-debug.log 14 | 15 | # misc 16 | _gh_pages 17 | vendor 18 | temp 19 | tmp 20 | TODO.md 21 | dist 22 | /index.html 23 | -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonschlinkert/remarkable/7c5e433620c967618eb38cdb57360734274061c4/.nojekyll -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-present, Jon Schlinkert 4 | Copyright (c) 2014 Jon Schlinkert, Vitaly Puzrin. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PATH := ./node_modules/.bin:${PATH} 2 | NPM_VERSION := $(shell node -e 'process.stdout.write(require("./package.json").version)') 3 | GITHUB_PROJ := $(shell node -e 'process.stdout.write(require("./package.json").repository)') 4 | 5 | 6 | demo: 7 | ./support/demodata.js > demo/example.json 8 | jade demo/index.jade -P --obj demo/example.json 9 | stylus -u autoprefixer-stylus demo/assets/index.styl 10 | rm -rf demo/example.json 11 | 12 | gh-pages: 13 | if [ "git branch --list gh-pages" ]; then \ 14 | git branch -D gh-pages ; \ 15 | fi 16 | git branch gh-pages 17 | git push origin gh-pages -f 18 | 19 | publish: 20 | @if test 0 -ne `git status --porcelain | wc -l` ; then \ 21 | echo "Unclean working tree. Commit or stash changes first." >&2 ; \ 22 | exit 128 ; \ 23 | fi 24 | @if test 0 -ne `git fetch ; git status | grep '^# Your branch' | wc -l` ; then \ 25 | echo "Local/Remote history differs. Please push/pull changes." >&2 ; \ 26 | exit 128 ; \ 27 | fi 28 | @if test 0 -ne `git tag -l ${NPM_VERSION} | wc -l` ; then \ 29 | echo "Tag ${NPM_VERSION} exists. Update package.json" >&2 ; \ 30 | exit 128 ; \ 31 | fi 32 | git tag ${NPM_VERSION} && git push origin ${NPM_VERSION} 33 | npm publish ${GITHUB_PROJ}/tarball/${NPM_VERSION} 34 | 35 | todo: 36 | grep 'TODO' -n -r ./lib 2>/dev/null || test true 37 | 38 | 39 | .PHONY: publish lint test gh-pages todo demo coverage 40 | .SILENT: help lint test todo 41 | -------------------------------------------------------------------------------- /benchmark/fixtures/block-bq-flat.md: -------------------------------------------------------------------------------- 1 | > the simple example of a blockquote 2 | > the simple example of a blockquote 3 | > the simple example of a blockquote 4 | > the simple example of a blockquote 5 | ... continuation 6 | ... continuation 7 | ... continuation 8 | ... continuation 9 | 10 | empty blockquote: 11 | 12 | > 13 | > 14 | > 15 | > 16 | 17 | -------------------------------------------------------------------------------- /benchmark/fixtures/block-bq-nested.md: -------------------------------------------------------------------------------- 1 | >>>>>> deeply nested blockquote 2 | >>>>> deeply nested blockquote 3 | >>>> deeply nested blockquote 4 | >>> deeply nested blockquote 5 | >> deeply nested blockquote 6 | > deeply nested blockquote 7 | 8 | > deeply nested blockquote 9 | >> deeply nested blockquote 10 | >>> deeply nested blockquote 11 | >>>> deeply nested blockquote 12 | >>>>> deeply nested blockquote 13 | >>>>>> deeply nested blockquote 14 | -------------------------------------------------------------------------------- /benchmark/fixtures/block-code.md: -------------------------------------------------------------------------------- 1 | 2 | an 3 | example 4 | 5 | of 6 | 7 | 8 | 9 | a code 10 | block 11 | 12 | -------------------------------------------------------------------------------- /benchmark/fixtures/block-fences.md: -------------------------------------------------------------------------------- 1 | 2 | ``````````text 3 | an 4 | example 5 | ``` 6 | of 7 | 8 | 9 | a fenced 10 | ``` 11 | code 12 | block 13 | `````````` 14 | 15 | -------------------------------------------------------------------------------- /benchmark/fixtures/block-heading.md: -------------------------------------------------------------------------------- 1 | # heading 2 | ### heading 3 | ##### heading 4 | 5 | # heading # 6 | ### heading ### 7 | ##### heading \#\#\#\#\###### 8 | 9 | ############ not a heading 10 | -------------------------------------------------------------------------------- /benchmark/fixtures/block-hr.md: -------------------------------------------------------------------------------- 1 | 2 | * * * * * 3 | 4 | - - - - - 5 | 6 | ________ 7 | 8 | 9 | ************************* text 10 | 11 | -------------------------------------------------------------------------------- /benchmark/fixtures/block-html.md: -------------------------------------------------------------------------------- 1 |
10 | **test** 11 | | 12 |
20 | 21 | test 22 | 23 | | 24 | 25 |
8 |11 |It’s really just here to make sure the Remarkable CLI can take a Markdown 9 | document as an input
10 |
It’s not comprehensive or anything
12 |Hopefully the CLI can handle it though
13 | `; 14 | 15 | describe("Remarkable CLI", function() { 16 | this.timeout(10000); 17 | it("simple Markdown file as input", function(done) { 18 | const command = "node -r esm ../lib/cli.js ./fixtures/cli-input.md" 19 | ChildProcess.exec(command, { cwd: __dirname }, (error, stdout) => { 20 | assert.strictEqual(stdout.toString(), desiredOutput); 21 | done(); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/commonmark.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { addTests } from './utils'; 3 | import { Remarkable } from '../lib/index'; 4 | 5 | describe('CommonMark', function () { 6 | var md = new Remarkable('commonmark'); 7 | addTests(path.join(__dirname, 'fixtures/commonmark/good.txt'), md); 8 | }); 9 | -------------------------------------------------------------------------------- /test/fixtures/cli-input.md: -------------------------------------------------------------------------------- 1 | ### This is a simple Markdown document 2 | 3 | > It's really just here to make sure the Remarkable CLI can take a Markdown 4 | > document as an input 5 | 6 | **It's not comprehensive or anything** 7 | 8 | Hopefully the CLI can handle it though 9 | -------------------------------------------------------------------------------- /test/fixtures/commonmark/bad.txt: -------------------------------------------------------------------------------- 1 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | src line: 3124 3 | 4 | . 5 | - # Foo 6 | - Bar 7 | --- 8 | baz 9 | . 10 |baz
url http://www.youtube.com/watch?v=5Jt5GEr4AYg.
6 | . 7 | 8 | 9 | don't touch text in links 10 | . 11 | [https://example.com](https://example.com) 12 | . 13 | 14 | . 15 | 16 | 17 | don't touch text in autolinks 18 | . 19 |The HTML specification 11 | is maintained by the W3C.
12 | . 13 | 14 | They can be multiline (see pandoc implementation). Not sure about newlines, but we should at least skip those definitions: 15 | 16 | . 17 | *[ 18 | foo 19 | bar 20 | ]: desc 21 | foo 22 | . 23 |foo
24 | . 25 | 26 | They can contain arbitrary markup (see pandoc implementation): 27 | 28 | . 29 | *[`]:`]: foo 30 | \`]:\` 31 | . 32 |`]:`
33 | . 34 | 35 | Can contain matched brackets: 36 | 37 | . 38 | *[[abbr]]: foo 39 | [abbr] 40 | . 41 |[abbr]
42 | . 43 | 44 | No empty abbreviations: 45 | 46 | . 47 | *[foo]: 48 | foo 49 | . 50 |*[foo]: 51 | foo
52 | . 53 | 54 | Intersecting abbreviations (first should match): 55 | 56 | . 57 | *[Bar Foo]: 123 58 | *[Foo Bar]: 456 59 | 60 | Foo Bar Foo 61 | 62 | Bar Foo Bar 63 | . 64 |Foo Bar Foo
65 |Bar Foo Bar
66 | . 67 | 68 | Don't bother with nested abbreviations (yet?): 69 | 70 | . 71 | *[JS]: javascript 72 | *[HTTP]: hyper text blah blah 73 | *[JS HTTP]: is awesome 74 | JS HTTP is a collection of low-level javascript HTTP-related modules 75 | . 76 |JS HTTP is a collection of low-level javascript HTTP-related modules
77 | . 78 | 79 | Don't match the middle of the string: 80 | 81 | . 82 | *[foo]: blah 83 | *[bar]: blah 84 | foobar 85 | . 86 |foobar
87 | . 88 | -------------------------------------------------------------------------------- /test/fixtures/remarkable/commonmark_extras.txt: -------------------------------------------------------------------------------- 1 | Regression tests for link backtracking optimizations: 2 | 3 | . 4 | [[some unrelated text [link] 5 | 6 | [link]: foo 7 | . 8 |[[some unrelated text link
9 | . 10 | 11 | . 12 | [[some unrelated text [[link]] 13 | 14 | [[link]]: foo 15 | . 16 |[[some unrelated text [link]
17 | . 18 | 19 | 20 | 21 | This is not a valid emphasis, because \n considered a whitespace: 22 | 23 | . 24 | **test 25 | ** 26 | 27 | ** 28 | test** 29 | 30 | ** 31 | test 32 | ** 33 | . 34 |**test 35 | **
36 |** 37 | test**
38 |** 39 | test 40 | **
41 | . 42 | 43 | 44 | Link label has priority over emphasis (not covered by commonmark tests): 45 | 46 | . 47 | [**link]()** 48 | 49 | **[link**]() 50 | . 51 |**link**
52 |**link**
53 | . 54 | 55 | 56 | Issue #55: 57 | 58 | . 59 | ![test] 60 | 61 |  62 | . 63 |![test]
64 |
65 | . 66 | 67 | 68 | Should unescape only needed things in link destinations/titles: 69 | 70 | . 71 | [test](<\f\o\o\>\\>) 72 | . 73 | 74 | . 75 | 76 | . 77 | [test](foo "\\\"\b\a\r") 78 | . 79 | 80 | . 81 | 82 | 83 | Not a closing tag 84 | 85 | . 86 | 123> 87 | . 88 |</ 123>
89 | . 90 | 91 | 92 | Not a list item 93 | 94 | . 95 | 1.list 96 | . 97 |1.list
98 | . 99 | 100 | 101 | Coverage. Direcctive can terminate paragraph. 102 | 103 | . 104 | a 105 | a 108 | 115 | . 116 |http://example.com/α%CE%B2γ%CE%B4
117 | . 118 | 119 | Autolinks do not allow escaping: 120 | 121 | . 122 |Hello google where are you?
149 |Hello google where are you?
150 |Hello google where are you?
151 | . 152 | 153 | 154 | Image alt should be unescaped 155 | 156 | . 157 | [Foo\\bar\]]: /url 158 | 159 | ![Foo\\bar\]] 160 | . 161 |Definition 1
20 |Definition 2
23 |{ some code, part of Definition 2 }
24 |
25 | Third paragraph of definition 2.
26 |Definition 43 | with lazy continuation.
44 |Second paragraph of the definition.
45 |code block
86 |
87 | Non-term 1 101 | :
102 |Non-term 2 103 | :
104 | . 105 | 106 | Definition lists should be second last in the queue. Exemplī grātiā, this isn't a valid one: 107 | 108 | . 109 | # test 110 | : just a paragraph with a colon 111 | . 112 |: just a paragraph with a colon
114 | . 115 | 116 | Nested definition lists: 117 | 118 | . 119 | test 120 | : foo 121 | : bar 122 | : baz 123 | : bar 124 | : foo 125 | . 126 |Strikeout
~~test~~
15 |**test**
~~link~~
25 |~~link~~
26 | . 27 | 28 | Strikeouts have the same priority as emphases with respect to backticks: 29 | . 30 | ~~`code~~` 31 | 32 | `~~code`~~ 33 | . 34 |~~code~~
~~code
~~
foo bar baz
f o o b a r
foo ~~ bar ~~ baz
56 | . 57 | 58 | 59 | Newline should be considered a whitespace: 60 | 61 | . 62 | ~~test 63 | ~~ 64 | 65 | ~~ 66 | test~~ 67 | 68 | ~~ 69 | test 70 | ~~ 71 | . 72 |~~test 73 | ~~
74 |~~ 75 | test~~
76 |~~ 77 | test 78 | ~~
79 | . 80 | -------------------------------------------------------------------------------- /test/fixtures/remarkable/ins.txt: -------------------------------------------------------------------------------- 1 | . 2 | ++Insert++ 3 | . 4 |Insert
5 | . 6 | 7 | 8 | These are not inserts, you have to use exactly two "++": 9 | . 10 | x +++foo+++ 11 | 12 | x ++foo+++ 13 | 14 | x +++foo++ 15 | . 16 |x +++foo+++
17 |x ++foo+++
18 |x +++foo++
19 | . 20 | 21 | Inserts have the same priority as emphases: 22 | 23 | . 24 | **++test**++ 25 | 26 | ++**test++** 27 | . 28 |++test++
29 |**test**
30 | . 31 | 32 | Inserts have the same priority as emphases with respect to links: 33 | . 34 | [++link]()++ 35 | 36 | ++[link++]() 37 | . 38 |++link++
39 |++link++
40 | . 41 | 42 | Inserts have the same priority as emphases with respect to backticks: 43 | . 44 | ++`code++` 45 | 46 | `++code`++ 47 | . 48 |++code++
++code
++
foo bar baz
57 | . 58 | 59 | . 60 | ++f **o ++o b++ a** r++ 61 | . 62 |f o o b a r
63 | . 64 | 65 | Should not have a whitespace between text and "++": 66 | . 67 | foo ++ bar ++ baz 68 | . 69 |foo ++ bar ++ baz
70 | . 71 | 72 | 73 | Newline should be considered a whitespace: 74 | 75 | . 76 | ++test 77 | ++ 78 | 79 | ++ 80 | test++ 81 | 82 | ++ 83 | test 84 | ++ 85 | . 86 |++test 87 | ++
88 |++ 89 | test++
90 |++ 91 | test 92 | ++
93 | . 94 | -------------------------------------------------------------------------------- /test/fixtures/remarkable/mark.txt: -------------------------------------------------------------------------------- 1 | . 2 | ==Mark== 3 | . 4 |Mark
5 | . 6 | 7 | 8 | These are not marks, you have to use exactly two "==": 9 | . 10 | x ===foo=== 11 | 12 | x ==foo=== 13 | 14 | x ===foo== 15 | . 16 |x ===foo===
17 |x ==foo===
18 |x ===foo==
19 | . 20 | 21 | Marks have the same priority as emphases: 22 | 23 | . 24 | **==test**== 25 | 26 | ==**test==** 27 | . 28 |==test==
29 |**test**
30 | . 31 | 32 | Marks have the same priority as emphases with respect to links: 33 | . 34 | [==link]()== 35 | 36 | ==[link==]() 37 | . 38 |==link==
39 |==link==
40 | . 41 | 42 | Marks have the same priority as emphases with respect to backticks: 43 | . 44 | ==`code==` 45 | 46 | `==code`== 47 | . 48 |==code==
==code
==
foo bar baz
57 | . 58 | 59 | . 60 | ==f **o ==o b== a** r== 61 | . 62 |f o o b a r
63 | . 64 | 65 | Should not have a whitespace between text and "==": 66 | . 67 | foo == bar == baz 68 | . 69 |foo == bar == baz
70 | . 71 | 72 | 73 | Newline should be considered a whitespace: 74 | 75 | . 76 | ==test 77 | == 78 | 79 | == 80 | test== 81 | 82 | == 83 | test 84 | == 85 | . 86 |== 88 | test==
89 |== 90 | test 91 | ==
92 | . 93 | -------------------------------------------------------------------------------- /test/fixtures/remarkable/proto.txt: -------------------------------------------------------------------------------- 1 | 2 | . 3 | [__proto__] 4 | 5 | [__proto__]: blah 6 | . 7 | 8 | . 9 | 10 | . 11 | [^__proto__] 12 | 13 | [^__proto__]: blah 14 | . 15 | 16 |blah ↩
20 |proto __proto__
31 | . 32 | 33 | . 34 | [hasOwnProperty] 35 | 36 | [hasOwnProperty]: blah 37 | . 38 | 39 | . 40 | 41 | . 42 | [^hasOwnProperty] 43 | 44 | [^hasOwnProperty]: blah 45 | . 46 | 47 |blah ↩
51 |hasOwnProperty
62 | . 63 | -------------------------------------------------------------------------------- /test/fixtures/remarkable/redos.txt: -------------------------------------------------------------------------------- 1 | . 2 | ReDoS 3 | . 4 |ReDoS<![CDATA[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]] >
5 | . 6 | 7 | . 8 | z 9 | . 10 |z<!–aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa—>
11 | . 12 | -------------------------------------------------------------------------------- /test/fixtures/remarkable/smartquotes.txt: -------------------------------------------------------------------------------- 1 | Should parse nested quotes: 2 | 3 | . 4 | "foo 'bar' baz" 5 | . 6 |“foo ‘bar’ baz”
7 | . 8 | 9 | . 10 | 'foo 'bar' baz' 11 | . 12 |‘foo ‘bar’ baz’
13 | . 14 | 15 | 16 | Should not overlap quotes: 17 | 18 | . 19 | 'foo "bar' baz" 20 | . 21 |‘foo "bar’ baz"
22 | . 23 | 24 | 25 | Should match quotes on the same level: 26 | 27 | . 28 | "foo *bar* baz" 29 | . 30 |“foo bar baz”
31 | . 32 | 33 | 34 | Should not match quotes on different levels: 35 | 36 | . 37 | *"foo* bar" 38 | 39 | "foo *bar"* 40 | . 41 |"foo bar"
42 |"foo bar"
43 | . 44 | 45 | . 46 | *"foo* bar *baz"* 47 | . 48 |"foo bar baz"
49 | . 50 | 51 | 52 | Should try and find matching quote in this case: 53 | 54 | . 55 | "foo "bar 'baz" 56 | . 57 |"foo “bar 'baz”
58 | . 59 | 60 | 61 | Should not touch 'inches' in quotes: 62 | 63 | . 64 | "Monitor 21"" 65 | . 66 |“Monitor 21"”
67 | . 68 | 69 | 70 | Should render an apostrophe as a rsquo: 71 | 72 | . 73 | This isn't and can't be the best approach to implement this... 74 | . 75 |This isn’t and can’t be the best approach to implement this…
76 | . 77 | 78 | 79 | Apostrophe could end the word, that's why original smartypants replaces all of them as rsquo: 80 | 81 | . 82 | users' stuff 83 | . 84 |users’ stuff
85 | . 86 | -------------------------------------------------------------------------------- /test/fixtures/remarkable/sub.txt: -------------------------------------------------------------------------------- 1 | 2 | . 3 | ~foo\~ 4 | . 5 |~foo~
6 | . 7 | 8 | . 9 | ~foo bar~ 10 | . 11 |~foo bar~
12 | . 13 | 14 | . 15 | ~foo\ bar\ baz~ 16 | . 17 |foo bar baz
18 | . 19 | 20 | . 21 | ~\ foo\ ~ 22 | . 23 |foo
24 | . 25 | 26 | . 27 | ~foo\\\\\\\ bar~ 28 | . 29 |foo\\\ bar
30 | . 31 | 32 | . 33 | ~foo\\\\\\ bar~ 34 | . 35 |~foo\\\ bar~
36 | . 37 | -------------------------------------------------------------------------------- /test/fixtures/remarkable/sup.txt: -------------------------------------------------------------------------------- 1 | 2 | . 3 | ^test^ 4 | . 5 |test
6 | . 7 | 8 | . 9 | ^foo\^ 10 | . 11 |^foo^
12 | . 13 | 14 | . 15 | 2^4 + 3^5 16 | . 17 |2^4 + 3^5
18 | . 19 | 20 | . 21 | ^foo~bar^baz^bar~foo^ 22 | . 23 |foo~barbazbar~foo
24 | . 25 | 26 | . 27 | ^\ foo\ ^ 28 | . 29 |foo
30 | . 31 | 32 | . 33 | ^foo\\\\\\\ bar^ 34 | . 35 |foo\\\ bar
36 | . 37 | 38 | . 39 | ^foo\\\\\\ bar^ 40 | . 41 |^foo\\\ bar^
42 | . 43 | -------------------------------------------------------------------------------- /test/fixtures/remarkable/tables.txt: -------------------------------------------------------------------------------- 1 | Tests from marked: 2 | 3 | . 4 | | Heading 1 | Heading 2 5 | | --------- | --------- 6 | | Cell 1 | Cell 2 7 | | Cell 3 | Cell 4 8 | . 9 |Heading 1 | Heading 2 |
---|---|
Cell 1 | Cell 2 |
Cell 3 | Cell 4 |
Header 1 | Header 2 | Header 3 | Header 4 |
---|---|---|---|
Cell 1 | Cell 2 | Cell 3 | Cell 4 |
Cell 5 | Cell 6 | Cell 7 | Cell 8 |
Header 1 | Header 2 |
---|---|
Cell 1 | Cell 2 |
Cell 3 | Cell 4 |
Header 1 | Header 2 | Header 3 | Header 4 |
---|---|---|---|
Cell 1 | Cell 2 | Cell 3 | Cell 4 |
Cell 5 | Cell 6 | Cell 7 | Cell 8 |
80 |89 |81 | 82 |
88 |83 | 84 | 85 | foo foo 86 | 87 | bar bar
baz|baz
90 | . 91 | 92 | Nested tables inside lists: 93 | 94 | . 95 | - foo|foo 96 | ---|--- 97 | bar|bar 98 | baz|baz 99 | . 100 |foo | foo |
---|---|
bar | bar |
baz|baz
112 | . 113 | 114 | Minimal one-column table test: 115 | 116 | . 117 | | foo 118 | |---- 119 | | test2 120 | . 121 |foo |
---|
test2 |
(bad)
5 | . 6 | 7 | 8 | copyright 9 | . 10 | (c) (C) 11 | . 12 |© ©
13 | . 14 | 15 | 16 | reserved 17 | . 18 | (r) (R) 19 | . 20 |® ®
21 | . 22 | 23 | 24 | trademark 25 | . 26 | (tm) (TM) 27 | . 28 |™ ™
29 | . 30 | 31 | 32 | paragraph 33 | . 34 | (p) (P) 35 | . 36 |§ §
37 | . 38 | 39 | 40 | plus-minus 41 | . 42 | +-5 43 | . 44 |±5
45 | . 46 | 47 | 48 | ellipsis 49 | . 50 | test.. test... test..... test?..... test!.... 51 | . 52 |test… test… test… test?.. test!..
53 | . 54 | 55 | 56 | dupes 57 | . 58 | !!!!!! ???? ,, 59 | . 60 |!!! ??? ,
61 | . 62 | 63 | 64 | dashes 65 | . 66 | ---remarkable --- super--- 67 | 68 | remarkable---awesome 69 | 70 | abc ---- 71 | . 72 |—remarkable — super—
73 |remarkable—awesome
74 |abc ----
75 | . 76 | . 77 | --remarkable -- super-- 78 | 79 | remarkable--awesome 80 | . 81 |–remarkable – super–
82 |remarkable–awesome
83 | . 84 | 85 | -------------------------------------------------------------------------------- /test/fixtures/remarkable/xss.txt: -------------------------------------------------------------------------------- 1 | . 2 | [normal link](javascript) 3 | . 4 | 5 | . 6 | 7 | 8 | 9 | Should not allow some protocols in links and images 10 | 11 | . 12 | [xss link](javascript:alert(1)) 13 | 14 | [xss link](JAVASCRIPT:alert(1)) 15 | 16 | [xss link](vbscript:alert(1)) 17 | 18 | [xss link](VBSCRIPT:alert(1)) 19 | 20 | [xss link](file:///123) 21 | . 22 |[xss link](javascript:alert(1))
23 |[xss link](JAVASCRIPT:alert(1))
24 |[xss link](vbscript:alert(1))
25 |[xss link](VBSCRIPT:alert(1))
26 |[xss link](file:///123)
27 | . 28 | 29 | 30 | . 31 | [xss link]("><script>alert("xss")</script>) 32 | . 33 | 34 | . 35 | 36 | . 37 | [xss link]([xss link](<javascript:alert(1)>)
40 | . 41 | 42 | . 43 | [xss link](javascript:alert(1)) 44 | . 45 |[xss link](javascript:alert(1))
46 | . 47 | 48 | 49 | Image parser use the same code base. 50 | 51 | . 52 | ) 53 | . 54 |)
55 | . 56 | 57 | 58 | Autolinks 59 | 60 | . 61 |<javascript:alert(1)>
66 |<javascript:alert(1)>
67 | . 68 | 69 | 70 | Linkifier 71 | 72 | . 73 | javascript:alert(1) 74 | 75 | javascript:alert(1) 76 | . 77 |javascript:alert(1)
78 |javascript:alert(1)
79 | . 80 | 81 | 82 | . 83 | [ASCII control characters XSS](javascript:alert(1)) 84 | . 85 |[ASCII control characters XSS](javascript:alert(1))
86 | . 87 | -------------------------------------------------------------------------------- /test/linkify.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import assert from 'assert'; 3 | import { addTests } from './utils'; 4 | import { Remarkable } from '../lib/index'; 5 | import { linkify } from '../lib/linkify'; 6 | 7 | describe('linkify plugin', function () { 8 | var md = new Remarkable({ html: true }).use(linkify); 9 | addTests(path.join(__dirname, 'fixtures/linkify.txt'), md); 10 | }); 11 | 12 | describe('linkify option', function () { 13 | it('should warn about using linkify option instead of plugin', () => { 14 | const messages = [] 15 | const oldWarn = console.warn; 16 | console.warn = message => messages.push(message); 17 | new Remarkable({ html: true, linkify: true }); 18 | console.warn = oldWarn; 19 | assert.deepEqual(messages, [ 20 | `linkify option is removed. Use linkify plugin instead:\n\n` + 21 | `import Remarkable from 'remarkable';\n` + 22 | `import linkify from 'remarkable/linkify';\n` + 23 | `new Remarkable().use(linkify)\n` 24 | ]) 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/remarkable.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { addTests } from './utils'; 3 | import { Remarkable } from '../lib/index'; 4 | 5 | describe('remarkable', function () { 6 | var md = new Remarkable('full', { 7 | html: true, 8 | langPrefix: '', 9 | typographer: true, 10 | }); 11 | 12 | addTests(path.join(__dirname, 'fixtures/remarkable'), md); 13 | }); 14 | -------------------------------------------------------------------------------- /test/ruler.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import Ruler from '../lib/ruler'; 3 | 4 | describe('Ruler', function () { 5 | 6 | it('should replace rule (.at)', function () { 7 | var ruler = new Ruler(); 8 | var res = 0; 9 | 10 | ruler.push('test', function foo() { res = 1; }); 11 | ruler.at('test', function bar() { res = 2; }); 12 | 13 | var rules = ruler.getRules(''); 14 | 15 | assert.strictEqual(rules.length, 1); 16 | rules[0](); 17 | assert.strictEqual(res, 2); 18 | }); 19 | 20 | 21 | it('should inject before/after rule', function () { 22 | var ruler = new Ruler(); 23 | var res = 0; 24 | 25 | ruler.push('test', function foo() { res = 1; }); 26 | ruler.before('test', 'before_test', function fooBefore() { res = -10; }); 27 | ruler.after('test', 'after_test', function fooAfter() { res = 10; }); 28 | 29 | var rules = ruler.getRules(''); 30 | 31 | assert.strictEqual(rules.length, 3); 32 | rules[0](); 33 | assert.strictEqual(res, -10); 34 | rules[1](); 35 | assert.strictEqual(res, 1); 36 | rules[2](); 37 | assert.strictEqual(res, 10); 38 | }); 39 | 40 | 41 | it('should enable/disable rule', function () { 42 | var rules, ruler = new Ruler(); 43 | 44 | ruler.push('test', function foo() {}); 45 | ruler.push('test2', function bar() {}); 46 | 47 | rules = ruler.getRules(''); 48 | assert.strictEqual(rules.length, 2); 49 | 50 | ruler.disable('test'); 51 | rules = ruler.getRules(''); 52 | assert.strictEqual(rules.length, 1); 53 | ruler.disable('test2'); 54 | rules = ruler.getRules(''); 55 | assert.strictEqual(rules.length, 0); 56 | 57 | ruler.enable('test'); 58 | rules = ruler.getRules(''); 59 | assert.strictEqual(rules.length, 1); 60 | ruler.enable('test2'); 61 | rules = ruler.getRules(''); 62 | assert.strictEqual(rules.length, 2); 63 | }); 64 | 65 | 66 | it('should enable/disable multiple rule', function () { 67 | var rules, ruler = new Ruler(); 68 | 69 | ruler.push('test', function foo() {}); 70 | ruler.push('test2', function bar() {}); 71 | 72 | ruler.disable([ 'test', 'test2' ]); 73 | rules = ruler.getRules(''); 74 | assert.strictEqual(rules.length, 0); 75 | ruler.enable([ 'test', 'test2' ]); 76 | rules = ruler.getRules(''); 77 | assert.strictEqual(rules.length, 2); 78 | }); 79 | 80 | 81 | it('should enable rules by whitelist', function () { 82 | var rules, ruler = new Ruler(); 83 | 84 | ruler.push('test', function foo() {}); 85 | ruler.push('test2', function bar() {}); 86 | 87 | ruler.enable('test', true); 88 | rules = ruler.getRules(''); 89 | assert.strictEqual(rules.length, 1); 90 | }); 91 | 92 | 93 | it('should support multiple chains', function () { 94 | var rules, ruler = new Ruler(); 95 | 96 | ruler.push('test', function foo() {}); 97 | ruler.push('test2', function bar() {}, { alt: [ 'alt1' ] }); 98 | ruler.push('test2', function bar() {}, { alt: [ 'alt1', 'alt2' ] }); 99 | 100 | rules = ruler.getRules(''); 101 | assert.strictEqual(rules.length, 3); 102 | rules = ruler.getRules('alt1'); 103 | assert.strictEqual(rules.length, 2); 104 | rules = ruler.getRules('alt2'); 105 | assert.strictEqual(rules.length, 1); 106 | }); 107 | 108 | 109 | it('should fail on invalid rule name', function () { 110 | var ruler = new Ruler(); 111 | 112 | ruler.push('test', function foo() {}); 113 | 114 | assert.throws(function () { 115 | ruler.at('invalid name', function bar() {}); 116 | }); 117 | assert.throws(function () { 118 | ruler.before('invalid name', function bar() {}); 119 | }); 120 | assert.throws(function () { 121 | ruler.after('invalid name', function bar() {}); 122 | }); 123 | assert.throws(function () { 124 | ruler.enable('invalid name'); 125 | }); 126 | assert.throws(function () { 127 | ruler.disable('invalid name'); 128 | }); 129 | }); 130 | 131 | it('should always return an array, even when no rules are defined for the rule name', function () { 132 | var rules, ruler = new Ruler(); 133 | 134 | rules = ruler.getRules('list'); 135 | assert.strictEqual(rules.constructor, Array); 136 | }); 137 | 138 | }); 139 | -------------------------------------------------------------------------------- /test/test-browser.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | 4 | const readFixture = file => 5 | JSON.stringify(fs.readFileSync(file, 'utf-8')); 6 | 7 | const readFixtureDir = dir => 8 | fs.readdirSync(dir).map(file => [JSON.stringify(file), readFixture(path.join(dir, file))]); 9 | 10 | const content = ` 11 | 38 | ` 39 | 40 | fs.writeFileSync('index.html', content) 41 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import assert from 'assert'; 4 | 5 | export function addTests(fPath, markdown, skip) { 6 | var input, 7 | stat = fs.statSync(fPath); 8 | 9 | if (stat.isFile()) { 10 | input = fs.readFileSync(fPath, 'utf8'); 11 | 12 | input = input.replace(/→/g, '\t'); 13 | 14 | describe(fPath, function () { 15 | input.replace(/^\.\n([\s\S]*?)^\.\n([\s\S]*?)^\.$/gm, function(__, md, html, offset, orig) { 16 | var line = orig.slice(0, offset).split(/\r?\n/g).length; 17 | 18 | // Also skip tests if file name starts with "_" 19 | if (!skip && path.basename(fPath)[0] !== '_') { 20 | it('line ' + line, function () { 21 | assert.strictEqual(html, markdown.render(md)); 22 | }); 23 | } else { 24 | it.skip('line ' + line, function () { 25 | assert.strictEqual(html, markdown.render(md)); 26 | }); 27 | } 28 | }); 29 | }); 30 | 31 | return; 32 | } 33 | 34 | if (stat.isDirectory()) { 35 | fs.readdirSync(fPath).forEach(function (name) { 36 | addTests(path.join(fPath, name), markdown, skip); 37 | }); 38 | } 39 | } 40 | --------------------------------------------------------------------------------