/ node_modules / accepts / index.js
index.js
  1  /*!
  2   * accepts
  3   * Copyright(c) 2014 Jonathan Ong
  4   * Copyright(c) 2015 Douglas Christopher Wilson
  5   * MIT Licensed
  6   */
  7  
  8  'use strict'
  9  
 10  /**
 11   * Module dependencies.
 12   * @private
 13   */
 14  
 15  var Negotiator = require('negotiator')
 16  var mime = require('mime-types')
 17  
 18  /**
 19   * Module exports.
 20   * @public
 21   */
 22  
 23  module.exports = Accepts
 24  
 25  /**
 26   * Create a new Accepts object for the given req.
 27   *
 28   * @param {object} req
 29   * @public
 30   */
 31  
 32  function Accepts (req) {
 33    if (!(this instanceof Accepts)) {
 34      return new Accepts(req)
 35    }
 36  
 37    this.headers = req.headers
 38    this.negotiator = new Negotiator(req)
 39  }
 40  
 41  /**
 42   * Check if the given `type(s)` is acceptable, returning
 43   * the best match when true, otherwise `undefined`, in which
 44   * case you should respond with 406 "Not Acceptable".
 45   *
 46   * The `type` value may be a single mime type string
 47   * such as "application/json", the extension name
 48   * such as "json" or an array `["json", "html", "text/plain"]`. When a list
 49   * or array is given the _best_ match, if any is returned.
 50   *
 51   * Examples:
 52   *
 53   *     // Accept: text/html
 54   *     this.types('html');
 55   *     // => "html"
 56   *
 57   *     // Accept: text/*, application/json
 58   *     this.types('html');
 59   *     // => "html"
 60   *     this.types('text/html');
 61   *     // => "text/html"
 62   *     this.types('json', 'text');
 63   *     // => "json"
 64   *     this.types('application/json');
 65   *     // => "application/json"
 66   *
 67   *     // Accept: text/*, application/json
 68   *     this.types('image/png');
 69   *     this.types('png');
 70   *     // => undefined
 71   *
 72   *     // Accept: text/*;q=.5, application/json
 73   *     this.types(['html', 'json']);
 74   *     this.types('html', 'json');
 75   *     // => "json"
 76   *
 77   * @param {String|Array} types...
 78   * @return {String|Array|Boolean}
 79   * @public
 80   */
 81  
 82  Accepts.prototype.type =
 83  Accepts.prototype.types = function (types_) {
 84    var types = types_
 85  
 86    // support flattened arguments
 87    if (types && !Array.isArray(types)) {
 88      types = new Array(arguments.length)
 89      for (var i = 0; i < types.length; i++) {
 90        types[i] = arguments[i]
 91      }
 92    }
 93  
 94    // no types, return all requested types
 95    if (!types || types.length === 0) {
 96      return this.negotiator.mediaTypes()
 97    }
 98  
 99    // no accept header, return first given type
100    if (!this.headers.accept) {
101      return types[0]
102    }
103  
104    var mimes = types.map(extToMime)
105    var accepts = this.negotiator.mediaTypes(mimes.filter(validMime))
106    var first = accepts[0]
107  
108    return first
109      ? types[mimes.indexOf(first)]
110      : false
111  }
112  
113  /**
114   * Return accepted encodings or best fit based on `encodings`.
115   *
116   * Given `Accept-Encoding: gzip, deflate`
117   * an array sorted by quality is returned:
118   *
119   *     ['gzip', 'deflate']
120   *
121   * @param {String|Array} encodings...
122   * @return {String|Array}
123   * @public
124   */
125  
126  Accepts.prototype.encoding =
127  Accepts.prototype.encodings = function (encodings_) {
128    var encodings = encodings_
129  
130    // support flattened arguments
131    if (encodings && !Array.isArray(encodings)) {
132      encodings = new Array(arguments.length)
133      for (var i = 0; i < encodings.length; i++) {
134        encodings[i] = arguments[i]
135      }
136    }
137  
138    // no encodings, return all requested encodings
139    if (!encodings || encodings.length === 0) {
140      return this.negotiator.encodings()
141    }
142  
143    return this.negotiator.encodings(encodings)[0] || false
144  }
145  
146  /**
147   * Return accepted charsets or best fit based on `charsets`.
148   *
149   * Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
150   * an array sorted by quality is returned:
151   *
152   *     ['utf-8', 'utf-7', 'iso-8859-1']
153   *
154   * @param {String|Array} charsets...
155   * @return {String|Array}
156   * @public
157   */
158  
159  Accepts.prototype.charset =
160  Accepts.prototype.charsets = function (charsets_) {
161    var charsets = charsets_
162  
163    // support flattened arguments
164    if (charsets && !Array.isArray(charsets)) {
165      charsets = new Array(arguments.length)
166      for (var i = 0; i < charsets.length; i++) {
167        charsets[i] = arguments[i]
168      }
169    }
170  
171    // no charsets, return all requested charsets
172    if (!charsets || charsets.length === 0) {
173      return this.negotiator.charsets()
174    }
175  
176    return this.negotiator.charsets(charsets)[0] || false
177  }
178  
179  /**
180   * Return accepted languages or best fit based on `langs`.
181   *
182   * Given `Accept-Language: en;q=0.8, es, pt`
183   * an array sorted by quality is returned:
184   *
185   *     ['es', 'pt', 'en']
186   *
187   * @param {String|Array} langs...
188   * @return {Array|String}
189   * @public
190   */
191  
192  Accepts.prototype.lang =
193  Accepts.prototype.langs =
194  Accepts.prototype.language =
195  Accepts.prototype.languages = function (languages_) {
196    var languages = languages_
197  
198    // support flattened arguments
199    if (languages && !Array.isArray(languages)) {
200      languages = new Array(arguments.length)
201      for (var i = 0; i < languages.length; i++) {
202        languages[i] = arguments[i]
203      }
204    }
205  
206    // no languages, return all requested languages
207    if (!languages || languages.length === 0) {
208      return this.negotiator.languages()
209    }
210  
211    return this.negotiator.languages(languages)[0] || false
212  }
213  
214  /**
215   * Convert extnames to mime.
216   *
217   * @param {String} type
218   * @return {String}
219   * @private
220   */
221  
222  function extToMime (type) {
223    return type.indexOf('/') === -1
224      ? mime.lookup(type)
225      : type
226  }
227  
228  /**
229   * Check if mime is valid.
230   *
231   * @param {String} type
232   * @return {Boolean}
233   * @private
234   */
235  
236  function validMime (type) {
237    return typeof type === 'string'
238  }