1267 lines
22 KiB
JavaScript
1267 lines
22 KiB
JavaScript
// Initiate ModeTest and set defaults
|
||
var MT = ModeTest;
|
||
MT.modeName = 'markdown';
|
||
MT.modeOptions = {};
|
||
|
||
MT.testMode(
|
||
'plainText',
|
||
'foo',
|
||
[
|
||
null, 'foo'
|
||
]
|
||
);
|
||
|
||
// Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
|
||
MT.testMode(
|
||
'codeBlocksUsing4Spaces',
|
||
' foo',
|
||
[
|
||
null, ' ',
|
||
'comment', 'foo'
|
||
]
|
||
);
|
||
// Code blocks using 4 spaces with internal indentation
|
||
MT.testMode(
|
||
'codeBlocksUsing4SpacesIndentation',
|
||
' bar\n hello\n world\n foo\nbar',
|
||
[
|
||
null, ' ',
|
||
'comment', 'bar',
|
||
null, ' ',
|
||
'comment', 'hello',
|
||
null, ' ',
|
||
'comment', 'world',
|
||
null, ' ',
|
||
'comment', 'foo',
|
||
null, 'bar'
|
||
]
|
||
);
|
||
// Code blocks using 4 spaces with internal indentation
|
||
MT.testMode(
|
||
'codeBlocksUsing4SpacesIndentation',
|
||
' foo\n bar\n hello\n world',
|
||
[
|
||
null, ' foo',
|
||
null, ' ',
|
||
'comment', 'bar',
|
||
null, ' ',
|
||
'comment', 'hello',
|
||
null, ' ',
|
||
'comment', 'world'
|
||
]
|
||
);
|
||
|
||
// Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
|
||
MT.testMode(
|
||
'codeBlocksUsing1Tab',
|
||
'\tfoo',
|
||
[
|
||
null, '\t',
|
||
'comment', 'foo'
|
||
]
|
||
);
|
||
|
||
// Inline code using backticks
|
||
MT.testMode(
|
||
'inlineCodeUsingBackticks',
|
||
'foo `bar`',
|
||
[
|
||
null, 'foo ',
|
||
'comment', '`bar`'
|
||
]
|
||
);
|
||
|
||
// Block code using single backtick (shouldn't work)
|
||
MT.testMode(
|
||
'blockCodeSingleBacktick',
|
||
'`\nfoo\n`',
|
||
[
|
||
'comment', '`',
|
||
null, 'foo',
|
||
'comment', '`'
|
||
]
|
||
);
|
||
|
||
// Unclosed backticks
|
||
// Instead of simply marking as CODE, it would be nice to have an
|
||
// incomplete flag for CODE, that is styled slightly different.
|
||
MT.testMode(
|
||
'unclosedBackticks',
|
||
'foo `bar',
|
||
[
|
||
null, 'foo ',
|
||
'comment', '`bar'
|
||
]
|
||
);
|
||
|
||
// Per documentation: "To include a literal backtick character within a
|
||
// code span, you can use multiple backticks as the opening and closing
|
||
// delimiters"
|
||
MT.testMode(
|
||
'doubleBackticks',
|
||
'``foo ` bar``',
|
||
[
|
||
'comment', '``foo ` bar``'
|
||
]
|
||
);
|
||
|
||
// Tests based on Dingus
|
||
// http://daringfireball.net/projects/markdown/dingus
|
||
//
|
||
// Multiple backticks within an inline code block
|
||
MT.testMode(
|
||
'consecutiveBackticks',
|
||
'`foo```bar`',
|
||
[
|
||
'comment', '`foo```bar`'
|
||
]
|
||
);
|
||
// Multiple backticks within an inline code block with a second code block
|
||
MT.testMode(
|
||
'consecutiveBackticks',
|
||
'`foo```bar` hello `world`',
|
||
[
|
||
'comment', '`foo```bar`',
|
||
null, ' hello ',
|
||
'comment', '`world`'
|
||
]
|
||
);
|
||
// Unclosed with several different groups of backticks
|
||
MT.testMode(
|
||
'unclosedBackticks',
|
||
'``foo ``` bar` hello',
|
||
[
|
||
'comment', '``foo ``` bar` hello'
|
||
]
|
||
);
|
||
// Closed with several different groups of backticks
|
||
MT.testMode(
|
||
'closedBackticks',
|
||
'``foo ``` bar` hello`` world',
|
||
[
|
||
'comment', '``foo ``` bar` hello``',
|
||
null, ' world'
|
||
]
|
||
);
|
||
|
||
// atx headers
|
||
// http://daringfireball.net/projects/markdown/syntax#header
|
||
//
|
||
// H1
|
||
MT.testMode(
|
||
'atxH1',
|
||
'# foo',
|
||
[
|
||
'header', '# foo'
|
||
]
|
||
);
|
||
// H2
|
||
MT.testMode(
|
||
'atxH2',
|
||
'## foo',
|
||
[
|
||
'header', '## foo'
|
||
]
|
||
);
|
||
// H3
|
||
MT.testMode(
|
||
'atxH3',
|
||
'### foo',
|
||
[
|
||
'header', '### foo'
|
||
]
|
||
);
|
||
// H4
|
||
MT.testMode(
|
||
'atxH4',
|
||
'#### foo',
|
||
[
|
||
'header', '#### foo'
|
||
]
|
||
);
|
||
// H5
|
||
MT.testMode(
|
||
'atxH5',
|
||
'##### foo',
|
||
[
|
||
'header', '##### foo'
|
||
]
|
||
);
|
||
// H6
|
||
MT.testMode(
|
||
'atxH6',
|
||
'###### foo',
|
||
[
|
||
'header', '###### foo'
|
||
]
|
||
);
|
||
// H6 - 7x '#' should still be H6, per Dingus
|
||
// http://daringfireball.net/projects/markdown/dingus
|
||
MT.testMode(
|
||
'atxH6NotH7',
|
||
'####### foo',
|
||
[
|
||
'header', '####### foo'
|
||
]
|
||
);
|
||
|
||
// Setext headers - H1, H2
|
||
// Per documentation, "Any number of underlining =’s or -’s will work."
|
||
// http://daringfireball.net/projects/markdown/syntax#header
|
||
// Ideally, the text would be marked as `header` as well, but this is
|
||
// not really feasible at the moment. So, instead, we're testing against
|
||
// what works today, to avoid any regressions.
|
||
//
|
||
// Check if single underlining = works
|
||
MT.testMode(
|
||
'setextH1',
|
||
'foo\n=',
|
||
[
|
||
null, 'foo',
|
||
'header', '='
|
||
]
|
||
);
|
||
// Check if 3+ ='s work
|
||
MT.testMode(
|
||
'setextH1',
|
||
'foo\n===',
|
||
[
|
||
null, 'foo',
|
||
'header', '==='
|
||
]
|
||
);
|
||
// Check if single underlining - works
|
||
MT.testMode(
|
||
'setextH2',
|
||
'foo\n-',
|
||
[
|
||
null, 'foo',
|
||
'header', '-'
|
||
]
|
||
);
|
||
// Check if 3+ -'s work
|
||
MT.testMode(
|
||
'setextH2',
|
||
'foo\n---',
|
||
[
|
||
null, 'foo',
|
||
'header', '---'
|
||
]
|
||
);
|
||
|
||
// Single-line blockquote with trailing space
|
||
MT.testMode(
|
||
'blockquoteSpace',
|
||
'> foo',
|
||
[
|
||
'quote', '> foo'
|
||
]
|
||
);
|
||
|
||
// Single-line blockquote
|
||
MT.testMode(
|
||
'blockquoteNoSpace',
|
||
'>foo',
|
||
[
|
||
'quote', '>foo'
|
||
]
|
||
);
|
||
|
||
// Single-line blockquote followed by normal paragraph
|
||
MT.testMode(
|
||
'blockquoteThenParagraph',
|
||
'>foo\n\nbar',
|
||
[
|
||
'quote', '>foo',
|
||
null, 'bar'
|
||
]
|
||
);
|
||
|
||
// Multi-line blockquote (lazy mode)
|
||
MT.testMode(
|
||
'multiBlockquoteLazy',
|
||
'>foo\nbar',
|
||
[
|
||
'quote', '>foo',
|
||
'quote', 'bar'
|
||
]
|
||
);
|
||
|
||
// Multi-line blockquote followed by normal paragraph (lazy mode)
|
||
MT.testMode(
|
||
'multiBlockquoteLazyThenParagraph',
|
||
'>foo\nbar\n\nhello',
|
||
[
|
||
'quote', '>foo',
|
||
'quote', 'bar',
|
||
null, 'hello'
|
||
]
|
||
);
|
||
|
||
// Multi-line blockquote (non-lazy mode)
|
||
MT.testMode(
|
||
'multiBlockquote',
|
||
'>foo\n>bar',
|
||
[
|
||
'quote', '>foo',
|
||
'quote', '>bar'
|
||
]
|
||
);
|
||
|
||
// Multi-line blockquote followed by normal paragraph (non-lazy mode)
|
||
MT.testMode(
|
||
'multiBlockquoteThenParagraph',
|
||
'>foo\n>bar\n\nhello',
|
||
[
|
||
'quote', '>foo',
|
||
'quote', '>bar',
|
||
null, 'hello'
|
||
]
|
||
);
|
||
|
||
// Check list types
|
||
MT.testMode(
|
||
'listAsterisk',
|
||
'* foo\n* bar',
|
||
[
|
||
'string', '* foo',
|
||
'string', '* bar'
|
||
]
|
||
);
|
||
MT.testMode(
|
||
'listPlus',
|
||
'+ foo\n+ bar',
|
||
[
|
||
'string', '+ foo',
|
||
'string', '+ bar'
|
||
]
|
||
);
|
||
MT.testMode(
|
||
'listDash',
|
||
'- foo\n- bar',
|
||
[
|
||
'string', '- foo',
|
||
'string', '- bar'
|
||
]
|
||
);
|
||
MT.testMode(
|
||
'listNumber',
|
||
'1. foo\n2. bar',
|
||
[
|
||
'string', '1. foo',
|
||
'string', '2. bar'
|
||
]
|
||
);
|
||
|
||
// Formatting in lists (*)
|
||
MT.testMode(
|
||
'listAsteriskFormatting',
|
||
'* *foo* bar\n\n* **foo** bar\n\n* ***foo*** bar\n\n* `foo` bar',
|
||
[
|
||
'string', '* ',
|
||
'string em', '*foo*',
|
||
'string', ' bar',
|
||
'string', '* ',
|
||
'string strong', '**foo**',
|
||
'string', ' bar',
|
||
'string', '* ',
|
||
'string strong', '**',
|
||
'string emstrong', '*foo**',
|
||
'string em', '*',
|
||
'string', ' bar',
|
||
'string', '* ',
|
||
'string comment', '`foo`',
|
||
'string', ' bar'
|
||
]
|
||
);
|
||
// Formatting in lists (+)
|
||
MT.testMode(
|
||
'listPlusFormatting',
|
||
'+ *foo* bar\n\n+ **foo** bar\n\n+ ***foo*** bar\n\n+ `foo` bar',
|
||
[
|
||
'string', '+ ',
|
||
'string em', '*foo*',
|
||
'string', ' bar',
|
||
'string', '+ ',
|
||
'string strong', '**foo**',
|
||
'string', ' bar',
|
||
'string', '+ ',
|
||
'string strong', '**',
|
||
'string emstrong', '*foo**',
|
||
'string em', '*',
|
||
'string', ' bar',
|
||
'string', '+ ',
|
||
'string comment', '`foo`',
|
||
'string', ' bar'
|
||
]
|
||
);
|
||
// Formatting in lists (-)
|
||
MT.testMode(
|
||
'listDashFormatting',
|
||
'- *foo* bar\n\n- **foo** bar\n\n- ***foo*** bar\n\n- `foo` bar',
|
||
[
|
||
'string', '- ',
|
||
'string em', '*foo*',
|
||
'string', ' bar',
|
||
'string', '- ',
|
||
'string strong', '**foo**',
|
||
'string', ' bar',
|
||
'string', '- ',
|
||
'string strong', '**',
|
||
'string emstrong', '*foo**',
|
||
'string em', '*',
|
||
'string', ' bar',
|
||
'string', '- ',
|
||
'string comment', '`foo`',
|
||
'string', ' bar'
|
||
]
|
||
);
|
||
// Formatting in lists (1.)
|
||
MT.testMode(
|
||
'listNumberFormatting',
|
||
'1. *foo* bar\n\n2. **foo** bar\n\n3. ***foo*** bar\n\n4. `foo` bar',
|
||
[
|
||
'string', '1. ',
|
||
'string em', '*foo*',
|
||
'string', ' bar',
|
||
'string', '2. ',
|
||
'string strong', '**foo**',
|
||
'string', ' bar',
|
||
'string', '3. ',
|
||
'string strong', '**',
|
||
'string emstrong', '*foo**',
|
||
'string em', '*',
|
||
'string', ' bar',
|
||
'string', '4. ',
|
||
'string comment', '`foo`',
|
||
'string', ' bar'
|
||
]
|
||
);
|
||
|
||
// Paragraph lists
|
||
MT.testMode(
|
||
'listParagraph',
|
||
'* foo\n\n* bar',
|
||
[
|
||
'string', '* foo',
|
||
'string', '* bar'
|
||
]
|
||
);
|
||
|
||
// Multi-paragraph lists
|
||
//
|
||
// 4 spaces
|
||
MT.testMode(
|
||
'listMultiParagraph',
|
||
'* foo\n\n* bar\n\n hello',
|
||
[
|
||
'string', '* foo',
|
||
'string', '* bar',
|
||
null, ' ',
|
||
'string', 'hello'
|
||
]
|
||
);
|
||
// 4 spaces, extra blank lines (should still be list, per Dingus)
|
||
MT.testMode(
|
||
'listMultiParagraphExtra',
|
||
'* foo\n\n* bar\n\n\n hello',
|
||
[
|
||
'string', '* foo',
|
||
'string', '* bar',
|
||
null, ' ',
|
||
'string', 'hello'
|
||
]
|
||
);
|
||
// 4 spaces, plus 1 space (should still be list, per Dingus)
|
||
MT.testMode(
|
||
'listMultiParagraphExtraSpace',
|
||
'* foo\n\n* bar\n\n hello\n\n world',
|
||
[
|
||
'string', '* foo',
|
||
'string', '* bar',
|
||
null, ' ',
|
||
'string', 'hello',
|
||
null, ' ',
|
||
'string', 'world'
|
||
]
|
||
);
|
||
// 1 tab
|
||
MT.testMode(
|
||
'listTab',
|
||
'* foo\n\n* bar\n\n\thello',
|
||
[
|
||
'string', '* foo',
|
||
'string', '* bar',
|
||
null, '\t',
|
||
'string', 'hello'
|
||
]
|
||
);
|
||
// No indent
|
||
MT.testMode(
|
||
'listNoIndent',
|
||
'* foo\n\n* bar\n\nhello',
|
||
[
|
||
'string', '* foo',
|
||
'string', '* bar',
|
||
null, 'hello'
|
||
]
|
||
);
|
||
// Blockquote
|
||
MT.testMode(
|
||
'blockquote',
|
||
'* foo\n\n* bar\n\n > hello',
|
||
[
|
||
'string', '* foo',
|
||
'string', '* bar',
|
||
null, ' ',
|
||
'string quote', '> hello'
|
||
]
|
||
);
|
||
// Code block
|
||
MT.testMode(
|
||
'blockquoteCode',
|
||
'* foo\n\n* bar\n\n > hello\n\n world',
|
||
[
|
||
'string', '* foo',
|
||
'string', '* bar',
|
||
null, ' ',
|
||
'comment', '> hello',
|
||
null, ' ',
|
||
'string', 'world'
|
||
]
|
||
);
|
||
// Code block followed by text
|
||
MT.testMode(
|
||
'blockquoteCodeText',
|
||
'* foo\n\n bar\n\n hello\n\n world',
|
||
[
|
||
'string', '* foo',
|
||
null, ' ',
|
||
'string', 'bar',
|
||
null, ' ',
|
||
'comment', 'hello',
|
||
null, ' ',
|
||
'string', 'world'
|
||
]
|
||
);
|
||
|
||
// Nested list
|
||
//
|
||
// *
|
||
MT.testMode(
|
||
'listAsteriskNested',
|
||
'* foo\n\n * bar',
|
||
[
|
||
'string', '* foo',
|
||
null, ' ',
|
||
'string', '* bar'
|
||
]
|
||
);
|
||
// +
|
||
MT.testMode(
|
||
'listPlusNested',
|
||
'+ foo\n\n + bar',
|
||
[
|
||
'string', '+ foo',
|
||
null, ' ',
|
||
'string', '+ bar'
|
||
]
|
||
);
|
||
// -
|
||
MT.testMode(
|
||
'listDashNested',
|
||
'- foo\n\n - bar',
|
||
[
|
||
'string', '- foo',
|
||
null, ' ',
|
||
'string', '- bar'
|
||
]
|
||
);
|
||
// 1.
|
||
MT.testMode(
|
||
'listNumberNested',
|
||
'1. foo\n\n 2. bar',
|
||
[
|
||
'string', '1. foo',
|
||
null, ' ',
|
||
'string', '2. bar'
|
||
]
|
||
);
|
||
// Mixed
|
||
MT.testMode(
|
||
'listMixed',
|
||
'* foo\n\n + bar\n\n - hello\n\n 1. world',
|
||
[
|
||
'string', '* foo',
|
||
null, ' ',
|
||
'string', '+ bar',
|
||
null, ' ',
|
||
'string', '- hello',
|
||
null, ' ',
|
||
'string', '1. world'
|
||
]
|
||
);
|
||
// Blockquote
|
||
MT.testMode(
|
||
'listBlockquote',
|
||
'* foo\n\n + bar\n\n > hello',
|
||
[
|
||
'string', '* foo',
|
||
null, ' ',
|
||
'string', '+ bar',
|
||
null, ' ',
|
||
'quote string', '> hello'
|
||
]
|
||
);
|
||
// Code
|
||
MT.testMode(
|
||
'listCode',
|
||
'* foo\n\n + bar\n\n hello',
|
||
[
|
||
'string', '* foo',
|
||
null, ' ',
|
||
'string', '+ bar',
|
||
null, ' ',
|
||
'comment', 'hello'
|
||
]
|
||
);
|
||
// Code with internal indentation
|
||
MT.testMode(
|
||
'listCodeIndentation',
|
||
'* foo\n\n bar\n hello\n world\n foo\n bar',
|
||
[
|
||
'string', '* foo',
|
||
null, ' ',
|
||
'comment', 'bar',
|
||
null, ' ',
|
||
'comment', 'hello',
|
||
null, ' ',
|
||
'comment', 'world',
|
||
null, ' ',
|
||
'comment', 'foo',
|
||
null, ' ',
|
||
'string', 'bar'
|
||
]
|
||
);
|
||
// Code followed by text
|
||
MT.testMode(
|
||
'listCodeText',
|
||
'* foo\n\n bar\n\nhello',
|
||
[
|
||
'string', '* foo',
|
||
null, ' ',
|
||
'comment', 'bar',
|
||
null, 'hello'
|
||
]
|
||
);
|
||
|
||
// Following tests directly from official Markdown documentation
|
||
// http://daringfireball.net/projects/markdown/syntax#hr
|
||
MT.testMode(
|
||
'hrSpace',
|
||
'* * *',
|
||
[
|
||
'hr', '* * *'
|
||
]
|
||
);
|
||
|
||
MT.testMode(
|
||
'hr',
|
||
'***',
|
||
[
|
||
'hr', '***'
|
||
]
|
||
);
|
||
|
||
MT.testMode(
|
||
'hrLong',
|
||
'*****',
|
||
[
|
||
'hr', '*****'
|
||
]
|
||
);
|
||
|
||
MT.testMode(
|
||
'hrSpaceDash',
|
||
'- - -',
|
||
[
|
||
'hr', '- - -'
|
||
]
|
||
);
|
||
|
||
MT.testMode(
|
||
'hrDashLong',
|
||
'---------------------------------------',
|
||
[
|
||
'hr', '---------------------------------------'
|
||
]
|
||
);
|
||
|
||
// Inline link with title
|
||
MT.testMode(
|
||
'linkTitle',
|
||
'[foo](http://example.com/ "bar") hello',
|
||
[
|
||
'link', '[foo]',
|
||
'string', '(http://example.com/ "bar")',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
|
||
// Inline link without title
|
||
MT.testMode(
|
||
'linkNoTitle',
|
||
'[foo](http://example.com/) bar',
|
||
[
|
||
'link', '[foo]',
|
||
'string', '(http://example.com/)',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
|
||
// Inline link with Em
|
||
MT.testMode(
|
||
'linkEm',
|
||
'[*foo*](http://example.com/) bar',
|
||
[
|
||
'link', '[',
|
||
'link em', '*foo*',
|
||
'link', ']',
|
||
'string', '(http://example.com/)',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
|
||
// Inline link with Strong
|
||
MT.testMode(
|
||
'linkStrong',
|
||
'[**foo**](http://example.com/) bar',
|
||
[
|
||
'link', '[',
|
||
'link strong', '**foo**',
|
||
'link', ']',
|
||
'string', '(http://example.com/)',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
|
||
// Inline link with EmStrong
|
||
MT.testMode(
|
||
'linkEmStrong',
|
||
'[***foo***](http://example.com/) bar',
|
||
[
|
||
'link', '[',
|
||
'link strong', '**',
|
||
'link emstrong', '*foo**',
|
||
'link em', '*',
|
||
'link', ']',
|
||
'string', '(http://example.com/)',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
|
||
// Image with title
|
||
MT.testMode(
|
||
'imageTitle',
|
||
' hello',
|
||
[
|
||
'tag', '![foo]',
|
||
'string', '(http://example.com/ "bar")',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
|
||
// Image without title
|
||
MT.testMode(
|
||
'imageNoTitle',
|
||
' bar',
|
||
[
|
||
'tag', '![foo]',
|
||
'string', '(http://example.com/)',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
|
||
// Image with asterisks
|
||
MT.testMode(
|
||
'imageAsterisks',
|
||
' bar',
|
||
[
|
||
'tag', '![*foo*]',
|
||
'string', '(http://example.com/)',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
|
||
// Not a link. Should be normal text due to square brackets being used
|
||
// regularly in text, especially in quoted material, and no space is allowed
|
||
// between square brackets and parentheses (per Dingus).
|
||
MT.testMode(
|
||
'notALink',
|
||
'[foo] (bar)',
|
||
[
|
||
null, '[foo] (bar)'
|
||
]
|
||
);
|
||
|
||
// Reference-style links
|
||
MT.testMode(
|
||
'linkReference',
|
||
'[foo][bar] hello',
|
||
[
|
||
'link', '[foo]',
|
||
'string', '[bar]',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
// Reference-style links with Em
|
||
MT.testMode(
|
||
'linkReferenceEm',
|
||
'[*foo*][bar] hello',
|
||
[
|
||
'link', '[',
|
||
'link em', '*foo*',
|
||
'link', ']',
|
||
'string', '[bar]',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
// Reference-style links with Strong
|
||
MT.testMode(
|
||
'linkReferenceStrong',
|
||
'[**foo**][bar] hello',
|
||
[
|
||
'link', '[',
|
||
'link strong', '**foo**',
|
||
'link', ']',
|
||
'string', '[bar]',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
// Reference-style links with EmStrong
|
||
MT.testMode(
|
||
'linkReferenceEmStrong',
|
||
'[***foo***][bar] hello',
|
||
[
|
||
'link', '[',
|
||
'link strong', '**',
|
||
'link emstrong', '*foo**',
|
||
'link em', '*',
|
||
'link', ']',
|
||
'string', '[bar]',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
|
||
// Reference-style links with optional space separator (per docuentation)
|
||
// "You can optionally use a space to separate the sets of brackets"
|
||
MT.testMode(
|
||
'linkReferenceSpace',
|
||
'[foo] [bar] hello',
|
||
[
|
||
'link', '[foo]',
|
||
null, ' ',
|
||
'string', '[bar]',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
// Should only allow a single space ("...use *a* space...")
|
||
MT.testMode(
|
||
'linkReferenceDoubleSpace',
|
||
'[foo] [bar] hello',
|
||
[
|
||
null, '[foo] [bar] hello'
|
||
]
|
||
);
|
||
|
||
// Reference-style links with implicit link name
|
||
MT.testMode(
|
||
'linkImplicit',
|
||
'[foo][] hello',
|
||
[
|
||
'link', '[foo]',
|
||
'string', '[]',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
|
||
// @todo It would be nice if, at some point, the document was actually
|
||
// checked to see if the referenced link exists
|
||
|
||
// Link label, for reference-style links (taken from documentation)
|
||
//
|
||
// No title
|
||
MT.testMode(
|
||
'labelNoTitle',
|
||
'[foo]: http://example.com/',
|
||
[
|
||
'link', '[foo]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/'
|
||
]
|
||
);
|
||
// Space in ID and title
|
||
MT.testMode(
|
||
'labelSpaceTitle',
|
||
'[foo bar]: http://example.com/ "hello"',
|
||
[
|
||
'link', '[foo bar]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/ "hello"'
|
||
]
|
||
);
|
||
// Double title
|
||
MT.testMode(
|
||
'labelDoubleTitle',
|
||
'[foo bar]: http://example.com/ "hello" "world"',
|
||
[
|
||
'link', '[foo bar]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/ "hello"',
|
||
null, ' "world"'
|
||
]
|
||
);
|
||
// Double quotes around title
|
||
MT.testMode(
|
||
'labelTitleDoubleQuotes',
|
||
'[foo]: http://example.com/ "bar"',
|
||
[
|
||
'link', '[foo]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/ "bar"'
|
||
]
|
||
);
|
||
// Single quotes around title
|
||
MT.testMode(
|
||
'labelTitleSingleQuotes',
|
||
'[foo]: http://example.com/ \'bar\'',
|
||
[
|
||
'link', '[foo]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/ \'bar\''
|
||
]
|
||
);
|
||
// Parentheses around title
|
||
MT.testMode(
|
||
'labelTitleParenthese',
|
||
'[foo]: http://example.com/ (bar)',
|
||
[
|
||
'link', '[foo]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/ (bar)'
|
||
]
|
||
);
|
||
// Invalid title
|
||
MT.testMode(
|
||
'labelTitleInvalid',
|
||
'[foo]: http://example.com/ bar',
|
||
[
|
||
'link', '[foo]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
// Angle brackets around URL
|
||
MT.testMode(
|
||
'labelLinkAngleBrackets',
|
||
'[foo]: <http://example.com/> "bar"',
|
||
[
|
||
'link', '[foo]:',
|
||
null, ' ',
|
||
'string', '<http://example.com/> "bar"'
|
||
]
|
||
);
|
||
// Title on next line per documentation (double quotes)
|
||
MT.testMode(
|
||
'labelTitleNextDoubleQuotes',
|
||
'[foo]: http://example.com/\n"bar" hello',
|
||
[
|
||
'link', '[foo]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/',
|
||
'string', '"bar"',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
// Title on next line per documentation (single quotes)
|
||
MT.testMode(
|
||
'labelTitleNextSingleQuotes',
|
||
'[foo]: http://example.com/\n\'bar\' hello',
|
||
[
|
||
'link', '[foo]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/',
|
||
'string', '\'bar\'',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
// Title on next line per documentation (parentheses)
|
||
MT.testMode(
|
||
'labelTitleNextParenthese',
|
||
'[foo]: http://example.com/\n(bar) hello',
|
||
[
|
||
'link', '[foo]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/',
|
||
'string', '(bar)',
|
||
null, ' hello'
|
||
]
|
||
);
|
||
// Title on next line per documentation (mixed)
|
||
MT.testMode(
|
||
'labelTitleNextMixed',
|
||
'[foo]: http://example.com/\n(bar" hello',
|
||
[
|
||
'link', '[foo]:',
|
||
null, ' ',
|
||
'string', 'http://example.com/',
|
||
null, '(bar" hello'
|
||
]
|
||
);
|
||
|
||
// Automatic links
|
||
MT.testMode(
|
||
'linkWeb',
|
||
'<http://example.com/> foo',
|
||
[
|
||
'link', '<http://example.com/>',
|
||
null, ' foo'
|
||
]
|
||
);
|
||
|
||
// Automatic email links
|
||
MT.testMode(
|
||
'linkEmail',
|
||
'<user@example.com> foo',
|
||
[
|
||
'link', '<user@example.com>',
|
||
null, ' foo'
|
||
]
|
||
);
|
||
|
||
// Single asterisk
|
||
MT.testMode(
|
||
'emAsterisk',
|
||
'*foo* bar',
|
||
[
|
||
'em', '*foo*',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
|
||
// Single underscore
|
||
MT.testMode(
|
||
'emUnderscore',
|
||
'_foo_ bar',
|
||
[
|
||
'em', '_foo_',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
|
||
// Emphasis characters within a word
|
||
MT.testMode(
|
||
'emInWordAsterisk',
|
||
'foo*bar*hello',
|
||
[
|
||
null, 'foo',
|
||
'em', '*bar*',
|
||
null, 'hello'
|
||
]
|
||
);
|
||
MT.testMode(
|
||
'emInWordUnderscore',
|
||
'foo_bar_hello',
|
||
[
|
||
null, 'foo',
|
||
'em', '_bar_',
|
||
null, 'hello'
|
||
]
|
||
);
|
||
// Per documentation: "...surround an * or _ with spaces, it’ll be
|
||
// treated as a literal asterisk or underscore."
|
||
//
|
||
// Inside EM
|
||
MT.testMode(
|
||
'emEscapedBySpaceIn',
|
||
'foo _bar _ hello_ world',
|
||
[
|
||
null, 'foo ',
|
||
'em', '_bar _ hello_',
|
||
null, ' world'
|
||
]
|
||
);
|
||
// Outside EM
|
||
MT.testMode(
|
||
'emEscapedBySpaceOut',
|
||
'foo _ bar_hello_world',
|
||
[
|
||
null, 'foo _ bar',
|
||
'em', '_hello_',
|
||
null, 'world'
|
||
]
|
||
);
|
||
|
||
// Unclosed emphasis characters
|
||
// Instead of simply marking as EM / STRONG, it would be nice to have an
|
||
// incomplete flag for EM and STRONG, that is styled slightly different.
|
||
MT.testMode(
|
||
'emIncompleteAsterisk',
|
||
'foo *bar',
|
||
[
|
||
null, 'foo ',
|
||
'em', '*bar'
|
||
]
|
||
);
|
||
MT.testMode(
|
||
'emIncompleteUnderscore',
|
||
'foo _bar',
|
||
[
|
||
null, 'foo ',
|
||
'em', '_bar'
|
||
]
|
||
);
|
||
|
||
// Double asterisk
|
||
MT.testMode(
|
||
'strongAsterisk',
|
||
'**foo** bar',
|
||
[
|
||
'strong', '**foo**',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
|
||
// Double underscore
|
||
MT.testMode(
|
||
'strongUnderscore',
|
||
'__foo__ bar',
|
||
[
|
||
'strong', '__foo__',
|
||
null, ' bar'
|
||
]
|
||
);
|
||
|
||
// Triple asterisk
|
||
MT.testMode(
|
||
'emStrongAsterisk',
|
||
'*foo**bar*hello** world',
|
||
[
|
||
'em', '*foo',
|
||
'emstrong', '**bar*',
|
||
'strong', 'hello**',
|
||
null, ' world'
|
||
]
|
||
);
|
||
|
||
// Triple underscore
|
||
MT.testMode(
|
||
'emStrongUnderscore',
|
||
'_foo__bar_hello__ world',
|
||
[
|
||
'em', '_foo',
|
||
'emstrong', '__bar_',
|
||
'strong', 'hello__',
|
||
null, ' world'
|
||
]
|
||
);
|
||
|
||
// Triple mixed
|
||
// "...same character must be used to open and close an emphasis span.""
|
||
MT.testMode(
|
||
'emStrongMixed',
|
||
'_foo**bar*hello__ world',
|
||
[
|
||
'em', '_foo',
|
||
'emstrong', '**bar*hello__ world'
|
||
]
|
||
);
|
||
|
||
MT.testMode(
|
||
'emStrongMixed',
|
||
'*foo__bar_hello** world',
|
||
[
|
||
'em', '*foo',
|
||
'emstrong', '__bar_hello** world'
|
||
]
|
||
);
|
||
|
||
// These characters should be escaped:
|
||
// \ backslash
|
||
// ` backtick
|
||
// * asterisk
|
||
// _ underscore
|
||
// {} curly braces
|
||
// [] square brackets
|
||
// () parentheses
|
||
// # hash mark
|
||
// + plus sign
|
||
// - minus sign (hyphen)
|
||
// . dot
|
||
// ! exclamation mark
|
||
//
|
||
// Backtick (code)
|
||
MT.testMode(
|
||
'escapeBacktick',
|
||
'foo \\`bar\\`',
|
||
[
|
||
null, 'foo \\`bar\\`'
|
||
]
|
||
);
|
||
MT.testMode(
|
||
'doubleEscapeBacktick',
|
||
'foo \\\\`bar\\\\`',
|
||
[
|
||
null, 'foo \\\\',
|
||
'comment', '`bar\\\\`'
|
||
]
|
||
);
|
||
// Asterisk (em)
|
||
MT.testMode(
|
||
'escapeAsterisk',
|
||
'foo \\*bar\\*',
|
||
[
|
||
null, 'foo \\*bar\\*'
|
||
]
|
||
);
|
||
MT.testMode(
|
||
'doubleEscapeAsterisk',
|
||
'foo \\\\*bar\\\\*',
|
||
[
|
||
null, 'foo \\\\',
|
||
'em', '*bar\\\\*'
|
||
]
|
||
);
|
||
// Underscore (em)
|
||
MT.testMode(
|
||
'escapeUnderscore',
|
||
'foo \\_bar\\_',
|
||
[
|
||
null, 'foo \\_bar\\_'
|
||
]
|
||
);
|
||
MT.testMode(
|
||
'doubleEscapeUnderscore',
|
||
'foo \\\\_bar\\\\_',
|
||
[
|
||
null, 'foo \\\\',
|
||
'em', '_bar\\\\_'
|
||
]
|
||
);
|
||
// Hash mark (headers)
|
||
MT.testMode(
|
||
'escapeHash',
|
||
'\\# foo',
|
||
[
|
||
null, '\\# foo'
|
||
]
|
||
);
|
||
MT.testMode(
|
||
'doubleEscapeHash',
|
||
'\\\\# foo',
|
||
[
|
||
null, '\\\\# foo'
|
||
]
|
||
);
|