├── .eslintignore ├── .eslintrc.yml ├── .github └── workflows │ ├── ci.yml │ └── scorecard.yml ├── .gitignore ├── HISTORY.md ├── LICENSE ├── README.md ├── index.js ├── mimeScore.js ├── package.json └── test ├── .eslintrc.yml └── test.js /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | node_modules 3 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | root: true 2 | extends: 3 | - standard 4 | - plugin:markdown/recommended 5 | plugins: 6 | - markdown 7 | overrides: 8 | - files: '**/*.md' 9 | processor: 'markdown/markdown' 10 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - '3.x' 8 | paths-ignore: 9 | - '*.md' 10 | pull_request: 11 | paths-ignore: 12 | - '*.md' 13 | 14 | jobs: 15 | test: 16 | runs-on: ubuntu-20.04 17 | strategy: 18 | matrix: 19 | name: 20 | - Node.js 18.x 21 | - Node.js 19.x 22 | - Node.js 20.x 23 | - Node.js 21.x 24 | - Node.js 22.x 25 | 26 | include: 27 | - name: Node.js 18.x 28 | node-version: "18" 29 | 30 | - name: Node.js 19.x 31 | node-version: "19" 32 | 33 | - name: Node.js 20.x 34 | node-version: "20" 35 | 36 | - name: Node.js 21.x 37 | node-version: "21" 38 | 39 | - name: Node.js 22.x 40 | node-version: "22" 41 | 42 | steps: 43 | - uses: actions/checkout@v4 44 | 45 | - name: Install Node.js ${{ matrix.node-version }} 46 | shell: bash -eo pipefail -l {0} 47 | run: | 48 | nvm install --default ${{ matrix.node-version }} 49 | dirname "$(nvm which ${{ matrix.node-version }})" >> "$GITHUB_PATH" 50 | 51 | - name: Configure npm 52 | run: | 53 | if [[ "$(npm config get package-lock)" == "true" ]]; then 54 | npm config set package-lock false 55 | else 56 | npm config set shrinkwrap false 57 | fi 58 | 59 | - name: Remove npm module(s) ${{ matrix.npm-rm }} 60 | run: npm rm --silent --save-dev ${{ matrix.npm-rm }} 61 | if: matrix.npm-rm != '' 62 | 63 | - name: Install npm module(s) ${{ matrix.npm-i }} 64 | run: npm install --save-dev ${{ matrix.npm-i }} 65 | if: matrix.npm-i != '' 66 | 67 | - name: Install Node.js dependencies 68 | run: npm install 69 | 70 | - name: List environment 71 | id: list_env 72 | shell: bash 73 | run: | 74 | echo "node@$(node -v)" 75 | echo "npm@$(npm -v)" 76 | npm -s ls ||: 77 | (npm -s ls --depth=0 ||:) | awk -F'[ @]' 'NR>1 && $2 { print "::set-output name=" $2 "::" $3 }' 78 | 79 | - name: Run tests 80 | shell: bash 81 | run: | 82 | if npm -ps ls nyc | grep -q nyc; then 83 | npm run test-ci 84 | else 85 | npm test 86 | fi 87 | 88 | - name: Lint code 89 | if: steps.list_env.outputs.eslint != '' 90 | run: npm run lint 91 | 92 | - name: Collect code coverage 93 | uses: coverallsapp/github-action@master 94 | if: steps.list_env.outputs.nyc != '' 95 | with: 96 | github-token: ${{ secrets.GITHUB_TOKEN }} 97 | flag-name: run-${{ matrix.test_number }} 98 | parallel: true 99 | 100 | coverage: 101 | needs: test 102 | runs-on: ubuntu-latest 103 | steps: 104 | - name: Upload code coverage 105 | uses: coverallsapp/github-action@master 106 | with: 107 | github-token: ${{ secrets.github_token }} 108 | parallel-finished: true 109 | -------------------------------------------------------------------------------- /.github/workflows/scorecard.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecard supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | branch_protection_rule: 10 | # To guarantee Maintained check is occasionally updated. See 11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 12 | schedule: 13 | - cron: '16 21 * * 1' 14 | push: 15 | branches: [ "master" ] 16 | 17 | # Declare default permissions as read only. 18 | permissions: read-all 19 | 20 | jobs: 21 | analysis: 22 | name: Scorecard analysis 23 | runs-on: ubuntu-latest 24 | permissions: 25 | # Needed to upload the results to code-scanning dashboard. 26 | security-events: write 27 | # Needed to publish results and get a badge (see publish_results below). 28 | id-token: write 29 | # Uncomment the permissions below if installing in a private repository. 30 | # contents: read 31 | # actions: read 32 | 33 | steps: 34 | - name: "Checkout code" 35 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 36 | with: 37 | persist-credentials: false 38 | 39 | - name: "Run analysis" 40 | uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 41 | with: 42 | results_file: results.sarif 43 | results_format: sarif 44 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 45 | # - you want to enable the Branch-Protection check on a *public* repository, or 46 | # - you are installing Scorecard on a *private* repository 47 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. 48 | # repo_token: ${{ secrets.SCORECARD_TOKEN }} 49 | 50 | # Public repositories: 51 | # - Publish results to OpenSSF REST API for easy access by consumers 52 | # - Allows the repository to include the Scorecard badge. 53 | # - See https://github.com/ossf/scorecard-action#publishing-results. 54 | # For private repositories: 55 | # - `publish_results` will always be set to `false`, regardless 56 | # of the value entered here. 57 | publish_results: true 58 | 59 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 60 | # format to the repository Actions tab. 61 | - name: "Upload artifact" 62 | uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 63 | with: 64 | name: SARIF file 65 | path: results.sarif 66 | retention-days: 5 67 | 68 | # Upload the results to GitHub's code scanning dashboard. 69 | - name: "Upload to code-scanning" 70 | uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 71 | with: 72 | sarif_file: results.sarif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .nyc_output 2 | coverage 3 | node_modules 4 | npm-debug.log 5 | package-lock.json 6 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | 3.0.1 / 2025-03-26 2 | =================== 3 | 4 | * deps: mime-db@1.54.0 5 | 6 | 3.0.0 / 2024-08-31 7 | =================== 8 | 9 | * Drop support for node <18 10 | * deps: mime-db@1.53.0 11 | * resolve extension conflicts with mime-score (#119) 12 | * asc -> application/pgp-signature is now application/pgp-keys 13 | * mpp -> application/vnd.ms-project is now application/dash-patch+xml 14 | * ac -> application/vnd.nokia.n-gage.ac+xml is now application/pkix-attr-cert 15 | * bdoc -> application/x-bdoc is now application/bdoc 16 | * wmz -> application/x-msmetafile is now application/x-ms-wmz 17 | * xsl -> application/xslt+xml is now application/xml 18 | * wav -> audio/wave is now audio/wav 19 | * rtf -> text/rtf is now application/rtf 20 | * xml -> text/xml is now application/xml 21 | * mp4 -> video/mp4 is now application/mp4 22 | * mpg4 -> video/mp4 is now application/mp4 23 | 24 | 25 | 2.1.35 / 2022-03-12 26 | =================== 27 | 28 | * deps: mime-db@1.52.0 29 | - Add extensions from IANA for more `image/*` types 30 | - Add extension `.asc` to `application/pgp-keys` 31 | - Add extensions to various XML types 32 | - Add new upstream MIME types 33 | 34 | 2.1.34 / 2021-11-08 35 | =================== 36 | 37 | * deps: mime-db@1.51.0 38 | - Add new upstream MIME types 39 | 40 | 2.1.33 / 2021-10-01 41 | =================== 42 | 43 | * deps: mime-db@1.50.0 44 | - Add deprecated iWorks mime types and extensions 45 | - Add new upstream MIME types 46 | 47 | 2.1.32 / 2021-07-27 48 | =================== 49 | 50 | * deps: mime-db@1.49.0 51 | - Add extension `.trig` to `application/trig` 52 | - Add new upstream MIME types 53 | 54 | 2.1.31 / 2021-06-01 55 | =================== 56 | 57 | * deps: mime-db@1.48.0 58 | - Add extension `.mvt` to `application/vnd.mapbox-vector-tile` 59 | - Add new upstream MIME types 60 | 61 | 2.1.30 / 2021-04-02 62 | =================== 63 | 64 | * deps: mime-db@1.47.0 65 | - Add extension `.amr` to `audio/amr` 66 | - Remove ambigious extensions from IANA for `application/*+xml` types 67 | - Update primary extension to `.es` for `application/ecmascript` 68 | 69 | 2.1.29 / 2021-02-17 70 | =================== 71 | 72 | * deps: mime-db@1.46.0 73 | - Add extension `.amr` to `audio/amr` 74 | - Add extension `.m4s` to `video/iso.segment` 75 | - Add extension `.opus` to `audio/ogg` 76 | - Add new upstream MIME types 77 | 78 | 2.1.28 / 2021-01-01 79 | =================== 80 | 81 | * deps: mime-db@1.45.0 82 | - Add `application/ubjson` with extension `.ubj` 83 | - Add `image/avif` with extension `.avif` 84 | - Add `image/ktx2` with extension `.ktx2` 85 | - Add extension `.dbf` to `application/vnd.dbf` 86 | - Add extension `.rar` to `application/vnd.rar` 87 | - Add extension `.td` to `application/urc-targetdesc+xml` 88 | - Add new upstream MIME types 89 | - Fix extension of `application/vnd.apple.keynote` to be `.key` 90 | 91 | 2.1.27 / 2020-04-23 92 | =================== 93 | 94 | * deps: mime-db@1.44.0 95 | - Add charsets from IANA 96 | - Add extension `.cjs` to `application/node` 97 | - Add new upstream MIME types 98 | 99 | 2.1.26 / 2020-01-05 100 | =================== 101 | 102 | * deps: mime-db@1.43.0 103 | - Add `application/x-keepass2` with extension `.kdbx` 104 | - Add extension `.mxmf` to `audio/mobile-xmf` 105 | - Add extensions from IANA for `application/*+xml` types 106 | - Add new upstream MIME types 107 | 108 | 2.1.25 / 2019-11-12 109 | =================== 110 | 111 | * deps: mime-db@1.42.0 112 | - Add new upstream MIME types 113 | - Add `application/toml` with extension `.toml` 114 | - Add `image/vnd.ms-dds` with extension `.dds` 115 | 116 | 2.1.24 / 2019-04-20 117 | =================== 118 | 119 | * deps: mime-db@1.40.0 120 | - Add extensions from IANA for `model/*` types 121 | - Add `text/mdx` with extension `.mdx` 122 | 123 | 2.1.23 / 2019-04-17 124 | =================== 125 | 126 | * deps: mime-db@~1.39.0 127 | - Add extensions `.siv` and `.sieve` to `application/sieve` 128 | - Add new upstream MIME types 129 | 130 | 2.1.22 / 2019-02-14 131 | =================== 132 | 133 | * deps: mime-db@~1.38.0 134 | - Add extension `.nq` to `application/n-quads` 135 | - Add extension `.nt` to `application/n-triples` 136 | - Add new upstream MIME types 137 | 138 | 2.1.21 / 2018-10-19 139 | =================== 140 | 141 | * deps: mime-db@~1.37.0 142 | - Add extensions to HEIC image types 143 | - Add new upstream MIME types 144 | 145 | 2.1.20 / 2018-08-26 146 | =================== 147 | 148 | * deps: mime-db@~1.36.0 149 | - Add Apple file extensions from IANA 150 | - Add extensions from IANA for `image/*` types 151 | - Add new upstream MIME types 152 | 153 | 2.1.19 / 2018-07-17 154 | =================== 155 | 156 | * deps: mime-db@~1.35.0 157 | - Add extension `.csl` to `application/vnd.citationstyles.style+xml` 158 | - Add extension `.es` to `application/ecmascript` 159 | - Add extension `.owl` to `application/rdf+xml` 160 | - Add new upstream MIME types 161 | - Add UTF-8 as default charset for `text/turtle` 162 | 163 | 2.1.18 / 2018-02-16 164 | =================== 165 | 166 | * deps: mime-db@~1.33.0 167 | - Add `application/raml+yaml` with extension `.raml` 168 | - Add `application/wasm` with extension `.wasm` 169 | - Add `text/shex` with extension `.shex` 170 | - Add extensions for JPEG-2000 images 171 | - Add extensions from IANA for `message/*` types 172 | - Add new upstream MIME types 173 | - Update font MIME types 174 | - Update `text/hjson` to registered `application/hjson` 175 | 176 | 2.1.17 / 2017-09-01 177 | =================== 178 | 179 | * deps: mime-db@~1.30.0 180 | - Add `application/vnd.ms-outlook` 181 | - Add `application/x-arj` 182 | - Add extension `.mjs` to `application/javascript` 183 | - Add glTF types and extensions 184 | - Add new upstream MIME types 185 | - Add `text/x-org` 186 | - Add VirtualBox MIME types 187 | - Fix `source` records for `video/*` types that are IANA 188 | - Update `font/opentype` to registered `font/otf` 189 | 190 | 2.1.16 / 2017-07-24 191 | =================== 192 | 193 | * deps: mime-db@~1.29.0 194 | - Add `application/fido.trusted-apps+json` 195 | - Add extension `.wadl` to `application/vnd.sun.wadl+xml` 196 | - Add extension `.gz` to `application/gzip` 197 | - Add new upstream MIME types 198 | - Update extensions `.md` and `.markdown` to be `text/markdown` 199 | 200 | 2.1.15 / 2017-03-23 201 | =================== 202 | 203 | * deps: mime-db@~1.27.0 204 | - Add new mime types 205 | - Add `image/apng` 206 | 207 | 2.1.14 / 2017-01-14 208 | =================== 209 | 210 | * deps: mime-db@~1.26.0 211 | - Add new mime types 212 | 213 | 2.1.13 / 2016-11-18 214 | =================== 215 | 216 | * deps: mime-db@~1.25.0 217 | - Add new mime types 218 | 219 | 2.1.12 / 2016-09-18 220 | =================== 221 | 222 | * deps: mime-db@~1.24.0 223 | - Add new mime types 224 | - Add `audio/mp3` 225 | 226 | 2.1.11 / 2016-05-01 227 | =================== 228 | 229 | * deps: mime-db@~1.23.0 230 | - Add new mime types 231 | 232 | 2.1.10 / 2016-02-15 233 | =================== 234 | 235 | * deps: mime-db@~1.22.0 236 | - Add new mime types 237 | - Fix extension of `application/dash+xml` 238 | - Update primary extension for `audio/mp4` 239 | 240 | 2.1.9 / 2016-01-06 241 | ================== 242 | 243 | * deps: mime-db@~1.21.0 244 | - Add new mime types 245 | 246 | 2.1.8 / 2015-11-30 247 | ================== 248 | 249 | * deps: mime-db@~1.20.0 250 | - Add new mime types 251 | 252 | 2.1.7 / 2015-09-20 253 | ================== 254 | 255 | * deps: mime-db@~1.19.0 256 | - Add new mime types 257 | 258 | 2.1.6 / 2015-09-03 259 | ================== 260 | 261 | * deps: mime-db@~1.18.0 262 | - Add new mime types 263 | 264 | 2.1.5 / 2015-08-20 265 | ================== 266 | 267 | * deps: mime-db@~1.17.0 268 | - Add new mime types 269 | 270 | 2.1.4 / 2015-07-30 271 | ================== 272 | 273 | * deps: mime-db@~1.16.0 274 | - Add new mime types 275 | 276 | 2.1.3 / 2015-07-13 277 | ================== 278 | 279 | * deps: mime-db@~1.15.0 280 | - Add new mime types 281 | 282 | 2.1.2 / 2015-06-25 283 | ================== 284 | 285 | * deps: mime-db@~1.14.0 286 | - Add new mime types 287 | 288 | 2.1.1 / 2015-06-08 289 | ================== 290 | 291 | * perf: fix deopt during mapping 292 | 293 | 2.1.0 / 2015-06-07 294 | ================== 295 | 296 | * Fix incorrectly treating extension-less file name as extension 297 | - i.e. `'path/to/json'` will no longer return `application/json` 298 | * Fix `.charset(type)` to accept parameters 299 | * Fix `.charset(type)` to match case-insensitive 300 | * Improve generation of extension to MIME mapping 301 | * Refactor internals for readability and no argument reassignment 302 | * Prefer `application/*` MIME types from the same source 303 | * Prefer any type over `application/octet-stream` 304 | * deps: mime-db@~1.13.0 305 | - Add nginx as a source 306 | - Add new mime types 307 | 308 | 2.0.14 / 2015-06-06 309 | =================== 310 | 311 | * deps: mime-db@~1.12.0 312 | - Add new mime types 313 | 314 | 2.0.13 / 2015-05-31 315 | =================== 316 | 317 | * deps: mime-db@~1.11.0 318 | - Add new mime types 319 | 320 | 2.0.12 / 2015-05-19 321 | =================== 322 | 323 | * deps: mime-db@~1.10.0 324 | - Add new mime types 325 | 326 | 2.0.11 / 2015-05-05 327 | =================== 328 | 329 | * deps: mime-db@~1.9.1 330 | - Add new mime types 331 | 332 | 2.0.10 / 2015-03-13 333 | =================== 334 | 335 | * deps: mime-db@~1.8.0 336 | - Add new mime types 337 | 338 | 2.0.9 / 2015-02-09 339 | ================== 340 | 341 | * deps: mime-db@~1.7.0 342 | - Add new mime types 343 | - Community extensions ownership transferred from `node-mime` 344 | 345 | 2.0.8 / 2015-01-29 346 | ================== 347 | 348 | * deps: mime-db@~1.6.0 349 | - Add new mime types 350 | 351 | 2.0.7 / 2014-12-30 352 | ================== 353 | 354 | * deps: mime-db@~1.5.0 355 | - Add new mime types 356 | - Fix various invalid MIME type entries 357 | 358 | 2.0.6 / 2014-12-30 359 | ================== 360 | 361 | * deps: mime-db@~1.4.0 362 | - Add new mime types 363 | - Fix various invalid MIME type entries 364 | - Remove example template MIME types 365 | 366 | 2.0.5 / 2014-12-29 367 | ================== 368 | 369 | * deps: mime-db@~1.3.1 370 | - Fix missing extensions 371 | 372 | 2.0.4 / 2014-12-10 373 | ================== 374 | 375 | * deps: mime-db@~1.3.0 376 | - Add new mime types 377 | 378 | 2.0.3 / 2014-11-09 379 | ================== 380 | 381 | * deps: mime-db@~1.2.0 382 | - Add new mime types 383 | 384 | 2.0.2 / 2014-09-28 385 | ================== 386 | 387 | * deps: mime-db@~1.1.0 388 | - Add new mime types 389 | - Update charsets 390 | 391 | 2.0.1 / 2014-09-07 392 | ================== 393 | 394 | * Support Node.js 0.6 395 | 396 | 2.0.0 / 2014-09-02 397 | ================== 398 | 399 | * Use `mime-db` 400 | * Remove `.define()` 401 | 402 | 1.0.2 / 2014-08-04 403 | ================== 404 | 405 | * Set charset=utf-8 for `text/javascript` 406 | 407 | 1.0.1 / 2014-06-24 408 | ================== 409 | 410 | * Add `text/jsx` type 411 | 412 | 1.0.0 / 2014-05-12 413 | ================== 414 | 415 | * Return `false` for unknown types 416 | * Set charset=utf-8 for `application/json` 417 | 418 | 0.1.0 / 2014-05-02 419 | ================== 420 | 421 | * Initial release 422 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2014 Jonathan Ong 4 | Copyright (c) 2015 Douglas Christopher Wilson 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | 'Software'), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mime-types 2 | 3 | [![NPM Version][npm-version-image]][npm-url] 4 | [![NPM Downloads][npm-downloads-image]][npm-url] 5 | [![Node.js Version][node-version-image]][node-version-url] 6 | [![Build Status][ci-image]][ci-url] 7 | [![Test Coverage][coveralls-image]][coveralls-url] 8 | 9 | The ultimate javascript content-type utility. 10 | 11 | Similar to [the `mime@1.x` module](https://www.npmjs.com/package/mime), except: 12 | 13 | - __No fallbacks.__ Instead of naively returning the first available type, 14 | `mime-types` simply returns `false`, so do 15 | `var type = mime.lookup('unrecognized') || 'application/octet-stream'`. 16 | - No `new Mime()` business, so you could do `var lookup = require('mime-types').lookup`. 17 | - No `.define()` functionality 18 | - Bug fixes for `.lookup(path)` 19 | 20 | Otherwise, the API is compatible with `mime` 1.x. 21 | 22 | ## Install 23 | 24 | This is a [Node.js](https://nodejs.org/en/) module available through the 25 | [npm registry](https://www.npmjs.com/). Installation is done using the 26 | [`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): 27 | 28 | ```sh 29 | $ npm install mime-types 30 | ``` 31 | 32 | ## Note on MIME Type Data and Semver 33 | 34 | This package considers the programmatic api as the semver compatibility. Additionally, the package which provides the MIME data 35 | for this package (`mime-db`) *also* considers it's programmatic api as the semver contract. This means the MIME type resolution is *not* considered 36 | in the semver bumps. 37 | 38 | In the past the version of `mime-db` was pinned to give two decision points when adopting MIME data changes. This is no longer true. We still update the 39 | `mime-db` package here as a `minor` release when necessary, but will use a `^` range going forward. This means that if you want to pin your `mime-db` data 40 | you will need to do it in your application. While this expectation was not set in docs until now, it is how the pacakge operated, so we do not feel this is 41 | a breaking change. 42 | 43 | If you wish to pin your `mime-db` version you can do that with overrides via your package manager of choice. See their documentation for how to correctly configure that. 44 | 45 | ## Adding Types 46 | 47 | All mime types are based on [mime-db](https://www.npmjs.com/package/mime-db), 48 | so open a PR there if you'd like to add mime types. 49 | 50 | ## API 51 | 52 | ```js 53 | var mime = require('mime-types') 54 | ``` 55 | 56 | All functions return `false` if input is invalid or not found. 57 | 58 | ### mime.lookup(path) 59 | 60 | Lookup the content-type associated with a file. 61 | 62 | ```js 63 | mime.lookup('json') // 'application/json' 64 | mime.lookup('.md') // 'text/markdown' 65 | mime.lookup('file.html') // 'text/html' 66 | mime.lookup('folder/file.js') // 'application/javascript' 67 | mime.lookup('folder/.htaccess') // false 68 | 69 | mime.lookup('cats') // false 70 | ``` 71 | 72 | ### mime.contentType(type) 73 | 74 | Create a full content-type header given a content-type or extension. 75 | When given an extension, `mime.lookup` is used to get the matching 76 | content-type, otherwise the given content-type is used. Then if the 77 | content-type does not already have a `charset` parameter, `mime.charset` 78 | is used to get the default charset and add to the returned content-type. 79 | 80 | ```js 81 | mime.contentType('markdown') // 'text/x-markdown; charset=utf-8' 82 | mime.contentType('file.json') // 'application/json; charset=utf-8' 83 | mime.contentType('text/html') // 'text/html; charset=utf-8' 84 | mime.contentType('text/html; charset=iso-8859-1') // 'text/html; charset=iso-8859-1' 85 | 86 | // from a full path 87 | mime.contentType(path.extname('/path/to/file.json')) // 'application/json; charset=utf-8' 88 | ``` 89 | 90 | ### mime.extension(type) 91 | 92 | Get the default extension for a content-type. 93 | 94 | ```js 95 | mime.extension('application/octet-stream') // 'bin' 96 | ``` 97 | 98 | ### mime.charset(type) 99 | 100 | Lookup the implied default charset of a content-type. 101 | 102 | ```js 103 | mime.charset('text/markdown') // 'UTF-8' 104 | ``` 105 | 106 | ### var type = mime.types[extension] 107 | 108 | A map of content-types by extension. 109 | 110 | ### [extensions...] = mime.extensions[type] 111 | 112 | A map of extensions by content-type. 113 | 114 | ## License 115 | 116 | [MIT](LICENSE) 117 | 118 | [ci-image]: https://badgen.net/github/checks/jshttp/mime-types/master?label=ci 119 | [ci-url]: https://github.com/jshttp/mime-types/actions/workflows/ci.yml 120 | [coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/mime-types/master 121 | [coveralls-url]: https://coveralls.io/r/jshttp/mime-types?branch=master 122 | [node-version-image]: https://badgen.net/npm/node/mime-types 123 | [node-version-url]: https://nodejs.org/en/download 124 | [npm-downloads-image]: https://badgen.net/npm/dm/mime-types 125 | [npm-url]: https://npmjs.org/package/mime-types 126 | [npm-version-image]: https://badgen.net/npm/v/mime-types 127 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * mime-types 3 | * Copyright(c) 2014 Jonathan Ong 4 | * Copyright(c) 2015 Douglas Christopher Wilson 5 | * MIT Licensed 6 | */ 7 | 8 | 'use strict' 9 | 10 | /** 11 | * Module dependencies. 12 | * @private 13 | */ 14 | 15 | var db = require('mime-db') 16 | var extname = require('path').extname 17 | var mimeScore = require('./mimeScore') 18 | 19 | /** 20 | * Module variables. 21 | * @private 22 | */ 23 | 24 | var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/ 25 | var TEXT_TYPE_REGEXP = /^text\//i 26 | 27 | /** 28 | * Module exports. 29 | * @public 30 | */ 31 | 32 | exports.charset = charset 33 | exports.charsets = { lookup: charset } 34 | exports.contentType = contentType 35 | exports.extension = extension 36 | exports.extensions = Object.create(null) 37 | exports.lookup = lookup 38 | exports.types = Object.create(null) 39 | exports._extensionConflicts = [] 40 | 41 | // Populate the extensions/types maps 42 | populateMaps(exports.extensions, exports.types) 43 | 44 | /** 45 | * Get the default charset for a MIME type. 46 | * 47 | * @param {string} type 48 | * @return {boolean|string} 49 | */ 50 | 51 | function charset (type) { 52 | if (!type || typeof type !== 'string') { 53 | return false 54 | } 55 | 56 | // TODO: use media-typer 57 | var match = EXTRACT_TYPE_REGEXP.exec(type) 58 | var mime = match && db[match[1].toLowerCase()] 59 | 60 | if (mime && mime.charset) { 61 | return mime.charset 62 | } 63 | 64 | // default text/* to utf-8 65 | if (match && TEXT_TYPE_REGEXP.test(match[1])) { 66 | return 'UTF-8' 67 | } 68 | 69 | return false 70 | } 71 | 72 | /** 73 | * Create a full Content-Type header given a MIME type or extension. 74 | * 75 | * @param {string} str 76 | * @return {boolean|string} 77 | */ 78 | 79 | function contentType (str) { 80 | // TODO: should this even be in this module? 81 | if (!str || typeof str !== 'string') { 82 | return false 83 | } 84 | 85 | var mime = str.indexOf('/') === -1 ? exports.lookup(str) : str 86 | 87 | if (!mime) { 88 | return false 89 | } 90 | 91 | // TODO: use content-type or other module 92 | if (mime.indexOf('charset') === -1) { 93 | var charset = exports.charset(mime) 94 | if (charset) mime += '; charset=' + charset.toLowerCase() 95 | } 96 | 97 | return mime 98 | } 99 | 100 | /** 101 | * Get the default extension for a MIME type. 102 | * 103 | * @param {string} type 104 | * @return {boolean|string} 105 | */ 106 | 107 | function extension (type) { 108 | if (!type || typeof type !== 'string') { 109 | return false 110 | } 111 | 112 | // TODO: use media-typer 113 | var match = EXTRACT_TYPE_REGEXP.exec(type) 114 | 115 | // get extensions 116 | var exts = match && exports.extensions[match[1].toLowerCase()] 117 | 118 | if (!exts || !exts.length) { 119 | return false 120 | } 121 | 122 | return exts[0] 123 | } 124 | 125 | /** 126 | * Lookup the MIME type for a file path/extension. 127 | * 128 | * @param {string} path 129 | * @return {boolean|string} 130 | */ 131 | 132 | function lookup (path) { 133 | if (!path || typeof path !== 'string') { 134 | return false 135 | } 136 | 137 | // get the extension ("ext" or ".ext" or full path) 138 | var extension = extname('x.' + path) 139 | .toLowerCase() 140 | .slice(1) 141 | 142 | if (!extension) { 143 | return false 144 | } 145 | 146 | return exports.types[extension] || false 147 | } 148 | 149 | /** 150 | * Populate the extensions and types maps. 151 | * @private 152 | */ 153 | 154 | function populateMaps (extensions, types) { 155 | Object.keys(db).forEach(function forEachMimeType (type) { 156 | var mime = db[type] 157 | var exts = mime.extensions 158 | 159 | if (!exts || !exts.length) { 160 | return 161 | } 162 | 163 | // mime -> extensions 164 | extensions[type] = exts 165 | 166 | // extension -> mime 167 | for (var i = 0; i < exts.length; i++) { 168 | var extension = exts[i] 169 | types[extension] = _preferredType(extension, types[extension], type) 170 | 171 | // DELETE (eventually): Capture extension->type maps that change as a 172 | // result of switching to mime-score. This is just to help make reviewing 173 | // PR #119 easier, and can be removed once that PR is approved. 174 | const legacyType = _preferredTypeLegacy( 175 | extension, 176 | types[extension], 177 | type 178 | ) 179 | if (legacyType !== types[extension]) { 180 | exports._extensionConflicts.push([extension, legacyType, types[extension]]) 181 | } 182 | } 183 | }) 184 | } 185 | 186 | // Resolve type conflict using mime-score 187 | function _preferredType (ext, type0, type1) { 188 | var score0 = type0 ? mimeScore(type0, db[type0].source) : 0 189 | var score1 = type1 ? mimeScore(type1, db[type1].source) : 0 190 | 191 | return score0 > score1 ? type0 : type1 192 | } 193 | 194 | // Resolve type conflict using pre-mime-score logic 195 | function _preferredTypeLegacy (ext, type0, type1) { 196 | var SOURCE_RANK = ['nginx', 'apache', undefined, 'iana'] 197 | 198 | var score0 = type0 ? SOURCE_RANK.indexOf(db[type0].source) : 0 199 | var score1 = type1 ? SOURCE_RANK.indexOf(db[type1].source) : 0 200 | 201 | if ( 202 | exports.types[extension] !== 'application/octet-stream' && 203 | (score0 > score1 || 204 | (score0 === score1 && 205 | exports.types[extension]?.slice(0, 12) === 'application/')) 206 | ) { 207 | return type0 208 | } 209 | 210 | return score0 > score1 ? type0 : type1 211 | } 212 | -------------------------------------------------------------------------------- /mimeScore.js: -------------------------------------------------------------------------------- 1 | // 'mime-score' back-ported to CommonJS 2 | 3 | // Score RFC facets (see https://tools.ietf.org/html/rfc6838#section-3) 4 | var FACET_SCORES = { 5 | 'prs.': 100, 6 | 'x-': 200, 7 | 'x.': 300, 8 | 'vnd.': 400, 9 | default: 900 10 | } 11 | 12 | // Score mime source (Logic originally from `jshttp/mime-types` module) 13 | var SOURCE_SCORES = { 14 | nginx: 10, 15 | apache: 20, 16 | iana: 40, 17 | default: 30 // definitions added by `jshttp/mime-db` project? 18 | } 19 | 20 | var TYPE_SCORES = { 21 | // prefer application/xml over text/xml 22 | // prefer application/rtf over text/rtf 23 | application: 1, 24 | 25 | // prefer font/woff over application/font-woff 26 | font: 2, 27 | 28 | default: 0 29 | } 30 | 31 | /** 32 | * Get each component of the score for a mime type. The sum of these is the 33 | * total score. The higher the score, the more "official" the type. 34 | */ 35 | module.exports = function mimeScore (mimeType, source = 'default') { 36 | if (mimeType === 'application/octet-stream') { 37 | return 0 38 | } 39 | 40 | const [type, subtype] = mimeType.split('/') 41 | 42 | const facet = subtype.replace(/(\.|x-).*/, '$1') 43 | 44 | const facetScore = FACET_SCORES[facet] || FACET_SCORES.default 45 | const sourceScore = SOURCE_SCORES[source] || SOURCE_SCORES.default 46 | const typeScore = TYPE_SCORES[type] || TYPE_SCORES.default 47 | 48 | // All else being equal prefer shorter types 49 | const lengthScore = 1 - mimeType.length / 100 50 | 51 | return facetScore + sourceScore + typeScore + lengthScore 52 | } 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mime-types", 3 | "description": "The ultimate javascript content-type utility.", 4 | "version": "3.0.1", 5 | "contributors": [ 6 | "Douglas Christopher Wilson ", 7 | "Jeremiah Senkpiel (https://searchbeam.jit.su)", 8 | "Jonathan Ong (http://jongleberry.com)" 9 | ], 10 | "license": "MIT", 11 | "keywords": [ 12 | "mime", 13 | "types" 14 | ], 15 | "repository": "jshttp/mime-types", 16 | "dependencies": { 17 | "mime-db": "^1.54.0" 18 | }, 19 | "devDependencies": { 20 | "eslint": "8.33.0", 21 | "eslint-config-standard": "14.1.1", 22 | "eslint-plugin-import": "2.27.5", 23 | "eslint-plugin-markdown": "3.0.0", 24 | "eslint-plugin-node": "11.1.0", 25 | "eslint-plugin-promise": "6.1.1", 26 | "eslint-plugin-standard": "4.1.0", 27 | "mocha": "10.2.0", 28 | "nyc": "15.1.0" 29 | }, 30 | "files": [ 31 | "HISTORY.md", 32 | "LICENSE", 33 | "index.js", 34 | "mimeScore.js" 35 | ], 36 | "engines": { 37 | "node": ">= 0.6" 38 | }, 39 | "scripts": { 40 | "lint": "eslint .", 41 | "test": "mocha --reporter spec test/test.js", 42 | "test-ci": "nyc --reporter=lcov --reporter=text npm test", 43 | "test-cov": "nyc --reporter=html --reporter=text npm test" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | mocha: true 3 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var mimeTypes = require('..') 3 | 4 | describe('mimeTypes', function () { 5 | describe('.charset(type)', function () { 6 | it('should return "UTF-8" for "application/json"', function () { 7 | assert.strictEqual(mimeTypes.charset('application/json'), 'UTF-8') 8 | }) 9 | 10 | it('should return "UTF-8" for "application/json; foo=bar"', function () { 11 | assert.strictEqual(mimeTypes.charset('application/json; foo=bar'), 'UTF-8') 12 | }) 13 | 14 | it('should return "UTF-8" for "application/javascript"', function () { 15 | assert.strictEqual(mimeTypes.charset('application/javascript'), 'UTF-8') 16 | }) 17 | 18 | it('should return "UTF-8" for "application/JavaScript"', function () { 19 | assert.strictEqual(mimeTypes.charset('application/JavaScript'), 'UTF-8') 20 | }) 21 | 22 | it('should return "UTF-8" for "text/html"', function () { 23 | assert.strictEqual(mimeTypes.charset('text/html'), 'UTF-8') 24 | }) 25 | 26 | it('should return "UTF-8" for "TEXT/HTML"', function () { 27 | assert.strictEqual(mimeTypes.charset('TEXT/HTML'), 'UTF-8') 28 | }) 29 | 30 | it('should return "UTF-8" for any text/*', function () { 31 | assert.strictEqual(mimeTypes.charset('text/x-bogus'), 'UTF-8') 32 | }) 33 | 34 | it('should return false for unknown types', function () { 35 | assert.strictEqual(mimeTypes.charset('application/x-bogus'), false) 36 | }) 37 | 38 | it('should return false for any application/octet-stream', function () { 39 | assert.strictEqual(mimeTypes.charset('application/octet-stream'), false) 40 | }) 41 | 42 | it('should return false for invalid arguments', function () { 43 | assert.strictEqual(mimeTypes.charset({}), false) 44 | assert.strictEqual(mimeTypes.charset(null), false) 45 | assert.strictEqual(mimeTypes.charset(true), false) 46 | assert.strictEqual(mimeTypes.charset(42), false) 47 | }) 48 | }) 49 | 50 | describe('.contentType(extension)', function () { 51 | it('should return content-type for "html"', function () { 52 | assert.strictEqual(mimeTypes.contentType('html'), 'text/html; charset=utf-8') 53 | }) 54 | 55 | it('should return content-type for ".html"', function () { 56 | assert.strictEqual(mimeTypes.contentType('.html'), 'text/html; charset=utf-8') 57 | }) 58 | 59 | it('should return content-type for "jade"', function () { 60 | assert.strictEqual(mimeTypes.contentType('jade'), 'text/jade; charset=utf-8') 61 | }) 62 | 63 | it('should return content-type for "json"', function () { 64 | assert.strictEqual(mimeTypes.contentType('json'), 'application/json; charset=utf-8') 65 | }) 66 | 67 | it('should return false for unknown extensions', function () { 68 | assert.strictEqual(mimeTypes.contentType('bogus'), false) 69 | }) 70 | 71 | it('should return false for invalid arguments', function () { 72 | assert.strictEqual(mimeTypes.contentType({}), false) 73 | assert.strictEqual(mimeTypes.contentType(null), false) 74 | assert.strictEqual(mimeTypes.contentType(true), false) 75 | assert.strictEqual(mimeTypes.contentType(42), false) 76 | }) 77 | }) 78 | 79 | describe('.contentType(type)', function () { 80 | it('should attach charset to "application/json"', function () { 81 | assert.strictEqual(mimeTypes.contentType('application/json'), 'application/json; charset=utf-8') 82 | }) 83 | 84 | it('should attach charset to "application/json; foo=bar"', function () { 85 | assert.strictEqual(mimeTypes.contentType('application/json; foo=bar'), 'application/json; foo=bar; charset=utf-8') 86 | }) 87 | 88 | it('should attach charset to "TEXT/HTML"', function () { 89 | assert.strictEqual(mimeTypes.contentType('TEXT/HTML'), 'TEXT/HTML; charset=utf-8') 90 | }) 91 | 92 | it('should attach charset to "text/html"', function () { 93 | assert.strictEqual(mimeTypes.contentType('text/html'), 'text/html; charset=utf-8') 94 | }) 95 | 96 | it('should not alter "text/html; charset=iso-8859-1"', function () { 97 | assert.strictEqual(mimeTypes.contentType('text/html; charset=iso-8859-1'), 'text/html; charset=iso-8859-1') 98 | }) 99 | 100 | it('should return type for unknown types', function () { 101 | assert.strictEqual(mimeTypes.contentType('application/x-bogus'), 'application/x-bogus') 102 | }) 103 | }) 104 | 105 | describe('.extension(type)', function () { 106 | it('should return extension for mime type', function () { 107 | assert.strictEqual(mimeTypes.extension('text/html'), 'html') 108 | assert.strictEqual(mimeTypes.extension(' text/html'), 'html') 109 | assert.strictEqual(mimeTypes.extension('text/html '), 'html') 110 | }) 111 | 112 | it('should return false for unknown type', function () { 113 | assert.strictEqual(mimeTypes.extension('application/x-bogus'), false) 114 | }) 115 | 116 | it('should return false for non-type string', function () { 117 | assert.strictEqual(mimeTypes.extension('bogus'), false) 118 | }) 119 | 120 | it('should return false for non-strings', function () { 121 | assert.strictEqual(mimeTypes.extension(null), false) 122 | assert.strictEqual(mimeTypes.extension(undefined), false) 123 | assert.strictEqual(mimeTypes.extension(42), false) 124 | assert.strictEqual(mimeTypes.extension({}), false) 125 | }) 126 | 127 | it('should return extension for mime type with parameters', function () { 128 | assert.strictEqual(mimeTypes.extension('text/html;charset=UTF-8'), 'html') 129 | assert.strictEqual(mimeTypes.extension('text/HTML; charset=UTF-8'), 'html') 130 | assert.strictEqual(mimeTypes.extension('text/html; charset=UTF-8'), 'html') 131 | assert.strictEqual(mimeTypes.extension('text/html; charset=UTF-8 '), 'html') 132 | assert.strictEqual(mimeTypes.extension('text/html ; charset=UTF-8'), 'html') 133 | }) 134 | }) 135 | 136 | describe('.lookup(extension)', function () { 137 | it('should return mime type for ".html"', function () { 138 | assert.strictEqual(mimeTypes.lookup('.html'), 'text/html') 139 | }) 140 | 141 | it('should return mime type for ".js"', function () { 142 | assert.strictEqual(mimeTypes.lookup('.js'), 'text/javascript') 143 | }) 144 | 145 | it('should return mime type for ".json"', function () { 146 | assert.strictEqual(mimeTypes.lookup('.json'), 'application/json') 147 | }) 148 | 149 | it('should return mime type for ".rtf"', function () { 150 | assert.strictEqual(mimeTypes.lookup('.rtf'), 'application/rtf') 151 | }) 152 | 153 | it('should return mime type for ".txt"', function () { 154 | assert.strictEqual(mimeTypes.lookup('.txt'), 'text/plain') 155 | }) 156 | 157 | it('should return mime type for ".xml"', function () { 158 | assert.strictEqual(mimeTypes.lookup('.xml'), 'application/xml') 159 | }) 160 | 161 | it('should work without the leading dot', function () { 162 | assert.strictEqual(mimeTypes.lookup('html'), 'text/html') 163 | assert.strictEqual(mimeTypes.lookup('xml'), 'application/xml') 164 | }) 165 | 166 | it('should be case insensitive', function () { 167 | assert.strictEqual(mimeTypes.lookup('HTML'), 'text/html') 168 | assert.strictEqual(mimeTypes.lookup('.Xml'), 'application/xml') 169 | }) 170 | 171 | it('should return false for unknown extension', function () { 172 | assert.strictEqual(mimeTypes.lookup('.bogus'), false) 173 | assert.strictEqual(mimeTypes.lookup('bogus'), false) 174 | }) 175 | 176 | it('should return false for non-strings', function () { 177 | assert.strictEqual(mimeTypes.lookup(null), false) 178 | assert.strictEqual(mimeTypes.lookup(undefined), false) 179 | assert.strictEqual(mimeTypes.lookup(42), false) 180 | assert.strictEqual(mimeTypes.lookup({}), false) 181 | }) 182 | }) 183 | 184 | describe('.lookup(path)', function () { 185 | it('should return mime type for file name', function () { 186 | assert.strictEqual(mimeTypes.lookup('page.html'), 'text/html') 187 | }) 188 | 189 | it('should return mime type for relative path', function () { 190 | assert.strictEqual(mimeTypes.lookup('path/to/page.html'), 'text/html') 191 | assert.strictEqual(mimeTypes.lookup('path\\to\\page.html'), 'text/html') 192 | }) 193 | 194 | it('should return mime type for absolute path', function () { 195 | assert.strictEqual(mimeTypes.lookup('/path/to/page.html'), 'text/html') 196 | assert.strictEqual(mimeTypes.lookup('C:\\path\\to\\page.html'), 'text/html') 197 | }) 198 | 199 | it('should be case insensitive', function () { 200 | assert.strictEqual(mimeTypes.lookup('/path/to/PAGE.HTML'), 'text/html') 201 | assert.strictEqual(mimeTypes.lookup('C:\\path\\to\\PAGE.HTML'), 'text/html') 202 | }) 203 | 204 | it('should return false for unknown extension', function () { 205 | assert.strictEqual(mimeTypes.lookup('/path/to/file.bogus'), false) 206 | }) 207 | 208 | it('should return false for path without extension', function () { 209 | assert.strictEqual(mimeTypes.lookup('/path/to/json'), false) 210 | }) 211 | 212 | describe('path with dotfile', function () { 213 | it('should return false when extension-less', function () { 214 | assert.strictEqual(mimeTypes.lookup('/path/to/.json'), false) 215 | }) 216 | 217 | it('should return mime type when there is extension', function () { 218 | assert.strictEqual(mimeTypes.lookup('/path/to/.config.json'), 'application/json') 219 | }) 220 | 221 | it('should return mime type when there is extension, but no path', function () { 222 | assert.strictEqual( 223 | mimeTypes.lookup('.config.json'), 224 | 'application/json' 225 | ) 226 | }) 227 | }) 228 | }) 229 | 230 | // Note the changes in extension->type mapping that result from using mime-score 231 | describe('extension conflicts', function () { 232 | console.warn('Mime-score logic changes extension->type mappings for the following:') 233 | for (var [extension, legacy, current] of mimeTypes._extensionConflicts) { 234 | console.warn(`* ${extension} -> ${legacy} is now ${current}`) 235 | } 236 | }) 237 | }) 238 | --------------------------------------------------------------------------------