Skip to content

Commit

Permalink
Merge a4a2873 into fb02cc9
Browse files Browse the repository at this point in the history
  • Loading branch information
SukkaW committed Nov 2, 2019
2 parents fb02cc9 + a4a2873 commit de8d1f8
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 0 deletions.
38 changes: 38 additions & 0 deletions README.md
Expand Up @@ -25,6 +25,7 @@ Utilities for [Hexo].
- [hash](#hashstr)
- [highlight](#highlightstr-options)
- [htmlTag](#htmltagtag-attrs-text-escape)
- [isExternalLink](#isexternallinkurl)
- [Pattern](#patternrule)
- [Permalink](#permalinkrule-options)
- [relative_url](#relative_urlfrom-to)
Expand Down Expand Up @@ -256,6 +257,42 @@ htmlTag('script', {src: '/foo.js', async: true}, '')
// <script src="/foo.js" async></script>
```

### isExternalLink(url)

Returns if a given url is external link relative to `config.url` and `config.exclude`.

``` yml
_config.yml
url: https://example.com # example
```

``` js
isExternalLink('https://example.com');
// false
isExternalLink('/archives/foo.html');
// false
isExternalLink('https://foo.com/');
// true
```

``` yml
_config.yml
url: https://example.com # example
exclude:
- foo.com
- bar.com
```

``` js
isExternalLink('https://foo.com');
// false
isExternalLink('https://bar.com');
// false
isExternalLink('https://baz.com/');
// true
```


### Pattern(rule)

Parses the string and tests if the string matches the rule. `rule` can be a string, a regular expression or a function.
Expand Down Expand Up @@ -451,6 +488,7 @@ Following utilities require `bind(hexo)` / `bind(this)` / `call(hexo, input)` /
- [`full_url_for()`](#full_url_forpath)
- [`url_for()`](#url_forpath)
- [`relative_url()`](#relative_urlfrom-to)
- [`isExternalLink()`](#isexternallinkurl)

Below examples demonstrate different approaches to creating a [helper](https://hexo.io/api/helper) (each example is separated by `/******/`),

Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -17,6 +17,7 @@ exports.hash = hash.hash;
exports.HashStream = hash.HashStream;
exports.highlight = require('./highlight');
exports.htmlTag = require('./html_tag');
exports.isExternalLink = require('./isExternalLink');
exports.Pattern = require('./pattern');
exports.Permalink = require('./permalink');
exports.relative_url = require('./relative_url');
Expand Down
43 changes: 43 additions & 0 deletions lib/is_external_link.js
@@ -0,0 +1,43 @@
'use strict';

const { URL } = require('url');

const urlObj = (str) => {
try {
return new URL(str);
} catch (err) {
return str;
}
};

/**
* Check whether the link is external
* @param {String} url The url to check
* @returns {Boolean} True if the link doesn't have protocol or link has same host with config.url
*/

function isExternalLink(url) {
const { config } = this;
const exclude = Array.isArray(config.external_link.exclude) ? config.external_link.exclude
: [config.external_link.exclude];
const data = urlObj(url);
const host = data.hostname;
const sitehost = typeof urlObj(config.url) === 'object' ? urlObj(config.url).hostname : config.url;

if (!sitehost || typeof data === 'string') return false;

// handle mailto: javascript: vbscript: and so on
if (data.origin === 'null') return false;

if (exclude && exclude.length) {
for (const i of exclude) {
if (host === i) return false;
}
}

if (host !== sitehost) return true;

return false;
}

module.exports = isExternalLink;
48 changes: 48 additions & 0 deletions test/is_external_link.spec.js
@@ -0,0 +1,48 @@
'use strict';

describe('isExternalLink', () => {
const ctx = {
config: {
url: 'https://example.com',
external_link: {}
}
};

const isExternalLink = require('../lib/is_external_link').bind(ctx);

it('external link', () => {
isExternalLink('https://hexo.io/').should.eql(true);
});

it('internal link', () => {
isExternalLink('https://example.com').should.eql(false);
isExternalLink('//example.com').should.eql(false);
isExternalLink('//example.com/archives/foo.html').should.eql(false);
isExternalLink('/archives/foo.html').should.eql(false);
});

it('hash, mailto, javascript', () => {
isExternalLink('#top').should.eql(false);
isExternalLink('mailto:hi@hexo.io').should.eql(false);
isExternalLink('javascript:alert(\'Hexo is Awesome\')').should.eql(false);
});

it('exclude - empty string', () => {
ctx.config.external_link.exclude = '';
isExternalLink('https://hexo.io/').should.eql(true);
});

it('exclude - string', () => {
ctx.config.external_link.exclude = 'foo.com';
isExternalLink('https://foo.com/').should.eql(false);
isExternalLink('https://bar.com/').should.eql(true);
isExternalLink('https://baz.com/').should.eql(true);
});

it('exclude - array', () => {
ctx.config.external_link.exclude = ['foo.com', 'bar.com'];
isExternalLink('https://foo.com/').should.eql(false);
isExternalLink('https://bar.com/').should.eql(false);
isExternalLink('https://baz.com/').should.eql(true);
});
});

0 comments on commit de8d1f8

Please sign in to comment.