Browse Source

Replaced `autolinker` with `linkify-it`, closes #2

pull/82/head
Vitaly Puzrin 10 years ago
parent
commit
9159018e2a
  1. 10
      lib/index.js
  2. 77
      lib/rules_core/linkify.js
  3. 2
      package.json
  4. 8
      test/fixtures/markdown-it/linkify.txt

10
lib/index.js

@ -9,6 +9,7 @@ var Renderer = require('./renderer');
var ParserCore = require('./parser_core'); var ParserCore = require('./parser_core');
var ParserBlock = require('./parser_block'); var ParserBlock = require('./parser_block');
var ParserInline = require('./parser_inline'); var ParserInline = require('./parser_inline');
var LinkifyIt = require('linkify-it');
var config = { var config = {
'default': require('./presets/default'), 'default': require('./presets/default'),
@ -192,6 +193,15 @@ function MarkdownIt(presetName, options) {
**/ **/
this.renderer = new Renderer(); this.renderer = new Renderer();
/**
* MarkdownIt#linkify -> LinkifyIt
*
* [linkify-it](https://github.com/markdown-it/linkify-it) instance.
* Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.js)
* rule.
**/
this.linkify = new LinkifyIt();
// Expose utils & helpers for easy acces from plugins // Expose utils & helpers for easy acces from plugins
/** /**

77
lib/rules_core/linkify.js

@ -5,11 +5,8 @@
'use strict'; 'use strict';
var Autolinker = require('autolinker');
var arrayReplaceAt = require('../common/utils').arrayReplaceAt; var arrayReplaceAt = require('../common/utils').arrayReplaceAt;
var normalizeLink = require('../common/utils').normalizeLink;
var LINK_SCAN_RE = /www|@|\:\/\//;
function isLinkOpen(str) { function isLinkOpen(str) {
@ -19,54 +16,17 @@ function isLinkClose(str) {
return /^<\/a\s*>/i.test(str); return /^<\/a\s*>/i.test(str);
} }
// Stupid fabric to avoid singletons, for thread safety.
// Required for engines like Nashorn.
//
function createLinkifier() {
var links = [];
var autolinker = new Autolinker({
stripPrefix: false,
url: true,
email: true,
twitter: false,
replaceFn: function (__, match) {
// Only collect matched strings but don't change anything.
switch (match.getType()) {
/*eslint default-case:0*/
case 'url':
links.push({
text: match.matchedText,
url: match.getUrl()
});
break;
case 'email':
links.push({
text: match.matchedText,
// normalize email protocol
url: 'mailto:' + match.getEmail().replace(/^mailto:/i, '')
});
break;
}
return false;
}
});
return {
links: links,
autolinker: autolinker
};
}
module.exports = function linkify(state) { module.exports = function linkify(state) {
var i, j, l, tokens, token, text, nodes, ln, pos, level, htmlLinkLevel, var i, j, l, tokens, token, nodes, ln, text, pos, lastPos, level, htmlLinkLevel,
blockTokens = state.tokens, blockTokens = state.tokens,
linkifier = null, links, autolinker; links;
if (!state.md.options.linkify) { return; } if (!state.md.options.linkify) { return; }
for (j = 0, l = blockTokens.length; j < l; j++) { for (j = 0, l = blockTokens.length; j < l; j++) {
if (blockTokens[j].type !== 'inline') { continue; } if (blockTokens[j].type !== 'inline') { continue; }
tokens = blockTokens[j].children; tokens = blockTokens[j].children;
htmlLinkLevel = 0; htmlLinkLevel = 0;
@ -96,42 +56,33 @@ module.exports = function linkify(state) {
} }
if (htmlLinkLevel > 0) { continue; } if (htmlLinkLevel > 0) { continue; }
if (token.type === 'text' && LINK_SCAN_RE.test(token.content)) { if (token.type === 'text' && state.md.linkify.test(token.content)) {
// Init linkifier in lazy manner, only if required.
if (!linkifier) {
linkifier = createLinkifier();
links = linkifier.links;
autolinker = linkifier.autolinker;
}
text = token.content; text = token.content;
links.length = 0; links = state.md.linkify.match(text);
autolinker.link(text);
if (!links.length) { continue; }
// Now split string to nodes // Now split string to nodes
nodes = []; nodes = [];
level = token.level; level = token.level;
lastPos = 0;
for (ln = 0; ln < links.length; ln++) { for (ln = 0; ln < links.length; ln++) {
if (!state.md.inline.validateLink(links[ln].url)) { continue; } if (!state.md.inline.validateLink(links[ln].url)) { continue; }
pos = text.indexOf(links[ln].text); pos = links[ln].index;
if (pos) { if (pos > lastPos) {
level = level; level = level;
nodes.push({ nodes.push({
type: 'text', type: 'text',
content: text.slice(0, pos), content: text.slice(lastPos, pos),
level: level level: level
}); });
} }
nodes.push({ nodes.push({
type: 'link_open', type: 'link_open',
href: links[ln].url, href: normalizeLink(links[ln].url),
target: '', target: '',
title: '', title: '',
level: level++ level: level++
@ -145,12 +96,12 @@ module.exports = function linkify(state) {
type: 'link_close', type: 'link_close',
level: --level level: --level
}); });
text = text.slice(pos + links[ln].text.length); lastPos = links[ln].lastIndex;
} }
if (text.length) { if (lastPos < text.length) {
nodes.push({ nodes.push({
type: 'text', type: 'text',
content: text, content: text.slice(lastPos),
level: level level: level
}); });
} }

2
package.json

@ -25,7 +25,7 @@
}, },
"dependencies": { "dependencies": {
"argparse": "~ 1.0.0", "argparse": "~ 1.0.0",
"autolinker": "~ 0.15.2", "linkify-it": "~ 0.1.1",
"uc.micro": "~ 0.1.0" "uc.micro": "~ 0.1.0"
}, },
"devDependencies": { "devDependencies": {

8
test/fixtures/markdown-it/linkify.txt

@ -38,14 +38,6 @@ www.example.org
. .
properly cut domain end
.
www.example.org版权所有
.
<p><a href="http://www.example.org">www.example.org</a>版权所有</p>
.
emails emails
. .
test@example.com test@example.com

Loading…
Cancel
Save