Skip to content

Commit

Permalink
feat!: resolve extension conflicts with mime-score, close jshttp#116
Browse files Browse the repository at this point in the history
  • Loading branch information
broofa committed Dec 12, 2023
1 parent c77d6b0 commit 497715a
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 5 deletions.
7 changes: 4 additions & 3 deletions index.js
Expand Up @@ -14,6 +14,7 @@

var db = require('mime-db')
var extname = require('path').extname
var mimeScore = require('./mimeScore')

/**
* Module variables.
Expand Down Expand Up @@ -171,11 +172,11 @@ function populateMaps (extensions, types) {
var extension = exts[i]

if (types[extension]) {
var from = preference.indexOf(db[types[extension]].source)
var to = preference.indexOf(mime.source)
var from = mimeScore(types[extension])
var to = mimeScore(type)

if (types[extension] !== 'application/octet-stream' &&
(from > to || (from === to && types[extension].slice(0, 12) === 'application/'))) {
from > to) {
// skip the remapping
continue
}
Expand Down
48 changes: 48 additions & 0 deletions mimeScore.js
@@ -0,0 +1,48 @@
// 'mime-score' back-ported to CommonJS

// Score RFC facets (see https://tools.ietf.org/html/rfc6838#section-3)
var FACET_SCORES = {
'prs.': 100,
'x-': 200,
'x.': 300,
'vnd.': 400,
default: 900,
}

// Score mime source (Logic originally from `jshttp/mime-types` module)
var SOURCE_SCORES = {
nginx: 10,
apache: 20,
iana: 40,
default: 30, // definitions added by `jshttp/mime-db` project?
}

var TYPE_SCORES = {
// prefer application/xml over text/xml
// prefer application/rtf over text/rtf
application: 1,

// prefer font/woff over application/font-woff
font: 2,

default: 0,
}

/**
* Get each component of the score for a mime type. The sum of these is the
* total score. The higher the score, the more "official" the type.
*/
module.exports = function mimeScore(mimeType, source = 'default') {
let [type, subtype] = mimeType.split('/')

const facet = subtype.replace(/(\.|x-).*/, '$1')

const facetScore = FACET_SCORES[facet] || FACET_SCORES.default
const sourceScore = SOURCE_SCORES[source] || SOURCE_SCORES.default
const typeScore = TYPE_SCORES[type] || TYPE_SCORES.default

// All else being equal prefer shorter types
const lengthScore = 1 - mimeType.length / 100

return facetScore + sourceScore + typeScore + lengthScore
}
19 changes: 17 additions & 2 deletions test/test.js
@@ -1,4 +1,3 @@

var assert = require('assert')
var mimeTypes = require('..')

Expand Down Expand Up @@ -220,7 +219,23 @@ describe('mimeTypes', function () {
})

it('should return mime type when there is extension, but no path', function () {
assert.strictEqual(mimeTypes.lookup('.config.json'), 'application/json')
assert.strictEqual(
mimeTypes.lookup('.config.json'),
'application/json'
)
})
})

describe('extension conflicts', function () {
it('should use mime-score', function () {
// Test extension conflicts where the lookup has changed as a result of the switch to mime-score
assert.strictEqual(mimeTypes.lookup('exe'), 'application/x-msdownload') // was application/x-msdos-program
assert.strictEqual(mimeTypes.lookup('prc'), 'application/x-pilot') // was application/x-mobipocket-ebook
assert.strictEqual(mimeTypes.lookup('mp3'), 'audio/mp3') // was audio/mpeg
assert.strictEqual(mimeTypes.lookup('wav'), 'audio/wav') // was audio/wave
assert.strictEqual(mimeTypes.lookup('ra'), 'audio/x-realaudio') // was audio/x-pn-realaudio
assert.strictEqual(mimeTypes.lookup('x3db'), 'model/x3d+binary') // was model/x3d+fastinfoset
assert.strictEqual(mimeTypes.lookup('jpm'), 'video/jpm') // was image/jpm
})
})
})
Expand Down

0 comments on commit 497715a

Please sign in to comment.