You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Mime.js 2.8KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. 'use strict';
  2. /**
  3. * @param typeMap [Object] Map of MIME type -> Array[extensions]
  4. * @param ...
  5. */
  6. function Mime() {
  7. this._types = Object.create(null);
  8. this._extensions = Object.create(null);
  9. for (var i = 0; i < arguments.length; i++) {
  10. this.define(arguments[i]);
  11. }
  12. this.define = this.define.bind(this);
  13. this.getType = this.getType.bind(this);
  14. this.getExtension = this.getExtension.bind(this);
  15. }
  16. /**
  17. * Define mimetype -> extension mappings. Each key is a mime-type that maps
  18. * to an array of extensions associated with the type. The first extension is
  19. * used as the default extension for the type.
  20. *
  21. * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']});
  22. *
  23. * If a type declares an extension that has already been defined, an error will
  24. * be thrown. To suppress this error and force the extension to be associated
  25. * with the new type, pass `force`=true. Alternatively, you may prefix the
  26. * extension with "*" to map the type to extension, without mapping the
  27. * extension to the type.
  28. *
  29. * e.g. mime.define({'audio/wav', ['wav']}, {'audio/x-wav', ['*wav']});
  30. *
  31. *
  32. * @param map (Object) type definitions
  33. * @param force (Boolean) if true, force overriding of existing definitions
  34. */
  35. Mime.prototype.define = function(typeMap, force) {
  36. for (var type in typeMap) {
  37. var extensions = typeMap[type].map(function(t) {return t.toLowerCase()});
  38. type = type.toLowerCase();
  39. for (var i = 0; i < extensions.length; i++) {
  40. var ext = extensions[i];
  41. // '*' prefix = not the preferred type for this extension. So fixup the
  42. // extension, and skip it.
  43. if (ext[0] == '*') {
  44. continue;
  45. }
  46. if (!force && (ext in this._types)) {
  47. throw new Error(
  48. 'Attempt to change mapping for "' + ext +
  49. '" extension from "' + this._types[ext] + '" to "' + type +
  50. '". Pass `force=true` to allow this, otherwise remove "' + ext +
  51. '" from the list of extensions for "' + type + '".'
  52. );
  53. }
  54. this._types[ext] = type;
  55. }
  56. // Use first extension as default
  57. if (force || !this._extensions[type]) {
  58. var ext = extensions[0];
  59. this._extensions[type] = (ext[0] != '*') ? ext : ext.substr(1)
  60. }
  61. }
  62. };
  63. /**
  64. * Lookup a mime type based on extension
  65. */
  66. Mime.prototype.getType = function(path) {
  67. path = String(path);
  68. var last = path.replace(/^.*[/\\]/, '').toLowerCase();
  69. var ext = last.replace(/^.*\./, '').toLowerCase();
  70. var hasPath = last.length < path.length;
  71. var hasDot = ext.length < last.length - 1;
  72. return (hasDot || !hasPath) && this._types[ext] || null;
  73. };
  74. /**
  75. * Return file extension associated with a mime type
  76. */
  77. Mime.prototype.getExtension = function(type) {
  78. type = /^\s*([^;\s]*)/.test(type) && RegExp.$1;
  79. return type && this._extensions[type.toLowerCase()] || null;
  80. };
  81. module.exports = Mime;