diff --git a/dist/showdown.js b/dist/showdown.js index 347181b..e746ab1 100644 --- a/dist/showdown.js +++ b/dist/showdown.js @@ -1,5 +1,5 @@ -;/*! showdown v 2.0.0 - 10-03-2022 */ -(function(){ +;/*! showdown v 2.0.0 - 10-03-2022 */ +(function(){ /** * Created by Tivie on 13-07-2015. */ @@ -202,7 +202,7 @@ function allOptionsOn () { } return ret; } - + /** * Created by Tivie on 06-01-2015. */ @@ -582,7 +582,7 @@ showdown.validateExtension = function (ext) { } return true; }; - + /** * showdownjs helper functions */ @@ -912,9 +912,10 @@ showdown.helper.splitAtIndex = function (str, index) { * Since it has a random component, subsequent calls to this function produce different results * * @param {string} mail + * @param {string} seed * @returns {string} */ -showdown.helper.encodeEmailAddress = function (mail) { +showdown.helper.encodeEmailAddress = function (mail, seed) { 'use strict'; var encode = [ function (ch) { @@ -2970,7 +2971,7 @@ showdown.helper.emojis = { 'trollface': '', 'showdown': '' }; - + /** * These are all the transformations that form block-level * tags like paragraphs, headers, and list items. @@ -3003,7 +3004,7 @@ showdown.subParser('makehtml.blockGamut', function (text, options, globals) { return text; }); - + showdown.subParser('makehtml.blockQuotes', function (text, options, globals) { 'use strict'; @@ -3046,7 +3047,7 @@ showdown.subParser('makehtml.blockQuotes', function (text, options, globals) { text = globals.converter._dispatch('makehtml.blockQuotes.after', text, options, globals).getText(); return text; }); - + /** * Process Markdown `
` blocks.
  */
@@ -3085,7 +3086,7 @@ showdown.subParser('makehtml.codeBlocks', function (text, options, globals) {
   text = globals.converter._dispatch('makehtml.codeBlocks.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  *
  *   *  Backtick quotes are used for  spans.
@@ -3134,7 +3135,7 @@ showdown.subParser('makehtml.codeSpans', function (text, options, globals) {
   text = globals.converter._dispatch('makehtml.codeSpans.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  * Create a full HTML document from the processed markdown
  */
@@ -3197,7 +3198,7 @@ showdown.subParser('makehtml.completeHTMLDocument', function (text, options, glo
   text = globals.converter._dispatch('makehtml.completeHTMLDocument.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  * Convert all tabs to spaces
  */
@@ -3231,7 +3232,7 @@ showdown.subParser('makehtml.detab', function (text, options, globals) {
   text = globals.converter._dispatch('makehtml.detab.after', text, options, globals).getText();
   return text;
 });
-
+
 showdown.subParser('makehtml.ellipsis', function (text, options, globals) {
   'use strict';
 
@@ -3247,7 +3248,7 @@ showdown.subParser('makehtml.ellipsis', function (text, options, globals) {
 
   return text;
 });
-
+
 /**
  * Turn emoji codes into emojis
  *
@@ -3275,7 +3276,7 @@ showdown.subParser('makehtml.emoji', function (text, options, globals) {
 
   return text;
 });
-
+
 /**
  * Smart processing for ampersands and angle brackets that need to be encoded.
  */
@@ -3299,7 +3300,7 @@ showdown.subParser('makehtml.encodeAmpsAndAngles', function (text, options, glob
   text = globals.converter._dispatch('makehtml.encodeAmpsAndAngles.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  * Returns the string, with after processing the following backslash escape sequences.
  *
@@ -3321,7 +3322,7 @@ showdown.subParser('makehtml.encodeBackslashEscapes', function (text, options, g
   text = globals.converter._dispatch('makehtml.encodeBackslashEscapes.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  * Encode/escape certain characters inside Markdown code runs.
  * The point is that in code, these characters are literals,
@@ -3345,7 +3346,7 @@ showdown.subParser('makehtml.encodeCode', function (text, options, globals) {
   text = globals.converter._dispatch('makehtml.encodeCode.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  * Within tags -- meaning between < and > -- encode [\ ` * _ ~ =] so they
  * don't conflict with their use in Markdown for code, italics and strong.
@@ -3372,7 +3373,7 @@ showdown.subParser('makehtml.escapeSpecialCharsWithinTagAttributes', function (t
   text = globals.converter._dispatch('makehtml.escapeSpecialCharsWithinTagAttributes.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  * Handle github codeblocks prior to running HashHTML so that
  * HTML contained within the codeblock gets escaped properly
@@ -3423,7 +3424,7 @@ showdown.subParser('makehtml.githubCodeBlocks', function (text, options, globals
 
   return globals.converter._dispatch('makehtml.githubCodeBlocks.after', text, options, globals).getText();
 });
-
+
 showdown.subParser('makehtml.hashBlock', function (text, options, globals) {
   'use strict';
   text = globals.converter._dispatch('makehtml.hashBlock.before', text, options, globals).getText();
@@ -3432,7 +3433,7 @@ showdown.subParser('makehtml.hashBlock', function (text, options, globals) {
   text = globals.converter._dispatch('makehtml.hashBlock.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  * Hash and escape  elements that should not be parsed as markdown
  */
@@ -3451,7 +3452,7 @@ showdown.subParser('makehtml.hashCodeTags', function (text, options, globals) {
   text = globals.converter._dispatch('makehtml.hashCodeTags.after', text, options, globals).getText();
   return text;
 });
-
+
 showdown.subParser('makehtml.hashElement', function (text, options, globals) {
   'use strict';
 
@@ -3471,7 +3472,7 @@ showdown.subParser('makehtml.hashElement', function (text, options, globals) {
     return blockText;
   };
 });
-
+
 showdown.subParser('makehtml.hashHTMLBlocks', function (text, options, globals) {
   'use strict';
   text = globals.converter._dispatch('makehtml.hashHTMLBlocks.before', text, options, globals).getText();
@@ -3571,7 +3572,7 @@ showdown.subParser('makehtml.hashHTMLBlocks', function (text, options, globals)
   text = globals.converter._dispatch('makehtml.hashHTMLBlocks.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  * Hash span elements that should not be parsed as markdown
  */
@@ -3630,7 +3631,7 @@ showdown.subParser('makehtml.unhashHTMLSpans', function (text, options, globals)
   text = globals.converter._dispatch('makehtml.unhashHTMLSpans.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  * Hash and escape 
 elements that should not be parsed as markdown
  */
@@ -3650,7 +3651,7 @@ showdown.subParser('makehtml.hashPreCodeTags', function (text, options, globals)
   text = globals.converter._dispatch('makehtml.hashPreCodeTags.after', text, options, globals).getText();
   return text;
 });
-
+
 showdown.subParser('makehtml.headers', function (text, options, globals) {
   'use strict';
 
@@ -3777,7 +3778,7 @@ showdown.subParser('makehtml.headers', function (text, options, globals) {
   text = globals.converter._dispatch('makehtml.headers.after', text, options, globals).getText();
   return text;
 });
-
+
 /**
  * Turn Markdown horizontal rule shortcuts into 
tags. * @@ -3796,7 +3797,7 @@ showdown.subParser('makehtml.horizontalRule', function (text, options, globals) text = globals.converter._dispatch('makehtml.horizontalRule.after', text, options, globals).getText(); return text; }); - + /** * Turn Markdown image shortcuts into tags. */ @@ -3907,7 +3908,7 @@ showdown.subParser('makehtml.images', function (text, options, globals) { text = globals.converter._dispatch('makehtml.images.after', text, options, globals).getText(); return text; }); - + showdown.subParser('makehtml.italicsAndBold', function (text, options, globals) { 'use strict'; @@ -3974,7 +3975,7 @@ showdown.subParser('makehtml.italicsAndBold', function (text, options, globals) text = globals.converter._dispatch('makehtml.italicsAndBold.after', text, options, globals).getText(); return text; }); - + //// // makehtml/links.js // Copyright (c) 2018 ShowdownJS @@ -4403,7 +4404,7 @@ showdown.subParser('makehtml.italicsAndBold', function (text, options, globals) return text; }); })(); - + /** * Form HTML ordered (numbered) and unordered (bulleted) lists. */ @@ -4665,7 +4666,7 @@ showdown.subParser('makehtml.lists', function (text, options, globals) { text = globals.converter._dispatch('makehtml.lists.after', text, options, globals).getText(); return text; }); - + /** * Parse metadata at the top of the document */ @@ -4720,7 +4721,7 @@ showdown.subParser('makehtml.metadata', function (text, options, globals) { text = globals.converter._dispatch('makehtml.metadata.after', text, options, globals).getText(); return text; }); - + /** * Remove one level of line-leading tabs or spaces */ @@ -4738,7 +4739,7 @@ showdown.subParser('makehtml.outdent', function (text, options, globals) { text = globals.converter._dispatch('makehtml.outdent.after', text, options, globals).getText(); return text; }); - + /** * */ @@ -4809,7 +4810,7 @@ showdown.subParser('makehtml.paragraphs', function (text, options, globals) { text = text.replace(/\n+$/g, ''); return globals.converter._dispatch('makehtml.paragraphs.after', text, options, globals).getText(); }); - + /** * Run extension */ @@ -4830,7 +4831,7 @@ showdown.subParser('makehtml.runExtension', function (ext, text, options, global return text; }); - + /** * These are all the transformations that occur *within* block-level * tags like paragraphs, headers, and list items. @@ -4881,7 +4882,7 @@ showdown.subParser('makehtml.spanGamut', function (text, options, globals) { text = globals.converter._dispatch('makehtml.spanGamut.after', text, options, globals).getText(); return text; }); - + showdown.subParser('makehtml.strikethrough', function (text, options, globals) { 'use strict'; @@ -4893,7 +4894,7 @@ showdown.subParser('makehtml.strikethrough', function (text, options, globals) { return text; }); - + /** * Strips link definitions from text, stores the URLs and titles in * hash references. @@ -4954,7 +4955,7 @@ showdown.subParser('makehtml.stripLinkDefinitions', function (text, options, glo return text; }); - + showdown.subParser('makehtml.tables', function (text, options, globals) { 'use strict'; @@ -5098,7 +5099,7 @@ showdown.subParser('makehtml.tables', function (text, options, globals) { return text; }); - + showdown.subParser('makehtml.underline', function (text, options, globals) { 'use strict'; @@ -5131,7 +5132,7 @@ showdown.subParser('makehtml.underline', function (text, options, globals) { return text; }); - + /** * Swap back in all the special characters we've hidden. */ @@ -5147,7 +5148,7 @@ showdown.subParser('makehtml.unescapeSpecialChars', function (text, options, glo text = globals.converter._dispatch('makehtml.unescapeSpecialChars.after', text, options, globals).getText(); return text; }); - + showdown.subParser('makeMarkdown.blockquote', function (node, globals) { 'use strict'; @@ -5170,13 +5171,13 @@ showdown.subParser('makeMarkdown.blockquote', function (node, globals) { txt = '> ' + txt.split('\n').join('\n> '); return txt; }); - + showdown.subParser('makeMarkdown.break', function () { 'use strict'; return ' \n'; }); - + showdown.subParser('makeMarkdown.codeBlock', function (node, globals) { 'use strict'; @@ -5184,13 +5185,13 @@ showdown.subParser('makeMarkdown.codeBlock', function (node, globals) { num = node.getAttribute('precodenum'); return '```' + lang + '\n' + globals.preList[num] + '\n```'; }); - + showdown.subParser('makeMarkdown.codeSpan', function (node) { 'use strict'; return '`' + node.innerHTML + '`'; }); - + showdown.subParser('makeMarkdown.emphasis', function (node, globals) { 'use strict'; @@ -5206,7 +5207,7 @@ showdown.subParser('makeMarkdown.emphasis', function (node, globals) { } return txt; }); - + showdown.subParser('makeMarkdown.header', function (node, globals, headerLevel) { 'use strict'; @@ -5224,13 +5225,13 @@ showdown.subParser('makeMarkdown.header', function (node, globals, headerLevel) } return txt; }); - + showdown.subParser('makeMarkdown.hr', function () { 'use strict'; return '---'; }); - + showdown.subParser('makeMarkdown.image', function (node) { 'use strict'; @@ -5249,7 +5250,7 @@ showdown.subParser('makeMarkdown.image', function (node) { } return txt; }); - + showdown.subParser('makeMarkdown.input', function (node, globals) { 'use strict'; @@ -5266,7 +5267,7 @@ showdown.subParser('makeMarkdown.input', function (node, globals) { } return txt; }); - + showdown.subParser('makeMarkdown.links', function (node, globals) { 'use strict'; @@ -5287,7 +5288,7 @@ showdown.subParser('makeMarkdown.links', function (node, globals) { } return txt; }); - + showdown.subParser('makeMarkdown.list', function (node, globals, type) { 'use strict'; @@ -5319,7 +5320,7 @@ showdown.subParser('makeMarkdown.list', function (node, globals, type) { return txt.trim(); }); - + showdown.subParser('makeMarkdown.listItem', function (node, globals) { 'use strict'; @@ -5345,7 +5346,7 @@ showdown.subParser('makeMarkdown.listItem', function (node, globals) { return listItemTxt; }); - + showdown.subParser('makeMarkdown.node', function (node, globals, spansOnly) { @@ -5474,7 +5475,7 @@ showdown.subParser('makeMarkdown.node', function (node, globals, spansOnly) { return txt; }); - + showdown.subParser('makeMarkdown.paragraph', function (node, globals) { 'use strict'; @@ -5492,14 +5493,14 @@ showdown.subParser('makeMarkdown.paragraph', function (node, globals) { return txt; }); - + showdown.subParser('makeMarkdown.pre', function (node, globals) { 'use strict'; var num = node.getAttribute('prenum'); return '
' + globals.preList[num] + '
'; }); - + showdown.subParser('makeMarkdown.strikethrough', function (node, globals) { 'use strict'; @@ -5515,7 +5516,7 @@ showdown.subParser('makeMarkdown.strikethrough', function (node, globals) { } return txt; }); - + showdown.subParser('makeMarkdown.strong', function (node, globals) { 'use strict'; @@ -5531,7 +5532,7 @@ showdown.subParser('makeMarkdown.strong', function (node, globals) { } return txt; }); - + showdown.subParser('makeMarkdown.table', function (node, globals) { 'use strict'; @@ -5602,7 +5603,7 @@ showdown.subParser('makeMarkdown.table', function (node, globals) { return txt.trim(); }); - + showdown.subParser('makeMarkdown.tableCell', function (node, globals) { 'use strict'; @@ -5618,7 +5619,7 @@ showdown.subParser('makeMarkdown.tableCell', function (node, globals) { } return txt.trim(); }); - + showdown.subParser('makeMarkdown.txt', function (node) { 'use strict'; @@ -5662,7 +5663,7 @@ showdown.subParser('makeMarkdown.txt', function (node) { return txt; }); - + /** * Created by Estevao on 31-05-2015. */ @@ -6265,7 +6266,7 @@ showdown.Converter = function (converterOptions) { metadata.raw = raw; }; }; - + var root = this; // AMD Loader @@ -6283,6 +6284,6 @@ if (typeof define === 'function' && define.amd) { } else { root.showdown = showdown; } -}).call(this); +}).call(this); -//# sourceMappingURL=showdown.js.map +//# sourceMappingURL=showdown.js.map diff --git a/src/helpers.js b/src/helpers.js index ac5f1c7..2eebf07 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -320,11 +320,48 @@ showdown.helper.splitAtIndex = function (str, index) { return [str.substring(0, index), str.substring(index)]; }; + +/** + * MurmurHash3's mixing function + * https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript/47593316#47593316 + * + * @param {string} string + * @returns {Number} + */ +/*jshint bitwise: false*/ +function xmur3 (str) { + for (var i = 0, h = 1779033703 ^ str.length; i < str.length; i++) { + h = Math.imul(h ^ str.charCodeAt(i), 3432918353); + h = h << 13 | h >>> 19; + } + return function () { + h = Math.imul(h ^ h >>> 16, 2246822507); + h = Math.imul(h ^ h >>> 13, 3266489909); + return (h ^= h >>> 16) >>> 0; + }; +} + +/** + * Random Number Generator + * https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript/47593316#47593316 + * + * @param {Number} seed + * @returns {Number} + */ +/*jshint bitwise: false*/ +function mulberry32 (a) { + return function () { + var t = a += 0x6D2B79F5; + t = Math.imul(t ^ t >>> 15, t | 1); + t ^= t + Math.imul(t ^ t >>> 7, t | 61); + return ((t ^ t >>> 14) >>> 0) / 4294967296; + }; +} + /** * Obfuscate an e-mail address through the use of Character Entities, * transforming ASCII characters into their equivalent decimal or hex entities. * - * Since it has a random component, subsequent calls to this function produce different results * * @param {string} mail * @returns {string} @@ -343,12 +380,15 @@ showdown.helper.encodeEmailAddress = function (mail) { } ]; + // RNG seeded with mail, so that we can get determined results for each email. + var rand = mulberry32(xmur3(mail)); + mail = mail.replace(/./g, function (ch) { if (ch === '@') { // this *must* be encoded. I insist. - ch = encode[Math.floor(Math.random() * 2)](ch); + ch = encode[Math.floor(rand() * 2)](ch); } else { - var r = Math.random(); + var r = rand(); // roughly 10% raw, 45% hex, 45% dec ch = ( r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch) @@ -569,6 +609,26 @@ if (typeof (console) === 'undefined') { }; } +// Math.imul() polyfill +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul +if (!Math.imul) { + Math.imul = function (opA, opB) { + opB |= 0; // ensure that opB is an integer. opA will automatically be coerced. + // floating points give us 53 bits of precision to work with plus 1 sign bit + // automatically handled for our convienence: + // 1. 0x003fffff /*opA & 0x000fffff*/ * 0x7fffffff /*opB*/ = 0x1fffff7fc00001 + // 0x1fffff7fc00001 < Number.MAX_SAFE_INTEGER /*0x1fffffffffffff*/ + var result = (opA & 0x003fffff) * opB; + // 2. We can remove an integer coersion from the statement above because: + // 0x1fffff7fc00001 + 0xffc00000 = 0x1fffffff800001 + // 0x1fffffff800001 < Number.MAX_SAFE_INTEGER /*0x1fffffffffffff*/ + if (opA & 0xffc00000 /*!== 0*/) { + result += (opA & 0xffc00000) * opB | 0; + } + return result | 0; + }; +} + /** * Common regexes. * We declare some common regexes to improve performance diff --git a/test/unit/showdown.helpers.js b/test/unit/showdown.helpers.js index 2995728..e4a4477 100644 --- a/test/unit/showdown.helpers.js +++ b/test/unit/showdown.helpers.js @@ -14,12 +14,17 @@ describe('encodeEmailAddress()', function () { 'use strict'; var encoder = showdown.helper.encodeEmailAddress, email = 'foobar@example.com', - encodedEmail = encoder(email); + encodedEmail = encoder(email), + encodedEmail2 = encoder(email); it('should encode email', function () { encodedEmail.should.not.equal(email); }); + it('should encode email determinated', function () { + encodedEmail.should.equal(encodedEmail2); + }); + it('should decode to original email', function () { var decodedEmail = encodedEmail.replace(/&#(.+?);/g, function (wm, cc) { if (cc.charAt(0) === 'x') {