[Pkg-javascript-commits] [node-negotiator] 05/09: New upstream version 0.6.1
Praveen Arimbrathodiyil
praveen at moszumanska.debian.org
Mon Sep 4 16:36:23 UTC 2017
This is an automated email from the git hooks/post-receive script.
praveen pushed a commit to branch master
in repository node-negotiator.
commit f954fbdca8132a4c0e79d9adf1f87f64d9131dec
Author: Pirate Praveen <praveen at debian.org>
Date: Mon Sep 4 21:45:46 2017 +0530
New upstream version 0.6.1
---
.gitignore | 23 ++
.travis.yml | 29 ++-
HISTORY.md | 98 +++++++++
LICENSE | 3 +-
README.md | 88 ++++++--
index.js | 124 +++++++++++
lib/charset.js | 164 ++++++++++----
lib/encoding.js | 191 ++++++++++------
lib/language.js | 167 ++++++++++----
lib/mediaType.js | 290 ++++++++++++++++++++-----
lib/negotiator.js | 37 ----
package.json | 38 ++--
test/charset.js | 408 ++++++++++++++++++++++++++++-------
test/encoding.js | 539 ++++++++++++++++++++++++++++++++++++---------
test/language.js | 531 +++++++++++++++++++++++++++++++++++----------
test/mediaType.js | 635 ++++++++++++++++++++++++++++++++++++++++++------------
16 files changed, 2649 insertions(+), 716 deletions(-)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3860288
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+# OS X
+.DS_Store*
+Icon?
+._*
+
+# Windows
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+
+# Linux
+.directory
+*~
+
+
+# npm
+node_modules
+*.log
+*.gz
+
+
+# Coveralls
+coverage
diff --git a/.travis.yml b/.travis.yml
index 25a64e6..f5f9911 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,8 +1,23 @@
-node_js:
-- "0.6"
-- "0.8"
-- "0.10"
-- "0.11"
language: node_js
-script: "npm run-script test-cov"
-after_script: "npm install coveralls at 2 && cat ./coverage/lcov.info | coveralls"
+node_js:
+ - "0.6"
+ - "0.8"
+ - "0.10"
+ - "0.12"
+ - "1.8"
+ - "2.5"
+ - "3.3"
+ - "4.4"
+ - "5.11"
+ - "6.0"
+sudo: false
+before_install:
+ # Setup Node.js version-specific dependencies
+ - "test $TRAVIS_NODE_VERSION != '0.6' || npm rm --save-dev istanbul"
+ - "test $TRAVIS_NODE_VERSION != '0.8' || npm rm --save-dev istanbul"
+script:
+ # Run test script, depending on istanbul install
+ - "test ! -z $(npm -ps ls istanbul) || npm test"
+ - "test -z $(npm -ps ls istanbul) || npm run-script test-travis"
+after_script:
+ - "test -e ./coverage/lcov.info && npm install coveralls at 2 && cat ./coverage/lcov.info | coveralls"
diff --git a/HISTORY.md b/HISTORY.md
new file mode 100644
index 0000000..10b6917
--- /dev/null
+++ b/HISTORY.md
@@ -0,0 +1,98 @@
+0.6.1 / 2016-05-02
+==================
+
+ * perf: improve `Accept` parsing speed
+ * perf: improve `Accept-Charset` parsing speed
+ * perf: improve `Accept-Encoding` parsing speed
+ * perf: improve `Accept-Language` parsing speed
+
+0.6.0 / 2015-09-29
+==================
+
+ * Fix including type extensions in parameters in `Accept` parsing
+ * Fix parsing `Accept` parameters with quoted equals
+ * Fix parsing `Accept` parameters with quoted semicolons
+ * Lazy-load modules from main entry point
+ * perf: delay type concatenation until needed
+ * perf: enable strict mode
+ * perf: hoist regular expressions
+ * perf: remove closures getting spec properties
+ * perf: remove a closure from media type parsing
+ * perf: remove property delete from media type parsing
+
+0.5.3 / 2015-05-10
+==================
+
+ * Fix media type parameter matching to be case-insensitive
+
+0.5.2 / 2015-05-06
+==================
+
+ * Fix comparing media types with quoted values
+ * Fix splitting media types with quoted commas
+
+0.5.1 / 2015-02-14
+==================
+
+ * Fix preference sorting to be stable for long acceptable lists
+
+0.5.0 / 2014-12-18
+==================
+
+ * Fix list return order when large accepted list
+ * Fix missing identity encoding when q=0 exists
+ * Remove dynamic building of Negotiator class
+
+0.4.9 / 2014-10-14
+==================
+
+ * Fix error when media type has invalid parameter
+
+0.4.8 / 2014-09-28
+==================
+
+ * Fix all negotiations to be case-insensitive
+ * Stable sort preferences of same quality according to client order
+ * Support Node.js 0.6
+
+0.4.7 / 2014-06-24
+==================
+
+ * Handle invalid provided languages
+ * Handle invalid provided media types
+
+0.4.6 / 2014-06-11
+==================
+
+ * Order by specificity when quality is the same
+
+0.4.5 / 2014-05-29
+==================
+
+ * Fix regression in empty header handling
+
+0.4.4 / 2014-05-29
+==================
+
+ * Fix behaviors when headers are not present
+
+0.4.3 / 2014-04-16
+==================
+
+ * Handle slashes on media params correctly
+
+0.4.2 / 2014-02-28
+==================
+
+ * Fix media type sorting
+ * Handle media types params strictly
+
+0.4.1 / 2014-01-16
+==================
+
+ * Use most specific matches
+
+0.4.0 / 2014-01-09
+==================
+
+ * Remove preferred prefix from methods
diff --git a/LICENSE b/LICENSE
index 692b534..ea6b9e2 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,8 @@
(The MIT License)
-Copyright (c) 2012 Federico Romero
+Copyright (c) 2012-2014 Federico Romero
Copyright (c) 2012-2014 Isaac Z. Schlueter
+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
diff --git a/README.md b/README.md
index 2461eb1..04a67ff 100644
--- a/README.md
+++ b/README.md
@@ -44,20 +44,29 @@ You can check a working example at `examples/accept.js`.
#### Methods
-##### mediaTypes(availableMediaTypes):
+##### mediaType()
-Returns an array of preferred media types ordered by priority from a list of available media types.
+Returns the most preferred media type from the client.
-##### mediaType(availableMediaType):
+##### mediaType(availableMediaType)
-Returns the top preferred media type from a list of available media types.
+Returns the most preferred media type from a list of available media types.
+
+##### mediaTypes()
+
+Returns an array of preferred media types ordered by the client preference.
+
+##### mediaTypes(availableMediaTypes)
+
+Returns an array of preferred media types ordered by priority from a list of
+available media types.
### Accept-Language Negotiation
```js
negotiator = new Negotiator(request)
-availableLanguages = 'en', 'es', 'fr'
+availableLanguages = ['en', 'es', 'fr']
// Let's say Accept-Language header is 'en;q=0.8, es, pt'
@@ -75,13 +84,22 @@ You can check a working example at `examples/language.js`.
#### Methods
-##### languages(availableLanguages):
+##### language()
+
+Returns the most preferred language from the client.
-Returns an array of preferred languages ordered by priority from a list of available languages.
+##### language(availableLanguages)
-##### language(availableLanguages):
+Returns the most preferred language from a list of available languages.
-Returns the top preferred language from a list of available languages.
+##### languages()
+
+Returns an array of preferred languages ordered by the client preference.
+
+##### languages(availableLanguages)
+
+Returns an array of preferred languages ordered by priority from a list of
+available languages.
### Accept-Charset Negotiation
@@ -106,13 +124,22 @@ You can check a working example at `examples/charset.js`.
#### Methods
-##### charsets(availableCharsets):
+##### charset()
+
+Returns the most preferred charset from the client.
-Returns an array of preferred charsets ordered by priority from a list of available charsets.
+##### charset(availableCharsets)
-##### charset(availableCharsets):
+Returns the most preferred charset from a list of available charsets.
-Returns the top preferred charset from a list of available charsets.
+##### charsets()
+
+Returns an array of preferred charsets ordered by the client preference.
+
+##### charsets(availableCharsets)
+
+Returns an array of preferred charsets ordered by priority from a list of
+available charsets.
### Accept-Encoding Negotiation
@@ -137,25 +164,40 @@ You can check a working example at `examples/encoding.js`.
#### Methods
-##### encodings(availableEncodings):
+##### encoding()
+
+Returns the most preferred encoding from the client.
+
+##### encoding(availableEncodings)
+
+Returns the most preferred encoding from a list of available encodings.
+
+##### encodings()
+
+Returns an array of preferred encodings ordered by the client preference.
+
+##### encodings(availableEncodings)
-Returns an array of preferred encodings ordered by priority from a list of available encodings.
+Returns an array of preferred encodings ordered by priority from a list of
+available encodings.
-##### encoding(availableEncodings):
+## See Also
-Returns the top preferred encoding from a list of available encodings.
+The [accepts](https://npmjs.org/package/accepts#readme) module builds on
+this module and provides an alternative interface, mime type validation,
+and more.
## License
[MIT](LICENSE)
-[npm-image]: https://img.shields.io/npm/v/negotiator.svg?style=flat
+[npm-image]: https://img.shields.io/npm/v/negotiator.svg
[npm-url]: https://npmjs.org/package/negotiator
-[node-version-image]: https://img.shields.io/node/v/negotiator.svg?style=flat
-[node-version-url]: http://nodejs.org/download/
-[travis-image]: https://img.shields.io/travis/jshttp/negotiator.svg?style=flat
+[node-version-image]: https://img.shields.io/node/v/negotiator.svg
+[node-version-url]: https://nodejs.org/en/download/
+[travis-image]: https://img.shields.io/travis/jshttp/negotiator/master.svg
[travis-url]: https://travis-ci.org/jshttp/negotiator
-[coveralls-image]: https://img.shields.io/coveralls/jshttp/negotiator.svg?style=flat
+[coveralls-image]: https://img.shields.io/coveralls/jshttp/negotiator/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/negotiator?branch=master
-[downloads-image]: https://img.shields.io/npm/dm/negotiator.svg?style=flat
+[downloads-image]: https://img.shields.io/npm/dm/negotiator.svg
[downloads-url]: https://npmjs.org/package/negotiator
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..8d4f6a2
--- /dev/null
+++ b/index.js
@@ -0,0 +1,124 @@
+/*!
+ * negotiator
+ * Copyright(c) 2012 Federico Romero
+ * Copyright(c) 2012-2014 Isaac Z. Schlueter
+ * Copyright(c) 2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Cached loaded submodules.
+ * @private
+ */
+
+var modules = Object.create(null);
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = Negotiator;
+module.exports.Negotiator = Negotiator;
+
+/**
+ * Create a Negotiator instance from a request.
+ * @param {object} request
+ * @public
+ */
+
+function Negotiator(request) {
+ if (!(this instanceof Negotiator)) {
+ return new Negotiator(request);
+ }
+
+ this.request = request;
+}
+
+Negotiator.prototype.charset = function charset(available) {
+ var set = this.charsets(available);
+ return set && set[0];
+};
+
+Negotiator.prototype.charsets = function charsets(available) {
+ var preferredCharsets = loadModule('charset').preferredCharsets;
+ return preferredCharsets(this.request.headers['accept-charset'], available);
+};
+
+Negotiator.prototype.encoding = function encoding(available) {
+ var set = this.encodings(available);
+ return set && set[0];
+};
+
+Negotiator.prototype.encodings = function encodings(available) {
+ var preferredEncodings = loadModule('encoding').preferredEncodings;
+ return preferredEncodings(this.request.headers['accept-encoding'], available);
+};
+
+Negotiator.prototype.language = function language(available) {
+ var set = this.languages(available);
+ return set && set[0];
+};
+
+Negotiator.prototype.languages = function languages(available) {
+ var preferredLanguages = loadModule('language').preferredLanguages;
+ return preferredLanguages(this.request.headers['accept-language'], available);
+};
+
+Negotiator.prototype.mediaType = function mediaType(available) {
+ var set = this.mediaTypes(available);
+ return set && set[0];
+};
+
+Negotiator.prototype.mediaTypes = function mediaTypes(available) {
+ var preferredMediaTypes = loadModule('mediaType').preferredMediaTypes;
+ return preferredMediaTypes(this.request.headers.accept, available);
+};
+
+// Backwards compatibility
+Negotiator.prototype.preferredCharset = Negotiator.prototype.charset;
+Negotiator.prototype.preferredCharsets = Negotiator.prototype.charsets;
+Negotiator.prototype.preferredEncoding = Negotiator.prototype.encoding;
+Negotiator.prototype.preferredEncodings = Negotiator.prototype.encodings;
+Negotiator.prototype.preferredLanguage = Negotiator.prototype.language;
+Negotiator.prototype.preferredLanguages = Negotiator.prototype.languages;
+Negotiator.prototype.preferredMediaType = Negotiator.prototype.mediaType;
+Negotiator.prototype.preferredMediaTypes = Negotiator.prototype.mediaTypes;
+
+/**
+ * Load the given module.
+ * @private
+ */
+
+function loadModule(moduleName) {
+ var module = modules[moduleName];
+
+ if (module !== undefined) {
+ return module;
+ }
+
+ // This uses a switch for static require analysis
+ switch (moduleName) {
+ case 'charset':
+ module = require('./lib/charset');
+ break;
+ case 'encoding':
+ module = require('./lib/encoding');
+ break;
+ case 'language':
+ module = require('./lib/language');
+ break;
+ case 'mediaType':
+ module = require('./lib/mediaType');
+ break;
+ default:
+ throw new Error('Cannot find module \'' + moduleName + '\'');
+ }
+
+ // Store to prevent invoking require()
+ modules[moduleName] = module;
+
+ return module;
+}
diff --git a/lib/charset.js b/lib/charset.js
index 58da58f..ac4217b 100644
--- a/lib/charset.js
+++ b/lib/charset.js
@@ -1,16 +1,57 @@
+/**
+ * negotiator
+ * Copyright(c) 2012 Isaac Z. Schlueter
+ * Copyright(c) 2014 Federico Romero
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module exports.
+ * @public
+ */
+
module.exports = preferredCharsets;
-preferredCharsets.preferredCharsets = preferredCharsets;
+module.exports.preferredCharsets = preferredCharsets;
+
+/**
+ * Module variables.
+ * @private
+ */
+
+var simpleCharsetRegExp = /^\s*([^\s;]+)\s*(?:;(.*))?$/;
+
+/**
+ * Parse the Accept-Charset header.
+ * @private
+ */
function parseAcceptCharset(accept) {
- return accept.split(',').map(function(e, i) {
- return parseCharset(e.trim(), i);
- }).filter(function(e) {
- return e;
- });
+ var accepts = accept.split(',');
+
+ for (var i = 0, j = 0; i < accepts.length; i++) {
+ var charset = parseCharset(accepts[i].trim(), i);
+
+ if (charset) {
+ accepts[j++] = charset;
+ }
+ }
+
+ // trim accepts
+ accepts.length = j;
+
+ return accepts;
}
-function parseCharset(s, i) {
- var match = s.match(/^\s*(\S+?)\s*(?:;(.*))?$/);
+/**
+ * Parse a charset from the Accept-Charset header.
+ * @private
+ */
+
+function parseCharset(str, i) {
+ var match = simpleCharsetRegExp.exec(str);
if (!match) return null;
var charset = match[1];
@@ -33,19 +74,31 @@ function parseCharset(s, i) {
};
}
-function getCharsetPriority(charset, accepted) {
- return (accepted.map(function(a) {
- return specify(charset, a);
- }).filter(Boolean).sort(function (a, b) {
- if(a.s == b.s) {
- return a.q > b.q ? -1 : 1;
- } else {
- return a.s > b.s ? -1 : 1;
+/**
+ * Get the priority of a charset.
+ * @private
+ */
+
+function getCharsetPriority(charset, accepted, index) {
+ var priority = {o: -1, q: 0, s: 0};
+
+ for (var i = 0; i < accepted.length; i++) {
+ var spec = specify(charset, accepted[i], index);
+
+ if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
+ priority = spec;
}
- })[0] || {s: 0, q:0});
+ }
+
+ return priority;
}
-function specify(charset, spec) {
+/**
+ * Get the specificity of the charset.
+ * @private
+ */
+
+function specify(charset, spec, index) {
var s = 0;
if(spec.charset.toLowerCase() === charset.toLowerCase()){
s |= 1;
@@ -54,34 +107,63 @@ function specify(charset, spec) {
}
return {
- s: s,
+ i: index,
+ o: spec.i,
q: spec.q,
+ s: s
}
}
+/**
+ * Get the preferred charsets from an Accept-Charset header.
+ * @public
+ */
+
function preferredCharsets(accept, provided) {
// RFC 2616 sec 14.2: no header = *
- accept = parseAcceptCharset(accept === undefined ? '*' : accept || '');
- if (provided) {
- return provided.map(function(type) {
- return [type, getCharsetPriority(type, accept)];
- }).filter(function(pair) {
- return pair[1].q > 0;
- }).sort(function(a, b) {
- var pa = a[1];
- var pb = b[1];
- return (pb.q - pa.q) || (pb.s - pa.s) || (pa.i - pb.i);
- }).map(function(pair) {
- return pair[0];
- });
- } else {
- return accept.sort(function (a, b) {
- // revsort
- return (b.q - a.q) || (a.i - b.i);
- }).filter(function(type) {
- return type.q > 0;
- }).map(function(type) {
- return type.charset;
- });
+ var accepts = parseAcceptCharset(accept === undefined ? '*' : accept || '');
+
+ if (!provided) {
+ // sorted list of all charsets
+ return accepts
+ .filter(isQuality)
+ .sort(compareSpecs)
+ .map(getFullCharset);
}
+
+ var priorities = provided.map(function getPriority(type, index) {
+ return getCharsetPriority(type, accepts, index);
+ });
+
+ // sorted list of accepted charsets
+ return priorities.filter(isQuality).sort(compareSpecs).map(function getCharset(priority) {
+ return provided[priorities.indexOf(priority)];
+ });
+}
+
+/**
+ * Compare two specs.
+ * @private
+ */
+
+function compareSpecs(a, b) {
+ return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
+}
+
+/**
+ * Get full charset string.
+ * @private
+ */
+
+function getFullCharset(spec) {
+ return spec.charset;
+}
+
+/**
+ * Check if a spec has any quality.
+ * @private
+ */
+
+function isQuality(spec) {
+ return spec.q > 0;
}
diff --git a/lib/encoding.js b/lib/encoding.js
index 4b8acc1..70ac3de 100644
--- a/lib/encoding.js
+++ b/lib/encoding.js
@@ -1,47 +1,73 @@
+/**
+ * negotiator
+ * Copyright(c) 2012 Isaac Z. Schlueter
+ * Copyright(c) 2014 Federico Romero
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module exports.
+ * @public
+ */
+
module.exports = preferredEncodings;
-preferredEncodings.preferredEncodings = preferredEncodings;
+module.exports.preferredEncodings = preferredEncodings;
+
+/**
+ * Module variables.
+ * @private
+ */
+
+var simpleEncodingRegExp = /^\s*([^\s;]+)\s*(?:;(.*))?$/;
+
+/**
+ * Parse the Accept-Encoding header.
+ * @private
+ */
function parseAcceptEncoding(accept) {
- var acceptableEncodings;
-
- if (accept) {
- acceptableEncodings = accept.split(',').map(function(e, i) {
- return parseEncoding(e.trim(), i);
- });
- } else {
- acceptableEncodings = [];
+ var accepts = accept.split(',');
+ var hasIdentity = false;
+ var minQuality = 1;
+
+ for (var i = 0, j = 0; i < accepts.length; i++) {
+ var encoding = parseEncoding(accepts[i].trim(), i);
+
+ if (encoding) {
+ accepts[j++] = encoding;
+ hasIdentity = hasIdentity || specify('identity', encoding);
+ minQuality = Math.min(minQuality, encoding.q || 1);
+ }
}
- if (!acceptableEncodings.some(function(e) {
- return e && specify('identity', e);
- })) {
+ if (!hasIdentity) {
/*
* If identity doesn't explicitly appear in the accept-encoding header,
* it's added to the list of acceptable encoding with the lowest q
- *
*/
- var lowestQ = 1;
-
- for(var i = 0; i < acceptableEncodings.length; i++){
- var e = acceptableEncodings[i];
- if(e && e.q < lowestQ){
- lowestQ = e.q;
- }
- }
- acceptableEncodings.push({
+ accepts[j++] = {
encoding: 'identity',
- q: lowestQ / 2,
- });
+ q: minQuality,
+ i: i
+ };
}
- return acceptableEncodings.filter(function(e) {
- return e;
- });
+ // trim accepts
+ accepts.length = j;
+
+ return accepts;
}
-function parseEncoding(s, i) {
- var match = s.match(/^\s*(\S+?)\s*(?:;(.*))?$/);
+/**
+ * Parse an encoding from the Accept-Encoding header.
+ * @private
+ */
+function parseEncoding(str, i) {
+ var match = simpleEncodingRegExp.exec(str);
if (!match) return null;
var encoding = match[1];
@@ -64,19 +90,31 @@ function parseEncoding(s, i) {
};
}
-function getEncodingPriority(encoding, accepted) {
- return (accepted.map(function(a) {
- return specify(encoding, a);
- }).filter(Boolean).sort(function (a, b) {
- if(a.s == b.s) {
- return a.q > b.q ? -1 : 1;
- } else {
- return a.s > b.s ? -1 : 1;
+/**
+ * Get the priority of an encoding.
+ * @private
+ */
+
+function getEncodingPriority(encoding, accepted, index) {
+ var priority = {o: -1, q: 0, s: 0};
+
+ for (var i = 0; i < accepted.length; i++) {
+ var spec = specify(encoding, accepted[i], index);
+
+ if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
+ priority = spec;
}
- })[0] || {s: 0, q: 0});
+ }
+
+ return priority;
}
-function specify(encoding, spec) {
+/**
+ * Get the specificity of the encoding.
+ * @private
+ */
+
+function specify(encoding, spec, index) {
var s = 0;
if(spec.encoding.toLowerCase() === encoding.toLowerCase()){
s |= 1;
@@ -85,33 +123,62 @@ function specify(encoding, spec) {
}
return {
- s: s,
+ i: index,
+ o: spec.i,
q: spec.q,
+ s: s
}
};
+/**
+ * Get the preferred encodings from an Accept-Encoding header.
+ * @public
+ */
+
function preferredEncodings(accept, provided) {
- accept = parseAcceptEncoding(accept || '');
- if (provided) {
- return provided.map(function(type) {
- return [type, getEncodingPriority(type, accept)];
- }).filter(function(pair) {
- return pair[1].q > 0;
- }).sort(function(a, b) {
- var pa = a[1];
- var pb = b[1];
- return (pb.q - pa.q) || (pb.s - pa.s) || (pa.i - pb.i);
- }).map(function(pair) {
- return pair[0];
- });
- } else {
- return accept.sort(function (a, b) {
- // revsort
- return (b.q - a.q) || (a.i - b.i);
- }).filter(function(type){
- return type.q > 0;
- }).map(function(type) {
- return type.encoding;
- });
+ var accepts = parseAcceptEncoding(accept || '');
+
+ if (!provided) {
+ // sorted list of all encodings
+ return accepts
+ .filter(isQuality)
+ .sort(compareSpecs)
+ .map(getFullEncoding);
}
+
+ var priorities = provided.map(function getPriority(type, index) {
+ return getEncodingPriority(type, accepts, index);
+ });
+
+ // sorted list of accepted encodings
+ return priorities.filter(isQuality).sort(compareSpecs).map(function getEncoding(priority) {
+ return provided[priorities.indexOf(priority)];
+ });
+}
+
+/**
+ * Compare two specs.
+ * @private
+ */
+
+function compareSpecs(a, b) {
+ return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
+}
+
+/**
+ * Get full encoding string.
+ * @private
+ */
+
+function getFullEncoding(spec) {
+ return spec.encoding;
+}
+
+/**
+ * Check if a spec has any quality.
+ * @private
+ */
+
+function isQuality(spec) {
+ return spec.q > 0;
}
diff --git a/lib/language.js b/lib/language.js
index 8fc63df..1bd2d0e 100644
--- a/lib/language.js
+++ b/lib/language.js
@@ -1,16 +1,57 @@
+/**
+ * negotiator
+ * Copyright(c) 2012 Isaac Z. Schlueter
+ * Copyright(c) 2014 Federico Romero
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module exports.
+ * @public
+ */
+
module.exports = preferredLanguages;
-preferredLanguages.preferredLanguages = preferredLanguages;
+module.exports.preferredLanguages = preferredLanguages;
+
+/**
+ * Module variables.
+ * @private
+ */
+
+var simpleLanguageRegExp = /^\s*([^\s\-;]+)(?:-([^\s;]+))?\s*(?:;(.*))?$/;
+
+/**
+ * Parse the Accept-Language header.
+ * @private
+ */
function parseAcceptLanguage(accept) {
- return accept.split(',').map(function(e, i) {
- return parseLanguage(e.trim(), i);
- }).filter(function(e) {
- return e;
- });
+ var accepts = accept.split(',');
+
+ for (var i = 0, j = 0; i < accepts.length; i++) {
+ var langauge = parseLanguage(accepts[i].trim(), i);
+
+ if (langauge) {
+ accepts[j++] = langauge;
+ }
+ }
+
+ // trim accepts
+ accepts.length = j;
+
+ return accepts;
}
-function parseLanguage(s, i) {
- var match = s.match(/^\s*(\S+?)(?:-(\S+?))?\s*(?:;(.*))?$/);
+/**
+ * Parse a language from the Accept-Language header.
+ * @private
+ */
+
+function parseLanguage(str, i) {
+ var match = simpleLanguageRegExp.exec(str);
if (!match) return null;
var prefix = match[1],
@@ -37,19 +78,31 @@ function parseLanguage(s, i) {
};
}
-function getLanguagePriority(language, accepted) {
- return (accepted.map(function(a){
- return specify(language, a);
- }).filter(Boolean).sort(function (a, b) {
- if(a.s == b.s) {
- return a.q > b.q ? -1 : 1;
- } else {
- return a.s > b.s ? -1 : 1;
+/**
+ * Get the priority of a language.
+ * @private
+ */
+
+function getLanguagePriority(language, accepted, index) {
+ var priority = {o: -1, q: 0, s: 0};
+
+ for (var i = 0; i < accepted.length; i++) {
+ var spec = specify(language, accepted[i], index);
+
+ if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
+ priority = spec;
}
- })[0] || {s: 0, q: 0});
+ }
+
+ return priority;
}
-function specify(language, spec) {
+/**
+ * Get the specificity of the language.
+ * @private
+ */
+
+function specify(language, spec, index) {
var p = parseLanguage(language)
if (!p) return null;
var s = 0;
@@ -64,37 +117,63 @@ function specify(language, spec) {
}
return {
- s: s,
+ i: index,
+ o: spec.i,
q: spec.q,
+ s: s
}
};
+/**
+ * Get the preferred languages from an Accept-Language header.
+ * @public
+ */
+
function preferredLanguages(accept, provided) {
// RFC 2616 sec 14.4: no header = *
- accept = parseAcceptLanguage(accept === undefined ? '*' : accept || '');
- if (provided) {
-
- var ret = provided.map(function(type) {
- return [type, getLanguagePriority(type, accept)];
- }).filter(function(pair) {
- return pair[1].q > 0;
- }).sort(function(a, b) {
- var pa = a[1];
- var pb = b[1];
- return (pb.q - pa.q) || (pb.s - pa.s) || (pa.i - pb.i);
- }).map(function(pair) {
- return pair[0];
- });
- return ret;
-
- } else {
- return accept.sort(function (a, b) {
- // revsort
- return (b.q - a.q) || (a.i - b.i);
- }).filter(function(type) {
- return type.q > 0;
- }).map(function(type) {
- return type.full;
- });
+ var accepts = parseAcceptLanguage(accept === undefined ? '*' : accept || '');
+
+ if (!provided) {
+ // sorted list of all languages
+ return accepts
+ .filter(isQuality)
+ .sort(compareSpecs)
+ .map(getFullLanguage);
}
+
+ var priorities = provided.map(function getPriority(type, index) {
+ return getLanguagePriority(type, accepts, index);
+ });
+
+ // sorted list of accepted languages
+ return priorities.filter(isQuality).sort(compareSpecs).map(function getLanguage(priority) {
+ return provided[priorities.indexOf(priority)];
+ });
+}
+
+/**
+ * Compare two specs.
+ * @private
+ */
+
+function compareSpecs(a, b) {
+ return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
+}
+
+/**
+ * Get full language string.
+ * @private
+ */
+
+function getFullLanguage(spec) {
+ return spec.full;
+}
+
+/**
+ * Check if a spec has any quality.
+ * @private
+ */
+
+function isQuality(spec) {
+ return spec.q > 0;
}
diff --git a/lib/mediaType.js b/lib/mediaType.js
index 55e74a1..67309dd 100644
--- a/lib/mediaType.js
+++ b/lib/mediaType.js
@@ -1,35 +1,84 @@
+/**
+ * negotiator
+ * Copyright(c) 2012 Isaac Z. Schlueter
+ * Copyright(c) 2014 Federico Romero
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module exports.
+ * @public
+ */
+
module.exports = preferredMediaTypes;
-preferredMediaTypes.preferredMediaTypes = preferredMediaTypes;
+module.exports.preferredMediaTypes = preferredMediaTypes;
+
+/**
+ * Module variables.
+ * @private
+ */
+
+var simpleMediaTypeRegExp = /^\s*([^\s\/;]+)\/([^;\s]+)\s*(?:;(.*))?$/;
+
+/**
+ * Parse the Accept header.
+ * @private
+ */
function parseAccept(accept) {
- return accept.split(',').map(function(e, i) {
- return parseMediaType(e.trim(), i);
- }).filter(function(e) {
- return e;
- });
-};
+ var accepts = splitMediaTypes(accept);
+
+ for (var i = 0, j = 0; i < accepts.length; i++) {
+ var mediaType = parseMediaType(accepts[i].trim(), i);
-function parseMediaType(s, i) {
- var match = s.match(/\s*(\S+?)\/([^;\s]+)\s*(?:;(.*))?/);
+ if (mediaType) {
+ accepts[j++] = mediaType;
+ }
+ }
+
+ // trim accepts
+ accepts.length = j;
+
+ return accepts;
+}
+
+/**
+ * Parse a media type from the Accept header.
+ * @private
+ */
+
+function parseMediaType(str, i) {
+ var match = simpleMediaTypeRegExp.exec(str);
if (!match) return null;
- var type = match[1],
- subtype = match[2],
- full = "" + type + "/" + subtype,
- params = {},
- q = 1;
+ var params = Object.create(null);
+ var q = 1;
+ var subtype = match[2];
+ var type = match[1];
if (match[3]) {
- params = match[3].split(';').map(function(s) {
- return s.trim().split('=');
- }).reduce(function (set, p) {
- set[p[0]] = p[1];
- return set
- }, params);
-
- if (params.q != null) {
- q = parseFloat(params.q);
- delete params.q;
+ var kvps = splitParameters(match[3]).map(splitKeyValuePair);
+
+ for (var j = 0; j < kvps.length; j++) {
+ var pair = kvps[j];
+ var key = pair[0].toLowerCase();
+ var val = pair[1];
+
+ // get the value, unwrapping quotes
+ var value = val && val[0] === '"' && val[val.length - 1] === '"'
+ ? val.substr(1, val.length - 2)
+ : val;
+
+ if (key === 'q') {
+ q = parseFloat(value);
+ break;
+ }
+
+ // store parameter
+ params[key] = value;
}
}
@@ -38,24 +87,35 @@ function parseMediaType(s, i) {
subtype: subtype,
params: params,
q: q,
- i: i,
- full: full
+ i: i
};
}
-function getMediaTypePriority(type, accepted) {
- return (accepted.map(function(a) {
- return specify(type, a);
- }).filter(Boolean).sort(function (a, b) {
- if(a.s == b.s) {
- return a.q > b.q ? -1 : 1;
- } else {
- return a.s > b.s ? -1 : 1;
+/**
+ * Get the priority of a media type.
+ * @private
+ */
+
+function getMediaTypePriority(type, accepted, index) {
+ var priority = {o: -1, q: 0, s: 0};
+
+ for (var i = 0; i < accepted.length; i++) {
+ var spec = specify(type, accepted[i], index);
+
+ if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
+ priority = spec;
}
- })[0] || {s: 0, q: 0});
+ }
+
+ return priority;
}
-function specify(type, spec) {
+/**
+ * Get the specificity of the media type.
+ * @private
+ */
+
+function specify(type, spec, index) {
var p = parseMediaType(type);
var s = 0;
@@ -78,7 +138,7 @@ function specify(type, spec) {
var keys = Object.keys(spec.params);
if (keys.length > 0) {
if (keys.every(function (k) {
- return spec.params[k] == '*' || spec.params[k].toLowerCase() == (p.params[k] || '').toLowerCase();
+ return spec.params[k] == '*' || (spec.params[k] || '').toLowerCase() == (p.params[k] || '').toLowerCase();
})) {
s |= 1
} else {
@@ -87,36 +147,148 @@ function specify(type, spec) {
}
return {
+ i: index,
+ o: spec.i,
q: spec.q,
s: s,
}
-
}
+/**
+ * Get the preferred media types from an Accept header.
+ * @public
+ */
+
function preferredMediaTypes(accept, provided) {
// RFC 2616 sec 14.2: no header = */*
- accept = parseAccept(accept === undefined ? '*/*' : accept || '');
- if (provided) {
- return provided.map(function(type) {
- return [type, getMediaTypePriority(type, accept)];
- }).filter(function(pair) {
- return pair[1].q > 0;
- }).sort(function(a, b) {
- var pa = a[1];
- var pb = b[1];
- return (pb.q - pa.q) || (pb.s - pa.s) || (pa.i - pb.i);
- }).map(function(pair) {
- return pair[0];
- });
+ var accepts = parseAccept(accept === undefined ? '*/*' : accept || '');
+ if (!provided) {
+ // sorted list of all types
+ return accepts
+ .filter(isQuality)
+ .sort(compareSpecs)
+ .map(getFullType);
+ }
+
+ var priorities = provided.map(function getPriority(type, index) {
+ return getMediaTypePriority(type, accepts, index);
+ });
+
+ // sorted list of accepted types
+ return priorities.filter(isQuality).sort(compareSpecs).map(function getType(priority) {
+ return provided[priorities.indexOf(priority)];
+ });
+}
+
+/**
+ * Compare two specs.
+ * @private
+ */
+
+function compareSpecs(a, b) {
+ return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
+}
+
+/**
+ * Get full type string.
+ * @private
+ */
+
+function getFullType(spec) {
+ return spec.type + '/' + spec.subtype;
+}
+
+/**
+ * Check if a spec has any quality.
+ * @private
+ */
+
+function isQuality(spec) {
+ return spec.q > 0;
+}
+
+/**
+ * Count the number of quotes in a string.
+ * @private
+ */
+
+function quoteCount(string) {
+ var count = 0;
+ var index = 0;
+
+ while ((index = string.indexOf('"', index)) !== -1) {
+ count++;
+ index++;
+ }
+
+ return count;
+}
+
+/**
+ * Split a key value pair.
+ * @private
+ */
+
+function splitKeyValuePair(str) {
+ var index = str.indexOf('=');
+ var key;
+ var val;
+
+ if (index === -1) {
+ key = str;
} else {
- return accept.sort(function (a, b) {
- // revsort
- return (b.q - a.q) || (a.i - b.i);
- }).filter(function(type) {
- return type.q > 0;
- }).map(function(type) {
- return type.full;
- });
+ key = str.substr(0, index);
+ val = str.substr(index + 1);
+ }
+
+ return [key, val];
+}
+
+/**
+ * Split an Accept header into media types.
+ * @private
+ */
+
+function splitMediaTypes(accept) {
+ var accepts = accept.split(',');
+
+ for (var i = 1, j = 0; i < accepts.length; i++) {
+ if (quoteCount(accepts[j]) % 2 == 0) {
+ accepts[++j] = accepts[i];
+ } else {
+ accepts[j] += ',' + accepts[i];
+ }
+ }
+
+ // trim accepts
+ accepts.length = j + 1;
+
+ return accepts;
+}
+
+/**
+ * Split a string of parameters.
+ * @private
+ */
+
+function splitParameters(str) {
+ var parameters = str.split(';');
+
+ for (var i = 1, j = 0; i < parameters.length; i++) {
+ if (quoteCount(parameters[j]) % 2 == 0) {
+ parameters[++j] = parameters[i];
+ } else {
+ parameters[j] += ';' + parameters[i];
+ }
}
+
+ // trim parameters
+ parameters.length = j + 1;
+
+ for (var i = 0; i < parameters.length; i++) {
+ parameters[i] = parameters[i].trim();
+ }
+
+ return parameters;
}
diff --git a/lib/negotiator.js b/lib/negotiator.js
deleted file mode 100644
index ba0c48b..0000000
--- a/lib/negotiator.js
+++ /dev/null
@@ -1,37 +0,0 @@
-module.exports = Negotiator;
-Negotiator.Negotiator = Negotiator;
-
-function Negotiator(request) {
- if (!(this instanceof Negotiator)) return new Negotiator(request);
- this.request = request;
-}
-
-var set = { charset: 'accept-charset',
- encoding: 'accept-encoding',
- language: 'accept-language',
- mediaType: 'accept' };
-
-
-function capitalize(string){
- return string.charAt(0).toUpperCase() + string.slice(1);
-}
-
-Object.keys(set).forEach(function (k) {
- var header = set[k],
- method = require('./'+k+'.js'),
- singular = k,
- plural = k + 's';
-
- Negotiator.prototype[plural] = function (available) {
- return method(this.request.headers[header], available);
- };
-
- Negotiator.prototype[singular] = function(available) {
- var set = this[plural](available);
- if (set) return set[0];
- };
-
- // Keep preferred* methods for legacy compatibility
- Negotiator.prototype['preferred'+capitalize(plural)] = Negotiator.prototype[plural];
- Negotiator.prototype['preferred'+capitalize(singular)] = Negotiator.prototype[singular];
-})
diff --git a/package.json b/package.json
index f63c4b6..6c5d066 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,13 @@
{
"name": "negotiator",
"description": "HTTP content negotiation",
- "version": "0.4.8",
- "author": "Federico Romero <federico.romero at outboxlabs.com>",
- "contributors": ["Isaac Z. Schlueter <i at izs.me> (http://blog.izs.me/)"],
- "repository": "jshttp/negotiator",
+ "version": "0.6.1",
+ "contributors": [
+ "Douglas Christopher Wilson <doug at somethingdoug.com>",
+ "Federico Romero <federico.romero at outboxlabs.com>",
+ "Isaac Z. Schlueter <i at izs.me> (http://blog.izs.me/)"
+ ],
+ "license": "MIT",
"keywords": [
"http",
"content negotiation",
@@ -13,21 +16,24 @@
"accept-encoding",
"accept-charset"
],
- "license": "MIT",
+ "repository": "jshttp/negotiator",
"devDependencies": {
- "istanbul": "~0.3.2",
- "nodeunit": "0.8.x"
- },
- "scripts": {
- "test": "nodeunit test",
- "test-cov": "istanbul cover ./node_modules/nodeunit/bin/nodeunit test"
+ "istanbul": "0.4.3",
+ "mocha": "~1.21.5"
},
+ "files": [
+ "lib/",
+ "HISTORY.md",
+ "LICENSE",
+ "index.js",
+ "README.md"
+ ],
"engines": {
"node": ">= 0.6"
},
- "main": "lib/negotiator.js",
- "files": [
- "lib",
- "LICENSE"
- ]
+ "scripts": {
+ "test": "mocha --reporter spec --check-leaks --bail test/",
+ "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
+ "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
+ }
}
diff --git a/test/charset.js b/test/charset.js
index c365898..5efa155 100644
--- a/test/charset.js
+++ b/test/charset.js
@@ -1,83 +1,329 @@
-(function() {
- var configuration, preferredCharsets, testConfigurations, testCorrectCharset, _i, _len,
- _this = this;
-
- preferredCharsets = require('../lib/charset').preferredCharsets;
-
- this["Should not return a charset when no charset is provided"] = function(test) {
- test.deepEqual(preferredCharsets('*', []), []);
- return test.done();
- };
-
- this["Should not return a charset when no charset is acceptable"] = function(test) {
- test.deepEqual(preferredCharsets('ISO-8859-1', ['utf-8']), []);
- return test.done();
- };
-
- this["Should not return a charset with q = 0"] = function(test) {
- test.deepEqual(preferredCharsets('utf-8;q=0', ['utf-8']), []);
- return test.done();
- };
-
- this["Should be case insensitive"] = function(test) {
- test.deepEqual(preferredCharsets('iso-8859-1', ['ISO-8859-1']), ['ISO-8859-1']);
- return test.done();
- };
-
- testCorrectCharset = function(c) {
- return _this["Should return " + c.selected + " for accept-charset header " + c.accept + " with provided charset " + c.provided] = function(test) {
- test.deepEqual(preferredCharsets(c.accept, c.provided), c.selected);
- return test.done();
- };
- };
-
- testConfigurations = [
- {
- accept: undefined,
- provided: ['utf-8'],
- selected: ['utf-8']
- }, {
- accept: 'utf-8',
- provided: ['utf-8'],
- selected: ['utf-8']
- }, {
- accept: '*',
- provided: ['utf-8'],
- selected: ['utf-8']
- }, {
- accept: 'utf-8',
- provided: ['utf-8', 'ISO-8859-1'],
- selected: ['utf-8']
- }, {
- accept: 'utf-8, ISO-8859-1',
- provided: ['utf-8'],
- selected: ['utf-8']
- }, {
- accept: 'utf-8;q=0.8, ISO-8859-1',
- provided: ['utf-8', 'ISO-8859-1'],
- selected: ['ISO-8859-1', 'utf-8']
- }, {
- accept: 'utf-8;q=0.8, ISO-8859-1',
- provided: null,
- selected: ['ISO-8859-1', 'utf-8']
- }, {
- accept: '*, utf-8;q=0',
- provided: ['utf-8', 'ISO-8859-1'],
- selected: ['ISO-8859-1']
- }, {
- accept : '*, utf-8',
- provided: ['utf-8', 'ISO-8859-1' ],
- selected: ['utf-8', 'ISO-8859-1' ]
- }, {
- accept : 'utf-8;q=0.9, ISO-8859-1;q=0.8, utf-8;q=0.7',
- provided: ['utf-8', 'ISO-8859-1' ],
- selected: ['utf-8', 'ISO-8859-1' ]
- }
- ];
-
- for (_i = 0, _len = testConfigurations.length; _i < _len; _i++) {
- configuration = testConfigurations[_i];
- testCorrectCharset(configuration);
+
+var assert = require('assert')
+var Negotiator = require('..')
+
+describe('negotiator.charset()', function () {
+ whenAcceptCharset(undefined, function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.charset(), '*')
+ })
+ })
+
+ whenAcceptCharset('*', function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.charset(), '*')
+ })
+ })
+
+ whenAcceptCharset('*, UTF-8', function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.charset(), '*')
+ })
+ })
+
+ whenAcceptCharset('*, UTF-8;q=0', function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.charset(), '*')
+ })
+ })
+
+ whenAcceptCharset('ISO-8859-1', function () {
+ it('should return ISO-8859-1', function () {
+ assert.strictEqual(this.negotiator.charset(), 'ISO-8859-1')
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0', function () {
+ it('should return undefined', function () {
+ assert.strictEqual(this.negotiator.charset(), undefined)
+ })
+ })
+
+ whenAcceptCharset('UTF-8, ISO-8859-1', function () {
+ it('should return UTF-8', function () {
+ assert.strictEqual(this.negotiator.charset(), 'UTF-8')
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0.8, ISO-8859-1', function () {
+ it('should return ISO-8859-1', function () {
+ assert.strictEqual(this.negotiator.charset(), 'ISO-8859-1')
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0.9, ISO-8859-1;q=0.8, UTF-8;q=0.7', function () {
+ it('should return UTF-8', function () {
+ assert.strictEqual(this.negotiator.charset(), 'UTF-8')
+ })
+ })
+})
+
+describe('negotiator.charset(array)', function () {
+ whenAcceptCharset(undefined, function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.charset([]), undefined)
+ })
+
+ it('should return first type in list', function () {
+ assert.strictEqual(this.negotiator.charset(['UTF-8']), 'UTF-8')
+ assert.strictEqual(this.negotiator.charset(['UTF-8', 'ISO-8859-1']), 'UTF-8')
+ })
+ })
+
+ whenAcceptCharset('*', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.charset([]), undefined)
+ })
+
+ it('should return first type in list', function () {
+ assert.strictEqual(this.negotiator.charset(['UTF-8']), 'UTF-8')
+ assert.strictEqual(this.negotiator.charset(['UTF-8', 'ISO-8859-1']), 'UTF-8')
+ })
+ })
+
+ whenAcceptCharset('*, UTF-8', function () {
+ it('should return first type in list', function () {
+ assert.strictEqual(this.negotiator.charset(['UTF-8']), 'UTF-8')
+ assert.strictEqual(this.negotiator.charset(['UTF-8', 'ISO-8859-1']), 'UTF-8')
+ })
+ })
+
+ whenAcceptCharset('*, UTF-8;q=0', function () {
+ it('should return most client-preferred charset', function () {
+ assert.strictEqual(this.negotiator.charset(['UTF-8', 'ISO-8859-1']), 'ISO-8859-1')
+ })
+
+ it('should exclude UTF-8', function () {
+ assert.strictEqual(this.negotiator.charset(['UTF-8']), undefined)
+ })
+ })
+
+ whenAcceptCharset('ISO-8859-1', function () {
+ it('should return matching charset', function () {
+ assert.strictEqual(this.negotiator.charset(['ISO-8859-1']), 'ISO-8859-1')
+ assert.strictEqual(this.negotiator.charset(['UTF-8', 'ISO-8859-1']), 'ISO-8859-1')
+ })
+
+ it('should be case insensitive, returning provided casing', function () {
+ assert.strictEqual(this.negotiator.charset(['iso-8859-1']), 'iso-8859-1')
+ assert.strictEqual(this.negotiator.charset(['iso-8859-1', 'ISO-8859-1']), 'iso-8859-1')
+ assert.strictEqual(this.negotiator.charset(['ISO-8859-1', 'iso-8859-1']), 'ISO-8859-1')
+ })
+
+ it('should return undefined when no matching charsets', function () {
+ assert.strictEqual(this.negotiator.charset(['utf-8']), undefined)
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0', function () {
+ it('should always return undefined', function () {
+ assert.strictEqual(this.negotiator.charset(['ISO-8859-1']), undefined)
+ assert.strictEqual(this.negotiator.charset(['UTF-8', 'KOI8-R', 'ISO-8859-1']), undefined)
+ assert.strictEqual(this.negotiator.charset(['KOI8-R']), undefined)
+ })
+ })
+
+ whenAcceptCharset('UTF-8, ISO-8859-1', function () {
+ it('should return first matching charset', function () {
+ assert.strictEqual(this.negotiator.charset(['ISO-8859-1']), 'ISO-8859-1')
+ assert.strictEqual(this.negotiator.charset(['UTF-8', 'KOI8-R', 'ISO-8859-1']), 'UTF-8')
+ })
+
+ it('should return undefined when no matching charsets', function () {
+ assert.strictEqual(this.negotiator.charset(['KOI8-R']), undefined)
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0.8, ISO-8859-1', function () {
+ it('should return most client-preferred charset', function () {
+ assert.strictEqual(this.negotiator.charset(['ISO-8859-1']), 'ISO-8859-1')
+ assert.strictEqual(this.negotiator.charset(['UTF-8', 'KOI8-R', 'ISO-8859-1']), 'ISO-8859-1')
+ assert.strictEqual(this.negotiator.charset(['UTF-8', 'KOI8-R']), 'UTF-8')
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0.9, ISO-8859-1;q=0.8, UTF-8;q=0.7', function () {
+ it('should use highest perferred order on duplicate', function () {
+ assert.strictEqual(this.negotiator.charset(['ISO-8859-1']), 'ISO-8859-1')
+ assert.strictEqual(this.negotiator.charset(['UTF-8', 'ISO-8859-1']), 'UTF-8')
+ assert.strictEqual(this.negotiator.charset(['ISO-8859-1', 'UTF-8']), 'UTF-8')
+ })
+ })
+})
+
+describe('negotiator.charsets()', function () {
+ whenAcceptCharset(undefined, function () {
+ it('should return *', function () {
+ assert.deepEqual(this.negotiator.charsets(), ['*'])
+ })
+ })
+
+ whenAcceptCharset('*', function () {
+ it('should return *', function () {
+ assert.deepEqual(this.negotiator.charsets(), ['*'])
+ })
+ })
+
+ whenAcceptCharset('*, UTF-8', function () {
+ it('should return client-preferred charsets', function () {
+ assert.deepEqual(this.negotiator.charsets(), ['*', 'UTF-8'])
+ })
+ })
+
+ whenAcceptCharset('*, UTF-8;q=0', function () {
+ it('should exclude UTF-8', function () {
+ assert.deepEqual(this.negotiator.charsets(), ['*'])
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0', function () {
+ it('should return empty list', function () {
+ assert.deepEqual(this.negotiator.charsets(), [])
+ })
+ })
+
+ whenAcceptCharset('ISO-8859-1', function () {
+ it('should return client-preferred charsets', function () {
+ assert.deepEqual(this.negotiator.charsets(), ['ISO-8859-1'])
+ })
+ })
+
+ whenAcceptCharset('UTF-8, ISO-8859-1', function () {
+ it('should return client-preferred charsets', function () {
+ assert.deepEqual(this.negotiator.charsets(), ['UTF-8', 'ISO-8859-1'])
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0.8, ISO-8859-1', function () {
+ it('should return client-preferred charsets', function () {
+ assert.deepEqual(this.negotiator.charsets(), ['ISO-8859-1', 'UTF-8'])
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0.9, ISO-8859-1;q=0.8, UTF-8;q=0.7', function () {
+ it.skip('should use highest perferred order on duplicate', function () {
+ assert.deepEqual(this.negotiator.charsets(), ['UTF-8', 'ISO-8859-1'])
+ })
+ })
+})
+
+describe('negotiator.charsets(array)', function () {
+ whenAcceptCharset(undefined, function () {
+ it('should return empty list for empty list', function () {
+ assert.deepEqual(this.negotiator.charsets([]), [])
+ })
+
+ it('should return original list', function () {
+ assert.deepEqual(this.negotiator.charsets(['UTF-8']), ['UTF-8'])
+ assert.deepEqual(this.negotiator.charsets(['UTF-8', 'ISO-8859-1']), ['UTF-8', 'ISO-8859-1'])
+ })
+ })
+
+ whenAcceptCharset('*', function () {
+ it('should return empty list for empty list', function () {
+ assert.deepEqual(this.negotiator.charsets([]), [])
+ })
+
+ it('should return original list', function () {
+ assert.deepEqual(this.negotiator.charsets(['UTF-8']), ['UTF-8'])
+ assert.deepEqual(this.negotiator.charsets(['UTF-8', 'ISO-8859-1']), ['UTF-8', 'ISO-8859-1'])
+ })
+ })
+
+ whenAcceptCharset('*, UTF-8', function () {
+ it('should return matching charsets', function () {
+ assert.deepEqual(this.negotiator.charsets(['UTF-8']), ['UTF-8'])
+ assert.deepEqual(this.negotiator.charsets(['UTF-8', 'ISO-8859-1']), ['UTF-8', 'ISO-8859-1'])
+ })
+ })
+
+ whenAcceptCharset('*, UTF-8;q=0', function () {
+ it('should exclude UTF-8', function () {
+ assert.deepEqual(this.negotiator.charsets(['UTF-8']), [])
+ assert.deepEqual(this.negotiator.charsets(['UTF-8', 'ISO-8859-1']), ['ISO-8859-1'])
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0', function () {
+ it('should always return empty list', function () {
+ assert.deepEqual(this.negotiator.charsets(['ISO-8859-1']), [])
+ assert.deepEqual(this.negotiator.charsets(['UTF-8', 'KOI8-R', 'ISO-8859-1']), [])
+ assert.deepEqual(this.negotiator.charsets(['KOI8-R']), [])
+ })
+ })
+
+ whenAcceptCharset('ISO-8859-1', function () {
+ it('should return matching charsets', function () {
+ assert.deepEqual(this.negotiator.charsets(['ISO-8859-1']), ['ISO-8859-1'])
+ assert.deepEqual(this.negotiator.charsets(['UTF-8', 'ISO-8859-1']), ['ISO-8859-1'])
+ })
+
+ it('should be case insensitive, returning provided casing', function () {
+ assert.deepEqual(this.negotiator.charsets(['iso-8859-1']), ['iso-8859-1'])
+ assert.deepEqual(this.negotiator.charsets(['iso-8859-1', 'ISO-8859-1']), ['iso-8859-1', 'ISO-8859-1'])
+ assert.deepEqual(this.negotiator.charsets(['ISO-8859-1', 'iso-8859-1']), ['ISO-8859-1', 'iso-8859-1'])
+ })
+
+ it('should return empty list when no matching charsets', function () {
+ assert.deepEqual(this.negotiator.charsets(['utf-8']), [])
+ })
+ })
+
+ whenAcceptCharset('UTF-8, ISO-8859-1', function () {
+ it('should return matching charsets', function () {
+ assert.deepEqual(this.negotiator.charsets(['ISO-8859-1']), ['ISO-8859-1'])
+ assert.deepEqual(this.negotiator.charsets(['UTF-8', 'KOI8-R', 'ISO-8859-1']), ['UTF-8', 'ISO-8859-1'])
+ })
+
+ it('should return empty list when no matching charsets', function () {
+ assert.deepEqual(this.negotiator.charsets(['KOI8-R']), [])
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0.8, ISO-8859-1', function () {
+ it('should return matching charsets in client-preferred order', function () {
+ assert.deepEqual(this.negotiator.charsets(['ISO-8859-1']), ['ISO-8859-1'])
+ assert.deepEqual(this.negotiator.charsets(['UTF-8', 'KOI8-R', 'ISO-8859-1']), ['ISO-8859-1', 'UTF-8'])
+ })
+
+ it('should return empty list when no matching charsets', function () {
+ assert.deepEqual(this.negotiator.charsets(['KOI8-R']), [])
+ })
+ })
+
+ whenAcceptCharset('UTF-8;q=0.9, ISO-8859-1;q=0.8, UTF-8;q=0.7', function () {
+ it('should use highest perferred order on duplicate', function () {
+ assert.deepEqual(this.negotiator.charsets(['ISO-8859-1']), ['ISO-8859-1'])
+ assert.deepEqual(this.negotiator.charsets(['UTF-8', 'ISO-8859-1']), ['UTF-8', 'ISO-8859-1'])
+ assert.deepEqual(this.negotiator.charsets(['ISO-8859-1', 'UTF-8']), ['UTF-8', 'ISO-8859-1'])
+ })
+ })
+})
+
+function createRequest(headers) {
+ var request = {
+ headers: {}
+ }
+
+ if (headers) {
+ Object.keys(headers).forEach(function (key) {
+ request.headers[key.toLowerCase()] = headers[key]
+ })
}
-}).call(this);
+ return request
+}
+
+function whenAcceptCharset(acceptCharset, func) {
+ var description = !acceptCharset
+ ? 'when no Accept-Charset'
+ : 'when Accept-Charset: ' + acceptCharset
+
+ describe(description, function () {
+ before(function () {
+ this.negotiator = new Negotiator(createRequest({'Accept-Charset': acceptCharset}))
+ })
+
+ func()
+ })
+}
diff --git a/test/encoding.js b/test/encoding.js
index 7e898bc..d6cc2b5 100644
--- a/test/encoding.js
+++ b/test/encoding.js
@@ -1,101 +1,442 @@
-(function() {
- var configuration, preferredEncodings, testConfigurations, testCorrectEncoding, _i, _len,
- _this = this;
-
- preferredEncodings = require('../lib/encoding').preferredEncodings;
-
- this["Should return identity encoding when no encoding is provided"] = function(test) {
- test.deepEqual(preferredEncodings(null), ['identity']);
- return test.done();
- };
-
- this["Should include the identity encoding even if not explicity listed"] = function(test) {
- test.ok(preferredEncodings('gzip').indexOf('identity') !== -1);
- return test.done();
- };
-
- this["Should not return identity encoding if q = 0"] = function(test) {
- test.ok(preferredEncodings('identity;q=0').indexOf('identity') === -1);
- return test.done();
- };
-
- this["Should not return identity encoding if * has q = 0"] = function(test) {
- test.ok(preferredEncodings('*;q=0').indexOf('identity') === -1);
- return test.done();
- };
-
- this["Should not return identity encoding if * has q = 0 but identity explicitly has q > 0"] = function(test) {
- test.ok(preferredEncodings('*;q=0, identity;q=0.5').indexOf('identity') !== -1);
- return test.done();
- };
-
- this["Should be case insensitive"] = function(test) {
- test.deepEqual(preferredEncodings('IDENTITY', ['identity']), ['identity']);
- return test.done();
- };
-
- testCorrectEncoding = function(c) {
- return _this["Should return " + c.selected + " for accept-encoding header " + c.accept + " with provided encoding " + c.provided] = function(test) {
- test.deepEqual(preferredEncodings(c.accept, c.provided), c.selected);
- return test.done();
- };
- };
-
- testConfigurations = [
- {
- accept: undefined,
- provided: ['identity', 'gzip'],
- selected: ['identity']
- }, {
- accept: 'gzip',
- provided: ['identity', 'gzip'],
- selected: ['gzip', 'identity']
- }, {
- accept: 'gzip, compress',
- provided: ['compress'],
- selected: ['compress']
- }, {
- accept: 'deflate',
- provided: ['gzip', 'identity'],
- selected: ['identity']
- }, {
- accept: '*',
- provided: ['identity', 'gzip'],
- selected: ['identity', 'gzip']
- }, {
- accept: 'gzip, compress',
- provided: ['compress', 'identity'],
- selected: ['compress', 'identity']
- }, {
- accept: 'gzip;q=0.8, identity;q=0.5, *;q=0.3',
- provided: ['identity', 'gzip', 'compress'],
- selected: ['gzip', 'identity', 'compress']
- }, {
- accept: 'gzip;q=0.8, compress',
- provided: ['gzip', 'compress'],
- selected: ['compress', 'gzip']
- }, {
- accept: '*, compress;q=0',
- provided: ['gzip', 'compress'],
- selected: ['gzip']
- }, {
- accept: 'gzip;q=0.8, compress',
- provided: null,
- selected: ['compress', 'gzip', 'identity']
- }, {
- accept : '*, compress',
- provided : ['gzip', 'compress'],
- selected : ['compress', 'gzip' ]
- }, {
- accept : 'gzip;q=0.9, compress;q=0.8, gzip;q=0.7',
- provided : ['gzip', 'compress'],
- selected : ['gzip', 'compress']
- }
- ];
-
- for (_i = 0, _len = testConfigurations.length; _i < _len; _i++) {
- configuration = testConfigurations[_i];
- testCorrectEncoding(configuration);
+
+var assert = require('assert')
+var Negotiator = require('..')
+
+describe('negotiator.encoding()', function () {
+ whenAcceptEncoding(undefined, function () {
+ it('should return identity', function () {
+ assert.strictEqual(this.negotiator.encoding(), 'identity')
+ })
+ })
+
+ whenAcceptEncoding('*', function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.encoding(), '*')
+ })
+ })
+
+ whenAcceptEncoding('*, gzip', function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.encoding(), '*')
+ })
+ })
+
+ whenAcceptEncoding('*, gzip;q=0', function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.encoding(), '*')
+ })
+ })
+
+ whenAcceptEncoding('*;q=0', function () {
+ it('should return undefined', function () {
+ assert.strictEqual(this.negotiator.encoding(), undefined)
+ })
+ })
+
+ whenAcceptEncoding('*;q=0, identity;q=1', function () {
+ it('should return identity', function () {
+ assert.strictEqual(this.negotiator.encoding(), 'identity')
+ })
+ })
+
+ whenAcceptEncoding('identity', function () {
+ it('should return identity', function () {
+ assert.strictEqual(this.negotiator.encoding(), 'identity')
+ })
+ })
+
+ whenAcceptEncoding('identity;q=0', function () {
+ it('should return undefined', function () {
+ assert.strictEqual(this.negotiator.encoding(), undefined)
+ })
+ })
+
+ whenAcceptEncoding('gzip', function () {
+ it('should return gzip', function () {
+ assert.strictEqual(this.negotiator.encoding(), 'gzip')
+ })
+ })
+
+ whenAcceptEncoding('gzip, compress;q=0', function () {
+ it('should return gzip', function () {
+ assert.strictEqual(this.negotiator.encoding(), 'gzip')
+ })
+ })
+
+ whenAcceptEncoding('gzip, deflate', function () {
+ it('should return gzip', function () {
+ assert.strictEqual(this.negotiator.encoding(), 'gzip')
+ })
+ })
+
+ whenAcceptEncoding('gzip;q=0.8, deflate', function () {
+ it('should return deflate', function () {
+ assert.strictEqual(this.negotiator.encoding(), 'deflate')
+ })
+ })
+
+ whenAcceptEncoding('gzip;q=0.8, identity;q=0.5, *;q=0.3', function () {
+ it('should return gzip', function () {
+ assert.strictEqual(this.negotiator.encoding(), 'gzip')
+ })
+ })
+})
+
+describe('negotiator.encoding(array)', function () {
+ whenAcceptEncoding(undefined, function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.encoding([]), undefined)
+ })
+
+ it('should only match identity', function () {
+ assert.strictEqual(this.negotiator.encoding(['identity']), 'identity')
+ assert.strictEqual(this.negotiator.encoding(['gzip']), undefined)
+ })
+ })
+
+ whenAcceptEncoding('*', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.encoding([]), undefined)
+ })
+
+ it('should return first item in list', function () {
+ assert.strictEqual(this.negotiator.encoding(['identity']), 'identity')
+ assert.strictEqual(this.negotiator.encoding(['gzip']), 'gzip')
+ assert.strictEqual(this.negotiator.encoding(['gzip', 'identity']), 'gzip')
+ })
+ })
+
+ whenAcceptEncoding('*, gzip', function () {
+ it('should prefer gzip', function () {
+ assert.strictEqual(this.negotiator.encoding(['identity']), 'identity')
+ assert.strictEqual(this.negotiator.encoding(['gzip']), 'gzip')
+ assert.strictEqual(this.negotiator.encoding(['compress', 'gzip']), 'gzip')
+ })
+ })
+
+ whenAcceptEncoding('*, gzip;q=0', function () {
+ it('should exclude gzip', function () {
+ assert.strictEqual(this.negotiator.encoding(['identity']), 'identity')
+ assert.strictEqual(this.negotiator.encoding(['gzip']), undefined)
+ assert.strictEqual(this.negotiator.encoding(['gzip', 'compress']), 'compress')
+ })
+ })
+
+ whenAcceptEncoding('*;q=0', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.encoding([]), undefined)
+ })
+
+ it('should match nothing', function () {
+ assert.strictEqual(this.negotiator.encoding(['identity']), undefined)
+ assert.strictEqual(this.negotiator.encoding(['gzip']), undefined)
+ })
+ })
+
+ whenAcceptEncoding('*;q=0, identity;q=1', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.encoding([]), undefined)
+ })
+
+ it('should still match identity', function () {
+ assert.strictEqual(this.negotiator.encoding(['identity']), 'identity')
+ assert.strictEqual(this.negotiator.encoding(['gzip']), undefined)
+ })
+ })
+
+ whenAcceptEncoding('identity', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.encoding([]), undefined)
+ })
+
+ it('should only match identity', function () {
+ assert.strictEqual(this.negotiator.encoding(['identity']), 'identity')
+ assert.strictEqual(this.negotiator.encoding(['gzip']), undefined)
+ })
+ })
+
+ whenAcceptEncoding('identity;q=0', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.encoding([]), undefined)
+ })
+
+ it('should match nothing', function () {
+ assert.strictEqual(this.negotiator.encoding(['identity']), undefined)
+ assert.strictEqual(this.negotiator.encoding(['gzip']), undefined)
+ })
+ })
+
+ whenAcceptEncoding('gzip', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.encoding([]), undefined)
+ })
+
+ it('should return client-preferred encodings', function () {
+ assert.strictEqual(this.negotiator.encoding(['gzip']), 'gzip')
+ assert.strictEqual(this.negotiator.encoding(['identity', 'gzip']), 'gzip')
+ assert.strictEqual(this.negotiator.encoding(['identity']), 'identity')
+ })
+ })
+
+ whenAcceptEncoding('gzip, compress;q=0', function () {
+ it('should not return compress', function () {
+ assert.strictEqual(this.negotiator.encoding(['compress']), undefined)
+ assert.strictEqual(this.negotiator.encoding(['deflate', 'compress']), undefined)
+ assert.strictEqual(this.negotiator.encoding(['gzip', 'compress']), 'gzip')
+ })
+ })
+
+ whenAcceptEncoding('gzip, deflate', function () {
+ it('should return first client-preferred encoding', function () {
+ assert.strictEqual(this.negotiator.encoding(['deflate', 'compress']), 'deflate')
+ })
+ })
+
+ whenAcceptEncoding('gzip;q=0.8, deflate', function () {
+ it('should return most client-preferred encoding', function () {
+ assert.strictEqual(this.negotiator.encoding(['gzip']), 'gzip')
+ assert.strictEqual(this.negotiator.encoding(['deflate']), 'deflate')
+ assert.strictEqual(this.negotiator.encoding(['deflate', 'gzip']), 'deflate')
+ })
+ })
+
+ whenAcceptEncoding('gzip;q=0.8, identity;q=0.5, *;q=0.3', function () {
+ it('should return most client-preferred encoding', function () {
+ assert.strictEqual(this.negotiator.encoding(['gzip']), 'gzip')
+ assert.strictEqual(this.negotiator.encoding(['compress', 'identity']), 'identity')
+ })
+ })
+})
+
+describe('negotiator.encodings()', function () {
+ whenAcceptEncoding(undefined, function () {
+ it('should return identity', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['identity'])
+ })
+ })
+
+ whenAcceptEncoding('*', function () {
+ it('should return *', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['*'])
+ })
+ })
+
+ whenAcceptEncoding('*, gzip', function () {
+ it('should prefer gzip', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['*', 'gzip'])
+ })
+ })
+
+ whenAcceptEncoding('*, gzip;q=0', function () {
+ it('should return *', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['*'])
+ })
+ })
+
+ whenAcceptEncoding('*;q=0', function () {
+ it('should return an empty list', function () {
+ assert.deepEqual(this.negotiator.encodings(), [])
+ })
+ })
+
+ whenAcceptEncoding('*;q=0, identity;q=1', function () {
+ it('should return identity', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['identity'])
+ })
+ })
+
+ whenAcceptEncoding('identity', function () {
+ it('should return identity', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['identity'])
+ })
+ })
+
+ whenAcceptEncoding('identity;q=0', function () {
+ it('should return an empty list', function () {
+ assert.deepEqual(this.negotiator.encodings(), [])
+ })
+ })
+
+ whenAcceptEncoding('gzip', function () {
+ it('should return gzip, identity', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['gzip', 'identity'])
+ })
+ })
+
+ whenAcceptEncoding('gzip, compress;q=0', function () {
+ it('should not return compress', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['gzip', 'identity'])
+ })
+ })
+
+ whenAcceptEncoding('gzip, deflate', function () {
+ it('should return client-preferred encodings', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['gzip', 'deflate', 'identity'])
+ })
+ })
+
+ whenAcceptEncoding('gzip;q=0.8, deflate', function () {
+ it('should return client-preferred encodings', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['deflate', 'gzip', 'identity'])
+ })
+ })
+
+ whenAcceptEncoding('gzip;q=0.8, identity;q=0.5, *;q=0.3', function () {
+ it('should return client-preferred encodings', function () {
+ assert.deepEqual(this.negotiator.encodings(), ['gzip', 'identity', '*'])
+ })
+ })
+})
+
+describe('negotiator.encodings(array)', function () {
+ whenAcceptEncoding(undefined, function () {
+ it('should return empty list for empty list', function () {
+ assert.deepEqual(this.negotiator.encodings([]), [])
+ })
+
+ it('should only match identity', function () {
+ assert.deepEqual(this.negotiator.encodings(['identity']), ['identity'])
+ assert.deepEqual(this.negotiator.encodings(['gzip']), [])
+ })
+ })
+
+ whenAcceptEncoding('*', function () {
+ it('should return empty list for empty list', function () {
+ assert.deepEqual(this.negotiator.encodings([]), [])
+ })
+
+ it('should return original list', function () {
+ assert.deepEqual(this.negotiator.encodings(['identity']), ['identity'])
+ assert.deepEqual(this.negotiator.encodings(['gzip']), ['gzip'])
+ assert.deepEqual(this.negotiator.encodings(['gzip', 'identity']), ['gzip', 'identity'])
+ })
+ })
+
+ whenAcceptEncoding('*, gzip', function () {
+ it('should prefer gzip', function () {
+ assert.deepEqual(this.negotiator.encodings(['identity']), ['identity'])
+ assert.deepEqual(this.negotiator.encodings(['gzip']), ['gzip'])
+ assert.deepEqual(this.negotiator.encodings(['compress', 'gzip']), ['gzip', 'compress'])
+ })
+ })
+
+ whenAcceptEncoding('*, gzip;q=0', function () {
+ it('should exclude gzip', function () {
+ assert.deepEqual(this.negotiator.encodings(['identity']), ['identity'])
+ assert.deepEqual(this.negotiator.encodings(['gzip']), [])
+ assert.deepEqual(this.negotiator.encodings(['gzip', 'compress']), ['compress'])
+ })
+ })
+
+ whenAcceptEncoding('*;q=0', function () {
+ it('should always return empty list', function () {
+ assert.deepEqual(this.negotiator.encodings([]), [])
+ assert.deepEqual(this.negotiator.encodings(['identity']), [])
+ assert.deepEqual(this.negotiator.encodings(['gzip']), [])
+ })
+ })
+
+ whenAcceptEncoding('*;q=0, identity;q=1', function () {
+ it('should still match identity', function () {
+ assert.deepEqual(this.negotiator.encodings([]), [])
+ assert.deepEqual(this.negotiator.encodings(['identity']), ['identity'])
+ assert.deepEqual(this.negotiator.encodings(['gzip']), [])
+ })
+ })
+
+ whenAcceptEncoding('identity', function () {
+ it('should return empty list for empty list', function () {
+ assert.deepEqual(this.negotiator.encodings([]), [])
+ })
+
+ it('should only match identity', function () {
+ assert.deepEqual(this.negotiator.encodings(['identity']), ['identity'])
+ assert.deepEqual(this.negotiator.encodings(['gzip']), [])
+ })
+ })
+
+ whenAcceptEncoding('identity;q=0', function () {
+ it('should always return empty list', function () {
+ assert.deepEqual(this.negotiator.encodings([]), [])
+ assert.deepEqual(this.negotiator.encodings(['identity']), [])
+ assert.deepEqual(this.negotiator.encodings(['gzip']), [])
+ })
+ })
+
+ whenAcceptEncoding('gzip', function () {
+ it('should return empty list for empty list', function () {
+ assert.deepEqual(this.negotiator.encodings([]), [])
+ })
+
+ it('should be case insensitive, returning provided casing', function () {
+ assert.deepEqual(this.negotiator.encodings(['GZIP']), ['GZIP'])
+ assert.deepEqual(this.negotiator.encodings(['gzip', 'GZIP']), ['gzip', 'GZIP'])
+ assert.deepEqual(this.negotiator.encodings(['GZIP', 'gzip']), ['GZIP', 'gzip'])
+ })
+
+ it('should return client-preferred encodings', function () {
+ assert.deepEqual(this.negotiator.encodings(['gzip']), ['gzip'])
+ assert.deepEqual(this.negotiator.encodings(['gzip', 'identity']), ['gzip', 'identity'])
+ assert.deepEqual(this.negotiator.encodings(['identity', 'gzip']), ['gzip', 'identity'])
+ assert.deepEqual(this.negotiator.encodings(['identity']), ['identity'])
+ })
+ })
+
+ whenAcceptEncoding('gzip, compress;q=0', function () {
+ it('should not return compress', function () {
+ assert.deepEqual(this.negotiator.encodings(['gzip', 'compress']), ['gzip'])
+ })
+ })
+
+ whenAcceptEncoding('gzip, deflate', function () {
+ it('should return client-preferred encodings', function () {
+ assert.deepEqual(this.negotiator.encodings(['gzip']), ['gzip'])
+ assert.deepEqual(this.negotiator.encodings(['gzip', 'identity']), ['gzip', 'identity'])
+ assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip']), ['gzip', 'deflate'])
+ assert.deepEqual(this.negotiator.encodings(['identity']), ['identity'])
+ })
+ })
+
+ whenAcceptEncoding('gzip;q=0.8, deflate', function () {
+ it('should return client-preferred encodings', function () {
+ assert.deepEqual(this.negotiator.encodings(['gzip']), ['gzip'])
+ assert.deepEqual(this.negotiator.encodings(['deflate']), ['deflate'])
+ assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip']), ['deflate', 'gzip'])
+ })
+ })
+
+ whenAcceptEncoding('gzip;q=0.8, identity;q=0.5, *;q=0.3', function () {
+ it('should return client-preferred encodings', function () {
+ assert.deepEqual(this.negotiator.encodings(['gzip']), ['gzip'])
+ assert.deepEqual(this.negotiator.encodings(['identity', 'gzip', 'compress']), ['gzip', 'identity', 'compress'])
+ })
+ })
+})
+
+function createRequest(headers) {
+ var request = {
+ headers: {}
+ }
+
+ if (headers) {
+ Object.keys(headers).forEach(function (key) {
+ request.headers[key.toLowerCase()] = headers[key]
+ })
}
-}).call(this);
+ return request
+}
+
+function whenAcceptEncoding(acceptEncoding, func) {
+ var description = !acceptEncoding
+ ? 'when no Accept-Encoding'
+ : 'when Accept-Encoding: ' + acceptEncoding
+
+ describe(description, function () {
+ before(function () {
+ this.negotiator = new Negotiator(createRequest({'Accept-Encoding': acceptEncoding}))
+ })
+
+ func()
+ })
+}
diff --git a/test/language.js b/test/language.js
index 5aad2a9..640c78b 100644
--- a/test/language.js
+++ b/test/language.js
@@ -1,110 +1,425 @@
-(function() {
- var configuration, preferredLanguages, testConfigurations, testCorrectType, _i, _len,
- _this = this;
-
- preferredLanguages = require('../lib/language').preferredLanguages;
-
- this["Should return list of languages in order"] = function(test) {
- test.deepEqual(preferredLanguages('nl;q=0.5,fr,de,en,it,es,pt,no,se,fi'), ['fr', 'de', 'en', 'it', 'es', 'pt', 'no', 'se', 'fi', 'nl']);
- return test.done();
- };
-
- this["Should return list of languages in order (large list)"] = function(test) {
- test.deepEqual(preferredLanguages('nl;q=0.5,fr,de,en,it,es,pt,no,se,fi,ro'), ['fr', 'de', 'en', 'it', 'es', 'pt', 'no', 'se', 'fi', 'ro', 'nl']);
- return test.done();
- };
-
- this["Should return list of languages"] = function(test) {
- test.deepEqual(preferredLanguages('nl;q=0.5,fr,de,en,it,es,pt,no,se,fi'), ['fr', 'de', 'en', 'it', 'es', 'pt', 'no', 'se', 'fi', 'nl']);
- return test.done();
- };
-
- this["Should not return a language when no is provided"] = function(test) {
- test.deepEqual(preferredLanguages('*', []), []);
- return test.done();
- };
-
- this["Should not return a language when no language is acceptable"] = function(test) {
- test.deepEqual(preferredLanguages('en', ['es']), []);
- return test.done();
- };
-
- this["Should not return a language with q = 0"] = function(test) {
- test.deepEqual(preferredLanguages('en;q=0', ['en']), []);
- return test.done();
- };
-
- this["Should be case insensitive"] = function(test) {
- test.deepEqual(preferredLanguages('en-us', ['en-US']), ['en-US']);
- return test.done();
- };
-
- testCorrectType = function(c) {
- return _this["Should return " + c.selected + " for accept-language header " + c.accept + " with provided language " + c.provided] = function(test) {
- test.deepEqual(preferredLanguages(c.accept, c.provided), c.selected);
- return test.done();
- };
- };
-
- testConfigurations = [
- {
- accept: undefined,
- provided: ['en'],
- selected: ['en']
- }, {
- accept: 'en',
- provided: ['en'],
- selected: ['en']
- }, {
- accept: '*',
- provided: ['en'],
- selected: ['en']
- }, {
- accept: 'en-US, en;q=0.8',
- provided: ['en-US', 'en-GB'],
- selected: ['en-US', 'en-GB']
- }, {
- accept: 'en-US, en-GB',
- provided: ['en-US'],
- selected: ['en-US']
- }, {
- accept: 'en',
- provided: ['en-US'],
- selected: ['en-US']
- }, {
- accept: 'en;q=0.8, es',
- provided: ['en', 'es'],
- selected: ['es', 'en']
- }, {
- accept: 'en-US;q=0.8, es',
- provided: ['en', 'es'],
- selected: ['es', 'en']
- }, {
- accept: '*, en;q=0',
- provided: ['en', 'es'],
- selected: ['es']
- }, {
- accept: 'en-US;q=0.8, es',
- provided: null,
- selected: ['es', 'en-US']
- }, {
- accept: '*, en',
- provided: ['es', 'en'],
- selected: ['en', 'es']
- }, {
- accept: 'en',
- provided: ['en', ''],
- selected: ['en']
- }, {
- accept: 'en;q=0.9, es;q=0.8, en;q=0.7',
- provided: ['en', 'es'],
- selected: ['en', 'es']
- }
- ];
-
- for (_i = 0, _len = testConfigurations.length; _i < _len; _i++) {
- configuration = testConfigurations[_i];
- testCorrectType(configuration);
+
+var assert = require('assert')
+var Negotiator = require('..')
+
+describe('negotiator.language()', function () {
+ whenAcceptLanguage(undefined, function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.language(), '*')
+ })
+ })
+
+ whenAcceptLanguage('*', function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.language(), '*')
+ })
+ })
+
+ whenAcceptLanguage('*, en', function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.language(), '*')
+ })
+ })
+
+ whenAcceptLanguage('*, en;q=0', function () {
+ it('should return *', function () {
+ assert.strictEqual(this.negotiator.language(), '*')
+ })
+ })
+
+ whenAcceptLanguage('*;q=0.8, en, es', function () {
+ it('should return en', function () {
+ assert.deepEqual(this.negotiator.language(), 'en')
+ })
+ })
+
+ whenAcceptLanguage('en', function () {
+ it('should en', function () {
+ assert.strictEqual(this.negotiator.language(), 'en')
+ })
+ })
+
+ whenAcceptLanguage('en;q=0', function () {
+ it('should return undefined', function () {
+ assert.strictEqual(this.negotiator.language(), undefined)
+ })
+ })
+
+ whenAcceptLanguage('en;q=0.8, es', function () {
+ it('should return es', function () {
+ assert.strictEqual(this.negotiator.language(), 'es')
+ })
+ })
+
+ whenAcceptLanguage('en;q=0.9, es;q=0.8, en;q=0.7', function () {
+ it('should return en', function () {
+ assert.strictEqual(this.negotiator.language(), 'en')
+ })
+ })
+
+ whenAcceptLanguage('en-US, en;q=0.8', function () {
+ it('should return en-US', function () {
+ assert.strictEqual(this.negotiator.language(), 'en-US')
+ })
+ })
+
+ whenAcceptLanguage('en-US, en-GB', function () {
+ it('should return en-US', function () {
+ assert.deepEqual(this.negotiator.language(), 'en-US')
+ })
+ })
+
+ whenAcceptLanguage('en-US;q=0.8, es', function () {
+ it('should return es', function () {
+ assert.strictEqual(this.negotiator.language(), 'es')
+ })
+ })
+
+ whenAcceptLanguage('nl;q=0.5, fr, de, en, it, es, pt, no, se, fi, ro', function () {
+ it('should return fr', function () {
+ assert.strictEqual(this.negotiator.language(), 'fr')
+ })
+ })
+})
+
+describe('negotiator.language(array)', function () {
+ whenAcceptLanguage(undefined, function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.language([]), undefined)
+ })
+
+ it('should return first language in list', function () {
+ assert.strictEqual(this.negotiator.language(['en']), 'en')
+ assert.strictEqual(this.negotiator.language(['es', 'en']), 'es')
+ })
+ })
+
+ whenAcceptLanguage('*', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.language([]), undefined)
+ })
+
+ it('should return first language in list', function () {
+ assert.strictEqual(this.negotiator.language(['en']), 'en')
+ assert.strictEqual(this.negotiator.language(['es', 'en']), 'es')
+ })
+ })
+
+ whenAcceptLanguage('*, en', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.language([]), undefined)
+ })
+
+ it('should return most preferred language', function () {
+ assert.strictEqual(this.negotiator.language(['en']), 'en')
+ assert.strictEqual(this.negotiator.language(['es', 'en']), 'en')
+ })
+ })
+
+ whenAcceptLanguage('*, en;q=0', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.language([]), undefined)
+ })
+
+ it('should exclude en', function () {
+ assert.strictEqual(this.negotiator.language(['en']), undefined)
+ assert.strictEqual(this.negotiator.language(['es', 'en']), 'es')
+ })
+ })
+
+ whenAcceptLanguage('*;q=0.8, en, es', function () {
+ it('should prefer en and es over everything', function () {
+ assert.deepEqual(this.negotiator.language(['en', 'nl']), 'en')
+ assert.deepEqual(this.negotiator.language(['ro', 'nl']), 'ro')
+ })
+ })
+
+ whenAcceptLanguage('en', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.language([]), undefined)
+ })
+
+ it('should return preferred langauge', function () {
+ assert.strictEqual(this.negotiator.language(['en']), 'en')
+ assert.strictEqual(this.negotiator.language(['es', 'en']), 'en')
+ })
+
+ it('should accept en-US, preferring en over en-US', function () {
+ assert.strictEqual(this.negotiator.language(['en-US']), 'en-US')
+ assert.strictEqual(this.negotiator.language(['en-US', 'en']), 'en')
+ assert.strictEqual(this.negotiator.language(['en', 'en-US']), 'en')
+ })
+ })
+
+ whenAcceptLanguage('en;q=0', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.language([]), undefined)
+ })
+
+ it('should return preferred langauge', function () {
+ assert.strictEqual(this.negotiator.language(['es', 'en']), undefined)
+ })
+ })
+
+ whenAcceptLanguage('en;q=0.8, es', function () {
+ it('should return undefined for empty list', function () {
+ assert.strictEqual(this.negotiator.language([]), undefined)
+ })
+
+ it('should return preferred langauge', function () {
+ assert.strictEqual(this.negotiator.language(['en']), 'en')
+ assert.strictEqual(this.negotiator.language(['en', 'es']), 'es')
+ })
+ })
+
+ whenAcceptLanguage('en;q=0.9, es;q=0.8, en;q=0.7', function () {
+ it('should use highest perferred order on duplicate', function () {
+ assert.strictEqual(this.negotiator.language(['es']), 'es')
+ assert.strictEqual(this.negotiator.language(['en', 'es']), 'en')
+ assert.strictEqual(this.negotiator.language(['es', 'en']), 'en')
+ })
+ })
+
+ whenAcceptLanguage('en-US, en;q=0.8', function () {
+ it('should use prefer en-US over en', function () {
+ assert.strictEqual(this.negotiator.language(['en', 'en-US']), 'en-US')
+ assert.strictEqual(this.negotiator.language(['en-GB', 'en-US']), 'en-US')
+ assert.strictEqual(this.negotiator.language(['en-GB', 'es']), 'en-GB')
+ })
+ })
+
+ whenAcceptLanguage('en-US, en-GB', function () {
+ it('should prefer en-US', function () {
+ assert.deepEqual(this.negotiator.language(['en-US', 'en-GB']), 'en-US')
+ assert.deepEqual(this.negotiator.language(['en-GB', 'en-US']), 'en-US')
+ })
+ })
+
+ whenAcceptLanguage('en-US;q=0.8, es', function () {
+ it('should prefer es over en-US', function () {
+ assert.strictEqual(this.negotiator.language(['es', 'en-US']), 'es')
+ assert.strictEqual(this.negotiator.language(['en-US', 'es']), 'es')
+ assert.strictEqual(this.negotiator.language(['en-US', 'en']), 'en-US')
+ })
+ })
+
+ whenAcceptLanguage('nl;q=0.5, fr, de, en, it, es, pt, no, se, fi, ro', function () {
+ it('should use prefer fr over nl', function () {
+ assert.strictEqual(this.negotiator.language(['nl', 'fr']), 'fr')
+ })
+ })
+})
+
+describe('negotiator.languages()', function () {
+ whenAcceptLanguage(undefined, function () {
+ it('should return *', function () {
+ assert.deepEqual(this.negotiator.languages(), ['*'])
+ })
+ })
+
+ whenAcceptLanguage('*', function () {
+ it('should return *', function () {
+ assert.deepEqual(this.negotiator.languages(), ['*'])
+ })
+ })
+
+ whenAcceptLanguage('*, en', function () {
+ it('should return *, en', function () {
+ assert.deepEqual(this.negotiator.languages(), ['*', 'en'])
+ })
+ })
+
+ whenAcceptLanguage('*, en;q=0', function () {
+ it('should return *', function () {
+ assert.deepEqual(this.negotiator.languages(), ['*'])
+ })
+ })
+
+ whenAcceptLanguage('*;q=0.8, en, es', function () {
+ it('should return preferred languages', function () {
+ assert.deepEqual(this.negotiator.languages(), ['en', 'es', '*'])
+ })
+ })
+
+ whenAcceptLanguage('en', function () {
+ it('should return preferred languages', function () {
+ assert.deepEqual(this.negotiator.languages(), ['en'])
+ })
+ })
+
+ whenAcceptLanguage('en;q=0', function () {
+ it('should return empty list', function () {
+ assert.deepEqual(this.negotiator.languages(), [])
+ })
+ })
+
+ whenAcceptLanguage('en;q=0.8, es', function () {
+ it('should return preferred languages', function () {
+ assert.deepEqual(this.negotiator.languages(), ['es', 'en'])
+ })
+ })
+
+ whenAcceptLanguage('en;q=0.9, es;q=0.8, en;q=0.7', function () {
+ it.skip('should use highest perferred order on duplicate', function () {
+ assert.deepEqual(this.negotiator.languages(), ['en', 'es'])
+ })
+ })
+
+ whenAcceptLanguage('en-US, en;q=0.8', function () {
+ it('should return en-US, en', function () {
+ assert.deepEqual(this.negotiator.languages(), ['en-US', 'en'])
+ })
+ })
+
+ whenAcceptLanguage('en-US, en-GB', function () {
+ it('should return en-US, en-GB', function () {
+ assert.deepEqual(this.negotiator.languages(), ['en-US', 'en-GB'])
+ })
+ })
+
+ whenAcceptLanguage('en-US;q=0.8, es', function () {
+ it('should return es, en-US', function () {
+ assert.deepEqual(this.negotiator.languages(), ['es', 'en-US'])
+ })
+ })
+
+ whenAcceptLanguage('nl;q=0.5, fr, de, en, it, es, pt, no, se, fi, ro', function () {
+ it('should use prefer fr over nl', function () {
+ assert.deepEqual(this.negotiator.languages(), ['fr', 'de', 'en', 'it', 'es', 'pt', 'no', 'se', 'fi', 'ro', 'nl'])
+ })
+ })
+})
+
+describe('negotiator.languages(array)', function () {
+ whenAcceptLanguage(undefined, function () {
+ it('should return original list', function () {
+ assert.deepEqual(this.negotiator.languages(['en']), ['en'])
+ assert.deepEqual(this.negotiator.languages(['es', 'en']), ['es', 'en'])
+ })
+ })
+
+ whenAcceptLanguage('*', function () {
+ it('should return original list', function () {
+ assert.deepEqual(this.negotiator.languages(['en']), ['en'])
+ assert.deepEqual(this.negotiator.languages(['es', 'en']), ['es', 'en'])
+ })
+ })
+
+ whenAcceptLanguage('*, en', function () {
+ it('should return list in client-preferred order', function () {
+ assert.deepEqual(this.negotiator.languages(['en']), ['en'])
+ assert.deepEqual(this.negotiator.languages(['es', 'en']), ['en', 'es'])
+ })
+ })
+
+ whenAcceptLanguage('*, en;q=0', function () {
+ it('should exclude en', function () {
+ assert.deepEqual(this.negotiator.languages(['en']), [])
+ assert.deepEqual(this.negotiator.languages(['es', 'en']), ['es'])
+ })
+ })
+
+ whenAcceptLanguage('*;q=0.8, en, es', function () {
+ it('should return preferred languages', function () {
+ assert.deepEqual(this.negotiator.languages(['fr', 'de', 'en', 'it', 'es', 'pt', 'no', 'se', 'fi', 'ro', 'nl']),
+ ['en', 'es', 'fr', 'de', 'it', 'pt', 'no', 'se', 'fi', 'ro', 'nl'])
+ })
+ })
+
+ whenAcceptLanguage('en', function () {
+ it('should return preferred languages', function () {
+ assert.deepEqual(this.negotiator.languages(['en']), ['en'])
+ assert.deepEqual(this.negotiator.languages(['en', 'es']), ['en'])
+ assert.deepEqual(this.negotiator.languages(['es', 'en']), ['en'])
+ })
+
+ it('should accept en-US, preferring en over en-US', function () {
+ assert.deepEqual(this.negotiator.languages(['en-US']), ['en-US'])
+ assert.deepEqual(this.negotiator.languages(['en-US', 'en']), ['en', 'en-US'])
+ assert.deepEqual(this.negotiator.languages(['en', 'en-US']), ['en', 'en-US'])
+ })
+ })
+
+ whenAcceptLanguage('en;q=0', function () {
+ it('should return nothing', function () {
+ assert.deepEqual(this.negotiator.languages(['en']), [])
+ assert.deepEqual(this.negotiator.languages(['en', 'es']), [])
+ })
+ })
+
+ whenAcceptLanguage('en;q=0.8, es', function () {
+ it('should return preferred languages', function () {
+ assert.deepEqual(this.negotiator.languages(['en']), ['en'])
+ assert.deepEqual(this.negotiator.languages(['en', 'es']), ['es', 'en'])
+ assert.deepEqual(this.negotiator.languages(['es', 'en']), ['es', 'en'])
+ })
+ })
+
+ whenAcceptLanguage('en;q=0.9, es;q=0.8, en;q=0.7', function () {
+ it.skip('should return preferred languages', function () {
+ assert.deepEqual(this.negotiator.languages(['en']), ['en'])
+ assert.deepEqual(this.negotiator.languages(['en', 'es']), ['es', 'en'])
+ assert.deepEqual(this.negotiator.languages(['es', 'en']), ['es', 'en'])
+ })
+ })
+
+ whenAcceptLanguage('en-US, en;q=0.8', function () {
+ it('should be case insensitive', function () {
+ assert.deepEqual(this.negotiator.languages(['en-us', 'EN']), ['en-us', 'EN'])
+ })
+
+ it('should prefer en-US over en', function () {
+ assert.deepEqual(this.negotiator.languages(['en-US', 'en']), ['en-US', 'en'])
+ assert.deepEqual(this.negotiator.languages(['en-GB', 'en-US', 'en']), ['en-US', 'en', 'en-GB'])
+ })
+ })
+
+ whenAcceptLanguage('en-US, en-GB', function () {
+ it('should prefer en-US over en-GB', function () {
+ assert.deepEqual(this.negotiator.languages(['en-US', 'en-GB']), ['en-US', 'en-GB'])
+ assert.deepEqual(this.negotiator.languages(['en-GB', 'en-US']), ['en-US', 'en-GB'])
+ })
+ })
+
+ whenAcceptLanguage('en-US;q=0.8, es', function () {
+ it('should prefer es over en-US', function () {
+ assert.deepEqual(this.negotiator.languages(['en', 'es']), ['es', 'en'])
+ assert.deepEqual(this.negotiator.languages(['en', 'es', 'en-US']), ['es', 'en-US', 'en'])
+ })
+ })
+
+ whenAcceptLanguage('nl;q=0.5, fr, de, en, it, es, pt, no, se, fi, ro', function () {
+ it('should return preferred languages', function () {
+ assert.deepEqual(this.negotiator.languages(['fr', 'de', 'en', 'it', 'es', 'pt', 'no', 'se', 'fi', 'ro', 'nl']),
+ ['fr', 'de', 'en', 'it', 'es', 'pt', 'no', 'se', 'fi', 'ro', 'nl'])
+ })
+ })
+})
+
+function createRequest(headers) {
+ var request = {
+ headers: {}
+ }
+
+ if (headers) {
+ Object.keys(headers).forEach(function (key) {
+ request.headers[key.toLowerCase()] = headers[key]
+ })
}
-}).call(this);
+ return request
+}
+
+function whenAcceptLanguage(acceptLanguage, func) {
+ var description = !acceptLanguage
+ ? 'when no Accept-Language'
+ : 'when Accept-Language: ' + acceptLanguage
+
+ describe(description, function () {
+ before(function () {
+ this.negotiator = new Negotiator(createRequest({'Accept-Language': acceptLanguage}))
+ })
+
+ func()
+ })
+}
diff --git a/test/mediaType.js b/test/mediaType.js
index 6cf0795..8365be7 100644
--- a/test/mediaType.js
+++ b/test/mediaType.js
@@ -1,140 +1,499 @@
-(function() {
- var configuration, preferredMediaTypes, testConfigurations, testCorrectType, _i, _len,
- _this = this;
-
- preferredMediaTypes = require('../lib/mediaType').preferredMediaTypes;
-
- this["Should not return a media type when no media type provided"] = function(test) {
- test.deepEqual(preferredMediaTypes('*/*', []), []);
- return test.done();
- };
-
- this["Should not return a media type when no media type is acceptable"] = function(test) {
- test.deepEqual(preferredMediaTypes('application/json', ['text/html']), []);
- return test.done();
- };
-
- this["Should not return a media type with q = 0"] = function(test) {
- test.deepEqual(preferredMediaTypes('text/html;q=0', ['text/html']), []);
- return test.done();
- };
-
- this["Should handle extra slashes on query params"] = function(test) {
- var type = 'application/xhtml+xml;profile="http://www.wapforum.org/xhtml"'
- test.deepEqual(preferredMediaTypes(type, ['application/xhtml+xml;profile="http://www.wapforum.org/xhtml"']), ['application/xhtml+xml;profile="http://www.wapforum.org/xhtml"']);
-
- return test.done();
- };
-
- this["Should be case insensitive"] = function(test) {
- test.deepEqual(preferredMediaTypes('application/JSON', ['application/json']), ['application/json']);
- return test.done();
- };
-
-
- testCorrectType = function(c) {
- return _this["Should return " + c.selected + " for access header " + c.accept + " with provided types " + c.provided] = function(test) {
- test.deepEqual(preferredMediaTypes(c.accept, c.provided), c.selected);
- return test.done();
- };
- };
-
- testConfigurations = [
- {
- accept: undefined,
- provided: ['text/html'],
- selected: ['text/html']
- }, {
- accept: 'text/html',
- provided: ['text/html'],
- selected: ['text/html']
- }, {
- accept: '*/*',
- provided: ['text/html'],
- selected: ['text/html']
- }, {
- accept: 'text/*',
- provided: ['text/html'],
- selected: ['text/html']
- }, {
- accept: 'application/json, text/html',
- provided: ['text/html'],
- selected: ['text/html']
- }, {
- accept: 'text/html;q=0.1',
- provided: ['text/html'],
- selected: ['text/html']
- }, {
- accept: 'application/json, text/html',
- provided: ['application/json', 'text/html'],
- selected: ['application/json', 'text/html']
- }, {
- accept: 'application/json;q=0.2, text/html',
- provided: ['application/json', 'text/html'],
- selected: ['text/html', 'application/json']
- }, {
- accept: 'application/json;q=0.2, text/html',
- provided: null,
- selected: ['text/html', 'application/json']
- }, {
- accept: 'text/*, text/html;q=0',
- provided: ['text/html', 'text/plain'],
- selected: ['text/plain']
- }, {
- accept: 'text/*, text/html;q=0.5',
- provided: ['text/html', 'text/plain'],
- selected: ['text/plain', 'text/html']
- }, {
- accept: 'application/json, */*; q=0.01',
- provided: ['text/html', 'application/json'],
- selected: ['application/json', 'text/html']
- }, {
- accept: 'application/vnd.example;attribute=value',
- provided: ['application/vnd.example;attribute=other', 'application/vnd.example;attribute=value'],
- selected: ['application/vnd.example;attribute=value']
- }, {
- accept: 'application/vnd.example;attribute=other',
- provided: ['application/vnd.example', 'application/vnd.example;attribute=other'],
- selected: ['application/vnd.example;attribute=other']
- }, {
- accept: 'text/html;level=1',
- provided: ['text/html;level=1;foo=bar'],
- selected: ['text/html;level=1;foo=bar']
- }, {
- accept: 'text/html;level=1;foo=bar',
- provided: ['text/html;level=1'],
- selected: []
- }, {
- accept: 'text/html;level=2',
- provided: ['text/html;level=1'],
- selected: []
- }, {
- accept : 'text/html, text/html;level=1;q=0.1',
- provided : ['text/html', 'text/html;level=1'],
- selected : ['text/html', 'text/html;level=1']
- }, {
- accept : 'text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5',
- provided : ['text/html;level=1', 'text/html', 'text/html;level=3', 'image/jpeg', 'text/html;level=2', 'text/plain'],
- selected : ['text/html;level=1', 'text/html', 'text/html;level=3', 'image/jpeg', 'text/html;level=2', 'text/plain']
- }, {
- accept : 'text/html, application/xhtml+xml, */*',
- provided : ['application/json', 'text/html'],
- selected : ['text/html', 'application/json' ]
- }, {
- accept : 'text/html, application/json',
- provided : ['text/html', 'boom'],
- selected : ['text/html']
- }, {
- accept: 'application/json;q=0.9, text/html;q=0.8, application/json;q=0.7',
- provided: ['application/json', 'text/html'],
- selected: ['application/json', 'text/html']
- }
-
- ];
-
- for (_i = 0, _len = testConfigurations.length; _i < _len; _i++) {
- configuration = testConfigurations[_i];
- testCorrectType(configuration);
+
+var assert = require('assert')
+var Negotiator = require('..')
+
+describe('negotiator.mediaType()', function () {
+ whenAccept(undefined, function () {
+ it('should return */*', function () {
+ assert.strictEqual(this.negotiator.mediaType(), '*/*')
+ })
+ })
+
+ whenAccept('*/*', function () {
+ it('should return */*', function () {
+ assert.strictEqual(this.negotiator.mediaType(), '*/*')
+ })
+ })
+
+ whenAccept('application/json', function () {
+ it('should return application/json', function () {
+ assert.deepEqual(this.negotiator.mediaType(), 'application/json')
+ })
+ })
+
+ whenAccept('application/json;q=0', function () {
+ it('should return undefined', function () {
+ assert.strictEqual(this.negotiator.mediaType(), undefined)
+ })
+ })
+
+ whenAccept('application/json;q=0.2, text/html', function () {
+ it('should return text/html', function () {
+ assert.deepEqual(this.negotiator.mediaType(), 'text/html')
+ })
+ })
+
+ whenAccept('text/*', function () {
+ it('should return text/*', function () {
+ assert.strictEqual(this.negotiator.mediaType(), 'text/*')
+ })
+ })
+
+ whenAccept('text/plain, application/json;q=0.5, text/html, */*;q=0.1', function () {
+ it('should return text/plain', function () {
+ assert.strictEqual(this.negotiator.mediaType(), 'text/plain')
+ })
+ })
+
+ whenAccept('text/plain, application/json;q=0.5, text/html, text/xml, text/yaml, text/javascript, text/csv, text/css, text/rtf, text/markdown, application/octet-stream;q=0.2, */*;q=0.1', function () {
+ it('should return text/plain', function () {
+ assert.strictEqual(this.negotiator.mediaType(), 'text/plain')
+ })
+ })
+})
+
+describe('negotiator.mediaType(array)', function () {
+ whenAccept(undefined, function () {
+ it('should return first item in list', function () {
+ assert.strictEqual(this.negotiator.mediaType(['text/html']), 'text/html')
+ assert.strictEqual(this.negotiator.mediaType(['text/html', 'application/json']), 'text/html')
+ assert.strictEqual(this.negotiator.mediaType(['application/json', 'text/html']), 'application/json')
+ })
+ })
+
+ whenAccept('*/*', function () {
+ it('should return first item in list', function () {
+ assert.strictEqual(this.negotiator.mediaType(['text/html']), 'text/html')
+ assert.strictEqual(this.negotiator.mediaType(['text/html', 'application/json']), 'text/html')
+ assert.strictEqual(this.negotiator.mediaType(['application/json', 'text/html']), 'application/json')
+ })
+ })
+
+ whenAccept('application/json', function () {
+ it('should be case insensitive', function () {
+ assert.strictEqual(this.negotiator.mediaType(['application/JSON']), 'application/JSON')
+ })
+
+ it('should only return application/json', function () {
+ assert.strictEqual(this.negotiator.mediaType(['text/html']), undefined)
+ assert.strictEqual(this.negotiator.mediaType(['text/html', 'application/json']), 'application/json')
+ })
+ })
+
+ whenAccept('application/json;q=0', function () {
+ it('should return undefined', function () {
+ assert.strictEqual(this.negotiator.mediaType(), undefined)
+ })
+ })
+
+ whenAccept('application/json;q=0.2, text/html', function () {
+ it('should prefer text/html over application/json', function () {
+ assert.strictEqual(this.negotiator.mediaType(['application/json']), 'application/json')
+ assert.strictEqual(this.negotiator.mediaType(['application/json', 'text/html']), 'text/html')
+ assert.strictEqual(this.negotiator.mediaType(['text/html', 'application/json']), 'text/html')
+ })
+ })
+
+ whenAccept('text/*', function () {
+ it('should prefer text media types', function () {
+ assert.strictEqual(this.negotiator.mediaType(['application/json']), undefined)
+ assert.strictEqual(this.negotiator.mediaType(['application/json', 'text/html']), 'text/html')
+ assert.strictEqual(this.negotiator.mediaType(['text/html', 'application/json']), 'text/html')
+ })
+ })
+
+ whenAccept('text/*, text/plain;q=0', function () {
+ it('should prefer text media types', function () {
+ assert.strictEqual(this.negotiator.mediaType(['application/json']), undefined)
+ assert.strictEqual(this.negotiator.mediaType(['application/json', 'text/html']), 'text/html')
+ assert.strictEqual(this.negotiator.mediaType(['text/html', 'application/json']), 'text/html')
+ })
+ })
+
+ whenAccept('text/plain, application/json;q=0.5, text/html, */*;q=0.1', function () {
+ it('should return in preferred order', function () {
+ assert.strictEqual(this.negotiator.mediaType(['application/json', 'text/plain', 'text/html']), 'text/plain')
+ assert.strictEqual(this.negotiator.mediaType(['image/jpeg', 'text/html']), 'text/html')
+ assert.strictEqual(this.negotiator.mediaType(['image/jpeg', 'image/gif']), 'image/jpeg')
+ })
+ })
+
+ whenAccept('text/plain, application/json;q=0.5, text/html, text/xml, text/yaml, text/javascript, text/csv, text/css, text/rtf, text/markdown, application/octet-stream;q=0.2, */*;q=0.1', function () {
+ it('should return the client-preferred order', function () {
+ assert.strictEqual(this.negotiator.mediaType(['text/plain', 'text/html', 'text/xml', 'text/yaml', 'text/javascript', 'text/csv', 'text/css', 'text/rtf', 'text/markdown', 'application/json', 'application/octet-stream']),
+ 'text/plain')
+ })
+ })
+})
+
+describe('negotiator.mediaTypes()', function () {
+ whenAccept(undefined, function () {
+ it('should return */*', function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), ['*/*'])
+ })
+ })
+
+ whenAccept('*/*', function () {
+ it('should return */*', mediaTypesPreferred(
+ ['*/*']
+ ))
+ })
+
+ whenAccept('application/json', function () {
+ it('should return application/json', function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), ['application/json'])
+ })
+ })
+
+ whenAccept('application/json;q=0', function () {
+ it('should return empty list', function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), [])
+ })
+ })
+
+ whenAccept('application/json;q=0.2, text/html', function () {
+ it('should return text/html, application/json', function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), ['text/html', 'application/json'])
+ })
+ })
+
+ whenAccept('text/*', function () {
+ it('should return text/*', function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), ['text/*'])
+ })
+ })
+
+ whenAccept('text/*, text/plain;q=0', function () {
+ it('should return text/*', function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), ['text/*'])
+ })
+ })
+
+ whenAccept('text/html;LEVEL=1', function () {
+ it('should return text/html;LEVEL=1', function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), ['text/html'])
+ })
+ })
+
+ whenAccept('text/html;foo="bar,text/css;";fizz="buzz,5", text/plain', function () {
+ it('should return text/html, text/plain', function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), ['text/html', 'text/plain'])
+ })
+ })
+
+ whenAccept('text/plain, application/json;q=0.5, text/html, */*;q=0.1', function () {
+ it('should return text/plain, text/html, application/json, */*', function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), ['text/plain', 'text/html', 'application/json', '*/*'])
+ })
+ })
+
+ whenAccept('text/plain, application/json;q=0.5, text/html, text/xml, text/yaml, text/javascript, text/csv, text/css, text/rtf, text/markdown, application/octet-stream;q=0.2, */*;q=0.1', function () {
+ it('should return the client-preferred order', function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), ['text/plain', 'text/html', 'text/xml', 'text/yaml', 'text/javascript', 'text/csv', 'text/css', 'text/rtf', 'text/markdown', 'application/json', 'application/octet-stream', '*/*'])
+ })
+ })
+})
+
+describe('negotiator.mediaTypes(array)', function () {
+ whenAccept(undefined, function () {
+ it('should return return original list', mediaTypesNegotiated(
+ ['application/json', 'text/plain'],
+ ['application/json', 'text/plain']
+ ))
+ })
+
+ whenAccept('*/*', function () {
+ it('should return return original list', mediaTypesNegotiated(
+ ['application/json', 'text/plain'],
+ ['application/json', 'text/plain']
+ ))
+ })
+
+ whenAccept('*/*;q=0.8, text/*, image/*', function () {
+ it('should return return stable-sorted list', mediaTypesNegotiated(
+ ['application/json', 'text/html', 'text/plain', 'text/xml', 'application/xml', 'image/gif', 'image/jpeg', 'image/png', 'audio/mp3', 'application/javascript', 'text/javascript'],
+ ['text/html', 'text/plain', 'text/xml', 'text/javascript', 'image/gif', 'image/jpeg', 'image/png', 'application/json', 'application/xml', 'audio/mp3', 'application/javascript']
+ ))
+ })
+
+ whenAccept('application/json', function () {
+ it('should accept application/json', mediaTypesNegotiated(
+ ['application/json'],
+ ['application/json']
+ ))
+
+ it('should be case insensitive', mediaTypesNegotiated(
+ ['application/JSON'],
+ ['application/JSON']
+ ))
+
+ it('should only return application/json', mediaTypesNegotiated(
+ ['text/html', 'application/json'],
+ ['application/json']
+ ))
+
+ it('should ignore invalid types', mediaTypesNegotiated(
+ ['boom', 'application/json'],
+ ['application/json']
+ ))
+ })
+
+ whenAccept('application/json;q=0', function () {
+ it('should not accept application/json', mediaTypesNegotiated(
+ ['application/json'],
+ []
+ ))
+
+ it('should not accept other media types', mediaTypesNegotiated(
+ ['application/json', 'text/html', 'image/jpeg'],
+ []
+ ))
+ })
+
+ whenAccept('application/json;q=0.2, text/html', function () {
+ it('should prefer text/html over application/json', mediaTypesNegotiated(
+ ['application/json', 'text/html'],
+ ['text/html', 'application/json']
+ ))
+ })
+
+ whenAccept('application/json;q=0.9, text/html;q=0.8, application/json;q=0.7', function () {
+ it('should prefer application/json over text/html', mediaTypesNegotiated(
+ ['text/html', 'application/json'],
+ ['application/json', 'text/html']
+ ))
+ })
+
+ whenAccept('application/json, */*;q=0.1', function () {
+ it('should prefer application/json over text/html', mediaTypesNegotiated(
+ ['text/html', 'application/json'],
+ ['application/json', 'text/html']
+ ))
+ })
+
+ whenAccept('application/xhtml+xml;profile="http://www.wapforum.org/xhtml"', function () {
+ it('should accept application/xhtml+xml;profile="http://www.wapforum.org/xhtml"', mediaTypesNegotiated(
+ ['application/xhtml+xml;profile="http://www.wapforum.org/xhtml"'],
+ ['application/xhtml+xml;profile="http://www.wapforum.org/xhtml"']
+ ))
+ })
+
+ whenAccept('text/*', function () {
+ it('should prefer text media types', mediaTypesNegotiated(
+ ['text/html', 'application/json', 'text/plain'],
+ ['text/html', 'text/plain']
+ ))
+ })
+
+ whenAccept('text/*, text/html;level', function () {
+ it('should accept text/html', mediaTypesNegotiated(
+ ['text/html'],
+ ['text/html']
+ ))
+ })
+
+ whenAccept('text/*, text/plain;q=0', function () {
+ it('should prefer text media types except text/plain', mediaTypesNegotiated(
+ ['text/html', 'text/plain'],
+ ['text/html']
+ ))
+ })
+
+ whenAccept('text/*, text/plain;q=0.5', function () {
+ it('should prefer text/plain below other text types', mediaTypesNegotiated(
+ ['text/html', 'text/plain', 'text/xml'],
+ ['text/html', 'text/xml', 'text/plain']
+ ))
+ })
+
+ whenAccept('text/html;level=1', function () {
+ it('should accept text/html;level=1', mediaTypesNegotiated(
+ ['text/html;level=1'],
+ ['text/html;level=1']
+ ))
+
+ it('should accept text/html;Level=1', mediaTypesNegotiated(
+ ['text/html;Level=1'],
+ ['text/html;Level=1']
+ ))
+
+ it('should not accept text/html;level=2', mediaTypesNegotiated(
+ ['text/html;level=2'],
+ []
+ ))
+
+ it('should not accept text/html', mediaTypesNegotiated(
+ ['text/html'],
+ []
+ ))
+
+ it('should accept text/html;level=1;foo=bar', mediaTypesNegotiated(
+ ['text/html;level=1;foo=bar'],
+ ['text/html;level=1;foo=bar']
+ ))
+ })
+
+ whenAccept('text/html;level=1;foo=bar', function () {
+ it('should not accept text/html;level=1', mediaTypesNegotiated(
+ ['text/html;level=1'],
+ []
+ ))
+
+ it('should accept text/html;level=1;foo=bar', mediaTypesNegotiated(
+ ['text/html;level=1;foo=bar'],
+ ['text/html;level=1;foo=bar']
+ ))
+
+ it('should accept text/html;foo=bar;level=1', mediaTypesNegotiated(
+ ['text/html;foo=bar;level=1'],
+ ['text/html;foo=bar;level=1']
+ ))
+ })
+
+ whenAccept('text/html;level=1;foo="bar"', function () {
+ it('should accept text/html;level=1;foo=bar', mediaTypesNegotiated(
+ ['text/html;level=1;foo=bar'],
+ ['text/html;level=1;foo=bar']
+ ))
+
+ it('should accept text/html;level=1;foo="bar"', mediaTypesNegotiated(
+ ['text/html;level=1;foo="bar"'],
+ ['text/html;level=1;foo="bar"']
+ ))
+ })
+
+ whenAccept('text/html;foo=";level=2;"', function () {
+ it('should not accept text/html;level=2', mediaTypesNegotiated(
+ ['text/html;level=2'],
+ []
+ ))
+
+ it('should accept text/html;foo=";level=2;"', mediaTypesNegotiated(
+ ['text/html;foo=";level=2;"'],
+ ['text/html;foo=";level=2;"']
+ ))
+ })
+
+ whenAccept('text/html;LEVEL=1', function () {
+ it('should accept text/html;level=1', mediaTypesNegotiated(
+ ['text/html;level=1'],
+ ['text/html;level=1']
+ ))
+
+ it('should accept text/html;Level=1', mediaTypesNegotiated(
+ ['text/html;Level=1'],
+ ['text/html;Level=1']
+ ))
+ })
+
+ whenAccept('text/html;LEVEL=1;level=2', function () {
+ it('should accept text/html;level=2', mediaTypesNegotiated(
+ ['text/html;level=2'],
+ ['text/html;level=2']
+ ))
+
+ it('should not accept text/html;level=1', mediaTypesNegotiated(
+ ['text/html;level=1'],
+ []
+ ))
+ })
+
+ whenAccept('text/html;level=2', function () {
+ it('should not accept text/html;level=1', mediaTypesNegotiated(
+ ['text/html;level=1'],
+ []
+ ))
+ })
+
+ whenAccept('text/html;level=2, text/html', function () {
+ it('should prefer text/html;level=2 over text/html', mediaTypesNegotiated(
+ ['text/html', 'text/html;level=2'],
+ ['text/html;level=2', 'text/html']
+ ))
+ })
+
+ whenAccept('text/html;level=2;q=0.1, text/html', function () {
+ it('should prefer text/html over text/html;level=2', mediaTypesNegotiated(
+ ['text/html;level=2', 'text/html'],
+ ['text/html', 'text/html;level=2']
+ ))
+ })
+
+ whenAccept('text/html;level=2;q=0.1;level=1', function () {
+ it('should not accept text/html;level=1', mediaTypesNegotiated(
+ ['text/html;level=1'],
+ []
+ ))
+ })
+
+ whenAccept('text/html;level=2;q=0.1, text/html;level=1, text/html;q=0.5', function () {
+ it('should prefer text/html;level=1, text/html, text/html;level=2', mediaTypesNegotiated(
+ ['text/html;level=1', 'text/html;level=2', 'text/html'],
+ ['text/html;level=1', 'text/html', 'text/html;level=2']
+ ))
+ })
+
+ whenAccept('text/plain, application/json;q=0.5, text/html, */*;q=0.1', function () {
+ it('should prefer text/plain over text/html', mediaTypesNegotiated(
+ ['text/html', 'text/plain'],
+ ['text/plain', 'text/html']
+ ))
+
+ it('should prefer application/json after text', mediaTypesNegotiated(
+ ['application/json', 'text/html', 'text/plain'],
+ ['text/plain', 'text/html', 'application/json']
+ ))
+
+ it('should prefer image/jpeg after text', mediaTypesNegotiated(
+ ['image/jpeg', 'text/html', 'text/plain'],
+ ['text/plain', 'text/html', 'image/jpeg']
+ ))
+ })
+
+ whenAccept('text/plain, application/json;q=0.5, text/html, text/xml, text/yaml, text/javascript, text/csv, text/css, text/rtf, text/markdown, application/octet-stream;q=0.2, */*;q=0.1', function () {
+ it('should return the client-preferred order', mediaTypesNegotiated(
+ ['text/plain', 'text/html', 'text/xml', 'text/yaml', 'text/javascript', 'text/csv', 'text/css', 'text/rtf', 'text/markdown', 'application/json', 'application/octet-stream'],
+ ['text/plain', 'text/html', 'text/xml', 'text/yaml', 'text/javascript', 'text/csv', 'text/css', 'text/rtf', 'text/markdown', 'application/json', 'application/octet-stream']
+ ))
+ })
+})
+
+function createRequest(headers) {
+ var request = {
+ headers: {}
+ }
+
+ if (headers) {
+ Object.keys(headers).forEach(function (key) {
+ request.headers[key.toLowerCase()] = headers[key]
+ })
+ }
+
+ return request
+}
+
+function mediaTypesNegotiated(serverTypes, preferredTypes) {
+ return function () {
+ assert.deepEqual(this.negotiator.mediaTypes(serverTypes), preferredTypes)
+ }
+}
+
+function mediaTypesPreferred(preferredTypes) {
+ return function () {
+ assert.deepEqual(this.negotiator.mediaTypes(), preferredTypes)
}
+}
+
+function whenAccept(accept, func) {
+ var description = !accept
+ ? 'when no Accept'
+ : 'when Accept: ' + accept
+
+ describe(description, function () {
+ before(function () {
+ this.negotiator = Negotiator(createRequest({'Accept': accept}))
+ })
-}).call(this);
+ func()
+ })
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-negotiator.git
More information about the Pkg-javascript-commits
mailing list