diff --git a/README.md b/README.md index 60c4cb6..f850823 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Add nofollow attribute to all external links automatically. -`hexo-filter-nofollow` add `rel="external nofollow noreferrer"` to all external links for security, privacy and SEO. [Read more](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). +`hexo-filter-nofollow` add `rel="noopener external nofollow noreferrer"` to all external links for security, privacy and SEO. [Read more](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). ## Installations diff --git a/lib/filter.js b/lib/filter.js index 0b07a4d..5e70272 100755 --- a/lib/filter.js +++ b/lib/filter.js @@ -31,20 +31,23 @@ module.exports = function(data) { } const filterExternal = (data) => { - const noFollow = 'external nofollow noreferrer'; - return data.replace(//gi, (str, hrefStr, href) => { if (!isExternal(href, config)) return str; + let noFollow = ['noopener', 'external', 'nofollow', 'noreferrer']; + if (/rel=/gi.test(str)) { - return str.replace(/rel="(.*?)"/gi, (relStr, rel) => { - // Avoid duplicate attribute - if (!/(external|nofollow|noreferrer)/gi.test(rel)) relStr = relStr.replace(rel, `${rel} ${noFollow}`); - return relStr; + str = str.replace(/\srel="(.*?)"/gi, (relStr, rel) => { + rel = rel.split(' '); + noFollow.push(...rel); + // De-duplicate + noFollow = [...new Set(noFollow)]; + + return ''; }); } - return str.replace(hrefStr, `${hrefStr} rel="${noFollow}"`); + return str.replace(hrefStr, `${hrefStr} rel="${noFollow.join(' ')}"`); }); }; diff --git a/test/index.js b/test/index.js index dca69db..161b609 100755 --- a/test/index.js +++ b/test/index.js @@ -11,7 +11,7 @@ describe('hexo-filter-nofollow', () => { hexo.config.url = 'https://example.com'; hexo.config.nofollow = {}; - it('Default (field to "site")', () => { + describe('Default', () => { const content = [ '# External link test', '1. External link', @@ -19,10 +19,10 @@ describe('hexo-filter-nofollow', () => { '2. External link with existed "rel" Attribute', 'Hexo', 'Hexo', - '3. External link with existed "rel=noopenner", "rel=external" or "rel=noreferrer"', - 'Hexo', + '3. External link with existing "rel=noopener", "rel=external" or "rel=noreferrer"', + 'Hexo', 'Hexo', - 'Hexo', + 'Hexo', 'Hexo', '4. External link with Other Attributes', 'Hexo', @@ -33,108 +33,46 @@ describe('hexo-filter-nofollow', () => { 'Anchor' ].join('\n'); - const result = nofollowFilter(content); - - result.should.eql([ + const expected = [ '# External link test', '1. External link', - 'Hexo', + 'Hexo', '2. External link with existed "rel" Attribute', - 'Hexo', - 'Hexo', - '3. External link with existed "rel=noopenner", "rel=external" or "rel=noreferrer"', - 'Hexo', - 'Hexo', - 'Hexo', - 'Hexo', + 'Hexo', + 'Hexo', + '3. External link with existing "rel=noopener", "rel=external" or "rel=noreferrer"', + 'Hexo', + 'Hexo', + 'Hexo', + 'Hexo', '4. External link with Other Attributes', - 'Hexo', - 'Hexo', - '5. Internal link', - 'Link', - '6. Ignore links don\'t have "href" attribute', - 'Anchor' - ].join('\n')); - }); - - it('Set field as "post"', () => { - const content = [ - '# External link test', - '1. External link', - 'Hexo', - '2. External link with existed "rel" Attribute', - 'Hexo', - 'Hexo', - '3. External link with existed "rel=noopenner", "rel=external" or "rel=noreferrer"', - 'Hexo', - 'Hexo', - 'Hexo', - 'Hexo', - '4. External link with Other Attributes', - 'Hexo', - 'Hexo', + 'Hexo', + 'Hexo', '5. Internal link', 'Link', '6. Ignore links don\'t have "href" attribute', 'Anchor' ].join('\n'); - hexo.config.nofollow.field = 'post'; - - const data = { content }; - const result = nofollowFilter(data).content; - - result.should.eql([ - '# External link test', - '1. External link', - 'Hexo', - '2. External link with existed "rel" Attribute', - 'Hexo', - 'Hexo', - '3. External link with existed "rel=noopenner", "rel=external" or "rel=noreferrer"', - 'Hexo', - 'Hexo', - 'Hexo', - 'Hexo', - '4. External link with Other Attributes', - 'Hexo', - 'Hexo', - '5. Internal link', - 'Link', - '6. Ignore links don\'t have "href" attribute', - 'Anchor' - ].join('\n')); + it('Default to field = "site"', () => { + const result = nofollowFilter(content); - hexo.config.nofollow.field = 'site'; - }); + result.should.eql(expected); + }); - it('Pass a string to hexo.config.nofollow.exclude', () => { - const content = [ - '# Exclude link test', - '1. External link', - 'Hexo', - '2. Ignore links whose hostname is same as config', - 'Example Domain', - '3. Ignore links whose hostname is same as exclude', - 'Example Domain' - ].join('\n'); + it('field = "post"', () => { + hexo.config.nofollow.field = 'post'; - hexo.config.nofollow.exclude = 'example.org'; + const data = { content }; + const result = nofollowFilter(data).content; - const result = nofollowFilter(content); + result.should.eql(expected); - result.should.eql([ - '# Exclude link test', - '1. External link', - 'Hexo', - '2. Ignore links whose hostname is same as config', - 'Example Domain', - '3. Ignore links whose hostname is same as exclude', - 'Example Domain' - ].join('\n')); + hexo.config.nofollow.field = 'site'; + }); }); - it('Pass a Array to hexo.config.nofollow.exclude', () => { + describe('Exclude', () => { const content = [ '# Exclude link test', '1. External link', @@ -146,19 +84,38 @@ describe('hexo-filter-nofollow', () => { 'Example Domain' ].join('\n'); - hexo.config.nofollow.exclude = ['example.org', 'test.example.org']; - - const result = nofollowFilter(content); - - result.should.eql([ - '# Exclude link test', - '1. External link', - 'Hexo', - '2. Ignore links whose hostname is same as config', - 'Example Domain', - '3. Ignore links whose hostname is included in exclude', - 'Example Domain', - 'Example Domain' - ].join('\n')); + it('String', () => { + hexo.config.nofollow.exclude = 'example.org'; + + const result = nofollowFilter(content); + + result.should.eql([ + '# Exclude link test', + '1. External link', + 'Hexo', + '2. Ignore links whose hostname is same as config', + 'Example Domain', + '3. Ignore links whose hostname is included in exclude', + 'Example Domain', + 'Example Domain' + ].join('\n')); + }); + + it('Array', () => { + hexo.config.nofollow.exclude = ['example.org', 'test.example.org']; + + const result = nofollowFilter(content); + + result.should.eql([ + '# Exclude link test', + '1. External link', + 'Hexo', + '2. Ignore links whose hostname is same as config', + 'Example Domain', + '3. Ignore links whose hostname is included in exclude', + 'Example Domain', + 'Example Domain' + ].join('\n')); + }); }); });