109 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			109 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | var path = require('path'); | ||
|  | var fs = require('fs'); | ||
|  | 
 | ||
|  | function Mime() { | ||
|  |   // Map of extension -> mime type
 | ||
|  |   this.types = Object.create(null); | ||
|  | 
 | ||
|  |   // Map of mime type -> extension
 | ||
|  |   this.extensions = Object.create(null); | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Define mimetype -> extension mappings.  Each key is a mime-type that maps | ||
|  |  * to an array of extensions associated with the type.  The first extension is | ||
|  |  * used as the default extension for the type. | ||
|  |  * | ||
|  |  * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']}); | ||
|  |  * | ||
|  |  * @param map (Object) type definitions | ||
|  |  */ | ||
|  | Mime.prototype.define = function (map) { | ||
|  |   for (var type in map) { | ||
|  |     var exts = map[type]; | ||
|  |     for (var i = 0; i < exts.length; i++) { | ||
|  |       if (process.env.DEBUG_MIME && this.types[exts[i]]) { | ||
|  |         console.warn((this._loading || "define()").replace(/.*\//, ''), 'changes "' + exts[i] + '" extension type from ' + | ||
|  |           this.types[exts[i]] + ' to ' + type); | ||
|  |       } | ||
|  | 
 | ||
|  |       this.types[exts[i]] = type; | ||
|  |     } | ||
|  | 
 | ||
|  |     // Default extension is the first one we encounter
 | ||
|  |     if (!this.extensions[type]) { | ||
|  |       this.extensions[type] = exts[0]; | ||
|  |     } | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Load an Apache2-style ".types" file | ||
|  |  * | ||
|  |  * This may be called multiple times (it's expected).  Where files declare | ||
|  |  * overlapping types/extensions, the last file wins. | ||
|  |  * | ||
|  |  * @param file (String) path of file to load. | ||
|  |  */ | ||
|  | Mime.prototype.load = function(file) { | ||
|  |   this._loading = file; | ||
|  |   // Read file and split into lines
 | ||
|  |   var map = {}, | ||
|  |       content = fs.readFileSync(file, 'ascii'), | ||
|  |       lines = content.split(/[\r\n]+/); | ||
|  | 
 | ||
|  |   lines.forEach(function(line) { | ||
|  |     // Clean up whitespace/comments, and split into fields
 | ||
|  |     var fields = line.replace(/\s*#.*|^\s*|\s*$/g, '').split(/\s+/); | ||
|  |     map[fields.shift()] = fields; | ||
|  |   }); | ||
|  | 
 | ||
|  |   this.define(map); | ||
|  | 
 | ||
|  |   this._loading = null; | ||
|  | }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Lookup a mime type based on extension | ||
|  |  */ | ||
|  | Mime.prototype.lookup = function(path, fallback) { | ||
|  |   var ext = path.replace(/^.*[\.\/\\]/, '').toLowerCase(); | ||
|  | 
 | ||
|  |   return this.types[ext] || fallback || this.default_type; | ||
|  | }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Return file extension associated with a mime type | ||
|  |  */ | ||
|  | Mime.prototype.extension = function(mimeType) { | ||
|  |   var type = mimeType.match(/^\s*([^;\s]*)(?:;|\s|$)/)[1].toLowerCase(); | ||
|  |   return this.extensions[type]; | ||
|  | }; | ||
|  | 
 | ||
|  | // Default instance
 | ||
|  | var mime = new Mime(); | ||
|  | 
 | ||
|  | // Define built-in types
 | ||
|  | mime.define(require('./types.json')); | ||
|  | 
 | ||
|  | // Default type
 | ||
|  | mime.default_type = mime.lookup('bin'); | ||
|  | 
 | ||
|  | //
 | ||
|  | // Additional API specific to the default instance
 | ||
|  | //
 | ||
|  | 
 | ||
|  | mime.Mime = Mime; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Lookup a charset based on mime type. | ||
|  |  */ | ||
|  | mime.charsets = { | ||
|  |   lookup: function(mimeType, fallback) { | ||
|  |     // Assume text types are utf8
 | ||
|  |     return (/^text\/|^application\/(javascript|json)/).test(mimeType) ? 'UTF-8' : fallback; | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | module.exports = mime; |