Skip to content

Instantly share code, notes, and snippets.

@suisun2015
Created April 30, 2016 16:36
Show Gist options
  • Save suisun2015/0002863db9e30afcb9d62a3e245c205e to your computer and use it in GitHub Desktop.
Save suisun2015/0002863db9e30afcb9d62a3e245c205e to your computer and use it in GitHub Desktop.
uranai
This gist exceeds the recommended number of files (~10). To access all files, please clone this gist.
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="file://$PROJECT_DIR$" libraries="{project04 node_modules}" />
<includedPredefinedLibrary name="Node.js Core" />
</component>
</project>
<component name="libraryTable">
<library name="project04 node_modules" type="javaScript">
<properties>
<option name="frameworkName" value="node_modules" />
<sourceFilesUrls>
<item url="file://$PROJECT_DIR$/node_modules" />
</sourceFilesUrls>
</properties>
<CLASSES>
<root url="file://$PROJECT_DIR$/node_modules" />
</CLASSES>
<SOURCES />
</library>
</component>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/project04.iml" filepath="$PROJECT_DIR$/.idea/project04.iml" />
</modules>
</component>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="project04 node_modules" level="project" />
</component>
</module>
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="bin\www" type="NodeJSConfigurationType" factoryName="Node.js" path-to-node="C:/Program Files/nodejs/node" path-to-js-file="bin/www" working-dir="$PROJECT_DIR$">
<envs>
<env name="DEBUG" value="project04:*" />
</envs>
<browser name="16bf23d4-93e0-4ffc-bfd6-cb13575177b0" start="true" url="http://localhost:3000/" />
<method />
</configuration>
</component>
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('project04:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}

1.13.3 / 2015-07-31

  • deps: type-is@~1.6.6
    • deps: mime-types@~2.1.4

1.13.2 / 2015-07-05

  • deps: iconv-lite@0.4.11
  • deps: qs@4.0.0
    • Fix dropping parameters like hasOwnProperty
    • Fix user-visible incompatibilities from 3.1.0
    • Fix various parsing edge cases
  • deps: raw-body@~2.1.2
    • Fix error stack traces to skip makeError
    • deps: iconv-lite@0.4.11
  • deps: type-is@~1.6.4
    • deps: mime-types@~2.1.2
    • perf: enable strict mode
    • perf: remove argument reassignment

1.13.1 / 2015-06-16

  • deps: qs@2.4.2
    • Downgraded from 3.1.0 because of user-visible incompatibilities

1.13.0 / 2015-06-14

  • Add statusCode property on Errors, in addition to status
  • Change type default to application/json for JSON parser
  • Change type default to application/x-www-form-urlencoded for urlencoded parser
  • Provide static require analysis
  • Use the http-errors module to generate errors
  • deps: bytes@2.1.0
    • Slight optimizations
  • deps: iconv-lite@0.4.10
    • The encoding UTF-16 without BOM now defaults to UTF-16LE when detection fails
    • Leading BOM is now removed when decoding
  • deps: on-finished@~2.3.0
    • Add defined behavior for HTTP CONNECT requests
    • Add defined behavior for HTTP Upgrade requests
    • deps: ee-first@1.1.1
  • deps: qs@3.1.0
    • Fix dropping parameters like hasOwnProperty
    • Fix various parsing edge cases
    • Parsed object now has null prototype
  • deps: raw-body@~2.1.1
    • Use unpipe module for unpiping requests
    • deps: iconv-lite@0.4.10
  • deps: type-is@~1.6.3
    • deps: mime-types@~2.1.1
    • perf: reduce try block size
    • perf: remove bitwise operations
  • perf: enable strict mode
  • perf: remove argument reassignment
  • perf: remove delete call

1.12.4 / 2015-05-10

  • deps: debug@~2.2.0
  • deps: qs@2.4.2
    • Fix allowing parameters like constructor
  • deps: on-finished@~2.2.1
  • deps: raw-body@~2.0.1
    • Fix a false-positive when unpiping in Node.js 0.8
    • deps: bytes@2.0.1
  • deps: type-is@~1.6.2
    • deps: mime-types@~2.0.11

1.12.3 / 2015-04-15

  • Slight efficiency improvement when not debugging
  • deps: depd@~1.0.1
  • deps: iconv-lite@0.4.8
    • Add encoding alias UNICODE-1-1-UTF-7
  • deps: raw-body@1.3.4
    • Fix hanging callback if request aborts during read
    • deps: iconv-lite@0.4.8

1.12.2 / 2015-03-16

  • deps: qs@2.4.1
    • Fix error when parameter hasOwnProperty is present

1.12.1 / 2015-03-15

  • deps: debug@~2.1.3
    • Fix high intensity foreground color for bold
    • deps: ms@0.7.0
  • deps: type-is@~1.6.1
    • deps: mime-types@~2.0.10

1.12.0 / 2015-02-13

  • add debug messages
  • accept a function for the type option
  • use content-type to parse Content-Type headers
  • deps: iconv-lite@0.4.7
    • Gracefully support enumerables on Object.prototype
  • deps: raw-body@1.3.3
    • deps: iconv-lite@0.4.7
  • deps: type-is@~1.6.0
    • fix argument reassignment
    • fix false-positives in hasBody Transfer-Encoding check
    • support wildcard for both type and subtype (*/*)
    • deps: mime-types@~2.0.9

1.11.0 / 2015-01-30

  • make internal extended: true depth limit infinity
  • deps: type-is@~1.5.6
    • deps: mime-types@~2.0.8

1.10.2 / 2015-01-20

  • deps: iconv-lite@0.4.6
    • Fix rare aliases of single-byte encodings
  • deps: raw-body@1.3.2
    • deps: iconv-lite@0.4.6

1.10.1 / 2015-01-01

  • deps: on-finished@~2.2.0
  • deps: type-is@~1.5.5
    • deps: mime-types@~2.0.7

1.10.0 / 2014-12-02

  • make internal extended: true array limit dynamic

1.9.3 / 2014-11-21

  • deps: iconv-lite@0.4.5
    • Fix Windows-31J and X-SJIS encoding support
  • deps: qs@2.3.3
    • Fix arrayLimit behavior
  • deps: raw-body@1.3.1
    • deps: iconv-lite@0.4.5
  • deps: type-is@~1.5.3
    • deps: mime-types@~2.0.3

1.9.2 / 2014-10-27

  • deps: qs@2.3.2
    • Fix parsing of mixed objects and values

1.9.1 / 2014-10-22

  • deps: on-finished@~2.1.1
    • Fix handling of pipelined requests
  • deps: qs@2.3.0
    • Fix parsing of mixed implicit and explicit arrays
  • deps: type-is@~1.5.2
    • deps: mime-types@~2.0.2

1.9.0 / 2014-09-24

  • include the charset in "unsupported charset" error message
  • include the encoding in "unsupported content encoding" error message
  • deps: depd@~1.0.0

1.8.4 / 2014-09-23

  • fix content encoding to be case-insensitive

1.8.3 / 2014-09-19

  • deps: qs@2.2.4
    • Fix issue with object keys starting with numbers truncated

1.8.2 / 2014-09-15

  • deps: depd@0.4.5

1.8.1 / 2014-09-07

  • deps: media-typer@0.3.0
  • deps: type-is@~1.5.1

1.8.0 / 2014-09-05

  • make empty-body-handling consistent between chunked requests
    • empty json produces {}
    • empty raw produces new Buffer(0)
    • empty text produces ''
    • empty urlencoded produces {}
  • deps: qs@2.2.3
    • Fix issue where first empty value in array is discarded
  • deps: type-is@~1.5.0
    • fix hasbody to be true for content-length: 0

1.7.0 / 2014-09-01

  • add parameterLimit option to urlencoded parser
  • change urlencoded extended array limit to 100
  • respond with 413 when over parameterLimit in urlencoded

1.6.7 / 2014-08-29

  • deps: qs@2.2.2
    • Remove unnecessary cloning

1.6.6 / 2014-08-27

  • deps: qs@2.2.0
    • Array parsing fix
    • Performance improvements

1.6.5 / 2014-08-16

  • deps: on-finished@2.1.0

1.6.4 / 2014-08-14

  • deps: qs@1.2.2

1.6.3 / 2014-08-10

  • deps: qs@1.2.1

1.6.2 / 2014-08-07

  • deps: qs@1.2.0
    • Fix parsing array of objects

1.6.1 / 2014-08-06

  • deps: qs@1.1.0
    • Accept urlencoded square brackets
    • Accept empty values in implicit array notation

1.6.0 / 2014-08-05

  • deps: qs@1.0.2
    • Complete rewrite
    • Limits array length to 20
    • Limits object depth to 5
    • Limits parameters to 1,000

1.5.2 / 2014-07-27

  • deps: depd@0.4.4
    • Work-around v8 generating empty stack traces

1.5.1 / 2014-07-26

  • deps: depd@0.4.3
    • Fix exception when global Error.stackTraceLimit is too low

1.5.0 / 2014-07-20

  • deps: depd@0.4.2
    • Add TRACE_DEPRECATION environment variable
    • Remove non-standard grey color from color output
    • Support --no-deprecation argument
    • Support --trace-deprecation argument
  • deps: iconv-lite@0.4.4
    • Added encoding UTF-7
  • deps: raw-body@1.3.0
    • deps: iconv-lite@0.4.4
    • Added encoding UTF-7
    • Fix Cannot switch to old mode now error on Node.js 0.10+
  • deps: type-is@~1.3.2

1.4.3 / 2014-06-19

  • deps: type-is@1.3.1
    • fix global variable leak

1.4.2 / 2014-06-19

  • deps: type-is@1.3.0
    • improve type parsing

1.4.1 / 2014-06-19

  • fix urlencoded extended deprecation message

1.4.0 / 2014-06-19

  • add text parser
  • add raw parser
  • check accepted charset in content-type (accepts utf-8)
  • check accepted encoding in content-encoding (accepts identity)
  • deprecate bodyParser() middleware; use .json() and .urlencoded() as needed
  • deprecate urlencoded() without provided extended option
  • lazy-load urlencoded parsers
  • parsers split into files for reduced mem usage
  • support gzip and deflate bodies
    • set inflate: false to turn off
  • deps: raw-body@1.2.2
    • Support all encodings from iconv-lite

1.3.1 / 2014-06-11

  • deps: type-is@1.2.1
    • Switch dependency from mime to mime-types@1.0.0

1.3.0 / 2014-05-31

  • add extended option to urlencoded parser

1.2.2 / 2014-05-27

  • deps: raw-body@1.1.6
    • assert stream encoding on node.js 0.8
    • assert stream encoding on node.js < 0.10.6
    • deps: bytes@1

1.2.1 / 2014-05-26

  • invoke next(err) after request fully read
    • prevents hung responses and socket hang ups

1.2.0 / 2014-05-11

  • add verify option
  • deps: type-is@1.2.0
    • support suffix matching

1.1.2 / 2014-05-11

  • improve json parser speed

1.1.1 / 2014-05-11

  • fix repeated limit parsing with every request

1.1.0 / 2014-05-10

  • add type option
  • deps: pin for safety and consistency

1.0.2 / 2014-04-14

  • use type-is module

1.0.1 / 2014-03-20

  • lower default limits to 100kb
/*!
* body-parser
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var deprecate = require('depd')('body-parser')
/**
* Cache of loaded parsers.
* @private
*/
var parsers = Object.create(null)
/**
* @typedef Parsers
* @type {function}
* @property {function} json
* @property {function} raw
* @property {function} text
* @property {function} urlencoded
*/
/**
* Module exports.
* @type {Parsers}
*/
exports = module.exports = deprecate.function(bodyParser,
'bodyParser: use individual json/urlencoded middlewares')
/**
* JSON parser.
* @public
*/
Object.defineProperty(exports, 'json', {
configurable: true,
enumerable: true,
get: createParserGetter('json')
})
/**
* Raw parser.
* @public
*/
Object.defineProperty(exports, 'raw', {
configurable: true,
enumerable: true,
get: createParserGetter('raw')
})
/**
* Text parser.
* @public
*/
Object.defineProperty(exports, 'text', {
configurable: true,
enumerable: true,
get: createParserGetter('text')
})
/**
* URL-encoded parser.
* @public
*/
Object.defineProperty(exports, 'urlencoded', {
configurable: true,
enumerable: true,
get: createParserGetter('urlencoded')
})
/**
* Create a middleware to parse json and urlencoded bodies.
*
* @param {object} [options]
* @return {function}
* @deprecated
* @public
*/
function bodyParser(options){
var opts = {}
// exclude type option
if (options) {
for (var prop in options) {
if ('type' !== prop) {
opts[prop] = options[prop]
}
}
}
var _urlencoded = exports.urlencoded(opts)
var _json = exports.json(opts)
return function bodyParser(req, res, next) {
_json(req, res, function(err){
if (err) return next(err);
_urlencoded(req, res, next);
});
}
}
/**
* Create a getter for loading a parser.
* @private
*/
function createParserGetter(name) {
return function get() {
return loadParser(name)
}
}
/**
* Load a parser module.
* @private
*/
function loadParser(parserName) {
var parser = parsers[parserName]
if (parser !== undefined) {
return parser
}
// this uses a switch for static require analysis
switch (parserName) {
case 'json':
parser = require('./lib/types/json')
break
case 'raw':
parser = require('./lib/types/raw')
break
case 'text':
parser = require('./lib/types/text')
break
case 'urlencoded':
parser = require('./lib/types/urlencoded')
break
}
// store to prevent invoking require()
return parsers[parserName] = parser
}
/*!
* body-parser
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var createError = require('http-errors')
var getBody = require('raw-body')
var iconv = require('iconv-lite')
var onFinished = require('on-finished')
var zlib = require('zlib')
/**
* Module exports.
*/
module.exports = read
/**
* Read a request into a buffer and parse.
*
* @param {object} req
* @param {object} res
* @param {function} next
* @param {function} parse
* @param {function} debug
* @param {object} [options]
* @api private
*/
function read(req, res, next, parse, debug, options) {
var length
var stream
// flag as parsed
req._body = true
var opts = options || {}
try {
stream = contentstream(req, debug, opts.inflate)
length = stream.length
stream.length = undefined
} catch (err) {
return next(err)
}
opts.length = length
var encoding = opts.encoding !== null
? opts.encoding || 'utf-8'
: null
var verify = opts.verify
opts.encoding = verify
? null
: encoding
// read body
debug('read body')
getBody(stream, opts, function (err, body) {
if (err) {
// default to 400
setErrorStatus(err, 400)
// echo back charset
if (err.type === 'encoding.unsupported') {
err = createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
charset: encoding.toLowerCase()
})
}
// read off entire request
stream.resume()
onFinished(req, function onfinished() {
next(err)
})
return
}
// verify
if (verify) {
try {
debug('verify body')
verify(req, res, body, encoding)
} catch (err) {
// default to 403
setErrorStatus(err, 403)
next(err)
return
}
}
// parse
var str
try {
debug('parse body')
str = typeof body !== 'string' && encoding !== null
? iconv.decode(body, encoding)
: body
req.body = parse(str)
} catch (err) {
err.body = str === undefined
? body
: str
// default to 400
setErrorStatus(err, 400)
next(err)
return
}
next()
})
}
/**
* Get the content stream of the request.
*
* @param {object} req
* @param {function} debug
* @param {boolean} [inflate=true]
* @return {object}
* @api private
*/
function contentstream(req, debug, inflate) {
var encoding = (req.headers['content-encoding'] || 'identity').toLowerCase()
var length = req.headers['content-length']
var stream
debug('content-encoding "%s"', encoding)
if (inflate === false && encoding !== 'identity') {
throw createError(415, 'content encoding unsupported')
}
switch (encoding) {
case 'deflate':
stream = zlib.createInflate()
debug('inflate body')
req.pipe(stream)
break
case 'gzip':
stream = zlib.createGunzip()
debug('gunzip body')
req.pipe(stream)
break
case 'identity':
stream = req
stream.length = length
break
default:
throw createError(415, 'unsupported content encoding "' + encoding + '"', {
encoding: encoding
})
}
return stream
}
/**
* Set a status on an error object, if ones does not exist
* @private
*/
function setErrorStatus(error, status) {
if (!error.status && !error.statusCode) {
error.status = status
error.statusCode = status
}
}
/*!
* body-parser
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var bytes = require('bytes')
var contentType = require('content-type')
var createError = require('http-errors')
var debug = require('debug')('body-parser:json')
var read = require('../read')
var typeis = require('type-is')
/**
* Module exports.
*/
module.exports = json
/**
* RegExp to match the first non-space in a string.
*
* Allowed whitespace is defined in RFC 7159:
*
* ws = *(
* %x20 / ; Space
* %x09 / ; Horizontal tab
* %x0A / ; Line feed or New line
* %x0D ) ; Carriage return
*/
var firstcharRegExp = /^[\x20\x09\x0a\x0d]*(.)/
/**
* Create a middleware to parse JSON bodies.
*
* @param {object} [options]
* @return {function}
* @public
*/
function json(options) {
var opts = options || {}
var limit = typeof opts.limit !== 'number'
? bytes.parse(opts.limit || '100kb')
: opts.limit
var inflate = opts.inflate !== false
var reviver = opts.reviver
var strict = opts.strict !== false
var type = opts.type || 'application/json'
var verify = opts.verify || false
if (verify !== false && typeof verify !== 'function') {
throw new TypeError('option verify must be function')
}
// create the appropriate type checking function
var shouldParse = typeof type !== 'function'
? typeChecker(type)
: type
function parse(body) {
if (body.length === 0) {
// special-case empty json body, as it's a common client-side mistake
// TODO: maybe make this configurable or part of "strict" option
return {}
}
if (strict) {
var first = firstchar(body)
if (first !== '{' && first !== '[') {
debug('strict violation')
throw new Error('invalid json')
}
}
debug('parse json')
return JSON.parse(body, reviver)
}
return function jsonParser(req, res, next) {
if (req._body) {
return debug('body already parsed'), next()
}
req.body = req.body || {}
// skip requests without bodies
if (!typeis.hasBody(req)) {
return debug('skip empty body'), next()
}
debug('content-type %j', req.headers['content-type'])
// determine if request should be parsed
if (!shouldParse(req)) {
return debug('skip parsing'), next()
}
// assert charset per RFC 7159 sec 8.1
var charset = getCharset(req) || 'utf-8'
if (charset.substr(0, 4) !== 'utf-') {
debug('invalid charset')
next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
charset: charset
}))
return
}
// read
read(req, res, next, parse, debug, {
encoding: charset,
inflate: inflate,
limit: limit,
verify: verify
})
}
}
/**
* Get the first non-whitespace character in a string.
*
* @param {string} str
* @return {function}
* @api public
*/
function firstchar(str) {
var match = firstcharRegExp.exec(str)
return match ? match[1] : ''
}
/**
* Get the charset of a request.
*
* @param {object} req
* @api private
*/
function getCharset(req) {
try {
return contentType.parse(req).parameters.charset.toLowerCase()
} catch (e) {
return undefined
}
}
/**
* Get the simple type checker.
*
* @param {string} type
* @return {function}
*/
function typeChecker(type) {
return function checkType(req) {
return Boolean(typeis(req, type))
}
}
/*!
* body-parser
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
*/
var bytes = require('bytes')
var debug = require('debug')('body-parser:raw')
var read = require('../read')
var typeis = require('type-is')
/**
* Module exports.
*/
module.exports = raw
/**
* Create a middleware to parse raw bodies.
*
* @param {object} [options]
* @return {function}
* @api public
*/
function raw(options) {
var opts = options || {};
var inflate = opts.inflate !== false
var limit = typeof opts.limit !== 'number'
? bytes.parse(opts.limit || '100kb')
: opts.limit
var type = opts.type || 'application/octet-stream'
var verify = opts.verify || false
if (verify !== false && typeof verify !== 'function') {
throw new TypeError('option verify must be function')
}
// create the appropriate type checking function
var shouldParse = typeof type !== 'function'
? typeChecker(type)
: type
function parse(buf) {
return buf
}
return function rawParser(req, res, next) {
if (req._body) {
return debug('body already parsed'), next()
}
req.body = req.body || {}
// skip requests without bodies
if (!typeis.hasBody(req)) {
return debug('skip empty body'), next()
}
debug('content-type %j', req.headers['content-type'])
// determine if request should be parsed
if (!shouldParse(req)) {
return debug('skip parsing'), next()
}
// read
read(req, res, next, parse, debug, {
encoding: null,
inflate: inflate,
limit: limit,
verify: verify
})
}
}
/**
* Get the simple type checker.
*
* @param {string} type
* @return {function}
*/
function typeChecker(type) {
return function checkType(req) {
return Boolean(typeis(req, type))
}
}
/*!
* body-parser
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
*/
var bytes = require('bytes')
var contentType = require('content-type')
var debug = require('debug')('body-parser:text')
var read = require('../read')
var typeis = require('type-is')
/**
* Module exports.
*/
module.exports = text
/**
* Create a middleware to parse text bodies.
*
* @param {object} [options]
* @return {function}
* @api public
*/
function text(options) {
var opts = options || {}
var defaultCharset = opts.defaultCharset || 'utf-8'
var inflate = opts.inflate !== false
var limit = typeof opts.limit !== 'number'
? bytes.parse(opts.limit || '100kb')
: opts.limit
var type = opts.type || 'text/plain'
var verify = opts.verify || false
if (verify !== false && typeof verify !== 'function') {
throw new TypeError('option verify must be function')
}
// create the appropriate type checking function
var shouldParse = typeof type !== 'function'
? typeChecker(type)
: type
function parse(buf) {
return buf
}
return function textParser(req, res, next) {
if (req._body) {
return debug('body already parsed'), next()
}
req.body = req.body || {}
// skip requests without bodies
if (!typeis.hasBody(req)) {
return debug('skip empty body'), next()
}
debug('content-type %j', req.headers['content-type'])
// determine if request should be parsed
if (!shouldParse(req)) {
return debug('skip parsing'), next()
}
// get charset
var charset = getCharset(req) || defaultCharset
// read
read(req, res, next, parse, debug, {
encoding: charset,
inflate: inflate,
limit: limit,
verify: verify
})
}
}
/**
* Get the charset of a request.
*
* @param {object} req
* @api private
*/
function getCharset(req) {
try {
return contentType.parse(req).parameters.charset.toLowerCase()
} catch (e) {
return undefined
}
}
/**
* Get the simple type checker.
*
* @param {string} type
* @return {function}
*/
function typeChecker(type) {
return function checkType(req) {
return Boolean(typeis(req, type))
}
}
/*!
* body-parser
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var bytes = require('bytes')
var contentType = require('content-type')
var createError = require('http-errors')
var debug = require('debug')('body-parser:urlencoded')
var deprecate = require('depd')('body-parser')
var read = require('../read')
var typeis = require('type-is')
/**
* Module exports.
*/
module.exports = urlencoded
/**
* Cache of parser modules.
*/
var parsers = Object.create(null)
/**
* Create a middleware to parse urlencoded bodies.
*
* @param {object} [options]
* @return {function}
* @public
*/
function urlencoded(options) {
var opts = options || {}
// notice because option default will flip in next major
if (opts.extended === undefined) {
deprecate('undefined extended: provide extended option')
}
var extended = opts.extended !== false
var inflate = opts.inflate !== false
var limit = typeof opts.limit !== 'number'
? bytes.parse(opts.limit || '100kb')
: opts.limit
var type = opts.type || 'application/x-www-form-urlencoded'
var verify = opts.verify || false
if (verify !== false && typeof verify !== 'function') {
throw new TypeError('option verify must be function')
}
// create the appropriate query parser
var queryparse = extended
? extendedparser(opts)
: simpleparser(opts)
// create the appropriate type checking function
var shouldParse = typeof type !== 'function'
? typeChecker(type)
: type
function parse(body) {
return body.length
? queryparse(body)
: {}
}
return function urlencodedParser(req, res, next) {
if (req._body) {
return debug('body already parsed'), next()
}
req.body = req.body || {}
// skip requests without bodies
if (!typeis.hasBody(req)) {
return debug('skip empty body'), next()
}
debug('content-type %j', req.headers['content-type'])
// determine if request should be parsed
if (!shouldParse(req)) {
return debug('skip parsing'), next()
}
// assert charset
var charset = getCharset(req) || 'utf-8'
if (charset !== 'utf-8') {
debug('invalid charset')
next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
charset: charset
}))
return
}
// read
read(req, res, next, parse, debug, {
debug: debug,
encoding: charset,
inflate: inflate,
limit: limit,
verify: verify
})
}
}
/**
* Get the extended query parser.
*
* @param {object} options
*/
function extendedparser(options) {
var parameterLimit = options.parameterLimit !== undefined
? options.parameterLimit
: 1000
var parse = parser('qs')
if (isNaN(parameterLimit) || parameterLimit < 1) {
throw new TypeError('option parameterLimit must be a positive number')
}
if (isFinite(parameterLimit)) {
parameterLimit = parameterLimit | 0
}
return function queryparse(body) {
var paramCount = parameterCount(body, parameterLimit)
if (paramCount === undefined) {
debug('too many parameters')
throw createError(413, 'too many parameters')
}
var arrayLimit = Math.max(100, paramCount)
debug('parse extended urlencoding')
return parse(body, {
allowDots: false,
allowPrototypes: true,
arrayLimit: arrayLimit,
depth: Infinity,
parameterLimit: parameterLimit
})
}
}
/**
* Get the charset of a request.
*
* @param {object} req
* @api private
*/
function getCharset(req) {
try {
return contentType.parse(req).parameters.charset.toLowerCase()
} catch (e) {
return undefined
}
}
/**
* Count the number of parameters, stopping once limit reached
*
* @param {string} body
* @param {number} limit
* @api private
*/
function parameterCount(body, limit) {
var count = 0
var index = 0
while ((index = body.indexOf('&', index)) !== -1) {
count++
index++
if (count === limit) {
return undefined
}
}
return count
}
/**
* Get parser for module name dynamically.
*
* @param {string} name
* @return {function}
* @api private
*/
function parser(name) {
var mod = parsers[name]
if (mod) {
return mod.parse
}
// load module
mod = parsers[name] = require(name)
return mod.parse
}
/**
* Get the simple query parser.
*
* @param {object} options
*/
function simpleparser(options) {
var parameterLimit = options.parameterLimit !== undefined
? options.parameterLimit
: 1000
var parse = parser('querystring')
if (isNaN(parameterLimit) || parameterLimit < 1) {
throw new TypeError('option parameterLimit must be a positive number')
}
if (isFinite(parameterLimit)) {
parameterLimit = parameterLimit | 0
}
return function queryparse(body) {
var paramCount = parameterCount(body, parameterLimit)
if (paramCount === undefined) {
debug('too many parameters')
throw createError(413, 'too many parameters')
}
debug('parse urlencoding')
return parse(body, undefined, undefined, {maxKeys: parameterLimit})
}
}
/**
* Get the simple type checker.
*
* @param {string} type
* @return {function}
*/
function typeChecker(type) {
return function checkType(req) {
return Boolean(typeis(req, type))
}
}
(The MIT License)
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

2.1.0 / 2015-05-21

  • add .format export
  • add .parse export

2.0.2 / 2015-05-20

  • remove map recreation
  • remove unnecessary object construction

2.0.1 / 2015-05-07

  • fix browserify require
  • remove node.extend dependency

2.0.0 / 2015-04-12

  • add option "case"
  • add option "thousandsSeparator"
  • return "null" on invalid parse input
  • support proper round-trip: bytes(bytes(num)) === num
  • units no longer case sensitive when parsing

1.0.0 / 2014-05-05

  • add negative support. fixes #6

0.3.0 / 2014-03-19

  • added terabyte support

0.2.1 / 2013-04-01

  • add .component

0.2.0 / 2012-10-28

  • bytes(200).should.eql('200b')

0.1.0 / 2012-07-04

  • add bytes to string conversion [yields]
/*!
* bytes
* Copyright(c) 2012-2014 TJ Holowaychuk
* Copyright(c) 2015 Jed Watson
* MIT Licensed
*/
'use strict';
/**
* Module exports.
* @public
*/
module.exports = bytes;
module.exports.format = format;
module.exports.parse = parse;
/**
* Module variables.
* @private
*/
var map = {
b: 1,
kb: 1 << 10,
mb: 1 << 20,
gb: 1 << 30,
tb: ((1 << 30) * 1024)
};
/**
*Convert the given value in bytes into a string or parse to string to an integer in bytes.
*
* @param {string|number} value
* @param {{
* case: [string],
* thousandsSeparator: [string]
* }} [options] bytes options.
*
* @returns {string|number|null}
*/
function bytes(value, options) {
if (typeof value === 'string') {
return parse(value);
}
if (typeof value === 'number') {
return format(value, options);
}
return null;
}
/**
* Format the given value in bytes into a string.
*
* If the value is negative, it is kept as such. If it is a float,
* it is rounded.
*
* @param {number} value
* @param {object} [options]
* @param {string} [options.thousandsSeparator=]
* @public
*/
function format(val, options) {
if (typeof val !== 'number') {
return null;
}
var mag = Math.abs(val);
var thousandsSeparator = (options && options.thousandsSeparator) || '';
var unit = 'B';
var value = val;
if (mag >= map.tb) {
value = Math.round(value / map.tb * 100) / 100;
unit = 'TB';
} else if (mag >= map.gb) {
value = Math.round(value / map.gb * 100) / 100;
unit = 'GB';
} else if (mag >= map.mb) {
value = Math.round(value / map.mb * 100) / 100;
unit = 'MB';
} else if (mag >= map.kb) {
value = Math.round(value / map.kb * 100) / 100;
unit = 'kB';
}
if (thousandsSeparator) {
value = value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, thousandsSeparator);
}
return value + unit;
}
/**
* Parse the string value into an integer in bytes.
*
* If no unit is given, it is assumed the value is in bytes.
*
* @param {number|string} val
* @public
*/
function parse(val) {
if (typeof val === 'number' && !isNaN(val)) {
return val;
}
if (typeof val !== 'string') {
return null;
}
// Test if the string passed is valid
var results = val.match(/^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb)$/i);
var floatValue;
var unit = 'b';
if (!results) {
// Nothing could be extracted from the given string
floatValue = parseInt(val);
unit = 'b'
} else {
// Retrieve the value and the unit
floatValue = parseFloat(results[1]);
unit = results[4].toLowerCase();
}
return map[unit] * floatValue;
}
{
"name": "bytes",
"description": "Utility to parse a string bytes to bytes and vice-versa",
"version": "2.1.0",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca",
"url": "http://tjholowaychuk.com"
},
"contributors": [
{
"name": "Jed Watson",
"email": "jed.watson@me.com"
}
],
"license": "MIT",
"keywords": [
"byte",
"bytes",
"utility",
"parse",
"parser",
"convert",
"converter"
],
"repository": {
"type": "git",
"url": "git+https://github.com/visionmedia/bytes.js.git"
},
"component": {
"scripts": {
"bytes/index.js": "index.js"
}
},
"devDependencies": {
"mocha": "*"
},
"files": [
"History.md",
"LICENSE",
"Readme.md",
"index.js"
],
"scripts": {
"test": "mocha --check-leaks --reporter spec"
},
"gitHead": "86e4520cc369b34866154a53344ca50b2bb5ddcd",
"bugs": {
"url": "https://github.com/visionmedia/bytes.js/issues"
},
"homepage": "https://github.com/visionmedia/bytes.js",
"_id": "bytes@2.1.0",
"_shasum": "ac93c410e2ffc9cc7cf4b464b38289067f5e47b4",
"_from": "bytes@2.1.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "ac93c410e2ffc9cc7cf4b464b38289067f5e47b4",
"tarball": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz",
"readme": "ERROR: No README data found!"
}

Bytes utility

Utility to parse a string bytes (ex: 1TB) to bytes (1099511627776) and vice-versa.

Usage

var bytes = require('bytes');

bytes.format(number value, [options]): string|null

Format the given value in bytes into a string. If the value is negative, it is kept as such. If it is a float, it is rounded.

Arguments

Name Type Description
value number Value in bytes
options Object Conversion options

Options

Property Type Description
thousandsSeparator string|null Example of values: ' ', ',' and .... Default value to ' '.

Returns

Name Type Description
results string|null Return null upon error. String value otherwise.

Example

bytes(1024);
// output: '1kB'

bytes(1000);
// output: '1000B'

bytes(1000, {thousandsSeparator: ' '});
// output: '1 000B'

bytes.parse(string value): number|null

Parse the string value into an integer in bytes. If no unit is given, it is assumed the value is in bytes.

Arguments

Name Type Description
value string String to parse.

Returns

Name Type Description
results number|null Return null upon error. Value in bytes otherwise.

Example

bytes('1kB');
// output: 1024

bytes('1024');
// output: 1024

Installation

npm install bytes --save
component install visionmedia/bytes.js

License

npm

1.0.1 / 2015-02-13

  • Improve missing Content-Type header error message

1.0.0 / 2015-02-01

  • Initial implementation, derived from media-typer@0.3.0
/*!
* content-type
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1
*
* parameter = token "=" ( token / quoted-string )
* token = 1*tchar
* tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
* / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
* / DIGIT / ALPHA
* ; any VCHAR, except delimiters
* quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
* qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text
* obs-text = %x80-FF
* quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
*/
var paramRegExp = /; *([!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) */g
var textRegExp = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/
var tokenRegExp = /^[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+$/
/**
* RegExp to match quoted-pair in RFC 7230 sec 3.2.6
*
* quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
* obs-text = %x80-FF
*/
var qescRegExp = /\\([\u000b\u0020-\u00ff])/g
/**
* RegExp to match chars that must be quoted-pair in RFC 7230 sec 3.2.6
*/
var quoteRegExp = /([\\"])/g
/**
* RegExp to match type in RFC 6838
*
* media-type = type "/" subtype
* type = token
* subtype = token
*/
var typeRegExp = /^[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+\/[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+$/
/**
* Module exports.
* @public
*/
exports.format = format
exports.parse = parse
/**
* Format object to media type.
*
* @param {object} obj
* @return {string}
* @public
*/
function format(obj) {
if (!obj || typeof obj !== 'object') {
throw new TypeError('argument obj is required')
}
var parameters = obj.parameters
var type = obj.type
if (!type || !typeRegExp.test(type)) {
throw new TypeError('invalid type')
}
var string = type
// append parameters
if (parameters && typeof parameters === 'object') {
var param
var params = Object.keys(parameters).sort()
for (var i = 0; i < params.length; i++) {
param = params[i]
if (!tokenRegExp.test(param)) {
throw new TypeError('invalid parameter name')
}
string += '; ' + param + '=' + qstring(parameters[param])
}
}
return string
}
/**
* Parse media type to object.
*
* @param {string|object} string
* @return {Object}
* @public
*/
function parse(string) {
if (!string) {
throw new TypeError('argument string is required')
}
if (typeof string === 'object') {
// support req/res-like objects as argument
string = getcontenttype(string)
if (typeof string !== 'string') {
throw new TypeError('content-type header is missing from object');
}
}
if (typeof string !== 'string') {
throw new TypeError('argument string is required to be a string')
}
var index = string.indexOf(';')
var type = index !== -1
? string.substr(0, index).trim()
: string.trim()
if (!typeRegExp.test(type)) {
throw new TypeError('invalid media type')
}
var key
var match
var obj = new ContentType(type.toLowerCase())
var value
paramRegExp.lastIndex = index
while (match = paramRegExp.exec(string)) {
if (match.index !== index) {
throw new TypeError('invalid parameter format')
}
index += match[0].length
key = match[1].toLowerCase()
value = match[2]
if (value[0] === '"') {
// remove quotes and escapes
value = value
.substr(1, value.length - 2)
.replace(qescRegExp, '$1')
}
obj.parameters[key] = value
}
if (index !== -1 && index !== string.length) {
throw new TypeError('invalid parameter format')
}
return obj
}
/**
* Get content-type from req/res objects.
*
* @param {object}
* @return {Object}
* @private
*/
function getcontenttype(obj) {
if (typeof obj.getHeader === 'function') {
// res-like
return obj.getHeader('content-type')
}
if (typeof obj.headers === 'object') {
// req-like
return obj.headers && obj.headers['content-type']
}
}
/**
* Quote a string if necessary.
*
* @param {string} val
* @return {string}
* @private
*/
function qstring(val) {
var str = String(val)
// no need to quote tokens
if (tokenRegExp.test(str)) {
return str
}
if (str.length > 0 && !textRegExp.test(str)) {
throw new TypeError('invalid parameter value')
}
return '"' + str.replace(quoteRegExp, '\\$1') + '"'
}
/**
* Class to represent a content type.
* @private
*/
function ContentType(type) {
this.parameters = Object.create(null)
this.type = type
}
(The MIT License)
Copyright (c) 2015 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
{
"name": "content-type",
"description": "Create and parse HTTP Content-Type header",
"version": "1.0.1",
"author": {
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
"license": "MIT",
"keywords": [
"content-type",
"http",
"req",
"res",
"rfc7231"
],
"repository": {
"type": "git",
"url": "git+https://github.com/jshttp/content-type.git"
},
"devDependencies": {
"istanbul": "0.3.5",
"mocha": "~1.21.5"
},
"files": [
"LICENSE",
"HISTORY.md",
"README.md",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"test": "mocha --reporter spec --check-leaks --bail test/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/"
},
"gitHead": "3aa58f9c5a358a3634b8601602177888b4a477d8",
"bugs": {
"url": "https://github.com/jshttp/content-type/issues"
},
"homepage": "https://github.com/jshttp/content-type",
"_id": "content-type@1.0.1",
"_shasum": "a19d2247327dc038050ce622b7a154ec59c5e600",
"_from": "content-type@>=1.0.1 <1.1.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "a19d2247327dc038050ce622b7a154ec59c5e600",
"tarball": "https://registry.npmjs.org/content-type/-/content-type-1.0.1.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.1.tgz",
"readme": "ERROR: No README data found!"
}

content-type

NPM Version NPM Downloads Node.js Version Build Status Test Coverage

Create and parse HTTP Content-Type header according to RFC 7231

Installation

$ npm install content-type

API

var contentType = require('content-type')

contentType.parse(string)

var obj = contentType.parse('image/svg+xml; charset=utf-8')

Parse a content type string. This will return an object with the following properties (examples are shown for the string 'image/svg+xml; charset=utf-8'):

  • type: The media type (the type and subtype, always lower case). Example: 'image/svg+xml'

  • parameters: An object of the parameters in the media type (name of parameter always lower case). Example: {charset: 'utf-8'}

Throws a TypeError if the string is missing or invalid.

contentType.parse(req)

var obj = contentType.parse(req)

Parse the content-type header from the given req. Short-cut for contentType.parse(req.headers['content-type']).

Throws a TypeError if the Content-Type header is missing or invalid.

contentType.parse(res)

var obj = contentType.parse(res)

Parse the content-type header set on the given res. Short-cut for contentType.parse(res.getHeader('content-type')).

Throws a TypeError if the Content-Type header is missing or invalid.

contentType.format(obj)

var str = contentType.format({type: 'image/svg+xml'})

Format an object into a content type string. This will return a string of the content type for the given object with the following properties (examples are shown that produce the string 'image/svg+xml; charset=utf-8'):

  • type: The media type (will be lower-cased). Example: 'image/svg+xml'

  • parameters: An object of the parameters in the media type (name of the parameter will be lower-cased). Example: {charset: 'utf-8'}

Throws a TypeError if the object contains an invalid type or parameter names.

License

MIT

1.0.1 / 2015-04-07

  • Fix TypeErrors when under 'use strict' code
  • Fix useless type name on auto-generated messages
  • Support io.js 1.x
  • Support Node.js 0.12

1.0.0 / 2014-09-17

  • No changes

0.4.5 / 2014-09-09

  • Improve call speed to functions using the function wrapper
  • Support Node.js 0.6

0.4.4 / 2014-07-27

  • Work-around v8 generating empty stack traces

0.4.3 / 2014-07-26

  • Fix exception when global Error.stackTraceLimit is too low

0.4.2 / 2014-07-19

  • Correct call site for wrapped functions and properties

0.4.1 / 2014-07-19

  • Improve automatic message generation for function properties

0.4.0 / 2014-07-19

  • Add TRACE_DEPRECATION environment variable
  • Remove non-standard grey color from color output
  • Support --no-deprecation argument
  • Support --trace-deprecation argument
  • Support deprecate.property(fn, prop, message)

0.3.0 / 2014-06-16

  • Add NO_DEPRECATION environment variable

0.2.0 / 2014-06-15

  • Add deprecate.property(obj, prop, message)
  • Remove supports-color dependency for node.js 0.8

0.1.0 / 2014-06-15

  • Add deprecate.function(fn, message)
  • Add process.on('deprecation', fn) emitter
  • Automatically generate message when omitted from deprecate()

0.0.1 / 2014-06-15

  • Fix warning for dynamic calls at singe call site

0.0.0 / 2014-06-15

  • Initial implementation
/*!
* depd
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
*/
var callSiteToString = require('./lib/compat').callSiteToString
var EventEmitter = require('events').EventEmitter
var relative = require('path').relative
/**
* Module exports.
*/
module.exports = depd
/**
* Get the path to base files on.
*/
var basePath = process.cwd()
/**
* Get listener count on event emitter.
*/
/*istanbul ignore next*/
var eventListenerCount = EventEmitter.listenerCount
|| function (emitter, type) { return emitter.listeners(type).length }
/**
* Determine if namespace is contained in the string.
*/
function containsNamespace(str, namespace) {
var val = str.split(/[ ,]+/)
namespace = String(namespace).toLowerCase()
for (var i = 0 ; i < val.length; i++) {
if (!(str = val[i])) continue;
// namespace contained
if (str === '*' || str.toLowerCase() === namespace) {
return true
}
}
return false
}
/**
* Convert a data descriptor to accessor descriptor.
*/
function convertDataDescriptorToAccessor(obj, prop, message) {
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
var value = descriptor.value
descriptor.get = function getter() { return value }
if (descriptor.writable) {
descriptor.set = function setter(val) { return value = val }
}
delete descriptor.value
delete descriptor.writable
Object.defineProperty(obj, prop, descriptor)
return descriptor
}
/**
* Create arguments string to keep arity.
*/
function createArgumentsString(arity) {
var str = ''
for (var i = 0; i < arity; i++) {
str += ', arg' + i
}
return str.substr(2)
}
/**
* Create stack string from stack.
*/
function createStackString(stack) {
var str = this.name + ': ' + this.namespace
if (this.message) {
str += ' deprecated ' + this.message
}
for (var i = 0; i < stack.length; i++) {
str += '\n at ' + callSiteToString(stack[i])
}
return str
}
/**
* Create deprecate for namespace in caller.
*/
function depd(namespace) {
if (!namespace) {
throw new TypeError('argument namespace is required')
}
var stack = getStack()
var site = callSiteLocation(stack[1])
var file = site[0]
function deprecate(message) {
// call to self as log
log.call(deprecate, message)
}
deprecate._file = file
deprecate._ignored = isignored(namespace)
deprecate._namespace = namespace
deprecate._traced = istraced(namespace)
deprecate._warned = Object.create(null)
deprecate.function = wrapfunction
deprecate.property = wrapproperty
return deprecate
}
/**
* Determine if namespace is ignored.
*/
function isignored(namespace) {
/* istanbul ignore next: tested in a child processs */
if (process.noDeprecation) {
// --no-deprecation support
return true
}
var str = process.env.NO_DEPRECATION || ''
// namespace ignored
return containsNamespace(str, namespace)
}
/**
* Determine if namespace is traced.
*/
function istraced(namespace) {
/* istanbul ignore next: tested in a child processs */
if (process.traceDeprecation) {
// --trace-deprecation support
return true
}
var str = process.env.TRACE_DEPRECATION || ''
// namespace traced
return containsNamespace(str, namespace)
}
/**
* Display deprecation message.
*/
function log(message, site) {
var haslisteners = eventListenerCount(process, 'deprecation') !== 0
// abort early if no destination
if (!haslisteners && this._ignored) {
return
}
var caller
var callFile
var callSite
var i = 0
var seen = false
var stack = getStack()
var file = this._file
if (site) {
// provided site
callSite = callSiteLocation(stack[1])
callSite.name = site.name
file = callSite[0]
} else {
// get call site
i = 2
site = callSiteLocation(stack[i])
callSite = site
}
// get caller of deprecated thing in relation to file
for (; i < stack.length; i++) {
caller = callSiteLocation(stack[i])
callFile = caller[0]
if (callFile === file) {
seen = true
} else if (callFile === this._file) {
file = this._file
} else if (seen) {
break
}
}
var key = caller
? site.join(':') + '__' + caller.join(':')
: undefined
if (key !== undefined && key in this._warned) {
// already warned
return
}
this._warned[key] = true
// generate automatic message from call site
if (!message) {
message = callSite === site || !callSite.name
? defaultMessage(site)
: defaultMessage(callSite)
}
// emit deprecation if listeners exist
if (haslisteners) {
var err = DeprecationError(this._namespace, message, stack.slice(i))
process.emit('deprecation', err)
return
}
// format and write message
var format = process.stderr.isTTY
? formatColor
: formatPlain
var msg = format.call(this, message, caller, stack.slice(i))
process.stderr.write(msg + '\n', 'utf8')
return
}
/**
* Get call site location as array.
*/
function callSiteLocation(callSite) {
var file = callSite.getFileName() || '<anonymous>'
var line = callSite.getLineNumber()
var colm = callSite.getColumnNumber()
if (callSite.isEval()) {
file = callSite.getEvalOrigin() + ', ' + file
}
var site = [file, line, colm]
site.callSite = callSite
site.name = callSite.getFunctionName()
return site
}
/**
* Generate a default message from the site.
*/
function defaultMessage(site) {
var callSite = site.callSite
var funcName = site.name
// make useful anonymous name
if (!funcName) {
funcName = '<anonymous@' + formatLocation(site) + '>'
}
var context = callSite.getThis()
var typeName = context && callSite.getTypeName()
// ignore useless type name
if (typeName === 'Object') {
typeName = undefined
}
// make useful type name
if (typeName === 'Function') {
typeName = context.name || typeName
}
return typeName && callSite.getMethodName()
? typeName + '.' + funcName
: funcName
}
/**
* Format deprecation message without color.
*/
function formatPlain(msg, caller, stack) {
var timestamp = new Date().toUTCString()
var formatted = timestamp
+ ' ' + this._namespace
+ ' deprecated ' + msg
// add stack trace
if (this._traced) {
for (var i = 0; i < stack.length; i++) {
formatted += '\n at ' + callSiteToString(stack[i])
}
return formatted
}
if (caller) {
formatted += ' at ' + formatLocation(caller)
}
return formatted
}
/**
* Format deprecation message with color.