Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prioritize by "facet" when resolving type collisions #156

Merged
merged 3 commits into from
May 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"root": true,
"env": {
"browser": true,
"commonjs": true,
"node": true,
"mocha": true
},
"extends": ["eslint:recommended"],
"installedESLint": true,
"rules": {
"array-bracket-spacing": ["warn", "never"],
"arrow-body-style": ["warn", "as-needed"],
"arrow-parens": ["warn", "as-needed"],
"arrow-spacing": "warn",
"brace-style": "warn",
"camelcase": "warn",
"comma-spacing": ["warn", {"after": true}],
"dot-notation": "warn",
"indent": ["warn", 2, {
"SwitchCase": 1,
"FunctionDeclaration": {"parameters": 1},
"MemberExpression": 1,
"CallExpression": {"arguments": 1}
}],
"key-spacing": ["warn", {"beforeColon": false, "afterColon": true, "mode": "minimum"}],
"keyword-spacing": "warn",
"no-console": "off",
"no-empty": "off",
"no-multi-spaces": "warn",
"no-redeclare": "off",
"no-restricted-globals": ["warn", "Promise"],
"no-trailing-spaces": "warn",
"no-undef": "error",
"no-unused-vars": ["warn", {"args": "none"}],
"padded-blocks": ["warn", "never"],
"object-curly-spacing": ["warn", "never"],
"quotes": ["warn", "single"],
"react/prop-types": "off",
"react/jsx-no-bind": "off",
"semi": ["warn", "always"],
"space-before-blocks": ["warn", "always"],
"space-before-function-paren": ["warn", "never"],
"space-in-parens": ["warn", "never"]
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules
npm-debug.log
*.sw* # VIM temp files
.DS_Store # Mac desktop services store
19 changes: 18 additions & 1 deletion build/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

var mime = require('../mime');
var assert = require('assert');
var path = require('path');

//
// Test mime lookups
Expand All @@ -21,6 +20,24 @@ assert.equal('text/plain', mime.lookup('\\txt')); // Windows, extension-l
assert.equal('application/octet-stream', mime.lookup('text.nope')); // unrecognized
assert.equal('fallback', mime.lookup('text.fallback', 'fallback')); // alternate default

//
// Test types that are known to have conflicting definitions but different facet priorities
//

assert.equal('application/octet-stream', mime.lookup('dmg'));
assert.equal('application/bdoc', mime.lookup('bdoc'));
assert.equal('application/octet-stream', mime.lookup('deb'));
assert.equal('application/octet-stream', mime.lookup('iso'));
assert.equal('application/octet-stream', mime.lookup('exe'));
assert.equal('application/octet-stream', mime.lookup('exe'));
assert.equal('application/octet-stream', mime.lookup('dll'));
assert.equal('application/octet-stream', mime.lookup('msi'));
assert.equal('application/vnd.palm', mime.lookup('pdb'));
assert.equal('audio/mp3', mime.lookup('mp3'));
assert.equal('audio/mp4', mime.lookup('m4a'));
assert.equal('font/opentype', mime.lookup('otf'));
assert.equal('image/bmp', mime.lookup('bmp'));

//
// Test extensions
//
Expand Down
38 changes: 27 additions & 11 deletions mime.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
var path = require('path');
var fs = require('fs');

// If two types claim the same extension, we resolve the conflict by checking
// facet precedence. https://tools.ietf.org/html/rfc6838#section-3
// Facets listed here are in order of decreasing precedence
var FACETS = ['vnd.', 'x-', 'prs.'];
var FACET_RE = new RegExp('/(' + FACETS.join('|') + ')');

function Mime() {
// Map of extension -> mime type
this.types = Object.create(null);
Expand All @@ -18,16 +23,27 @@ function Mime() {
*
* @param map (Object) type definitions
*/
Mime.prototype.define = function (map) {
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);
var ext = exts[i];
var found = this.types[ext];

// If there's already a type for this extension ...
if (found) {
var pri0 = FACETS.indexOf(FACET_RE.test(found) && RegExp.$1);
var pri1 = FACETS.indexOf(FACET_RE.test(type) && RegExp.$1);

if (process.env.DEBUG_MIME) console.warn('Type conflict for .' + ext +
' (' + found + ' pri=' + pri0 + ', ' + type + ' pri=' + pri1 + ')');

// Prioritize based on facet precedence
if (pri0 <= pri1) continue;
}

this.types[exts[i]] = type;
this.types[ext] = type;
}

// Default extension is the first one we encounter
Expand All @@ -48,9 +64,9 @@ Mime.prototype.define = function (map) {
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]+/);
var map = {};
var content = fs.readFileSync(file, 'ascii');
var lines = content.split(/[\r\n]+/);

lines.forEach(function(line) {
// Clean up whitespace/comments, and split into fields
Expand All @@ -69,7 +85,7 @@ Mime.prototype.load = function(file) {
Mime.prototype.lookup = function(path, fallback) {
var ext = path.replace(/.*[\.\/\\]/, '').toLowerCase();

return this.types[ext] || fallback || this.default_type;
return this.types[ext] || fallback || this.default_type; // eslint-disable-line camelcase
};

/**
Expand All @@ -87,7 +103,7 @@ var mime = new Mime();
mime.define(require('./types.json'));

// Default type
mime.default_type = mime.lookup('bin');
mime.default_type = mime.lookup('bin'); // eslint-disable-line camelcase

//
// Additional API specific to the default instance
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"mime-db": "^1.22.0"
},
"scripts": {
"prepublish": "node build/build.js > types.json",
"prepare": "node build/build.js > types.json",
"test": "node build/test.js"
},
"keywords": [
Expand All @@ -34,5 +34,5 @@
"url": "https://github.com/broofa/node-mime",
"type": "git"
},
"version": "1.3.4"
"version": "1.3.5"
}
2 changes: 1 addition & 1 deletion types.json

Large diffs are not rendered by default.