diff --git a/lib/header.js b/lib/header.js index 2212e50..a1c1ac6 100755 --- a/lib/header.js +++ b/lib/header.js @@ -70,7 +70,6 @@ exports.selections = function (header, preferences, options) { // weight = OWS ";" OWS "q=" qvalue // qvalue = ( "0" [ "." 0*3DIGIT ] ) / ( "1" [ "." 0*3("0") ] ) - internals.parse = function (raw, preferences, options) { // Normalize header (remove spaces and tabs) @@ -83,7 +82,18 @@ internals.parse = function (raw, preferences, options) { if (preferences) { for (let i = 0; i < preferences.length; ++i) { const preference = preferences[i]; - lowers.set(preference.toLowerCase(), { orig: preference, pos: i }); + const lowerPreference = preference.toLowerCase(); + lowers.set(lowerPreference, { orig: preference, pos: i }); + if ( options.type === 'accept-language') { + const languageParts = lowerPreference.split('-'); + languageParts.pop(); + + while (languageParts.length) { + lowers.set(languageParts.join('-'), { orig: preference, pos: i }); + languageParts.pop(); + } + + } } } @@ -124,13 +134,16 @@ internals.parse = function (raw, preferences, options) { specificity: options.specificity ? token.split('-') : null }; - if (preferences && - lowers.has(token)) { - + if (preferences && lowers.has(token)) { selection.pref = lowers.get(token).pos; } - map.add(selection.token); + if (preferences && lowers.has(selection.token)) { + map.add(lowers.get(selection.token).orig); + } + else { + map.add(selection.token); + } // Parse q=value @@ -210,6 +223,13 @@ internals.sort = function (a, b) { return b.q - a.q; } + if (a.specificity && + a.specificity[0] === b.specificity[0] && + a.specificity.length !== b.specificity.length) { + + return b.specificity.length - a.specificity.length; + } + if (b.pref !== a.pref) { if (a.pref === undefined) { return bFirst; @@ -222,12 +242,5 @@ internals.sort = function (a, b) { return a.pref - b.pref; } - if (a.specificity && - a.specificity[0] === b.specificity[0] && - a.specificity.length !== b.specificity.length) { - - return b.specificity.length - a.specificity.length; - } - return a.pos - b.pos; }; diff --git a/test/language.js b/test/language.js index fe55996..2e7e983 100755 --- a/test/language.js +++ b/test/language.js @@ -72,12 +72,12 @@ describe('language()', () => { it('returns preference with highest specificity', () => { - expect(Accept.language('da, en, en-GB', ['en', 'en-GB'])).to.equal('en'); + expect(Accept.language('da, en, en-GB', ['en', 'en-GB'])).to.equal('en-GB'); expect(Accept.language('da, en, en-GB', ['en-GB', 'en'])).to.equal('en-GB'); expect(Accept.language('en, en-GB, en-US')).to.equal('en-gb'); }); - it('return language with heighest weight', () => { + it('returns language with heighest weight', () => { const language = Accept.language('da;q=0.5, en;q=1', ['da', 'en']); expect(language).to.equal('en'); @@ -88,6 +88,12 @@ describe('language()', () => { const language = Accept.language('da, en-GB, en', ['en-us', 'en-gb']); // en-GB vs en-gb expect(language).to.equal('en-gb'); }); + + it('returns a more specific preference if a less specific one is requested', () => { + + const language = Accept.language('de-LI,de', ['en-us', 'de-de']); + expect(language).to.equal('de-de'); + }); }); @@ -123,15 +129,16 @@ describe('languages()', () => { expect(languages).to.equal(['da', 'en-gb', 'es', 'en']); }); - it('return empty array when no header is present', () => { + it('returns empty array when no header is present', () => { const languages = Accept.languages(); expect(languages).to.equal([]); }); - it('return empty array when header is empty', () => { + it('returns empty array when header is empty', () => { const languages = Accept.languages(''); expect(languages).to.equal([]); }); + });