Skip to content

Commit

Permalink
refactor(external_link): optimize (#4008)
Browse files Browse the repository at this point in the history
* refactor(external_link): optimize

* refactor(external_link): optimize regexp

* refactor(external_link): remove castArray step

* refactor(external_link): simplify regexp
  • Loading branch information
SukkaW authored Jan 11, 2020
1 parent 5c098cc commit da5723c
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 43 deletions.
14 changes: 5 additions & 9 deletions lib/plugins/filter/after_post_render/external_link.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,17 @@ function externalLinkFilter(data) {
if (config.external_link === false || config.external_link.enable === false
|| config.external_link.field !== 'post') return;

const exclude = Array.isArray(config.external_link.exclude) ? config.external_link.exclude
: [config.external_link.exclude];

data.content = data.content.replace(/<a .*?(href=['"](.+?)['"]).*?>/gi, (str, hrefStr, href) => {
if (/target=/gi.test(str) || !isExternalLink(href, config.url, exclude)) return str;
data.content = data.content.replace(/<a([\s]+|[\s]+[^<>]+[\s]+)href=["']([^<>"']+)["'][^<>]*>/gi, (str, _, href) => {
if (/target=/gi.test(str) || !isExternalLink(href, config.url, config.external_link.exclude)) return str;

if (/rel=/gi.test(str)) {
str = str.replace(/rel="(.*?)"/gi, (relStr, rel) => {
if (!rel.includes('noopenner')) relStr = relStr.replace(rel, `${rel} noopener`);
return relStr;
return rel.includes('noopenner') ? relStr : `rel="${rel} noopener"`;
});
return str.replace(hrefStr, `${hrefStr} target="_blank"`);
return str.replace('href=', 'target="_blank" href=');
}

return str.replace(hrefStr, `${hrefStr} target="_blank" rel="noopener"`);
return str.replace('href=', 'target="_blank" rel="noopener" href=');
});
}

Expand Down
14 changes: 5 additions & 9 deletions lib/plugins/filter/after_render/external_link.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,17 @@ function externalLinkFilter(data) {
if (config.external_link === false || config.external_link.enable === false
|| config.external_link.field !== 'site') return;

const exclude = Array.isArray(config.external_link.exclude) ? config.external_link.exclude
: [config.external_link.exclude];

data = data.replace(/<a .*?(href=['"](.+?)['"]).*?>/gi, (str, hrefStr, href) => {
if (/target=/gi.test(str) || !isExternalLink(href, config.url, exclude)) return str;
data = data.replace(/<a([\s]+|[\s]+[^<>]+[\s]+)href=["']([^<>"']+)["'][^<>]*>/gi, (str, _, href) => {
if (/target=/gi.test(str) || !isExternalLink(href, config.url, config.external_link.exclude)) return str;

if (/rel=/gi.test(str)) {
str = str.replace(/rel="(.*?)"/gi, (relStr, rel) => {
if (!rel.includes('noopenner')) relStr = relStr.replace(rel, `${rel} noopener`);
return relStr;
return rel.includes('noopenner') ? relStr : `rel="${rel} noopener"`;
});
return str.replace(hrefStr, `${hrefStr} target="_blank"`);
return str.replace('href=', 'target="_blank" href=');
}

return str.replace(hrefStr, `${hrefStr} target="_blank" rel="noopener"`);
return str.replace('href=', 'target="_blank" rel="noopener" href=');
});

return data;
Expand Down
50 changes: 25 additions & 25 deletions test/scripts/filters/external_link.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,17 @@ describe('External link', () => {
result.should.eql([
'# External link test',
'1. External link',
'<a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>',
'<a target="_blank" rel="noopener" href="https://hexo.io/">Hexo</a>',
'2. External link with "rel" Attribute',
'<a rel="external noopener" href="https://hexo.io/" target="_blank">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="external noopener">Hexo</a>',
'<a rel="noopenner" href="https://hexo.io/" target="_blank">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="noopenner">Hexo</a>',
'<a rel="external noopenner" href="https://hexo.io/" target="_blank">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="external noopenner">Hexo</a>',
'<a rel="external noopener" target="_blank" href="https://hexo.io/">Hexo</a>',
'<a target="_blank" href="https://hexo.io/" rel="external noopener">Hexo</a>',
'<a rel="noopenner" target="_blank" href="https://hexo.io/">Hexo</a>',
'<a target="_blank" href="https://hexo.io/" rel="noopenner">Hexo</a>',
'<a rel="external noopenner" target="_blank" href="https://hexo.io/">Hexo</a>',
'<a target="_blank" href="https://hexo.io/" rel="external noopenner">Hexo</a>',
'3. External link with Other Attributes',
'<a class="img" href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="noopener" class="img">Hexo</a>',
'<a class="img" target="_blank" rel="noopener" href="https://hexo.io/">Hexo</a>',
'<a target="_blank" rel="noopener" href="https://hexo.io/" class="img">Hexo</a>',
'4. Internal link',
'<a href="/archives/foo.html">Link</a>',
'5. Ignore links have "target" attribute',
Expand Down Expand Up @@ -113,7 +113,7 @@ describe('External link', () => {
hexo.config.external_link = true;

const result = externalLink(content);
result.should.eql('<a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>');
result.should.eql('<a target="_blank" rel="noopener" href="https://hexo.io/">Hexo</a>');

hexo.config.external_link = {
enable: true,
Expand All @@ -135,8 +135,8 @@ describe('External link', () => {

result.should.eql([
'<a href="https://foo.com/">Hexo</a>',
'<a href="https://bar.com/" target="_blank" rel="noopener">Hexo</a>',
'<a href="https://baz.com/" target="_blank" rel="noopener">Hexo</a>'
'<a target="_blank" rel="noopener" href="https://bar.com/">Hexo</a>',
'<a target="_blank" rel="noopener" href="https://baz.com/">Hexo</a>'
].join('\n'));

hexo.config.external_link.exclude = '';
Expand All @@ -156,7 +156,7 @@ describe('External link', () => {
result.should.eql([
'<a href="https://foo.com/">Hexo</a>',
'<a href="https://bar.com/">Hexo</a>',
'<a href="https://baz.com/" target="_blank" rel="noopener">Hexo</a>'
'<a target="_blank" rel="noopener" href="https://baz.com/">Hexo</a>'
].join('\n'));

hexo.config.external_link.exclude = '';
Expand Down Expand Up @@ -236,21 +236,21 @@ describe('External link - post', () => {
data.content.should.eql([
'# External link test',
'1. External link',
'<a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>',
'<a target="_blank" rel="noopener" href="https://hexo.io/">Hexo</a>',
'2. Link with hash (#), mailto: , javascript: shouldn\'t be processed',
'<a href="#top">Hexo</a>',
'<a href="mailto:hi@hexo.io">Hexo</a>',
'<a href="javascript:alert(\'Hexo is awesome!\');">Hexo</a>',
'3. External link with "rel" Attribute',
'<a rel="external noopener" href="https://hexo.io/" target="_blank">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="external noopener">Hexo</a>',
'<a rel="noopenner" href="https://hexo.io/" target="_blank">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="noopenner">Hexo</a>',
'<a rel="external noopenner" href="https://hexo.io/" target="_blank">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="external noopenner">Hexo</a>',
'<a rel="external noopener" target="_blank" href="https://hexo.io/">Hexo</a>',
'<a target="_blank" href="https://hexo.io/" rel="external noopener">Hexo</a>',
'<a rel="noopenner" target="_blank" href="https://hexo.io/">Hexo</a>',
'<a target="_blank" href="https://hexo.io/" rel="noopenner">Hexo</a>',
'<a rel="external noopenner" target="_blank" href="https://hexo.io/">Hexo</a>',
'<a target="_blank" href="https://hexo.io/" rel="external noopenner">Hexo</a>',
'4. External link with Other Attributes',
'<a class="img" href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="noopener" class="img">Hexo</a>',
'<a class="img" target="_blank" rel="noopener" href="https://hexo.io/">Hexo</a>',
'<a target="_blank" rel="noopener" href="https://hexo.io/" class="img">Hexo</a>',
'5. Internal link',
'<a href="/archives/foo.html">Link</a>',
'6. Ignore links have "target" attribute',
Expand Down Expand Up @@ -295,8 +295,8 @@ describe('External link - post', () => {

data.content.should.eql([
'<a href="https://foo.com/">Hexo</a>',
'<a href="https://bar.com/" target="_blank" rel="noopener">Hexo</a>',
'<a href="https://baz.com/" target="_blank" rel="noopener">Hexo</a>'
'<a target="_blank" rel="noopener" href="https://bar.com/">Hexo</a>',
'<a target="_blank" rel="noopener" href="https://baz.com/">Hexo</a>'
].join('\n'));

hexo.config.external_link.exclude = '';
Expand All @@ -317,7 +317,7 @@ describe('External link - post', () => {
data.content.should.eql([
'<a href="https://foo.com/">Hexo</a>',
'<a href="https://bar.com/">Hexo</a>',
'<a href="https://baz.com/" target="_blank" rel="noopener">Hexo</a>'
'<a target="_blank" rel="noopener" href="https://baz.com/">Hexo</a>'
].join('\n'));

hexo.config.external_link.exclude = '';
Expand Down

0 comments on commit da5723c

Please sign in to comment.