Skip to content

Commit e2fe4ab

Browse files
committed
Media Type: Expose more-complete, unstringified parse results
1 parent d904ca6 commit e2fe4ab

File tree

3 files changed

+116
-7
lines changed

3 files changed

+116
-7
lines changed

index.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@ Negotiator.prototype.languages = function languages(available) {
6767
return preferredLanguages(this.request.headers['accept-language'], available);
6868
};
6969

70-
Negotiator.prototype.mediaType = function mediaType(available) {
71-
var set = this.mediaTypes(available);
70+
Negotiator.prototype.mediaType = function mediaType(available, options) {
71+
var set = this.mediaTypes(available, options);
7272
return set && set[0];
7373
};
7474

75-
Negotiator.prototype.mediaTypes = function mediaTypes(available) {
75+
Negotiator.prototype.mediaTypes = function mediaTypes(available, options) {
7676
var preferredMediaTypes = loadModule('mediaType').preferredMediaTypes;
77-
return preferredMediaTypes(this.request.headers.accept, available);
77+
return preferredMediaTypes(this.request.headers.accept, available, options);
7878
};
7979

8080
// Backwards compatibility

lib/mediaType.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,26 +159,29 @@ function specify(type, spec, index) {
159159
* @public
160160
*/
161161

162-
function preferredMediaTypes(accept, provided) {
162+
function preferredMediaTypes(accept, provided, options) {
163163
// RFC 2616 sec 14.2: no header = */*
164164
var accepts = parseAccept(accept === undefined ? '*/*' : accept || '');
165+
var detailed = options && options.detailed;
165166

166167
if (!provided) {
167168
// sorted list of all types
168169
return accepts
169170
.filter(isQuality)
170171
.sort(compareSpecs)
171-
.map(getFullType);
172+
.map(detailed ? getDetailedSpec : getFullType);
172173
}
173174

174175
var priorities = provided.map(function getPriority(type, index) {
175176
return getMediaTypePriority(type, accepts, index);
176177
});
177178

178179
// sorted list of accepted types
179-
return priorities.filter(isQuality).sort(compareSpecs).map(function getType(priority) {
180+
var acceptables = priorities.filter(isQuality).sort(compareSpecs).map(function getType(priority) {
180181
return provided[priorities.indexOf(priority)];
181182
});
183+
184+
return detailed ? acceptables.map(parseMediaType).map(getDetailedSpec) : acceptables;
182185
}
183186

184187
/**
@@ -199,6 +202,19 @@ function getFullType(spec) {
199202
return spec.type + '/' + spec.subtype;
200203
}
201204

205+
/**
206+
* Get detailed description object for this spec.
207+
* @private
208+
*/
209+
210+
function getDetailedSpec(spec) {
211+
return {
212+
type: spec.type + '/' + spec.subtype,
213+
parameters: spec.params,
214+
q: spec.q
215+
};
216+
};
217+
202218
/**
203219
* Check if a spec has any quality.
204220
* @private

test/mediaType.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,26 @@ describe('negotiator.mediaType()', function () {
5252
})
5353
})
5454

55+
describe('negotiator.mediaType(undefined, {detailed: true})', function () {
56+
whenAccept('text/*', function () {
57+
it('should return a detailed spec object with text/*', function () {
58+
assert.deepEqual(
59+
this.negotiator.mediaType(undefined, {detailed: true}),
60+
{"type": "text/*", parameters: {}, "q": 1}
61+
)
62+
})
63+
})
64+
65+
whenAccept('text/plain;charset=utf-8;q=0.8, application/json;q=0.5, text/html;q=0.7, */*;q=0.1', function () {
66+
it('should return a detailed object for text/plain', function () {
67+
assert.deepEqual(
68+
this.negotiator.mediaType(undefined, {detailed: true}),
69+
{"type": "text/plain", parameters: {"charset": "utf-8"}, "q": .8}
70+
)
71+
})
72+
})
73+
})
74+
5575
describe('negotiator.mediaType(array)', function () {
5676
whenAccept(undefined, function () {
5777
it('should return first item in list', function () {
@@ -126,6 +146,31 @@ describe('negotiator.mediaType(array)', function () {
126146
})
127147
})
128148

149+
describe('negotiator.mediaType(array, {detailed: true})', function() {
150+
whenAccept('text/*', function () {
151+
it('should return a detailed spec object with text/html', function () {
152+
assert.deepEqual(
153+
this.negotiator.mediaType(["text/html"], {detailed: true}),
154+
{"type": "text/html", parameters: {}, "q": 1}
155+
)
156+
})
157+
})
158+
159+
whenAccept('text/html;LEVEL=1, application/json;q=0.5', function () {
160+
it('should return parameters, but require an exact match', function () {
161+
assert.deepEqual(
162+
this.negotiator.mediaType(["text/html"], {detailed: true}),
163+
undefined
164+
)
165+
166+
assert.deepEqual(
167+
this.negotiator.mediaType(["text/html; level=1"], {detailed: true}),
168+
{"type": "text/html", "parameters": {"level": "1"}, "q": 1}
169+
)
170+
})
171+
})
172+
})
173+
129174
describe('negotiator.mediaTypes()', function () {
130175
whenAccept(undefined, function () {
131176
it('should return */*', function () {
@@ -194,6 +239,29 @@ describe('negotiator.mediaTypes()', function () {
194239
})
195240
})
196241

242+
describe('negotiator.mediaTypes(undefined, {detailed: true})', function() {
243+
whenAccept('text/*', function () {
244+
it('should return a detailed spec object with text/*', function () {
245+
assert.deepEqual(
246+
this.negotiator.mediaTypes(undefined, {detailed: true}),
247+
[{"type": "text/*", parameters: {}, "q": 1}]
248+
)
249+
})
250+
})
251+
252+
whenAccept('text/html;LEVEL=1, application/json;q=0.5', function () {
253+
it('should return more-detailed spec objects', function () {
254+
assert.deepEqual(
255+
this.negotiator.mediaTypes(undefined, {detailed: true}),
256+
[
257+
{"type": "text/html", "parameters": {"level": "1"}, "q": 1},
258+
{"type": "application/json", "parameters": {}, "q": 0.5}
259+
]
260+
)
261+
})
262+
})
263+
})
264+
197265
describe('negotiator.mediaTypes(array)', function () {
198266
whenAccept(undefined, function () {
199267
it('should return return original list', mediaTypesNegotiated(
@@ -458,6 +526,31 @@ describe('negotiator.mediaTypes(array)', function () {
458526
})
459527
})
460528

529+
describe('negotiator.mediaTypes(array, {detailed: true})', function() {
530+
whenAccept('text/*', function () {
531+
it('should return a detailed spect object with text/html', function () {
532+
assert.deepEqual(
533+
this.negotiator.mediaTypes(["text/html"], {detailed: true}),
534+
[{"type": "text/html", parameters: {}, "q": 1}]
535+
)
536+
})
537+
})
538+
539+
whenAccept('text/html;LEVEL=1, application/json;q=0.5', function () {
540+
it('should return parameters, but require an exact match', function () {
541+
assert.deepEqual(
542+
this.negotiator.mediaTypes(["text/html"], {detailed: true}),
543+
[]
544+
)
545+
546+
assert.deepEqual(
547+
this.negotiator.mediaTypes(["text/html; level=1"], {detailed: true}),
548+
[{"type": "text/html", "parameters": {"level": "1"}, "q": 1}]
549+
)
550+
})
551+
})
552+
})
553+
461554
function createRequest(headers) {
462555
var request = {
463556
headers: {}

0 commit comments

Comments
 (0)