Comparing version
183
index.js
@@ -1,124 +0,19 @@ | ||
const url = require('url') | ||
const got = require('got') | ||
const gzipSize = require('gzip-size') | ||
const prettyBytes = require('pretty-bytes') | ||
const color = require('./lib/color') | ||
const compression = require('./lib/compression') | ||
const constraints = require('./lib/constraints') | ||
const fetch = require('./lib/fetch') | ||
const init = require('./lib/init') | ||
const pretty = require('./lib/pretty') | ||
const send = require('./lib/send') | ||
/** URLs of services in use. */ | ||
const GITHUB_URL = 'https://raw.githubusercontent.com' | ||
const SHIELDS_URL = 'https://img.shields.io/badge' | ||
const bind = (fn, ...args) => fn.bind(fn, ...args) | ||
/** | ||
* Parse infos from request parameters and build a baton. | ||
* | ||
* @param {ServerRequest} req | ||
* @return {Promise} | ||
*/ | ||
function parse(req) { | ||
return new Promise((resolve, reject) => { | ||
const { pathname, query } = url.parse(req.url, true) | ||
let baton = { | ||
label: query.label || ((query.compression ? 'gzip ' : '') + 'size'), | ||
color: query.color || 'brightgreen', | ||
style: query.style || null, | ||
value: 'unknown', | ||
extension: 'svg', | ||
size: 0, | ||
compression: query.compression, | ||
compressedSize: 0, | ||
err: null | ||
} | ||
// empty path | ||
if ('/' === pathname) { | ||
baton.err = new Error('Empty path') | ||
return reject(baton) | ||
} | ||
// url or github path | ||
if (pathname.startsWith('/http')) { | ||
baton.url = pathname.substr(1) | ||
} | ||
else { | ||
baton.url = `${GITHUB_URL}${pathname}` | ||
} | ||
// image extension | ||
let index = pathname.lastIndexOf('.') | ||
if (-1 !== index) { | ||
baton.extension = pathname.substr(index + 1) | ||
if (-1 === 'svg|png|jpg'.indexOf(baton.extension)) { | ||
baton.extension = 'svg' | ||
} | ||
else { | ||
baton.url = `${GITHUB_URL}${pathname.substr(0, index)}` | ||
} | ||
} | ||
resolve(baton) | ||
}) | ||
const cond = (fn, param) => async (baton) => { | ||
if (baton[param] != null) { | ||
await fn(baton) | ||
} | ||
} | ||
/** | ||
* Fetch file to stat from Github. | ||
* | ||
* @param {object} baton | ||
* @return {Promise} | ||
*/ | ||
function fetch(baton) { | ||
return new Promise((resolve, reject) => { | ||
got[baton.compression ? 'get' : 'head'](baton.url, { | ||
headers: { | ||
'accept-encoding': 'identity' | ||
} | ||
}).then(res => { | ||
baton.size = Number(res.headers['content-length']) | ||
baton.data = res.body | ||
resolve(baton) | ||
}).catch(err => { | ||
baton.err = 'Unknown path' | ||
return reject(baton) | ||
}) | ||
}) | ||
} | ||
/** | ||
* Stat compressed size of the file if requested. | ||
* | ||
* @param {object} baton | ||
* @return {object|Promise} | ||
*/ | ||
function compressed(baton) { | ||
if (!baton.compression) return baton | ||
return new Promise((resolve, reject) => { | ||
baton.compressedSize = baton.size | ||
if ('gzip' === baton.compression) { | ||
gzipSize(baton.data, (err, size) => { | ||
/* istanbul ignore if */ | ||
if (err) { | ||
baton.err = err | ||
return reject(baton) | ||
} | ||
baton.compressedSize = size | ||
resolve(baton) | ||
}) | ||
} | ||
else { | ||
baton.err = 'Unknown compression' | ||
reject(baton) | ||
} | ||
}) | ||
} | ||
/** | ||
* Make file size pretty to read. | ||
* | ||
* @param {object} baton | ||
* @return {object} | ||
*/ | ||
function pretty(baton) { | ||
baton.value = prettyBytes(baton.compressedSize || baton.size) | ||
const tap = (fn) => async (baton) => { | ||
await fn(baton) | ||
return baton | ||
@@ -128,38 +23,2 @@ } | ||
/** | ||
* Redirect to shields.io to serve the badge image. | ||
* | ||
* @param {ServerResponse} res | ||
* @return {function} | ||
*/ | ||
function redirect(res) { | ||
return function(baton) { | ||
if (baton.err) { | ||
baton.value = ('string' === typeof baton.err ? | ||
baton.err : | ||
baton.err.message | ||
).toLowerCase() | ||
baton.color = 'lightgrey' | ||
} | ||
let pathname = encodeURI( | ||
`/${baton.label}-${baton.value}-${baton.color}.${baton.extension}` | ||
) | ||
let badgeUrl = `${SHIELDS_URL}${pathname}` | ||
if (baton.style) badgeUrl += `?style=${baton.style}` | ||
res.writeHead(303, { | ||
'location': badgeUrl, | ||
// align on github raw cdn which caches content for 5 minutes | ||
'cache-control': 'max-age=300', | ||
// set expires to avoid github caching | ||
// https://github.com/github/markup/issues/224#issuecomment-48532178 | ||
'expires': new Date(Date.now() + 300 * 1000).toUTCString() | ||
}) | ||
res.end() | ||
} | ||
} | ||
/* -------------------------------------------------------------------------- */ | ||
/** | ||
* Handle a badge request. | ||
@@ -173,8 +32,10 @@ * It redirects to a shields.io badge of type: `size-{size}-brightgreen`. | ||
module.exports = function badgeSize(req, res) { | ||
return parse(req) | ||
.then(fetch) | ||
.then(compressed) | ||
.then(pretty) | ||
.then(redirect(res)) | ||
.catch(redirect(res)) | ||
return init(req) | ||
.then(tap(fetch)) | ||
.then(tap(cond(compression, 'compression'))) | ||
.then(tap(pretty)) | ||
.then(tap(cond(constraints, 'max'))) | ||
.then(tap(color)) | ||
.then(bind(send, res)) | ||
.catch(bind(send, res)) | ||
} |
{ | ||
"name": "badge-size", | ||
"version": "0.4.1", | ||
"version": "1.0.0", | ||
"description": "Displays the size of a given file in your repository", | ||
@@ -10,6 +10,7 @@ "author": "Nicolas Gryman <ngryman@gmail.com> (http://ngryman.sh)", | ||
"engines": { | ||
"node": ">=6" | ||
"node": "^8.10.0 || >=9.10.0" | ||
}, | ||
"files": [ | ||
"index.js" | ||
"index.js", | ||
"lib" | ||
], | ||
@@ -19,3 +20,3 @@ "scripts": { | ||
"unit": "nyc ava", | ||
"start": "micro index.js -p ${PORT:=3000}", | ||
"start": "micro index.js --listen tcp://0.0.0.0:${PORT-3000}", | ||
"test": "npm run lint -s && npm run unit -s", | ||
@@ -25,2 +26,3 @@ "dev": "npm run unit -- --watch", | ||
"check-coverage": "nyc check-coverage --lines 95 --functions 95 --branches 95", | ||
"see-coverage": "nyc report --reporter=html && open coverage/index.html", | ||
"contributors": "contributor-faces --exclude '*-bot'" | ||
@@ -47,14 +49,15 @@ }, | ||
"dependencies": { | ||
"got": "^6.5.0", | ||
"gzip-size": "^3.0.0", | ||
"micro": "^6.0.2", | ||
"pretty-bytes": "^4.0.2" | ||
"brotli-size": "^0.0.3", | ||
"got": "^9.0.0", | ||
"gzip-size": "^5.0.0", | ||
"micro": "^9.3.2", | ||
"pretty-bytes": "^5.1.0" | ||
}, | ||
"devDependencies": { | ||
"ava": "^0.16.0", | ||
"ava": "^0.25.0", | ||
"codecov.io": "^0.1.6", | ||
"contributor-faces": "^0.3.0", | ||
"eslint": "^3.7.0", | ||
"contributor-faces": "^1.0.0", | ||
"eslint": "^5.3.0", | ||
"eslint-config-ngryman": "^1.7.0", | ||
"nyc": "^8.3.0", | ||
"nyc": "^12.0.2", | ||
"pre-commit": "^1.1.3", | ||
@@ -61,0 +64,0 @@ "test-listen": "^1.0.0" |
@@ -24,2 +24,3 @@ # badge-size [![npm][npm-image]][npm-url] [![travis][travis-image]][travis-url] | ||
Gzipped size |  | ||
Brotli size |  | ||
Custom label |  | ||
@@ -36,3 +37,3 @@ PNG format |  | ||
``` | ||
http://img.badgesize.io/:filepath[.svg|png|jpg][?compression=gzip][&label=string] | ||
http://img.badgesize.io/:filepath[.svg|png|jpg][?compression=gzip|brotli][&label=string][&max=string][&softmax=string] | ||
``` | ||
@@ -42,3 +43,5 @@ | ||
It's the url of your file on `github` when you browse it in the source explorer, minus `blob/` part. | ||
Relative URL of file on GitHub of any absolute URL if hosted elsewhere. | ||
The format of the GitHub URL is the same as when you browse it in the source explorer, minus `blob/` part. | ||
Here is its typical form: | ||
@@ -60,10 +63,10 @@ | ||
#### `[?compression=gzip]` | ||
#### `[?compression=gzip|brotli]` | ||
Optional compression format to measure. It's useful if you want to advertise the *true* size your | ||
file would take on the wire, assuming the server has `gzip` compression enabled. | ||
file would take on the wire, assuming the server has `gzip` or `brotli` compression enabled. | ||
#### `[&label=string]` | ||
Optional text to display in the badge instead of *size* / *gzip size*. | ||
Optional text to display in the badge instead of *size* / *gzip size* / *brotli size*. | ||
@@ -95,10 +98,31 @@ #### `[&color=string]` | ||
#### `[&max=string] [&softmax=string]` | ||
Optional size limits in bytes.<br> | ||
Max is a hard limit. Exceeding this will generate a red badge. <br> | ||
If softlimit is provided (in addition to max) and the file size falls within the range of max and softmax, a yellow badge will be generated.<br> | ||
This setting will override the color option in the above two scenarios. | ||
``` | ||
http://img.badgesize.io/:filepath?max=100000&softmax=200000 | ||
``` | ||
 | ||
 | ||
 | ||
## Contributors | ||
[//]: contributor-faces | ||
<a href="https://github.com/ngryman"><img src="https://avatars.githubusercontent.com/u/892048?v=3" title="ngryman" width="80" height="80"></a> | ||
<a href="https://github.com/bfred-it"><img src="https://avatars.githubusercontent.com/u/1402241?v=3" title="bfred-it" width="80" height="80"></a> | ||
<a href="https://github.com/nathancahill"><img src="https://avatars.githubusercontent.com/u/1383872?v=3" title="nathancahill" width="80" height="80"></a> | ||
<a href="https://github.com/coopy"><img src="https://avatars.githubusercontent.com/u/794843?v=3" title="coopy" width="80" height="80"></a> | ||
<a href="https://github.com/ngryman"><img src="https://avatars2.githubusercontent.com/u/892048?v=4" title="ngryman" width="80" height="80"></a> | ||
<a href="https://github.com/bfred-it"><img src="https://avatars3.githubusercontent.com/u/1402241?v=4" title="bfred-it" width="80" height="80"></a> | ||
<a href="https://github.com/nathancahill"><img src="https://avatars0.githubusercontent.com/u/1383872?v=4" title="nathancahill" width="80" height="80"></a> | ||
<a href="https://github.com/apps/greenkeeper"><img src="https://avatars3.githubusercontent.com/in/505?v=4" title="greenkeeper[bot]" width="80" height="80"></a> | ||
<a href="https://github.com/FezVrasta"><img src="https://avatars2.githubusercontent.com/u/5382443?v=4" title="FezVrasta" width="80" height="80"></a> | ||
<a href="https://github.com/OliverJAsh"><img src="https://avatars2.githubusercontent.com/u/921609?v=4" title="OliverJAsh" width="80" height="80"></a> | ||
<a href="https://github.com/coopy"><img src="https://avatars2.githubusercontent.com/u/794843?v=4" title="coopy" width="80" height="80"></a> | ||
<a href="https://github.com/hairmot"><img src="https://avatars2.githubusercontent.com/u/8102124?v=4" title="hairmot" width="80" height="80"></a> | ||
[//]: contributor-faces | ||
@@ -105,0 +129,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
12803
30.83%10
233.33%218
36.25%1
-50%131
22.43%5
25%2
100%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated