parent
1038f3cf20
commit
07129b9b41
@ -1 +0,0 @@
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
module.exports = [
|
||||
{
|
||||
name: 'Count Chocula',
|
||||
location: 'Minneapolis, Minnesota, US',
|
||||
gender: 'm',
|
||||
victims: 2,
|
||||
img: 'https://lh4.googleusercontent.com/-_oirva0sMdA/AAAAAAAAAAI/AAAAAAAAACE/bOsdh9NyZbc/photo.jpg'
|
||||
},{
|
||||
name: 'Dracula',
|
||||
location: 'Transylvania, Romania',
|
||||
gender: 'm',
|
||||
victims: 1238,
|
||||
img: 'http://static2.hypable.com/wp-content/uploads/2012/12/Once-Upon-a-Time-Dracula.png'
|
||||
},{
|
||||
name: 'Elizabeth Bathory ',
|
||||
location: 'Nyírbátor, Hungary',
|
||||
gender: 'f',
|
||||
victims: 980,
|
||||
img: 'http://media.hotbirthdays.com/thumb_x386x415/upload/1560/08/08/elizabeth-bathory.jpg'
|
||||
},{
|
||||
name: 'Lestat',
|
||||
location: 'Auvergne, France',
|
||||
gender: 'm',
|
||||
victims: 324,
|
||||
img: 'https://vapeloungellc.com/wp-content/uploads/2013/03/Lestat.jpg'
|
||||
},{
|
||||
name: 'Louis de Pointe du Lac',
|
||||
location: 'New Orleans, Louisiana, US',
|
||||
gender:'m',
|
||||
victims: 150,
|
||||
img: 'http://img01.deviantart.net/e4fa/i/2009/290/2/7/louis_de_pointe_du_lac_by_alleluia00.jpg'
|
||||
},{
|
||||
name:'Akasha',
|
||||
location: 'Kemet, Egypt',
|
||||
gender: 'f',
|
||||
victims: 210234,
|
||||
img: 'http://www.polyvore.com/cgi/img-thing?.out=jpg&size=l&tid=108498982'
|
||||
},{
|
||||
name: 'Edward Cullen',
|
||||
location: 'Chicago, Illinois, US',
|
||||
gender: 'm',
|
||||
victims: 0,
|
||||
img: 'http://images4.fanpop.com/image/articles/97000/edward-cullen_97754_top.jpg?cache=1299179722'
|
||||
},{
|
||||
name: 'Count Orlok',
|
||||
location: 'Transylvania, Romania',
|
||||
gender: 'm',
|
||||
victims: 99,
|
||||
img: 'http://1.bp.blogspot.com/_k6Blra-PMrc/TC0pG85mI3I/AAAAAAAACFo/tQuVA0Y21XE/s1600/Nosferatu.jpg'
|
||||
}
|
||||
];
|
||||
447
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/HISTORY.md
generated
vendored
447
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/HISTORY.md
generated
vendored
@ -0,0 +1,447 @@
|
||||
1.15.1 / 2016-05-05
|
||||
===================
|
||||
|
||||
* deps: bytes@2.3.0
|
||||
- Drop partial bytes on all parsed units
|
||||
- Fix parsing byte string that looks like hex
|
||||
* deps: raw-body@~2.1.6
|
||||
- deps: bytes@2.3.0
|
||||
* deps: type-is@~1.6.12
|
||||
- deps: mime-types@~2.1.10
|
||||
|
||||
1.15.0 / 2016-02-10
|
||||
===================
|
||||
|
||||
* deps: http-errors@~1.4.0
|
||||
- Add `HttpError` export, for `err instanceof createError.HttpError`
|
||||
- deps: inherits@2.0.1
|
||||
- deps: statuses@'>= 1.2.1 < 2'
|
||||
* deps: qs@6.1.0
|
||||
* deps: type-is@~1.6.11
|
||||
- deps: mime-types@~2.1.9
|
||||
|
||||
1.14.2 / 2015-12-16
|
||||
===================
|
||||
|
||||
* deps: bytes@2.2.0
|
||||
* deps: iconv-lite@0.4.13
|
||||
* deps: qs@5.2.0
|
||||
* deps: raw-body@~2.1.5
|
||||
- deps: bytes@2.2.0
|
||||
- deps: iconv-lite@0.4.13
|
||||
* deps: type-is@~1.6.10
|
||||
- deps: mime-types@~2.1.8
|
||||
|
||||
1.14.1 / 2015-09-27
|
||||
===================
|
||||
|
||||
* Fix issue where invalid charset results in 400 when `verify` used
|
||||
* deps: iconv-lite@0.4.12
|
||||
- Fix CESU-8 decoding in Node.js 4.x
|
||||
* deps: raw-body@~2.1.4
|
||||
- Fix masking critical errors from `iconv-lite`
|
||||
- deps: iconv-lite@0.4.12
|
||||
* deps: type-is@~1.6.9
|
||||
- deps: mime-types@~2.1.7
|
||||
|
||||
1.14.0 / 2015-09-16
|
||||
===================
|
||||
|
||||
* Fix JSON strict parse error to match syntax errors
|
||||
* Provide static `require` analysis in `urlencoded` parser
|
||||
* deps: depd@~1.1.0
|
||||
- Support web browser loading
|
||||
* deps: qs@5.1.0
|
||||
* deps: raw-body@~2.1.3
|
||||
- Fix sync callback when attaching data listener causes sync read
|
||||
* deps: type-is@~1.6.8
|
||||
- Fix type error when given invalid type to match against
|
||||
- deps: mime-types@~2.1.6
|
||||
|
||||
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 `Error`s, 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
|
||||
23
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/LICENSE
generated
vendored
23
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/LICENSE
generated
vendored
@ -0,0 +1,23 @@
|
||||
(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.
|
||||
404
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/README.md
generated
vendored
404
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/README.md
generated
vendored
@ -0,0 +1,404 @@
|
||||
# body-parser
|
||||
|
||||
[![NPM Version][npm-image]][npm-url]
|
||||
[![NPM Downloads][downloads-image]][downloads-url]
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||
[![Gratipay][gratipay-image]][gratipay-url]
|
||||
|
||||
Node.js body parsing middleware.
|
||||
|
||||
_This does not handle multipart bodies_, due to their complex and typically
|
||||
large nature. For multipart bodies, you may be interested in the following
|
||||
modules:
|
||||
|
||||
* [busboy](https://www.npmjs.org/package/busboy#readme) and
|
||||
[connect-busboy](https://www.npmjs.org/package/connect-busboy#readme)
|
||||
* [multiparty](https://www.npmjs.org/package/multiparty#readme) and
|
||||
[connect-multiparty](https://www.npmjs.org/package/connect-multiparty#readme)
|
||||
* [formidable](https://www.npmjs.org/package/formidable#readme)
|
||||
* [multer](https://www.npmjs.org/package/multer#readme)
|
||||
|
||||
This module provides the following parsers:
|
||||
|
||||
* [JSON body parser](#bodyparserjsonoptions)
|
||||
* [Raw body parser](#bodyparserrawoptions)
|
||||
* [Text body parser](#bodyparsertextoptions)
|
||||
* [URL-encoded form body parser](#bodyparserurlencodedoptions)
|
||||
|
||||
Other body parsers you might be interested in:
|
||||
|
||||
- [body](https://www.npmjs.org/package/body#readme)
|
||||
- [co-body](https://www.npmjs.org/package/co-body#readme)
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ npm install body-parser
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var bodyParser = require('body-parser')
|
||||
```
|
||||
|
||||
The `bodyParser` object exposes various factories to create middlewares. All
|
||||
middlewares will populate the `req.body` property with the parsed body, or an
|
||||
empty object (`{}`) if there was no body to parse (or an error was returned).
|
||||
|
||||
The various errors returned by this module are described in the
|
||||
[errors section](#errors).
|
||||
|
||||
### bodyParser.json(options)
|
||||
|
||||
Returns middleware that only parses `json`. This parser accepts any Unicode
|
||||
encoding of the body and supports automatic inflation of `gzip` and `deflate`
|
||||
encodings.
|
||||
|
||||
A new `body` object containing the parsed data is populated on the `request`
|
||||
object after the middleware (i.e. `req.body`).
|
||||
|
||||
#### Options
|
||||
|
||||
The `json` function takes an option `options` object that may contain any of
|
||||
the following keys:
|
||||
|
||||
##### inflate
|
||||
|
||||
When set to `true`, then deflated (compressed) bodies will be inflated; when
|
||||
`false`, deflated bodies are rejected. Defaults to `true`.
|
||||
|
||||
##### limit
|
||||
|
||||
Controls the maximum request body size. If this is a number, then the value
|
||||
specifies the number of bytes; if it is a string, the value is passed to the
|
||||
[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
|
||||
to `'100kb'`.
|
||||
|
||||
##### reviver
|
||||
|
||||
The `reviver` option is passed directly to `JSON.parse` as the second
|
||||
argument. You can find more information on this argument
|
||||
[in the MDN documentation about JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter).
|
||||
|
||||
##### strict
|
||||
|
||||
When set to `true`, will only accept arrays and objects; when `false` will
|
||||
accept anything `JSON.parse` accepts. Defaults to `true`.
|
||||
|
||||
##### type
|
||||
|
||||
The `type` option is used to determine what media type the middleware will
|
||||
parse. This option can be a function or a string. If a string, `type` option
|
||||
is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
|
||||
library and this can be an extension name (like `json`), a mime type (like
|
||||
`application/json`), or a mime type with a wildcard (like `*/*` or `*/json`).
|
||||
If a function, the `type` option is called as `fn(req)` and the request is
|
||||
parsed if it returns a truthy value. Defaults to `application/json`.
|
||||
|
||||
##### verify
|
||||
|
||||
The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
|
||||
where `buf` is a `Buffer` of the raw request body and `encoding` is the
|
||||
encoding of the request. The parsing can be aborted by throwing an error.
|
||||
|
||||
### bodyParser.raw(options)
|
||||
|
||||
Returns middleware that parses all bodies as a `Buffer`. This parser
|
||||
supports automatic inflation of `gzip` and `deflate` encodings.
|
||||
|
||||
A new `body` object containing the parsed data is populated on the `request`
|
||||
object after the middleware (i.e. `req.body`). This will be a `Buffer` object
|
||||
of the body.
|
||||
|
||||
#### Options
|
||||
|
||||
The `raw` function takes an option `options` object that may contain any of
|
||||
the following keys:
|
||||
|
||||
##### inflate
|
||||
|
||||
When set to `true`, then deflated (compressed) bodies will be inflated; when
|
||||
`false`, deflated bodies are rejected. Defaults to `true`.
|
||||
|
||||
##### limit
|
||||
|
||||
Controls the maximum request body size. If this is a number, then the value
|
||||
specifies the number of bytes; if it is a string, the value is passed to the
|
||||
[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
|
||||
to `'100kb'`.
|
||||
|
||||
##### type
|
||||
|
||||
The `type` option is used to determine what media type the middleware will
|
||||
parse. This option can be a function or a string. If a string, `type` option
|
||||
is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
|
||||
library and this can be an extension name (like `bin`), a mime type (like
|
||||
`application/octet-stream`), or a mime type with a wildcard (like `*/*` or
|
||||
`application/*`). If a function, the `type` option is called as `fn(req)`
|
||||
and the request is parsed if it returns a truthy value. Defaults to
|
||||
`application/octet-stream`.
|
||||
|
||||
##### verify
|
||||
|
||||
The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
|
||||
where `buf` is a `Buffer` of the raw request body and `encoding` is the
|
||||
encoding of the request. The parsing can be aborted by throwing an error.
|
||||
|
||||
### bodyParser.text(options)
|
||||
|
||||
Returns middleware that parses all bodies as a string. This parser supports
|
||||
automatic inflation of `gzip` and `deflate` encodings.
|
||||
|
||||
A new `body` string containing the parsed data is populated on the `request`
|
||||
object after the middleware (i.e. `req.body`). This will be a string of the
|
||||
body.
|
||||
|
||||
#### Options
|
||||
|
||||
The `text` function takes an option `options` object that may contain any of
|
||||
the following keys:
|
||||
|
||||
##### defaultCharset
|
||||
|
||||
Specify the default character set for the text content if the charset is not
|
||||
specified in the `Content-Type` header of the request. Defaults to `utf-8`.
|
||||
|
||||
##### inflate
|
||||
|
||||
When set to `true`, then deflated (compressed) bodies will be inflated; when
|
||||
`false`, deflated bodies are rejected. Defaults to `true`.
|
||||
|
||||
##### limit
|
||||
|
||||
Controls the maximum request body size. If this is a number, then the value
|
||||
specifies the number of bytes; if it is a string, the value is passed to the
|
||||
[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
|
||||
to `'100kb'`.
|
||||
|
||||
##### type
|
||||
|
||||
The `type` option is used to determine what media type the middleware will
|
||||
parse. This option can be a function or a string. If a string, `type` option
|
||||
is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
|
||||
library and this can be an extension name (like `txt`), a mime type (like
|
||||
`text/plain`), or a mime type with a wildcard (like `*/*` or `text/*`).
|
||||
If a function, the `type` option is called as `fn(req)` and the request is
|
||||
parsed if it returns a truthy value. Defaults to `text/plain`.
|
||||
|
||||
##### verify
|
||||
|
||||
The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
|
||||
where `buf` is a `Buffer` of the raw request body and `encoding` is the
|
||||
encoding of the request. The parsing can be aborted by throwing an error.
|
||||
|
||||
### bodyParser.urlencoded(options)
|
||||
|
||||
Returns middleware that only parses `urlencoded` bodies. This parser accepts
|
||||
only UTF-8 encoding of the body and supports automatic inflation of `gzip`
|
||||
and `deflate` encodings.
|
||||
|
||||
A new `body` object containing the parsed data is populated on the `request`
|
||||
object after the middleware (i.e. `req.body`). This object will contain
|
||||
key-value pairs, where the value can be a string or array (when `extended` is
|
||||
`false`), or any type (when `extended` is `true`).
|
||||
|
||||
#### Options
|
||||
|
||||
The `urlencoded` function takes an option `options` object that may contain
|
||||
any of the following keys:
|
||||
|
||||
##### extended
|
||||
|
||||
The `extended` option allows to choose between parsing the URL-encoded data
|
||||
with the `querystring` library (when `false`) or the `qs` library (when
|
||||
`true`). The "extended" syntax allows for rich objects and arrays to be
|
||||
encoded into the URL-encoded format, allowing for a JSON-like experience
|
||||
with URL-encoded. For more information, please
|
||||
[see the qs library](https://www.npmjs.org/package/qs#readme).
|
||||
|
||||
Defaults to `true`, but using the default has been deprecated. Please
|
||||
research into the difference between `qs` and `querystring` and choose the
|
||||
appropriate setting.
|
||||
|
||||
##### inflate
|
||||
|
||||
When set to `true`, then deflated (compressed) bodies will be inflated; when
|
||||
`false`, deflated bodies are rejected. Defaults to `true`.
|
||||
|
||||
##### limit
|
||||
|
||||
Controls the maximum request body size. If this is a number, then the value
|
||||
specifies the number of bytes; if it is a string, the value is passed to the
|
||||
[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
|
||||
to `'100kb'`.
|
||||
|
||||
##### parameterLimit
|
||||
|
||||
The `parameterLimit` option controls the maximum number of parameters that
|
||||
are allowed in the URL-encoded data. If a request contains more parameters
|
||||
than this value, a 413 will be returned to the client. Defaults to `1000`.
|
||||
|
||||
##### type
|
||||
|
||||
The `type` option is used to determine what media type the middleware will
|
||||
parse. This option can be a function or a string. If a string, `type` option
|
||||
is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
|
||||
library and this can be an extension name (like `urlencoded`), a mime type (like
|
||||
`application/x-www-form-urlencoded`), or a mime type with a wildcard (like
|
||||
`*/x-www-form-urlencoded`). If a function, the `type` option is called as
|
||||
`fn(req)` and the request is parsed if it returns a truthy value. Defaults
|
||||
to `application/x-www-form-urlencoded`.
|
||||
|
||||
##### verify
|
||||
|
||||
The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
|
||||
where `buf` is a `Buffer` of the raw request body and `encoding` is the
|
||||
encoding of the request. The parsing can be aborted by throwing an error.
|
||||
|
||||
## Errors
|
||||
|
||||
The middlewares provided by this module create errors depending on the error
|
||||
condition during parsing. The errors will typically have a `status` property
|
||||
that contains the suggested HTTP response code and a `body` property containing
|
||||
the read body, if available.
|
||||
|
||||
The following are the common errors emitted, though any error can come through
|
||||
for various reasons.
|
||||
|
||||
### content encoding unsupported
|
||||
|
||||
This error will occur when the request had a `Content-Encoding` header that
|
||||
contained an encoding but the "inflation" option was set to `false`. The
|
||||
`status` property is set to `415`.
|
||||
|
||||
### request aborted
|
||||
|
||||
This error will occur when the request is aborted by the client before reading
|
||||
the body has finished. The `received` property will be set to the number of
|
||||
bytes received before the request was aborted and the `expected` property is
|
||||
set to the number of expected bytes. The `status` property is set to `400`.
|
||||
|
||||
### request entity too large
|
||||
|
||||
This error will occur when the request body's size is larger than the "limit"
|
||||
option. The `limit` property will be set to the byte limit and the `length`
|
||||
property will be set to the request body's length. The `status` property is
|
||||
set to `413`.
|
||||
|
||||
### request size did not match content length
|
||||
|
||||
This error will occur when the request's length did not match the length from
|
||||
the `Content-Length` header. This typically occurs when the request is malformed,
|
||||
typically when the `Content-Length` header was calculated based on characters
|
||||
instead of bytes. The `status` property is set to `400`.
|
||||
|
||||
### stream encoding should not be set
|
||||
|
||||
This error will occur when something called the `req.setEncoding` method prior
|
||||
to this middleware. This module operates directly on bytes only and you cannot
|
||||
call `req.setEncoding` when using this module. The `status` property is set to
|
||||
`500`.
|
||||
|
||||
### unsupported charset "BOGUS"
|
||||
|
||||
This error will occur when the request had a charset parameter in the
|
||||
`Content-Type` header, but the `iconv-lite` module does not support it OR the
|
||||
parser does not support it. The charset is contained in the message as well
|
||||
as in the `charset` property. The `status` property is set to `415`.
|
||||
|
||||
### unsupported content encoding "bogus"
|
||||
|
||||
This error will occur when the request had a `Content-Encoding` header that
|
||||
contained an unsupported encoding. The encoding is contained in the message
|
||||
as well as in the `encoding` property. The `status` property is set to `415`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Express/Connect top-level generic
|
||||
|
||||
This example demonstrates adding a generic JSON and URL-encoded parser as a
|
||||
top-level middleware, which will parse the bodies of all incoming requests.
|
||||
This is the simplest setup.
|
||||
|
||||
```js
|
||||
var express = require('express')
|
||||
var bodyParser = require('body-parser')
|
||||
|
||||
var app = express()
|
||||
|
||||
// parse application/x-www-form-urlencoded
|
||||
app.use(bodyParser.urlencoded({ extended: false }))
|
||||
|
||||
// parse application/json
|
||||
app.use(bodyParser.json())
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.setHeader('Content-Type', 'text/plain')
|
||||
res.write('you posted:\n')
|
||||
res.end(JSON.stringify(req.body, null, 2))
|
||||
})
|
||||
```
|
||||
|
||||
### Express route-specific
|
||||
|
||||
This example demonstrates adding body parsers specifically to the routes that
|
||||
need them. In general, this is the most recommended way to use body-parser with
|
||||
Express.
|
||||
|
||||
```js
|
||||
var express = require('express')
|
||||
var bodyParser = require('body-parser')
|
||||
|
||||
var app = express()
|
||||
|
||||
// create application/json parser
|
||||
var jsonParser = bodyParser.json()
|
||||
|
||||
// create application/x-www-form-urlencoded parser
|
||||
var urlencodedParser = bodyParser.urlencoded({ extended: false })
|
||||
|
||||
// POST /login gets urlencoded bodies
|
||||
app.post('/login', urlencodedParser, function (req, res) {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
res.send('welcome, ' + req.body.username)
|
||||
})
|
||||
|
||||
// POST /api/users gets JSON bodies
|
||||
app.post('/api/users', jsonParser, function (req, res) {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
// create user in req.body
|
||||
})
|
||||
```
|
||||
|
||||
### Change accepted type for parsers
|
||||
|
||||
All the parsers accept a `type` option which allows you to change the
|
||||
`Content-Type` that the middleware will parse.
|
||||
|
||||
```js
|
||||
// parse various different custom JSON types as JSON
|
||||
app.use(bodyParser.json({ type: 'application/*+json' }))
|
||||
|
||||
// parse some custom thing into a Buffer
|
||||
app.use(bodyParser.raw({ type: 'application/vnd.custom-type' }))
|
||||
|
||||
// parse an HTML body into a string
|
||||
app.use(bodyParser.text({ type: 'text/html' }))
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/body-parser.svg
|
||||
[npm-url]: https://npmjs.org/package/body-parser
|
||||
[travis-image]: https://img.shields.io/travis/expressjs/body-parser/master.svg
|
||||
[travis-url]: https://travis-ci.org/expressjs/body-parser
|
||||
[coveralls-image]: https://img.shields.io/coveralls/expressjs/body-parser/master.svg
|
||||
[coveralls-url]: https://coveralls.io/r/expressjs/body-parser?branch=master
|
||||
[downloads-image]: https://img.shields.io/npm/dm/body-parser.svg
|
||||
[downloads-url]: https://npmjs.org/package/body-parser
|
||||
[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
|
||||
[gratipay-url]: https://www.gratipay.com/dougwilson/
|
||||
157
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/index.js
generated
vendored
157
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/index.js
generated
vendored
@ -0,0 +1,157 @@
|
||||
/*!
|
||||
* 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
|
||||
}
|
||||
188
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/lib/read.js
generated
vendored
188
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/lib/read.js
generated
vendored
@ -0,0 +1,188 @@
|
||||
/*!
|
||||
* 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 opts = options || {}
|
||||
var stream
|
||||
|
||||
// flag as parsed
|
||||
req._body = true
|
||||
|
||||
// read options
|
||||
var encoding = opts.encoding !== null
|
||||
? opts.encoding || 'utf-8'
|
||||
: null
|
||||
var verify = opts.verify
|
||||
|
||||
try {
|
||||
// get the content stream
|
||||
stream = contentstream(req, debug, opts.inflate)
|
||||
length = stream.length
|
||||
stream.length = undefined
|
||||
} catch (err) {
|
||||
return next(err)
|
||||
}
|
||||
|
||||
// set raw-body options
|
||||
opts.length = length
|
||||
opts.encoding = verify
|
||||
? null
|
||||
: encoding
|
||||
|
||||
// assert charset is supported
|
||||
if (opts.encoding === null && encoding !== null && !iconv.encodingExists(encoding)) {
|
||||
return next(createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
|
||||
charset: encoding.toLowerCase()
|
||||
}))
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
170
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/lib/types/json.js
generated
vendored
170
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/lib/types/json.js
generated
vendored
@ -0,0 +1,170 @@
|
||||
/*!
|
||||
* 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 SyntaxError('Unexpected token ' + first)
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
/*!
|
||||
* 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))
|
||||
}
|
||||
}
|
||||
115
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/lib/types/text.js
generated
vendored
115
server_hw_resources/3_vampires_express_solution/node_modules/body-parser/lib/types/text.js
generated
vendored
@ -0,0 +1,115 @@
|
||||
/*!
|
||||
* 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))
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,273 @@
|
||||
/*!
|
||||
* 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, {
|
||||
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 !== undefined) {
|
||||
return mod.parse
|
||||
}
|
||||
|
||||
// this uses a switch for static require analysis
|
||||
switch (name) {
|
||||
case 'qs':
|
||||
mod = require('qs')
|
||||
break
|
||||
case 'querystring':
|
||||
mod = require('querystring')
|
||||
break
|
||||
}
|
||||
|
||||
// store to prevent invoking require()
|
||||
parsers[name] = mod
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
2.3.0 / 2016-02-15
|
||||
==================
|
||||
|
||||
* Drop partial bytes on all parsed units
|
||||
* Fix non-finite numbers to `.format` to return `null`
|
||||
* Fix parsing byte string that looks like hex
|
||||
* perf: hoist regular expressions
|
||||
|
||||
2.2.0 / 2015-11-13
|
||||
==================
|
||||
|
||||
* add option "decimalPlaces"
|
||||
* add option "fixedDecimals"
|
||||
|
||||
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]
|
||||
@ -0,0 +1,23 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2012-2014 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2015 Jed Watson <jed.watson@me.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.
|
||||
@ -0,0 +1,109 @@
|
||||
# Bytes utility
|
||||
|
||||
[![NPM Version][npm-image]][npm-url]
|
||||
[![NPM Downloads][downloads-image]][downloads-url]
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
|
||||
Utility to parse a string bytes (ex: `1TB`) to bytes (`1099511627776`) and vice-versa.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
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 |
|
||||
|-------------------|--------|-----------------------------------------------------------------------------------------|
|
||||
| decimalPlaces | `number`|`null` | Maximum number of decimal places to include in output. Default value to `2`. |
|
||||
| fixedDecimals | `boolean`|`null` | Whether to always display the maximum number of decimal places. Default value to `false` |
|
||||
| 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**
|
||||
|
||||
```js
|
||||
bytes(1024);
|
||||
// output: '1kB'
|
||||
|
||||
bytes(1000);
|
||||
// output: '1000B'
|
||||
|
||||
bytes(1000, {thousandsSeparator: ' '});
|
||||
// output: '1 000B'
|
||||
|
||||
bytes(1024 * 1.7, {decimalPlaces: 0});
|
||||
// output: '2kB'
|
||||
```
|
||||
|
||||
#### 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.
|
||||
|
||||
Supported units and abbreviations are as follows and are case-insensitive:
|
||||
|
||||
* "b" for bytes
|
||||
* "kb" for kilobytes
|
||||
* "mb" for megabytes
|
||||
* "gb" for gigabytes
|
||||
* "tb" for terabytes
|
||||
|
||||
The units are in powers of two, not ten. This means 1kb = 1024b according to this parser.
|
||||
|
||||
**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**
|
||||
|
||||
```js
|
||||
bytes('1kB');
|
||||
// output: 1024
|
||||
|
||||
bytes('1024');
|
||||
// output: 1024
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install bytes --save
|
||||
component install visionmedia/bytes.js
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[](https://github.com/visionmedia/bytes.js/blob/master/LICENSE)
|
||||
|
||||
[downloads-image]: https://img.shields.io/npm/dm/bytes.svg
|
||||
[downloads-url]: https://npmjs.org/package/bytes
|
||||
[npm-image]: https://img.shields.io/npm/v/bytes.svg
|
||||
[npm-url]: https://npmjs.org/package/bytes
|
||||
[travis-image]: https://img.shields.io/travis/visionmedia/bytes.js/master.svg
|
||||
[travis-url]: https://travis-ci.org/visionmedia/bytes.js
|
||||
@ -0,0 +1,154 @@
|
||||
/*!
|
||||
* 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 formatThousandsRegExp = /\B(?=(\d{3})+(?!\d))/g;
|
||||
|
||||
var formatDecimalsRegExp = /(?:\.0*|(\.[^0]+)0+)$/;
|
||||
|
||||
var map = {
|
||||
b: 1,
|
||||
kb: 1 << 10,
|
||||
mb: 1 << 20,
|
||||
gb: 1 << 30,
|
||||
tb: ((1 << 30) * 1024)
|
||||
};
|
||||
|
||||
// TODO: use is-finite module?
|
||||
var numberIsFinite = Number.isFinite || function (v) { return typeof v === 'number' && isFinite(v); };
|
||||
|
||||
var parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb)$/i;
|
||||
|
||||
/**
|
||||
* 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],
|
||||
* decimalPlaces: [number]
|
||||
* fixedDecimals: [boolean]
|
||||
* 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 {number} [options.decimalPlaces=2]
|
||||
* @param {number} [options.fixedDecimals=false]
|
||||
* @param {string} [options.thousandsSeparator=]
|
||||
*
|
||||
* @returns {string|null}
|
||||
* @public
|
||||
*/
|
||||
|
||||
function format(value, options) {
|
||||
if (!numberIsFinite(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var mag = Math.abs(value);
|
||||
var thousandsSeparator = (options && options.thousandsSeparator) || '';
|
||||
var decimalPlaces = (options && options.decimalPlaces !== undefined) ? options.decimalPlaces : 2;
|
||||
var fixedDecimals = Boolean(options && options.fixedDecimals);
|
||||
var unit = 'B';
|
||||
|
||||
if (mag >= map.tb) {
|
||||
unit = 'TB';
|
||||
} else if (mag >= map.gb) {
|
||||
unit = 'GB';
|
||||
} else if (mag >= map.mb) {
|
||||
unit = 'MB';
|
||||
} else if (mag >= map.kb) {
|
||||
unit = 'kB';
|
||||
}
|
||||
|
||||
var val = value / map[unit.toLowerCase()];
|
||||
var str = val.toFixed(decimalPlaces);
|
||||
|
||||
if (!fixedDecimals) {
|
||||
str = str.replace(formatDecimalsRegExp, '$1');
|
||||
}
|
||||
|
||||
if (thousandsSeparator) {
|
||||
str = str.replace(formatThousandsRegExp, thousandsSeparator);
|
||||
}
|
||||
|
||||
return str + 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
|
||||
*
|
||||
* @returns {number|null}
|
||||
* @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 = parseRegExp.exec(val);
|
||||
var floatValue;
|
||||
var unit = 'b';
|
||||
|
||||
if (!results) {
|
||||
// Nothing could be extracted from the given string
|
||||
floatValue = parseInt(val, 10);
|
||||
unit = 'b'
|
||||
} else {
|
||||
// Retrieve the value and the unit
|
||||
floatValue = parseFloat(results[1]);
|
||||
unit = results[4].toLowerCase();
|
||||
}
|
||||
|
||||
return Math.floor(map[unit] * floatValue);
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
{
|
||||
"name": "bytes",
|
||||
"description": "Utility to parse a string bytes to bytes and vice-versa",
|
||||
"version": "2.3.0",
|
||||
"author": {
|
||||
"name": "TJ Holowaychuk",
|
||||
"email": "tj@vision-media.ca",
|
||||
"url": "http://tjholowaychuk.com"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Jed Watson",
|
||||
"email": "jed.watson@me.com"
|
||||
},
|
||||
{
|
||||
"name": "Théo FIDRY",
|
||||
"email": "theo.fidry@gmail.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": "1.21.5"
|
||||
},
|
||||
"files": [
|
||||
"History.md",
|
||||
"LICENSE",
|
||||
"Readme.md",
|
||||
"index.js"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "mocha --check-leaks --reporter spec"
|
||||
},
|
||||
"gitHead": "c8be41b24b04e04992d5918356d5a4dd35fbf805",
|
||||
"bugs": {
|
||||
"url": "https://github.com/visionmedia/bytes.js/issues"
|
||||
},
|
||||
"homepage": "https://github.com/visionmedia/bytes.js#readme",
|
||||
"_id": "bytes@2.3.0",
|
||||
"_shasum": "d5b680a165b6201739acb611542aabc2d8ceb070",
|
||||
"_from": "bytes@2.3.0",
|
||||
"_npmVersion": "2.14.7",
|
||||
"_nodeVersion": "4.2.3",
|
||||
"_npmUser": {
|
||||
"name": "dougwilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
"dist": {
|
||||
"shasum": "d5b680a165b6201739acb611542aabc2d8ceb070",
|
||||
"tarball": "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "dougwilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
{
|
||||
"name": "tjholowaychuk",
|
||||
"email": "tj@vision-media.ca"
|
||||
}
|
||||
],
|
||||
"_npmOperationalInternal": {
|
||||
"host": "packages-6-west.internal.npmjs.com",
|
||||
"tmp": "tmp/bytes-2.3.0.tgz_1455595208428_0.5990735022351146"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz"
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
1.0.2 / 2016-05-09
|
||||
==================
|
||||
|
||||
* perf: enable strict mode
|
||||
|
||||
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`
|
||||
@ -0,0 +1,22 @@
|
||||
(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.
|
||||
@ -0,0 +1,92 @@
|
||||
# content-type
|
||||
|
||||
[![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]
|
||||
|
||||
Create and parse HTTP Content-Type header according to RFC 7231
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ npm install content-type
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var contentType = require('content-type')
|
||||
```
|
||||
|
||||
### contentType.parse(string)
|
||||
|
||||
```js
|
||||
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)
|
||||
|
||||
```js
|
||||
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)
|
||||
|
||||
```js
|
||||
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)
|
||||
|
||||
```js
|
||||
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](LICENSE)
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/content-type.svg
|
||||
[npm-url]: https://npmjs.org/package/content-type
|
||||
[node-version-image]: https://img.shields.io/node/v/content-type.svg
|
||||
[node-version-url]: http://nodejs.org/download/
|
||||
[travis-image]: https://img.shields.io/travis/jshttp/content-type/master.svg
|
||||
[travis-url]: https://travis-ci.org/jshttp/content-type
|
||||
[coveralls-image]: https://img.shields.io/coveralls/jshttp/content-type/master.svg
|
||||
[coveralls-url]: https://coveralls.io/r/jshttp/content-type
|
||||
[downloads-image]: https://img.shields.io/npm/dm/content-type.svg
|
||||
[downloads-url]: https://npmjs.org/package/content-type
|
||||
@ -0,0 +1,216 @@
|
||||
/*!
|
||||
* content-type
|
||||
* Copyright(c) 2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "content-type",
|
||||
"description": "Create and parse HTTP Content-Type header",
|
||||
"version": "1.0.2",
|
||||
"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.4.3",
|
||||
"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": "8118763adfbbac80cf1254191889330aec8b8be7",
|
||||
"bugs": {
|
||||
"url": "https://github.com/jshttp/content-type/issues"
|
||||
},
|
||||
"homepage": "https://github.com/jshttp/content-type#readme",
|
||||
"_id": "content-type@1.0.2",
|
||||
"_shasum": "b7d113aee7a8dd27bd21133c4dc2529df1721eed",
|
||||
"_from": "content-type@>=1.0.1 <1.1.0",
|
||||
"_npmVersion": "2.15.1",
|
||||
"_nodeVersion": "4.4.3",
|
||||
"_npmUser": {
|
||||
"name": "dougwilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
"dist": {
|
||||
"shasum": "b7d113aee7a8dd27bd21133c4dc2529df1721eed",
|
||||
"tarball": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "dougwilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
}
|
||||
],
|
||||
"_npmOperationalInternal": {
|
||||
"host": "packages-12-west.internal.npmjs.com",
|
||||
"tmp": "tmp/content-type-1.0.2.tgz_1462852785748_0.5491233412176371"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"laxbreak": true
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
support
|
||||
test
|
||||
examples
|
||||
example
|
||||
*.sock
|
||||
dist
|
||||
@ -0,0 +1,195 @@
|
||||
|
||||
2.2.0 / 2015-05-09
|
||||
==================
|
||||
|
||||
* package: update "ms" to v0.7.1 (#202, @dougwilson)
|
||||
* README: add logging to file example (#193, @DanielOchoa)
|
||||
* README: fixed a typo (#191, @amir-s)
|
||||
* browser: expose `storage` (#190, @stephenmathieson)
|
||||
* Makefile: add a `distclean` target (#189, @stephenmathieson)
|
||||
|
||||
2.1.3 / 2015-03-13
|
||||
==================
|
||||
|
||||
* Updated stdout/stderr example (#186)
|
||||
* Updated example/stdout.js to match debug current behaviour
|
||||
* Renamed example/stderr.js to stdout.js
|
||||
* Update Readme.md (#184)
|
||||
* replace high intensity foreground color for bold (#182, #183)
|
||||
|
||||
2.1.2 / 2015-03-01
|
||||
==================
|
||||
|
||||
* dist: recompile
|
||||
* update "ms" to v0.7.0
|
||||
* package: update "browserify" to v9.0.3
|
||||
* component: fix "ms.js" repo location
|
||||
* changed bower package name
|
||||
* updated documentation about using debug in a browser
|
||||
* fix: security error on safari (#167, #168, @yields)
|
||||
|
||||
2.1.1 / 2014-12-29
|
||||
==================
|
||||
|
||||
* browser: use `typeof` to check for `console` existence
|
||||
* browser: check for `console.log` truthiness (fix IE 8/9)
|
||||
* browser: add support for Chrome apps
|
||||
* Readme: added Windows usage remarks
|
||||
* Add `bower.json` to properly support bower install
|
||||
|
||||
2.1.0 / 2014-10-15
|
||||
==================
|
||||
|
||||
* node: implement `DEBUG_FD` env variable support
|
||||
* package: update "browserify" to v6.1.0
|
||||
* package: add "license" field to package.json (#135, @panuhorsmalahti)
|
||||
|
||||
2.0.0 / 2014-09-01
|
||||
==================
|
||||
|
||||
* package: update "browserify" to v5.11.0
|
||||
* node: use stderr rather than stdout for logging (#29, @stephenmathieson)
|
||||
|
||||
1.0.4 / 2014-07-15
|
||||
==================
|
||||
|
||||
* dist: recompile
|
||||
* example: remove `console.info()` log usage
|
||||
* example: add "Content-Type" UTF-8 header to browser example
|
||||
* browser: place %c marker after the space character
|
||||
* browser: reset the "content" color via `color: inherit`
|
||||
* browser: add colors support for Firefox >= v31
|
||||
* debug: prefer an instance `log()` function over the global one (#119)
|
||||
* Readme: update documentation about styled console logs for FF v31 (#116, @wryk)
|
||||
|
||||
1.0.3 / 2014-07-09
|
||||
==================
|
||||
|
||||
* Add support for multiple wildcards in namespaces (#122, @seegno)
|
||||
* browser: fix lint
|
||||
|
||||
1.0.2 / 2014-06-10
|
||||
==================
|
||||
|
||||
* browser: update color palette (#113, @gscottolson)
|
||||
* common: make console logging function configurable (#108, @timoxley)
|
||||
* node: fix %o colors on old node <= 0.8.x
|
||||
* Makefile: find node path using shell/which (#109, @timoxley)
|
||||
|
||||
1.0.1 / 2014-06-06
|
||||
==================
|
||||
|
||||
* browser: use `removeItem()` to clear localStorage
|
||||
* browser, node: don't set DEBUG if namespaces is undefined (#107, @leedm777)
|
||||
* package: add "contributors" section
|
||||
* node: fix comment typo
|
||||
* README: list authors
|
||||
|
||||
1.0.0 / 2014-06-04
|
||||
==================
|
||||
|
||||
* make ms diff be global, not be scope
|
||||
* debug: ignore empty strings in enable()
|
||||
* node: make DEBUG_COLORS able to disable coloring
|
||||
* *: export the `colors` array
|
||||
* npmignore: don't publish the `dist` dir
|
||||
* Makefile: refactor to use browserify
|
||||
* package: add "browserify" as a dev dependency
|
||||
* Readme: add Web Inspector Colors section
|
||||
* node: reset terminal color for the debug content
|
||||
* node: map "%o" to `util.inspect()`
|
||||
* browser: map "%j" to `JSON.stringify()`
|
||||
* debug: add custom "formatters"
|
||||
* debug: use "ms" module for humanizing the diff
|
||||
* Readme: add "bash" syntax highlighting
|
||||
* browser: add Firebug color support
|
||||
* browser: add colors for WebKit browsers
|
||||
* node: apply log to `console`
|
||||
* rewrite: abstract common logic for Node & browsers
|
||||
* add .jshintrc file
|
||||
|
||||
0.8.1 / 2014-04-14
|
||||
==================
|
||||
|
||||
* package: re-add the "component" section
|
||||
|
||||
0.8.0 / 2014-03-30
|
||||
==================
|
||||
|
||||
* add `enable()` method for nodejs. Closes #27
|
||||
* change from stderr to stdout
|
||||
* remove unnecessary index.js file
|
||||
|
||||
0.7.4 / 2013-11-13
|
||||
==================
|
||||
|
||||
* remove "browserify" key from package.json (fixes something in browserify)
|
||||
|
||||
0.7.3 / 2013-10-30
|
||||
==================
|
||||
|
||||
* fix: catch localStorage security error when cookies are blocked (Chrome)
|
||||
* add debug(err) support. Closes #46
|
||||
* add .browser prop to package.json. Closes #42
|
||||
|
||||
0.7.2 / 2013-02-06
|
||||
==================
|
||||
|
||||
* fix package.json
|
||||
* fix: Mobile Safari (private mode) is broken with debug
|
||||
* fix: Use unicode to send escape character to shell instead of octal to work with strict mode javascript
|
||||
|
||||
0.7.1 / 2013-02-05
|
||||
==================
|
||||
|
||||
* add repository URL to package.json
|
||||
* add DEBUG_COLORED to force colored output
|
||||
* add browserify support
|
||||
* fix component. Closes #24
|
||||
|
||||
0.7.0 / 2012-05-04
|
||||
==================
|
||||
|
||||
* Added .component to package.json
|
||||
* Added debug.component.js build
|
||||
|
||||
0.6.0 / 2012-03-16
|
||||
==================
|
||||
|
||||
* Added support for "-" prefix in DEBUG [Vinay Pulim]
|
||||
* Added `.enabled` flag to the node version [TooTallNate]
|
||||
|
||||
0.5.0 / 2012-02-02
|
||||
==================
|
||||
|
||||
* Added: humanize diffs. Closes #8
|
||||
* Added `debug.disable()` to the CS variant
|
||||
* Removed padding. Closes #10
|
||||
* Fixed: persist client-side variant again. Closes #9
|
||||
|
||||
0.4.0 / 2012-02-01
|
||||
==================
|
||||
|
||||
* Added browser variant support for older browsers [TooTallNate]
|
||||
* Added `debug.enable('project:*')` to browser variant [TooTallNate]
|
||||
* Added padding to diff (moved it to the right)
|
||||
|
||||
0.3.0 / 2012-01-26
|
||||
==================
|
||||
|
||||
* Added millisecond diff when isatty, otherwise UTC string
|
||||
|
||||
0.2.0 / 2012-01-22
|
||||
==================
|
||||
|
||||
* Added wildcard support
|
||||
|
||||
0.1.0 / 2011-12-02
|
||||
==================
|
||||
|
||||
* Added: remove colors unless stderr isatty [TooTallNate]
|
||||
|
||||
0.0.1 / 2010-01-03
|
||||
==================
|
||||
|
||||
* Initial release
|
||||
@ -0,0 +1,36 @@
|
||||
|
||||
# get Makefile directory name: http://stackoverflow.com/a/5982798/376773
|
||||
THIS_MAKEFILE_PATH:=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
|
||||
THIS_DIR:=$(shell cd $(dir $(THIS_MAKEFILE_PATH));pwd)
|
||||
|
||||
# BIN directory
|
||||
BIN := $(THIS_DIR)/node_modules/.bin
|
||||
|
||||
# applications
|
||||
NODE ?= $(shell which node)
|
||||
NPM ?= $(NODE) $(shell which npm)
|
||||
BROWSERIFY ?= $(NODE) $(BIN)/browserify
|
||||
|
||||
all: dist/debug.js
|
||||
|
||||
install: node_modules
|
||||
|
||||
clean:
|
||||
@rm -rf dist
|
||||
|
||||
dist:
|
||||
@mkdir -p $@
|
||||
|
||||
dist/debug.js: node_modules browser.js debug.js dist
|
||||
@$(BROWSERIFY) \
|
||||
--standalone debug \
|
||||
. > $@
|
||||
|
||||
distclean: clean
|
||||
@rm -rf node_modules
|
||||
|
||||
node_modules: package.json
|
||||
@NODE_ENV= $(NPM) install
|
||||
@touch node_modules
|
||||
|
||||
.PHONY: all install clean distclean
|
||||
@ -0,0 +1,188 @@
|
||||
# debug
|
||||
|
||||
tiny node.js debugging utility modelled after node core's debugging technique.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install debug
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.
|
||||
|
||||
Example _app.js_:
|
||||
|
||||
```js
|
||||
var debug = require('debug')('http')
|
||||
, http = require('http')
|
||||
, name = 'My App';
|
||||
|
||||
// fake app
|
||||
|
||||
debug('booting %s', name);
|
||||
|
||||
http.createServer(function(req, res){
|
||||
debug(req.method + ' ' + req.url);
|
||||
res.end('hello\n');
|
||||
}).listen(3000, function(){
|
||||
debug('listening');
|
||||
});
|
||||
|
||||
// fake worker of some kind
|
||||
|
||||
require('./worker');
|
||||
```
|
||||
|
||||
Example _worker.js_:
|
||||
|
||||
```js
|
||||
var debug = require('debug')('worker');
|
||||
|
||||
setInterval(function(){
|
||||
debug('doing some work');
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### Windows note
|
||||
|
||||
On Windows the environment variable is set using the `set` command.
|
||||
|
||||
```cmd
|
||||
set DEBUG=*,-not_this
|
||||
```
|
||||
|
||||
Then, run the program to be debugged as usual.
|
||||
|
||||
## Millisecond diff
|
||||
|
||||
When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.
|
||||
|
||||

|
||||
|
||||
When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:
|
||||
|
||||

|
||||
|
||||
## Conventions
|
||||
|
||||
If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser".
|
||||
|
||||
## Wildcards
|
||||
|
||||
The `*` character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect:compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.
|
||||
|
||||
You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=*,-connect:*` would include all debuggers except those starting with "connect:".
|
||||
|
||||
## Browser support
|
||||
|
||||
Debug works in the browser as well, currently persisted by `localStorage`. Consider the situation shown below where you have `worker:a` and `worker:b`, and wish to debug both. Somewhere in the code on your page, include:
|
||||
|
||||
```js
|
||||
window.myDebug = require("debug");
|
||||
```
|
||||
|
||||
("debug" is a global object in the browser so we give this object a different name.) When your page is open in the browser, type the following in the console:
|
||||
|
||||
```js
|
||||
myDebug.enable("worker:*")
|
||||
```
|
||||
|
||||
Refresh the page. Debug output will continue to be sent to the console until it is disabled by typing `myDebug.disable()` in the console.
|
||||
|
||||
```js
|
||||
a = debug('worker:a');
|
||||
b = debug('worker:b');
|
||||
|
||||
setInterval(function(){
|
||||
a('doing some work');
|
||||
}, 1000);
|
||||
|
||||
setInterval(function(){
|
||||
b('doing some work');
|
||||
}, 1200);
|
||||
```
|
||||
|
||||
#### Web Inspector Colors
|
||||
|
||||
Colors are also enabled on "Web Inspectors" that understand the `%c` formatting
|
||||
option. These are WebKit web inspectors, Firefox ([since version
|
||||
31](https://hacks.mozilla.org/2014/05/editable-box-model-multiple-selection-sublime-text-keys-much-more-firefox-developer-tools-episode-31/))
|
||||
and the Firebug plugin for Firefox (any version).
|
||||
|
||||
Colored output looks something like:
|
||||
|
||||

|
||||
|
||||
### stderr vs stdout
|
||||
|
||||
You can set an alternative logging method per-namespace by overriding the `log` method on a per-namespace or globally:
|
||||
|
||||
Example _stdout.js_:
|
||||
|
||||
```js
|
||||
var debug = require('debug');
|
||||
var error = debug('app:error');
|
||||
|
||||
// by default stderr is used
|
||||
error('goes to stderr!');
|
||||
|
||||
var log = debug('app:log');
|
||||
// set this namespace to log via console.log
|
||||
log.log = console.log.bind(console); // don't forget to bind to console!
|
||||
log('goes to stdout');
|
||||
error('still goes to stderr!');
|
||||
|
||||
// set all output to go via console.info
|
||||
// overrides all per-namespace log settings
|
||||
debug.log = console.info.bind(console);
|
||||
error('now goes to stdout via console.info');
|
||||
log('still goes to stdout, but via console.info now');
|
||||
```
|
||||
|
||||
### Save debug output to a file
|
||||
|
||||
You can save all debug statements to a file by piping them.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
$ DEBUG_FD=3 node your-app.js 3> whatever.log
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
- TJ Holowaychuk
|
||||
- Nathan Rajlich
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
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.
|
||||
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "visionmedia-debug",
|
||||
"main": "dist/debug.js",
|
||||
"version": "2.2.0",
|
||||
"homepage": "https://github.com/visionmedia/debug",
|
||||
"authors": [
|
||||
"TJ Holowaychuk <tj@vision-media.ca>"
|
||||
],
|
||||
"description": "visionmedia-debug",
|
||||
"moduleType": [
|
||||
"amd",
|
||||
"es6",
|
||||
"globals",
|
||||
"node"
|
||||
],
|
||||
"keywords": [
|
||||
"visionmedia",
|
||||
"debug"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,168 @@
|
||||
|
||||
/**
|
||||
* This is the web browser implementation of `debug()`.
|
||||
*
|
||||
* Expose `debug()` as the module.
|
||||
*/
|
||||
|
||||
exports = module.exports = require('./debug');
|
||||
exports.log = log;
|
||||
exports.formatArgs = formatArgs;
|
||||
exports.save = save;
|
||||
exports.load = load;
|
||||
exports.useColors = useColors;
|
||||
exports.storage = 'undefined' != typeof chrome
|
||||
&& 'undefined' != typeof chrome.storage
|
||||
? chrome.storage.local
|
||||
: localstorage();
|
||||
|
||||
/**
|
||||
* Colors.
|
||||
*/
|
||||
|
||||
exports.colors = [
|
||||
'lightseagreen',
|
||||
'forestgreen',
|
||||
'goldenrod',
|
||||
'dodgerblue',
|
||||
'darkorchid',
|
||||
'crimson'
|
||||
];
|
||||
|
||||
/**
|
||||
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
|
||||
* and the Firebug extension (any Firefox version) are known
|
||||
* to support "%c" CSS customizations.
|
||||
*
|
||||
* TODO: add a `localStorage` variable to explicitly enable/disable colors
|
||||
*/
|
||||
|
||||
function useColors() {
|
||||
// is webkit? http://stackoverflow.com/a/16459606/376773
|
||||
return ('WebkitAppearance' in document.documentElement.style) ||
|
||||
// is firebug? http://stackoverflow.com/a/398120/376773
|
||||
(window.console && (console.firebug || (console.exception && console.table))) ||
|
||||
// is firefox >= v31?
|
||||
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
|
||||
(navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
|
||||
*/
|
||||
|
||||
exports.formatters.j = function(v) {
|
||||
return JSON.stringify(v);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Colorize log arguments if enabled.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function formatArgs() {
|
||||
var args = arguments;
|
||||
var useColors = this.useColors;
|
||||
|
||||
args[0] = (useColors ? '%c' : '')
|
||||
+ this.namespace
|
||||
+ (useColors ? ' %c' : ' ')
|
||||
+ args[0]
|
||||
+ (useColors ? '%c ' : ' ')
|
||||
+ '+' + exports.humanize(this.diff);
|
||||
|
||||
if (!useColors) return args;
|
||||
|
||||
var c = 'color: ' + this.color;
|
||||
args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
|
||||
|
||||
// the final "%c" is somewhat tricky, because there could be other
|
||||
// arguments passed either before or after the %c, so we need to
|
||||
// figure out the correct index to insert the CSS into
|
||||
var index = 0;
|
||||
var lastC = 0;
|
||||
args[0].replace(/%[a-z%]/g, function(match) {
|
||||
if ('%%' === match) return;
|
||||
index++;
|
||||
if ('%c' === match) {
|
||||
// we only are interested in the *last* %c
|
||||
// (the user may have provided their own)
|
||||
lastC = index;
|
||||
}
|
||||
});
|
||||
|
||||
args.splice(lastC, 0, c);
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes `console.log()` when available.
|
||||
* No-op when `console.log` is not a "function".
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function log() {
|
||||
// this hackery is required for IE8/9, where
|
||||
// the `console.log` function doesn't have 'apply'
|
||||
return 'object' === typeof console
|
||||
&& console.log
|
||||
&& Function.prototype.apply.call(console.log, console, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save `namespaces`.
|
||||
*
|
||||
* @param {String} namespaces
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function save(namespaces) {
|
||||
try {
|
||||
if (null == namespaces) {
|
||||
exports.storage.removeItem('debug');
|
||||
} else {
|
||||
exports.storage.debug = namespaces;
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load `namespaces`.
|
||||
*
|
||||
* @return {String} returns the previously persisted debug modes
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function load() {
|
||||
var r;
|
||||
try {
|
||||
r = exports.storage.debug;
|
||||
} catch(e) {}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable namespaces listed in `localStorage.debug` initially.
|
||||
*/
|
||||
|
||||
exports.enable(load());
|
||||
|
||||
/**
|
||||
* Localstorage attempts to return the localstorage.
|
||||
*
|
||||
* This is necessary because safari throws
|
||||
* when a user disables cookies/localstorage
|
||||
* and you attempt to access it.
|
||||
*
|
||||
* @return {LocalStorage}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function localstorage(){
|
||||
try {
|
||||
return window.localStorage;
|
||||
} catch (e) {}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "debug",
|
||||
"repo": "visionmedia/debug",
|
||||
"description": "small debugging utility",
|
||||
"version": "2.2.0",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"log",
|
||||
"debugger"
|
||||
],
|
||||
"main": "browser.js",
|
||||
"scripts": [
|
||||
"browser.js",
|
||||
"debug.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"rauchg/ms.js": "0.7.1"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,197 @@
|
||||
|
||||
/**
|
||||
* This is the common logic for both the Node.js and web browser
|
||||
* implementations of `debug()`.
|
||||
*
|
||||
* Expose `debug()` as the module.
|
||||
*/
|
||||
|
||||
exports = module.exports = debug;
|
||||
exports.coerce = coerce;
|
||||
exports.disable = disable;
|
||||
exports.enable = enable;
|
||||
exports.enabled = enabled;
|
||||
exports.humanize = require('ms');
|
||||
|
||||
/**
|
||||
* The currently active debug mode names, and names to skip.
|
||||
*/
|
||||
|
||||
exports.names = [];
|
||||
exports.skips = [];
|
||||
|
||||
/**
|
||||
* Map of special "%n" handling functions, for the debug "format" argument.
|
||||
*
|
||||
* Valid key names are a single, lowercased letter, i.e. "n".
|
||||
*/
|
||||
|
||||
exports.formatters = {};
|
||||
|
||||
/**
|
||||
* Previously assigned color.
|
||||
*/
|
||||
|
||||
var prevColor = 0;
|
||||
|
||||
/**
|
||||
* Previous log timestamp.
|
||||
*/
|
||||
|
||||
var prevTime;
|
||||
|
||||
/**
|
||||
* Select a color.
|
||||
*
|
||||
* @return {Number}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function selectColor() {
|
||||
return exports.colors[prevColor++ % exports.colors.length];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a debugger with the given `namespace`.
|
||||
*
|
||||
* @param {String} namespace
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function debug(namespace) {
|
||||
|
||||
// define the `disabled` version
|
||||
function disabled() {
|
||||
}
|
||||
disabled.enabled = false;
|
||||
|
||||
// define the `enabled` version
|
||||
function enabled() {
|
||||
|
||||
var self = enabled;
|
||||
|
||||
// set `diff` timestamp
|
||||
var curr = +new Date();
|
||||
var ms = curr - (prevTime || curr);
|
||||
self.diff = ms;
|
||||
self.prev = prevTime;
|
||||
self.curr = curr;
|
||||
prevTime = curr;
|
||||
|
||||
// add the `color` if not set
|
||||
if (null == self.useColors) self.useColors = exports.useColors();
|
||||
if (null == self.color && self.useColors) self.color = selectColor();
|
||||
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
|
||||
args[0] = exports.coerce(args[0]);
|
||||
|
||||
if ('string' !== typeof args[0]) {
|
||||
// anything else let's inspect with %o
|
||||
args = ['%o'].concat(args);
|
||||
}
|
||||
|
||||
// apply any `formatters` transformations
|
||||
var index = 0;
|
||||
args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
|
||||
// if we encounter an escaped % then don't increase the array index
|
||||
if (match === '%%') return match;
|
||||
index++;
|
||||
var formatter = exports.formatters[format];
|
||||
if ('function' === typeof formatter) {
|
||||
var val = args[index];
|
||||
match = formatter.call(self, val);
|
||||
|
||||
// now we need to remove `args[index]` since it's inlined in the `format`
|
||||
args.splice(index, 1);
|
||||
index--;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
||||
if ('function' === typeof exports.formatArgs) {
|
||||
args = exports.formatArgs.apply(self, args);
|
||||
}
|
||||
var logFn = enabled.log || exports.log || console.log.bind(console);
|
||||
logFn.apply(self, args);
|
||||
}
|
||||
enabled.enabled = true;
|
||||
|
||||
var fn = exports.enabled(namespace) ? enabled : disabled;
|
||||
|
||||
fn.namespace = namespace;
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables a debug mode by namespaces. This can include modes
|
||||
* separated by a colon and wildcards.
|
||||
*
|
||||
* @param {String} namespaces
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function enable(namespaces) {
|
||||
exports.save(namespaces);
|
||||
|
||||
var split = (namespaces || '').split(/[\s,]+/);
|
||||
var len = split.length;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (!split[i]) continue; // ignore empty strings
|
||||
namespaces = split[i].replace(/\*/g, '.*?');
|
||||
if (namespaces[0] === '-') {
|
||||
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
|
||||
} else {
|
||||
exports.names.push(new RegExp('^' + namespaces + '$'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable debug output.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function disable() {
|
||||
exports.enable('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given mode name is enabled, false otherwise.
|
||||
*
|
||||
* @param {String} name
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function enabled(name) {
|
||||
var i, len;
|
||||
for (i = 0, len = exports.skips.length; i < len; i++) {
|
||||
if (exports.skips[i].test(name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (i = 0, len = exports.names.length; i < len; i++) {
|
||||
if (exports.names[i].test(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerce `val`.
|
||||
*
|
||||
* @param {Mixed} val
|
||||
* @return {Mixed}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function coerce(val) {
|
||||
if (val instanceof Error) return val.stack || val.message;
|
||||
return val;
|
||||
}
|
||||
@ -0,0 +1,209 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var tty = require('tty');
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* This is the Node.js implementation of `debug()`.
|
||||
*
|
||||
* Expose `debug()` as the module.
|
||||
*/
|
||||
|
||||
exports = module.exports = require('./debug');
|
||||
exports.log = log;
|
||||
exports.formatArgs = formatArgs;
|
||||
exports.save = save;
|
||||
exports.load = load;
|
||||
exports.useColors = useColors;
|
||||
|
||||
/**
|
||||
* Colors.
|
||||
*/
|
||||
|
||||
exports.colors = [6, 2, 3, 4, 5, 1];
|
||||
|
||||
/**
|
||||
* The file descriptor to write the `debug()` calls to.
|
||||
* Set the `DEBUG_FD` env variable to override with another value. i.e.:
|
||||
*
|
||||
* $ DEBUG_FD=3 node script.js 3>debug.log
|
||||
*/
|
||||
|
||||
var fd = parseInt(process.env.DEBUG_FD, 10) || 2;
|
||||
var stream = 1 === fd ? process.stdout :
|
||||
2 === fd ? process.stderr :
|
||||
createWritableStdioStream(fd);
|
||||
|
||||
/**
|
||||
* Is stdout a TTY? Colored output is enabled when `true`.
|
||||
*/
|
||||
|
||||
function useColors() {
|
||||
var debugColors = (process.env.DEBUG_COLORS || '').trim().toLowerCase();
|
||||
if (0 === debugColors.length) {
|
||||
return tty.isatty(fd);
|
||||
} else {
|
||||
return '0' !== debugColors
|
||||
&& 'no' !== debugColors
|
||||
&& 'false' !== debugColors
|
||||
&& 'disabled' !== debugColors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map %o to `util.inspect()`, since Node doesn't do that out of the box.
|
||||
*/
|
||||
|
||||
var inspect = (4 === util.inspect.length ?
|
||||
// node <= 0.8.x
|
||||
function (v, colors) {
|
||||
return util.inspect(v, void 0, void 0, colors);
|
||||
} :
|
||||
// node > 0.8.x
|
||||
function (v, colors) {
|
||||
return util.inspect(v, { colors: colors });
|
||||
}
|
||||
);
|
||||
|
||||
exports.formatters.o = function(v) {
|
||||
return inspect(v, this.useColors)
|
||||
.replace(/\s*\n\s*/g, ' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds ANSI color escape codes if enabled.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function formatArgs() {
|
||||
var args = arguments;
|
||||
var useColors = this.useColors;
|
||||
var name = this.namespace;
|
||||
|
||||
if (useColors) {
|
||||
var c = this.color;
|
||||
|
||||
args[0] = ' \u001b[3' + c + ';1m' + name + ' '
|
||||
+ '\u001b[0m'
|
||||
+ args[0] + '\u001b[3' + c + 'm'
|
||||
+ ' +' + exports.humanize(this.diff) + '\u001b[0m';
|
||||
} else {
|
||||
args[0] = new Date().toUTCString()
|
||||
+ ' ' + name + ' ' + args[0];
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes `console.error()` with the specified arguments.
|
||||
*/
|
||||
|
||||
function log() {
|
||||
return stream.write(util.format.apply(this, arguments) + '\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Save `namespaces`.
|
||||
*
|
||||
* @param {String} namespaces
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function save(namespaces) {
|
||||
if (null == namespaces) {
|
||||
// If you set a process.env field to null or undefined, it gets cast to the
|
||||
// string 'null' or 'undefined'. Just delete instead.
|
||||
delete process.env.DEBUG;
|
||||
} else {
|
||||
process.env.DEBUG = namespaces;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load `namespaces`.
|
||||
*
|
||||
* @return {String} returns the previously persisted debug modes
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function load() {
|
||||
return process.env.DEBUG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from `node/src/node.js`.
|
||||
*
|
||||
* XXX: It's lame that node doesn't expose this API out-of-the-box. It also
|
||||
* relies on the undocumented `tty_wrap.guessHandleType()` which is also lame.
|
||||
*/
|
||||
|
||||
function createWritableStdioStream (fd) {
|
||||
var stream;
|
||||
var tty_wrap = process.binding('tty_wrap');
|
||||
|
||||
// Note stream._type is used for test-module-load-list.js
|
||||
|
||||
switch (tty_wrap.guessHandleType(fd)) {
|
||||
case 'TTY':
|
||||
stream = new tty.WriteStream(fd);
|
||||
stream._type = 'tty';
|
||||
|
||||
// Hack to have stream not keep the event loop alive.
|
||||
// See https://github.com/joyent/node/issues/1726
|
||||
if (stream._handle && stream._handle.unref) {
|
||||
stream._handle.unref();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'FILE':
|
||||
var fs = require('fs');
|
||||
stream = new fs.SyncWriteStream(fd, { autoClose: false });
|
||||
stream._type = 'fs';
|
||||
break;
|
||||
|
||||
case 'PIPE':
|
||||
case 'TCP':
|
||||
var net = require('net');
|
||||
stream = new net.Socket({
|
||||
fd: fd,
|
||||
readable: false,
|
||||
writable: true
|
||||
});
|
||||
|
||||
// FIXME Should probably have an option in net.Socket to create a
|
||||
// stream from an existing fd which is writable only. But for now
|
||||
// we'll just add this hack and set the `readable` member to false.
|
||||
// Test: ./node test/fixtures/echo.js < /etc/passwd
|
||||
stream.readable = false;
|
||||
stream.read = null;
|
||||
stream._type = 'pipe';
|
||||
|
||||
// FIXME Hack to have stream not keep the event loop alive.
|
||||
// See https://github.com/joyent/node/issues/1726
|
||||
if (stream._handle && stream._handle.unref) {
|
||||
stream._handle.unref();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Probably an error on in uv_guess_handle()
|
||||
throw new Error('Implement me. Unknown stream file type!');
|
||||
}
|
||||
|
||||
// For supporting legacy API we put the FD here.
|
||||
stream.fd = fd;
|
||||
|
||||
stream._isStdio = true;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable namespaces listed in `process.env.DEBUG` initially.
|
||||
*/
|
||||
|
||||
exports.enable(load());
|
||||
@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
test
|
||||
History.md
|
||||
Makefile
|
||||
component.json
|
||||
@ -0,0 +1,66 @@
|
||||
|
||||
0.7.1 / 2015-04-20
|
||||
==================
|
||||
|
||||
* prevent extraordinary long inputs (@evilpacket)
|
||||
* Fixed broken readme link
|
||||
|
||||
0.7.0 / 2014-11-24
|
||||
==================
|
||||
|
||||
* add time abbreviations, updated tests and readme for the new units
|
||||
* fix example in the readme.
|
||||
* add LICENSE file
|
||||
|
||||
0.6.2 / 2013-12-05
|
||||
==================
|
||||
|
||||
* Adding repository section to package.json to suppress warning from NPM.
|
||||
|
||||
0.6.1 / 2013-05-10
|
||||
==================
|
||||
|
||||
* fix singularization [visionmedia]
|
||||
|
||||
0.6.0 / 2013-03-15
|
||||
==================
|
||||
|
||||
* fix minutes
|
||||
|
||||
0.5.1 / 2013-02-24
|
||||
==================
|
||||
|
||||
* add component namespace
|
||||
|
||||
0.5.0 / 2012-11-09
|
||||
==================
|
||||
|
||||
* add short formatting as default and .long option
|
||||
* add .license property to component.json
|
||||
* add version to component.json
|
||||
|
||||
0.4.0 / 2012-10-22
|
||||
==================
|
||||
|
||||
* add rounding to fix crazy decimals
|
||||
|
||||
0.3.0 / 2012-09-07
|
||||
==================
|
||||
|
||||
* fix `ms(<String>)` [visionmedia]
|
||||
|
||||
0.2.0 / 2012-09-03
|
||||
==================
|
||||
|
||||
* add component.json [visionmedia]
|
||||
* add days support [visionmedia]
|
||||
* add hours support [visionmedia]
|
||||
* add minutes support [visionmedia]
|
||||
* add seconds support [visionmedia]
|
||||
* add ms string support [visionmedia]
|
||||
* refactor tests to facilitate ms(number) [visionmedia]
|
||||
|
||||
0.1.0 / 2012-03-07
|
||||
==================
|
||||
|
||||
* Initial release
|
||||
@ -0,0 +1,20 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 Guillermo Rauch <rauchg@gmail.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.
|
||||
@ -0,0 +1,35 @@
|
||||
# ms.js: miliseconds conversion utility
|
||||
|
||||
```js
|
||||
ms('2 days') // 172800000
|
||||
ms('1d') // 86400000
|
||||
ms('10h') // 36000000
|
||||
ms('2.5 hrs') // 9000000
|
||||
ms('2h') // 7200000
|
||||
ms('1m') // 60000
|
||||
ms('5s') // 5000
|
||||
ms('100') // 100
|
||||
```
|
||||
|
||||
```js
|
||||
ms(60000) // "1m"
|
||||
ms(2 * 60000) // "2m"
|
||||
ms(ms('10 hours')) // "10h"
|
||||
```
|
||||
|
||||
```js
|
||||
ms(60000, { long: true }) // "1 minute"
|
||||
ms(2 * 60000, { long: true }) // "2 minutes"
|
||||
ms(ms('10 hours'), { long: true }) // "10 hours"
|
||||
```
|
||||
|
||||
- Node/Browser compatible. Published as [`ms`](https://www.npmjs.org/package/ms) in [NPM](http://nodejs.org/download).
|
||||
- If a number is supplied to `ms`, a string with a unit is returned.
|
||||
- If a string that contains the number is supplied, it returns it as
|
||||
a number (e.g: it returns `100` for `'100'`).
|
||||
- If you pass a string with a number and a valid unit, the number of
|
||||
equivalent ms is returned.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Helpers.
|
||||
*/
|
||||
|
||||
var s = 1000;
|
||||
var m = s * 60;
|
||||
var h = m * 60;
|
||||
var d = h * 24;
|
||||
var y = d * 365.25;
|
||||
|
||||
/**
|
||||
* Parse or format the given `val`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `long` verbose formatting [false]
|
||||
*
|
||||
* @param {String|Number} val
|
||||
* @param {Object} options
|
||||
* @return {String|Number}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function(val, options){
|
||||
options = options || {};
|
||||
if ('string' == typeof val) return parse(val);
|
||||
return options.long
|
||||
? long(val)
|
||||
: short(val);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse the given `str` and return milliseconds.
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Number}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function parse(str) {
|
||||
str = '' + str;
|
||||
if (str.length > 10000) return;
|
||||
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);
|
||||
if (!match) return;
|
||||
var n = parseFloat(match[1]);
|
||||
var type = (match[2] || 'ms').toLowerCase();
|
||||
switch (type) {
|
||||
case 'years':
|
||||
case 'year':
|
||||
case 'yrs':
|
||||
case 'yr':
|
||||
case 'y':
|
||||
return n * y;
|
||||
case 'days':
|
||||
case 'day':
|
||||
case 'd':
|
||||
return n * d;
|
||||
case 'hours':
|
||||
case 'hour':
|
||||
case 'hrs':
|
||||
case 'hr':
|
||||
case 'h':
|
||||
return n * h;
|
||||
case 'minutes':
|
||||
case 'minute':
|
||||
case 'mins':
|
||||
case 'min':
|
||||
case 'm':
|
||||
return n * m;
|
||||
case 'seconds':
|
||||
case 'second':
|
||||
case 'secs':
|
||||
case 'sec':
|
||||
case 's':
|
||||
return n * s;
|
||||
case 'milliseconds':
|
||||
case 'millisecond':
|
||||
case 'msecs':
|
||||
case 'msec':
|
||||
case 'ms':
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Short format for `ms`.
|
||||
*
|
||||
* @param {Number} ms
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function short(ms) {
|
||||
if (ms >= d) return Math.round(ms / d) + 'd';
|
||||
if (ms >= h) return Math.round(ms / h) + 'h';
|
||||
if (ms >= m) return Math.round(ms / m) + 'm';
|
||||
if (ms >= s) return Math.round(ms / s) + 's';
|
||||
return ms + 'ms';
|
||||
}
|
||||
|
||||
/**
|
||||
* Long format for `ms`.
|
||||
*
|
||||
* @param {Number} ms
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function long(ms) {
|
||||
return plural(ms, d, 'day')
|
||||
|| plural(ms, h, 'hour')
|
||||
|| plural(ms, m, 'minute')
|
||||
|| plural(ms, s, 'second')
|
||||
|| ms + ' ms';
|
||||
}
|
||||
|
||||
/**
|
||||
* Pluralization helper.
|
||||
*/
|
||||
|
||||
function plural(ms, n, name) {
|
||||
if (ms < n) return;
|
||||
if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
|
||||
return Math.ceil(ms / n) + ' ' + name + 's';
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "ms",
|
||||
"version": "0.7.1",
|
||||
"description": "Tiny ms conversion utility",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/guille/ms.js.git"
|
||||
},
|
||||
"main": "./index",
|
||||
"devDependencies": {
|
||||
"mocha": "*",
|
||||
"expect.js": "*",
|
||||
"serve": "*"
|
||||
},
|
||||
"component": {
|
||||
"scripts": {
|
||||
"ms/index.js": "index.js"
|
||||
}
|
||||
},
|
||||
"gitHead": "713dcf26d9e6fd9dbc95affe7eff9783b7f1b909",
|
||||
"bugs": {
|
||||
"url": "https://github.com/guille/ms.js/issues"
|
||||
},
|
||||
"homepage": "https://github.com/guille/ms.js",
|
||||
"_id": "ms@0.7.1",
|
||||
"scripts": {},
|
||||
"_shasum": "9cd13c03adbff25b65effde7ce864ee952017098",
|
||||
"_from": "ms@0.7.1",
|
||||
"_npmVersion": "2.7.5",
|
||||
"_nodeVersion": "0.12.2",
|
||||
"_npmUser": {
|
||||
"name": "rauchg",
|
||||
"email": "rauchg@gmail.com"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "rauchg",
|
||||
"email": "rauchg@gmail.com"
|
||||
}
|
||||
],
|
||||
"dist": {
|
||||
"shasum": "9cd13c03adbff25b65effde7ce864ee952017098",
|
||||
"tarball": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "debug",
|
||||
"version": "2.2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/visionmedia/debug.git"
|
||||
},
|
||||
"description": "small debugging utility",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"log",
|
||||
"debugger"
|
||||
],
|
||||
"author": {
|
||||
"name": "TJ Holowaychuk",
|
||||
"email": "tj@vision-media.ca"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nathan Rajlich",
|
||||
"email": "nathan@tootallnate.net",
|
||||
"url": "http://n8.io"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "0.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browserify": "9.0.3",
|
||||
"mocha": "*"
|
||||
},
|
||||
"main": "./node.js",
|
||||
"browser": "./browser.js",
|
||||
"component": {
|
||||
"scripts": {
|
||||
"debug/index.js": "browser.js",
|
||||
"debug/debug.js": "debug.js"
|
||||
}
|
||||
},
|
||||
"gitHead": "b38458422b5aa8aa6d286b10dfe427e8a67e2b35",
|
||||
"bugs": {
|
||||
"url": "https://github.com/visionmedia/debug/issues"
|
||||
},
|
||||
"homepage": "https://github.com/visionmedia/debug",
|
||||
"_id": "debug@2.2.0",
|
||||
"scripts": {},
|
||||
"_shasum": "f87057e995b1a1f6ae6a4960664137bc56f039da",
|
||||
"_from": "debug@>=2.2.0 <2.3.0",
|
||||
"_npmVersion": "2.7.4",
|
||||
"_nodeVersion": "0.12.2",
|
||||
"_npmUser": {
|
||||
"name": "tootallnate",
|
||||
"email": "nathan@tootallnate.net"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "tjholowaychuk",
|
||||
"email": "tj@vision-media.ca"
|
||||
},
|
||||
{
|
||||
"name": "tootallnate",
|
||||
"email": "nathan@tootallnate.net"
|
||||
}
|
||||
],
|
||||
"dist": {
|
||||
"shasum": "f87057e995b1a1f6ae6a4960664137bc56f039da",
|
||||
"tarball": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
1.1.0 / 2015-09-14
|
||||
==================
|
||||
|
||||
* Enable strict mode in more places
|
||||
* Support io.js 3.x
|
||||
* Support io.js 2.x
|
||||
* Support web browser loading
|
||||
- Requires bundler like Browserify or webpack
|
||||
|
||||
1.0.1 / 2015-04-07
|
||||
==================
|
||||
|
||||
* Fix `TypeError`s 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
|
||||
@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014-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.
|
||||
@ -0,0 +1,281 @@
|
||||
# depd
|
||||
|
||||
[![NPM Version][npm-version-image]][npm-url]
|
||||
[![NPM Downloads][npm-downloads-image]][npm-url]
|
||||
[![Node.js Version][node-image]][node-url]
|
||||
[![Linux Build][travis-image]][travis-url]
|
||||
[![Windows Build][appveyor-image]][appveyor-url]
|
||||
[![Coverage Status][coveralls-image]][coveralls-url]
|
||||
[![Gratipay][gratipay-image]][gratipay-url]
|
||||
|
||||
Deprecate all the things
|
||||
|
||||
> With great modules comes great responsibility; mark things deprecated!
|
||||
|
||||
## Install
|
||||
|
||||
This module is installed directly using `npm`:
|
||||
|
||||
```sh
|
||||
$ npm install depd
|
||||
```
|
||||
|
||||
This module can also be bundled with systems like
|
||||
[Browserify](http://browserify.org/) or [webpack](https://webpack.github.io/),
|
||||
though by default this module will alter it's API to no longer display or
|
||||
track deprecations.
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var deprecate = require('depd')('my-module')
|
||||
```
|
||||
|
||||
This library allows you to display deprecation messages to your users.
|
||||
This library goes above and beyond with deprecation warnings by
|
||||
introspection of the call stack (but only the bits that it is interested
|
||||
in).
|
||||
|
||||
Instead of just warning on the first invocation of a deprecated
|
||||
function and never again, this module will warn on the first invocation
|
||||
of a deprecated function per unique call site, making it ideal to alert
|
||||
users of all deprecated uses across the code base, rather than just
|
||||
whatever happens to execute first.
|
||||
|
||||
The deprecation warnings from this module also include the file and line
|
||||
information for the call into the module that the deprecated function was
|
||||
in.
|
||||
|
||||
**NOTE** this library has a similar interface to the `debug` module, and
|
||||
this module uses the calling file to get the boundary for the call stacks,
|
||||
so you should always create a new `deprecate` object in each file and not
|
||||
within some central file.
|
||||
|
||||
### depd(namespace)
|
||||
|
||||
Create a new deprecate function that uses the given namespace name in the
|
||||
messages and will display the call site prior to the stack entering the
|
||||
file this function was called from. It is highly suggested you use the
|
||||
name of your module as the namespace.
|
||||
|
||||
### deprecate(message)
|
||||
|
||||
Call this function from deprecated code to display a deprecation message.
|
||||
This message will appear once per unique caller site. Caller site is the
|
||||
first call site in the stack in a different file from the caller of this
|
||||
function.
|
||||
|
||||
If the message is omitted, a message is generated for you based on the site
|
||||
of the `deprecate()` call and will display the name of the function called,
|
||||
similar to the name displayed in a stack trace.
|
||||
|
||||
### deprecate.function(fn, message)
|
||||
|
||||
Call this function to wrap a given function in a deprecation message on any
|
||||
call to the function. An optional message can be supplied to provide a custom
|
||||
message.
|
||||
|
||||
### deprecate.property(obj, prop, message)
|
||||
|
||||
Call this function to wrap a given property on object in a deprecation message
|
||||
on any accessing or setting of the property. An optional message can be supplied
|
||||
to provide a custom message.
|
||||
|
||||
The method must be called on the object where the property belongs (not
|
||||
inherited from the prototype).
|
||||
|
||||
If the property is a data descriptor, it will be converted to an accessor
|
||||
descriptor in order to display the deprecation message.
|
||||
|
||||
### process.on('deprecation', fn)
|
||||
|
||||
This module will allow easy capturing of deprecation errors by emitting the
|
||||
errors as the type "deprecation" on the global `process`. If there are no
|
||||
listeners for this type, the errors are written to STDERR as normal, but if
|
||||
there are any listeners, nothing will be written to STDERR and instead only
|
||||
emitted. From there, you can write the errors in a different format or to a
|
||||
logging source.
|
||||
|
||||
The error represents the deprecation and is emitted only once with the same
|
||||
rules as writing to STDERR. The error has the following properties:
|
||||
|
||||
- `message` - This is the message given by the library
|
||||
- `name` - This is always `'DeprecationError'`
|
||||
- `namespace` - This is the namespace the deprecation came from
|
||||
- `stack` - This is the stack of the call to the deprecated thing
|
||||
|
||||
Example `error.stack` output:
|
||||
|
||||
```
|
||||
DeprecationError: my-cool-module deprecated oldfunction
|
||||
at Object.<anonymous> ([eval]-wrapper:6:22)
|
||||
at Module._compile (module.js:456:26)
|
||||
at evalScript (node.js:532:25)
|
||||
at startup (node.js:80:7)
|
||||
at node.js:902:3
|
||||
```
|
||||
|
||||
### process.env.NO_DEPRECATION
|
||||
|
||||
As a user of modules that are deprecated, the environment variable `NO_DEPRECATION`
|
||||
is provided as a quick solution to silencing deprecation warnings from being
|
||||
output. The format of this is similar to that of `DEBUG`:
|
||||
|
||||
```sh
|
||||
$ NO_DEPRECATION=my-module,othermod node app.js
|
||||
```
|
||||
|
||||
This will suppress deprecations from being output for "my-module" and "othermod".
|
||||
The value is a list of comma-separated namespaces. To suppress every warning
|
||||
across all namespaces, use the value `*` for a namespace.
|
||||
|
||||
Providing the argument `--no-deprecation` to the `node` executable will suppress
|
||||
all deprecations (only available in Node.js 0.8 or higher).
|
||||
|
||||
**NOTE** This will not suppress the deperecations given to any "deprecation"
|
||||
event listeners, just the output to STDERR.
|
||||
|
||||
### process.env.TRACE_DEPRECATION
|
||||
|
||||
As a user of modules that are deprecated, the environment variable `TRACE_DEPRECATION`
|
||||
is provided as a solution to getting more detailed location information in deprecation
|
||||
warnings by including the entire stack trace. The format of this is the same as
|
||||
`NO_DEPRECATION`:
|
||||
|
||||
```sh
|
||||
$ TRACE_DEPRECATION=my-module,othermod node app.js
|
||||
```
|
||||
|
||||
This will include stack traces for deprecations being output for "my-module" and
|
||||
"othermod". The value is a list of comma-separated namespaces. To trace every
|
||||
warning across all namespaces, use the value `*` for a namespace.
|
||||
|
||||
Providing the argument `--trace-deprecation` to the `node` executable will trace
|
||||
all deprecations (only available in Node.js 0.8 or higher).
|
||||
|
||||
**NOTE** This will not trace the deperecations silenced by `NO_DEPRECATION`.
|
||||
|
||||
## Display
|
||||
|
||||

|
||||
|
||||
When a user calls a function in your library that you mark deprecated, they
|
||||
will see the following written to STDERR (in the given colors, similar colors
|
||||
and layout to the `debug` module):
|
||||
|
||||
```
|
||||
bright cyan bright yellow
|
||||
| | reset cyan
|
||||
| | | |
|
||||
▼ ▼ ▼ ▼
|
||||
my-cool-module deprecated oldfunction [eval]-wrapper:6:22
|
||||
▲ ▲ ▲ ▲
|
||||
| | | |
|
||||
namespace | | location of mycoolmod.oldfunction() call
|
||||
| deprecation message
|
||||
the word "deprecated"
|
||||
```
|
||||
|
||||
If the user redirects their STDERR to a file or somewhere that does not support
|
||||
colors, they see (similar layout to the `debug` module):
|
||||
|
||||
```
|
||||
Sun, 15 Jun 2014 05:21:37 GMT my-cool-module deprecated oldfunction at [eval]-wrapper:6:22
|
||||
▲ ▲ ▲ ▲ ▲
|
||||
| | | | |
|
||||
timestamp of message namespace | | location of mycoolmod.oldfunction() call
|
||||
| deprecation message
|
||||
the word "deprecated"
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Deprecating all calls to a function
|
||||
|
||||
This will display a deprecated message about "oldfunction" being deprecated
|
||||
from "my-module" on STDERR.
|
||||
|
||||
```js
|
||||
var deprecate = require('depd')('my-cool-module')
|
||||
|
||||
// message automatically derived from function name
|
||||
// Object.oldfunction
|
||||
exports.oldfunction = deprecate.function(function oldfunction() {
|
||||
// all calls to function are deprecated
|
||||
})
|
||||
|
||||
// specific message
|
||||
exports.oldfunction = deprecate.function(function () {
|
||||
// all calls to function are deprecated
|
||||
}, 'oldfunction')
|
||||
```
|
||||
|
||||
### Conditionally deprecating a function call
|
||||
|
||||
This will display a deprecated message about "weirdfunction" being deprecated
|
||||
from "my-module" on STDERR when called with less than 2 arguments.
|
||||
|
||||
```js
|
||||
var deprecate = require('depd')('my-cool-module')
|
||||
|
||||
exports.weirdfunction = function () {
|
||||
if (arguments.length < 2) {
|
||||
// calls with 0 or 1 args are deprecated
|
||||
deprecate('weirdfunction args < 2')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When calling `deprecate` as a function, the warning is counted per call site
|
||||
within your own module, so you can display different deprecations depending
|
||||
on different situations and the users will still get all the warnings:
|
||||
|
||||
```js
|
||||
var deprecate = require('depd')('my-cool-module')
|
||||
|
||||
exports.weirdfunction = function () {
|
||||
if (arguments.length < 2) {
|
||||
// calls with 0 or 1 args are deprecated
|
||||
deprecate('weirdfunction args < 2')
|
||||
} else if (typeof arguments[0] !== 'string') {
|
||||
// calls with non-string first argument are deprecated
|
||||
deprecate('weirdfunction non-string first arg')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Deprecating property access
|
||||
|
||||
This will display a deprecated message about "oldprop" being deprecated
|
||||
from "my-module" on STDERR when accessed. A deprecation will be displayed
|
||||
when setting the value and when getting the value.
|
||||
|
||||
```js
|
||||
var deprecate = require('depd')('my-cool-module')
|
||||
|
||||
exports.oldprop = 'something'
|
||||
|
||||
// message automatically derives from property name
|
||||
deprecate.property(exports, 'oldprop')
|
||||
|
||||
// explicit message
|
||||
deprecate.property(exports, 'oldprop', 'oldprop >= 0.10')
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[npm-version-image]: https://img.shields.io/npm/v/depd.svg
|
||||
[npm-downloads-image]: https://img.shields.io/npm/dm/depd.svg
|
||||
[npm-url]: https://npmjs.org/package/depd
|
||||
[travis-image]: https://img.shields.io/travis/dougwilson/nodejs-depd/master.svg?label=linux
|
||||
[travis-url]: https://travis-ci.org/dougwilson/nodejs-depd
|
||||
[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/nodejs-depd/master.svg?label=windows
|
||||
[appveyor-url]: https://ci.appveyor.com/project/dougwilson/nodejs-depd
|
||||
[coveralls-image]: https://img.shields.io/coveralls/dougwilson/nodejs-depd/master.svg
|
||||
[coveralls-url]: https://coveralls.io/r/dougwilson/nodejs-depd?branch=master
|
||||
[node-image]: https://img.shields.io/node/v/depd.svg
|
||||
[node-url]: http://nodejs.org/download/
|
||||
[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
|
||||
[gratipay-url]: https://www.gratipay.com/dougwilson/
|
||||
@ -0,0 +1,521 @@
|
||||
/*!
|
||||
* depd
|
||||
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var callSiteToString = require('./lib/compat').callSiteToString
|
||||
var eventListenerCount = require('./lib/compat').eventListenerCount
|
||||
var relative = require('path').relative
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
module.exports = depd
|
||||
|
||||
/**
|
||||
* Get the path to base files on.
|
||||
*/
|
||||
|
||||
var basePath = process.cwd()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
function formatColor(msg, caller, stack) {
|
||||
var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' // bold cyan
|
||||
+ ' \x1b[33;1mdeprecated\x1b[22;39m' // bold yellow
|
||||
+ ' \x1b[0m' + msg + '\x1b[39m' // reset
|
||||
|
||||
// add stack trace
|
||||
if (this._traced) {
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
formatted += '\n \x1b[36mat ' + callSiteToString(stack[i]) + '\x1b[39m' // cyan
|
||||
}
|
||||
|
||||
return formatted
|
||||
}
|
||||
|
||||
if (caller) {
|
||||
formatted += ' \x1b[36m' + formatLocation(caller) + '\x1b[39m' // cyan
|
||||
}
|
||||
|
||||
return formatted
|
||||
}
|
||||
|
||||
/**
|
||||
* Format call site location.
|
||||
*/
|
||||
|
||||
function formatLocation(callSite) {
|
||||
return relative(basePath, callSite[0])
|
||||
+ ':' + callSite[1]
|
||||
+ ':' + callSite[2]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stack as array of call sites.
|
||||
*/
|
||||
|
||||
function getStack() {
|
||||
var limit = Error.stackTraceLimit
|
||||
var obj = {}
|
||||
var prep = Error.prepareStackTrace
|
||||
|
||||
Error.prepareStackTrace = prepareObjectStackTrace
|
||||
Error.stackTraceLimit = Math.max(10, limit)
|
||||
|
||||
// capture the stack
|
||||
Error.captureStackTrace(obj)
|
||||
|
||||
// slice this function off the top
|
||||
var stack = obj.stack.slice(1)
|
||||
|
||||
Error.prepareStackTrace = prep
|
||||
Error.stackTraceLimit = limit
|
||||
|
||||
return stack
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture call site stack from v8.
|
||||
*/
|
||||
|
||||
function prepareObjectStackTrace(obj, stack) {
|
||||
return stack
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a wrapped function in a deprecation message.
|
||||
*/
|
||||
|
||||
function wrapfunction(fn, message) {
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('argument fn must be a function')
|
||||
}
|
||||
|
||||
var args = createArgumentsString(fn.length)
|
||||
var deprecate = this
|
||||
var stack = getStack()
|
||||
var site = callSiteLocation(stack[1])
|
||||
|
||||
site.name = fn.name
|
||||
|
||||
var deprecatedfn = eval('(function (' + args + ') {\n'
|
||||
+ '"use strict"\n'
|
||||
+ 'log.call(deprecate, message, site)\n'
|
||||
+ 'return fn.apply(this, arguments)\n'
|
||||
+ '})')
|
||||
|
||||
return deprecatedfn
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap property in a deprecation message.
|
||||
*/
|
||||
|
||||
function wrapproperty(obj, prop, message) {
|
||||
if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
||||
throw new TypeError('argument obj must be object')
|
||||
}
|
||||
|
||||
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
|
||||
|
||||
if (!descriptor) {
|
||||
throw new TypeError('must call property on owner object')
|
||||
}
|
||||
|
||||
if (!descriptor.configurable) {
|
||||
throw new TypeError('property must be configurable')
|
||||
}
|
||||
|
||||
var deprecate = this
|
||||
var stack = getStack()
|
||||
var site = callSiteLocation(stack[1])
|
||||
|
||||
// set site name
|
||||
site.name = prop
|
||||
|
||||
// convert data descriptor
|
||||
if ('value' in descriptor) {
|
||||
descriptor = convertDataDescriptorToAccessor(obj, prop, message)
|
||||
}
|
||||
|
||||
var get = descriptor.get
|
||||
var set = descriptor.set
|
||||
|
||||
// wrap getter
|
||||
if (typeof get === 'function') {
|
||||
descriptor.get = function getter() {
|
||||
log.call(deprecate, message, site)
|
||||
return get.apply(this, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
// wrap setter
|
||||
if (typeof set === 'function') {
|
||||
descriptor.set = function setter() {
|
||||
log.call(deprecate, message, site)
|
||||
return set.apply(this, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(obj, prop, descriptor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create DeprecationError for deprecation
|
||||
*/
|
||||
|
||||
function DeprecationError(namespace, message, stack) {
|
||||
var error = new Error()
|
||||
var stackString
|
||||
|
||||
Object.defineProperty(error, 'constructor', {
|
||||
value: DeprecationError
|
||||
})
|
||||
|
||||
Object.defineProperty(error, 'message', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: message,
|
||||
writable: true
|
||||
})
|
||||
|
||||
Object.defineProperty(error, 'name', {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: 'DeprecationError',
|
||||
writable: true
|
||||
})
|
||||
|
||||
Object.defineProperty(error, 'namespace', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: namespace,
|
||||
writable: true
|
||||
})
|
||||
|
||||
Object.defineProperty(error, 'stack', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
get: function () {
|
||||
if (stackString !== undefined) {
|
||||
return stackString
|
||||
}
|
||||
|
||||
// prepare stack trace
|
||||
return stackString = createStackString.call(this, stack)
|
||||
},
|
||||
set: function setter(val) {
|
||||
stackString = val
|
||||
}
|
||||
})
|
||||
|
||||
return error
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
/*!
|
||||
* depd
|
||||
* Copyright(c) 2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
* @public
|
||||
*/
|
||||
|
||||
module.exports = depd
|
||||
|
||||
/**
|
||||
* Create deprecate for namespace in caller.
|
||||
*/
|
||||
|
||||
function depd(namespace) {
|
||||
if (!namespace) {
|
||||
throw new TypeError('argument namespace is required')
|
||||
}
|
||||
|
||||
function deprecate(message) {
|
||||
// no-op in browser
|
||||
}
|
||||
|
||||
deprecate._file = undefined
|
||||
deprecate._ignored = true
|
||||
deprecate._namespace = namespace
|
||||
deprecate._traced = false
|
||||
deprecate._warned = Object.create(null)
|
||||
|
||||
deprecate.function = wrapfunction
|
||||
deprecate.property = wrapproperty
|
||||
|
||||
return deprecate
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a wrapped function in a deprecation message.
|
||||
*
|
||||
* This is a no-op version of the wrapper, which does nothing but call
|
||||
* validation.
|
||||
*/
|
||||
|
||||
function wrapfunction(fn, message) {
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('argument fn must be a function')
|
||||
}
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap property in a deprecation message.
|
||||
*
|
||||
* This is a no-op version of the wrapper, which does nothing but call
|
||||
* validation.
|
||||
*/
|
||||
|
||||
function wrapproperty(obj, prop, message) {
|
||||
if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
||||
throw new TypeError('argument obj must be object')
|
||||
}
|
||||
|
||||
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
|
||||
|
||||
if (!descriptor) {
|
||||
throw new TypeError('must call property on owner object')
|
||||
}
|
||||
|
||||
if (!descriptor.configurable) {
|
||||
throw new TypeError('property must be configurable')
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
/*!
|
||||
* depd
|
||||
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
module.exports = bufferConcat
|
||||
|
||||
/**
|
||||
* Concatenate an array of Buffers.
|
||||
*/
|
||||
|
||||
function bufferConcat(bufs) {
|
||||
var length = 0
|
||||
|
||||
for (var i = 0, len = bufs.length; i < len; i++) {
|
||||
length += bufs[i].length
|
||||
}
|
||||
|
||||
var buf = new Buffer(length)
|
||||
var pos = 0
|
||||
|
||||
for (var i = 0, len = bufs.length; i < len; i++) {
|
||||
bufs[i].copy(buf, pos)
|
||||
pos += bufs[i].length
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
/*!
|
||||
* depd
|
||||
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
module.exports = callSiteToString
|
||||
|
||||
/**
|
||||
* Format a CallSite file location to a string.
|
||||
*/
|
||||
|
||||
function callSiteFileLocation(callSite) {
|
||||
var fileName
|
||||
var fileLocation = ''
|
||||
|
||||
if (callSite.isNative()) {
|
||||
fileLocation = 'native'
|
||||
} else if (callSite.isEval()) {
|
||||
fileName = callSite.getScriptNameOrSourceURL()
|
||||
if (!fileName) {
|
||||
fileLocation = callSite.getEvalOrigin()
|
||||
}
|
||||
} else {
|
||||
fileName = callSite.getFileName()
|
||||
}
|
||||
|
||||
if (fileName) {
|
||||
fileLocation += fileName
|
||||
|
||||
var lineNumber = callSite.getLineNumber()
|
||||
if (lineNumber != null) {
|
||||
fileLocation += ':' + lineNumber
|
||||
|
||||
var columnNumber = callSite.getColumnNumber()
|
||||
if (columnNumber) {
|
||||
fileLocation += ':' + columnNumber
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fileLocation || 'unknown source'
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a CallSite to a string.
|
||||
*/
|
||||
|
||||
function callSiteToString(callSite) {
|
||||
var addSuffix = true
|
||||
var fileLocation = callSiteFileLocation(callSite)
|
||||
var functionName = callSite.getFunctionName()
|
||||
var isConstructor = callSite.isConstructor()
|
||||
var isMethodCall = !(callSite.isToplevel() || isConstructor)
|
||||
var line = ''
|
||||
|
||||
if (isMethodCall) {
|
||||
var methodName = callSite.getMethodName()
|
||||
var typeName = getConstructorName(callSite)
|
||||
|
||||
if (functionName) {
|
||||
if (typeName && functionName.indexOf(typeName) !== 0) {
|
||||
line += typeName + '.'
|
||||
}
|
||||
|
||||
line += functionName
|
||||
|
||||
if (methodName && functionName.lastIndexOf('.' + methodName) !== functionName.length - methodName.length - 1) {
|
||||
line += ' [as ' + methodName + ']'
|
||||
}
|
||||
} else {
|
||||
line += typeName + '.' + (methodName || '<anonymous>')
|
||||
}
|
||||
} else if (isConstructor) {
|
||||
line += 'new ' + (functionName || '<anonymous>')
|
||||
} else if (functionName) {
|
||||
line += functionName
|
||||
} else {
|
||||
addSuffix = false
|
||||
line += fileLocation
|
||||
}
|
||||
|
||||
if (addSuffix) {
|
||||
line += ' (' + fileLocation + ')'
|
||||
}
|
||||
|
||||
return line
|
||||
}
|
||||
|
||||
/**
|
||||
* Get constructor name of reviver.
|
||||
*/
|
||||
|
||||
function getConstructorName(obj) {
|
||||
var receiver = obj.receiver
|
||||
return (receiver.constructor && receiver.constructor.name) || null
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
/*!
|
||||
* depd
|
||||
* Copyright(c) 2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
* @public
|
||||
*/
|
||||
|
||||
module.exports = eventListenerCount
|
||||
|
||||
/**
|
||||
* Get the count of listeners on an event emitter of a specific type.
|
||||
*/
|
||||
|
||||
function eventListenerCount(emitter, type) {
|
||||
return emitter.listeners(type).length
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
/*!
|
||||
* depd
|
||||
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var Buffer = require('buffer')
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
* @public
|
||||
*/
|
||||
|
||||
lazyProperty(module.exports, 'bufferConcat', function bufferConcat() {
|
||||
return Buffer.concat || require('./buffer-concat')
|
||||
})
|
||||
|
||||
lazyProperty(module.exports, 'callSiteToString', function callSiteToString() {
|
||||
var limit = Error.stackTraceLimit
|
||||
var obj = {}
|
||||
var prep = Error.prepareStackTrace
|
||||
|
||||
function prepareObjectStackTrace(obj, stack) {
|
||||
return stack
|
||||
}
|
||||
|
||||
Error.prepareStackTrace = prepareObjectStackTrace
|
||||
Error.stackTraceLimit = 2
|
||||
|
||||
// capture the stack
|
||||
Error.captureStackTrace(obj)
|
||||
|
||||
// slice the stack
|
||||
var stack = obj.stack.slice()
|
||||
|
||||
Error.prepareStackTrace = prep
|
||||
Error.stackTraceLimit = limit
|
||||
|
||||
return stack[0].toString ? toString : require('./callsite-tostring')
|
||||
})
|
||||
|
||||
lazyProperty(module.exports, 'eventListenerCount', function eventListenerCount() {
|
||||
return EventEmitter.listenerCount || require('./event-listener-count')
|
||||
})
|
||||
|
||||
/**
|
||||
* Define a lazy property.
|
||||
*/
|
||||
|
||||
function lazyProperty(obj, prop, getter) {
|
||||
function get() {
|
||||
var val = getter()
|
||||
|
||||
Object.defineProperty(obj, prop, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
value: val
|
||||
})
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
Object.defineProperty(obj, prop, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: get
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Call toString() on the obj
|
||||
*/
|
||||
|
||||
function toString(obj) {
|
||||
return obj.toString()
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "depd",
|
||||
"description": "Deprecate all the things",
|
||||
"version": "1.1.0",
|
||||
"author": {
|
||||
"name": "Douglas Christopher Wilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"deprecate",
|
||||
"deprecated"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/dougwilson/nodejs-depd.git"
|
||||
},
|
||||
"browser": "lib/browser/index.js",
|
||||
"devDependencies": {
|
||||
"benchmark": "1.0.0",
|
||||
"beautify-benchmark": "0.2.4",
|
||||
"istanbul": "0.3.5",
|
||||
"mocha": "~1.21.5"
|
||||
},
|
||||
"files": [
|
||||
"lib/",
|
||||
"History.md",
|
||||
"LICENSE",
|
||||
"index.js",
|
||||
"Readme.md"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
},
|
||||
"scripts": {
|
||||
"bench": "node benchmark/index.js",
|
||||
"test": "mocha --reporter spec --bail test/",
|
||||
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --no-exit test/",
|
||||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot test/"
|
||||
},
|
||||
"gitHead": "78c659de20283e3a6bee92bda455e6daff01686a",
|
||||
"bugs": {
|
||||
"url": "https://github.com/dougwilson/nodejs-depd/issues"
|
||||
},
|
||||
"homepage": "https://github.com/dougwilson/nodejs-depd",
|
||||
"_id": "depd@1.1.0",
|
||||
"_shasum": "e1bd82c6aab6ced965b97b88b17ed3e528ca18c3",
|
||||
"_from": "depd@>=1.1.0 <1.2.0",
|
||||
"_npmVersion": "1.4.28",
|
||||
"_npmUser": {
|
||||
"name": "dougwilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "dougwilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
}
|
||||
],
|
||||
"dist": {
|
||||
"shasum": "e1bd82c6aab6ced965b97b88b17ed3e528ca18c3",
|
||||
"tarball": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
2016-01-28 / 1.4.0
|
||||
==================
|
||||
|
||||
* Add `HttpError` export, for `err instanceof createError.HttpError`
|
||||
* deps: inherits@2.0.1
|
||||
* deps: statuses@'>= 1.2.1 < 2'
|
||||
- Fix message for status 451
|
||||
- Remove incorrect nginx status code
|
||||
|
||||
2015-02-02 / 1.3.1
|
||||
==================
|
||||
|
||||
* Fix regression where status can be overwritten in `createError` `props`
|
||||
|
||||
2015-02-01 / 1.3.0
|
||||
==================
|
||||
|
||||
* Construct errors using defined constructors from `createError`
|
||||
* Fix error names that are not identifiers
|
||||
- `createError["I'mateapot"]` is now `createError.ImATeapot`
|
||||
* Set a meaningful `name` property on constructed errors
|
||||
|
||||
2014-12-09 / 1.2.8
|
||||
==================
|
||||
|
||||
* Fix stack trace from exported function
|
||||
* Remove `arguments.callee` usage
|
||||
|
||||
2014-10-14 / 1.2.7
|
||||
==================
|
||||
|
||||
* Remove duplicate line
|
||||
|
||||
2014-10-02 / 1.2.6
|
||||
==================
|
||||
|
||||
* Fix `expose` to be `true` for `ClientError` constructor
|
||||
|
||||
2014-09-28 / 1.2.5
|
||||
==================
|
||||
|
||||
* deps: statuses@1
|
||||
|
||||
2014-09-21 / 1.2.4
|
||||
==================
|
||||
|
||||
* Fix dependency version to work with old `npm`s
|
||||
|
||||
2014-09-21 / 1.2.3
|
||||
==================
|
||||
|
||||
* deps: statuses@~1.1.0
|
||||
|
||||
2014-09-21 / 1.2.2
|
||||
==================
|
||||
|
||||
* Fix publish error
|
||||
|
||||
2014-09-21 / 1.2.1
|
||||
==================
|
||||
|
||||
* Support Node.js 0.6
|
||||
* Use `inherits` instead of `util`
|
||||
|
||||
2014-09-09 / 1.2.0
|
||||
==================
|
||||
|
||||
* Fix the way inheriting functions
|
||||
* Support `expose` being provided in properties argument
|
||||
|
||||
2014-09-08 / 1.1.0
|
||||
==================
|
||||
|
||||
* Default status to 500
|
||||
* Support provided `error` to extend
|
||||
|
||||
2014-09-08 / 1.0.1
|
||||
==================
|
||||
|
||||
* Fix accepting string message
|
||||
|
||||
2014-09-08 / 1.0.0
|
||||
==================
|
||||
|
||||
* Initial release
|
||||
@ -0,0 +1,22 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Jonathan Ong me@jongleberry.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.
|
||||
@ -0,0 +1,66 @@
|
||||
# http-errors
|
||||
|
||||
[![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]
|
||||
|
||||
Create HTTP errors for Express, Koa, Connect, etc. with ease.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
var createError = require('http-errors');
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
if (!req.user) return next(createError(401, 'Please login to view this page.'));
|
||||
next();
|
||||
})
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
This is the current API, currently extracted from Koa and subject to change.
|
||||
|
||||
All errors inherit from JavaScript `Error` and the exported `createError.HttpError`.
|
||||
|
||||
### Error Properties
|
||||
|
||||
- `expose` - can be used to signal if `message` should be sent to the client, defaulting to `false` when `status` >= 500
|
||||
- `message`
|
||||
- `status` and `statusCode` - the status code of the error, defaulting to `500`
|
||||
|
||||
### createError([status], [message], [properties])
|
||||
|
||||
```js
|
||||
var err = createError(404, 'This video does not exist!');
|
||||
```
|
||||
|
||||
- `status: 500` - the status code as a number
|
||||
- `message` - the message of the error, defaulting to node's text for that status code.
|
||||
- `properties` - custom properties to attach to the object
|
||||
|
||||
### new createError\[code || name\](\[msg]\))
|
||||
|
||||
```js
|
||||
var err = new createError.NotFound();
|
||||
```
|
||||
|
||||
- `code` - the status code as a number
|
||||
- `name` - the name of the error as a "bumpy case", i.e. `NotFound` or `InternalServerError`.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/http-errors.svg?style=flat
|
||||
[npm-url]: https://npmjs.org/package/http-errors
|
||||
[node-version-image]: https://img.shields.io/node/v/http-errors.svg?style=flat
|
||||
[node-version-url]: https://nodejs.org/en/download/
|
||||
[travis-image]: https://img.shields.io/travis/jshttp/http-errors.svg?style=flat
|
||||
[travis-url]: https://travis-ci.org/jshttp/http-errors
|
||||
[coveralls-image]: https://img.shields.io/coveralls/jshttp/http-errors.svg?style=flat
|
||||
[coveralls-url]: https://coveralls.io/r/jshttp/http-errors
|
||||
[downloads-image]: https://img.shields.io/npm/dm/http-errors.svg?style=flat
|
||||
[downloads-url]: https://npmjs.org/package/http-errors
|
||||
@ -0,0 +1,126 @@
|
||||
|
||||
var statuses = require('statuses');
|
||||
var inherits = require('inherits');
|
||||
|
||||
function toIdentifier(str) {
|
||||
return str.split(' ').map(function (token) {
|
||||
return token.slice(0, 1).toUpperCase() + token.slice(1)
|
||||
}).join('').replace(/[^ _0-9a-z]/gi, '')
|
||||
}
|
||||
|
||||
exports = module.exports = function httpError() {
|
||||
// so much arity going on ~_~
|
||||
var err;
|
||||
var msg;
|
||||
var status = 500;
|
||||
var props = {};
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var arg = arguments[i];
|
||||
if (arg instanceof Error) {
|
||||
err = arg;
|
||||
status = err.status || err.statusCode || status;
|
||||
continue;
|
||||
}
|
||||
switch (typeof arg) {
|
||||
case 'string':
|
||||
msg = arg;
|
||||
break;
|
||||
case 'number':
|
||||
status = arg;
|
||||
break;
|
||||
case 'object':
|
||||
props = arg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof status !== 'number' || !statuses[status]) {
|
||||
status = 500
|
||||
}
|
||||
|
||||
// constructor
|
||||
var HttpError = exports[status]
|
||||
|
||||
if (!err) {
|
||||
// create error
|
||||
err = HttpError
|
||||
? new HttpError(msg)
|
||||
: new Error(msg || statuses[status])
|
||||
Error.captureStackTrace(err, httpError)
|
||||
}
|
||||
|
||||
if (!HttpError || !(err instanceof HttpError)) {
|
||||
// add properties to generic error
|
||||
err.expose = status < 500
|
||||
err.status = err.statusCode = status
|
||||
}
|
||||
|
||||
for (var key in props) {
|
||||
if (key !== 'status' && key !== 'statusCode') {
|
||||
err[key] = props[key]
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
var HttpError = exports.HttpError = function HttpError() {
|
||||
throw new TypeError('cannot construct abstract class');
|
||||
};
|
||||
|
||||
inherits(HttpError, Error);
|
||||
|
||||
// create generic error objects
|
||||
var codes = statuses.codes.filter(function (num) {
|
||||
return num >= 400;
|
||||
});
|
||||
|
||||
codes.forEach(function (code) {
|
||||
var name = toIdentifier(statuses[code])
|
||||
var className = name.match(/Error$/) ? name : name + 'Error'
|
||||
|
||||
if (code >= 500) {
|
||||
var ServerError = function ServerError(msg) {
|
||||
var self = new Error(msg != null ? msg : statuses[code])
|
||||
Error.captureStackTrace(self, ServerError)
|
||||
self.__proto__ = ServerError.prototype
|
||||
Object.defineProperty(self, 'name', {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: className,
|
||||
writable: true
|
||||
})
|
||||
return self
|
||||
}
|
||||
inherits(ServerError, HttpError);
|
||||
ServerError.prototype.status =
|
||||
ServerError.prototype.statusCode = code;
|
||||
ServerError.prototype.expose = false;
|
||||
exports[code] =
|
||||
exports[name] = ServerError
|
||||
return;
|
||||
}
|
||||
|
||||
var ClientError = function ClientError(msg) {
|
||||
var self = new Error(msg != null ? msg : statuses[code])
|
||||
Error.captureStackTrace(self, ClientError)
|
||||
self.__proto__ = ClientError.prototype
|
||||
Object.defineProperty(self, 'name', {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: className,
|
||||
writable: true
|
||||
})
|
||||
return self
|
||||
}
|
||||
inherits(ClientError, HttpError);
|
||||
ClientError.prototype.status =
|
||||
ClientError.prototype.statusCode = code;
|
||||
ClientError.prototype.expose = true;
|
||||
exports[code] =
|
||||
exports[name] = ClientError
|
||||
return;
|
||||
});
|
||||
|
||||
// backwards-compatibility
|
||||
exports["I'mateapot"] = exports.ImATeapot
|
||||
@ -0,0 +1,16 @@
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
Browser-friendly inheritance fully compatible with standard node.js
|
||||
[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).
|
||||
|
||||
This package exports standard `inherits` from node.js `util` module in
|
||||
node environment, but also provides alternative browser-friendly
|
||||
implementation through [browser
|
||||
field](https://gist.github.com/shtylman/4339901). Alternative
|
||||
implementation is a literal copy of standard one located in standalone
|
||||
module to avoid requiring of `util`. It also has a shim for old
|
||||
browsers with no `Object.create` support.
|
||||
|
||||
While keeping you sure you are using standard `inherits`
|
||||
implementation in node.js environment, it allows bundlers such as
|
||||
[browserify](https://github.com/substack/node-browserify) to not
|
||||
include full `util` package to your client code if all you need is
|
||||
just `inherits` function. It worth, because browser shim for `util`
|
||||
package is large and `inherits` is often the single function you need
|
||||
from it.
|
||||
|
||||
It's recommended to use this package instead of
|
||||
`require('util').inherits` for any code that has chances to be used
|
||||
not only in node.js but in browser too.
|
||||
|
||||
## usage
|
||||
|
||||
```js
|
||||
var inherits = require('inherits');
|
||||
// then use exactly as the standard one
|
||||
```
|
||||
|
||||
## note on version ~1.0
|
||||
|
||||
Version ~1.0 had completely different motivation and is not compatible
|
||||
neither with 2.0 nor with standard node.js `inherits`.
|
||||
|
||||
If you are using version ~1.0 and planning to switch to ~2.0, be
|
||||
careful:
|
||||
|
||||
* new version uses `super_` instead of `super` for referencing
|
||||
superclass
|
||||
* new version overwrites current prototype while old one preserves any
|
||||
existing fields on it
|
||||
@ -0,0 +1 @@
|
||||
module.exports = require('util').inherits
|
||||
@ -0,0 +1,23 @@
|
||||
if (typeof Object.create === 'function') {
|
||||
// implementation from standard node.js 'util' module
|
||||
module.exports = function inherits(ctor, superCtor) {
|
||||
ctor.super_ = superCtor
|
||||
ctor.prototype = Object.create(superCtor.prototype, {
|
||||
constructor: {
|
||||
value: ctor,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
};
|
||||
} else {
|
||||
// old school shim for old browsers
|
||||
module.exports = function inherits(ctor, superCtor) {
|
||||
ctor.super_ = superCtor
|
||||
var TempCtor = function () {}
|
||||
TempCtor.prototype = superCtor.prototype
|
||||
ctor.prototype = new TempCtor()
|
||||
ctor.prototype.constructor = ctor
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "inherits",
|
||||
"description": "Browser-friendly inheritance fully compatible with standard node.js inherits()",
|
||||
"version": "2.0.1",
|
||||
"keywords": [
|
||||
"inheritance",
|
||||
"class",
|
||||
"klass",
|
||||
"oop",
|
||||
"object-oriented",
|
||||
"inherits",
|
||||
"browser",
|
||||
"browserify"
|
||||
],
|
||||
"main": "./inherits.js",
|
||||
"browser": "./inherits_browser.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/inherits.git"
|
||||
},
|
||||
"license": "ISC",
|
||||
"scripts": {
|
||||
"test": "node test"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/inherits/issues"
|
||||
},
|
||||
"_id": "inherits@2.0.1",
|
||||
"dist": {
|
||||
"shasum": "b17d08d326b4423e568eff719f91b0b1cbdf69f1",
|
||||
"tarball": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
||||
},
|
||||
"_from": "inherits@2.0.1",
|
||||
"_npmVersion": "1.3.8",
|
||||
"_npmUser": {
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
}
|
||||
],
|
||||
"directories": {},
|
||||
"_shasum": "b17d08d326b4423e568eff719f91b0b1cbdf69f1",
|
||||
"_resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
|
||||
"readme": "ERROR: No README data found!",
|
||||
"homepage": "https://github.com/isaacs/inherits#readme"
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
var inherits = require('./inherits.js')
|
||||
var assert = require('assert')
|
||||
|
||||
function test(c) {
|
||||
assert(c.constructor === Child)
|
||||
assert(c.constructor.super_ === Parent)
|
||||
assert(Object.getPrototypeOf(c) === Child.prototype)
|
||||
assert(Object.getPrototypeOf(Object.getPrototypeOf(c)) === Parent.prototype)
|
||||
assert(c instanceof Child)
|
||||
assert(c instanceof Parent)
|
||||
}
|
||||
|
||||
function Child() {
|
||||
Parent.call(this)
|
||||
test(this)
|
||||
}
|
||||
|
||||
function Parent() {}
|
||||
|
||||
inherits(Child, Parent)
|
||||
|
||||
var c = new Child
|
||||
test(c)
|
||||
|
||||
console.log('ok')
|
||||
@ -0,0 +1,50 @@
|
||||
1.3.0 / 2016-05-17
|
||||
==================
|
||||
|
||||
* Add `421 Misdirected Request`
|
||||
* perf: enable strict mode
|
||||
|
||||
1.2.1 / 2015-02-01
|
||||
==================
|
||||
|
||||
* Fix message for status 451
|
||||
- `451 Unavailable For Legal Reasons`
|
||||
|
||||
1.2.0 / 2014-09-28
|
||||
==================
|
||||
|
||||
* Add `208 Already Repored`
|
||||
* Add `226 IM Used`
|
||||
* Add `306 (Unused)`
|
||||
* Add `415 Unable For Legal Reasons`
|
||||
* Add `508 Loop Detected`
|
||||
|
||||
1.1.1 / 2014-09-24
|
||||
==================
|
||||
|
||||
* Add missing 308 to `codes.json`
|
||||
|
||||
1.1.0 / 2014-09-21
|
||||
==================
|
||||
|
||||
* Add `codes.json` for universal support
|
||||
|
||||
1.0.4 / 2014-08-20
|
||||
==================
|
||||
|
||||
* Package cleanup
|
||||
|
||||
1.0.3 / 2014-06-08
|
||||
==================
|
||||
|
||||
* Add 308 to `.redirect` category
|
||||
|
||||
1.0.2 / 2014-03-13
|
||||
==================
|
||||
|
||||
* Add `.retry` category
|
||||
|
||||
1.0.1 / 2014-03-12
|
||||
==================
|
||||
|
||||
* Initial release
|
||||
@ -0,0 +1,23 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
|
||||
Copyright (c) 2016 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.
|
||||
@ -0,0 +1,114 @@
|
||||
# Statuses
|
||||
|
||||
[![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]
|
||||
|
||||
HTTP status utility for node.
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var status = require('statuses')
|
||||
```
|
||||
|
||||
### var code = status(Integer || String)
|
||||
|
||||
If `Integer` or `String` is a valid HTTP code or status message, then the appropriate `code` will be returned. Otherwise, an error will be thrown.
|
||||
|
||||
```js
|
||||
status(403) // => 403
|
||||
status('403') // => 403
|
||||
status('forbidden') // => 403
|
||||
status('Forbidden') // => 403
|
||||
status(306) // throws, as it's not supported by node.js
|
||||
```
|
||||
|
||||
### status.codes
|
||||
|
||||
Returns an array of all the status codes as `Integer`s.
|
||||
|
||||
### var msg = status[code]
|
||||
|
||||
Map of `code` to `status message`. `undefined` for invalid `code`s.
|
||||
|
||||
```js
|
||||
status[404] // => 'Not Found'
|
||||
```
|
||||
|
||||
### var code = status[msg]
|
||||
|
||||
Map of `status message` to `code`. `msg` can either be title-cased or lower-cased. `undefined` for invalid `status message`s.
|
||||
|
||||
```js
|
||||
status['not found'] // => 404
|
||||
status['Not Found'] // => 404
|
||||
```
|
||||
|
||||
### status.redirect[code]
|
||||
|
||||
Returns `true` if a status code is a valid redirect status.
|
||||
|
||||
```js
|
||||
status.redirect[200] // => undefined
|
||||
status.redirect[301] // => true
|
||||
```
|
||||
|
||||
### status.empty[code]
|
||||
|
||||
Returns `true` if a status code expects an empty body.
|
||||
|
||||
```js
|
||||
status.empty[200] // => undefined
|
||||
status.empty[204] // => true
|
||||
status.empty[304] // => true
|
||||
```
|
||||
|
||||
### status.retry[code]
|
||||
|
||||
Returns `true` if you should retry the rest.
|
||||
|
||||
```js
|
||||
status.retry[501] // => undefined
|
||||
status.retry[503] // => true
|
||||
```
|
||||
|
||||
### statuses/codes.json
|
||||
|
||||
```js
|
||||
var codes = require('statuses/codes.json')
|
||||
```
|
||||
|
||||
This is a JSON file of the status codes
|
||||
taken from `require('http').STATUS_CODES`.
|
||||
This is saved so that codes are consistent even in older node.js versions.
|
||||
For example, `308` will be added in v0.12.
|
||||
|
||||
## Adding Status Codes
|
||||
|
||||
The status codes are primarily sourced from http://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv.
|
||||
Additionally, custom codes are added from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes.
|
||||
These are added manually in the `lib/*.json` files.
|
||||
If you would like to add a status code, add it to the appropriate JSON file.
|
||||
|
||||
To rebuild `codes.json`, run the following:
|
||||
|
||||
```bash
|
||||
# update src/iana.json
|
||||
npm run fetch
|
||||
# build codes.json
|
||||
npm run build
|
||||
```
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/statuses.svg
|
||||
[npm-url]: https://npmjs.org/package/statuses
|
||||
[node-version-image]: https://img.shields.io/badge/node.js-%3E%3D_0.6-brightgreen.svg
|
||||
[node-version-url]: https://nodejs.org/en/download
|
||||
[travis-image]: https://img.shields.io/travis/jshttp/statuses.svg
|
||||
[travis-url]: https://travis-ci.org/jshttp/statuses
|
||||
[coveralls-image]: https://img.shields.io/coveralls/jshttp/statuses.svg
|
||||
[coveralls-url]: https://coveralls.io/r/jshttp/statuses?branch=master
|
||||
[downloads-image]: https://img.shields.io/npm/dm/statuses.svg
|
||||
[downloads-url]: https://npmjs.org/package/statuses
|
||||
@ -0,0 +1,65 @@
|
||||
{
|
||||
"100": "Continue",
|
||||
"101": "Switching Protocols",
|
||||
"102": "Processing",
|
||||
"200": "OK",
|
||||
"201": "Created",
|
||||
"202": "Accepted",
|
||||
"203": "Non-Authoritative Information",
|
||||
"204": "No Content",
|
||||
"205": "Reset Content",
|
||||
"206": "Partial Content",
|
||||
"207": "Multi-Status",
|
||||
"208": "Already Reported",
|
||||
"226": "IM Used",
|
||||
"300": "Multiple Choices",
|
||||
"301": "Moved Permanently",
|
||||
"302": "Found",
|
||||
"303": "See Other",
|
||||
"304": "Not Modified",
|
||||
"305": "Use Proxy",
|
||||
"306": "(Unused)",
|
||||
"307": "Temporary Redirect",
|
||||
"308": "Permanent Redirect",
|
||||
"400": "Bad Request",
|
||||
"401": "Unauthorized",
|
||||
"402": "Payment Required",
|
||||
"403": "Forbidden",
|
||||
"404": "Not Found",
|
||||
"405": "Method Not Allowed",
|
||||
"406": "Not Acceptable",
|
||||
"407": "Proxy Authentication Required",
|
||||
"408": "Request Timeout",
|
||||
"409": "Conflict",
|
||||
"410": "Gone",
|
||||
"411": "Length Required",
|
||||
"412": "Precondition Failed",
|
||||
"413": "Payload Too Large",
|
||||
"414": "URI Too Long",
|
||||
"415": "Unsupported Media Type",
|
||||
"416": "Range Not Satisfiable",
|
||||
"417": "Expectation Failed",
|
||||
"418": "I'm a teapot",
|
||||
"421": "Misdirected Request",
|
||||
"422": "Unprocessable Entity",
|
||||
"423": "Locked",
|
||||
"424": "Failed Dependency",
|
||||
"425": "Unordered Collection",
|
||||
"426": "Upgrade Required",
|
||||
"428": "Precondition Required",
|
||||
"429": "Too Many Requests",
|
||||
"431": "Request Header Fields Too Large",
|
||||
"451": "Unavailable For Legal Reasons",
|
||||
"500": "Internal Server Error",
|
||||
"501": "Not Implemented",
|
||||
"502": "Bad Gateway",
|
||||
"503": "Service Unavailable",
|
||||
"504": "Gateway Timeout",
|
||||
"505": "HTTP Version Not Supported",
|
||||
"506": "Variant Also Negotiates",
|
||||
"507": "Insufficient Storage",
|
||||
"508": "Loop Detected",
|
||||
"509": "Bandwidth Limit Exceeded",
|
||||
"510": "Not Extended",
|
||||
"511": "Network Authentication Required"
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
/*!
|
||||
* statuses
|
||||
* Copyright(c) 2014 Jonathan Ong
|
||||
* Copyright(c) 2016 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var codes = require('./codes.json')
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
* @public
|
||||
*/
|
||||
|
||||
module.exports = status
|
||||
|
||||
// array of status codes
|
||||
status.codes = populateStatusesMap(status, codes)
|
||||
|
||||
// status codes for redirects
|
||||
status.redirect = {
|
||||
300: true,
|
||||
301: true,
|
||||
302: true,
|
||||
303: true,
|
||||
305: true,
|
||||
307: true,
|
||||
308: true
|
||||
}
|
||||
|
||||
// status codes for empty bodies
|
||||
status.empty = {
|
||||
204: true,
|
||||
205: true,
|
||||
304: true
|
||||
}
|
||||
|
||||
// status codes for when you should retry the request
|
||||
status.retry = {
|
||||
502: true,
|
||||
503: true,
|
||||
504: true
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the statuses map for given codes.
|
||||
* @private
|
||||
*/
|
||||
|
||||
function populateStatusesMap (statuses, codes) {
|
||||
var arr = []
|
||||
|
||||
Object.keys(codes).forEach(function forEachCode (code) {
|
||||
var message = codes[code]
|
||||
var status = Number(code)
|
||||
|
||||
// Populate properties
|
||||
statuses[status] = message
|
||||
statuses[message] = status
|
||||
statuses[message.toLowerCase()] = status
|
||||
|
||||
// Add to array
|
||||
arr.push(status)
|
||||
})
|
||||
|
||||
return arr
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status code.
|
||||
*
|
||||
* Given a number, this will throw if it is not a known status
|
||||
* code, otherwise the code will be returned. Given a string,
|
||||
* the string will be parsed for a number and return the code
|
||||
* if valid, otherwise will lookup the code assuming this is
|
||||
* the status message.
|
||||
*
|
||||
* @param {string|number} code
|
||||
* @returns {string}
|
||||
* @public
|
||||
*/
|
||||
|
||||
function status (code) {
|
||||
if (typeof code === 'number') {
|
||||
if (!status[code]) throw new Error('invalid status code: ' + code)
|
||||
return code
|
||||
}
|
||||
|
||||
if (typeof code !== 'string') {
|
||||
throw new TypeError('code must be a number or string')
|
||||
}
|
||||
|
||||
// '403'
|
||||
var n = parseInt(code, 10)
|
||||
if (!isNaN(n)) {
|
||||
if (!status[n]) throw new Error('invalid status code: ' + n)
|
||||
return n
|
||||
}
|
||||
|
||||
n = status[code.toLowerCase()]
|
||||
if (!n) throw new Error('invalid status message: "' + code + '"')
|
||||
return n
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
{
|
||||
"name": "statuses",
|
||||
"description": "HTTP status utility",
|
||||
"version": "1.3.0",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Douglas Christopher Wilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Ong",
|
||||
"email": "me@jongleberry.com",
|
||||
"url": "http://jongleberry.com"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jshttp/statuses"
|
||||
},
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"http",
|
||||
"status",
|
||||
"code"
|
||||
],
|
||||
"files": [
|
||||
"HISTORY.md",
|
||||
"index.js",
|
||||
"codes.json",
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"csv-parse": "1.0.1",
|
||||
"eslint": "2.10.2",
|
||||
"eslint-config-standard": "5.3.1",
|
||||
"eslint-plugin-promise": "1.1.0",
|
||||
"eslint-plugin-standard": "1.3.2",
|
||||
"istanbul": "0.4.3",
|
||||
"mocha": "1.21.5",
|
||||
"stream-to-array": "2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node scripts/build.js",
|
||||
"fetch": "node scripts/fetch.js",
|
||||
"lint": "eslint **/*.js",
|
||||
"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/",
|
||||
"update": "npm run fetch && npm run build"
|
||||
},
|
||||
"gitHead": "b3e31e8c32dd8107e898b44b8c0b2dfff3cba495",
|
||||
"bugs": {
|
||||
"url": "https://github.com/jshttp/statuses/issues"
|
||||
},
|
||||
"homepage": "https://github.com/jshttp/statuses",
|
||||
"_id": "statuses@1.3.0",
|
||||
"_shasum": "8e55758cb20e7682c1f4fce8dcab30bf01d1e07a",
|
||||
"_from": "statuses@>=1.2.1 <2.0.0",
|
||||
"_npmVersion": "1.4.28",
|
||||
"_npmUser": {
|
||||
"name": "dougwilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "defunctzombie",
|
||||
"email": "shtylman@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "dougwilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
{
|
||||
"name": "fishrock123",
|
||||
"email": "fishrock123@rocketmail.com"
|
||||
},
|
||||
{
|
||||
"name": "jongleberry",
|
||||
"email": "jonathanrichardong@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "mscdex",
|
||||
"email": "mscdex@mscdex.net"
|
||||
},
|
||||
{
|
||||
"name": "tjholowaychuk",
|
||||
"email": "tj@vision-media.ca"
|
||||
}
|
||||
],
|
||||
"dist": {
|
||||
"shasum": "8e55758cb20e7682c1f4fce8dcab30bf01d1e07a",
|
||||
"tarball": "https://registry.npmjs.org/statuses/-/statuses-1.3.0.tgz"
|
||||
},
|
||||
"_npmOperationalInternal": {
|
||||
"host": "packages-12-west.internal.npmjs.com",
|
||||
"tmp": "tmp/statuses-1.3.0.tgz_1463517875633_0.19560232176445425"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.0.tgz"
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
{
|
||||
"name": "http-errors",
|
||||
"description": "Create HTTP error objects",
|
||||
"version": "1.4.0",
|
||||
"author": {
|
||||
"name": "Jonathan Ong",
|
||||
"email": "me@jongleberry.com",
|
||||
"url": "http://jongleberry.com"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Alan Plum",
|
||||
"email": "me@pluma.io"
|
||||
},
|
||||
{
|
||||
"name": "Douglas Christopher Wilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/jshttp/http-errors.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"inherits": "2.0.1",
|
||||
"statuses": ">= 1.2.1 < 2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"istanbul": "0.4.2",
|
||||
"mocha": "1.21.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha --reporter spec --bail",
|
||||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot",
|
||||
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter dot"
|
||||
},
|
||||
"keywords": [
|
||||
"http",
|
||||
"error"
|
||||
],
|
||||
"files": [
|
||||
"index.js",
|
||||
"HISTORY.md",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
],
|
||||
"gitHead": "3d49066ba40bd7f512bc4cf367bbe650c5f2191f",
|
||||
"bugs": {
|
||||
"url": "https://github.com/jshttp/http-errors/issues"
|
||||
},
|
||||
"homepage": "https://github.com/jshttp/http-errors#readme",
|
||||
"_id": "http-errors@1.4.0",
|
||||
"_shasum": "6c0242dea6b3df7afda153c71089b31c6e82aabf",
|
||||
"_from": "http-errors@>=1.4.0 <1.5.0",
|
||||
"_npmVersion": "2.14.7",
|
||||
"_nodeVersion": "4.2.3",
|
||||
"_npmUser": {
|
||||
"name": "dougwilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
"dist": {
|
||||
"shasum": "6c0242dea6b3df7afda153c71089b31c6e82aabf",
|
||||
"tarball": "https://registry.npmjs.org/http-errors/-/http-errors-1.4.0.tgz"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "egeste",
|
||||
"email": "npm@egeste.net"
|
||||
},
|
||||
{
|
||||
"name": "jongleberry",
|
||||
"email": "jonathanrichardong@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "dougwilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
}
|
||||
],
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.4.0.tgz"
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
*~
|
||||
*sublime-*
|
||||
generation
|
||||
test
|
||||
wiki
|
||||
coverage
|
||||
@ -0,0 +1,20 @@
|
||||
sudo: false
|
||||
env:
|
||||
- CXX=g++-4.8
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.11"
|
||||
- "0.12"
|
||||
- "iojs"
|
||||
- "4.0"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-4.8
|
||||
- g++-4.8
|
||||
before_install:
|
||||
- "test $TRAVIS_NODE_VERSION != '0.8' || npm install -g npm@1.2.8000"
|
||||
@ -0,0 +1,93 @@
|
||||
|
||||
# 0.4.13 / 2015-10-01
|
||||
|
||||
* Fix silly mistake in deprecation notice.
|
||||
|
||||
|
||||
# 0.4.12 / 2015-09-26
|
||||
|
||||
* Node v4 support:
|
||||
* Added CESU-8 decoding (#106)
|
||||
* Added deprecation notice for `extendNodeEncodings`
|
||||
* Added Travis tests for Node v4 and io.js latest (#105 by @Mithgol)
|
||||
|
||||
|
||||
# 0.4.11 / 2015-07-03
|
||||
|
||||
* Added CESU-8 encoding.
|
||||
|
||||
|
||||
# 0.4.10 / 2015-05-26
|
||||
|
||||
* Changed UTF-16 endianness heuristic to take into account any ASCII chars, not
|
||||
just spaces. This should minimize the importance of "default" endianness.
|
||||
|
||||
|
||||
# 0.4.9 / 2015-05-24
|
||||
|
||||
* Streamlined BOM handling: strip BOM by default, add BOM when encoding if
|
||||
addBOM: true. Added docs to Readme.
|
||||
* UTF16 now uses UTF16-LE by default.
|
||||
* Fixed minor issue with big5 encoding.
|
||||
* Added io.js testing on Travis; updated node-iconv version to test against.
|
||||
Now we just skip testing SBCS encodings that node-iconv doesn't support.
|
||||
* (internal refactoring) Updated codec interface to use classes.
|
||||
* Use strict mode in all files.
|
||||
|
||||
|
||||
# 0.4.8 / 2015-04-14
|
||||
|
||||
* added alias UNICODE-1-1-UTF-7 for UTF-7 encoding (#94)
|
||||
|
||||
|
||||
# 0.4.7 / 2015-02-05
|
||||
|
||||
* stop official support of Node.js v0.8. Should still work, but no guarantees.
|
||||
reason: Packages needed for testing are hard to get on Travis CI.
|
||||
* work in environment where Object.prototype is monkey patched with enumerable
|
||||
props (#89).
|
||||
|
||||
|
||||
# 0.4.6 / 2015-01-12
|
||||
|
||||
* fix rare aliases of single-byte encodings (thanks @mscdex)
|
||||
* double the timeout for dbcs tests to make them less flaky on travis
|
||||
|
||||
|
||||
# 0.4.5 / 2014-11-20
|
||||
|
||||
* fix windows-31j and x-sjis encoding support (@nleush)
|
||||
* minor fix: undefined variable reference when internal error happens
|
||||
|
||||
|
||||
# 0.4.4 / 2014-07-16
|
||||
|
||||
* added encodings UTF-7 (RFC2152) and UTF-7-IMAP (RFC3501 Section 5.1.3)
|
||||
* fixed streaming base64 encoding
|
||||
|
||||
|
||||
# 0.4.3 / 2014-06-14
|
||||
|
||||
* added encodings UTF-16BE and UTF-16 with BOM
|
||||
|
||||
|
||||
# 0.4.2 / 2014-06-12
|
||||
|
||||
* don't throw exception if `extendNodeEncodings()` is called more than once
|
||||
|
||||
|
||||
# 0.4.1 / 2014-06-11
|
||||
|
||||
* codepage 808 added
|
||||
|
||||
|
||||
# 0.4.0 / 2014-06-10
|
||||
|
||||
* code is rewritten from scratch
|
||||
* all widespread encodings are supported
|
||||
* streaming interface added
|
||||
* browserify compatibility added
|
||||
* (optional) extend core primitive encodings to make usage even simpler
|
||||
* moved from vows to mocha as the testing framework
|
||||
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
Copyright (c) 2011 Alexander Shtuchkin
|
||||
|
||||
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.
|
||||
|
||||
@ -0,0 +1,554 @@
|
||||
"use strict"
|
||||
|
||||
// Multibyte codec. In this scheme, a character is represented by 1 or more bytes.
|
||||
// Our codec supports UTF-16 surrogates, extensions for GB18030 and unicode sequences.
|
||||
// To save memory and loading time, we read table files only when requested.
|
||||
|
||||
exports._dbcs = DBCSCodec;
|
||||
|
||||
var UNASSIGNED = -1,
|
||||
GB18030_CODE = -2,
|
||||
SEQ_START = -10,
|
||||
NODE_START = -1000,
|
||||
UNASSIGNED_NODE = new Array(0x100),
|
||||
DEF_CHAR = -1;
|
||||
|
||||
for (var i = 0; i < 0x100; i++)
|
||||
UNASSIGNED_NODE[i] = UNASSIGNED;
|
||||
|
||||
|
||||
// Class DBCSCodec reads and initializes mapping tables.
|
||||
function DBCSCodec(codecOptions, iconv) {
|
||||
this.encodingName = codecOptions.encodingName;
|
||||
if (!codecOptions)
|
||||
throw new Error("DBCS codec is called without the data.")
|
||||
if (!codecOptions.table)
|
||||
throw new Error("Encoding '" + this.encodingName + "' has no data.");
|
||||
|
||||
// Load tables.
|
||||
var mappingTable = codecOptions.table();
|
||||
|
||||
|
||||
// Decode tables: MBCS -> Unicode.
|
||||
|
||||
// decodeTables is a trie, encoded as an array of arrays of integers. Internal arrays are trie nodes and all have len = 256.
|
||||
// Trie root is decodeTables[0].
|
||||
// Values: >= 0 -> unicode character code. can be > 0xFFFF
|
||||
// == UNASSIGNED -> unknown/unassigned sequence.
|
||||
// == GB18030_CODE -> this is the end of a GB18030 4-byte sequence.
|
||||
// <= NODE_START -> index of the next node in our trie to process next byte.
|
||||
// <= SEQ_START -> index of the start of a character code sequence, in decodeTableSeq.
|
||||
this.decodeTables = [];
|
||||
this.decodeTables[0] = UNASSIGNED_NODE.slice(0); // Create root node.
|
||||
|
||||
// Sometimes a MBCS char corresponds to a sequence of unicode chars. We store them as arrays of integers here.
|
||||
this.decodeTableSeq = [];
|
||||
|
||||
// Actual mapping tables consist of chunks. Use them to fill up decode tables.
|
||||
for (var i = 0; i < mappingTable.length; i++)
|
||||
this._addDecodeChunk(mappingTable[i]);
|
||||
|
||||
this.defaultCharUnicode = iconv.defaultCharUnicode;
|
||||
|
||||
|
||||
// Encode tables: Unicode -> DBCS.
|
||||
|
||||
// `encodeTable` is array mapping from unicode char to encoded char. All its values are integers for performance.
|
||||
// Because it can be sparse, it is represented as array of buckets by 256 chars each. Bucket can be null.
|
||||
// Values: >= 0 -> it is a normal char. Write the value (if <=256 then 1 byte, if <=65536 then 2 bytes, etc.).
|
||||
// == UNASSIGNED -> no conversion found. Output a default char.
|
||||
// <= SEQ_START -> it's an index in encodeTableSeq, see below. The character starts a sequence.
|
||||
this.encodeTable = [];
|
||||
|
||||
// `encodeTableSeq` is used when a sequence of unicode characters is encoded as a single code. We use a tree of
|
||||
// objects where keys correspond to characters in sequence and leafs are the encoded dbcs values. A special DEF_CHAR key
|
||||
// means end of sequence (needed when one sequence is a strict subsequence of another).
|
||||
// Objects are kept separately from encodeTable to increase performance.
|
||||
this.encodeTableSeq = [];
|
||||
|
||||
// Some chars can be decoded, but need not be encoded.
|
||||
var skipEncodeChars = {};
|
||||
if (codecOptions.encodeSkipVals)
|
||||
for (var i = 0; i < codecOptions.encodeSkipVals.length; i++) {
|
||||
var val = codecOptions.encodeSkipVals[i];
|
||||
if (typeof val === 'number')
|
||||
skipEncodeChars[val] = true;
|
||||
else
|
||||
for (var j = val.from; j <= val.to; j++)
|
||||
skipEncodeChars[j] = true;
|
||||
}
|
||||
|
||||
// Use decode trie to recursively fill out encode tables.
|
||||
this._fillEncodeTable(0, 0, skipEncodeChars);
|
||||
|
||||
// Add more encoding pairs when needed.
|
||||
if (codecOptions.encodeAdd) {
|
||||
for (var uChar in codecOptions.encodeAdd)
|
||||
if (Object.prototype.hasOwnProperty.call(codecOptions.encodeAdd, uChar))
|
||||
this._setEncodeChar(uChar.charCodeAt(0), codecOptions.encodeAdd[uChar]);
|
||||
}
|
||||
|
||||
this.defCharSB = this.encodeTable[0][iconv.defaultCharSingleByte.charCodeAt(0)];
|
||||
if (this.defCharSB === UNASSIGNED) this.defCharSB = this.encodeTable[0]['?'];
|
||||
if (this.defCharSB === UNASSIGNED) this.defCharSB = "?".charCodeAt(0);
|
||||
|
||||
|
||||
// Load & create GB18030 tables when needed.
|
||||
if (typeof codecOptions.gb18030 === 'function') {
|
||||
this.gb18030 = codecOptions.gb18030(); // Load GB18030 ranges.
|
||||
|
||||
// Add GB18030 decode tables.
|
||||
var thirdByteNodeIdx = this.decodeTables.length;
|
||||
var thirdByteNode = this.decodeTables[thirdByteNodeIdx] = UNASSIGNED_NODE.slice(0);
|
||||
|
||||
var fourthByteNodeIdx = this.decodeTables.length;
|
||||
var fourthByteNode = this.decodeTables[fourthByteNodeIdx] = UNASSIGNED_NODE.slice(0);
|
||||
|
||||
for (var i = 0x81; i <= 0xFE; i++) {
|
||||
var secondByteNodeIdx = NODE_START - this.decodeTables[0][i];
|
||||
var secondByteNode = this.decodeTables[secondByteNodeIdx];
|
||||
for (var j = 0x30; j <= 0x39; j++)
|
||||
secondByteNode[j] = NODE_START - thirdByteNodeIdx;
|
||||
}
|
||||
for (var i = 0x81; i <= 0xFE; i++)
|
||||
thirdByteNode[i] = NODE_START - fourthByteNodeIdx;
|
||||
for (var i = 0x30; i <= 0x39; i++)
|
||||
fourthByteNode[i] = GB18030_CODE
|
||||
}
|
||||
}
|
||||
|
||||
DBCSCodec.prototype.encoder = DBCSEncoder;
|
||||
DBCSCodec.prototype.decoder = DBCSDecoder;
|
||||
|
||||
// Decoder helpers
|
||||
DBCSCodec.prototype._getDecodeTrieNode = function(addr) {
|
||||
var bytes = [];
|
||||
for (; addr > 0; addr >>= 8)
|
||||
bytes.push(addr & 0xFF);
|
||||
if (bytes.length == 0)
|
||||
bytes.push(0);
|
||||
|
||||
var node = this.decodeTables[0];
|
||||
for (var i = bytes.length-1; i > 0; i--) { // Traverse nodes deeper into the trie.
|
||||
var val = node[bytes[i]];
|
||||
|
||||
if (val == UNASSIGNED) { // Create new node.
|
||||
node[bytes[i]] = NODE_START - this.decodeTables.length;
|
||||
this.decodeTables.push(node = UNASSIGNED_NODE.slice(0));
|
||||
}
|
||||
else if (val <= NODE_START) { // Existing node.
|
||||
node = this.decodeTables[NODE_START - val];
|
||||
}
|
||||
else
|
||||
throw new Error("Overwrite byte in " + this.encodingName + ", addr: " + addr.toString(16));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
DBCSCodec.prototype._addDecodeChunk = function(chunk) {
|
||||
// First element of chunk is the hex mbcs code where we start.
|
||||
var curAddr = parseInt(chunk[0], 16);
|
||||
|
||||
// Choose the decoding node where we'll write our chars.
|
||||
var writeTable = this._getDecodeTrieNode(curAddr);
|
||||
curAddr = curAddr & 0xFF;
|
||||
|
||||
// Write all other elements of the chunk to the table.
|
||||
for (var k = 1; k < chunk.length; k++) {
|
||||
var part = chunk[k];
|
||||
if (typeof part === "string") { // String, write as-is.
|
||||
for (var l = 0; l < part.length;) {
|
||||
var code = part.charCodeAt(l++);
|
||||
if (0xD800 <= code && code < 0xDC00) { // Decode surrogate
|
||||
var codeTrail = part.charCodeAt(l++);
|
||||
if (0xDC00 <= codeTrail && codeTrail < 0xE000)
|
||||
writeTable[curAddr++] = 0x10000 + (code - 0xD800) * 0x400 + (codeTrail - 0xDC00);
|
||||
else
|
||||
throw new Error("Incorrect surrogate pair in " + this.encodingName + " at chunk " + chunk[0]);
|
||||
}
|
||||
else if (0x0FF0 < code && code <= 0x0FFF) { // Character sequence (our own encoding used)
|
||||
var len = 0xFFF - code + 2;
|
||||
var seq = [];
|
||||
for (var m = 0; m < len; m++)
|
||||
seq.push(part.charCodeAt(l++)); // Simple variation: don't support surrogates or subsequences in seq.
|
||||
|
||||
writeTable[curAddr++] = SEQ_START - this.decodeTableSeq.length;
|
||||
this.decodeTableSeq.push(seq);
|
||||
}
|
||||
else
|
||||
writeTable[curAddr++] = code; // Basic char
|
||||
}
|
||||
}
|
||||
else if (typeof part === "number") { // Integer, meaning increasing sequence starting with prev character.
|
||||
var charCode = writeTable[curAddr - 1] + 1;
|
||||
for (var l = 0; l < part; l++)
|
||||
writeTable[curAddr++] = charCode++;
|
||||
}
|
||||
else
|
||||
throw new Error("Incorrect type '" + typeof part + "' given in " + this.encodingName + " at chunk " + chunk[0]);
|
||||
}
|
||||
if (curAddr > 0xFF)
|
||||
throw new Error("Incorrect chunk in " + this.encodingName + " at addr " + chunk[0] + ": too long" + curAddr);
|
||||
}
|
||||
|
||||
// Encoder helpers
|
||||
DBCSCodec.prototype._getEncodeBucket = function(uCode) {
|
||||
var high = uCode >> 8; // This could be > 0xFF because of astral characters.
|
||||
if (this.encodeTable[high] === undefined)
|
||||
this.encodeTable[high] = UNASSIGNED_NODE.slice(0); // Create bucket on demand.
|
||||
return this.encodeTable[high];
|
||||
}
|
||||
|
||||
DBCSCodec.prototype._setEncodeChar = function(uCode, dbcsCode) {
|
||||
var bucket = this._getEncodeBucket(uCode);
|
||||
var low = uCode & 0xFF;
|
||||
if (bucket[low] <= SEQ_START)
|
||||
this.encodeTableSeq[SEQ_START-bucket[low]][DEF_CHAR] = dbcsCode; // There's already a sequence, set a single-char subsequence of it.
|
||||
else if (bucket[low] == UNASSIGNED)
|
||||
bucket[low] = dbcsCode;
|
||||
}
|
||||
|
||||
DBCSCodec.prototype._setEncodeSequence = function(seq, dbcsCode) {
|
||||
|
||||
// Get the root of character tree according to first character of the sequence.
|
||||
var uCode = seq[0];
|
||||
var bucket = this._getEncodeBucket(uCode);
|
||||
var low = uCode & 0xFF;
|
||||
|
||||
var node;
|
||||
if (bucket[low] <= SEQ_START) {
|
||||
// There's already a sequence with - use it.
|
||||
node = this.encodeTableSeq[SEQ_START-bucket[low]];
|
||||
}
|
||||
else {
|
||||
// There was no sequence object - allocate a new one.
|
||||
node = {};
|
||||
if (bucket[low] !== UNASSIGNED) node[DEF_CHAR] = bucket[low]; // If a char was set before - make it a single-char subsequence.
|
||||
bucket[low] = SEQ_START - this.encodeTableSeq.length;
|
||||
this.encodeTableSeq.push(node);
|
||||
}
|
||||
|
||||
// Traverse the character tree, allocating new nodes as needed.
|
||||
for (var j = 1; j < seq.length-1; j++) {
|
||||
var oldVal = node[uCode];
|
||||
if (typeof oldVal === 'object')
|
||||
node = oldVal;
|
||||
else {
|
||||
node = node[uCode] = {}
|
||||
if (oldVal !== undefined)
|
||||
node[DEF_CHAR] = oldVal
|
||||
}
|
||||
}
|
||||
|
||||
// Set the leaf to given dbcsCode.
|
||||
uCode = seq[seq.length-1];
|
||||
node[uCode] = dbcsCode;
|
||||
}
|
||||
|
||||
DBCSCodec.prototype._fillEncodeTable = function(nodeIdx, prefix, skipEncodeChars) {
|
||||
var node = this.decodeTables[nodeIdx];
|
||||
for (var i = 0; i < 0x100; i++) {
|
||||
var uCode = node[i];
|
||||
var mbCode = prefix + i;
|
||||
if (skipEncodeChars[mbCode])
|
||||
continue;
|
||||
|
||||
if (uCode >= 0)
|
||||
this._setEncodeChar(uCode, mbCode);
|
||||
else if (uCode <= NODE_START)
|
||||
this._fillEncodeTable(NODE_START - uCode, mbCode << 8, skipEncodeChars);
|
||||
else if (uCode <= SEQ_START)
|
||||
this._setEncodeSequence(this.decodeTableSeq[SEQ_START - uCode], mbCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// == Encoder ==================================================================
|
||||
|
||||
function DBCSEncoder(options, codec) {
|
||||
// Encoder state
|
||||
this.leadSurrogate = -1;
|
||||
this.seqObj = undefined;
|
||||
|
||||
// Static data
|
||||
this.encodeTable = codec.encodeTable;
|
||||
this.encodeTableSeq = codec.encodeTableSeq;
|
||||
this.defaultCharSingleByte = codec.defCharSB;
|
||||
this.gb18030 = codec.gb18030;
|
||||
}
|
||||
|
||||
DBCSEncoder.prototype.write = function(str) {
|
||||
var newBuf = new Buffer(str.length * (this.gb18030 ? 4 : 3)),
|
||||
leadSurrogate = this.leadSurrogate,
|
||||
seqObj = this.seqObj, nextChar = -1,
|
||||
i = 0, j = 0;
|
||||
|
||||
while (true) {
|
||||
// 0. Get next character.
|
||||
if (nextChar === -1) {
|
||||
if (i == str.length) break;
|
||||
var uCode = str.charCodeAt(i++);
|
||||
}
|
||||
else {
|
||||
var uCode = nextChar;
|
||||
nextChar = -1;
|
||||
}
|
||||
|
||||
// 1. Handle surrogates.
|
||||
if (0xD800 <= uCode && uCode < 0xE000) { // Char is one of surrogates.
|
||||
if (uCode < 0xDC00) { // We've got lead surrogate.
|
||||
if (leadSurrogate === -1) {
|
||||
leadSurrogate = uCode;
|
||||
continue;
|
||||
} else {
|
||||
leadSurrogate = uCode;
|
||||
// Double lead surrogate found.
|
||||
uCode = UNASSIGNED;
|
||||
}
|
||||
} else { // We've got trail surrogate.
|
||||
if (leadSurrogate !== -1) {
|
||||
uCode = 0x10000 + (leadSurrogate - 0xD800) * 0x400 + (uCode - 0xDC00);
|
||||
leadSurrogate = -1;
|
||||
} else {
|
||||
// Incomplete surrogate pair - only trail surrogate found.
|
||||
uCode = UNASSIGNED;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (leadSurrogate !== -1) {
|
||||
// Incomplete surrogate pair - only lead surrogate found.
|
||||
nextChar = uCode; uCode = UNASSIGNED; // Write an error, then current char.
|
||||
leadSurrogate = -1;
|
||||
}
|
||||
|
||||
// 2. Convert uCode character.
|
||||
var dbcsCode = UNASSIGNED;
|
||||
if (seqObj !== undefined && uCode != UNASSIGNED) { // We are in the middle of the sequence
|
||||
var resCode = seqObj[uCode];
|
||||
if (typeof resCode === 'object') { // Sequence continues.
|
||||
seqObj = resCode;
|
||||
continue;
|
||||
|
||||
} else if (typeof resCode == 'number') { // Sequence finished. Write it.
|
||||
dbcsCode = resCode;
|
||||
|
||||
} else if (resCode == undefined) { // Current character is not part of the sequence.
|
||||
|
||||
// Try default character for this sequence
|
||||
resCode = seqObj[DEF_CHAR];
|
||||
if (resCode !== undefined) {
|
||||
dbcsCode = resCode; // Found. Write it.
|
||||
nextChar = uCode; // Current character will be written too in the next iteration.
|
||||
|
||||
} else {
|
||||
// TODO: What if we have no default? (resCode == undefined)
|
||||
// Then, we should write first char of the sequence as-is and try the rest recursively.
|
||||
// Didn't do it for now because no encoding has this situation yet.
|
||||
// Currently, just skip the sequence and write current char.
|
||||
}
|
||||
}
|
||||
seqObj = undefined;
|
||||
}
|
||||
else if (uCode >= 0) { // Regular character
|
||||
var subtable = this.encodeTable[uCode >> 8];
|
||||
if (subtable !== undefined)
|
||||
dbcsCode = subtable[uCode & 0xFF];
|
||||
|
||||
if (dbcsCode <= SEQ_START) { // Sequence start
|
||||
seqObj = this.encodeTableSeq[SEQ_START-dbcsCode];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dbcsCode == UNASSIGNED && this.gb18030) {
|
||||
// Use GB18030 algorithm to find character(s) to write.
|
||||
var idx = findIdx(this.gb18030.uChars, uCode);
|
||||
if (idx != -1) {
|
||||
var dbcsCode = this.gb18030.gbChars[idx] + (uCode - this.gb18030.uChars[idx]);
|
||||
newBuf[j++] = 0x81 + Math.floor(dbcsCode / 12600); dbcsCode = dbcsCode % 12600;
|
||||
newBuf[j++] = 0x30 + Math.floor(dbcsCode / 1260); dbcsCode = dbcsCode % 1260;
|
||||
newBuf[j++] = 0x81 + Math.floor(dbcsCode / 10); dbcsCode = dbcsCode % 10;
|
||||
newBuf[j++] = 0x30 + dbcsCode;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Write dbcsCode character.
|
||||
if (dbcsCode === UNASSIGNED)
|
||||
dbcsCode = this.defaultCharSingleByte;
|
||||
|
||||
if (dbcsCode < 0x100) {
|
||||
newBuf[j++] = dbcsCode;
|
||||
}
|
||||
else if (dbcsCode < 0x10000) {
|
||||
newBuf[j++] = dbcsCode >> 8; // high byte
|
||||
newBuf[j++] = dbcsCode & 0xFF; // low byte
|
||||
}
|
||||
else {
|
||||
newBuf[j++] = dbcsCode >> 16;
|
||||
newBuf[j++] = (dbcsCode >> 8) & 0xFF;
|
||||
newBuf[j++] = dbcsCode & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
this.seqObj = seqObj;
|
||||
this.leadSurrogate = leadSurrogate;
|
||||
return newBuf.slice(0, j);
|
||||
}
|
||||
|
||||
DBCSEncoder.prototype.end = function() {
|
||||
if (this.leadSurrogate === -1 && this.seqObj === undefined)
|
||||
return; // All clean. Most often case.
|
||||
|
||||
var newBuf = new Buffer(10), j = 0;
|
||||
|
||||
if (this.seqObj) { // We're in the sequence.
|
||||
var dbcsCode = this.seqObj[DEF_CHAR];
|
||||
if (dbcsCode !== undefined) { // Write beginning of the sequence.
|
||||
if (dbcsCode < 0x100) {
|
||||
newBuf[j++] = dbcsCode;
|
||||
}
|
||||
else {
|
||||
newBuf[j++] = dbcsCode >> 8; // high byte
|
||||
newBuf[j++] = dbcsCode & 0xFF; // low byte
|
||||
}
|
||||
} else {
|
||||
// See todo above.
|
||||
}
|
||||
this.seqObj = undefined;
|
||||
}
|
||||
|
||||
if (this.leadSurrogate !== -1) {
|
||||
// Incomplete surrogate pair - only lead surrogate found.
|
||||
newBuf[j++] = this.defaultCharSingleByte;
|
||||
this.leadSurrogate = -1;
|
||||
}
|
||||
|
||||
return newBuf.slice(0, j);
|
||||
}
|
||||
|
||||
// Export for testing
|
||||
DBCSEncoder.prototype.findIdx = findIdx;
|
||||
|
||||
|
||||
// == Decoder ==================================================================
|
||||
|
||||
function DBCSDecoder(options, codec) {
|
||||
// Decoder state
|
||||
this.nodeIdx = 0;
|
||||
this.prevBuf = new Buffer(0);
|
||||
|
||||
// Static data
|
||||
this.decodeTables = codec.decodeTables;
|
||||
this.decodeTableSeq = codec.decodeTableSeq;
|
||||
this.defaultCharUnicode = codec.defaultCharUnicode;
|
||||
this.gb18030 = codec.gb18030;
|
||||
}
|
||||
|
||||
DBCSDecoder.prototype.write = function(buf) {
|
||||
var newBuf = new Buffer(buf.length*2),
|
||||
nodeIdx = this.nodeIdx,
|
||||
prevBuf = this.prevBuf, prevBufOffset = this.prevBuf.length,
|
||||
seqStart = -this.prevBuf.length, // idx of the start of current parsed sequence.
|
||||
uCode;
|
||||
|
||||
if (prevBufOffset > 0) // Make prev buf overlap a little to make it easier to slice later.
|
||||
prevBuf = Buffer.concat([prevBuf, buf.slice(0, 10)]);
|
||||
|
||||
for (var i = 0, j = 0; i < buf.length; i++) {
|
||||
var curByte = (i >= 0) ? buf[i] : prevBuf[i + prevBufOffset];
|
||||
|
||||
// Lookup in current trie node.
|
||||
var uCode = this.decodeTables[nodeIdx][curByte];
|
||||
|
||||
if (uCode >= 0) {
|
||||
// Normal character, just use it.
|
||||
}
|
||||
else if (uCode === UNASSIGNED) { // Unknown char.
|
||||
// TODO: Callback with seq.
|
||||
//var curSeq = (seqStart >= 0) ? buf.slice(seqStart, i+1) : prevBuf.slice(seqStart + prevBufOffset, i+1 + prevBufOffset);
|
||||
i = seqStart; // Try to parse again, after skipping first byte of the sequence ('i' will be incremented by 'for' cycle).
|
||||
uCode = this.defaultCharUnicode.charCodeAt(0);
|
||||
}
|
||||
else if (uCode === GB18030_CODE) {
|
||||
var curSeq = (seqStart >= 0) ? buf.slice(seqStart, i+1) : prevBuf.slice(seqStart + prevBufOffset, i+1 + prevBufOffset);
|
||||
var ptr = (curSeq[0]-0x81)*12600 + (curSeq[1]-0x30)*1260 + (curSeq[2]-0x81)*10 + (curSeq[3]-0x30);
|
||||
var idx = findIdx(this.gb18030.gbChars, ptr);
|
||||
uCode = this.gb18030.uChars[idx] + ptr - this.gb18030.gbChars[idx];
|
||||
}
|
||||
else if (uCode <= NODE_START) { // Go to next trie node.
|
||||
nodeIdx = NODE_START - uCode;
|
||||
continue;
|
||||
}
|
||||
else if (uCode <= SEQ_START) { // Output a sequence of chars.
|
||||
var seq = this.decodeTableSeq[SEQ_START - uCode];
|
||||
for (var k = 0; k < seq.length - 1; k++) {
|
||||
uCode = seq[k];
|
||||
newBuf[j++] = uCode & 0xFF;
|
||||
newBuf[j++] = uCode >> 8;
|
||||
}
|
||||
uCode = seq[seq.length-1];
|
||||
}
|
||||
else
|
||||
throw new Error("iconv-lite internal error: invalid decoding table value " + uCode + " at " + nodeIdx + "/" + curByte);
|
||||
|
||||
// Write the character to buffer, handling higher planes using surrogate pair.
|
||||
if (uCode > 0xFFFF) {
|
||||
uCode -= 0x10000;
|
||||
var uCodeLead = 0xD800 + Math.floor(uCode / 0x400);
|
||||
newBuf[j++] = uCodeLead & 0xFF;
|
||||
newBuf[j++] = uCodeLead >> 8;
|
||||
|
||||
uCode = 0xDC00 + uCode % 0x400;
|
||||
}
|
||||
newBuf[j++] = uCode & 0xFF;
|
||||
newBuf[j++] = uCode >> 8;
|
||||
|
||||
// Reset trie node.
|
||||
nodeIdx = 0; seqStart = i+1;
|
||||
}
|
||||
|
||||
this.nodeIdx = nodeIdx;
|
||||
this.prevBuf = (seqStart >= 0) ? buf.slice(seqStart) : prevBuf.slice(seqStart + prevBufOffset);
|
||||
return newBuf.slice(0, j).toString('ucs2');
|
||||
}
|
||||
|
||||
DBCSDecoder.prototype.end = function() {
|
||||
var ret = '';
|
||||
|
||||
// Try to parse all remaining chars.
|
||||
while (this.prevBuf.length > 0) {
|
||||
// Skip 1 character in the buffer.
|
||||
ret += this.defaultCharUnicode;
|
||||
var buf = this.prevBuf.slice(1);
|
||||
|
||||
// Parse remaining as usual.
|
||||
this.prevBuf = new Buffer(0);
|
||||
this.nodeIdx = 0;
|
||||
if (buf.length > 0)
|
||||
ret += this.write(buf);
|
||||
}
|
||||
|
||||
this.nodeIdx = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Binary search for GB18030. Returns largest i such that table[i] <= val.
|
||||
function findIdx(table, val) {
|
||||
if (table[0] > val)
|
||||
return -1;
|
||||
|
||||
var l = 0, r = table.length;
|
||||
while (l < r-1) { // always table[l] <= val < table[r]
|
||||
var mid = l + Math.floor((r-l+1)/2);
|
||||
if (table[mid] <= val)
|
||||
l = mid;
|
||||
else
|
||||
r = mid;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
@ -0,0 +1,170 @@
|
||||
"use strict"
|
||||
|
||||
// Description of supported double byte encodings and aliases.
|
||||
// Tables are not require()-d until they are needed to speed up library load.
|
||||
// require()-s are direct to support Browserify.
|
||||
|
||||
module.exports = {
|
||||
|
||||
// == Japanese/ShiftJIS ====================================================
|
||||
// All japanese encodings are based on JIS X set of standards:
|
||||
// JIS X 0201 - Single-byte encoding of ASCII + ¥ + Kana chars at 0xA1-0xDF.
|
||||
// JIS X 0208 - Main set of 6879 characters, placed in 94x94 plane, to be encoded by 2 bytes.
|
||||
// Has several variations in 1978, 1983, 1990 and 1997.
|
||||
// JIS X 0212 - Supplementary plane of 6067 chars in 94x94 plane. 1990. Effectively dead.
|
||||
// JIS X 0213 - Extension and modern replacement of 0208 and 0212. Total chars: 11233.
|
||||
// 2 planes, first is superset of 0208, second - revised 0212.
|
||||
// Introduced in 2000, revised 2004. Some characters are in Unicode Plane 2 (0x2xxxx)
|
||||
|
||||
// Byte encodings are:
|
||||
// * Shift_JIS: Compatible with 0201, uses not defined chars in top half as lead bytes for double-byte
|
||||
// encoding of 0208. Lead byte ranges: 0x81-0x9F, 0xE0-0xEF; Trail byte ranges: 0x40-0x7E, 0x80-0x9E, 0x9F-0xFC.
|
||||
// Windows CP932 is a superset of Shift_JIS. Some companies added more chars, notably KDDI.
|
||||
// * EUC-JP: Up to 3 bytes per character. Used mostly on *nixes.
|
||||
// 0x00-0x7F - lower part of 0201
|
||||
// 0x8E, 0xA1-0xDF - upper part of 0201
|
||||
// (0xA1-0xFE)x2 - 0208 plane (94x94).
|
||||
// 0x8F, (0xA1-0xFE)x2 - 0212 plane (94x94).
|
||||
// * JIS X 208: 7-bit, direct encoding of 0208. Byte ranges: 0x21-0x7E (94 values). Uncommon.
|
||||
// Used as-is in ISO2022 family.
|
||||
// * ISO2022-JP: Stateful encoding, with escape sequences to switch between ASCII,
|
||||
// 0201-1976 Roman, 0208-1978, 0208-1983.
|
||||
// * ISO2022-JP-1: Adds esc seq for 0212-1990.
|
||||
// * ISO2022-JP-2: Adds esc seq for GB2313-1980, KSX1001-1992, ISO8859-1, ISO8859-7.
|
||||
// * ISO2022-JP-3: Adds esc seq for 0201-1976 Kana set, 0213-2000 Planes 1, 2.
|
||||
// * ISO2022-JP-2004: Adds 0213-2004 Plane 1.
|
||||
//
|
||||
// After JIS X 0213 appeared, Shift_JIS-2004, EUC-JISX0213 and ISO2022-JP-2004 followed, with just changing the planes.
|
||||
//
|
||||
// Overall, it seems that it's a mess :( http://www8.plala.or.jp/tkubota1/unicode-symbols-map2.html
|
||||
|
||||
|
||||
'shiftjis': {
|
||||
type: '_dbcs',
|
||||
table: function() { return require('./tables/shiftjis.json') },
|
||||
encodeAdd: {'\u00a5': 0x5C, '\u203E': 0x7E},
|
||||
encodeSkipVals: [{from: 0xED40, to: 0xF940}],
|
||||
},
|
||||
'csshiftjis': 'shiftjis',
|
||||
'mskanji': 'shiftjis',
|
||||
'sjis': 'shiftjis',
|
||||
'windows31j': 'shiftjis',
|
||||
'xsjis': 'shiftjis',
|
||||
'windows932': 'shiftjis',
|
||||
'932': 'shiftjis',
|
||||
'cp932': 'shiftjis',
|
||||
|
||||
'eucjp': {
|
||||
type: '_dbcs',
|
||||
table: function() { return require('./tables/eucjp.json') },
|
||||
encodeAdd: {'\u00a5': 0x5C, '\u203E': 0x7E},
|
||||
},
|
||||
|
||||
// TODO: KDDI extension to Shift_JIS
|
||||
// TODO: IBM CCSID 942 = CP932, but F0-F9 custom chars and other char changes.
|
||||
// TODO: IBM CCSID 943 = Shift_JIS = CP932 with original Shift_JIS lower 128 chars.
|
||||
|
||||
// == Chinese/GBK ==========================================================
|
||||
// http://en.wikipedia.org/wiki/GBK
|
||||
|
||||
// Oldest GB2312 (1981, ~7600 chars) is a subset of CP936
|
||||
'gb2312': 'cp936',
|
||||
'gb231280': 'cp936',
|
||||
'gb23121980': 'cp936',
|
||||
'csgb2312': 'cp936',
|
||||
'csiso58gb231280': 'cp936',
|
||||
'euccn': 'cp936',
|
||||
'isoir58': 'gbk',
|
||||
|
||||
// Microsoft's CP936 is a subset and approximation of GBK.
|
||||
// TODO: Euro = 0x80 in cp936, but not in GBK (where it's valid but undefined)
|
||||
'windows936': 'cp936',
|
||||
'936': 'cp936',
|
||||
'cp936': {
|
||||
type: '_dbcs',
|
||||
table: function() { return require('./tables/cp936.json') },
|
||||
},
|
||||
|
||||
// GBK (~22000 chars) is an extension of CP936 that added user-mapped chars and some other.
|
||||
'gbk': {
|
||||
type: '_dbcs',
|
||||
table: function() { return require('./tables/cp936.json').concat(require('./tables/gbk-added.json')) },
|
||||
},
|
||||
'xgbk': 'gbk',
|
||||
|
||||
// GB18030 is an algorithmic extension of GBK.
|
||||
'gb18030': {
|
||||
type: '_dbcs',
|
||||
table: function() { return require('./tables/cp936.json').concat(require('./tables/gbk-added.json')) },
|
||||
gb18030: function() { return require('./tables/gb18030-ranges.json') },
|
||||
},
|
||||
|
||||
'chinese': 'gb18030',
|
||||
|
||||
// TODO: Support GB18030 (~27000 chars + whole unicode mapping, cp54936)
|
||||
// http://icu-project.org/docs/papers/gb18030.html
|
||||
// http://source.icu-project.org/repos/icu/data/trunk/charset/data/xml/gb-18030-2000.xml
|
||||
// http://www.khngai.com/chinese/charmap/tblgbk.php?page=0
|
||||
|
||||
// == Korean ===============================================================
|
||||
// EUC-KR, KS_C_5601 and KS X 1001 are exactly the same.
|
||||
'windows949': 'cp949',
|
||||
'949': 'cp949',
|
||||
'cp949': {
|
||||
type: '_dbcs',
|
||||
table: function() { return require('./tables/cp949.json') },
|
||||
},
|
||||
|
||||
'cseuckr': 'cp949',
|
||||
'csksc56011987': 'cp949',
|
||||
'euckr': 'cp949',
|
||||
'isoir149': 'cp949',
|
||||
'korean': 'cp949',
|
||||
'ksc56011987': 'cp949',
|
||||
'ksc56011989': 'cp949',
|
||||
'ksc5601': 'cp949',
|
||||
|
||||
|
||||
// == Big5/Taiwan/Hong Kong ================================================
|
||||
// There are lots of tables for Big5 and cp950. Please see the following links for history:
|
||||
// http://moztw.org/docs/big5/ http://www.haible.de/bruno/charsets/conversion-tables/Big5.html
|
||||
// Variations, in roughly number of defined chars:
|
||||
// * Windows CP 950: Microsoft variant of Big5. Canonical: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT
|
||||
// * Windows CP 951: Microsoft variant of Big5-HKSCS-2001. Seems to be never public. http://me.abelcheung.org/articles/research/what-is-cp951/
|
||||
// * Big5-2003 (Taiwan standard) almost superset of cp950.
|
||||
// * Unicode-at-on (UAO) / Mozilla 1.8. Falling out of use on the Web. Not supported by other browsers.
|
||||
// * Big5-HKSCS (-2001, -2004, -2008). Hong Kong standard.
|
||||
// many unicode code points moved from PUA to Supplementary plane (U+2XXXX) over the years.
|
||||
// Plus, it has 4 combining sequences.
|
||||
// Seems that Mozilla refused to support it for 10 yrs. https://bugzilla.mozilla.org/show_bug.cgi?id=162431 https://bugzilla.mozilla.org/show_bug.cgi?id=310299
|
||||
// because big5-hkscs is the only encoding to include astral characters in non-algorithmic way.
|
||||
// Implementations are not consistent within browsers; sometimes labeled as just big5.
|
||||
// MS Internet Explorer switches from big5 to big5-hkscs when a patch applied.
|
||||
// Great discussion & recap of what's going on https://bugzilla.mozilla.org/show_bug.cgi?id=912470#c31
|
||||
// In the encoder, it might make sense to support encoding old PUA mappings to Big5 bytes seq-s.
|
||||
// Official spec: http://www.ogcio.gov.hk/en/business/tech_promotion/ccli/terms/doc/2003cmp_2008.txt
|
||||
// http://www.ogcio.gov.hk/tc/business/tech_promotion/ccli/terms/doc/hkscs-2008-big5-iso.txt
|
||||
//
|
||||
// Current understanding of how to deal with Big5(-HKSCS) is in the Encoding Standard, http://encoding.spec.whatwg.org/#big5-encoder
|
||||
// Unicode mapping (http://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/OTHER/BIG5.TXT) is said to be wrong.
|
||||
|
||||
'windows950': 'cp950',
|
||||
'950': 'cp950',
|
||||
'cp950': {
|
||||
type: '_dbcs',
|
||||
table: function() { return require('./tables/cp950.json') },
|
||||
},
|
||||
|
||||
// Big5 has many variations and is an extension of cp950. We use Encoding Standard's as a consensus.
|
||||
'big5': 'big5hkscs',
|
||||
'big5hkscs': {
|
||||
type: '_dbcs',
|
||||
table: function() { return require('./tables/cp950.json').concat(require('./tables/big5-added.json')) },
|
||||
encodeSkipVals: [0xa2cc],
|
||||
},
|
||||
|
||||
'cnbig5': 'big5hkscs',
|
||||
'csbig5': 'big5hkscs',
|
||||
'xxbig5': 'big5hkscs',
|
||||
|
||||
};
|
||||
@ -0,0 +1,22 @@
|
||||
"use strict"
|
||||
|
||||
// Update this array if you add/rename/remove files in this directory.
|
||||
// We support Browserify by skipping automatic module discovery and requiring modules directly.
|
||||
var modules = [
|
||||
require("./internal"),
|
||||
require("./utf16"),
|
||||
require("./utf7"),
|
||||
require("./sbcs-codec"),
|
||||
require("./sbcs-data"),
|
||||
require("./sbcs-data-generated"),
|
||||
require("./dbcs-codec"),
|
||||
require("./dbcs-data"),
|
||||
];
|
||||
|
||||
// Put all encoding/alias/codec definitions to single object and export it.
|
||||
for (var i = 0; i < modules.length; i++) {
|
||||
var module = modules[i];
|
||||
for (var enc in module)
|
||||
if (Object.prototype.hasOwnProperty.call(module, enc))
|
||||
exports[enc] = module[enc];
|
||||
}
|
||||
@ -0,0 +1,187 @@
|
||||
"use strict"
|
||||
|
||||
// Export Node.js internal encodings.
|
||||
|
||||
module.exports = {
|
||||
// Encodings
|
||||
utf8: { type: "_internal", bomAware: true},
|
||||
cesu8: { type: "_internal", bomAware: true},
|
||||
unicode11utf8: "utf8",
|
||||
|
||||
ucs2: { type: "_internal", bomAware: true},
|
||||
utf16le: "ucs2",
|
||||
|
||||
binary: { type: "_internal" },
|
||||
base64: { type: "_internal" },
|
||||
hex: { type: "_internal" },
|
||||
|
||||
// Codec.
|
||||
_internal: InternalCodec,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
function InternalCodec(codecOptions, iconv) {
|
||||
this.enc = codecOptions.encodingName;
|
||||
this.bomAware = codecOptions.bomAware;
|
||||
|
||||
if (this.enc === "base64")
|
||||
this.encoder = InternalEncoderBase64;
|
||||
else if (this.enc === "cesu8") {
|
||||
this.enc = "utf8"; // Use utf8 for decoding.
|
||||
this.encoder = InternalEncoderCesu8;
|
||||
|
||||
// Add decoder for versions of Node not supporting CESU-8
|
||||
if (new Buffer("eda080", 'hex').toString().length == 3) {
|
||||
this.decoder = InternalDecoderCesu8;
|
||||
this.defaultCharUnicode = iconv.defaultCharUnicode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InternalCodec.prototype.encoder = InternalEncoder;
|
||||
InternalCodec.prototype.decoder = InternalDecoder;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// We use node.js internal decoder. Its signature is the same as ours.
|
||||
var StringDecoder = require('string_decoder').StringDecoder;
|
||||
|
||||
if (!StringDecoder.prototype.end) // Node v0.8 doesn't have this method.
|
||||
StringDecoder.prototype.end = function() {};
|
||||
|
||||
|
||||
function InternalDecoder(options, codec) {
|
||||
StringDecoder.call(this, codec.enc);
|
||||
}
|
||||
|
||||
InternalDecoder.prototype = StringDecoder.prototype;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Encoder is mostly trivial
|
||||
|
||||
function InternalEncoder(options, codec) {
|
||||
this.enc = codec.enc;
|
||||
}
|
||||
|
||||
InternalEncoder.prototype.write = function(str) {
|
||||
return new Buffer(str, this.enc);
|
||||
}
|
||||
|
||||
InternalEncoder.prototype.end = function() {
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Except base64 encoder, which must keep its state.
|
||||
|
||||
function InternalEncoderBase64(options, codec) {
|
||||
this.prevStr = '';
|
||||
}
|
||||
|
||||
InternalEncoderBase64.prototype.write = function(str) {
|
||||
str = this.prevStr + str;
|
||||
var completeQuads = str.length - (str.length % 4);
|
||||
this.prevStr = str.slice(completeQuads);
|
||||
str = str.slice(0, completeQuads);
|
||||
|
||||
return new Buffer(str, "base64");
|
||||
}
|
||||
|
||||
InternalEncoderBase64.prototype.end = function() {
|
||||
return new Buffer(this.prevStr, "base64");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CESU-8 encoder is also special.
|
||||
|
||||
function InternalEncoderCesu8(options, codec) {
|
||||
}
|
||||
|
||||
InternalEncoderCesu8.prototype.write = function(str) {
|
||||
var buf = new Buffer(str.length * 3), bufIdx = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var charCode = str.charCodeAt(i);
|
||||
// Naive implementation, but it works because CESU-8 is especially easy
|
||||
// to convert from UTF-16 (which all JS strings are encoded in).
|
||||
if (charCode < 0x80)
|
||||
buf[bufIdx++] = charCode;
|
||||
else if (charCode < 0x800) {
|
||||
buf[bufIdx++] = 0xC0 + (charCode >>> 6);
|
||||
buf[bufIdx++] = 0x80 + (charCode & 0x3f);
|
||||
}
|
||||
else { // charCode will always be < 0x10000 in javascript.
|
||||
buf[bufIdx++] = 0xE0 + (charCode >>> 12);
|
||||
buf[bufIdx++] = 0x80 + ((charCode >>> 6) & 0x3f);
|
||||
buf[bufIdx++] = 0x80 + (charCode & 0x3f);
|
||||
}
|
||||
}
|
||||
return buf.slice(0, bufIdx);
|
||||
}
|
||||
|
||||
InternalEncoderCesu8.prototype.end = function() {
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CESU-8 decoder is not implemented in Node v4.0+
|
||||
|
||||
function InternalDecoderCesu8(options, codec) {
|
||||
this.acc = 0;
|
||||
this.contBytes = 0;
|
||||
this.accBytes = 0;
|
||||
this.defaultCharUnicode = codec.defaultCharUnicode;
|
||||
}
|
||||
|
||||
InternalDecoderCesu8.prototype.write = function(buf) {
|
||||
var acc = this.acc, contBytes = this.contBytes, accBytes = this.accBytes,
|
||||
res = '';
|
||||
for (var i = 0; i < buf.length; i++) {
|
||||
var curByte = buf[i];
|
||||
if ((curByte & 0xC0) !== 0x80) { // Leading byte
|
||||
if (contBytes > 0) { // Previous code is invalid
|
||||
res += this.defaultCharUnicode;
|
||||
contBytes = 0;
|
||||
}
|
||||
|
||||
if (curByte < 0x80) { // Single-byte code
|
||||
res += String.fromCharCode(curByte);
|
||||
} else if (curByte < 0xE0) { // Two-byte code
|
||||
acc = curByte & 0x1F;
|
||||
contBytes = 1; accBytes = 1;
|
||||
} else if (curByte < 0xF0) { // Three-byte code
|
||||
acc = curByte & 0x0F;
|
||||
contBytes = 2; accBytes = 1;
|
||||
} else { // Four or more are not supported for CESU-8.
|
||||
res += this.defaultCharUnicode;
|
||||
}
|
||||
} else { // Continuation byte
|
||||
if (contBytes > 0) { // We're waiting for it.
|
||||
acc = (acc << 6) | (curByte & 0x3f);
|
||||
contBytes--; accBytes++;
|
||||
if (contBytes === 0) {
|
||||
// Check for overlong encoding, but support Modified UTF-8 (encoding NULL as C0 80)
|
||||
if (accBytes === 2 && acc < 0x80 && acc > 0)
|
||||
res += this.defaultCharUnicode;
|
||||
else if (accBytes === 3 && acc < 0x800)
|
||||
res += this.defaultCharUnicode;
|
||||
else
|
||||
// Actually add character.
|
||||
res += String.fromCharCode(acc);
|
||||
}
|
||||
} else { // Unexpected continuation byte
|
||||
res += this.defaultCharUnicode;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.acc = acc; this.contBytes = contBytes; this.accBytes = accBytes;
|
||||
return res;
|
||||
}
|
||||
|
||||
InternalDecoderCesu8.prototype.end = function() {
|
||||
var res = 0;
|
||||
if (this.contBytes > 0)
|
||||
res += this.defaultCharUnicode;
|
||||
return res;
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
"use strict"
|
||||
|
||||
// Single-byte codec. Needs a 'chars' string parameter that contains 256 or 128 chars that
|
||||
// correspond to encoded bytes (if 128 - then lower half is ASCII).
|
||||
|
||||
exports._sbcs = SBCSCodec;
|
||||
function SBCSCodec(codecOptions, iconv) {
|
||||
if (!codecOptions)
|
||||
throw new Error("SBCS codec is called without the data.")
|
||||
|
||||
// Prepare char buffer for decoding.
|
||||
if (!codecOptions.chars || (codecOptions.chars.length !== 128 && codecOptions.chars.length !== 256))
|
||||
throw new Error("Encoding '"+codecOptions.type+"' has incorrect 'chars' (must be of len 128 or 256)");
|
||||
|
||||
if (codecOptions.chars.length === 128) {
|
||||
var asciiString = "";
|
||||
for (var i = 0; i < 128; i++)
|
||||
asciiString += String.fromCharCode(i);
|
||||
codecOptions.chars = asciiString + codecOptions.chars;
|
||||
}
|
||||
|
||||
this.decodeBuf = new Buffer(codecOptions.chars, 'ucs2');
|
||||
|
||||
// Encoding buffer.
|
||||
var encodeBuf = new Buffer(65536);
|
||||
encodeBuf.fill(iconv.defaultCharSingleByte.charCodeAt(0));
|
||||
|
||||
for (var i = 0; i < codecOptions.chars.length; i++)
|
||||
encodeBuf[codecOptions.chars.charCodeAt(i)] = i;
|
||||
|
||||
this.encodeBuf = encodeBuf;
|
||||
}
|
||||
|
||||
SBCSCodec.prototype.encoder = SBCSEncoder;
|
||||
SBCSCodec.prototype.decoder = SBCSDecoder;
|
||||
|
||||
|
||||
function SBCSEncoder(options, codec) {
|
||||
this.encodeBuf = codec.encodeBuf;
|
||||
}
|
||||
|
||||
SBCSEncoder.prototype.write = function(str) {
|
||||
var buf = new Buffer(str.length);
|
||||
for (var i = 0; i < str.length; i++)
|
||||
buf[i] = this.encodeBuf[str.charCodeAt(i)];
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
SBCSEncoder.prototype.end = function() {
|
||||
}
|
||||
|
||||
|
||||
function SBCSDecoder(options, codec) {
|
||||
this.decodeBuf = codec.decodeBuf;
|
||||
}
|
||||
|
||||
SBCSDecoder.prototype.write = function(buf) {
|
||||
// Strings are immutable in JS -> we use ucs2 buffer to speed up computations.
|
||||
var decodeBuf = this.decodeBuf;
|
||||
var newBuf = new Buffer(buf.length*2);
|
||||
var idx1 = 0, idx2 = 0;
|
||||
for (var i = 0; i < buf.length; i++) {
|
||||
idx1 = buf[i]*2; idx2 = i*2;
|
||||
newBuf[idx2] = decodeBuf[idx1];
|
||||
newBuf[idx2+1] = decodeBuf[idx1+1];
|
||||
}
|
||||
return newBuf.toString('ucs2');
|
||||
}
|
||||
|
||||
SBCSDecoder.prototype.end = function() {
|
||||
}
|
||||
@ -0,0 +1,169 @@
|
||||
"use strict"
|
||||
|
||||
// Manually added data to be used by sbcs codec in addition to generated one.
|
||||
|
||||
module.exports = {
|
||||
// Not supported by iconv, not sure why.
|
||||
"10029": "maccenteuro",
|
||||
"maccenteuro": {
|
||||
"type": "_sbcs",
|
||||
"chars": "ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ"
|
||||
},
|
||||
|
||||
"808": "cp808",
|
||||
"ibm808": "cp808",
|
||||
"cp808": {
|
||||
"type": "_sbcs",
|
||||
"chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№€■ "
|
||||
},
|
||||
|
||||
// Aliases of generated encodings.
|
||||
"ascii8bit": "ascii",
|
||||
"usascii": "ascii",
|
||||
"ansix34": "ascii",
|
||||
"ansix341968": "ascii",
|
||||
"ansix341986": "ascii",
|
||||
"csascii": "ascii",
|
||||
"cp367": "ascii",
|
||||
"ibm367": "ascii",
|
||||
"isoir6": "ascii",
|
||||
"iso646us": "ascii",
|
||||
"iso646irv": "ascii",
|
||||
"us": "ascii",
|
||||
|
||||
"latin1": "iso88591",
|
||||
"latin2": "iso88592",
|
||||
"latin3": "iso88593",
|
||||
"latin4": "iso88594",
|
||||
"latin5": "iso88599",
|
||||
"latin6": "iso885910",
|
||||
"latin7": "iso885913",
|
||||
"latin8": "iso885914",
|
||||
"latin9": "iso885915",
|
||||
"latin10": "iso885916",
|
||||
|
||||
"csisolatin1": "iso88591",
|
||||
"csisolatin2": "iso88592",
|
||||
"csisolatin3": "iso88593",
|
||||
"csisolatin4": "iso88594",
|
||||
"csisolatincyrillic": "iso88595",
|
||||
"csisolatinarabic": "iso88596",
|
||||
"csisolatingreek" : "iso88597",
|
||||
"csisolatinhebrew": "iso88598",
|
||||
"csisolatin5": "iso88599",
|
||||
"csisolatin6": "iso885910",
|
||||
|
||||
"l1": "iso88591",
|
||||
"l2": "iso88592",
|
||||
"l3": "iso88593",
|
||||
"l4": "iso88594",
|
||||
"l5": "iso88599",
|
||||
"l6": "iso885910",
|
||||
"l7": "iso885913",
|
||||
"l8": "iso885914",
|
||||
"l9": "iso885915",
|
||||
"l10": "iso885916",
|
||||
|
||||
"isoir14": "iso646jp",
|
||||
"isoir57": "iso646cn",
|
||||
"isoir100": "iso88591",
|
||||
"isoir101": "iso88592",
|
||||
"isoir109": "iso88593",
|
||||
"isoir110": "iso88594",
|
||||
"isoir144": "iso88595",
|
||||
"isoir127": "iso88596",
|
||||
"isoir126": "iso88597",
|
||||
"isoir138": "iso88598",
|
||||
"isoir148": "iso88599",
|
||||
"isoir157": "iso885910",
|
||||
"isoir166": "tis620",
|
||||
"isoir179": "iso885913",
|
||||
"isoir199": "iso885914",
|
||||
"isoir203": "iso885915",
|
||||
"isoir226": "iso885916",
|
||||
|
||||
"cp819": "iso88591",
|
||||
"ibm819": "iso88591",
|
||||
|
||||
"cyrillic": "iso88595",
|
||||
|
||||
"arabic": "iso88596",
|
||||
"arabic8": "iso88596",
|
||||
"ecma114": "iso88596",
|
||||
"asmo708": "iso88596",
|
||||
|
||||
"greek" : "iso88597",
|
||||
"greek8" : "iso88597",
|
||||
"ecma118" : "iso88597",
|
||||
"elot928" : "iso88597",
|
||||
|
||||
"hebrew": "iso88598",
|
||||
"hebrew8": "iso88598",
|
||||
|
||||
"turkish": "iso88599",
|
||||
"turkish8": "iso88599",
|
||||
|
||||
"thai": "iso885911",
|
||||
"thai8": "iso885911",
|
||||
|
||||
"celtic": "iso885914",
|
||||
"celtic8": "iso885914",
|
||||
"isoceltic": "iso885914",
|
||||
|
||||
"tis6200": "tis620",
|
||||
"tis62025291": "tis620",
|
||||
"tis62025330": "tis620",
|
||||
|
||||
"10000": "macroman",
|
||||
"10006": "macgreek",
|
||||
"10007": "maccyrillic",
|
||||
"10079": "maciceland",
|
||||
"10081": "macturkish",
|
||||
|
||||
"cspc8codepage437": "cp437",
|
||||
"cspc775baltic": "cp775",
|
||||
"cspc850multilingual": "cp850",
|
||||
"cspcp852": "cp852",
|
||||
"cspc862latinhebrew": "cp862",
|
||||
"cpgr": "cp869",
|
||||
|
||||
"msee": "cp1250",
|
||||
"mscyrl": "cp1251",
|
||||
"msansi": "cp1252",
|
||||
"msgreek": "cp1253",
|
||||
"msturk": "cp1254",
|
||||
"mshebr": "cp1255",
|
||||
"msarab": "cp1256",
|
||||
"winbaltrim": "cp1257",
|
||||
|
||||
"cp20866": "koi8r",
|
||||
"20866": "koi8r",
|
||||
"ibm878": "koi8r",
|
||||
"cskoi8r": "koi8r",
|
||||
|
||||
"cp21866": "koi8u",
|
||||
"21866": "koi8u",
|
||||
"ibm1168": "koi8u",
|
||||
|
||||
"strk10482002": "rk1048",
|
||||
|
||||
"tcvn5712": "tcvn",
|
||||
"tcvn57121": "tcvn",
|
||||
|
||||
"gb198880": "iso646cn",
|
||||
"cn": "iso646cn",
|
||||
|
||||
"csiso14jisc6220ro": "iso646jp",
|
||||
"jisc62201969ro": "iso646jp",
|
||||
"jp": "iso646jp",
|
||||
|
||||
"cshproman8": "hproman8",
|
||||
"r8": "hproman8",
|
||||
"roman8": "hproman8",
|
||||
"xroman8": "hproman8",
|
||||
"ibm1051": "hproman8",
|
||||
|
||||
"mac": "macintosh",
|
||||
"csmacintosh": "macintosh",
|
||||
};
|
||||
|
||||
@ -0,0 +1 @@
|
||||
{"uChars":[128,165,169,178,184,216,226,235,238,244,248,251,253,258,276,284,300,325,329,334,364,463,465,467,469,471,473,475,477,506,594,610,712,716,730,930,938,962,970,1026,1104,1106,8209,8215,8218,8222,8231,8241,8244,8246,8252,8365,8452,8454,8458,8471,8482,8556,8570,8596,8602,8713,8720,8722,8726,8731,8737,8740,8742,8748,8751,8760,8766,8777,8781,8787,8802,8808,8816,8854,8858,8870,8896,8979,9322,9372,9548,9588,9616,9622,9634,9652,9662,9672,9676,9680,9702,9735,9738,9793,9795,11906,11909,11913,11917,11928,11944,11947,11951,11956,11960,11964,11979,12284,12292,12312,12319,12330,12351,12436,12447,12535,12543,12586,12842,12850,12964,13200,13215,13218,13253,13263,13267,13270,13384,13428,13727,13839,13851,14617,14703,14801,14816,14964,15183,15471,15585,16471,16736,17208,17325,17330,17374,17623,17997,18018,18212,18218,18301,18318,18760,18811,18814,18820,18823,18844,18848,18872,19576,19620,19738,19887,40870,59244,59336,59367,59413,59417,59423,59431,59437,59443,59452,59460,59478,59493,63789,63866,63894,63976,63986,64016,64018,64021,64025,64034,64037,64042,65074,65093,65107,65112,65127,65132,65375,65510,65536],"gbChars":[0,36,38,45,50,81,89,95,96,100,103,104,105,109,126,133,148,172,175,179,208,306,307,308,309,310,311,312,313,341,428,443,544,545,558,741,742,749,750,805,819,820,7922,7924,7925,7927,7934,7943,7944,7945,7950,8062,8148,8149,8152,8164,8174,8236,8240,8262,8264,8374,8380,8381,8384,8388,8390,8392,8393,8394,8396,8401,8406,8416,8419,8424,8437,8439,8445,8482,8485,8496,8521,8603,8936,8946,9046,9050,9063,9066,9076,9092,9100,9108,9111,9113,9131,9162,9164,9218,9219,11329,11331,11334,11336,11346,11361,11363,11366,11370,11372,11375,11389,11682,11686,11687,11692,11694,11714,11716,11723,11725,11730,11736,11982,11989,12102,12336,12348,12350,12384,12393,12395,12397,12510,12553,12851,12962,12973,13738,13823,13919,13933,14080,14298,14585,14698,15583,15847,16318,16434,16438,16481,16729,17102,17122,17315,17320,17402,17418,17859,17909,17911,17915,17916,17936,17939,17961,18664,18703,18814,18962,19043,33469,33470,33471,33484,33485,33490,33497,33501,33505,33513,33520,33536,33550,37845,37921,37948,38029,38038,38064,38065,38066,38069,38075,38076,38078,39108,39109,39113,39114,39115,39116,39265,39394,189000]}
|
||||
@ -0,0 +1,174 @@
|
||||
"use strict"
|
||||
|
||||
// == UTF16-BE codec. ==========================================================
|
||||
|
||||
exports.utf16be = Utf16BECodec;
|
||||
function Utf16BECodec() {
|
||||
}
|
||||
|
||||
Utf16BECodec.prototype.encoder = Utf16BEEncoder;
|
||||
Utf16BECodec.prototype.decoder = Utf16BEDecoder;
|
||||
Utf16BECodec.prototype.bomAware = true;
|
||||
|
||||
|
||||
// -- Encoding
|
||||
|
||||
function Utf16BEEncoder() {
|
||||
}
|
||||
|
||||
Utf16BEEncoder.prototype.write = function(str) {
|
||||
var buf = new Buffer(str, 'ucs2');
|
||||
for (var i = 0; i < buf.length; i += 2) {
|
||||
var tmp = buf[i]; buf[i] = buf[i+1]; buf[i+1] = tmp;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
Utf16BEEncoder.prototype.end = function() {
|
||||
}
|
||||
|
||||
|
||||
// -- Decoding
|
||||
|
||||
function Utf16BEDecoder() {
|
||||
this.overflowByte = -1;
|
||||
}
|
||||
|
||||
Utf16BEDecoder.prototype.write = function(buf) {
|
||||
if (buf.length == 0)
|
||||
return '';
|
||||
|
||||
var buf2 = new Buffer(buf.length + 1),
|
||||
i = 0, j = 0;
|
||||
|
||||
if (this.overflowByte !== -1) {
|
||||
buf2[0] = buf[0];
|
||||
buf2[1] = this.overflowByte;
|
||||
i = 1; j = 2;
|
||||
}
|
||||
|
||||
for (; i < buf.length-1; i += 2, j+= 2) {
|
||||
buf2[j] = buf[i+1];
|
||||
buf2[j+1] = buf[i];
|
||||
}
|
||||
|
||||
this.overflowByte = (i == buf.length-1) ? buf[buf.length-1] : -1;
|
||||
|
||||
return buf2.slice(0, j).toString('ucs2');
|
||||
}
|
||||
|
||||
Utf16BEDecoder.prototype.end = function() {
|
||||
}
|
||||
|
||||
|
||||
// == UTF-16 codec =============================================================
|
||||
// Decoder chooses automatically from UTF-16LE and UTF-16BE using BOM and space-based heuristic.
|
||||
// Defaults to UTF-16LE, as it's prevalent and default in Node.
|
||||
// http://en.wikipedia.org/wiki/UTF-16 and http://encoding.spec.whatwg.org/#utf-16le
|
||||
// Decoder default can be changed: iconv.decode(buf, 'utf16', {defaultEncoding: 'utf-16be'});
|
||||
|
||||
// Encoder uses UTF-16LE and prepends BOM (which can be overridden with addBOM: false).
|
||||
|
||||
exports.utf16 = Utf16Codec;
|
||||
function Utf16Codec(codecOptions, iconv) {
|
||||
this.iconv = iconv;
|
||||
}
|
||||
|
||||
Utf16Codec.prototype.encoder = Utf16Encoder;
|
||||
Utf16Codec.prototype.decoder = Utf16Decoder;
|
||||
|
||||
|
||||
// -- Encoding (pass-through)
|
||||
|
||||
function Utf16Encoder(options, codec) {
|
||||
options = options || {};
|
||||
if (options.addBOM === undefined)
|
||||
options.addBOM = true;
|
||||
this.encoder = codec.iconv.getEncoder('utf-16le', options);
|
||||
}
|
||||
|
||||
Utf16Encoder.prototype.write = function(str) {
|
||||
return this.encoder.write(str);
|
||||
}
|
||||
|
||||
Utf16Encoder.prototype.end = function() {
|
||||
return this.encoder.end();
|
||||
}
|
||||
|
||||
|
||||
// -- Decoding
|
||||
|
||||
function Utf16Decoder(options, codec) {
|
||||
this.decoder = null;
|
||||
this.initialBytes = [];
|
||||
this.initialBytesLen = 0;
|
||||
|
||||
this.options = options || {};
|
||||
this.iconv = codec.iconv;
|
||||
}
|
||||
|
||||
Utf16Decoder.prototype.write = function(buf) {
|
||||
if (!this.decoder) {
|
||||
// Codec is not chosen yet. Accumulate initial bytes.
|
||||
this.initialBytes.push(buf);
|
||||
this.initialBytesLen += buf.length;
|
||||
|
||||
if (this.initialBytesLen < 16) // We need more bytes to use space heuristic (see below)
|
||||
return '';
|
||||
|
||||
// We have enough bytes -> detect endianness.
|
||||
var buf = Buffer.concat(this.initialBytes),
|
||||
encoding = detectEncoding(buf, this.options.defaultEncoding);
|
||||
this.decoder = this.iconv.getDecoder(encoding, this.options);
|
||||
this.initialBytes.length = this.initialBytesLen = 0;
|
||||
}
|
||||
|
||||
return this.decoder.write(buf);
|
||||
}
|
||||
|
||||
Utf16Decoder.prototype.end = function() {
|
||||
if (!this.decoder) {
|
||||
var buf = Buffer.concat(this.initialBytes),
|
||||
encoding = detectEncoding(buf, this.options.defaultEncoding);
|
||||
this.decoder = this.iconv.getDecoder(encoding, this.options);
|
||||
|
||||
var res = this.decoder.write(buf),
|
||||
trail = this.decoder.end();
|
||||
|
||||
return trail ? (res + trail) : res;
|
||||
}
|
||||
return this.decoder.end();
|
||||
}
|
||||
|
||||
function detectEncoding(buf, defaultEncoding) {
|
||||
var enc = defaultEncoding || 'utf-16le';
|
||||
|
||||
if (buf.length >= 2) {
|
||||
// Check BOM.
|
||||
if (buf[0] == 0xFE && buf[1] == 0xFF) // UTF-16BE BOM
|
||||
enc = 'utf-16be';
|
||||
else if (buf[0] == 0xFF && buf[1] == 0xFE) // UTF-16LE BOM
|
||||
enc = 'utf-16le';
|
||||
else {
|
||||
// No BOM found. Try to deduce encoding from initial content.
|
||||
// Most of the time, the content has ASCII chars (U+00**), but the opposite (U+**00) is uncommon.
|
||||
// So, we count ASCII as if it was LE or BE, and decide from that.
|
||||
var asciiCharsLE = 0, asciiCharsBE = 0, // Counts of chars in both positions
|
||||
_len = Math.min(buf.length - (buf.length % 2), 64); // Len is always even.
|
||||
|
||||
for (var i = 0; i < _len; i += 2) {
|
||||
if (buf[i] === 0 && buf[i+1] !== 0) asciiCharsBE++;
|
||||
if (buf[i] !== 0 && buf[i+1] === 0) asciiCharsLE++;
|
||||
}
|
||||
|
||||
if (asciiCharsBE > asciiCharsLE)
|
||||
enc = 'utf-16be';
|
||||
else if (asciiCharsBE < asciiCharsLE)
|
||||
enc = 'utf-16le';
|
||||
}
|
||||
}
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,289 @@
|
||||
"use strict"
|
||||
|
||||
// UTF-7 codec, according to https://tools.ietf.org/html/rfc2152
|
||||
// See also below a UTF-7-IMAP codec, according to http://tools.ietf.org/html/rfc3501#section-5.1.3
|
||||
|
||||
exports.utf7 = Utf7Codec;
|
||||
exports.unicode11utf7 = 'utf7'; // Alias UNICODE-1-1-UTF-7
|
||||
function Utf7Codec(codecOptions, iconv) {
|
||||
this.iconv = iconv;
|
||||
};
|
||||
|
||||
Utf7Codec.prototype.encoder = Utf7Encoder;
|
||||
Utf7Codec.prototype.decoder = Utf7Decoder;
|
||||
Utf7Codec.prototype.bomAware = true;
|
||||
|
||||
|
||||
// -- Encoding
|
||||
|
||||
var nonDirectChars = /[^A-Za-z0-9'\(\),-\.\/:\? \n\r\t]+/g;
|
||||
|
||||
function Utf7Encoder(options, codec) {
|
||||
this.iconv = codec.iconv;
|
||||
}
|
||||
|
||||
Utf7Encoder.prototype.write = function(str) {
|
||||
// Naive implementation.
|
||||
// Non-direct chars are encoded as "+<base64>-"; single "+" char is encoded as "+-".
|
||||
return new Buffer(str.replace(nonDirectChars, function(chunk) {
|
||||
return "+" + (chunk === '+' ? '' :
|
||||
this.iconv.encode(chunk, 'utf16-be').toString('base64').replace(/=+$/, ''))
|
||||
+ "-";
|
||||
}.bind(this)));
|
||||
}
|
||||
|
||||
Utf7Encoder.prototype.end = function() {
|
||||
}
|
||||
|
||||
|
||||
// -- Decoding
|
||||
|
||||
function Utf7Decoder(options, codec) {
|
||||
this.iconv = codec.iconv;
|
||||
this.inBase64 = false;
|
||||
this.base64Accum = '';
|
||||
}
|
||||
|
||||
var base64Regex = /[A-Za-z0-9\/+]/;
|
||||
var base64Chars = [];
|
||||
for (var i = 0; i < 256; i++)
|
||||
base64Chars[i] = base64Regex.test(String.fromCharCode(i));
|
||||
|
||||
var plusChar = '+'.charCodeAt(0),
|
||||
minusChar = '-'.charCodeAt(0),
|
||||
andChar = '&'.charCodeAt(0);
|
||||
|
||||
Utf7Decoder.prototype.write = function(buf) {
|
||||
var res = "", lastI = 0,
|
||||
inBase64 = this.inBase64,
|
||||
base64Accum = this.base64Accum;
|
||||
|
||||
// The decoder is more involved as we must handle chunks in stream.
|
||||
|
||||
for (var i = 0; i < buf.length; i++) {
|
||||
if (!inBase64) { // We're in direct mode.
|
||||
// Write direct chars until '+'
|
||||
if (buf[i] == plusChar) {
|
||||
res += this.iconv.decode(buf.slice(lastI, i), "ascii"); // Write direct chars.
|
||||
lastI = i+1;
|
||||
inBase64 = true;
|
||||
}
|
||||
} else { // We decode base64.
|
||||
if (!base64Chars[buf[i]]) { // Base64 ended.
|
||||
if (i == lastI && buf[i] == minusChar) {// "+-" -> "+"
|
||||
res += "+";
|
||||
} else {
|
||||
var b64str = base64Accum + buf.slice(lastI, i).toString();
|
||||
res += this.iconv.decode(new Buffer(b64str, 'base64'), "utf16-be");
|
||||
}
|
||||
|
||||
if (buf[i] != minusChar) // Minus is absorbed after base64.
|
||||
i--;
|
||||
|
||||
lastI = i+1;
|
||||
inBase64 = false;
|
||||
base64Accum = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!inBase64) {
|
||||
res += this.iconv.decode(buf.slice(lastI), "ascii"); // Write direct chars.
|
||||
} else {
|
||||
var b64str = base64Accum + buf.slice(lastI).toString();
|
||||
|
||||
var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars.
|
||||
base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future.
|
||||
b64str = b64str.slice(0, canBeDecoded);
|
||||
|
||||
res += this.iconv.decode(new Buffer(b64str, 'base64'), "utf16-be");
|
||||
}
|
||||
|
||||
this.inBase64 = inBase64;
|
||||
this.base64Accum = base64Accum;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Utf7Decoder.prototype.end = function() {
|
||||
var res = "";
|
||||
if (this.inBase64 && this.base64Accum.length > 0)
|
||||
res = this.iconv.decode(new Buffer(this.base64Accum, 'base64'), "utf16-be");
|
||||
|
||||
this.inBase64 = false;
|
||||
this.base64Accum = '';
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// UTF-7-IMAP codec.
|
||||
// RFC3501 Sec. 5.1.3 Modified UTF-7 (http://tools.ietf.org/html/rfc3501#section-5.1.3)
|
||||
// Differences:
|
||||
// * Base64 part is started by "&" instead of "+"
|
||||
// * Direct characters are 0x20-0x7E, except "&" (0x26)
|
||||
// * In Base64, "," is used instead of "/"
|
||||
// * Base64 must not be used to represent direct characters.
|
||||
// * No implicit shift back from Base64 (should always end with '-')
|
||||
// * String must end in non-shifted position.
|
||||
// * "-&" while in base64 is not allowed.
|
||||
|
||||
|
||||
exports.utf7imap = Utf7IMAPCodec;
|
||||
function Utf7IMAPCodec(codecOptions, iconv) {
|
||||
this.iconv = iconv;
|
||||
};
|
||||
|
||||
Utf7IMAPCodec.prototype.encoder = Utf7IMAPEncoder;
|
||||
Utf7IMAPCodec.prototype.decoder = Utf7IMAPDecoder;
|
||||
Utf7IMAPCodec.prototype.bomAware = true;
|
||||
|
||||
|
||||
// -- Encoding
|
||||
|
||||
function Utf7IMAPEncoder(options, codec) {
|
||||
this.iconv = codec.iconv;
|
||||
this.inBase64 = false;
|
||||
this.base64Accum = new Buffer(6);
|
||||
this.base64AccumIdx = 0;
|
||||
}
|
||||
|
||||
Utf7IMAPEncoder.prototype.write = function(str) {
|
||||
var inBase64 = this.inBase64,
|
||||
base64Accum = this.base64Accum,
|
||||
base64AccumIdx = this.base64AccumIdx,
|
||||
buf = new Buffer(str.length*5 + 10), bufIdx = 0;
|
||||
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var uChar = str.charCodeAt(i);
|
||||
if (0x20 <= uChar && uChar <= 0x7E) { // Direct character or '&'.
|
||||
if (inBase64) {
|
||||
if (base64AccumIdx > 0) {
|
||||
bufIdx += buf.write(base64Accum.slice(0, base64AccumIdx).toString('base64').replace(/\//g, ',').replace(/=+$/, ''), bufIdx);
|
||||
base64AccumIdx = 0;
|
||||
}
|
||||
|
||||
buf[bufIdx++] = minusChar; // Write '-', then go to direct mode.
|
||||
inBase64 = false;
|
||||
}
|
||||
|
||||
if (!inBase64) {
|
||||
buf[bufIdx++] = uChar; // Write direct character
|
||||
|
||||
if (uChar === andChar) // Ampersand -> '&-'
|
||||
buf[bufIdx++] = minusChar;
|
||||
}
|
||||
|
||||
} else { // Non-direct character
|
||||
if (!inBase64) {
|
||||
buf[bufIdx++] = andChar; // Write '&', then go to base64 mode.
|
||||
inBase64 = true;
|
||||
}
|
||||
if (inBase64) {
|
||||
base64Accum[base64AccumIdx++] = uChar >> 8;
|
||||
base64Accum[base64AccumIdx++] = uChar & 0xFF;
|
||||
|
||||
if (base64AccumIdx == base64Accum.length) {
|
||||
bufIdx += buf.write(base64Accum.toString('base64').replace(/\//g, ','), bufIdx);
|
||||
base64AccumIdx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.inBase64 = inBase64;
|
||||
this.base64AccumIdx = base64AccumIdx;
|
||||
|
||||
return buf.slice(0, bufIdx);
|
||||
}
|
||||
|
||||
Utf7IMAPEncoder.prototype.end = function() {
|
||||
var buf = new Buffer(10), bufIdx = 0;
|
||||
if (this.inBase64) {
|
||||
if (this.base64AccumIdx > 0) {
|
||||
bufIdx += buf.write(this.base64Accum.slice(0, this.base64AccumIdx).toString('base64').replace(/\//g, ',').replace(/=+$/, ''), bufIdx);
|
||||
this.base64AccumIdx = 0;
|
||||
}
|
||||
|
||||
buf[bufIdx++] = minusChar; // Write '-', then go to direct mode.
|
||||
this.inBase64 = false;
|
||||
}
|
||||
|
||||
return buf.slice(0, bufIdx);
|
||||
}
|
||||
|
||||
|
||||
// -- Decoding
|
||||
|
||||
function Utf7IMAPDecoder(options, codec) {
|
||||
this.iconv = codec.iconv;
|
||||
this.inBase64 = false;
|
||||
this.base64Accum = '';
|
||||
}
|
||||
|
||||
var base64IMAPChars = base64Chars.slice();
|
||||
base64IMAPChars[','.charCodeAt(0)] = true;
|
||||
|
||||
Utf7IMAPDecoder.prototype.write = function(buf) {
|
||||
var res = "", lastI = 0,
|
||||
inBase64 = this.inBase64,
|
||||
base64Accum = this.base64Accum;
|
||||
|
||||
// The decoder is more involved as we must handle chunks in stream.
|
||||
// It is forgiving, closer to standard UTF-7 (for example, '-' is optional at the end).
|
||||
|
||||
for (var i = 0; i < buf.length; i++) {
|
||||
if (!inBase64) { // We're in direct mode.
|
||||
// Write direct chars until '&'
|
||||
if (buf[i] == andChar) {
|
||||
res += this.iconv.decode(buf.slice(lastI, i), "ascii"); // Write direct chars.
|
||||
lastI = i+1;
|
||||
inBase64 = true;
|
||||
}
|
||||
} else { // We decode base64.
|
||||
if (!base64IMAPChars[buf[i]]) { // Base64 ended.
|
||||
if (i == lastI && buf[i] == minusChar) { // "&-" -> "&"
|
||||
res += "&";
|
||||
} else {
|
||||
var b64str = base64Accum + buf.slice(lastI, i).toString().replace(/,/g, '/');
|
||||
res += this.iconv.decode(new Buffer(b64str, 'base64'), "utf16-be");
|
||||
}
|
||||
|
||||
if (buf[i] != minusChar) // Minus may be absorbed after base64.
|
||||
i--;
|
||||
|
||||
lastI = i+1;
|
||||
inBase64 = false;
|
||||
base64Accum = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!inBase64) {
|
||||
res += this.iconv.decode(buf.slice(lastI), "ascii"); // Write direct chars.
|
||||
} else {
|
||||
var b64str = base64Accum + buf.slice(lastI).toString().replace(/,/g, '/');
|
||||
|
||||
var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars.
|
||||
base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future.
|
||||
b64str = b64str.slice(0, canBeDecoded);
|
||||
|
||||
res += this.iconv.decode(new Buffer(b64str, 'base64'), "utf16-be");
|
||||
}
|
||||
|
||||
this.inBase64 = inBase64;
|
||||
this.base64Accum = base64Accum;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Utf7IMAPDecoder.prototype.end = function() {
|
||||
var res = "";
|
||||
if (this.inBase64 && this.base64Accum.length > 0)
|
||||
res = this.iconv.decode(new Buffer(this.base64Accum, 'base64'), "utf16-be");
|
||||
|
||||
this.inBase64 = false;
|
||||
this.base64Accum = '';
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
"use strict"
|
||||
|
||||
var BOMChar = '\uFEFF';
|
||||
|
||||
exports.PrependBOM = PrependBOMWrapper
|
||||
function PrependBOMWrapper(encoder, options) {
|
||||
this.encoder = encoder;
|
||||
this.addBOM = true;
|
||||
}
|
||||
|
||||
PrependBOMWrapper.prototype.write = function(str) {
|
||||
if (this.addBOM) {
|
||||
str = BOMChar + str;
|
||||
this.addBOM = false;
|
||||
}
|
||||
|
||||
return this.encoder.write(str);
|
||||
}
|
||||
|
||||
PrependBOMWrapper.prototype.end = function() {
|
||||
return this.encoder.end();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
exports.StripBOM = StripBOMWrapper;
|
||||
function StripBOMWrapper(decoder, options) {
|
||||
this.decoder = decoder;
|
||||
this.pass = false;
|
||||
this.options = options || {};
|
||||
}
|
||||
|
||||
StripBOMWrapper.prototype.write = function(buf) {
|
||||
var res = this.decoder.write(buf);
|
||||
if (this.pass || !res)
|
||||
return res;
|
||||
|
||||
if (res[0] === BOMChar) {
|
||||
res = res.slice(1);
|
||||
if (typeof this.options.stripBOM === 'function')
|
||||
this.options.stripBOM();
|
||||
}
|
||||
|
||||
this.pass = true;
|
||||
return res;
|
||||
}
|
||||
|
||||
StripBOMWrapper.prototype.end = function() {
|
||||
return this.decoder.end();
|
||||
}
|
||||
|
||||
@ -0,0 +1,214 @@
|
||||
"use strict"
|
||||
|
||||
// == Extend Node primitives to use iconv-lite =================================
|
||||
|
||||
module.exports = function (iconv) {
|
||||
var original = undefined; // Place to keep original methods.
|
||||
|
||||
// Node authors rewrote Buffer internals to make it compatible with
|
||||
// Uint8Array and we cannot patch key functions since then.
|
||||
iconv.supportsNodeEncodingsExtension = !(new Buffer(0) instanceof Uint8Array);
|
||||
|
||||
iconv.extendNodeEncodings = function extendNodeEncodings() {
|
||||
if (original) return;
|
||||
original = {};
|
||||
|
||||
if (!iconv.supportsNodeEncodingsExtension) {
|
||||
console.error("ACTION NEEDED: require('iconv-lite').extendNodeEncodings() is not supported in your version of Node");
|
||||
console.error("See more info at https://github.com/ashtuchkin/iconv-lite/wiki/Node-v4-compatibility");
|
||||
return;
|
||||
}
|
||||
|
||||
var nodeNativeEncodings = {
|
||||
'hex': true, 'utf8': true, 'utf-8': true, 'ascii': true, 'binary': true,
|
||||
'base64': true, 'ucs2': true, 'ucs-2': true, 'utf16le': true, 'utf-16le': true,
|
||||
};
|
||||
|
||||
Buffer.isNativeEncoding = function(enc) {
|
||||
return enc && nodeNativeEncodings[enc.toLowerCase()];
|
||||
}
|
||||
|
||||
// -- SlowBuffer -----------------------------------------------------------
|
||||
var SlowBuffer = require('buffer').SlowBuffer;
|
||||
|
||||
original.SlowBufferToString = SlowBuffer.prototype.toString;
|
||||
SlowBuffer.prototype.toString = function(encoding, start, end) {
|
||||
encoding = String(encoding || 'utf8').toLowerCase();
|
||||
|
||||
// Use native conversion when possible
|
||||
if (Buffer.isNativeEncoding(encoding))
|
||||
return original.SlowBufferToString.call(this, encoding, start, end);
|
||||
|
||||
// Otherwise, use our decoding method.
|
||||
if (typeof start == 'undefined') start = 0;
|
||||
if (typeof end == 'undefined') end = this.length;
|
||||
return iconv.decode(this.slice(start, end), encoding);
|
||||
}
|
||||
|
||||
original.SlowBufferWrite = SlowBuffer.prototype.write;
|
||||
SlowBuffer.prototype.write = function(string, offset, length, encoding) {
|
||||
// Support both (string, offset, length, encoding)
|
||||
// and the legacy (string, encoding, offset, length)
|
||||
if (isFinite(offset)) {
|
||||
if (!isFinite(length)) {
|
||||
encoding = length;
|
||||
length = undefined;
|
||||
}
|
||||
} else { // legacy
|
||||
var swap = encoding;
|
||||
encoding = offset;
|
||||
offset = length;
|
||||
length = swap;
|
||||
}
|
||||
|
||||
offset = +offset || 0;
|
||||
var remaining = this.length - offset;
|
||||
if (!length) {
|
||||
length = remaining;
|
||||
} else {
|
||||
length = +length;
|
||||
if (length > remaining) {
|
||||
length = remaining;
|
||||
}
|
||||
}
|
||||
encoding = String(encoding || 'utf8').toLowerCase();
|
||||
|
||||
// Use native conversion when possible
|
||||
if (Buffer.isNativeEncoding(encoding))
|
||||
return original.SlowBufferWrite.call(this, string, offset, length, encoding);
|
||||
|
||||
if (string.length > 0 && (length < 0 || offset < 0))
|
||||
throw new RangeError('attempt to write beyond buffer bounds');
|
||||
|
||||
// Otherwise, use our encoding method.
|
||||
var buf = iconv.encode(string, encoding);
|
||||
if (buf.length < length) length = buf.length;
|
||||
buf.copy(this, offset, 0, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
// -- Buffer ---------------------------------------------------------------
|
||||
|
||||
original.BufferIsEncoding = Buffer.isEncoding;
|
||||
Buffer.isEncoding = function(encoding) {
|
||||
return Buffer.isNativeEncoding(encoding) || iconv.encodingExists(encoding);
|
||||
}
|
||||
|
||||
original.BufferByteLength = Buffer.byteLength;
|
||||
Buffer.byteLength = SlowBuffer.byteLength = function(str, encoding) {
|
||||
encoding = String(encoding || 'utf8').toLowerCase();
|
||||
|
||||
// Use native conversion when possible
|
||||
if (Buffer.isNativeEncoding(encoding))
|
||||
return original.BufferByteLength.call(this, str, encoding);
|
||||
|
||||
// Slow, I know, but we don't have a better way yet.
|
||||
return iconv.encode(str, encoding).length;
|
||||
}
|
||||
|
||||
original.BufferToString = Buffer.prototype.toString;
|
||||
Buffer.prototype.toString = function(encoding, start, end) {
|
||||
encoding = String(encoding || 'utf8').toLowerCase();
|
||||
|
||||
// Use native conversion when possible
|
||||
if (Buffer.isNativeEncoding(encoding))
|
||||
return original.BufferToString.call(this, encoding, start, end);
|
||||
|
||||
// Otherwise, use our decoding method.
|
||||
if (typeof start == 'undefined') start = 0;
|
||||
if (typeof end == 'undefined') end = this.length;
|
||||
return iconv.decode(this.slice(start, end), encoding);
|
||||
}
|
||||
|
||||
original.BufferWrite = Buffer.prototype.write;
|
||||
Buffer.prototype.write = function(string, offset, length, encoding) {
|
||||
var _offset = offset, _length = length, _encoding = encoding;
|
||||
// Support both (string, offset, length, encoding)
|
||||
// and the legacy (string, encoding, offset, length)
|
||||
if (isFinite(offset)) {
|
||||
if (!isFinite(length)) {
|
||||
encoding = length;
|
||||
length = undefined;
|
||||
}
|
||||
} else { // legacy
|
||||
var swap = encoding;
|
||||
encoding = offset;
|
||||
offset = length;
|
||||
length = swap;
|
||||
}
|
||||
|
||||
encoding = String(encoding || 'utf8').toLowerCase();
|
||||
|
||||
// Use native conversion when possible
|
||||
if (Buffer.isNativeEncoding(encoding))
|
||||
return original.BufferWrite.call(this, string, _offset, _length, _encoding);
|
||||
|
||||
offset = +offset || 0;
|
||||
var remaining = this.length - offset;
|
||||
if (!length) {
|
||||
length = remaining;
|
||||
} else {
|
||||
length = +length;
|
||||
if (length > remaining) {
|
||||
length = remaining;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.length > 0 && (length < 0 || offset < 0))
|
||||
throw new RangeError('attempt to write beyond buffer bounds');
|
||||
|
||||
// Otherwise, use our encoding method.
|
||||
var buf = iconv.encode(string, encoding);
|
||||
if (buf.length < length) length = buf.length;
|
||||
buf.copy(this, offset, 0, length);
|
||||
return length;
|
||||
|
||||
// TODO: Set _charsWritten.
|
||||
}
|
||||
|
||||
|
||||
// -- Readable -------------------------------------------------------------
|
||||
if (iconv.supportsStreams) {
|
||||
var Readable = require('stream').Readable;
|
||||
|
||||
original.ReadableSetEncoding = Readable.prototype.setEncoding;
|
||||
Readable.prototype.setEncoding = function setEncoding(enc, options) {
|
||||
// Use our own decoder, it has the same interface.
|
||||
// We cannot use original function as it doesn't handle BOM-s.
|
||||
this._readableState.decoder = iconv.getDecoder(enc, options);
|
||||
this._readableState.encoding = enc;
|
||||
}
|
||||
|
||||
Readable.prototype.collect = iconv._collect;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove iconv-lite Node primitive extensions.
|
||||
iconv.undoExtendNodeEncodings = function undoExtendNodeEncodings() {
|
||||
if (!iconv.supportsNodeEncodingsExtension)
|
||||
return;
|
||||
if (!original)
|
||||
throw new Error("require('iconv-lite').undoExtendNodeEncodings(): Nothing to undo; extendNodeEncodings() is not called.")
|
||||
|
||||
delete Buffer.isNativeEncoding;
|
||||
|
||||
var SlowBuffer = require('buffer').SlowBuffer;
|
||||
|
||||
SlowBuffer.prototype.toString = original.SlowBufferToString;
|
||||
SlowBuffer.prototype.write = original.SlowBufferWrite;
|
||||
|
||||
Buffer.isEncoding = original.BufferIsEncoding;
|
||||
Buffer.byteLength = original.BufferByteLength;
|
||||
Buffer.prototype.toString = original.BufferToString;
|
||||
Buffer.prototype.write = original.BufferWrite;
|
||||
|
||||
if (iconv.supportsStreams) {
|
||||
var Readable = require('stream').Readable;
|
||||
|
||||
Readable.prototype.setEncoding = original.ReadableSetEncoding;
|
||||
delete Readable.prototype.collect;
|
||||
}
|
||||
|
||||
original = undefined;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
"use strict"
|
||||
|
||||
var Transform = require("stream").Transform;
|
||||
|
||||
|
||||
// == Exports ==================================================================
|
||||
module.exports = function(iconv) {
|
||||
|
||||
// Additional Public API.
|
||||
iconv.encodeStream = function encodeStream(encoding, options) {
|
||||
return new IconvLiteEncoderStream(iconv.getEncoder(encoding, options), options);
|
||||
}
|
||||
|
||||
iconv.decodeStream = function decodeStream(encoding, options) {
|
||||
return new IconvLiteDecoderStream(iconv.getDecoder(encoding, options), options);
|
||||
}
|
||||
|
||||
iconv.supportsStreams = true;
|
||||
|
||||
|
||||
// Not published yet.
|
||||
iconv.IconvLiteEncoderStream = IconvLiteEncoderStream;
|
||||
iconv.IconvLiteDecoderStream = IconvLiteDecoderStream;
|
||||
iconv._collect = IconvLiteDecoderStream.prototype.collect;
|
||||
};
|
||||
|
||||
|
||||
// == Encoder stream =======================================================
|
||||
function IconvLiteEncoderStream(conv, options) {
|
||||
this.conv = conv;
|
||||
options = options || {};
|
||||
options.decodeStrings = false; // We accept only strings, so we don't need to decode them.
|
||||
Transform.call(this, options);
|
||||
}
|
||||
|
||||
IconvLiteEncoderStream.prototype = Object.create(Transform.prototype, {
|
||||
constructor: { value: IconvLiteEncoderStream }
|
||||
});
|
||||
|
||||
IconvLiteEncoderStream.prototype._transform = function(chunk, encoding, done) {
|
||||
if (typeof chunk != 'string')
|
||||
return done(new Error("Iconv encoding stream needs strings as its input."));
|
||||
try {
|
||||
var res = this.conv.write(chunk);
|
||||
if (res && res.length) this.push(res);
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
}
|
||||
|
||||
IconvLiteEncoderStream.prototype._flush = function(done) {
|
||||
try {
|
||||
var res = this.conv.end();
|
||||
if (res && res.length) this.push(res);
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
}
|
||||
|
||||
IconvLiteEncoderStream.prototype.collect = function(cb) {
|
||||
var chunks = [];
|
||||
this.on('error', cb);
|
||||
this.on('data', function(chunk) { chunks.push(chunk); });
|
||||
this.on('end', function() {
|
||||
cb(null, Buffer.concat(chunks));
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// == Decoder stream =======================================================
|
||||
function IconvLiteDecoderStream(conv, options) {
|
||||
this.conv = conv;
|
||||
options = options || {};
|
||||
options.encoding = this.encoding = 'utf8'; // We output strings.
|
||||
Transform.call(this, options);
|
||||
}
|
||||
|
||||
IconvLiteDecoderStream.prototype = Object.create(Transform.prototype, {
|
||||
constructor: { value: IconvLiteDecoderStream }
|
||||
});
|
||||
|
||||
IconvLiteDecoderStream.prototype._transform = function(chunk, encoding, done) {
|
||||
if (!Buffer.isBuffer(chunk))
|
||||
return done(new Error("Iconv decoding stream needs buffers as its input."));
|
||||
try {
|
||||
var res = this.conv.write(chunk);
|
||||
if (res && res.length) this.push(res, this.encoding);
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
}
|
||||
|
||||
IconvLiteDecoderStream.prototype._flush = function(done) {
|
||||
try {
|
||||
var res = this.conv.end();
|
||||
if (res && res.length) this.push(res, this.encoding);
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
}
|
||||
|
||||
IconvLiteDecoderStream.prototype.collect = function(cb) {
|
||||
var res = '';
|
||||
this.on('error', cb);
|
||||
this.on('data', function(chunk) { res += chunk; });
|
||||
this.on('end', function() {
|
||||
cb(null, res);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -0,0 +1,118 @@
|
||||
{
|
||||
"name": "iconv-lite",
|
||||
"description": "Convert character encodings in pure javascript.",
|
||||
"version": "0.4.13",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"iconv",
|
||||
"convert",
|
||||
"charset",
|
||||
"icu"
|
||||
],
|
||||
"author": {
|
||||
"name": "Alexander Shtuchkin",
|
||||
"email": "ashtuchkin@gmail.com"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Jinwu Zhan",
|
||||
"url": "https://github.com/jenkinv"
|
||||
},
|
||||
{
|
||||
"name": "Adamansky Anton",
|
||||
"url": "https://github.com/adamansky"
|
||||
},
|
||||
{
|
||||
"name": "George Stagas",
|
||||
"url": "https://github.com/stagas"
|
||||
},
|
||||
{
|
||||
"name": "Mike D Pilsbury",
|
||||
"url": "https://github.com/pekim"
|
||||
},
|
||||
{
|
||||
"name": "Niggler",
|
||||
"url": "https://github.com/Niggler"
|
||||
},
|
||||
{
|
||||
"name": "wychi",
|
||||
"url": "https://github.com/wychi"
|
||||
},
|
||||
{
|
||||
"name": "David Kuo",
|
||||
"url": "https://github.com/david50407"
|
||||
},
|
||||
{
|
||||
"name": "ChangZhuo Chen",
|
||||
"url": "https://github.com/czchen"
|
||||
},
|
||||
{
|
||||
"name": "Lee Treveil",
|
||||
"url": "https://github.com/leetreveil"
|
||||
},
|
||||
{
|
||||
"name": "Brian White",
|
||||
"url": "https://github.com/mscdex"
|
||||
},
|
||||
{
|
||||
"name": "Mithgol",
|
||||
"url": "https://github.com/Mithgol"
|
||||
},
|
||||
{
|
||||
"name": "Nazar Leush",
|
||||
"url": "https://github.com/nleush"
|
||||
}
|
||||
],
|
||||
"main": "./lib/index.js",
|
||||
"homepage": "https://github.com/ashtuchkin/iconv-lite",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ashtuchkin/iconv-lite/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/ashtuchkin/iconv-lite.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"coverage": "istanbul cover _mocha -- --grep .",
|
||||
"coverage-open": "open coverage/lcov-report/index.html",
|
||||
"test": "mocha --reporter spec --grep ."
|
||||
},
|
||||
"browser": {
|
||||
"./extend-node": false,
|
||||
"./streams": false
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "*",
|
||||
"request": "2.47",
|
||||
"unorm": "*",
|
||||
"errto": "*",
|
||||
"async": "*",
|
||||
"istanbul": "*",
|
||||
"iconv": "2.1"
|
||||
},
|
||||
"gitHead": "f5ec51b1e7dd1477a3570824960641eebdc5fbc6",
|
||||
"_id": "iconv-lite@0.4.13",
|
||||
"_shasum": "1f88aba4ab0b1508e8312acc39345f36e992e2f2",
|
||||
"_from": "iconv-lite@0.4.13",
|
||||
"_npmVersion": "2.14.4",
|
||||
"_nodeVersion": "4.1.1",
|
||||
"_npmUser": {
|
||||
"name": "ashtuchkin",
|
||||
"email": "ashtuchkin@gmail.com"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "ashtuchkin",
|
||||
"email": "ashtuchkin@gmail.com"
|
||||
}
|
||||
],
|
||||
"dist": {
|
||||
"shasum": "1f88aba4ab0b1508e8312acc39345f36e992e2f2",
|
||||
"tarball": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz"
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
2.3.0 / 2015-05-26
|
||||
==================
|
||||
|
||||
* Add defined behavior for HTTP `CONNECT` requests
|
||||
* Add defined behavior for HTTP `Upgrade` requests
|
||||
* deps: ee-first@1.1.1
|
||||
|
||||
2.2.1 / 2015-04-22
|
||||
==================
|
||||
|
||||
* Fix `isFinished(req)` when data buffered
|
||||
|
||||
2.2.0 / 2014-12-22
|
||||
==================
|
||||
|
||||
* Add message object to callback arguments
|
||||
|
||||
2.1.1 / 2014-10-22
|
||||
==================
|
||||
|
||||
* Fix handling of pipelined requests
|
||||
|
||||
2.1.0 / 2014-08-16
|
||||
==================
|
||||
|
||||
* Check if `socket` is detached
|
||||
* Return `undefined` for `isFinished` if state unknown
|
||||
|
||||
2.0.0 / 2014-08-16
|
||||
==================
|
||||
|
||||
* Add `isFinished` function
|
||||
* Move to `jshttp` organization
|
||||
* Remove support for plain socket argument
|
||||
* Rename to `on-finished`
|
||||
* Support both `req` and `res` as arguments
|
||||
* deps: ee-first@1.0.5
|
||||
|
||||
1.2.2 / 2014-06-10
|
||||
==================
|
||||
|
||||
* Reduce listeners added to emitters
|
||||
- avoids "event emitter leak" warnings when used multiple times on same request
|
||||
|
||||
1.2.1 / 2014-06-08
|
||||
==================
|
||||
|
||||
* Fix returned value when already finished
|
||||
|
||||
1.2.0 / 2014-06-05
|
||||
==================
|
||||
|
||||
* Call callback when called on already-finished socket
|
||||
|
||||
1.1.4 / 2014-05-27
|
||||
==================
|
||||
|
||||
* Support node.js 0.8
|
||||
|
||||
1.1.3 / 2014-04-30
|
||||
==================
|
||||
|
||||
* Make sure errors passed as instanceof `Error`
|
||||
|
||||
1.1.2 / 2014-04-18
|
||||
==================
|
||||
|
||||
* Default the `socket` to passed-in object
|
||||
|
||||
1.1.1 / 2014-01-16
|
||||
==================
|
||||
|
||||
* Rename module to `finished`
|
||||
|
||||
1.1.0 / 2013-12-25
|
||||
==================
|
||||
|
||||
* Call callback when called on already-errored socket
|
||||
|
||||
1.0.1 / 2013-12-20
|
||||
==================
|
||||
|
||||
* Actually pass the error to the callback
|
||||
|
||||
1.0.0 / 2013-12-20
|
||||
==================
|
||||
|
||||
* Initial release
|
||||
@ -0,0 +1,23 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2013 Jonathan Ong <me@jongleberry.com>
|
||||
Copyright (c) 2014 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.
|
||||
@ -0,0 +1,154 @@
|
||||
# on-finished
|
||||
|
||||
[![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]
|
||||
|
||||
Execute a callback when a HTTP request closes, finishes, or errors.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
$ npm install on-finished
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var onFinished = require('on-finished')
|
||||
```
|
||||
|
||||
### onFinished(res, listener)
|
||||
|
||||
Attach a listener to listen for the response to finish. The listener will
|
||||
be invoked only once when the response finished. If the response finished
|
||||
to an error, the first argument will contain the error. If the response
|
||||
has already finished, the listener will be invoked.
|
||||
|
||||
Listening to the end of a response would be used to close things associated
|
||||
with the response, like open files.
|
||||
|
||||
Listener is invoked as `listener(err, res)`.
|
||||
|
||||
```js
|
||||
onFinished(res, function (err, res) {
|
||||
// clean up open fds, etc.
|
||||
// err contains the error is request error'd
|
||||
})
|
||||
```
|
||||
|
||||
### onFinished(req, listener)
|
||||
|
||||
Attach a listener to listen for the request to finish. The listener will
|
||||
be invoked only once when the request finished. If the request finished
|
||||
to an error, the first argument will contain the error. If the request
|
||||
has already finished, the listener will be invoked.
|
||||
|
||||
Listening to the end of a request would be used to know when to continue
|
||||
after reading the data.
|
||||
|
||||
Listener is invoked as `listener(err, req)`.
|
||||
|
||||
```js
|
||||
var data = ''
|
||||
|
||||
req.setEncoding('utf8')
|
||||
res.on('data', function (str) {
|
||||
data += str
|
||||
})
|
||||
|
||||
onFinished(req, function (err, req) {
|
||||
// data is read unless there is err
|
||||
})
|
||||
```
|
||||
|
||||
### onFinished.isFinished(res)
|
||||
|
||||
Determine if `res` is already finished. This would be useful to check and
|
||||
not even start certain operations if the response has already finished.
|
||||
|
||||
### onFinished.isFinished(req)
|
||||
|
||||
Determine if `req` is already finished. This would be useful to check and
|
||||
not even start certain operations if the request has already finished.
|
||||
|
||||
## Special Node.js requests
|
||||
|
||||
### HTTP CONNECT method
|
||||
|
||||
The meaning of the `CONNECT` method from RFC 7231, section 4.3.6:
|
||||
|
||||
> The CONNECT method requests that the recipient establish a tunnel to
|
||||
> the destination origin server identified by the request-target and,
|
||||
> if successful, thereafter restrict its behavior to blind forwarding
|
||||
> of packets, in both directions, until the tunnel is closed. Tunnels
|
||||
> are commonly used to create an end-to-end virtual connection, through
|
||||
> one or more proxies, which can then be secured using TLS (Transport
|
||||
> Layer Security, [RFC5246]).
|
||||
|
||||
In Node.js, these request objects come from the `'connect'` event on
|
||||
the HTTP server.
|
||||
|
||||
When this module is used on a HTTP `CONNECT` request, the request is
|
||||
considered "finished" immediately, **due to limitations in the Node.js
|
||||
interface**. This means if the `CONNECT` request contains a request entity,
|
||||
the request will be considered "finished" even before it has been read.
|
||||
|
||||
There is no such thing as a response object to a `CONNECT` request in
|
||||
Node.js, so there is no support for for one.
|
||||
|
||||
### HTTP Upgrade request
|
||||
|
||||
The meaning of the `Upgrade` header from RFC 7230, section 6.1:
|
||||
|
||||
> The "Upgrade" header field is intended to provide a simple mechanism
|
||||
> for transitioning from HTTP/1.1 to some other protocol on the same
|
||||
> connection.
|
||||
|
||||
In Node.js, these request objects come from the `'upgrade'` event on
|
||||
the HTTP server.
|
||||
|
||||
When this module is used on a HTTP request with an `Upgrade` header, the
|
||||
request is considered "finished" immediately, **due to limitations in the
|
||||
Node.js interface**. This means if the `Upgrade` request contains a request
|
||||
entity, the request will be considered "finished" even before it has been
|
||||
read.
|
||||
|
||||
There is no such thing as a response object to a `Upgrade` request in
|
||||
Node.js, so there is no support for for one.
|
||||
|
||||
## Example
|
||||
|
||||
The following code ensures that file descriptors are always closed
|
||||
once the response finishes.
|
||||
|
||||
```js
|
||||
var destroy = require('destroy')
|
||||
var http = require('http')
|
||||
var onFinished = require('on-finished')
|
||||
|
||||
http.createServer(function onRequest(req, res) {
|
||||
var stream = fs.createReadStream('package.json')
|
||||
stream.pipe(res)
|
||||
onFinished(res, function (err) {
|
||||
destroy(stream)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/on-finished.svg
|
||||
[npm-url]: https://npmjs.org/package/on-finished
|
||||
[node-version-image]: https://img.shields.io/node/v/on-finished.svg
|
||||
[node-version-url]: http://nodejs.org/download/
|
||||
[travis-image]: https://img.shields.io/travis/jshttp/on-finished/master.svg
|
||||
[travis-url]: https://travis-ci.org/jshttp/on-finished
|
||||
[coveralls-image]: https://img.shields.io/coveralls/jshttp/on-finished/master.svg
|
||||
[coveralls-url]: https://coveralls.io/r/jshttp/on-finished?branch=master
|
||||
[downloads-image]: https://img.shields.io/npm/dm/on-finished.svg
|
||||
[downloads-url]: https://npmjs.org/package/on-finished
|
||||
@ -0,0 +1,196 @@
|
||||
/*!
|
||||
* on-finished
|
||||
* Copyright(c) 2013 Jonathan Ong
|
||||
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
* @public
|
||||
*/
|
||||
|
||||
module.exports = onFinished
|
||||
module.exports.isFinished = isFinished
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var first = require('ee-first')
|
||||
|
||||
/**
|
||||
* Variables.
|
||||
* @private
|
||||
*/
|
||||
|
||||
/* istanbul ignore next */
|
||||
var defer = typeof setImmediate === 'function'
|
||||
? setImmediate
|
||||
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
|
||||
|
||||
/**
|
||||
* Invoke callback when the response has finished, useful for
|
||||
* cleaning up resources afterwards.
|
||||
*
|
||||
* @param {object} msg
|
||||
* @param {function} listener
|
||||
* @return {object}
|
||||
* @public
|
||||
*/
|
||||
|
||||
function onFinished(msg, listener) {
|
||||
if (isFinished(msg) !== false) {
|
||||
defer(listener, null, msg)
|
||||
return msg
|
||||
}
|
||||
|
||||
// attach the listener to the message
|
||||
attachListener(msg, listener)
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if message is already finished.
|
||||
*
|
||||
* @param {object} msg
|
||||
* @return {boolean}
|
||||
* @public
|
||||
*/
|
||||
|
||||
function isFinished(msg) {
|
||||
var socket = msg.socket
|
||||
|
||||
if (typeof msg.finished === 'boolean') {
|
||||
// OutgoingMessage
|
||||
return Boolean(msg.finished || (socket && !socket.writable))
|
||||
}
|
||||
|
||||
if (typeof msg.complete === 'boolean') {
|
||||
// IncomingMessage
|
||||
return Boolean(msg.upgrade || !socket || !socket.readable || (msg.complete && !msg.readable))
|
||||
}
|
||||
|
||||
// don't know
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a finished listener to the message.
|
||||
*
|
||||
* @param {object} msg
|
||||
* @param {function} callback
|
||||
* @private
|
||||
*/
|
||||
|
||||
function attachFinishedListener(msg, callback) {
|
||||
var eeMsg
|
||||
var eeSocket
|
||||
var finished = false
|
||||
|
||||
function onFinish(error) {
|
||||
eeMsg.cancel()
|
||||
eeSocket.cancel()
|
||||
|
||||
finished = true
|
||||
callback(error)
|
||||
}
|
||||
|
||||
// finished on first message event
|
||||
eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish)
|
||||
|
||||
function onSocket(socket) {
|
||||
// remove listener
|
||||
msg.removeListener('socket', onSocket)
|
||||
|
||||
if (finished) return
|
||||
if (eeMsg !== eeSocket) return
|
||||
|
||||
// finished on first socket event
|
||||
eeSocket = first([[socket, 'error', 'close']], onFinish)
|
||||
}
|
||||
|
||||
if (msg.socket) {
|
||||
// socket already assigned
|
||||
onSocket(msg.socket)
|
||||
return
|
||||
}
|
||||
|
||||
// wait for socket to be assigned
|
||||
msg.on('socket', onSocket)
|
||||
|
||||
if (msg.socket === undefined) {
|
||||
// node.js 0.8 patch
|
||||
patchAssignSocket(msg, onSocket)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach the listener to the message.
|
||||
*
|
||||
* @param {object} msg
|
||||
* @return {function}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function attachListener(msg, listener) {
|
||||
var attached = msg.__onFinished
|
||||
|
||||
// create a private single listener with queue
|
||||
if (!attached || !attached.queue) {
|
||||
attached = msg.__onFinished = createListener(msg)
|
||||
attachFinishedListener(msg, attached)
|
||||
}
|
||||
|
||||
attached.queue.push(listener)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create listener on message.
|
||||
*
|
||||
* @param {object} msg
|
||||
* @return {function}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function createListener(msg) {
|
||||
function listener(err) {
|
||||
if (msg.__onFinished === listener) msg.__onFinished = null
|
||||
if (!listener.queue) return
|
||||
|
||||
var queue = listener.queue
|
||||
listener.queue = null
|
||||
|
||||
for (var i = 0; i < queue.length; i++) {
|
||||
queue[i](err, msg)
|
||||
}
|
||||
}
|
||||
|
||||
listener.queue = []
|
||||
|
||||
return listener
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch ServerResponse.prototype.assignSocket for node.js 0.8.
|
||||
*
|
||||
* @param {ServerResponse} res
|
||||
* @param {function} callback
|
||||
* @private
|
||||
*/
|
||||
|
||||
function patchAssignSocket(res, callback) {
|
||||
var assignSocket = res.assignSocket
|
||||
|
||||
if (typeof assignSocket !== 'function') return
|
||||
|
||||
// res.on('socket', callback) is broken in 0.8
|
||||
res.assignSocket = function _assignSocket(socket) {
|
||||
assignSocket.call(this, socket)
|
||||
callback(socket)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Jonathan Ong me@jongleberry.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.
|
||||
@ -0,0 +1,80 @@
|
||||
# EE First
|
||||
|
||||
[![NPM version][npm-image]][npm-url]
|
||||
[![Build status][travis-image]][travis-url]
|
||||
[![Test coverage][coveralls-image]][coveralls-url]
|
||||
[![License][license-image]][license-url]
|
||||
[![Downloads][downloads-image]][downloads-url]
|
||||
[![Gittip][gittip-image]][gittip-url]
|
||||
|
||||
Get the first event in a set of event emitters and event pairs,
|
||||
then clean up after itself.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
$ npm install ee-first
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var first = require('ee-first')
|
||||
```
|
||||
|
||||
### first(arr, listener)
|
||||
|
||||
Invoke `listener` on the first event from the list specified in `arr`. `arr` is
|
||||
an array of arrays, with each array in the format `[ee, ...event]`. `listener`
|
||||
will be called only once, the first time any of the given events are emitted. If
|
||||
`error` is one of the listened events, then if that fires first, the `listener`
|
||||
will be given the `err` argument.
|
||||
|
||||
The `listener` is invoked as `listener(err, ee, event, args)`, where `err` is the
|
||||
first argument emitted from an `error` event, if applicable; `ee` is the event
|
||||
emitter that fired; `event` is the string event name that fired; and `args` is an
|
||||
array of the arguments that were emitted on the event.
|
||||
|
||||
```js
|
||||
var ee1 = new EventEmitter()
|
||||
var ee2 = new EventEmitter()
|
||||
|
||||
first([
|
||||
[ee1, 'close', 'end', 'error'],
|
||||
[ee2, 'error']
|
||||
], function (err, ee, event, args) {
|
||||
// listener invoked
|
||||
})
|
||||
```
|
||||
|
||||
#### .cancel()
|
||||
|
||||
The group of listeners can be cancelled before being invoked and have all the event
|
||||
listeners removed from the underlying event emitters.
|
||||
|
||||
```js
|
||||
var thunk = first([
|
||||
[ee1, 'close', 'end', 'error'],
|
||||
[ee2, 'error']
|
||||
], function (err, ee, event, args) {
|
||||
// listener invoked
|
||||
})
|
||||
|
||||
// cancel and clean up
|
||||
thunk.cancel()
|
||||
```
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/ee-first.svg?style=flat-square
|
||||
[npm-url]: https://npmjs.org/package/ee-first
|
||||
[github-tag]: http://img.shields.io/github/tag/jonathanong/ee-first.svg?style=flat-square
|
||||
[github-url]: https://github.com/jonathanong/ee-first/tags
|
||||
[travis-image]: https://img.shields.io/travis/jonathanong/ee-first.svg?style=flat-square
|
||||
[travis-url]: https://travis-ci.org/jonathanong/ee-first
|
||||
[coveralls-image]: https://img.shields.io/coveralls/jonathanong/ee-first.svg?style=flat-square
|
||||
[coveralls-url]: https://coveralls.io/r/jonathanong/ee-first?branch=master
|
||||
[license-image]: http://img.shields.io/npm/l/ee-first.svg?style=flat-square
|
||||
[license-url]: LICENSE.md
|
||||
[downloads-image]: http://img.shields.io/npm/dm/ee-first.svg?style=flat-square
|
||||
[downloads-url]: https://npmjs.org/package/ee-first
|
||||
[gittip-image]: https://img.shields.io/gittip/jonathanong.svg?style=flat-square
|
||||
[gittip-url]: https://www.gittip.com/jonathanong/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue