Skip to content

Commit e63c4d9

Browse files
committed
Refactor to ES module
- bundling with rollup - updating `package.json` - updating tests - setup linter - updating ci config
1 parent 844a442 commit e63c4d9

11 files changed

Lines changed: 254 additions & 126 deletions

File tree

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lib

.eslintrc.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
extends: 'semistandard',
3+
rules: {
4+
'prefer-const': 'error',
5+
'space-before-function-paren': ['error', {
6+
anonymous: 'always',
7+
named: 'never'
8+
}]
9+
}
10+
};

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
node_modules
2+
lib
23
.tmp_*~
34
*#
45
.#*

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
language: node_js
2+
3+
script:
4+
- yarn run lint
5+
- yarn test
6+
27
node_js:
38
- 8
9+
- 10
410
- node
511
- lts/*

index.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

lib/gravatar.js

Lines changed: 0 additions & 63 deletions
This file was deleted.

package.json

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,22 @@
33
"description": "Gravatar Node.js library",
44
"keywords": [
55
"gravatar",
6-
"avatar",
7-
"package.json"
6+
"avatar"
87
],
98
"version": "1.8.0",
109
"author": "Emerson Macedo <emerleite@gmail.com>",
1110
"repository": {
1211
"type": "git",
1312
"url": "git://github.com/emerleite/node-gravatar.git"
1413
},
14+
"files": [
15+
"lib"
16+
],
1517
"dependencies": {
16-
"blueimp-md5": "^2.3.0",
18+
"normalize-url": "^4.3.0",
19+
"yargs": "^13.2.4"
20+
},
21+
"devDependencies": {
1722
"email-validator": "^2.0.4",
1823
"eslint": "^5.16.0",
1924
"eslint-config-semistandard": "^13.0.0",
@@ -22,19 +27,20 @@
2227
"eslint-plugin-node": "^9.1.0",
2328
"eslint-plugin-promise": "^4.1.1",
2429
"eslint-plugin-standard": "^4.0.0",
25-
"path": "^0.12.7",
26-
"querystring": "0.2.0",
27-
"yargs": "^13.2.4"
28-
},
29-
"devDependencies": {
3030
"mocha": "6.1.4",
3131
"nixt": "^0.5.1",
32+
"rollup": "^1.15.2",
33+
"rollup-plugin-commonjs": "^10.0.0",
34+
"rollup-plugin-node-resolve": "^5.0.1",
3235
"should": "13.2.3"
3336
},
34-
"main": "index.js",
37+
"main": "lib/gravatar.js",
38+
"module": "lib/gravatar.esm.js",
3539
"scripts": {
3640
"lint": "eslint .",
37-
"test": "node_modules/mocha/bin/mocha -R spec"
41+
"build": "rollup -c rollup.config.js",
42+
"pretest": "yarn run build",
43+
"test": "mocha -R spec"
3844
},
3945
"license": "MIT",
4046
"engines": {

rollup.config.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import commonJs from 'rollup-plugin-commonjs';
2+
import path from 'path';
3+
import resolve from 'rollup-plugin-node-resolve';
4+
5+
/** @type import('rollup').RollupOptions */
6+
const baseConfig = {
7+
input: 'src/gravatar.js',
8+
plugins: [
9+
resolve({ preferBuiltins: true }),
10+
commonJs()
11+
]
12+
};
13+
14+
/** @type Array<import('rollup').RollupOptions> */
15+
const config = [{
16+
...baseConfig,
17+
output: {
18+
format: 'esm',
19+
file: path.join(__dirname, 'lib/gravatar.esm.js')
20+
}
21+
}, {
22+
...baseConfig,
23+
output: {
24+
format: 'cjs',
25+
file: path.join(__dirname, 'lib/gravatar.js')
26+
}
27+
}];
28+
29+
export default config;

