Socket
Socket
Sign inDemoInstall

gitter-markdown-processor

Package Overview
Dependencies
Maintainers
5
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gitter-markdown-processor - npm Package Compare versions

Comparing version 14.0.0 to 15.0.0

.eslintrc.json

67

lib/decoration-url-matcher.js

@@ -1,9 +0,9 @@

"use strict";
'use strict';
var url = require('url');
const url = require('url');
var URL_RE = /(?:\/(.*))+?\/(.*)\/(issues|merge_requests|pull|commit)\/([a-f0-9]+)$/;
const URL_RE = /(?:\/(.*))+?\/(.*)\/(issues|merge_requests|pull|commit)\/([a-f0-9]+)$/;
function isValidIssueNumber(val) {
var number = Number(val);
const number = Number(val);
return number > 0 && number < Infinity;

@@ -13,3 +13,3 @@ }

function isValidCommitHash(val) {
var hash = val.match(/[a-f0-9]*/)[0] || '';
const hash = val.match(/[a-f0-9]*/)[0] || '';
return val.length === hash.length;

@@ -27,24 +27,25 @@ }

// https://gitlab.com/gitlab-org/gitter/styleguide/commit/6a61175e447548d9e1f3e5ed8e329d8578a38bb1
var urlObj = url.parse(href);
var pathMatches = urlObj.pathname && urlObj.pathname.match(URL_RE);
const urlObj = url.parse(href);
const pathMatches = urlObj.pathname && urlObj.pathname.match(URL_RE);
var isGitLab = urlObj.hostname === 'gitlab.com';
var isGitHub = urlObj.hostname === 'github.com';
const isGitLab = urlObj.hostname === 'gitlab.com';
const isGitHub = urlObj.hostname === 'github.com';
if((isGitHub || isGitLab) && !urlObj.hash && pathMatches) {
if ((isGitHub || isGitLab) && !urlObj.hash && pathMatches) {
const group = pathMatches[1];
const project = pathMatches[2];
const pathType = pathMatches[3];
const id = pathMatches[4];
var group = pathMatches[1];
var project = pathMatches[2];
var pathType = pathMatches[3];
var id = pathMatches[4];
if((pathType === 'issues' || pathType === 'merge_requests' || pathType === 'pull') && id && isValidIssueNumber(id)) {
var type = 'issue';
if(project === 'issues') {
if (
(pathType === 'issues' || pathType === 'merge_requests' || pathType === 'pull') &&
id &&
isValidIssueNumber(id)
) {
let type = 'issue';
if (project === 'issues') {
type = 'issue';
}
else if(pathType === 'merge_requests') {
} else if (pathType === 'merge_requests') {
type = 'mr';
}
else if(pathType === 'pull') {
} else if (pathType === 'pull') {
type = 'pr';

@@ -54,21 +55,21 @@ }

return {
type: type,
type,
provider: isGitLab ? 'gitlab' : 'github',
repo: group + '/' + project,
id: id,
href: href,
text: group + '/' + project + (isGitLab && type === 'mr' ? '!' : '#') + id
repo: `${group}/${project}`,
id,
href,
text: `${group}/${project}${isGitLab && type === 'mr' ? '!' : '#'}${id}`,
};
} else if(pathType === 'commit' && id && isValidCommitHash(id)) {
}
if (pathType === 'commit' && id && isValidCommitHash(id)) {
return {
type: 'commit',
provider: isGitLab ? 'gitlab' : 'github',
repo: group + '/' + project,
id: id,
href: href,
text: group + '/' + project + '@' + id.substring(0,7)
repo: `${group}/${project}`,
id,
href,
text: `${group}/${project}@${id.substring(0, 7)}`,
};
}
}
};

@@ -1,28 +0,26 @@

"use strict";
'use strict';
var cld = require('cld');
var Promise = require('bluebird');
const cld = require('cld');
const Promise = require('bluebird');
module.exports = exports = function detectLang(text) {
return Promise.fromCallback(function(callback) {
cld.detect(text, callback);
})
.then(function(result) {
if(!result || !result.languages || !Array.isArray(result.languages)) return;
return Promise.fromCallback(callback => {
cld.detect(text, callback);
})
.then(result => {
if (!result || !result.languages || !Array.isArray(result.languages)) return;
// Sometimes there are undefined values in the array
// Seems to be when the result is unreliable
var langs = result.languages.filter(function(f) {
return !!f;
});
const langs = result.languages.filter(f => Boolean(f));
var primary = langs.shift();
const primary = langs.shift();
if(!primary) return;
if (!primary) return;
return primary.code;
})
.catch(function() {
return; // Ignore errors
.catch(() => {
// Ignore errors
});
};

@@ -1,22 +0,19 @@

"use strict";
'use strict';
var Promise = require('bluebird');
var processChat = require('./process-chat');
var detectLang = require('./detect-lang');
const Promise = require('bluebird');
const processChat = require('./process-chat');
const detectLang = require('./detect-lang');
module.exports = exports = function processChatAsync(text, callback) {
return Promise.try(function() {
return processChat(text);
})
.then(function(result) {
var plainText = result.plainText.trim();
return Promise.try(() => processChat(text))
.then(result => {
const plainText = result.plainText.trim();
if(!plainText) return result;
return detectLang(plainText)
.then(function(lang) {
result.lang = lang;
return result;
});
if (!plainText) return result;
return detectLang(plainText).then(lang => {
result.lang = lang;
return result;
});
})
.nodeify(callback);
};

@@ -1,131 +0,165 @@

"use strict";
'use strict';
var marked = require('gitter-marked');
var highlight = require('highlight.js');
var _ = require('underscore');
var util = require('util');
var katex = require('katex');
var matcher = require('./decoration-url-matcher');
var htmlencode = require('htmlencode');
const marked = require('gitter-marked');
const highlight = require('highlight.js');
const _ = require('underscore');
const util = require('util');
const katex = require('katex');
const htmlencode = require('htmlencode');
const matcher = require('./decoration-url-matcher');
var options = { gfm: true, tables: true, sanitize: true, breaks: true, linkify: true, skipComments: true };
const options = {
gfm: true,
tables: true,
sanitize: true,
breaks: true,
linkify: true,
skipComments: true,
};
var lexer = new marked.Lexer(options);
const lexer = new marked.Lexer(options);
var JAVA = 'java';
var SCRIPT = 'script:';
var scriptUrl = JAVA + SCRIPT;
var dataUrl = 'data:';
var httpUrl = 'http://';
var httpsUrl = 'https://';
var noProtocolUrl = '//';
highlight.configure({
classPrefix: '',
languages: [
'apache',
'applescript',
'css',
'bash',
'clojure-repl',
'clojure',
'javascript',
'coffeescript',
'cpp',
'cs',
'd',
'dart',
'delphi',
'diff',
'django',
'dockerfile',
'dos',
'elixir',
'erb',
'erlang-repl',
'erlang',
'fortran',
'fsharp',
'gcode',
'gherkin',
'go',
'gradle',
'groovy',
'haml',
'handlebars',
'haskell',
'http',
'ini',
'java',
'json',
'kotlin',
'less',
'lisp',
'livescript',
'lua',
'makefile',
'markdown',
'mathematica',
'matlab',
'nginx',
'objectivec',
'perl',
'php',
'powershell',
'prolog',
'puppet',
'python',
'q',
'r',
'rib',
'rsl',
'ruby',
'rust',
'scala',
'scheme',
'scilab',
'scss',
'smali',
'smalltalk',
'sml',
'sql',
'stylus',
'swift',
'tcl',
'tex',
'typescript',
'vbnet',
'vbscript-html',
'vbscript',
'vim',
'x86asm',
'xml',
],
});
highlight.configure({ classPrefix: '', languages: [
"apache",
"applescript",
"css",
"bash",
"clojure-repl",
"clojure",
"javascript",
"coffeescript",
"cpp",
"cs",
"d",
"dart",
"delphi",
"diff",
"django",
"dockerfile",
"dos",
"elixir",
"erb",
"erlang-repl",
"erlang",
"fortran",
"fsharp",
"gcode",
"gherkin",
"go",
"gradle",
"groovy",
"haml",
"handlebars",
"haskell",
"http",
"ini",
"java",
"json",
"kotlin",
"less",
"lisp",
"livescript",
"lua",
"makefile",
"markdown",
"mathematica",
"matlab",
"nginx",
"objectivec",
"perl",
"php",
"powershell",
"prolog",
"puppet",
"python",
"q",
"r",
"rib",
"rsl",
"ruby",
"rust",
"scala",
"scheme",
"scilab",
"scss",
"smali",
"smalltalk",
"sml",
"sql",
"stylus",
"swift",
"tcl",
"tex",
"typescript",
"vbnet",
"vbscript-html",
"vbscript",
"vim",
"x86asm",
"xml"
]});
const startsWith = (string, substring) =>
string
.trim()
.toLowerCase()
.indexOf(substring) === 0;
function checkForIllegalUrl(href) {
if(!href) return "";
href = href.trim();
var hrefLower = href.toLowerCase();
if(hrefLower.indexOf(scriptUrl) === 0 || hrefLower.indexOf(dataUrl) === 0) {
const replaceScriptUrls = urlString => {
// eslint-disable-next-line no-script-url
if (startsWith(urlString, 'javascript:') || startsWith(urlString, 'data:')) {
/* Rickroll the script kiddies */
return "https://goo.gl/7NDM3x";
return 'https://goo.gl/7NDM3x';
}
return urlString;
};
if(hrefLower.indexOf(httpUrl) !== 0 && hrefLower.indexOf(httpsUrl) !== 0 && hrefLower.indexOf(noProtocolUrl) !== 0) {
return httpUrl + href;
/* prepend http protocol if URL doesn't use it yet */
const prependHttp = urlString => {
if (
!startsWith(urlString, 'http://') &&
!startsWith(urlString, 'https://') &&
!startsWith(urlString, '//')
) {
return `http://${urlString}`;
}
return urlString;
};
return href;
/* use punycode version of url if it contains unicode */
const normalizeIdn = urlString => {
const parsedUrl = new URL(urlString);
if (startsWith(parsedUrl.host, 'xn--')) {
return parsedUrl.href;
}
return urlString;
};
const RTLO = '\u202E';
const ENCODED_RTLO = '%E2%80%AE';
/* replaces right to left override character */
const replaceRtlo = urlString => urlString.replace(RTLO, ENCODED_RTLO);
function validateUrl(urlString) {
if (!urlString) return '';
return [urlString]
.map(replaceScriptUrls)
.map(replaceRtlo)
.map(prependHttp)
.map(normalizeIdn)
.pop();
}
function getRenderer(renderContext) {
const renderer = new marked.Renderer();
var renderer = new marked.Renderer();
// Highlight code blocks
renderer.code = function(code, lang) {
lang = (lang + '').toLowerCase();
lang = String(lang).toLowerCase();
if (lang === "text") {
if (lang === 'text') {
return util.format('<pre><code class="text">%s</code></pre>', htmlencode.htmlEncode(code));

@@ -135,3 +169,7 @@ }

if (highlight.getLanguage(lang))
return util.format('<pre><code class="%s">%s</code></pre>', lang, highlight.highlight(lang, code).value);
return util.format(
'<pre><code class="%s">%s</code></pre>',
lang,
highlight.highlight(lang, code).value,
);

@@ -145,4 +183,8 @@ return util.format('<pre><code>%s</code></pre>', highlight.highlightAuto(code).value);

return katex.renderToString(latexCode);
} catch(e) {
return util.format('<pre><code>%s: %s</code></pre>', htmlencode.htmlEncode(e.message), htmlencode.htmlEncode(latexCode));
} catch (e) {
return util.format(
'<pre><code>%s: %s</code></pre>',
htmlencode.htmlEncode(e.message),
htmlencode.htmlEncode(latexCode),
);
}

@@ -160,18 +202,18 @@ };

number: issue,
repo: repo ? repo : undefined
repo: repo || undefined,
});
var out = '<a target="_blank" data-link-type="' + type + '" data-issue="' + issue + '"';
if(href) {
let out = `<a target="_blank" data-link-type="${type}" data-issue="${issue}"`;
if (href) {
out += util.format(' href="%s"', href);
}
if(provider) {
if (provider) {
out += util.format(' data-provider="%s"', provider);
}
if(repo) {
if (repo) {
out += util.format(' data-issue-repo="%s"', repo);
}
out += ' class="' + type + '">' + text + '</a>';
out += ` class="${type}">${text}</a>`;
return out;
}
};

@@ -190,7 +232,7 @@ renderer.issue = function(provider, repo, issue, href, text) {

renderer.commit = function(provider, repo, sha, href, text) {
var text = repo+'@'+sha.substring(0, 7);
renderer.commit = function(provider, repo, sha, href /* , text */) {
const text = `${repo}@${sha.substring(0, 7)}`;
if(!href) {
var baseUrl = 'https://github.com/';
if (!href) {
let baseUrl = 'https://github.com/';
if (provider === 'gitlab') {

@@ -200,39 +242,54 @@ baseUrl = 'https://gitlab.com/';

href = baseUrl + repo + '/commit/' + sha;
href = `${baseUrl + repo}/commit/${sha}`;
}
var out = '<a href="' + href + '" target="_blank" ' +
'data-link-type="commit" ' +
'data-provider="' + provider + '" ' +
'data-commit-sha="' + sha + '" ' +
'data-commit-repo="' + repo + '" ' +
'class="commit">' + text + '</a>';
const out =
`<a href="${href}" target="_blank" ` +
`data-link-type="commit" ` +
`data-provider="${provider}" ` +
`data-commit-sha="${sha}" ` +
`data-commit-repo="${repo}" ` +
`class="commit">${text}</a>`;
return out;
};
renderer.link = function(href, title, text) {
href = checkForIllegalUrl(href);
var urlData = matcher(href);
if(urlData) {
return renderer[urlData.type](urlData.provider, urlData.repo, urlData.id, urlData.href, urlData.text);
} else {
renderContext.urls.push({ url: href });
return util.format('<a href="%s" rel="nofollow noopener noreferrer" target="_blank" class="link">%s</a>', href, text);
renderer.link = (href, title, text) => {
const validatedHref = validateUrl(href);
const urlData = matcher(href);
const showTooltip = validatedHref !== href ? 'link-tooltip' : '';
if (urlData) {
return renderer[urlData.type](
urlData.provider,
urlData.repo,
urlData.id,
urlData.href,
urlData.text,
);
}
renderContext.urls.push({ url: validatedHref });
return util.format(
'<a href="%s" rel="nofollow noopener noreferrer" target="_blank" class="link %s">%s</a>',
validatedHref,
showTooltip,
replaceRtlo(text),
);
};
renderer.image = function(href, title, text) {
href = checkForIllegalUrl(href);
href = validateUrl(href);
renderContext.urls.push({ url: href });
if (title) {
return util.format('<img src="%s" title="%s" alt="%s" rel="nofollow">', href, title, text);
} else {
return util.format('<img src="%s" alt="%s" rel="nofollow">', href, text);
}
return util.format('<img src="%s" alt="%s" rel="nofollow">', href, text);
};
renderer.mention = function(href, title, text) {
var screenName = text.charAt(0) === '@' ? text.substring(1) : text;
renderContext.mentions.push({ screenName: screenName });
return util.format('<span data-link-type="mention" data-screen-name="%s" class="mention">%s</span>', screenName, text);
const screenName = text.charAt(0) === '@' ? text.substring(1) : text;
renderContext.mentions.push({ screenName });
return util.format(
'<span data-link-type="mention" data-screen-name="%s" class="mention">%s</span>',
screenName,
text,
);
};

@@ -242,7 +299,11 @@

renderContext.mentions.push({ screenName: name, group: true });
return util.format('<span data-link-type="groupmention" data-group-name="%s" class="groupmention">%s</span>', name, text);
return util.format(
'<span data-link-type="groupmention" data-group-name="%s" class="groupmention">%s</span>',
name,
text,
);
};
renderer.email = function(href, title, text) {
checkForIllegalUrl(href);
validateUrl(href);

@@ -253,10 +314,4 @@ renderContext.urls.push({ url: href });

renderer.heading = function(text, level/*, raw */) {
return '<h' +
level +
'>' +
text +
'</h' +
level +
'>\n';
renderer.heading = function(text, level /* , raw */) {
return `<h${level}>${text}</h${level}>\n`;
};

@@ -273,7 +328,4 @@

module.exports = exports = function processChat(text) {
var renderContext = {
const renderContext = {
urls: [],

@@ -283,10 +335,10 @@ mentions: [],

plainText: [],
paragraphCount: 0
paragraphCount: 0,
};
var html = "";
let html = '';
if(text) {
text = "" + text; // Force to string
var renderer = getRenderer(renderContext);
if (text) {
text = `${text}`; // Force to string
const renderer = getRenderer(renderContext);
// Reset any references, see https://github.com/gitterHQ/gitter/issues/1041

@@ -296,20 +348,20 @@ lexer.tokens = [];

var tokens = lexer.lex(text);
var parser = new marked.Parser(_.extend({ renderer: renderer }, options));
const tokens = lexer.lex(text);
const parser = new marked.Parser(_.extend({ renderer }, options));
html = parser.parse(tokens);
if(renderContext.paragraphCount === 1) {
html = html.replace(/<\/?p>/g,'');
if (renderContext.paragraphCount === 1) {
html = html.replace(/<\/?p>/g, '');
}
} else {
text = "";
text = '';
}
return {
text: text,
html: html,
text,
html,
urls: renderContext.urls,
mentions: renderContext.mentions,
issues: renderContext.issues,
plainText: renderContext.plainText.join(' ')
plainText: renderContext.plainText.join(' '),
};
};

@@ -1,14 +0,15 @@

"use strict";
'use strict';
var workerFarm = require('worker-farm');
var htmlencode = require('htmlencode');
var version = require('../package.json').version;
const workerFarm = require('worker-farm');
const htmlencode = require('htmlencode');
const { version } = require('../package.json');
var Processor = function() {
this.farm = workerFarm({
const Processor = function() {
this.farm = workerFarm(
{
maxConcurrentWorkers: 1,
maxConcurrentCallsPerWorker: 1,
maxCallTime: 3000
maxCallTime: 3000,
},
require.resolve('./process-chat-async')
require.resolve('./process-chat-async'),
);

@@ -18,11 +19,11 @@ };

Processor.prototype.process = function(text, callback) {
this.farm(text, function(err, result) {
if(err && err.type === 'TimeoutError') {
this.farm(text, (err, result) => {
if (err && err.type === 'TimeoutError') {
result = {
text: text,
html: htmlencode.htmlEncode(text).replace(/\n|&#10;/g,'<br>'),
text,
html: htmlencode.htmlEncode(text).replace(/\n|&#10;/g, '<br>'),
urls: [],
mentions: [],
issues: [],
markdownProcessingFailed: true
markdownProcessingFailed: true,
};

@@ -29,0 +30,0 @@ }

{
"name": "gitter-markdown-processor",
"version": "14.0.0",
"version": "15.0.0",
"description": "parses gitter chat messages, but in its own process",

@@ -18,5 +18,7 @@ "main": "index.js",

"devDependencies": {
"eslint": "^5.5.0",
"@gitlab/eslint-config": "^1.6.0",
"eslint": "^6.1.0",
"eslint-plugin-node": "^7.0.1",
"mocha": "^5.2.0"
"mocha": "^5.2.0",
"prettier": "^1.18.2"
},

@@ -26,3 +28,4 @@ "scripts": {

"mocha": "mocha",
"lint": "eslint ."
"validate": "eslint . && prettier --check **/*.js",
"validate-fix": "eslint --fix . && prettier --write **/*.js"
},

@@ -29,0 +32,0 @@ "author": "Andy Trevorah",

@@ -1,13 +0,13 @@

/*jslint node:true, unused:true*/
/*global describe:true, it:true */
"use strict";
/* jslint node:true, unused:true */
/* global describe:true, it:true */
var assert = require('assert');
var matcher = require('../lib/decoration-url-matcher');
'use strict';
describe('decoration-url-matcher', function() {
const assert = require('assert');
const matcher = require('../lib/decoration-url-matcher');
describe('GitLab', function() {
it('should match an issue url', function() {
var result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/issues/216');
describe('decoration-url-matcher', () => {
describe('GitLab', () => {
it('should match an issue url', () => {
const result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/issues/216');
assert.equal(result.type, 'issue');

@@ -20,4 +20,4 @@ assert.equal(result.provider, 'gitlab');

it('should match an issue url in a sub-group', function() {
var result = matcher('https://gitlab.com/gitlab-org/gitter/webapp/issues/1755');
it('should match an issue url in a sub-group', () => {
const result = matcher('https://gitlab.com/gitlab-org/gitter/webapp/issues/1755');
assert.equal(result.type, 'issue');

@@ -30,9 +30,9 @@ assert.equal(result.provider, 'gitlab');

it('shouldnt match an issue url with non-numeric ID', function() {
var result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/issues/abc');
it('shouldnt match an issue url with non-numeric ID', () => {
const result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/issues/abc');
assert(!result);
});
it('should match a merge request url', function() {
var result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/1');
it('should match a merge request url', () => {
const result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/1');
assert.equal(result.type, 'mr');

@@ -45,9 +45,11 @@ assert.equal(result.provider, 'gitlab');

it('shouldnt match a merge request url without ID', function() {
var result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/');
it('shouldnt match a merge request url without ID', () => {
const result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/');
assert(!result);
});
it('should match a commit url', function() {
var result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/commit/eb9ca0e7e1ea4c2151abc320199e844f794bda54');
it('should match a commit url', () => {
const result = matcher(
'https://gitlab.com/gitlab-org/gitlab-ce/commit/eb9ca0e7e1ea4c2151abc320199e844f794bda54',
);
assert.equal(result.type, 'commit');

@@ -60,14 +62,14 @@ assert.equal(result.provider, 'gitlab');

it('shouldnt match an odd commit url', function() {
var result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/commit/xxxxxxxxxxxx');
it('shouldnt match an odd commit url', () => {
const result = matcher('https://gitlab.com/gitlab-org/gitlab-ce/commit/xxxxxxxxxxxx');
assert(!result);
});
it('shouldnt match url with no path (host/port only)', function() {
var result = matcher('localhost:1234');
it('shouldnt match url with no path (host/port only)', () => {
const result = matcher('localhost:1234');
assert(!result);
});
it('shouldnt match url with no path (no URL)', function() {
var result = matcher('');
it('shouldnt match url with no path (no URL)', () => {
const result = matcher('');
assert(!result);

@@ -77,5 +79,5 @@ });

describe('GitHub', function() {
it('should match an issue url', function() {
var result = matcher('https://github.com/gitterHQ/gitter/issues/216');
describe('GitHub', () => {
it('should match an issue url', () => {
const result = matcher('https://github.com/gitterHQ/gitter/issues/216');
assert.equal(result.type, 'issue');

@@ -88,4 +90,4 @@ assert.equal(result.provider, 'github');

it('should match a pull request url', function() {
var result = matcher('https://github.com/gitterHQ/gitter/pull/1');
it('should match a pull request url', () => {
const result = matcher('https://github.com/gitterHQ/gitter/pull/1');
assert.equal(result.type, 'pr');

@@ -98,14 +100,18 @@ assert.equal(result.provider, 'github');

it('shouldnt match an odd japanese issue url', function() {
var result = matcher('https://github.com/gitterHQ/gitter/issues/460]をマージしてもよろしいでしょうか?');
it('shouldnt match an odd japanese issue url', () => {
const result = matcher(
'https://github.com/gitterHQ/gitter/issues/460]をマージしてもよろしいでしょうか?',
);
assert(!result);
});
it('shouldnt match an odd issue url', function() {
var result = matcher('https://github.com/gitterHQ/gitter/issues/214]p');
it('shouldnt match an odd issue url', () => {
const result = matcher('https://github.com/gitterHQ/gitter/issues/214]p');
assert(!result);
});
it('should match a commit url', function() {
var result = matcher('https://github.com/twbs/bootstrap/commit/c8a8e768510cc1bd9e72d5cade23fba715efb59f');
it('should match a commit url', () => {
const result = matcher(
'https://github.com/twbs/bootstrap/commit/c8a8e768510cc1bd9e72d5cade23fba715efb59f',
);
assert.equal(result.type, 'commit');

@@ -118,9 +124,9 @@ assert.equal(result.provider, 'github');

it('shouldnt match an odd commit url', function() {
var result = matcher('https://github.com/gitterHQ/gitter/commit/xxxxxxxxxxxx');
it('shouldnt match an odd commit url', () => {
const result = matcher('https://github.com/gitterHQ/gitter/commit/xxxxxxxxxxxx');
assert(!result);
});
it('shouldnt match an odd commit url with no hash', function() {
var result = matcher('https://github.com/gitterHQ/gitter/commit/');
it('shouldnt match an odd commit url with no hash', () => {
const result = matcher('https://github.com/gitterHQ/gitter/commit/');
assert(!result);

@@ -127,0 +133,0 @@ });

@@ -1,96 +0,78 @@

"use strict";
'use strict';
var assert = require('assert');
var processChatAsync = require('../lib/process-chat-async');
var fs = require('fs');
var path = require('path');
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const processChatAsync = require('../lib/process-chat-async');
describe('process-chat-async', function() {
describe('process-chat-async', () => {
const dir = path.join(__dirname, 'markdown-conversions');
var dir = path.join(__dirname, 'markdown-conversions');
const items = fs.readdirSync(dir);
items
.filter(file => /\.markdown$/.test(file))
.forEach(file => {
const markdownFile = path.join(dir, file);
const htmlFile = markdownFile.replace('.markdown', '.html');
const markdown = fs.readFileSync(markdownFile, { encoding: 'utf8' });
const expectedHtml = fs.readFileSync(htmlFile, { encoding: 'utf8' });
var items = fs.readdirSync(dir);
items.filter(function(file) {
return /\.markdown$/.test(file);
}).forEach(function(file) {
var markdownFile = path.join(dir, file);
var htmlFile = markdownFile.replace('.markdown', '.html');
var markdown = fs.readFileSync(markdownFile, { encoding: 'utf8' });
var expectedHtml = fs.readFileSync(htmlFile, { encoding: 'utf8' });
it('should handle ' + file, function() {
return processChatAsync(markdown)
.then(function(result) {
var html = result.html;
it(`should handle ${file}`, () =>
processChatAsync(markdown).then(result => {
const { html } = result;
assert.equal(html.trim(), expectedHtml.trim());
});
}));
});
});
it('should detect japanese', () =>
processChatAsync('世界こんにちは、お元気ですか?').then(result => {
assert.equal(result.lang, 'ja');
}));
it('should detect japanese', function() {
return processChatAsync("世界こんにちは、お元気ですか?")
.then(function(result) {
assert.equal(result.lang, 'ja');
});
});
it('should detect korean', () =>
processChatAsync('세계 안녕하세요, 어떻게 지내 ?').then(result => {
assert.equal(result.lang, 'ko');
}));
it('should detect korean', function() {
return processChatAsync("세계 안녕하세요, 어떻게 지내 ?")
.then(function(result) {
assert.equal(result.lang, 'ko');
});
});
it('should detect russian', () =>
processChatAsync('Привет мир , как ты?').then(result => {
assert.equal(result.lang, 'ru');
return processChatAsync('1. Привет мир , как ты?');
}));
it('should detect russian', function() {
return processChatAsync("Привет мир , как ты?")
.then(function(result) {
assert.equal(result.lang, 'ru');
return processChatAsync("1. Привет мир , как ты?");
})
});
it('should detect chinese (simplified)', () =>
processChatAsync('您好,欢迎来到小胶质').then(result => {
assert.equal(result.lang, 'zh');
}));
it('should detect chinese (simplified)', function() {
return processChatAsync("您好,欢迎来到小胶质")
.then(function(result) {
assert.equal(result.lang, 'zh');
});
});
it('should detect chinese (traditional)', () =>
processChatAsync('您好,歡迎來到小膠質').then(result => {
assert.equal(result.lang, 'zh-Hant');
}));
it('should detect chinese (traditional)', function() {
return processChatAsync("您好,歡迎來到小膠質")
.then(function(result) {
assert.equal(result.lang, 'zh-Hant');
});
});
it('should detect afrikaans', function() {
return processChatAsync("hoe is jy meneer?")
.then(function(result) {
it('should detect afrikaans', () =>
processChatAsync('hoe is jy meneer?')
.then(result => {
assert.equal(result.lang, 'af');
return processChatAsync("## hoe is jy meneer?");
return processChatAsync('## hoe is jy meneer?');
})
.then(function(result) {
.then(result => {
assert.equal(result.lang, 'af');
});
});
}));
it('should deal with unreliable text snippets', function() {
return processChatAsync("あ、app/assets/javascripts/main.js は requirejs.config なんですか")
.then(function(result) {
it('should deal with unreliable text snippets', () =>
processChatAsync('あ、app/assets/javascripts/main.js は requirejs.config なんですか').then(
result => {
assert.equal(result.lang, 'ja');
});
});
},
));
it('should handle greek', function() {
return processChatAsync("Μουλιάζουμε τα ξερά σύκα στο κρασί. Ζεσταίνουμε σε τηγάνι τη 1 κουτ. σούπας λάδι και σοτάρουμε το μπέικον, μέχρι να ροδίσει. Αλατοπιπερώνουμε και ρίχνουμε το χυμό λεμονιού,το υπόλοιπο λάδι και το σπανάκι. Ανακατεύουμε ίσα να λαδωθεί το σπανάκι και να μαραθεί λίγο. Στραγγίζουμε τα σύκα και τα ανακατεύουμε με το μείγμα του τηγανιού. Απλώνουμε τη σαλάτα πάνω στις φρυγανισμένες φέτες ψωμί και σερβίρουμε")
.then(function(result) {
assert.equal(result.lang, 'el');
});
});
it('should handle greek', () =>
processChatAsync(
'Μουλιάζουμε τα ξερά σύκα στο κρασί. Ζεσταίνουμε σε τηγάνι τη 1 κουτ. σούπας λάδι και σοτάρουμε το μπέικον, μέχρι να ροδίσει. Αλατοπιπερώνουμε και ρίχνουμε το χυμό λεμονιού,το υπόλοιπο λάδι και το σπανάκι. Ανακατεύουμε ίσα να λαδωθεί το σπανάκι και να μαραθεί λίγο. Στραγγίζουμε τα σύκα και τα ανακατεύουμε με το μείγμα του τηγανιού. Απλώνουμε τη σαλάτα πάνω στις φρυγανισμένες φέτες ψωμί και σερβίρουμε',
).then(result => {
assert.equal(result.lang, 'el');
}));
it('should handle null', function() {
return processChatAsync(null);
});
it('should handle null', () => processChatAsync(null));
});

@@ -1,39 +0,36 @@

"use strict";
'use strict';
var assert = require('assert');
var Processor = require('..');
var fs = require('fs');
var path = require('path');
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const Processor = require('..');
function listTestPairs() {
var dir = path.join(__dirname, 'markdown-conversions');
const dir = path.join(__dirname, 'markdown-conversions');
var items = fs.readdirSync(dir);
return items.filter(function(file) {
return /\.markdown$/.test(file);
}).map(function(file) {
var markdownFile = path.join(dir, file);
var name = file.replace('.markdown', '');
var htmlFile = markdownFile.replace('.markdown', '.html');
var markdown = fs.readFileSync(markdownFile, { encoding: 'utf8' });
var expectedHtml = fs.readFileSync(htmlFile, { encoding: 'utf8' });
const items = fs.readdirSync(dir);
return items
.filter(file => /\.markdown$/.test(file))
.map(file => {
const markdownFile = path.join(dir, file);
const name = file.replace('.markdown', '');
const htmlFile = markdownFile.replace('.markdown', '.html');
const markdown = fs.readFileSync(markdownFile, { encoding: 'utf8' });
const expectedHtml = fs.readFileSync(htmlFile, { encoding: 'utf8' });
return {
name: name,
markdownFile: markdownFile,
htmlFile: htmlFile,
markdown: markdown,
expectedHtml: expectedHtml
};
});
return {
name,
markdownFile,
htmlFile,
markdown,
expectedHtml,
};
});
}
describe('process-chat', function() {
var processor = new Processor();
describe('process-chat', () => {
const processor = new Processor();
after(function(callback) {
processor.shutdown(function() {
after(callback => {
processor.shutdown(() => {
// Add an extra time on cos mocha will just exit without waiting

@@ -45,9 +42,9 @@ // for the child to shutdown

describe('tests', function() {
listTestPairs().forEach(function(item) {
it('should handle ' + item.name, function(done) {
processor.process(item.markdown, function(err, result) {
if(err) return done(err);
describe('tests', () => {
listTestPairs().forEach(item => {
it(`should handle ${item.name}`, done => {
processor.process(item.markdown, (err, result) => {
if (err) return done(err);
var html = result.html;
const { html } = result;
assert.equal(html.trim(), item.expectedHtml.trim());

@@ -60,23 +57,20 @@ done();

describe.skip('performance tests', function() {
listTestPairs().forEach(function(item) {
it('should handle ' + item.name, function(done) {
var completed = 0;
for(var i = 0; i < 1000; i++) {
processor.process(item.markdown, function(err, result) {
describe.skip('performance tests', () => {
listTestPairs().forEach(item => {
it(`should handle ${item.name}`, done => {
let completed = 0;
for (let i = 0; i < 1000; i++) {
processor.process(item.markdown, (err, result) => {
completed++;
if(err) return done(err);
if (err) return done(err);
var html = result.html;
const { html } = result;
assert.equal(html.trim(), item.expectedHtml.trim());
if(completed === 1000) return done();
if (completed === 1000) return done();
});
}
});
});
});
});

@@ -1,37 +0,117 @@

"use strict";
'use strict';
var assert = require('assert');
var processChat = require('../lib/process-chat');
var fs = require('fs');
var path = require('path');
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const processChat = require('../lib/process-chat');
describe('process-chat', function() {
describe('process-chat', () => {
const dir = path.join(__dirname, 'markdown-conversions');
var dir = path.join(__dirname, 'markdown-conversions');
var items = fs.readdirSync(dir);
items.filter(function(file) {
return /\.markdown$/.test(file);
}).forEach(function(file) {
var markdownFile = path.join(dir, file);
var htmlFile = markdownFile.replace('.markdown', '.html');
var markdown = fs.readFileSync(markdownFile, { encoding: 'utf8' });
var expectedHtml = fs.readFileSync(htmlFile, { encoding: 'utf8' });
it('should handle ' + file, function() {
var html = processChat(markdown).html;
assert.equal(html.trim(), expectedHtml.trim());
const items = fs.readdirSync(dir);
items
.filter(file => /\.markdown$/.test(file))
.forEach(file => {
const markdownFile = path.join(dir, file);
const htmlFile = markdownFile.replace('.markdown', '.html');
const markdown = fs.readFileSync(markdownFile, { encoding: 'utf8' });
const expectedHtml = fs.readFileSync(htmlFile, { encoding: 'utf8' });
it(`should handle ${file}`, () => {
const { html } = processChat(markdown);
assert.equal(html.trim(), expectedHtml.trim());
});
});
});
it('should isolate link references between messages', function() {
var inputMd1 = '[Community for developers to chat][1]\n\n[1]: https://gitter.im/';
var inputMd2 = 'arr[1]';
var html1 = processChat(inputMd1).html;
assert.equal(html1.trim(), '<a href="https://gitter.im/" rel="nofollow noopener noreferrer" target="_blank" class="link">Community for developers to chat</a>');
var html2 = processChat(inputMd2).html;
it('should isolate link references between messages', () => {
const inputMd1 = '[Community for developers to chat][1]\n\n[1]: https://gitter.im/';
const inputMd2 = 'arr[1]';
const html1 = processChat(inputMd1).html;
assert.equal(
html1.trim(),
'<a href="https://gitter.im/" rel="nofollow noopener noreferrer" target="_blank" class="link ">Community for developers to chat</a>',
);
const html2 = processChat(inputMd2).html;
assert.equal(html2.trim(), 'arr[1]');
});
describe('invalid and suspicious links', () => {
it('replaces URL with javascript: and data:', () => {
const examples = [
'[click here](data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=)',
// eslint-disable-next-line no-script-url
'[click here](javascript:alert(1))',
];
const htmlLinks = examples.map(markdown => processChat(markdown).html);
htmlLinks.forEach(link =>
assert(
link.indexOf('https://goo.gl/7NDM3x') !== -1,
`should replace their link (${link}) with a rickroll video`,
),
);
});
it('adds http to links without correct protocol', () => {
const htmlLink = processChat('[label](www.example.com)').html;
assert(
htmlLink.indexOf('http://www.example.com') !== -1,
`Link ${htmlLink} should have http:// prepended`,
);
});
it('should add a tooltip class to links that are not normalized/valid', () => {
const examples = [
'http://example.com/evil\u202E3pm.exe',
'[evilexe.mp3](http://example.com/evil\u202E3pm.exe)',
'rdar://localhost.com/\u202E3pm.exe',
'http://one😄two.com',
'[Evil-Test](http://one😄two.com)',
'http://\u0261itlab.com',
'[Evil-GitLab-link](http://\u0261itlab.com)',
];
const htmlLinks = examples.map(markdown => processChat(markdown).html);
htmlLinks.forEach(link =>
assert(link.indexOf('tooltip') !== -1, `Link ${link} is missing tooltip`),
);
});
it('should use normalized href for IDN hosts', () => {
const idnLink = 'http://one😄two.com';
const link = processChat(idnLink).html;
// Test the displayed URL text in the <a>xxx</a> tag
assert(link.indexOf('>http://one😄two.com<') !== -1, `Link label got changed: ${link}`);
// Test the href attribute
assert(
link.indexOf('href="http://xn--onetwo-yw74e.com/"') !== -1,
`Link href should be in punycode: ${link}`,
);
});
it('escapes RTLO characters', () => {
// Rendered text looks like it does not have any extra RTLO characters in it - "http://example.com/evilexe.mp3"
// Actual dodgy string with RTLO character in it - http://example.com/evil‮3pm.exe
const evilLink = 'http://example.com/evil\u202E3pm.exe';
const link = processChat(evilLink).html;
assert(
link.indexOf('http://example.com/evil%E2%80%AE3pm.exe') !== -1,
`RTLO character is not escaped: ${link}`,
);
assert(
link.indexOf('\u202E') === -1,
`Doesn't leave any unescaped RTLO characters anywhere in the link ${link}`,
);
});
it('should add no tooltips for safe links', () => {
const goodExamples = [
'http://example.com',
'[Safe-Test](http://example.com)',
'https://commons.wikimedia.org/wiki/File:اسكرام_2_-_تمنراست.jpg',
'[Wikipedia-link](https://commons.wikimedia.org/wiki/File:اسكرام_2_-_تمنراست.jpg)',
];
const htmlLinks = goodExamples.map(markdown => processChat(markdown).html);
htmlLinks.forEach(link =>
assert(link.indexOf('tooltip') === -1, `Link ${link} shouldn't have a tooltip`),
);
});
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc