Skip to content

Commit

Permalink
Close #61 PR: Convert to promise API. Fixes #56
Browse files Browse the repository at this point in the history
  • Loading branch information
callumlocke authored and sindresorhus committed Nov 5, 2015
1 parent f3a47bb commit 64e8825
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 122 deletions.
5 changes: 4 additions & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
"noarg": true,
"undef": true,
"unused": "vars",
"strict": true
"strict": true,
"predef": [
"-Promise"
]
}
27 changes: 8 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,23 @@ $ npm install --save psi
var psi = require('psi');

// get the PageSpeed Insights report
psi('html5rocks.com', function (err, data) {
psi('html5rocks.com').then(function (data) {
console.log(data.ruleGroups.SPEED.score);
console.log(data.pageStats);
});

// output a formatted report to the terminal
psi.output('html5rocks.com', function (err) {
psi.output('html5rocks.com').then(function () {
console.log('done');
});
```


## API

### psi(url, [options], callback)
### psi(url, [options])

Returns a promise for the response data from Google PageSpeed Insights.

#### url

Expand Down Expand Up @@ -76,26 +78,13 @@ Default: `70`

Threshold score to pass the PageSpeed test.

#### callback(error, data)

*Required*
Type: `function`

##### data

Type: `object`

The response from Google PageSpeed Insights.

### psi.output(url, [options], [callback])
### psi.output(url, [options])

Output the formatted report to the terminal.

`url` and `options` is the same as `psi()`.
Returns a promise for the response data from Google PageSpeed Insights.

#### callback(error)

Type: `function`
`url` and `options` is the same as `psi()`.


## CLI
Expand Down
18 changes: 8 additions & 10 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,13 @@ if (!cli.input[0]) {
process.exit(1);
}

psi.output(cli.input[0], cli.flags, function (err, res) {
if (err) {
if (err.noStack) {
console.error(err.message);
process.exit(1);
} else {
throw err;
}
}

psi.output(cli.input[0], cli.flags).then(function () {
process.exit(0);
}, function (err) {
if (err.noStack) {
console.error(err.message);
process.exit(1);
} else {
throw err;
}
});
47 changes: 15 additions & 32 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use strict';
var Promise = require('pinkie-promise');
var googleapis = require('googleapis');
var prependHttp = require('prepend-http');
var objectAssign = require('object-assign');
var pagespeed = googleapis.pagespeedonline('v2').pagespeedapi.runpagespeed;
var pify = require('pify');
var pagespeed = pify(googleapis.pagespeedonline('v2').pagespeedapi.runpagespeed, Promise);
var output = require('./lib/output');

function handleOpts(url, opts) {
Expand All @@ -12,45 +14,26 @@ function handleOpts(url, opts) {
return opts;
}

var psi = module.exports = function (url, opts, cb) {
if (typeof opts !== 'object') {
cb = opts;
var psi = module.exports = function (url, opts) {
return Promise.resolve().then(function () {
if (typeof opts !== 'object') {
opts = {};
}

if (!url) {
throw new Error('URL required');
}

if (typeof cb !== 'function') {
throw new Error('Callback required');
}

pagespeed(handleOpts(url, opts), function (err, response) {
if (err) {
err.noStack = true;
cb(err);
return;
}

cb(null, response);
if (!url) {
throw new Error('URL required');
}

return pagespeed(handleOpts(url, opts));
});
};

module.exports.output = function (url, opts, cb) {
module.exports.output = function (url, opts) {
if (typeof opts !== 'object') {
cb = opts;
opts = {};
opts = {};
}

cb = cb || function () {};

psi(url, opts, function (err, data) {
if (err) {
cb(err);
return;
}

output(handleOpts(url, opts), data, cb);
return psi(url, opts).then(function (data) {
return output(handleOpts(url, opts), data);
});
};
61 changes: 32 additions & 29 deletions lib/output.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
'use strict';
var Promise = require('pinkie-promise');
var prettyBytes = require('pretty-bytes');
var sortOn = require('sort-on');
var humanizeUrl = require('humanize-url');
var Download = require('download');
var querystring = require('querystring');
var writeFileSync = require('fs').writeFileSync;
var THRESHOLD = 70;
var RESOURCE_URL = 'https://developers.google.com/speed/pagespeed/insights/optimizeContents?';

Expand Down Expand Up @@ -60,32 +60,35 @@ function getReporter(format) {
return require('./formats/' + format);
}

module.exports = function (parameters, response, cb) {
var renderer = getReporter(parameters.format);
var threshold = parameters.threshold || THRESHOLD;
var optimizedResoruceURL = RESOURCE_URL + querystring.stringify({url: response.id, strategy: parameters.strategy})

console.log(renderer(
overview(humanizeUrl(response.id), parameters.strategy, response.ruleGroups.SPEED.score),
statistics(response.pageStats),
ruleSetResults(response.formattedResults.ruleResults),
threshold
));

if (parameters.optimized) {
console.log('\nHere are your optimized images: ', humanizeUrl(optimizedResoruceURL));
}

if (response.ruleGroups.SPEED.score < threshold) {
var err = new Error('Threshold of ' + threshold + ' not met with score of ' + response.ruleGroups.SPEED.score);
return cb(err);
}

if (parameters.download) {
new Download()
.get(optimizedResoruceURL)
.dest('.')
.rename('./optimized.zip')
.run(cb);
}
module.exports = function (parameters, response) {
return Promise.resolve().then(function () {
var renderer = getReporter(parameters.format);
var threshold = parameters.threshold || THRESHOLD;
var optimizedResoruceURL = RESOURCE_URL + querystring.stringify({url: response.id, strategy: parameters.strategy});

console.log(renderer(
overview(humanizeUrl(response.id), parameters.strategy, response.ruleGroups.SPEED.score),
statistics(response.pageStats),
ruleSetResults(response.formattedResults.ruleResults),
threshold
));

if (parameters.optimized) {
console.log('\nHere are your optimized images: ', humanizeUrl(optimizedResoruceURL));
}

if (response.ruleGroups.SPEED.score < threshold) {
var err = new Error('Threshold of ' + threshold + ' not met with score of ' + response.ruleGroups.SPEED.score);
throw err;
}

if (parameters.download) {
var download = new Download()
.get(optimizedResoruceURL)
.dest('.')
.rename('./optimized.zip');

return pify(download.run.bind(download), Promise)();
}
});
};
26 changes: 14 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,22 @@
"size"
],
"dependencies": {
"chalk": "^1.0.0",
"download": "^4.2.0",
"googleapis": "^2.0.3",
"humanize-url": "^1.0.0",
"lodash": "^3.2.0",
"meow": "^3.3.0",
"object-assign": "^2.0.0",
"prepend-http": "^1.0.0",
"pretty-bytes": "^1.0.1",
"repeating": "^1.1.1",
"sort-on": "^1.0.0",
"chalk": "^1.1.1",
"download": "^4.4.1",
"googleapis": "^2.1.6",
"humanize-url": "^1.0.1",
"lodash": "^3.10.1",
"meow": "^3.5.0",
"object-assign": "^4.0.1",
"pify": "^2.3.0",
"pinkie-promise": "^1.0.0",
"prepend-http": "^1.0.3",
"pretty-bytes": "^2.0.1",
"repeating": "^2.0.0",
"sort-on": "^1.2.2",
"update-notifier": "^0.5.0"
},
"devDependencies": {
"mocha": "^2.0.1"
"mocha": "^2.3.3"
}
}
38 changes: 19 additions & 19 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,44 +22,44 @@ describe('Formatting', function () {
});

it('should correctly format PageSpeed Insights response', function () {
output({strategy: 'desktop'}, response);
assert(/Score: 88/.test(chalk.stripColor(this.formattedOutput)));
return output({strategy: 'desktop'}, response).then(function () {
assert(/Score: 88/.test(chalk.stripColor(this.formattedOutput)));
}.bind(this));
});

it('should format PageSpeed Insights response as TAP output', function () {
output({strategy: 'desktop', format: 'tap'}, response);
assert(/ok 1 - psi/.test(chalk.stripColor(this.formattedOutput)));
return output({strategy: 'desktop', format: 'tap'}, response).then(function () {
assert(/ok 1 - psi/.test(chalk.stripColor(this.formattedOutput)));
}.bind(this));
});

it('should format PageSpeed Insights response as JSON output', function () {
output({strategy: 'desktop', format: 'json'}, response);
assert(/"Score": 88/.test(chalk.stripColor(this.formattedOutput)));
return output({strategy: 'desktop', format: 'json'}, response).then(function () {
assert(/"Score": 88/.test(chalk.stripColor(this.formattedOutput)));
}.bind(this));
});

it('should have an error in the callback if threshold is not met', function (done) {
output({threshold: 100}, response, function (err, result) {
assert.equal(err.name, 'Error', 'Expcted an error.');
done();
});
it('should have an error in the callback if threshold is not met', function () {
return output({threshold: 100}, response).catch(function (err) {
return err;
}).then(function (err) {
assert.equal(err.name, 'Error', 'Expected an error.');
});
});
});

describe('API', function () {
this.timeout(50000);

it('should get data from PageSpeed Insights', function (cb) {
psi('google.com', function (err, data) {
assert(!err, err);
it('should get data from PageSpeed Insights', function () {
return psi('google.com').then(function (data) {
assert.strictEqual(data.title, 'Google');
cb();
});
});

it('should support options', function (cb) {
psi('google.com', {locale: 'no'}, function (err, data) {
assert(!err, err);
it('should support options', function () {
return psi('google.com', {locale: 'no'}).then(function (data) {
assert.strictEqual(data.formattedResults.locale, 'no');
cb();
});
});
});

0 comments on commit 64e8825

Please sign in to comment.