import CodeMirror from '../../src/codemirror.js'; import { mediaWikiLang } from '../../src/codemirror.mode.mediawiki.js'; import { mwModeConfig } from '../../src/codemirror.mode.mediawiki.config.js'; const testCases = [ { title: 'p tags, extra closing tag', input: 'this is

content

', output: '
this is <p><div>content</p></p>
' }, { title: 'HTML tag attributes', input: '', output: '
<span title="a<b"><b title="a>b"></b></span>
' }, { title: 'ref tag attributes', input: '', output: '
<ref name="a<b"/>
' }, { title: 'indented table with caption and inline headings', input: ' ::{| class="wikitable"\n |+ Caption\n |-\n ! Uno !! Dos\n |-\n | Foo || Bar\n |}', output: '
::{| class="wikitable"
|+ Caption
|-
! Uno !! Dos
|-
| Foo || Bar
|}
' }, { title: 'apostrophe before italic', input: 'plain l\'\'\'italic\'\'plain', output: '
plain l\'\'\'italic\'\'plain
' }, { title: 'free external links', input: 'https://wikimedia.org [ftp://foo.bar FOO] //archive.org', output: '
https://wikimedia.org [ftp://foo.bar FOO] //archive.org
' }, { title: 'void tags', input: 'a
b
c a
b
c
d', output: '
a<br>b</br>c a<div>b<br>c</div>d
' }, { title: 'magic words', input: '__NOTOC__', output: '
__NOTOC__
' }, { title: 'nowiki', input: '{{foo}}

{{{\n
\n\n {{bar}}
', output: '
<nowiki>{{foo}}<p> </div> {{{</nowiki>
<nowiki/><pre class="foo">

{{bar}}</pre>
' }, { title: 'ref tag with cite web, extraneous curly braces', input: '{{cite web|2=foo}}}}', output: '
<ref>{{cite web|2=foo}}}}</ref>
' }, { title: 'template with params and parser function', input: '{{foo|1=bar|2={{{param|blah}}}|{{#if:{{{3|}}}|yes|no}}}}', output: '
{{foo|1=bar|2={{{param|blah}}}|{{#if:{{{3|}}}|yes|no}}}}
' }, { title: 'T277767: newlines and comments in template names', input: '{{#if: | {{some template\n }} }}', output: '
{{#if: | {{some template
<!-- comment --> }} }}
' }, { title: 'T108450: template transclusion where the template name is a parameter', input: '{{{{{1}}}|…}}', output: '
{{{{{1}}}|}}
' }, { title: 'T292967: table syntax where all | are escaped with the {{!}} parser function', input: '{{{!}} class="wikitable"\n! header\n{{!}}-\n{{!}} cell\n{{!}}}', output: '
{{{!}} class="wikitable"
! header
{{!}}-
{{!}} cell
{{!}}}
' }, { title: 'section headings', input: '== My section ==\nFoo bar\n=== Blah ===\nBaz\n= { =\nText', output: '
== My section ==
Foo bar
=== Blah ===
Baz
= { =
Text
' }, { title: 'section headings with trailing comments', input: '== My section == \nFoo bar\n=== Blah ===\nBaz\n== a == ', output: '
== My section == <!-- comment -->
Foo bar
=== Blah ===<!--comment-->
Baz
== <i>a</i> <!-- comment --> == <!--comment-->
' }, { title: 'bullets and numbering, with invalid leading spacing', input: '* bullet A\n* bullet B\n# one\n # two', output: '
* bullet A
* bullet B
# one
# two
' }, { title: 'link with bold text', input: '[[Link title|\'\'\'bold link\'\'\']]', output: '
[[Link title|\'\'\'bold link\'\'\']]
' }, { title: 'horizontal rule', input: 'One\n----\nTwo', output: '
One
----
Two
' }, { title: 'comments', input: '', output: '
<!-- foo [[bar]] {{{param}}} -->
' }, { title: 'signatures', input: 'my sig ~~~ ~~~~ ~~~~~~~', output: '
my sig ~~~ ~~~~ ~~~~~~~
' }, { title: 'capitalization of tags', input: '', output: '
<ref></Ref>
' }, { title: 'multi-line tag', input: 'bar', output: '
<div
id="foo"
>bar</div>
' }, { title: 'HTML entities', input: '—\n[[/dev/null]]', output: '
&#x2014;
[[&#47;dev/null]]
' }, { title: 'Extension tag with no TagMode', input: 'foo\nbar\nbaz', output: '
<myextension>foo
bar
baz</myextension>
' } ]; // Setup CodeMirror instance. const textarea = document.createElement( 'textarea' ); document.body.appendChild( textarea ); const cm = new CodeMirror( textarea ); // Stub the config normally provided by mw.config.get('extCodeMirrorConfig') const mwLang = mediaWikiLang( { urlProtocols: 'ftp://|https://', doubleUnderscore: [ { __notoc__: 'notoc' } ], functionSynonyms: [ {}, { '!': '!' } ], tags: { nowiki: true, pre: true, ref: true, references: true, // Made-up tag, for testing when a corresponding TagMode is not configured. myextension: true }, tagModes: { ref: 'mediawiki', references: 'mediawiki' } } ); cm.initialize( [ ...cm.defaultExtensions, mwLang ] ); describe( 'CodeMirrorModeMediaWiki', () => { it.each( testCases )( 'syntax highlighting ($title)', ( { input, output } ) => { cm.view.dispatch( { changes: { from: 0, to: cm.view.state.doc.length, insert: input } } ); cm.$textarea.textSelection = jest.fn().mockReturnValue( input ); expect( cm.view.dom.querySelector( '.cm-content' ).innerHTML ).toStrictEqual( output ); } ); it( 'configuration contains all expected tokens', () => { expect( Object.keys( mwModeConfig.tags ) ).toStrictEqual( [ 'apostrophes', 'apostrophesBold', 'apostrophesItalic', 'comment', 'doubleUnderscore', 'extLink', 'extLinkBracket', 'extLinkProtocol', 'extLinkText', 'hr', 'htmlTagAttribute', 'htmlTagBracket', 'htmlTagName', 'indenting', 'linkBracket', 'linkDelimiter', 'linkText', 'linkToSection', 'list', 'parserFunction', 'parserFunctionBracket', 'parserFunctionDelimiter', 'parserFunctionName', 'sectionHeader', 'sectionHeader1', 'sectionHeader2', 'sectionHeader3', 'sectionHeader4', 'sectionHeader5', 'sectionHeader6', 'signature', 'tableBracket', 'tableDefinition', 'tableDelimiter', 'template', 'templateArgumentName', 'templateBracket', 'templateDelimiter', 'templateName', 'templateVariable', 'templateVariableBracket', 'templateVariableName', // Custom tags 'em', 'error', 'extGround', 'extNowiki', 'extPre', 'extTag', 'extTagAttribute', 'extTagBracket', 'extTagName', 'freeExtLink', 'freeExtLinkProtocol', 'htmlEntity', 'link', 'linkGround', 'linkPageName', 'nowiki', 'pageName', 'pre', 'section', 'skipFormatting', 'strong', 'tableCaption', 'templateGround', 'templateExtGround', 'templateLinkGround', 'templateVariableDelimiter', 'template2ExtGround', 'template2Ground', 'template3ExtGround', 'template3Ground' ] ); } ); } );