src/gravatar.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import crypto from 'crypto';
2+
import { deprecate } from 'util';
3+
import normalizeUrl from 'normalize-url';
4+
import { URLSearchParams } from 'url';
5+
6+
const isBoolean = arg => typeof arg === 'boolean';
7+
const isString = arg => typeof arg === 'string';
8+
const isUndefined = arg => typeof arg === 'undefined';
9+
const md5 = val => crypto.createHash('md5').update(val, 'utf8').digest('hex');
10+
11+
const BASE_URL = '//gravatar.com';
12+
const RE_MD5 = /^[0-9a-f]{32}$/;
13+
14+
function proto({ protocol } = {}) {
15+
if (isBoolean(protocol)) return protocol;
16+
if (protocol === 'https') return true;
17+
if (protocol === 'http') return false;
18+
}
19+
20+
function getHash(email) {
21+
email = isString(email) ? email.trim().toLowerCase() : 'unspecified';
22+
if (RE_MD5.test(email)) return email;
23+
return md5(email);
24+
}
25+
26+
function getQuery({ format, protocol, cdn, ...options } = {}) {
27+
const entries = Object.entries(options);
28+
if (!entries.length) return '';
29+
const searchParams = new URLSearchParams(entries);
30+
return `?${searchParams}`;
31+
}
32+
function url(email, { cdn, ...options } = {}, protocol = proto(options)) {
33+
let url;
34+
if (cdn) {
35+
url = `${cdn}/avatar`;
36+
} else {
37+
url = `${BASE_URL}/avatar`;
38+
if (!isUndefined(protocol)) {
39+
url = normalizeUrl(url, { forceHttps: protocol });
40+
}
41+
}
42+
const hash = getHash(email);
43+
const query = getQuery(options);
44+
return `${url}/${hash}${query}`;
45+
}
46+
47+
function profileUrl(email, { cdn, format = 'json', ...options } = {}, protocol = proto(options)) {
48+
let url = '';
49+
if (cdn) {
50+
url = `${cdn}`;
51+
} else {
52+
url = BASE_URL;
53+
const defaultProtocol = protocol ? 'https:' : 'http:';
54+
url = normalizeUrl(url, { defaultProtocol });
55+
}
56+
const hash = getHash(email);
57+
const query = getQuery(options);
58+
return `${url}/${hash}.${format}${query}`;
59+
}
60+
61+
export default {
62+
url,
63+
profileUrl,
64+
profile_url: deprecate(profileUrl, 'profile_url() is deprecated. Use profileUrl() instead.')
65+
};

test/gravatar.test.js

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
/* eslint-disable */
2-
const should = require('should');
3-
const url = require('url');
1+
'use strict';
2+
3+
/* eslint-env mocha */
4+
5+
require('should');
6+
const { URL } = require('url');
7+
const gravatar = require('..');
48
const nixt = require('nixt');
5-
const gravatar = require('../lib/gravatar');
9+
const normalizeUrl = require('normalize-url');
10+
11+
const parseUrl = url => new URL(normalizeUrl(url));
612

