Skip to content

Commit

Permalink
Merge afdc7f8 into f80d6c6
Browse files Browse the repository at this point in the history
  • Loading branch information
SukkaW committed Dec 19, 2019
2 parents f80d6c6 + afdc7f8 commit 141e153
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 55 deletions.
42 changes: 42 additions & 0 deletions README.md
Expand Up @@ -12,6 +12,7 @@ Utilities for [Hexo].

- [Installation](#installation)
- [Usage](#usage)
- [Cache](#cache)
- [CacheStream](#cachestream)
- [camelCaseKeys](#camelcasekeysobj-options)
- [createSha1Hash](#createsha1hash)
Expand Down Expand Up @@ -53,6 +54,47 @@ $ npm install hexo-util --save
var util = require('hexo-util');
```

### Cache()

A simple plain object cache

``` js
const cache = new Cache();

// set(key, value)
cache.set('foo', 'bar');

// get(key) => value
cache.get('foo');
// 'bar'

// has(key) => Boolean
cache.has('foo');
// true
cache.has('bar');
// false

// apply(key. value)
cache.apply('baz', () => 123);
// 123
cache.apply('baz', () => 456);
// 123
cache.apply('qux', 456);
// 456
cache.apply('qux', '789');
// 456

// del(key)
cache.del('baz');
cache.has('baz');
// false

// flush()
cache.flush();
cache.has('foo');
// false
```

### CacheStream()

Caches contents piped to the stream.
Expand Down
36 changes: 36 additions & 0 deletions lib/cache.js
@@ -0,0 +1,36 @@
'use strict';

module.exports = class Cache {
constructor() {
this.cache = {};
}

set(id, value) {
this.cache[id] = value;
}

has(id) {
return typeof this.cache[id] !== 'undefined';
}

get(id) {
return this.cache[id];
}

del(id) {
delete this.cache[id];
}

apply(id, value) {
if (this.has(id)) return this.get(id);

if (typeof value === 'function') value = value();

this.set(id, value);
return value;
}

flush() {
this.cache = {};
}
};
25 changes: 15 additions & 10 deletions lib/full_url_for.js
Expand Up @@ -4,27 +4,32 @@ const { parse, URL } = require('url');
const encodeURL = require('./encode_url');
const prettyUrls = require('./pretty_urls');

const Cache = require('./cache');
const cache = new Cache();

function fullUrlForHelper(path = '/') {
const pathRegex = /^(\/\/|http(s)?:)/;
if (pathRegex.test(path)) return path;

const { config } = this;
const sitehost = parse(config.url).hostname || config.url;
const data = new URL(path, `http://${sitehost}`);

// Exit if input is an external link or a data url
if (data.hostname !== sitehost || data.origin === 'null') return path;

path = encodeURL(config.url + `/${path}`.replace(/\/{2,}/g, '/'));

const prettyUrlsOptions = Object.assign({
trailing_index: true,
trailing_html: true
}, config.pretty_urls);

path = prettyUrls(path, prettyUrlsOptions);
// cacheId is designed to works across different hexo.config & options
return cache.apply(`${config.url}-${prettyUrlsOptions.trailing_index}-${prettyUrlsOptions.trailing_html}-${path}`, () => {
const sitehost = parse(config.url).hostname || config.url;
const data = new URL(path, `http://${sitehost}`);

// Exit if input is an external link or a data url
if (data.hostname !== sitehost || data.origin === 'null') return path;

path = encodeURL(config.url + `/${path}`.replace(/\/{2,}/g, '/'));
path = prettyUrls(path, prettyUrlsOptions);

return path;
return path;
});
}

module.exports = fullUrlForHelper;
9 changes: 8 additions & 1 deletion lib/gravatar.js
Expand Up @@ -3,6 +3,9 @@
const { createHash } = require('crypto');
const { stringify } = require('querystring');

const Cache = require('./cache');
const cache = new Cache();

function md5(str) {
return createHash('md5').update(str).digest('hex');
}
Expand All @@ -12,11 +15,15 @@ function gravatarHelper(email, options) {
options = {s: options};
}

let str = `https://www.gravatar.com/avatar/${md5(email.toLowerCase())}`;
const hash = cache.has(email) ? cache.get(email) : md5(email.toLowerCase());
let str = `https://www.gravatar.com/avatar/${hash}`;

const qs = stringify(options);

if (qs) str += `?${qs}`;

cache.set('email', hash);

return str;
}

Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -2,6 +2,7 @@

const hash = require('./hash');

exports.Cache = require('./cache');
exports.CacheStream = require('./cache_stream');
exports.camelCaseKeys = require('./camel_case_keys');
exports.Color = require('./color');
Expand Down
31 changes: 18 additions & 13 deletions lib/is_external_link.js
Expand Up @@ -2,6 +2,9 @@

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

const Cache = require('./cache');
const cache = new Cache();

/**
* Check whether the link is external
* @param {String} input The url to check
Expand All @@ -13,27 +16,29 @@ function isExternalLink(input, sitehost, exclude) {

if (!sitehost) return false;

// handle relative url
const data = new URL(input, `http://${sitehost}`);
return cache.apply(`${input}-${sitehost}-${exclude}`, () => {
// handle relative url
const data = new URL(input, `http://${sitehost}`);

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

const host = data.hostname;
const host = data.hostname;

if (exclude) {
exclude = Array.isArray(exclude) ? exclude : [exclude];
if (exclude) {
exclude = Array.isArray(exclude) ? exclude : [exclude];

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

if (host !== sitehost) return true;
if (host !== sitehost) return true;

return false;
return false;
});
}

module.exports = isExternalLink;
39 changes: 22 additions & 17 deletions lib/relative_url.js
Expand Up @@ -2,30 +2,35 @@

const encodeURL = require('./encode_url');

const Cache = require('./cache');
const cache = new Cache();

function relativeUrlHelper(from = '', to = '') {
const fromParts = from.split('/');
const toParts = to.split('/');
const length = Math.min(fromParts.length, toParts.length);
let i = 0;
return cache.apply(`${from}-${to}`, () => {
const fromParts = from.split('/');
const toParts = to.split('/');
const length = Math.min(fromParts.length, toParts.length);
let i = 0;

for (; i < length; i++) {
if (fromParts[i] !== toParts[i]) break;
}
for (; i < length; i++) {
if (fromParts[i] !== toParts[i]) break;
}

let out = toParts.slice(i);
let out = toParts.slice(i);

for (let j = fromParts.length - i - 1; j > 0; j--) {
out.unshift('..');
}
for (let j = fromParts.length - i - 1; j > 0; j--) {
out.unshift('..');
}

const outLength = out.length;
const outLength = out.length;

// If the last 2 elements of `out` is empty strings, replace them with `index.html`.
if (outLength > 1 && !out[outLength - 1] && !out[outLength - 2]) {
out = out.slice(0, outLength - 2).concat('index.html');
}
// If the last 2 elements of `out` is empty strings, replace them with `index.html`.
if (outLength > 1 && !out[outLength - 1] && !out[outLength - 2]) {
out = out.slice(0, outLength - 2).concat('index.html');
}

return encodeURL(out.join('/').replace(/\/{2,}/g, '/'));
return encodeURL(out.join('/').replace(/\/{2,}/g, '/'));
});
}

module.exports = relativeUrlHelper;
39 changes: 25 additions & 14 deletions lib/url_for.js
Expand Up @@ -5,17 +5,11 @@ const encodeURL = require('./encode_url');
const relative_url = require('./relative_url');
const prettyUrls = require('./pretty_urls');

function urlForHelper(path = '/', options) {
const pathRegex = /^(#|\/\/|http(s)?:)/;
if (pathRegex.test(path)) return path;
const Cache = require('./cache');
const cache = new Cache();

function urlForHelper(path = '/', options) {
const { config } = this;
const { root } = config;
const sitehost = parse(config.url).hostname || config.url;
const data = new URL(path, `http://${sitehost}`);

// Exit if input is an external link or a data url
if (data.hostname !== sitehost || data.origin === 'null') return path;

options = Object.assign({
relative: config.relative_link
Expand All @@ -26,17 +20,34 @@ function urlForHelper(path = '/', options) {
return relative_url(this.path, path);
}

// Prepend root path
path = encodeURL((root + path).replace(/\/{2,}/g, '/'));

const { root } = config;
const prettyUrlsOptions = Object.assign({
trailing_index: true,
trailing_html: true
}, config.pretty_urls);

path = prettyUrls(path, prettyUrlsOptions);
// cacheId is designed to works across different hexo.config & options
return cache.apply(`${config.url}-${root}-${prettyUrlsOptions.trailing_index}-${prettyUrlsOptions.trailing_html}-${path}`, () => {
const pathRegex = /^(#|\/\/|http(s)?:)/;
if (pathRegex.test(path)) {
return path;
}

const sitehost = parse(config.url).hostname || config.url;
const data = new URL(path, `http://${sitehost}`);

// Exit if input is an external link or a data url
if (data.hostname !== sitehost || data.origin === 'null') {
return path;
}

// Prepend root path
path = encodeURL((root + path).replace(/\/{2,}/g, '/'));

path = prettyUrls(path, prettyUrlsOptions);

return path;
return path;
});
}

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

require('chai').should();

describe('Cache', () => {
const Cache = require('../lib/cache');
const cache = new Cache();

it('get & set', () => {
cache.set('foo', 123);
cache.get('foo').should.eql(123);
});

it('has', () => {
cache.has('foo').should.eql(true);
cache.has('bar').should.eql(false);
});

it('apply - non function', () => {
cache.apply('bar', 123).should.eql(123);
cache.apply('bar', 456).should.eql(123);

cache.apply('foo', 456).should.eql(123);
});

it('apply - function', () => {
cache.apply('baz', () => 123).should.eql(123);
cache.apply('baz', () => 456).should.eql(123);
});

it('del', () => {
cache.del('baz');
cache.has('foo').should.eql(true);
cache.has('baz').should.eql(false);
});

it('flush', () => {
cache.flush();
cache.has('foo').should.eql(false);
cache.has('bar').should.eql(false);
cache.has('baz').should.eql(false);
});

it('cache null', () => {
cache.apply('foo', null);
(cache.apply('foo', 123) === null).should.eql(true);
});
});

0 comments on commit 141e153

Please sign in to comment.