UNPKG

mime-type

Version:

the custom more powerful mime-type utility can work with mime-db.

340 lines (328 loc) 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MimeType = MimeType; exports.default = void 0; var _posix = _interopRequireDefault(require("picomatch/posix")); var _utilEx = require("util-ex"); var _path = _interopRequireDefault(require("path.js")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function isMatch(str, pattern, options) { return (0, _posix.default)(pattern, options)(str); } const extractTypeRegExp = /^\s*([^;\s]*)(?:;|\s|$)/; const textTypeRegExp = /^text\//i; const indexOf = Array.prototype.indexOf; const refSources = ['nginx', 'apache', undefined, 'iana']; const shouldDebug = typeof process === 'object' && process && process.env && process.env.DEBUG_MIME; MimeType.dupDefault = MimeType.prototype.dupDefault = 0; MimeType.dupSkip = MimeType.prototype.dupSkip = 1; MimeType.dupOverwrite = MimeType.prototype.dupOverwrite = 2; MimeType.dupAppend = MimeType.prototype.dupAppend = 3; /** * Constructs a MimeType object to manage MIME types and their associated extensions. * @param {Object} db - An initial database containing MIME type mappings. * @param {number} [duplicationProcessWay] - A flag specifying how to handle duplicate MIME type entries. * If provided, it should be one of: * - `dupDefault: 0`: Default strategy that resolves duplicates based on source priority. * See the description for details on this strategy. * - `dupSkip: 1`: Skip adding the new MIME type if a duplicate entry already exists. * - `dupOverwrite: 2`: Replace the existing MIME type with the new one if a duplicate is found. * - `dupAppend: 3`: Add the new MIME type to the end of the existing ones if a duplicate is encountered. * If not specified, it defaults to the `dupDefault` strategy, * The `dupDefault` strategy works as follows: * - If the existing MIME type is 'application/octet-stream', it's not overwritten. * - If sources are equal and the existing type starts with 'application/', it's preserved. * - Otherwise, if the new source is considered more authoritative (earlier in the `refSources` array), * the new type overwrites the old one. The `refSources` array may include server configurations * and standards bodies, such as ['nginx', 'apache', undefined, 'iana'], with `undefined` representing * an unspecified or less authoritative source. */ function MimeType(db, duplicationProcessWay) { if (!(this instanceof MimeType)) { return new MimeType(db, duplicationProcessWay); } (0, _utilEx.defineProperty)(this, 'types', {}); (0, _utilEx.defineProperty)(this, 'dup', this.dupDefault); (0, _utilEx.defineProperty)(this, 'extensions', undefined, { get: function () { var j, k, len, mime, ref, result; result = {}; ref = Object.keys(this); for (j = 0, len = ref.length; j < len; j++) { k = ref[j]; mime = this[k]; result[k] = mime.extensions; } return result; } }); if (duplicationProcessWay && indexOf.call([0, 1, 2, 3], duplicationProcessWay) >= 0) { this.dup = duplicationProcessWay; } if (db) { this.load(db); } } /* * Get the default charset for a MIME type. * * @param {string} type * @return {boolean|string} */ MimeType.prototype.charset = function (type) { let result; if (type && (0, _utilEx.isString)(type)) { try { const match = extractTypeRegExp.exec(type); const mime = match && this[match[1].toLowerCase()]; if (mime && mime.charset) { result = mime.charset; } // default text/* to utf-8 if (!result && match && textTypeRegExp.test(match[1])) { result = 'utf-8'; } } catch (error) {} } return result; }; /* * Create a full Content-Type header given a MIME type or extension. * * @param {string} str * @return {boolean|string} */ MimeType.prototype.contentType = function (str) { var charset; var charset, mime; if (str && (0, _utilEx.isString)(str)) { mime = str.indexOf('/') === -1 ? this.lookup(str) : str; if (mime) { if (mime.indexOf('charset') === -1) { charset = this.charset(mime); if (charset) { mime += '; charset=' + charset.toLowerCase(); } } } } return mime; }; /* * Get the default extension for a MIME type. * * @param {string} type * @return {boolean|string} */ MimeType.prototype.extension = function (type) { var result; if (type && (0, _utilEx.isString)(type)) { result = extractTypeRegExp.exec(type); result = result && this[result[1].toLowerCase()]; if (result) { result = result.defaultExtension || result.extensions[0]; } } return result; }; /* * Lookup the MIME types for a file path/extension. * * @param {string} path * @return {undefined|string|array} */ MimeType.prototype.lookup = function (aPath) { var extension, result; if (aPath && (0, _utilEx.isString)(aPath)) { // get the extension ("ext" or ".ext" or full path) extension = _path.default.extname('x.' + aPath).toLowerCase().slice(1); if (extension) { if (/[*?!+|{]/.test(extension)) { result = Object.keys(this.types).filter(name => isMatch(name, extension)); result = result.length ? result.map(ext => this.types[ext]) : undefined; } else { result = this.types[extension]; } } } return result; }; /* * Return all MIME types which matching a pattern * [spec](http://tools.ietf.org/html/rfc2616#section-14.1) * @param {string} pattern the mime type pattern, For example "video/*", "audio/*", .. * @return {array} */ MimeType.prototype.glob = function (pattern) { var result; if (pattern === '*/*') { return ['application/octet-stream']; } result = Object.keys(this).filter(function (name) { return isMatch(name, pattern); }); return result; }; /* * Whether the mime type is exist. * @param {string} type the mime type * @return {boolean} */ MimeType.prototype.exist = Object.prototype.hasOwnProperty; /* * Add a custom mime/extension mapping and handles potential conflicts. * @param (string) type: mime type * @param (object) mime: mime object * * "source": "iana", * * "charset": "UTF-8", * * "compressible": true, * * "extensions": ["js"] * @param {number} [dup=this.dup] - The conflict resolution strategy. Can be one of: * - `this.dupSkip`: Skip the existing mapping. * - `this.dupAppend`: Append the new type to the existing mapping. * - `this.dupOverwrite`: Overwrite the existing mapping. * - `this.dupDefault`: Uses a default strategy where: * - If the existing MIME type is 'application/octet-stream', it is not overwritten. * - If sources are equal and the existing type starts with 'application/', it is retained. * - Otherwise, if the new source is considered more authoritative (appears earlier in `refSources`), * the new type will overwrite the old one. The `refSources` array includes server configurations * and standards bodies, e.g., ['nginx', 'apache', undefined, 'iana'], with `undefined` marking * an unspecified or less authoritative source. * @return {array<string>}: the added extensions */ MimeType.prototype.define = function (type, mime, dup) { var extension, exts, from, j, len, ref, t, to; if (!(type && mime && mime.extensions && !this.hasOwnProperty(type))) { return; } if (dup == null) { dup = this.dup; } exts = mime.extensions; if (!(0, _utilEx.isArray)(exts)) { mime.extensions = [exts]; } exts = []; if (mime.charset) { mime.charset = mime.charset.toLowerCase(); } ref = mime.extensions; for (j = 0, len = ref.length; j < len; j++) { extension = ref[j]; t = this.types[extension]; if (t) { switch (dup) { case this.dupSkip: continue; case this.dupAppend: if ((0, _utilEx.isString)(t)) { t = [t]; } if (indexOf.call(t, type) < 0) { t.push(type); } break; case this.dupOverwrite: t = type; break; case this.dupDefault: if ((0, _utilEx.isArray)(t)) { t = t[0]; } from = refSources.indexOf(this[t].source); to = refSources.indexOf(mime.source); if (t !== 'application/octet-stream' && from > to || from === to && t.substr(0, 12) === 'application/') { if (shouldDebug) { console.warn("defineMime(" + type + "): the " + extension + " extension is exists on\n" + t + " skipped it."); } continue; } else { t = type; } } } else { t = type; } this.types[extension] = t; exts.push(extension); } if (exts.length) { mime.extensions = exts; this[type] = mime; } return exts; }; /* * load mime-types from db. */ MimeType.prototype.load = function (mimes, duplicationProcessWay) { var result; result = 0; Object.keys(mimes).forEach(function (_this) { return function (type) { var t; t = _this.define(type, mimes[type], duplicationProcessWay); if (t && t.length) { return result++; } }; }(this)); return result; }; /* * remove the specified mime-type. */ MimeType.prototype.delete = function (type) { var i, k, ref, result, v; result = this.exist(type); if (result) { ref = this.types; for (k in ref) { v = ref[k]; if ((0, _utilEx.isArray)(v)) { i = v.indexOf(type); if (i !== -1) { v.splice(i, 1); if (v.length === 1) { this.types[k] = v[0]; } } } else if (type === v) { delete this.types[k]; } } delete this[type]; } return result; }; /* * clear the mime-types. */ MimeType.prototype.clear = function (filter) { var k, ref, result, v; result = 0; ref = this; for (k in ref) { v = ref[k]; if (this.hasOwnProperty(k)) { if ((0, _utilEx.isFunction)(filter)) { if (filter(k, v)) { this["delete"](k); result++; } } else if ((0, _utilEx.isString)(filter)) { if (isMatch(k, filter)) { this["delete"](k); result++; } } else { this["delete"](k); result++; } } } return result; }; var _default = exports.default = MimeType;