Comparing version 0.6.2 to 1.0.0-beta.1
694
index.js
@@ -1,92 +0,632 @@ | ||
var matcher = require('./matcher'); | ||
var formatter = require('./formatter'); | ||
/*! | ||
* router | ||
* Copyright(c) 2013 Roman Shtylman | ||
* Copyright(c) 2014 Douglas Christopher Wilson | ||
* MIT Licensed | ||
*/ | ||
var METHODS = ['get', 'post', 'put', 'del' , 'delete', 'head', 'options']; | ||
var HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'DELETE', 'HEAD', 'OPTIONS']; | ||
/** | ||
* Module dependencies. | ||
* @private | ||
*/ | ||
var noop = function() {}; | ||
var error = function(res) { | ||
return function() { | ||
res.statusCode = 404; | ||
res.end(); | ||
}; | ||
}; | ||
var router = function() { | ||
var methods = {}; | ||
var traps = {}; | ||
var debug = require('debug')('router') | ||
var Layer = require('./lib/layer') | ||
var methods = require('methods') | ||
var mixin = require('utils-merge') | ||
var parseUrl = require('parseurl') | ||
var Route = require('./lib/route') | ||
var utils = require('./lib/utils') | ||
HTTP_METHODS.forEach(function(method) { | ||
methods[method] = []; | ||
}); | ||
/** | ||
* Module variables. | ||
* @private | ||
*/ | ||
var route = function(req, res, next) { | ||
var method = methods[req.method]; | ||
var trap = traps[req.method]; | ||
var index = req.url.indexOf('?'); | ||
var url = index === -1 ? req.url : req.url.substr(0, index); | ||
var i = 0; | ||
var slice = Array.prototype.slice | ||
next = next || error(res); | ||
if (!method) return next(); | ||
/* istanbul ignore next */ | ||
var defer = typeof setImmediate === 'function' | ||
? setImmediate | ||
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) } | ||
var loop = function(err) { | ||
if (err) return next(err); | ||
while (i < method.length) { | ||
var route = method[i]; | ||
/** | ||
* Expose `Router`. | ||
*/ | ||
i++; | ||
req.params = route.pattern(url); | ||
if (!req.params) continue; | ||
if (route.rewrite) { | ||
req.url = url = route.rewrite(req.params)+(index === -1 ? '' : req.url.substr(index)); | ||
} | ||
route.fn(req, res, loop); | ||
return; | ||
} | ||
if (!trap) return next(); | ||
trap(req, res, next); | ||
}; | ||
module.exports = Router | ||
loop(); | ||
}; | ||
/** | ||
* Expose `Route`. | ||
*/ | ||
METHODS.forEach(function(method, i) { | ||
route[method] = function(pattern, rewrite, fn) { | ||
if (Array.isArray(pattern)) { | ||
pattern.forEach(function(item) { | ||
route[method](item, rewrite, fn); | ||
}); | ||
return; | ||
} | ||
module.exports.Route = Route | ||
if (!fn && !rewrite) return route[method](null, null, pattern); | ||
if (!fn && typeof rewrite === 'string') return route[method](pattern, rewrite, route); | ||
if (!fn && typeof rewrite === 'function') return route[method](pattern, null, rewrite); | ||
if (!fn) return route; | ||
/** | ||
* Initialize a new `Router` with the given `options`. | ||
* | ||
* @param {object} options | ||
* @return {Router} which is an callable function | ||
* @public | ||
*/ | ||
(route.onmount || noop)(pattern, rewrite, fn); | ||
function Router(options) { | ||
if (!(this instanceof Router)) { | ||
return new Router(options) | ||
} | ||
if (!pattern) { | ||
traps[HTTP_METHODS[i]] = fn; | ||
return route; | ||
} | ||
var opts = options || {} | ||
methods[HTTP_METHODS[i]].push({ | ||
pattern:matcher(pattern), | ||
rewrite:formatter(rewrite), | ||
fn:fn | ||
}); | ||
return route; | ||
}; | ||
}); | ||
route.all = function(pattern, rewrite, fn) { | ||
METHODS.forEach(function(method) { | ||
route[method](pattern, rewrite, fn); | ||
}); | ||
return route; | ||
}; | ||
function router(req, res, next) { | ||
router.handle(req, res, next) | ||
} | ||
return route; | ||
}; | ||
// inherit from the correct prototype | ||
router.__proto__ = this | ||
module.exports = router; | ||
router.caseSensitive = opts.caseSensitive | ||
router.mergeParams = opts.mergeParams | ||
router.params = {} | ||
router.strict = opts.strict | ||
router.stack = [] | ||
return router | ||
} | ||
/** | ||
* Router prototype inherits from a Function. | ||
*/ | ||
/* istanbul ignore next */ | ||
Router.prototype = function () {} | ||
/** | ||
* Map the given param placeholder `name`(s) to the given callback. | ||
* | ||
* Parameter mapping is used to provide pre-conditions to routes | ||
* which use normalized placeholders. For example a _:user_id_ parameter | ||
* could automatically load a user's information from the database without | ||
* any additional code. | ||
* | ||
* The callback uses the same signature as middleware, the only difference | ||
* being that the value of the placeholder is passed, in this case the _id_ | ||
* of the user. Once the `next()` function is invoked, just like middleware | ||
* it will continue on to execute the route, or subsequent parameter functions. | ||
* | ||
* Just like in middleware, you must either respond to the request or call next | ||
* to avoid stalling the request. | ||
* | ||
* router.param('user_id', function(req, res, next, id){ | ||
* User.find(id, function(err, user){ | ||
* if (err) { | ||
* return next(err) | ||
* } else if (!user) { | ||
* return next(new Error('failed to load user')) | ||
* } | ||
* req.user = user | ||
* next() | ||
* }) | ||
* }) | ||
* | ||
* @param {string} name | ||
* @param {function} fn | ||
* @public | ||
*/ | ||
Router.prototype.param = function param(name, fn) { | ||
if (!name) { | ||
throw new TypeError('argument name is required') | ||
} | ||
if (typeof name !== 'string') { | ||
throw new TypeError('argument name must be a string') | ||
} | ||
if (!fn) { | ||
throw new TypeError('argument fn is required') | ||
} | ||
if (typeof fn !== 'function') { | ||
throw new TypeError('argument fn must be a function') | ||
} | ||
if (name[0] === ':') { | ||
name = name.substr(1) | ||
} | ||
var params = this.params[name] | ||
if (!params) { | ||
params = this.params[name] = [] | ||
} | ||
params.push(fn) | ||
return this | ||
} | ||
/** | ||
* Dispatch a req, res into the router. | ||
* | ||
* @private | ||
*/ | ||
Router.prototype.handle = function handle(req, res, callback) { | ||
if (!callback) { | ||
throw new TypeError('argument callback is required') | ||
} | ||
debug('dispatching %s %s', req.method, req.url) | ||
var search = 1 + req.url.indexOf('?') | ||
var pathlength = search ? search - 1 : req.url.length | ||
var fqdn = req.url[0] !== '/' && 1 + req.url.substr(0, pathlength).indexOf('://') | ||
var protohost = fqdn ? req.url.substr(0, req.url.indexOf('/', 2 + fqdn)) : '' | ||
var idx = 0 | ||
var removed = '' | ||
var self = this | ||
var slashAdded = false | ||
var paramcalled = {} | ||
// store options for OPTIONS request | ||
// only used if OPTIONS request | ||
var options = [] | ||
// middleware and routes | ||
var stack = this.stack | ||
// manage inter-router variables | ||
var parentParams = req.params | ||
var parentUrl = req.baseUrl || '' | ||
var done = restore(callback, req, 'baseUrl', 'next', 'params') | ||
// setup next layer | ||
req.next = next | ||
// for options requests, respond with a default if nothing else responds | ||
if (req.method === 'OPTIONS') { | ||
done = wrap(done, function onDone(old, err) { | ||
if (err || options.length === 0) { | ||
return old(err) | ||
} | ||
var methods = options.sort().join(', ') | ||
res.setHeader('Allow', methods) | ||
res.setHeader('Content-Length', Buffer.byteLength(methods)) | ||
res.setHeader('Content-Type', 'text/plain') | ||
res.setHeader('X-Content-Type-Options', 'nosniff') | ||
res.end(methods) | ||
}) | ||
} | ||
// setup basic req values | ||
req.baseUrl = parentUrl | ||
req.originalUrl = req.originalUrl || req.url | ||
next() | ||
function next(err) { | ||
var layerError = err === 'route' | ||
? null | ||
: err | ||
var layer = stack[idx++] | ||
if (slashAdded) { | ||
req.url = req.url.substr(1) | ||
slashAdded = false | ||
} | ||
if (removed.length !== 0) { | ||
req.baseUrl = parentUrl | ||
req.url = protohost + removed + req.url.substr(protohost.length) | ||
removed = '' | ||
} | ||
if (!layer) { | ||
defer(done, layerError) | ||
return | ||
} | ||
self.match_layer(layer, req, res, function (err, path) { | ||
if (err || path === undefined) { | ||
next(layerError || err) | ||
return | ||
} | ||
// route object and not middleware | ||
var route = layer.route | ||
// if final route, then we support options | ||
if (route) { | ||
// we don't run any routes with error first | ||
if (layerError) { | ||
next(layerError) | ||
return | ||
} | ||
var method = req.method | ||
var has_method = route._handles_method(method) | ||
// build up automatic options response | ||
if (!has_method && method === 'OPTIONS') { | ||
options.push.apply(options, route._options()) | ||
} | ||
// don't even bother | ||
if (!has_method && method !== 'HEAD') { | ||
next() | ||
return | ||
} | ||
// we can now dispatch to the route | ||
req.route = route | ||
} | ||
// Capture one-time layer values | ||
req.params = self.mergeParams | ||
? mergeParams(layer.params, parentParams) | ||
: layer.params | ||
var layerPath = layer.path | ||
// this should be done for the layer | ||
self.process_params(layer, paramcalled, req, res, function (err) { | ||
if (err) { | ||
next(layerError || err) | ||
return | ||
} | ||
if (route) { | ||
return layer.handle_request(req, res, next) | ||
} | ||
trim_prefix(layer, layerError, layerPath, path) | ||
}) | ||
}) | ||
} | ||
function trim_prefix(layer, layerError, layerPath, path) { | ||
var c = path[layerPath.length] | ||
if (c && '/' !== c && '.' !== c) { | ||
next(layerError) | ||
return | ||
} | ||
// Trim off the part of the url that matches the route | ||
// middleware (.use stuff) needs to have the path stripped | ||
if (layerPath.length !== 0) { | ||
debug('trim prefix (%s) from url %s', layerPath, req.url) | ||
removed = layerPath | ||
req.url = protohost + req.url.substr(protohost.length + removed.length) | ||
// Ensure leading slash | ||
if (!fqdn && req.url[0] !== '/') { | ||
req.url = '/' + req.url | ||
slashAdded = true | ||
} | ||
// Setup base URL (no trailing slash) | ||
req.baseUrl = parentUrl + (removed[removed.length - 1] === '/' | ||
? removed.substring(0, removed.length - 1) | ||
: removed) | ||
} | ||
debug('%s %s : %s', layer.name, layerPath, req.originalUrl) | ||
if (layerError) { | ||
layer.handle_error(layerError, req, res, next) | ||
} else { | ||
layer.handle_request(req, res, next) | ||
} | ||
} | ||
} | ||
/** | ||
* Match request to a layer. | ||
* | ||
* @private | ||
*/ | ||
Router.prototype.match_layer = function match_layer(layer, req, res, done) { | ||
var error = null | ||
var path | ||
try { | ||
path = parseUrl(req).pathname | ||
if (!layer.match(path)) { | ||
path = undefined | ||
} | ||
} catch (err) { | ||
error = err | ||
} | ||
done(error, path) | ||
} | ||
/** | ||
* Process any parameters for the layer. | ||
* | ||
* @private | ||
*/ | ||
Router.prototype.process_params = function process_params(layer, called, req, res, done) { | ||
var params = this.params | ||
// captured parameters from the layer, keys and values | ||
var keys = layer.keys | ||
// fast track | ||
if (!keys || keys.length === 0) { | ||
return done() | ||
} | ||
var i = 0 | ||
var name | ||
var paramIndex = 0 | ||
var key | ||
var paramVal | ||
var paramCallbacks | ||
var paramCalled | ||
// process params in order | ||
// param callbacks can be async | ||
function param(err) { | ||
if (err) { | ||
return done(err) | ||
} | ||
if (i >= keys.length ) { | ||
return done() | ||
} | ||
paramIndex = 0 | ||
key = keys[i++] | ||
if (!key) { | ||
return done() | ||
} | ||
name = key.name | ||
paramVal = req.params[name] | ||
paramCallbacks = params[name] | ||
paramCalled = called[name] | ||
if (paramVal === undefined || !paramCallbacks) { | ||
return param() | ||
} | ||
// param previously called with same value or error occurred | ||
if (paramCalled && (paramCalled.error || paramCalled.match === paramVal)) { | ||
// restore value | ||
req.params[name] = paramCalled.value | ||
// next param | ||
return param(paramCalled.error) | ||
} | ||
called[name] = paramCalled = { | ||
error: null, | ||
match: paramVal, | ||
value: paramVal | ||
} | ||
paramCallback() | ||
} | ||
// single param callbacks | ||
function paramCallback(err) { | ||
var fn = paramCallbacks[paramIndex++] | ||
// store updated value | ||
paramCalled.value = req.params[key.name] | ||
if (err) { | ||
// store error | ||
paramCalled.error = err | ||
param(err) | ||
return | ||
} | ||
if (!fn) return param() | ||
try { | ||
fn(req, res, paramCallback, paramVal, key.name) | ||
} catch (e) { | ||
paramCallback(e) | ||
} | ||
} | ||
param() | ||
} | ||
/** | ||
* Use the given middleware function, with optional path, defaulting to "/". | ||
* | ||
* Use (like `.all`) will run for any http METHOD, but it will not add | ||
* handlers for those methods so OPTIONS requests will not consider `.use` | ||
* functions even if they could respond. | ||
* | ||
* The other difference is that _route_ path is stripped and not visible | ||
* to the handler function. The main effect of this feature is that mounted | ||
* handlers can operate without any code changes regardless of the "prefix" | ||
* pathname. | ||
* | ||
* @public | ||
*/ | ||
Router.prototype.use = function use(handler) { | ||
var offset = 0 | ||
var path = '/' | ||
// default path to '/' | ||
// disambiguate router.use([handler]) | ||
if (typeof handler !== 'function') { | ||
var arg = handler | ||
while (Array.isArray(arg) && arg.length !== 0) { | ||
arg = arg[0] | ||
} | ||
// first arg is the path | ||
if (typeof arg !== 'function') { | ||
offset = 1 | ||
path = handler | ||
} | ||
} | ||
var callbacks = utils.flatten(slice.call(arguments, offset)) | ||
if (callbacks.length === 0) { | ||
throw new TypeError('argument handler is required') | ||
} | ||
callbacks.forEach(function (fn) { | ||
if (typeof fn !== 'function') { | ||
throw new TypeError('argument handler must be a function') | ||
} | ||
// add the middleware | ||
debug('use %s %s', path, fn.name || '<anonymous>') | ||
var layer = new Layer(path, { | ||
sensitive: this.caseSensitive, | ||
strict: false, | ||
end: false | ||
}, fn) | ||
layer.route = undefined | ||
this.stack.push(layer) | ||
}, this) | ||
return this | ||
} | ||
/** | ||
* Create a new Route for the given path. | ||
* | ||
* Each route contains a separate middleware stack and VERB handlers. | ||
* | ||
* See the Route api documentation for details on adding handlers | ||
* and middleware to routes. | ||
* | ||
* @param {string} path | ||
* @return {Route} | ||
* @public | ||
*/ | ||
Router.prototype.route = function route(path) { | ||
var route = new Route(path) | ||
var layer = new Layer(path, { | ||
sensitive: this.caseSensitive, | ||
strict: this.strict, | ||
end: true | ||
}, handle) | ||
function handle(req, res, next) { | ||
route.dispatch(req, res, next) | ||
} | ||
layer.route = route | ||
this.stack.push(layer) | ||
return route | ||
} | ||
// create Router#VERB functions | ||
methods.concat('all').forEach(function(method){ | ||
Router.prototype[method] = function (path) { | ||
var route = this.route(path) | ||
route[method].apply(route, slice.call(arguments, 1)) | ||
return this | ||
} | ||
}) | ||
/** | ||
* Merge params with parent params | ||
* | ||
* @private | ||
*/ | ||
function mergeParams(params, parent) { | ||
if (typeof parent !== 'object' || !parent) { | ||
return params | ||
} | ||
// make copy of parent for base | ||
var obj = mixin({}, parent) | ||
// simple non-numeric merging | ||
if (!(0 in params) || !(0 in parent)) { | ||
return mixin(obj, params) | ||
} | ||
var i = 0 | ||
var o = 0 | ||
// determine numeric gaps | ||
while (i === o || o in parent) { | ||
if (i in params) i++ | ||
if (o in parent) o++ | ||
} | ||
// offset numeric indices in params before merge | ||
for (i--; i >= 0; i--) { | ||
params[i + o] = params[i] | ||
// create holes for the merge when necessary | ||
if (i < o) { | ||
delete params[i] | ||
} | ||
} | ||
return mixin(parent, params) | ||
} | ||
/** | ||
* Restore obj props after function | ||
* | ||
* @private | ||
*/ | ||
function restore(fn, obj) { | ||
var props = new Array(arguments.length - 2) | ||
var vals = new Array(arguments.length - 2) | ||
for (var i = 0; i < props.length; i++) { | ||
props[i] = arguments[i + 2] | ||
vals[i] = obj[props[i]] | ||
} | ||
return function(err){ | ||
// restore vals | ||
for (var i = 0; i < props.length; i++) { | ||
obj[props[i]] = vals[i] | ||
} | ||
return fn.apply(this, arguments) | ||
} | ||
} | ||
/** | ||
* Wrap a function | ||
* | ||
* @private | ||
*/ | ||
function wrap(old, fn) { | ||
return function proxy() { | ||
var args = new Array(arguments.length + 1) | ||
args[0] = old | ||
for (var i = 0, len = arguments.length; i < len; i++) { | ||
args[i + 1] = arguments[i] | ||
} | ||
fn.apply(this, args) | ||
} | ||
} |
{ | ||
"name":"router", | ||
"version":"0.6.2", | ||
"description":"A lean and mean http router", | ||
"keywords":["connect","middleware","router","route","http"], | ||
"repository": {"type": "git", "url": "git://github.com/gett/router.git"}, | ||
"contributors": [ | ||
"Mathias Buus Madsen <m@ge.tt>", | ||
"Ian Jorgensen <i@ge.tt" | ||
], | ||
"dependencies": {} | ||
"name": "router", | ||
"description": "Simple middleware-style router", | ||
"version": "1.0.0-beta.1", | ||
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>", | ||
"license": "MIT", | ||
"repository": "pillarjs/router", | ||
"dependencies": { | ||
"debug": "~2.1.0", | ||
"methods": "~1.1.0", | ||
"parseurl": "~1.3.0", | ||
"path-to-regexp": "0.1.3", | ||
"utils-merge": "1.0.0" | ||
}, | ||
"devDependencies": { | ||
"after": "0.8.1", | ||
"finalhandler": "0.3.2", | ||
"istanbul": "0.3.2", | ||
"mocha": "~2.0.1", | ||
"supertest": "~0.14.0" | ||
}, | ||
"files": [ | ||
"lib/", | ||
"LICENSE", | ||
"HISTORY.md", | ||
"README.md", | ||
"index.js" | ||
], | ||
"engines": { | ||
"node": ">= 0.8" | ||
}, | ||
"scripts": { | ||
"test": "mocha --reporter spec --bail --check-leaks test/", | ||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/", | ||
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/" | ||
} | ||
} |
121
README.md
@@ -1,104 +0,49 @@ | ||
# Router | ||
# router | ||
A lean and mean http router for [node.js](http://nodejs.org). | ||
It is available through npm: | ||
[![NPM Version][npm-image]][npm-url] | ||
[![NPM Downloads][downloads-image]][downloads-url] | ||
[![Node.js Version][node-version-image]][node-version-url] | ||
[![Build Status][travis-image]][travis-url] | ||
[![Test Coverage][coveralls-image]][coveralls-url] | ||
npm install router | ||
## Usage | ||
Simple middleware-style router | ||
Router does one thing and one thing only - route http requests. | ||
## Installation | ||
``` js | ||
var http = require('http'); | ||
var router = require('router'); | ||
var route = router(); | ||
route.get('/', function(req, res) { | ||
res.writeHead(200); | ||
res.end('hello index page'); | ||
}); | ||
http.createServer(route).listen(8080); // start the server on port 8080 | ||
```sh | ||
$ npm install router | ||
``` | ||
If you want to grap a part of the path you can use capture groups in the pattern: | ||
## API | ||
``` js | ||
route.get('/{base}', function(req, res) { | ||
var base = req.params.base; // ex: if the path is /foo/bar, then base = foo | ||
}); | ||
```js | ||
var Router = require('router') | ||
``` | ||
The capture patterns matches until the next `/` or character present after the group | ||
This module is currently an extracted version from the Express 4.x project, | ||
but with the main change being it can be used with a plain `http.createServer` | ||
object or something like `connect` by removing Express-specific API calls. | ||
``` js | ||
route.get('/{x}x{y}', function(req, res) { | ||
// if the path was /200x200, then req.params = {x:'200', y:'200'} | ||
}); | ||
``` | ||
Documentation is forthcoming, but the Express 4.x documentation can be found | ||
at http://expressjs.com/4x/api.html#router | ||
Optional patterns are supported by adding a `?` at the end | ||
## Testing | ||
``` js | ||
route.get('/{prefix}?/{top}', function(req, res) { | ||
// matches both '/a/b' and '/b' | ||
}); | ||
```sh | ||
$ npm test | ||
``` | ||
If you want to just match everything you can use a wildcard `*` which works like unix wildcards | ||
## License | ||
``` js | ||
route.get('/{prefix}/*', function(req, res) { | ||
// matches both '/a/', '/a/b', 'a/b/c' and so on. | ||
// the value of the wildcard is available through req.params.wildcard | ||
}); | ||
``` | ||
[MIT](LICENSE) | ||
If the standard capture groups aren't expressive enough for you can specify an optional inline regex | ||
``` js | ||
route.get('/{digits}([0-9]+)', function(req, res) { | ||
// matches both '/24' and '/424' but not '/abefest' and so on. | ||
}); | ||
``` | ||
You can also use regular expressions and the related capture groups instead: | ||
``` js | ||
route.get(/^\/foo\/(\w+)/, function(req, res) { | ||
var group = req.params[1]; // if path is /foo/bar, then group is bar | ||
}); | ||
``` | ||
## Methods | ||
* `route.get`: Match `GET` requests | ||
* `route.post`: Match `POST` requests | ||
* `route.put`: Match `PUT` requests | ||
* `route.head`: Match `HEAD` requests | ||
* `route.del`: Match `DELETE` requests | ||
* `route.options`: Match `OPTIONS` requests | ||
* `route.all`: Match all above request methods. | ||
## Error handling | ||
By default Router will return 404 if you no route matched. If you want to do your own thing you can give it a callback: | ||
``` js | ||
route(req, res, function() { | ||
// no route was matched | ||
res.writeHead(404); | ||
res.end(); | ||
}); | ||
``` | ||
You can also provide a catch-all to a given route that is called if no route was matched: | ||
``` js | ||
route.get(function(req, res) { | ||
// called if no other get route matched | ||
res.writeHead(404); | ||
res.end('no GET handler found'); | ||
}); | ||
``` | ||
[npm-image]: https://img.shields.io/npm/v/router.svg?style=flat | ||
[npm-url]: https://npmjs.org/package/router | ||
[node-version-image]: https://img.shields.io/node/v/router.svg?style=flat | ||
[node-version-url]: http://nodejs.org/download/ | ||
[travis-image]: https://img.shields.io/travis/pillarjs/router.svg?style=flat | ||
[travis-url]: https://travis-ci.org/pillarjs/router | ||
[coveralls-image]: https://img.shields.io/coveralls/pillarjs/router.svg?style=flat | ||
[coveralls-url]: https://coveralls.io/r/pillarjs/router?branch=master | ||
[downloads-image]: https://img.shields.io/npm/dm/router.svg?style=flat | ||
[downloads-url]: https://npmjs.org/package/router |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No License Found
License(Experimental) License information could not be found.
Found 1 instance in 1 package
24259
0
822
5
5
8
50
2
+ Addeddebug@~2.1.0
+ Addedmethods@~1.1.0
+ Addedparseurl@~1.3.0
+ Addedpath-to-regexp@0.1.3
+ Addedutils-merge@1.0.0
+ Addeddebug@2.1.3(transitive)
+ Addedmethods@1.1.2(transitive)
+ Addedms@0.7.0(transitive)
+ Addedparseurl@1.3.3(transitive)
+ Addedpath-to-regexp@0.1.3(transitive)
+ Addedutils-merge@1.0.0(transitive)