713
describe('gravatar', function () {
8-
const baseNoProtocolURL = '//www.gravatar.com/avatar/';
9-
const baseUnsecureURL = 'http://www.gravatar.com/avatar/';
10-
const baseSecureURL = 'https://s.gravatar.com/avatar/';
11-
const profileURL = 'http://www.gravatar.com/';
12-
const profileSecureURL = 'https://secure.gravatar.com/';
14+
const baseNoProtocolURL = '//gravatar.com/avatar/';
15+
const baseUnsecureURL = 'http://gravatar.com/avatar/';
16+
const baseSecureURL = 'https://gravatar.com/avatar/';
17+
const profileURL = 'http://gravatar.com/';
18+
const profileSecureURL = 'https://gravatar.com/';
1319
const unspecifiedHash = 'd415f0e30c471dfdd9bc4f827329ef48';
1420

1521
it('should gererate correct uri given an email', function () {
@@ -30,11 +36,11 @@ describe('gravatar', function () {
3036

3137
it('should generate uri with user passed parameters', function () {
3238
const gravatarURL = gravatar.url('emerleite@gmail.com', { s: '200', f: 'y', r: 'g', d: '404' });
33-
const queryString = url.parse(gravatarURL, true).query;
34-
queryString.s.should.equal('200');
35-
queryString.f.should.equal('y');
36-
queryString.r.should.equal('g');
37-
queryString.d.should.equal('404');
39+
const { searchParams } = parseUrl(gravatarURL);
40+
searchParams.get('s').should.equal('200');
41+
searchParams.get('f').should.equal('y');
42+
searchParams.get('r').should.equal('g');
43+
searchParams.get('d').should.equal('404');
3844
});
3945

4046
it('should force http protocol on gravatar uri generation', function () {
@@ -48,9 +54,11 @@ describe('gravatar', function () {
4854
});
4955

5056
it('should handle falsey values for the email property', function () {
57+
/* eslint-disable no-unused-expressions */
5158
gravatar.url(null).should.be.ok;
5259
gravatar.url(undefined).should.be.ok;
5360
gravatar.url('').should.be.ok;
61+
/* eslint-enable */
5462
});
5563

5664
it('should handle non string values for the email property', function () {
@@ -82,11 +90,11 @@ describe('gravatar', function () {
8290

8391
it('should generate uri with user passed parameters and protocol in options', function () {
8492
const gravatarURL = gravatar.url('emerleite@gmail.com', { protocol: 'https', s: '200', f: 'y', r: 'g', d: '404' });
85-
const queryString = url.parse(gravatarURL, true).query;
86-
queryString.s.should.equal('200');
87-
queryString.f.should.equal('y');
88-
queryString.r.should.equal('g');
89-
queryString.d.should.equal('404');
93+
const { searchParams } = parseUrl(gravatarURL);
94+
searchParams.get('s').should.equal('200');
95+
searchParams.get('f').should.equal('y');
96+
searchParams.get('r').should.equal('g');
97+
searchParams.get('d').should.equal('404');
9098
});
9199

92100
it('should generate profile url with protocol in options', function () {
@@ -112,7 +120,7 @@ describe('CLI', function () {
112120
it('accepts an email argument with options and writes gravatar URL to STDOUT', function (done) {
113121
nixt()
114122
.run('./cli.js zeke@sikelianos.com -p https -s 500 -d retro')
115-
.stdout('Gravatar (avatar):\nhttps://s.gravatar.com/avatar/8f344b1c4bdcfc28bd848e97e94c3523?default=retro&size=500')
123+
.stdout('Gravatar (avatar):\nhttps://gravatar.com/avatar/8f344b1c4bdcfc28bd848e97e94c3523?default=retro&size=500')
116124
.end(done);
117125
});
118126
it('outputs usage if -h arg is present', function (done) {
@@ -127,7 +135,7 @@ describe('CLI', function () {
127135
it('accepts an email argument with options and writes gravatar URL to STDOUT', function (done) {
128136
nixt()
129137
.run('./cli.js avatar zeke@sikelianos.com -p https -s 500 -d retro')
130-
.stdout('Gravatar (avatar):\nhttps://s.gravatar.com/avatar/8f344b1c4bdcfc28bd848e97e94c3523?default=retro&size=500')
138+
.stdout('Gravatar (avatar):\nhttps://gravatar.com/avatar/8f344b1c4bdcfc28bd848e97e94c3523?default=retro&size=500')
131139
.end(done);
132140
});
133141
});
@@ -136,7 +144,7 @@ describe('CLI', function () {
136144
it('accepts an email argument with options and writes gravatar profile URL to STDOUT', function (done) {
137145
nixt()
138146
.run('./cli.js profile zeke@sikelianos.com -p https -c doSomething')
139-
.stdout('Gravatar (profile):\nhttps://secure.gravatar.com/8f344b1c4bdcfc28bd848e97e94c3523.json?callback=doSomething')
147+
.stdout('Gravatar (profile):\nhttps://gravatar.com/8f344b1c4bdcfc28bd848e97e94c3523.json?callback=doSomething')
140148
.end(done);
141149
});
142150
});

0 commit comments

Comments
 (0)