fix(links): a number of issues with links subparser

This is a major refactor of the links subparser, previously known as anchors subparser.

Closes #355, #534

BREAKING CHANGE: `excludeTrailingPunctuationFromURLs` option was removed. This is now the default behavior
This commit is contained in:
Estevao Soares dos Santos 2018-09-25 04:04:59 +01:00
parent 798bbe6751
commit d3ebff7ef0
38 changed files with 5571 additions and 272 deletions

View File

@ -14,7 +14,7 @@
"quotmark": "single",
"undef": false,
"unused": true,
"strict": true,
"strict": false,
"trailing": true,
"smarttabs": true,
"onevar": true,

View File

@ -259,16 +259,8 @@ var defaultOptions = showdown.getDefaultOptions();
<p>some text <a href="www.google.com">www.google.com</a>
```
* **excludeTrailingPunctuationFromURLs**: (boolean) [default false] This option excludes trailing punctuation from autolinking urls.
Punctuation excluded: `. ! ? ( )`. Only applies if **simplifiedAutoLink** option is set to `true`.
```md
check this link www.google.com!
```
will be parsed as
```html
<p>check this link <a href="www.google.com">www.google.com</a>!</p>
```
* ~~**excludeTrailingPunctuationFromURLs**: (boolean) [default false] This option excludes trailing punctuation from autolinking urls.
Punctuation excluded: `. ! ? ( )`. Only applies if **simplifiedAutoLink** option is set to `true`.~~
* **literalMidWordUnderscores**: (boolean) [default false] Turning this on will stop showdown from interpreting
underscores in the middle of words as `<em>` and `<strong>` and instead treat them as literal underscores.

View File

@ -22,7 +22,7 @@
This option is weird, hard to maintain and really... makes little sense.
- [ ] **excludeTrailingPunctuationFromURLs** (removal)
- [X] **excludeTrailingPunctuationFromURLs** (removal)
This option will be removed and will be the default behavior from now on.
@ -89,16 +89,15 @@
HTML and OTP extensions will be dropped in favor of Listener Extensions. We might even give them a new name
## Subparsers
- [ ] **Anchors**: Revamp the anchors subparser so it calls strikethrough, bold, italic and underline directly
- [ ] **autoLinks**: Fix some lingering bugs and issues with autolinks
- [X] **Anchors**: Revamp the anchors subparser so it calls strikethrough, bold, italic and underline directly
- [X] **autoLinks**: Fix some lingering bugs and issues with autolinks
## Priority Bugs
- [ ] **#355**: *simplifiedAutoLink URLs inside parenthesis followed by another character are not parsed correctly*
- [X] **#355**: *simplifiedAutoLink URLs inside parenthesis followed by another character are not parsed correctly*
- [X] **#534**: *Multiple parentheses () in url link is not parsed correctly*
- [ ] **#367**: *sublists rendering with 2 spaces* - related to disableForced4SpacesIndentedSublists option...
- [ ] **#537**: *master branch doesn't work in a web worker*
## CLI
- [ ] Refactor the CLI
- [ ] **#381**: *Support for src and dst directories in showdown cli*
@ -114,6 +113,7 @@
- [ ] **#486**: *A backslash at the end of the line is a hard line break*
- [ ] **#548**: *anchors and images of subParser are errors when they are specific strings*
- [ ] **#549**: *Strange parsing issue with `<pre><code>`*
- [ ] Rethink the global variable
## NEW Features

BIN
dist/showdown.js vendored

Binary file not shown.

BIN
dist/showdown.js.map vendored

Binary file not shown.

BIN
dist/showdown.min.js vendored

Binary file not shown.

Binary file not shown.

View File

@ -396,15 +396,26 @@ showdown.helper.unescapeHTMLEntities = function (txt) {
.replace(/&amp;/g, '&');
};
showdown.helper._hashHTMLSpan = function (html, globals) {
return '¨C' + (globals.gHtmlSpans.push(html) - 1) + 'C';
};
/**
* Showdown's Event Object
* @param {string} name Name of the event
* @param {string} text Text
* @param {{}} params optional. params of the event
* @constructor
*/
showdown.helper.Event = function (name, text, params) {
'use strict';
var regexp = params.regexp || null;
var matches = params.matches || {};
var options = params.options || {};
var converter = params.converter || null;
var globals = params.globals || {};
/**
* Get the name of the event
* @returns {string}
@ -417,12 +428,6 @@ showdown.helper.Event = function (name, text, params) {
return name;
};
var regexp = params.regexp || null;
var matches = params.matches || {};
var options = params.options || {};
var converter = params.converter || null;
var globals = params.globals || {};
this._stopExecution = false;
this.parsedText = params.parsedText || null;
@ -430,30 +435,39 @@ showdown.helper.Event = function (name, text, params) {
this.getRegexp = function () {
return regexp;
};
this.getOptions = function () {
return options;
};
this.getConverter = function () {
return converter;
};
this.getGlobals = function () {
return globals;
};
this.getCapturedText = function () {
return text;
};
this.getText = function () {
return text;
};
this.setText = function (newText) {
text = newText;
};
this.getMatches = function () {
return matches;
};
this.setMatches = function (newMatches) {
matches = newMatches;
};
this.preventDefault = function (bool) {
this._stopExecution = !bool;
};
@ -485,7 +499,8 @@ if (typeof(console) === 'undefined') {
* We declare some common regexes to improve performance
*/
showdown.helper.regexes = {
asteriskDashAndColon: /([*_:~])/g
asteriskDashTildeAndColon: /([*_:~])/g,
asteriskDashAndTilde: /([*_~])/g
};
/**

View File

@ -51,11 +51,6 @@ function getDefaultOpts (simple) {
describe: 'Turn on/off GFM autolink style',
type: 'boolean'
},
excludeTrailingPunctuationFromURLs: {
defaultValue: false,
describe: 'Excludes trailing punctuation from links generated with autoLinking',
type: 'boolean'
},
literalMidWordUnderscores: {
defaultValue: false,
describe: 'Parse midword underscores as literal underscores',

View File

@ -11,7 +11,6 @@ var showdown = {},
github: {
omitExtraWLInCodeBlocks: true,
simplifiedAutoLink: true,
excludeTrailingPunctuationFromURLs: true,
literalMidWordUnderscores: true,
strikethrough: true,
tables: true,
@ -35,7 +34,6 @@ var showdown = {},
omitExtraWLInCodeBlocks: true,
parseImgDimensions: true,
simplifiedAutoLink: true,
excludeTrailingPunctuationFromURLs: true,
literalMidWordUnderscores: true,
strikethrough: true,
tables: true,

View File

@ -1,79 +0,0 @@
// url allowed chars [a-z\d_.~:/?#[]@!$&'()*+,;=-]
var simpleURLRegex = /([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi,
simpleURLRegex2 = /([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]])?(\1)?(?=\s|$)(?!["<>])/gi,
delimUrlRegex = /()<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>()/gi,
simpleMailRegex = /(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gmi,
delimMailRegex = /<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
replaceLink = function (options) {
'use strict';
return function (wm, leadingMagicChars, link, m2, m3, trailingPunctuation, trailingMagicChars) {
link = link.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
var lnkTxt = link,
append = '',
target = '',
lmc = leadingMagicChars || '',
tmc = trailingMagicChars || '';
if (/^www\./i.test(link)) {
link = link.replace(/^www\./i, 'http://www.');
}
if (options.excludeTrailingPunctuationFromURLs && trailingPunctuation) {
append = trailingPunctuation;
}
if (options.openLinksInNewWindow) {
target = ' target="¨E95Eblank"';
}
return lmc + '<a href="' + link + '"' + target + '>' + lnkTxt + '</a>' + append + tmc;
};
},
replaceMail = function (options, globals) {
'use strict';
return function (wholeMatch, b, mail) {
var href = 'mailto:';
b = b || '';
mail = showdown.subParser('makehtml.unescapeSpecialChars')(mail, options, globals);
if (options.encodeEmails) {
href = showdown.helper.encodeEmailAddress(href + mail);
mail = showdown.helper.encodeEmailAddress(mail);
} else {
href = href + mail;
}
return b + '<a href="' + href + '">' + mail + '</a>';
};
};
showdown.subParser('makehtml.autoLinks', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('makehtml.autoLinks.before', text, options, globals).getText();
text = text.replace(delimUrlRegex, replaceLink(options));
text = text.replace(delimMailRegex, replaceMail(options, globals));
text = globals.converter._dispatch('makehtml.autoLinks.after', text, options, globals).getText();
return text;
});
showdown.subParser('makehtml.simplifiedAutoLinks', function (text, options, globals) {
'use strict';
if (!options.simplifiedAutoLink) {
return text;
}
text = globals.converter._dispatch('makehtml.simplifiedAutoLinks.before', text, options, globals).getText();
if (options.excludeTrailingPunctuationFromURLs) {
text = text.replace(simpleURLRegex2, replaceLink(options));
} else {
text = text.replace(simpleURLRegex, replaceLink(options));
}
text = text.replace(simpleMailRegex, replaceMail(options, globals));
text = globals.converter._dispatch('makehtml.simplifiedAutoLinks.after', text, options, globals).getText();
return text;
});

View File

@ -5,32 +5,26 @@ showdown.subParser('makehtml.hashHTMLSpans', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('makehtml.hashHTMLSpans.before', text, options, globals).getText();
function hashHTMLSpan (html) {
return '¨C' + (globals.gHtmlSpans.push(html) - 1) + 'C';
}
// Hash Self Closing tags
text = text.replace(/<[^>]+?\/>/gi, function (wm) {
return hashHTMLSpan(wm);
return showdown.helper._hashHTMLSpan(wm, globals);
});
// Hash tags without properties
text = text.replace(/<([^>]+?)>[\s\S]*?<\/\1>/g, function (wm) {
return hashHTMLSpan(wm);
return showdown.helper._hashHTMLSpan(wm, globals);
});
// Hash tags with properties
text = text.replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g, function (wm) {
return hashHTMLSpan(wm);
return showdown.helper._hashHTMLSpan(wm, globals);
});
// Hash self closing tags without />
text = text.replace(/<[^>]+?>/gi, function (wm) {
return hashHTMLSpan(wm);
return showdown.helper._hashHTMLSpan(wm, globals);
});
/*showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');*/
text = globals.converter._dispatch('makehtml.hashHTMLSpans.after', text, options, globals).getText();
return text;
});

View File

@ -56,16 +56,16 @@ showdown.subParser('makehtml.images', function (text, options, globals) {
altText = altText
.replace(/"/g, '&quot;')
//altText = showdown.helper.escapeCharacters(altText, '*_', false);
.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
.replace(showdown.helper.regexes.asteriskDashTildeAndColon, showdown.helper.escapeCharactersCallback);
//url = showdown.helper.escapeCharacters(url, '*_', false);
url = url.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
url = url.replace(showdown.helper.regexes.asteriskDashTildeAndColon, showdown.helper.escapeCharactersCallback);
var result = '<img src="' + url + '" alt="' + altText + '"';
if (title && showdown.helper.isString(title)) {
title = title
.replace(/"/g, '&quot;')
//title = showdown.helper.escapeCharacters(title, '*_', false);
.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
.replace(showdown.helper.regexes.asteriskDashTildeAndColon, showdown.helper.escapeCharactersCallback);
result += ' title="' + title + '"';
}

View File

@ -1,124 +1,419 @@
/**
* Turn Markdown link shortcuts into XHTML <a> tags.
*/
showdown.subParser('makehtml.links', function (text, options, globals) {
'use strict';
////
// makehtml/links.js
// Copyright (c) 2018 ShowdownJS
//
// Transforms MD links into `<a>` html anchors
//
// A link contains link text (the visible text), a link destination (the URI that is the link destination), and
// optionally a link title. There are two basic kinds of links in Markdown.
// In inline links the destination and title are given immediately after the link text.
// In reference links the destination and title are defined elsewhere in the document.
//
// ***Author:***
// - Estevão Soares dos Santos (Tivie) <https://github.com/tivie>
////
text = globals.converter._dispatch('makehtml.links.before', text, options, globals).getText();
var writeAnchorTag = function (rgx) {
return function (wholeMatch1, linkText1, linkId1, url1, m5, m6, title1) {
var evt = globals.converter._dispatch('makehtml.links.capturestart', wholeMatch1, options, globals, {
regexp: rgx,
matches: {
wholeMatch: wholeMatch1,
linkText: linkText1,
linkId: linkId1,
url: url1,
title: title1
}
});
var wholeMatch = evt.getMatches().wholeMatch;
var linkText = evt.getMatches().linkText;
var linkId = evt.getMatches().linkId;
var url = evt.getMatches().url;
var title = evt.getMatches().title;
if (showdown.helper.isUndefined(title)) {
title = '';
}
linkId = linkId.toLowerCase();
// Special case for explicit empty url
if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
url = '';
} else if (!url) {
if (!linkId) {
// lower-case and turn embedded newlines into spaces
linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
}
url = '#' + linkId;
if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {
url = globals.gUrls[linkId];
if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {
title = globals.gTitles[linkId];
}
} else {
return wholeMatch;
}
(function () {
/**
* Helper function: Wrapper function to pass as second replace parameter
*
* @param {RegExp} rgx
* @param {string} evtRootName
* @param {{}} options
* @param {{}} globals
* @returns {Function}
*/
function replaceAnchorTag (rgx, evtRootName, options, globals, emptyCase) {
emptyCase = !!emptyCase;
return function (wholeMatch, text, id, url, m5, m6, title) {
// bail we we find 2 newlines somewhere
if (/\n\n/.test(wholeMatch)) {
return wholeMatch;
}
//url = showdown.helper.escapeCharacters(url, '*_:~', false); // replaced line to improve performance
url = url.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
var result = '<a href="' + url + '"';
if (title !== '' && title !== null) {
title = title.replace(/"/g, '&quot;');
//title = showdown.helper.escapeCharacters(title, '*_', false); // replaced line to improve performance
title = title.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
result += ' title="' + title + '"';
}
// optionLinksInNewWindow only applies
// to external links. Hash links (#) open in same page
if (options.openLinksInNewWindow && !/^#/.test(url)) {
// escaped _
result += ' target="¨E95Eblank"';
}
result += '>' + linkText + '</a>';
return result;
var evt = createEvent(rgx, evtRootName + '.captureStart', wholeMatch, text, id, url, title, options, globals);
return writeAnchorTag(evt, options, globals, emptyCase);
};
};
}
var referenceRegex = /\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g;
// First, handle reference-style links: [link text] [id]
text = text.replace(referenceRegex, writeAnchorTag(referenceRegex));
/**
* TODO Normalize this
* Helper function: Create a capture event
* @param {RegExp} rgx
* @param {String} evtName Event name
* @param {String} wholeMatch
* @param {String} text
* @param {String} id
* @param {String} url
* @param {String} title
* @param {{}} options
* @param {{}} globals
* @returns {showdown.helper.Event|*}
*/
function createEvent (rgx, evtName, wholeMatch, text, id, url, title, options, globals) {
return globals.converter._dispatch(evtName, wholeMatch, options, globals, {
regexp: rgx,
matches: {
wholeMatch: wholeMatch,
text: text,
id: id,
url: url,
title: title
}
});
}
// Next, inline-style links: [link text](url "optional title")
// cases with crazy urls like ./image/cat1).png
var inlineRegexCrazy = /\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g;
text = text.replace(inlineRegexCrazy, writeAnchorTag(inlineRegexCrazy));
/**
* Helper Function: Normalize and write an anchor tag based on passed parameters
* @param evt
* @param options
* @param globals
* @param {boolean} emptyCase
* @returns {string}
*/
function writeAnchorTag (evt, options, globals, emptyCase) {
// normal cases
var inlineRegex = /\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g;
text = text.replace(inlineRegex, writeAnchorTag(inlineRegex));
var wholeMatch = evt.getMatches().wholeMatch;
var text = evt.getMatches().text;
var id = evt.getMatches().id;
var url = evt.getMatches().url;
var title = evt.getMatches().title;
var target = '';
// handle reference-style shortcuts: [link text]
// These must come last in case you've also got [link test][1]
// or [link test](/foo)
var referenceShortcutRegex = /\[([^\[\]]+)]()()()()()/g;
text = text.replace(referenceShortcutRegex, writeAnchorTag(referenceShortcutRegex));
if (!title) {
title = '';
}
id = (id) ? id.toLowerCase() : '';
// Lastly handle GithubMentions if option is enabled
if (options.ghMentions) {
text = text.replace(/(^|\s)(\\)?(@([a-z\d]+(?:[a-z\d._-]+?[a-z\d]+)*))/gmi, function (wm, st, escape, mentions, username) {
if (emptyCase) {
url = '';
} else if (!url) {
if (!id) {
// lower-case and turn embedded newlines into spaces
id = text.toLowerCase().replace(/ ?\n/g, ' ');
}
url = '#' + id;
if (!showdown.helper.isUndefined(globals.gUrls[id])) {
url = globals.gUrls[id];
if (!showdown.helper.isUndefined(globals.gTitles[id])) {
title = globals.gTitles[id];
}
} else {
return wholeMatch;
}
}
//url = showdown.helper.escapeCharacters(url, '*_:~', false); // replaced line to improve performance
url = url.replace(showdown.helper.regexes.asteriskDashTildeAndColon, showdown.helper.escapeCharactersCallback);
if (title !== '' && title !== null) {
title = title.replace(/"/g, '&quot;');
//title = showdown.helper.escapeCharacters(title, '*_', false); // replaced line to improve performance
title = title.replace(showdown.helper.regexes.asteriskDashTildeAndColon, showdown.helper.escapeCharactersCallback);
title = ' title="' + title + '"';
}
// optionLinksInNewWindow only applies
// to external links. Hash links (#) open in same page
if (options.openLinksInNewWindow && !/^#/.test(url)) {
// escaped _
target = ' target="¨E95Eblank"';
}
// Text can be a markdown element, so we run through the appropriate parsers
text = showdown.subParser('makehtml.codeSpans')(text, options, globals);
text = showdown.subParser('makehtml.emoji')(text, options, globals);
text = showdown.subParser('makehtml.underline')(text, options, globals);
text = showdown.subParser('makehtml.italicsAndBold')(text, options, globals);
text = showdown.subParser('makehtml.strikethrough')(text, options, globals);
text = showdown.subParser('makehtml.ellipsis')(text, options, globals);
text = showdown.subParser('makehtml.hashHTMLSpans')(text, options, globals);
//evt = createEvent(rgx, evtRootName + '.captureEnd', wholeMatch, text, id, url, title, options, globals);
var result = '<a href="' + url + '"' + title + target + '>' + text + '</a>';
//evt = createEvent(rgx, evtRootName + '.beforeHash', wholeMatch, text, id, url, title, options, globals);
result = showdown.subParser('makehtml.hashHTMLSpans')(result, options, globals);
return result;
}
var evtRootName = 'makehtml.links';
/**
* Turn Markdown link shortcuts into XHTML <a> tags.
*/
showdown.subParser('makehtml.links', function (text, options, globals) {
text = globals.converter._dispatch(evtRootName + '.start', text, options, globals).getText();
// 1. Handle reference-style links: [link text] [id]
text = showdown.subParser('makehtml.links.reference')(text, options, globals);
// 2. Handle inline-style links: [link text](url "optional title")
text = showdown.subParser('makehtml.links.inline')(text, options, globals);
// 3. Handle reference-style shortcuts: [link text]
// These must come last in case there's a [link text][1] or [link text](/foo)
text = showdown.subParser('makehtml.links.referenceShortcut')(text, options, globals);
// 4. Handle angle brackets links -> `<http://example.com/>`
// Must come after links, because you can use < and > delimiters in inline links like [this](<url>).
text = showdown.subParser('makehtml.links.angleBrackets')(text, options, globals);
// 5. Handle GithubMentions (if option is enabled)
text = showdown.subParser('makehtml.links.ghMentions')(text, options, globals);
// 6. Handle <a> tags and img tags
text = text.replace(/<a\s[^>]*>[\s\S]*<\/a>/g, function (wholeMatch) {
return showdown.helper._hashHTMLSpan(wholeMatch, globals);
});
text = text.replace(/<img\s[^>]*\/?>/g, function (wholeMatch) {
return showdown.helper._hashHTMLSpan(wholeMatch, globals);
});
// 7. Handle naked links (if option is enabled)
text = showdown.subParser('makehtml.links.naked')(text, options, globals);
text = globals.converter._dispatch(evtRootName + '.end', text, options, globals).getText();
return text;
});
/**
* TODO WRITE THIS DOCUMENTATION
*/
showdown.subParser('makehtml.links.inline', function (text, options, globals) {
var evtRootName = evtRootName + '.inline';
text = globals.converter._dispatch(evtRootName + '.start', text, options, globals).getText();
// 1. Look for empty cases: []() and [empty]() and []("title")
var rgxEmpty = /\[(.*?)]()()()()\(<? ?>? ?(?:["'](.*)["'])?\)/g;
text = text.replace(rgxEmpty, replaceAnchorTag(rgxEmpty, evtRootName, options, globals, true));
// 2. Look for cases with crazy urls like ./image/cat1).png
var rgxCrazy = /\[((?:\[[^\]]*]|[^\[\]])*)]()\s?\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g;
text = text.replace(rgxCrazy, replaceAnchorTag(rgxCrazy, evtRootName, options, globals));
// 3. inline links with no title or titles wrapped in ' or ":
// [text](url.com) || [text](<url.com>) || [text](url.com "title") || [text](<url.com> "title")
//var rgx2 = /\[[ ]*[\s]?[ ]*([^\n\[\]]*?)[ ]*[\s]?[ ]*] ?()\(<?[ ]*[\s]?[ ]*([^\s'"]*)>?(?:[ ]*[\n]?[ ]*()(['"])(.*?)\5)?[ ]*[\s]?[ ]*\)/; // this regex is too slow!!!
var rgx2 = /\[([\S ]*?)]\s?()\( *<?([^\s'"]*?(?:\([\S]*?\)[\S]*?)?)>?\s*(?:()(['"])(.*?)\5)? *\)/g;
text = text.replace(rgx2, replaceAnchorTag(rgx2, evtRootName, options, globals));
// 4. inline links with titles wrapped in (): [foo](bar.com (title))
var rgx3 = /\[([\S ]*?)]\s?()\( *<?([^\s'"]*?(?:\([\S]*?\)[\S]*?)?)>?\s+()()\((.*?)\) *\)/g;
text = text.replace(rgx3, replaceAnchorTag(rgx3, evtRootName, options, globals));
text = globals.converter._dispatch(evtRootName + '.end', text, options, globals).getText();
return text;
});
/**
* TODO WRITE THIS DOCUMENTATION
*/
showdown.subParser('makehtml.links.reference', function (text, options, globals) {
var evtRootName = evtRootName + '.reference';
text = globals.converter._dispatch(evtRootName + '.start', text, options, globals).getText();
var rgx = /\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g;
text = text.replace(rgx, replaceAnchorTag(rgx, evtRootName, options, globals));
text = globals.converter._dispatch(evtRootName + '.end', text, options, globals).getText();
return text;
});
/**
* TODO WRITE THIS DOCUMENTATION
*/
showdown.subParser('makehtml.links.referenceShortcut', function (text, options, globals) {
var evtRootName = evtRootName + '.referenceShortcut';
text = globals.converter._dispatch(evtRootName + '.start', text, options, globals).getText();
var rgx = /\[([^\[\]]+)]()()()()()/g;
text = text.replace(rgx, replaceAnchorTag(rgx, evtRootName, options, globals));
text = globals.converter._dispatch(evtRootName + '.end', text, options, globals).getText();
return text;
});
/**
* TODO WRITE THIS DOCUMENTATION
*/
showdown.subParser('makehtml.links.ghMentions', function (text, options, globals) {
var evtRootName = evtRootName + 'ghMentions';
if (!options.ghMentions) {
return text;
}
text = globals.converter._dispatch(evtRootName + '.start', text, options, globals).getText();
var rgx = /(^|\s)(\\)?(@([a-z\d]+(?:[a-z\d._-]+?[a-z\d]+)*))/gi;
text = text.replace(rgx, function (wholeMatch, st, escape, mentions, username) {
// bail if the mentions was escaped
if (escape === '\\') {
return st + mentions;
}
//check if options.ghMentionsLink is a string
// check if options.ghMentionsLink is a string
// TODO Validation should be done at initialization not at runtime
if (!showdown.helper.isString(options.ghMentionsLink)) {
throw new Error('ghMentionsLink option must be a string');
}
var lnk = options.ghMentionsLink.replace(/\{u}/g, username),
target = '';
if (options.openLinksInNewWindow) {
target = ' target="¨E95Eblank"';
var url = options.ghMentionsLink.replace(/{u}/g, username);
var evt = createEvent(rgx, evtRootName + '.captureStart', wholeMatch, mentions, null, url, null, options, globals);
// captureEnd Event is triggered inside writeAnchorTag function
return st + writeAnchorTag(evt, options, globals);
});
text = globals.converter._dispatch(evtRootName + '.end', text, options, globals).getText();
return text;
});
/**
* TODO WRITE THIS DOCUMENTATION
*/
showdown.subParser('makehtml.links.angleBrackets', function (text, options, globals) {
var evtRootName = 'makehtml.links.angleBrackets';
text = globals.converter._dispatch(evtRootName + '.start', text, options, globals).getText();
// 1. Parse links first
var urlRgx = /<(((?:https?|ftp):\/\/|www\.)[^'">\s]+)>/gi;
text = text.replace(urlRgx, function (wholeMatch, url, urlStart) {
var text = url;
url = (urlStart === 'www.') ? 'http://' + url : url;
var evt = createEvent(urlRgx, evtRootName + '.captureStart', wholeMatch, text, null, url, null, options, globals);
return writeAnchorTag(evt, options, globals);
});
// 2. Then Mail Addresses
var mailRgx = /<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi;
text = text.replace(mailRgx, function (wholeMatch, mail) {
var url = 'mailto:';
mail = showdown.subParser('makehtml.unescapeSpecialChars')(mail, options, globals);
if (options.encodeEmails) {
url = showdown.helper.encodeEmailAddress(url + mail);
mail = showdown.helper.encodeEmailAddress(mail);
} else {
url = url + mail;
}
var evt = createEvent(mailRgx, evtRootName + '.captureStart', wholeMatch, mail, null, url, null, options, globals);
return writeAnchorTag(evt, options, globals);
});
text = globals.converter._dispatch(evtRootName + '.end', text, options, globals).getText();
return text;
});
/**
* TODO MAKE THIS WORK (IT'S NOT ACTIVATED)
* TODO WRITE THIS DOCUMENTATION
*/
showdown.subParser('makehtml.links.naked', function (text, options, globals) {
if (!options.simplifiedAutoLink) {
return text;
}
var evtRootName = 'makehtml.links.naked';
text = globals.converter._dispatch(evtRootName + '.start', text, options, globals).getText();
// 2. Now we check for
// we also include leading markdown magic chars [_*~] for cases like __https://www.google.com/foobar__
var urlRgx = /([_*~]*?)(((?:https?|ftp):\/\/|www\.)[^\s<>"'`´.-][^\s<>"'`´]*?\.[a-z\d.]+[^\s<>"']*)\1/gi;
text = text.replace(urlRgx, function (wholeMatch, leadingMDChars, url, urlPrefix) {
// we now will start traversing the url from the front to back, looking for punctuation chars [_*~,;:.!?\)\]]
var len = url.length;
var suffix = '';
for (var i = len - 1; i >= 0; --i) {
var char = url.charAt(i);
if (/[_*~,;:.!?]/.test(char)) {
// it's a punctuation char
// we remove it from the url
url = url.slice(0, -1);
// and prepend it to the suffix
suffix = char + suffix;
} else if (/\)/.test(char)) {
var opPar = url.match(/\(/g) || [];
var clPar = url.match(/\)/g);
// it's a curved parenthesis so we need to check for "balance" (kinda)
if (opPar.length < clPar.length) {
// there are more closing Parenthesis than opening so chop it!!!!!
url = url.slice(0, -1);
// and prepend it to the suffix
suffix = char + suffix;
} else {
// it's (kinda) balanced so our work is done
break;
}
} else if (/]/.test(char)) {
var opPar2 = url.match(/\[/g) || [];
var clPar2 = url.match(/\]/g);
// it's a squared parenthesis so we need to check for "balance" (kinda)
if (opPar2.length < clPar2.length) {
// there are more closing Parenthesis than opening so chop it!!!!!
url = url.slice(0, -1);
// and prepend it to the suffix
suffix = char + suffix;
} else {
// it's (kinda) balanced so our work is done
break;
}
} else {
// it's not a punctuation or a parenthesis so our work is done
break;
}
}
// lnk = showdown.helper.escapeCharacters(lnk, '*_', false); // replaced line to improve performance
lnk = lnk.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
// we copy the treated url to the text variable
var text = url;
// finally, if it's a www shortcut, we prepend http
url = (urlPrefix === 'www.') ? 'http://' + url : url;
return st + '<a href="' + lnk + '"' + target + '>' + mentions + '</a>';
// url part is done so let's take care of text now
// we need to escape the text (because of links such as www.example.com/foo__bar__baz)
text = text.replace(showdown.helper.regexes.asteriskDashTildeAndColon, showdown.helper.escapeCharactersCallback);
// finally we dispatch the event
var evt = createEvent(urlRgx, evtRootName + '.captureStart', wholeMatch, text, null, url, null, options, globals);
// and return the link tag, with the leadingMDChars and suffix. The leadingMDChars are added at the end too because
// we consumed those characters in the regexp
return leadingMDChars + writeAnchorTag(evt, options, globals) + suffix + leadingMDChars;
});
}
text = globals.converter._dispatch('makehtml.links.after', text, options, globals).getText();
return text;
});
// 2. Then mails
var mailRgx = /(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gmi;
text = text.replace(mailRgx, function (wholeMatch, leadingChar, mail) {
var url = 'mailto:';
mail = showdown.subParser('makehtml.unescapeSpecialChars')(mail, options, globals);
if (options.encodeEmails) {
url = showdown.helper.encodeEmailAddress(url + mail);
mail = showdown.helper.encodeEmailAddress(mail);
} else {
url = url + mail;
}
var evt = createEvent(mailRgx, evtRootName + '.captureStart', wholeMatch, mail, null, url, null, options, globals);
return leadingChar + writeAnchorTag(evt, options, globals);
});
text = globals.converter._dispatch(evtRootName + '.end', text, options, globals).getText();
return text;
});
})();

View File

@ -5,7 +5,8 @@
showdown.subParser('makehtml.spanGamut', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('smakehtml.panGamut.before', text, options, globals).getText();
text = globals.converter._dispatch('makehtml.span.before', text, options, globals).getText();
text = showdown.subParser('makehtml.codeSpans')(text, options, globals);
text = showdown.subParser('makehtml.escapeSpecialCharsWithinTagAttributes')(text, options, globals);
text = showdown.subParser('makehtml.encodeBackslashEscapes')(text, options, globals);
@ -13,13 +14,13 @@ showdown.subParser('makehtml.spanGamut', function (text, options, globals) {
// Process link and image tags. Images must come first,
// because ![foo][f] looks like a link.
text = showdown.subParser('makehtml.images')(text, options, globals);
text = showdown.subParser('makehtml.links')(text, options, globals);
// Make links out of things like `<http://example.com/>`
// Must come after links, because you can use < and >
// delimiters in inline links like [this](<url>).
text = showdown.subParser('makehtml.autoLinks')(text, options, globals);
text = showdown.subParser('makehtml.simplifiedAutoLinks')(text, options, globals);
text = globals.converter._dispatch('smakehtml.links.before', text, options, globals).getText();
text = showdown.subParser('makehtml.links')(text, options, globals);
text = globals.converter._dispatch('smakehtml.links.after', text, options, globals).getText();
//text = showdown.subParser('makehtml.autoLinks')(text, options, globals);
//text = showdown.subParser('makehtml.simplifiedAutoLinks')(text, options, globals);
text = showdown.subParser('makehtml.emoji')(text, options, globals);
text = showdown.subParser('makehtml.underline')(text, options, globals);
text = showdown.subParser('makehtml.italicsAndBold')(text, options, globals);

View File

@ -1,16 +1,9 @@
showdown.subParser('makehtml.strikethrough', function (text, options, globals) {
'use strict';
function parseInside (txt) {
if (options.simplifiedAutoLink) {
txt = showdown.subParser('makehtml.simplifiedAutoLinks')(txt, options, globals);
}
return '<del>' + txt + '</del>';
}
if (options.strikethrough) {
text = globals.converter._dispatch('makehtml.strikethrough.before', text, options, globals).getText();
text = text.replace(/(?:~){2}([\s\S]+?)(?:~){2}/g, function (wm, txt) { return parseInside(txt); });
text = text.replace(/(?:~){2}([\s\S]+?)(?:~){2}/g, function (wm, txt) { return '<del>' + txt + '</del>'; });
text = globals.converter._dispatch('makehtml.strikethrough.after', text, options, globals).getText();
}

File diff suppressed because it is too large Load Diff

View File

@ -2,5 +2,4 @@
<p>www.foobar</p>
<p><a href="http://www.foobar.com">www.foobar.com</a></p>
<p><a href="http://foobar.com">http://foobar.com</a></p>
<p><a href="https://www.foobar.com/baz?bazinga=nhecos;">https://www.foobar.com/baz?bazinga=nhecos;</a></p>
<p><a href="http://www.google.com/">http://www.google.com</a></p>
<p><a href="https://www.foobar.com/baz?bazinga=nhecos">https://www.foobar.com/baz?bazinga=nhecos</a>;</p>

View File

@ -7,5 +7,3 @@ www.foobar.com
http://foobar.com
https://www.foobar.com/baz?bazinga=nhecos;
<a href="http://www.google.com/">http://www.google.com</a>

View File

@ -0,0 +1 @@
<p>(<a href="https://www.google.com">https://www.google.com</a>)!</p>

View File

@ -0,0 +1 @@
<p><code>http://www.gmail.com</code></p>

View File

@ -0,0 +1 @@
`http://www.gmail.com`

View File

@ -28,9 +28,9 @@
<p><a href="http://j.mp">http://j.mp</a></p>
<p><a href="ftp://foo.bar/baz">ftp://foo.bar/baz</a></p>
<p><a href="http://foo.bar/?q=Test%20URL-encoded%20stuff">http://foo.bar/?q=Test%20URL-encoded%20stuff</a></p>
<p><a href="http://مثال.إختبار">http://مثال.إختبار</a></p>
<p><a href="http://例子.测试">http://例子.测试</a></p>
<p><a href="http://उदाहरण.परीक्षा">http://उदाहरण.परीक्षा</a></p>
<!-- http://مثال.إختبار -->
<!-- http://例子.测试 -->
<!-- http://उदाहरण.परीक्षा -->
<p><a href="http://1337.net">http://1337.net</a></p>
<p><a href="http://a.b-c.de">http://a.b-c.de</a></p>
<p><a href="http://223.255.255.254">http://223.255.255.254</a></p>
@ -41,6 +41,8 @@
<!-- SHOULD PARTIALLY PASS -->
<p><a href="http://foo.bar/foo(bar)baz">http://foo.bar/foo(bar)baz</a> quux</p>
<p><a href="http://foo.bar?q=Spaces">http://foo.bar?q=Spaces</a> should be encoded</p>
<p>http://.<a href="http://www.foo.bar/">www.foo.bar/</a></p>
<p>http://.<a href="http://www.foo.bar./">www.foo.bar./</a></p>
<!-- THESE ARE INVALID IPS BUT WE WILL LET THEM PASS -->
<p><a href="http://10.1.1.1">http://10.1.1.1</a></p>
<p><a href="http://10.1.1.254">http://10.1.1.254</a></p>
@ -73,7 +75,4 @@
<p>:// should fail</p>
<p>http://-error-.invalid/</p>
<p>http://-a.b.co</p>
<p>http://a.b-.co</p>
<p>http://3628126748</p>
<p>http://.www.foo.bar/</p>
<p>http://.www.foo.bar./</p>

View File

@ -58,11 +58,11 @@ ftp://foo.bar/baz
http://foo.bar/?q=Test%20URL-encoded%20stuff
http://مثال.إختبار
<!-- http://مثال.إختبار -->
http://例子.测试
<!-- http://例子.测试 -->
http://उदाहरण.परीक्षा
<!-- http://उदाहरण.परीक्षा -->
http://1337.net
@ -72,7 +72,6 @@ http://223.255.255.254
https://foo_bar.example.com/
<!-- WEIRD BUT SHOULD ALSO PASS -->
http://www.foo.bar./
@ -85,6 +84,10 @@ http://foo.bar/foo(bar)baz quux
http://foo.bar?q=Spaces should be encoded
http://.www.foo.bar/
http://.www.foo.bar./
<!-- THESE ARE INVALID IPS BUT WE WILL LET THEM PASS -->
http://10.1.1.1
@ -149,10 +152,4 @@ http://-error-.invalid/
http://-a.b.co
http://a.b-.co
http://3628126748
http://.www.foo.bar/
http://.www.foo.bar./

View File

@ -0,0 +1,8 @@
<p><a href="http://www.google.com">http://www.google.com</a>!</p>
<p><a href="http://www.google.com">http://www.google.com</a>!!!!!!!!!!!!!!!!</p>
<p><a href="http://www.google.com/!!!!!!!!!!!!!!!!foobar">http://www.google.com/!!!!!!!!!!!!!!!!foobar</a></p>
<p><a href="http://www.google.com/">http://www.google.com/</a>!!!!!!!!!!!!!!!! foobar</p>
<p>(<a href="http://www.google.com/">http://www.google.com/</a>?!.)</p>
<p><a href="http://www.google.com/?!.(">http://www.google.com/?!.(</a></p>
<p><a href="http://www.google.com/a()">http://www.google.com/a()</a></p>
<p><a href="http://www.google.com/a?!.()">http://www.google.com/a?!.()</a></p>

View File

@ -0,0 +1,15 @@
http://www.google.com!
http://www.google.com!!!!!!!!!!!!!!!!
http://www.google.com/!!!!!!!!!!!!!!!!foobar
http://www.google.com/!!!!!!!!!!!!!!!! foobar
(http://www.google.com/?!.)
http://www.google.com/?!.(
http://www.google.com/a()
http://www.google.com/a?!.()

View File

@ -0,0 +1,2 @@
<p>(<a href="https://www.google.com">https://www.google.com</a>)</p>
<p>(<a href="https://www.google.com">https://www.google.com</a>!?;)</p>

View File

@ -0,0 +1,5 @@
(https://www.google.com)
(https://www.google.com!?;)

View File

@ -17,7 +17,7 @@
var foo_bar_baz_bar_foo = "foo_bar_";
</script>
<p><a href="http://myurl.com/foo_bar_baz_bar_foo">foo_bar_baz foo_bar_baz_bar_foo <em>foo_bar baz_bar</em> baz_foo</a></p>
<p><a href="http://myurl.com/foo_bar_baz_bar_foo" title="foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo">foo_bar_baz foo_bar_baz_bar_foo <em>foo_bar baz_bar</em> baz_foo</a></p>
<p><a href="http://myurl.com/foo_bar_baz_bar_foo" title="foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo">foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo</a></p>
<p><img src="http://myurl.com/foo_bar_baz_bar_foo" alt="foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo"></p>
<h2 id="foo_bar_bazfoo_bar_baz_bar_foo_foo_barbaz_bar_baz_foo">foo_bar_baz foo_bar_baz_bar_foo <em>foo_bar baz_bar</em> baz_foo</h2>
<h3 id="foo_bar_bazfoo_bar_baz_bar_foo_foo_barbaz_bar_baz_foo-1">foo_bar_baz foo_bar_baz_bar_foo <em>foo_bar baz_bar</em> baz_foo</h3>

View File

@ -1,3 +1,4 @@
<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)" title="Textile">link</a>.</p>
<p>This is another <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)" title="Textile">link</a>.</p>
<p><a href="./image/cat1).png" title="title">link</a></p>
<p>This is another <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)" title="Textile">link2</a>.</p>
<p><a href="./image/cat1).png" title="title">link3</a></p>
<p><a href="https://en.wikipedia.org/wiki/Textile_(markup_language)" title="Textile">link4</a>(this should work)</p>

View File

@ -2,6 +2,8 @@ This is a [link][].
[link]: https://en.wikipedia.org/wiki/Textile_(markup_language) "Textile"
This is another [link](https://en.wikipedia.org/wiki/Textile_(markup_language) "Textile").
This is another [link2](https://en.wikipedia.org/wiki/Textile_(markup_language) "Textile").
[link](<./image/cat1).png> "title")
[link3](<./image/cat1).png> "title")
[link4](https://en.wikipedia.org/wiki/Textile_(markup_language) "Textile")(this should work)

View File

@ -12,3 +12,8 @@
<p><a href="">empty</a></p>
<p><img src="" alt="empty" title="title" /></p>
<p><a href="" title="title">empty</a></p>
<p><a href="">empty</a></p>
<p><a href="" title="title">empty</a></p>
<p><a href=""></a></p>
<p><a href=""></a></p>
<p><a href="" title="title"></a></p>

View File

@ -25,3 +25,13 @@
![empty](< > "title")
[empty](< > "title")
[empty]()
[empty]("title")
[]()
[](<>)
[]("title")

View File

@ -4,4 +4,4 @@ This is a [link](https://en.wikipedia.org/wiki/Textile_(markup) (some other text
This is a [link](https://en.wikipedia.org/wiki/Textile_(markup_language)) (some other text)
This is a [link](https://en.wikipedia.org/wiki/Textile_(markup_language)/foo) (some other text)
This is a [link](https://en.wikipedia.org/wiki/Textile_(markup_language)/foo) (some other text)

View File

@ -16,6 +16,11 @@
.map(map(dir));
}
function getJsonTestSuite (file) {
var json = JSON.parse(fs.readFileSync(file, 'utf8'));
return mapJson(json, file);
}
function filter () {
return function (file) {
var ext = file.slice(-3);
@ -25,7 +30,8 @@
function map (dir) {
return function (file) {
var name = file.replace('.md', ''),
var oFile = 'file://' + process.cwd().replace(/\\/g, '/') + dir + file,
name = file.replace('.md', ''),
htmlPath = dir + name + '.html',
html = fs.readFileSync(htmlPath, 'utf8'),
mdPath = dir + name + '.md',
@ -34,18 +40,40 @@
return {
name: name,
input: md,
expected: html
expected: html,
file: oFile
};
};
}
function mapJson (jsonArray, file) {
var tcObj = {};
for (var i = 0; i < jsonArray.length; ++i) {
var section = jsonArray[i].section;
var name = jsonArray[i].section + '_' + jsonArray[i].example;
var md = jsonArray[i].markdown;
var html = jsonArray[i].html;
if (!tcObj.hasOwnProperty(section)) {
tcObj[section] = [];
}
tcObj[section].push({
name: name,
input: md,
expected: html,
file: process.cwd().replace(/\\/g, '/') + file
});
}
return tcObj;
}
function assertion (testCase, converter) {
return function () {
testCase.actual = converter.makeHtml(testCase.input);
testCase = normalize(testCase);
// Compare
testCase.actual.should.equal(testCase.expected);
testCase.actual.should.equal(testCase.expected, testCase.file);
};
}
@ -81,6 +109,7 @@
module.exports = {
getTestSuite: getTestSuite,
getJsonTestSuite: getJsonTestSuite,
assertion: assertion,
normalize: normalize,
showdown: require('../../../.build/showdown.js')

View File

@ -0,0 +1,25 @@
/**
* Created by Estevao on 08-06-2015.
*/
// jshint ignore: start
/*
var bootstrap = require('./makehtml.bootstrap.js'),
converter = new bootstrap.showdown.Converter(),
assertion = bootstrap.assertion,
testsuite = bootstrap.getJsonTestSuite('test/functional/makehtml/cases/commonmark.testsuite.json');
describe('makeHtml() commonmark testsuite', function () {
'use strict';
for (var section in testsuite) {
if (testsuite.hasOwnProperty(section)) {
describe(section, function () {
for (var i = 0; i < testsuite[section].length; ++i) {
it(testsuite[section][i].name, assertion(testsuite[section][i], converter));
}
});
}
}
});
*/

View File

@ -62,7 +62,7 @@ describe('makeHtml() features testsuite', function () {
} else if (testsuite[i].name === 'simpleLineBreaks-handle-html-pre') {
converter = new showdown.Converter({simpleLineBreaks: true});
} else if (testsuite[i].name === 'excludeTrailingPunctuationFromURLs-option') {
converter = new showdown.Converter({simplifiedAutoLink: true, excludeTrailingPunctuationFromURLs: true});
converter = new showdown.Converter({simplifiedAutoLink: true});
} else if (testsuite[i].name === 'requireSpaceBeforeHeadingText') {
converter = new showdown.Converter({requireSpaceBeforeHeadingText: true});
} else if (testsuite[i].name === '#320.github-compatible-generated-header-id') {
@ -88,11 +88,13 @@ describe('makeHtml() features testsuite', function () {
} else if (testsuite[i].name === 'customizedHeaderId-simple') {
converter = new showdown.Converter({customizedHeaderId: true});
} else if (testsuite[i].name === '#378.simplifiedAutoLinks-with-excludeTrailingPunctuationFromURLs') {
converter = new showdown.Converter({simplifiedAutoLink: true, excludeTrailingPunctuationFromURLs: true});
converter = new showdown.Converter({simplifiedAutoLink: true});
} else if (testsuite[i].name === '#374.escape-html-tags') {
converter = new showdown.Converter({backslashEscapesHTMLTags: true});
} else if (testsuite[i].name === '#379.openLinksInNewWindow-breaks-em-markdup') {
converter = new showdown.Converter({openLinksInNewWindow: true});
} else if (testsuite[i].name === '#355.simplifiedAutoLink-URLs-inside-parenthesis-followed-by-another-character-are-not-parsed-correctly') {
converter = new showdown.Converter({simplifiedAutoLink: true});
} else {
converter = new showdown.Converter();
}