diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index c18b5f2..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-# EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs
-# http://editorconfig.org
-
-root = true
-
-[*]
-indent_style = space
-indent_size = 4
-charset = utf-8
-trim_trailing_whitespace = true
-insert_final_newline = true
-
-[*{.yml}]
-indent_size = 2
-
-[*.md]
-trim_trailing_whitespace = false
-max_line_length = off
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0b20bf1..a4b08b1 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -14,10 +14,10 @@ jobs:
name: Release
runs-on: ubuntu-latest
permissions:
- contents: write # to be able to publish a GitHub release
- issues: write # to be able to comment on released issues
+ contents: write # to be able to publish a GitHub release
+ issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
- id-token: write # to enable use of OIDC for npm provenance
+ id-token: write # to enable use of OIDC for npm provenance
steps:
- name: Checkout repository
uses: actions/checkout@v4
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
deleted file mode 100644
index 2ab4aa5..0000000
--- a/.github/workflows/stale.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-name: "Close stale issues and PRs"
-on:
- schedule:
- - cron: "0 0 * * *"
-
-jobs:
- stale:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/stale@v3
- with:
- repo-token: ${{ secrets.GITHUB_TOKEN }}
- days-before-stale: 60
- days-before-close: 7
- stale-issue-message: >
- This issue has been automatically marked as stale because it has not had
- recent activity in the past 60 days. It will be closed within 7 days if no further activity occurs. If the issue persists please comment here to bump your issue.
- Thank You - React Dropzone Maintaners
- stale-pr-message: >
- This PR has been automatically marked as stale because it has not had
- recent activity in the past 60 days. It will be closed within 7 days if no further activity occurs. If the issue persists please comment here to bump your issue.
- Thank You - React Dropzone Maintaners
- stale-issue-label: stale
- stale-pr-label: stale
diff --git a/README.md b/README.md
index 00d8207..5758af5 100644
--- a/README.md
+++ b/README.md
@@ -11,14 +11,13 @@
# Table of Contents
-* [Installation](#installation)
-* [Usage](#usage)
-* [Browser Support](#browser-support)
-* [Contribute](#contribute)
-* [Credits](#credits)
-* [Support](#support)
-* [License](#license)
-
+- [Installation](#installation)
+- [Usage](#usage)
+- [Browser Support](#browser-support)
+- [Contribute](#contribute)
+- [Credits](#credits)
+- [Support](#support)
+- [License](#license)
## Installation
@@ -33,7 +32,7 @@ npm add file-selector
If you are using a bundler such as [Vite](https://vite.dev/) or [Webpack](https://webpack.js.org/) you can import the package directly:
```js
-import {fromEvent} from 'file-selector';
+import { fromEvent } from "file-selector";
```
### Browser
@@ -46,7 +45,7 @@ If you want to use a CDN, you can use [Skypack](https://www.skypack.dev/), or an
```html
```
@@ -56,7 +55,7 @@ Self hosting is also possible, make sure to copy or link the contents of the NPM
```html
```
@@ -66,17 +65,17 @@ To avoid repeating the import path and get an experience similar to a bundler yo
```html
```
@@ -85,64 +84,69 @@ To avoid repeating the import path and get an experience similar to a bundler yo
Convert a [DragEvent](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent) to File objects:
```js
-import {fromEvent} from 'file-selector';
+import { fromEvent } from "file-selector";
-document.addEventListener('drop', async (event) => {
- const files = await fromEvent(event);
- console.log(files);
+document.addEventListener("drop", async (event) => {
+ const files = await fromEvent(event);
+ console.log(files);
});
```
Convert a [change event](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event) for an input type file to File objects:
```js
-import {fromEvent} from 'file-selector';
+import { fromEvent } from "file-selector";
-const input = document.getElementById('myInput');
-input.addEventListener('change', async (event) => {
- const files = await fromEvent(event);
- console.log(files);
+const input = document.getElementById("myInput");
+input.addEventListener("change", async (event) => {
+ const files = await fromEvent(event);
+ console.log(files);
});
```
Convert [FileSystemFileHandle](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileHandle) items to File objects:
```js
-import {fromEvent} from 'file-selector';
+import { fromEvent } from "file-selector";
-const handles = await window.showOpenFilePicker({multiple: true});
+const handles = await window.showOpenFilePicker({ multiple: true });
const files = await fromEvent(handles);
console.log(files);
```
-> [!NOTE]
+> [!NOTE]
> The above is experimental and subject to change.
## Browser Support
+
Most browser support basic File selection with drag 'n' drop or file input:
-* [File API](https://developer.mozilla.org/en-US/docs/Web/API/File#Browser_compatibility)
-* [Drag Event](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent#Browser_compatibility)
-* [DataTransfer](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer#Browser_compatibility)
-* [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Browser_compatibility)
+
+- [File API](https://developer.mozilla.org/en-US/docs/Web/API/File#Browser_compatibility)
+- [Drag Event](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent#Browser_compatibility)
+- [DataTransfer](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer#Browser_compatibility)
+- [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Browser_compatibility)
For folder drop we use the [FileSystem API](https://developer.mozilla.org/en-US/docs/Web/API/FileSystem) which has very limited support:
-* [DataTransferItem.getAsFile()](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/getAsFile#Browser_compatibility)
-* [DataTransferItem.webkitGetAsEntry()](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/webkitGetAsEntry#Browser_compatibility)
-* [FileSystemEntry](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry#Browser_compatibility)
-* [FileSystemFileEntry.file()](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileEntry/file#Browser_compatibility)
-* [FileSystemDirectoryEntry.createReader()](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryEntry/createReader#Browser_compatibility)
-* [FileSystemDirectoryReader.readEntries()](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryReader/readEntries#Browser_compatibility)
+- [DataTransferItem.getAsFile()](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/getAsFile#Browser_compatibility)
+- [DataTransferItem.webkitGetAsEntry()](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/webkitGetAsEntry#Browser_compatibility)
+- [FileSystemEntry](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry#Browser_compatibility)
+- [FileSystemFileEntry.file()](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileEntry/file#Browser_compatibility)
+- [FileSystemDirectoryEntry.createReader()](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryEntry/createReader#Browser_compatibility)
+- [FileSystemDirectoryReader.readEntries()](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryReader/readEntries#Browser_compatibility)
## Contribute
+
Checkout the organization [CONTRIBUTING.md](https://github.com/react-dropzone/.github/blob/main/CONTRIBUTING.md).
## Credits
-* [html5-file-selector](https://github.com/quarklemotion/html5-file-selector)
+
+- [html5-file-selector](https://github.com/quarklemotion/html5-file-selector)
## Support
### Backers
+
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/react-dropzone#backer)]
@@ -158,6 +162,7 @@ Support us with a monthly donation and help us continue our activities. [[Become
### Sponsors
+
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/react-dropzone#sponsor)]
@@ -173,4 +178,5 @@ Become a sponsor and get your logo on our README on Github with a link to your s
## License
+
MIT
diff --git a/eslint.config.js b/eslint.config.js
index 833eea3..4cc681a 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -1,14 +1,16 @@
-import eslint from '@eslint/js';
-import tseslint from 'typescript-eslint';
+import eslint from "@eslint/js";
+import tseslint from "typescript-eslint";
+import eslintConfigPrettier from "eslint-config-prettier";
export default tseslint.config(
- eslint.configs.recommended,
- ...tseslint.configs.recommended,
- {
- rules: {
- // TODO: Fix these rule and remove their overrides.
- '@typescript-eslint/no-empty-object-type': 'off',
- '@typescript-eslint/no-explicit-any': 'off',
- }
- }
+ eslint.configs.recommended,
+ ...tseslint.configs.recommended,
+ {
+ rules: {
+ // TODO: Fix these rule and remove their overrides.
+ "@typescript-eslint/no-empty-object-type": "off",
+ "@typescript-eslint/no-explicit-any": "off",
+ },
+ },
+ eslintConfigPrettier,
);
diff --git a/jest.config.js b/jest.config.js
index d0a057f..c0a3f93 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,15 +1,15 @@
-import { createDefaultEsmPreset } from 'ts-jest'
+import { createDefaultEsmPreset } from "ts-jest";
-const defaultPreset = createDefaultEsmPreset()
+const defaultPreset = createDefaultEsmPreset();
/** @type {import('ts-jest').JestConfigWithTsJest} */
const jestConfig = {
- ...defaultPreset,
- testEnvironment: 'jsdom',
- // Convert `.js` imports to one without an extension to support 'NodeNext' module resolution.
- moduleNameMapper: {
- '^(\\.{1,2}/.*)\\.js$': '$1'
- }
-}
+ ...defaultPreset,
+ testEnvironment: "jsdom",
+ // Convert `.js` imports to one without an extension to support 'NodeNext' module resolution.
+ moduleNameMapper: {
+ "^(\\.{1,2}/.*)\\.js$": "$1",
+ },
+};
-export default jestConfig
+export default jestConfig;
diff --git a/package-lock.json b/package-lock.json
index a1db184..6c435aa 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,8 +14,10 @@
"@types/jest": "^29.5.13",
"@types/node": "^22.7.5",
"eslint": "^9.14.0",
+ "eslint-config-prettier": "^9.1.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
+ "prettier": "^3.3.3",
"ts-jest": "^29.2.5",
"typescript": "^5.6.3",
"typescript-eslint": "^8.12.2"
@@ -2727,6 +2729,19 @@
}
}
},
+ "node_modules/eslint-config-prettier": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
+ "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
"node_modules/eslint-scope": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
@@ -4909,6 +4924,22 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
+ "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"node_modules/pretty-format": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
diff --git a/package.json b/package.json
index 625db0b..fa046f6 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,8 @@
},
"scripts": {
"build": "rm -rf dist && tsc -p ./tsconfig.build.json",
- "lint": "eslint .",
+ "lint": "prettier . --check && eslint .",
+ "lint:fix": "prettier --write . && eslint . --fix",
"test": "jest"
},
"devDependencies": {
@@ -45,8 +46,10 @@
"@types/jest": "^29.5.13",
"@types/node": "^22.7.5",
"eslint": "^9.14.0",
+ "eslint-config-prettier": "^9.1.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
+ "prettier": "^3.3.3",
"ts-jest": "^29.2.5",
"typescript": "^5.6.3",
"typescript-eslint": "^8.12.2"
diff --git a/src/file-selector.spec.ts b/src/file-selector.spec.ts
index 2df57f6..82c67d9 100644
--- a/src/file-selector.spec.ts
+++ b/src/file-selector.spec.ts
@@ -1,511 +1,581 @@
-import {FileWithPath} from './file.js';
-import {fromEvent} from './file-selector.js';
+import { FileWithPath } from "./file.js";
+import { fromEvent } from "./file-selector.js";
-it('returns a Promise', async () => {
- const evt = new Event('test');
- expect(fromEvent(evt)).toBeInstanceOf(Promise);
+it("returns a Promise", async () => {
+ const evt = new Event("test");
+ expect(fromEvent(evt)).toBeInstanceOf(Promise);
});
-it('should return an empty array if the passed arg is not what we expect', async () => {
- const files = await fromEvent({});
- expect(files).toHaveLength(0);
+it("should return an empty array if the passed arg is not what we expect", async () => {
+ const files = await fromEvent({});
+ expect(files).toHaveLength(0);
});
-it('should return an empty array if drag event', async () => {
- const files = await fromEvent({});
- expect(files).toHaveLength(0);
+it("should return an empty array if drag event", async () => {
+ const files = await fromEvent({});
+ expect(files).toHaveLength(0);
});
-it('should return the evt {target} {files} if the passed event is an input evt', async () => {
- const name = 'test.json';
- const mockFile = createFile(name, {ping: true}, {
- type: 'application/json'
- });
- const evt = inputEvtFromFiles(mockFile);
-
- const files = await fromEvent(evt);
- expect(files).toHaveLength(1);
- expect(files.every(file => file instanceof File)).toBe(true);
-
- const [file] = files as FileWithPath[];
-
- expect(file.name).toBe(mockFile.name);
- expect(file.type).toBe(mockFile.type);
- expect(file.size).toBe(mockFile.size);
- expect(file.lastModified).toBe(mockFile.lastModified);
- expect(file.path).toBe(`./${name}`);
+it("should return the evt {target} {files} if the passed event is an input evt", async () => {
+ const name = "test.json";
+ const mockFile = createFile(
+ name,
+ { ping: true },
+ {
+ type: "application/json",
+ },
+ );
+ const evt = inputEvtFromFiles(mockFile);
+
+ const files = await fromEvent(evt);
+ expect(files).toHaveLength(1);
+ expect(files.every((file) => file instanceof File)).toBe(true);
+
+ const [file] = files as FileWithPath[];
+
+ expect(file.name).toBe(mockFile.name);
+ expect(file.type).toBe(mockFile.type);
+ expect(file.size).toBe(mockFile.size);
+ expect(file.lastModified).toBe(mockFile.lastModified);
+ expect(file.path).toBe(`./${name}`);
});
-it('should return an empty array if the evt {target} has no {files} prop', async () => {
- const evt = inputEvtFromFiles();
- const files = await fromEvent(evt);
- expect(files).toHaveLength(0);
+it("should return an empty array if the evt {target} has no {files} prop", async () => {
+ const evt = inputEvtFromFiles();
+ const files = await fromEvent(evt);
+ expect(files).toHaveLength(0);
});
-it('should return files if the arg is a list of FileSystemFileHandle', async () => {
- const name = 'test.json';
- const [mockFile, mockHandle] = createFileSystemFileHandle(name, {ping: true}, {
- type: 'application/json'
- });
-
- const files = await fromEvent([mockHandle]);
- expect(files).toHaveLength(1);
- expect(files.every(file => file instanceof File)).toBe(true);
-
- const [file] = files as FileWithPath[];
-
- expect(file.name).toBe(mockFile.name);
- expect(file.type).toBe(mockFile.type);
- expect(file.size).toBe(mockFile.size);
- expect(file.lastModified).toBe(mockFile.lastModified);
- expect(file.path).toBe(`./${name}`);
+it("should return files if the arg is a list of FileSystemFileHandle", async () => {
+ const name = "test.json";
+ const [mockFile, mockHandle] = createFileSystemFileHandle(
+ name,
+ { ping: true },
+ {
+ type: "application/json",
+ },
+ );
+
+ const files = await fromEvent([mockHandle]);
+ expect(files).toHaveLength(1);
+ expect(files.every((file) => file instanceof File)).toBe(true);
+
+ const [file] = files as FileWithPath[];
+
+ expect(file.name).toBe(mockFile.name);
+ expect(file.type).toBe(mockFile.type);
+ expect(file.size).toBe(mockFile.size);
+ expect(file.lastModified).toBe(mockFile.lastModified);
+ expect(file.path).toBe(`./${name}`);
});
-it('should return an empty array if the passed event is not a DragEvent', async () => {
- const evt = new Event('test');
- const files = await fromEvent(evt);
- expect(files).toHaveLength(0);
+it("should return an empty array if the passed event is not a DragEvent", async () => {
+ const evt = new Event("test");
+ const files = await fromEvent(evt);
+ expect(files).toHaveLength(0);
});
-it('should return {files} from DataTransfer if {items} is not defined (e.g. IE11)', async () => {
- const name = 'test.json';
- const mockFile = createFile(name, {ping: true}, {
- type: 'application/json'
- });
- const evt = dragEvt([mockFile]);
-
- const files = await fromEvent(evt);
- expect(files).toHaveLength(1);
- expect(files.every(file => file instanceof File)).toBe(true);
-
- const [file] = files as FileWithPath[];
-
- expect(file.name).toBe(mockFile.name);
- expect(file.type).toBe(mockFile.type);
- expect(file.size).toBe(mockFile.size);
- expect(file.lastModified).toBe(mockFile.lastModified);
- expect(file.path).toBe(`./${name}`);
+it("should return {files} from DataTransfer if {items} is not defined (e.g. IE11)", async () => {
+ const name = "test.json";
+ const mockFile = createFile(
+ name,
+ { ping: true },
+ {
+ type: "application/json",
+ },
+ );
+ const evt = dragEvt([mockFile]);
+
+ const files = await fromEvent(evt);
+ expect(files).toHaveLength(1);
+ expect(files.every((file) => file instanceof File)).toBe(true);
+
+ const [file] = files as FileWithPath[];
+
+ expect(file.name).toBe(mockFile.name);
+ expect(file.type).toBe(mockFile.type);
+ expect(file.size).toBe(mockFile.size);
+ expect(file.lastModified).toBe(mockFile.lastModified);
+ expect(file.path).toBe(`./${name}`);
});
-it('should return files from DataTransfer {items} if the passed event is a DragEvent', async () => {
- const name = 'test.json';
- const mockFile = createFile(name, {ping: true}, {
- type: 'application/json'
- });
- const item = dataTransferItemFromFile(mockFile);
- const evt = dragEvtFromFilesAndItems([], [item]);
-
- const files = await fromEvent(evt);
- expect(files).toHaveLength(1);
- expect(files.every(file => file instanceof File)).toBe(true);
-
- const [file] = files as FileWithPath[];
-
- expect(file.name).toBe(mockFile.name);
- expect(file.type).toBe(mockFile.type);
- expect(file.size).toBe(mockFile.size);
- expect(file.lastModified).toBe(mockFile.lastModified);
- expect(file.path).toBe(`./${name}`);
+it("should return files from DataTransfer {items} if the passed event is a DragEvent", async () => {
+ const name = "test.json";
+ const mockFile = createFile(
+ name,
+ { ping: true },
+ {
+ type: "application/json",
+ },
+ );
+ const item = dataTransferItemFromFile(mockFile);
+ const evt = dragEvtFromFilesAndItems([], [item]);
+
+ const files = await fromEvent(evt);
+ expect(files).toHaveLength(1);
+ expect(files.every((file) => file instanceof File)).toBe(true);
+
+ const [file] = files as FileWithPath[];
+
+ expect(file.name).toBe(mockFile.name);
+ expect(file.type).toBe(mockFile.type);
+ expect(file.size).toBe(mockFile.size);
+ expect(file.lastModified).toBe(mockFile.lastModified);
+ expect(file.path).toBe(`./${name}`);
});
-it('should use the {fullPath} for {path} if {webkitGetAsEntry} is supported and the items are FileSystemFileEntry', async () => {
- const name = 'test.json';
- const fullPath = '/testfolder/test.json'
- const mockFile = createFile(name, {ping: true}, {
- type: 'application/json'
- });
-
- const file = fileSystemFileEntryFromFile(mockFile);
- file.fullPath = fullPath
- const item = dataTransferItemFromEntry(file, mockFile);
- const evt = dragEvtFromFilesAndItems([], [item]);
-
- const files = await fromEvent(evt);
- expect(files).toHaveLength(1);
- expect(files.every(file => file instanceof File)).toBe(true);
-
- const [f] = files as FileWithPath[];
-
- expect(f.name).toBe(mockFile.name);
- expect(f.type).toBe(mockFile.type);
- expect(f.size).toBe(mockFile.size);
- expect(f.lastModified).toBe(mockFile.lastModified);
- expect(f.path).toBe(fullPath);
+it("should use the {fullPath} for {path} if {webkitGetAsEntry} is supported and the items are FileSystemFileEntry", async () => {
+ const name = "test.json";
+ const fullPath = "/testfolder/test.json";
+ const mockFile = createFile(
+ name,
+ { ping: true },
+ {
+ type: "application/json",
+ },
+ );
+
+ const file = fileSystemFileEntryFromFile(mockFile);
+ file.fullPath = fullPath;
+ const item = dataTransferItemFromEntry(file, mockFile);
+ const evt = dragEvtFromFilesAndItems([], [item]);
+
+ const files = await fromEvent(evt);
+ expect(files).toHaveLength(1);
+ expect(files.every((file) => file instanceof File)).toBe(true);
+
+ const [f] = files as FileWithPath[];
+
+ expect(f.name).toBe(mockFile.name);
+ expect(f.type).toBe(mockFile.type);
+ expect(f.size).toBe(mockFile.size);
+ expect(f.lastModified).toBe(mockFile.lastModified);
+ expect(f.path).toBe(fullPath);
});
it('skips DataTransfer {items} that are of kind "string"', async () => {
- const name = 'test.json';
- const mockFile = createFile(name, {ping: true}, {
- type: 'application/json'
- });
- const f = dataTransferItemFromFile(mockFile);
- const str = dataTransferItemFromStr('test');
- const evt = dragEvtFromItems([str, f]);
-
- const files = await fromEvent(evt);
- expect(files).toHaveLength(1);
-
- const [file] = files as FileWithPath[];
-
- expect(file.name).toBe(mockFile.name);
- expect(file.type).toBe(mockFile.type);
- expect(file.size).toBe(mockFile.size);
- expect(file.lastModified).toBe(mockFile.lastModified);
- expect(file.path).toBe(`./${name}`);
+ const name = "test.json";
+ const mockFile = createFile(
+ name,
+ { ping: true },
+ {
+ type: "application/json",
+ },
+ );
+ const f = dataTransferItemFromFile(mockFile);
+ const str = dataTransferItemFromStr("test");
+ const evt = dragEvtFromItems([str, f]);
+
+ const files = await fromEvent(evt);
+ expect(files).toHaveLength(1);
+
+ const [file] = files as FileWithPath[];
+
+ expect(file.name).toBe(mockFile.name);
+ expect(file.type).toBe(mockFile.type);
+ expect(file.size).toBe(mockFile.size);
+ expect(file.lastModified).toBe(mockFile.lastModified);
+ expect(file.path).toBe(`./${name}`);
});
-it('can read a tree of directories recursively and return a flat list of FileWithPath objects', async () => {
- const mockFiles = sortFiles([
- createFile('ping.json', {ping: true}),
- createFile('pong.json', {pong: true}),
- createFile('foo.json', {foo: true}),
- createFile('bar.json', {bar: true}),
- createFile('john.json', {john: true}),
- createFile('jane.json', {jane: true})
- ]);
- const [f1, f2, f3, f4, f5, f6] = mockFiles;
- const [f7, f8] = [
- createFile('.DS_Store', {macOs: true}),
- createFile('Thumbs.db', {windows: true})
- ];
- const evt = dragEvtFromItems([
- dataTransferItemFromEntry(fileSystemFileEntryFromFile(f1), f1),
- dataTransferItemFromEntry(fileSystemFileEntryFromFile(f2), f2),
- dataTransferItemFromEntry(fileSystemDirEntryFromFile([
- fileSystemFileEntryFromFile(f3),
- fileSystemDirEntryFromFile([
- fileSystemFileEntryFromFile(f4)
- ]),
- fileSystemFileEntryFromFile(f5)
- ], 2)),
- dataTransferItemFromEntry(fileSystemFileEntryFromFile(f6), f6),
- dataTransferItemFromEntry(fileSystemFileEntryFromFile(f7), f7),
- dataTransferItemFromEntry(fileSystemFileEntryFromFile(f8), f8)
- ]);
-
- const items = await fromEvent(evt);
- const files = sortFiles(items as FileWithPath[]);
- expect(files).toHaveLength(6);
- expect(files.every(file => file instanceof File)).toBe(true);
- expect(files.every(file => typeof file.path === 'string')).toBe(true);
- expect(files).toEqual(mockFiles);
+it("can read a tree of directories recursively and return a flat list of FileWithPath objects", async () => {
+ const mockFiles = sortFiles([
+ createFile("ping.json", { ping: true }),
+ createFile("pong.json", { pong: true }),
+ createFile("foo.json", { foo: true }),
+ createFile("bar.json", { bar: true }),
+ createFile("john.json", { john: true }),
+ createFile("jane.json", { jane: true }),
+ ]);
+ const [f1, f2, f3, f4, f5, f6] = mockFiles;
+ const [f7, f8] = [
+ createFile(".DS_Store", { macOs: true }),
+ createFile("Thumbs.db", { windows: true }),
+ ];
+ const evt = dragEvtFromItems([
+ dataTransferItemFromEntry(fileSystemFileEntryFromFile(f1), f1),
+ dataTransferItemFromEntry(fileSystemFileEntryFromFile(f2), f2),
+ dataTransferItemFromEntry(
+ fileSystemDirEntryFromFile(
+ [
+ fileSystemFileEntryFromFile(f3),
+ fileSystemDirEntryFromFile([fileSystemFileEntryFromFile(f4)]),
+ fileSystemFileEntryFromFile(f5),
+ ],
+ 2,
+ ),
+ ),
+ dataTransferItemFromEntry(fileSystemFileEntryFromFile(f6), f6),
+ dataTransferItemFromEntry(fileSystemFileEntryFromFile(f7), f7),
+ dataTransferItemFromEntry(fileSystemFileEntryFromFile(f8), f8),
+ ]);
+
+ const items = await fromEvent(evt);
+ const files = sortFiles(items as FileWithPath[]);
+ expect(files).toHaveLength(6);
+ expect(files.every((file) => file instanceof File)).toBe(true);
+ expect(files.every((file) => typeof file.path === "string")).toBe(true);
+ expect(files).toEqual(mockFiles);
});
it('returns the DataTransfer {items} if the DragEvent {type} is not "drop"', async () => {
- const name = 'test.json';
- const mockFile = createFile(name, {ping: true}, {
- type: 'application/json'
- });
- const item = dataTransferItemFromFile(mockFile);
- const evt = dragEvtFromItems(item, 'dragenter');
-
- const items = await fromEvent(evt);
- expect(items).toHaveLength(1);
-
- const [itm] = items as DataTransferItem[];
+ const name = "test.json";
+ const mockFile = createFile(
+ name,
+ { ping: true },
+ {
+ type: "application/json",
+ },
+ );
+ const item = dataTransferItemFromFile(mockFile);
+ const evt = dragEvtFromItems(item, "dragenter");
+
+ const items = await fromEvent(evt);
+ expect(items).toHaveLength(1);
+
+ const [itm] = items as DataTransferItem[];
+
+ expect(itm.kind).toBe(item.kind);
+ expect(itm.kind).toBe("file");
+});
- expect(itm.kind).toBe(item.kind);
- expect(itm.kind).toBe('file');
+it('filters DataTransfer {items} if the DragEvent {type} is not "drop" and DataTransferItem {kind} is "string"', async () => {
+ const name = "test.json";
+ const mockFile = createFile(
+ name,
+ { ping: true },
+ {
+ type: "application/json",
+ },
+ );
+ const file = dataTransferItemFromFile(mockFile);
+ const str = dataTransferItemFromStr("test");
+ const evt = dragEvtFromItems([file, str], "dragenter");
+
+ const items = await fromEvent(evt);
+ expect(items).toHaveLength(1);
+
+ const [item] = items as DataTransferItem[];
+
+ expect(item.kind).toBe(file.kind);
+ expect(item.kind).toBe("file");
});
-it(
- 'filters DataTransfer {items} if the DragEvent {type} is not "drop" and DataTransferItem {kind} is "string"',
- async () => {
- const name = 'test.json';
- const mockFile = createFile(name, {ping: true}, {
- type: 'application/json'
- });
- const file = dataTransferItemFromFile(mockFile);
- const str = dataTransferItemFromStr('test');
- const evt = dragEvtFromItems([file, str], 'dragenter');
-
- const items = await fromEvent(evt);
- expect(items).toHaveLength(1);
-
- const [item] = items as DataTransferItem[];
-
- expect(item.kind).toBe(file.kind);
- expect(item.kind).toBe('file');
- }
-);
-
-it('filters thumbnail cache files', async () => {
- const mockFile = createFile('Thumbs.db', {ping: true}, {
- type: 'text/plain'
- });
- const evt = dragEvt([mockFile]);
- const items = await fromEvent(evt);
- expect(items).toHaveLength(0);
+it("filters thumbnail cache files", async () => {
+ const mockFile = createFile(
+ "Thumbs.db",
+ { ping: true },
+ {
+ type: "text/plain",
+ },
+ );
+ const evt = dragEvt([mockFile]);
+ const items = await fromEvent(evt);
+ expect(items).toHaveLength(0);
});
-it('should throw if reading dir entries fails', done => {
- const mockFiles = sortFiles([
- createFile('ping.json', {ping: true}),
- createFile('pong.json', {pong: true})
- ]);
- const [f1, f2] = mockFiles;
- const evt = dragEvtFromItems([
- dataTransferItemFromEntry(fileSystemDirEntryFromFile([
- fileSystemFileEntryFromFile(f1),
- fileSystemFileEntryFromFile(f2)
- ], 1, 1))
- ]);
-
- fromEvent(evt)
- .then(() => done.fail('Getting the files should have failed'))
- .catch(() => done());
+it("should throw if reading dir entries fails", (done) => {
+ const mockFiles = sortFiles([
+ createFile("ping.json", { ping: true }),
+ createFile("pong.json", { pong: true }),
+ ]);
+ const [f1, f2] = mockFiles;
+ const evt = dragEvtFromItems([
+ dataTransferItemFromEntry(
+ fileSystemDirEntryFromFile(
+ [fileSystemFileEntryFromFile(f1), fileSystemFileEntryFromFile(f2)],
+ 1,
+ 1,
+ ),
+ ),
+ ]);
+
+ fromEvent(evt)
+ .then(() => done.fail("Getting the files should have failed"))
+ .catch(() => done());
});
-it('should throw if reading file entry fails', done => {
- const mockFiles = sortFiles([
- createFile('ping.json', {ping: true}),
- createFile('pong.json', {pong: true})
- ]);
- const [f1, f2] = mockFiles;
- const evt = dragEvtFromItems([
- dataTransferItemFromEntry(fileSystemDirEntryFromFile([
- fileSystemFileEntryFromFile(f1),
- fileSystemFileEntryFromFile(f2, 'Oops :(')
- ], 1, 1))
- ]);
-
- fromEvent(evt)
- .then(() => done.fail('Getting the files should have failed'))
- .catch(() => done());
+it("should throw if reading file entry fails", (done) => {
+ const mockFiles = sortFiles([
+ createFile("ping.json", { ping: true }),
+ createFile("pong.json", { pong: true }),
+ ]);
+ const [f1, f2] = mockFiles;
+ const evt = dragEvtFromItems([
+ dataTransferItemFromEntry(
+ fileSystemDirEntryFromFile(
+ [
+ fileSystemFileEntryFromFile(f1),
+ fileSystemFileEntryFromFile(f2, "Oops :("),
+ ],
+ 1,
+ 1,
+ ),
+ ),
+ ]);
+
+ fromEvent(evt)
+ .then(() => done.fail("Getting the files should have failed"))
+ .catch(() => done());
});
-it('should throw if DataTransferItem is not a File', done => {
- const item = dataTransferItem(null, 'file');
- const evt = dragEvtFromFilesAndItems([], [item]);
+it("should throw if DataTransferItem is not a File", (done) => {
+ const item = dataTransferItem(null, "file");
+ const evt = dragEvtFromFilesAndItems([], [item]);
- fromEvent(evt)
- .then(() => done.fail('Getting the files should have failed'))
- .catch(() => done());
+ fromEvent(evt)
+ .then(() => done.fail("Getting the files should have failed"))
+ .catch(() => done());
});
-it('should use getAsFileSystemHandle when available', async () => {
- const name = 'test.json';
- const [f, h] = createFileSystemFileHandle(name, {ping: true}, {
- type: 'application/json'
- });
- const evt = dragEvtFromItems([
- dataTransferItemWithFsHandle(f, h)
- ]);
- const files = await fromEvent(evt);
- expect(files).toHaveLength(1);
- expect(files.every(file => file instanceof File)).toBe(true);
-
- const [file] = files as FileWithPath[];
-
- expect(file.name).toBe(f.name);
- expect(file.type).toBe(f.type);
- expect(file.size).toBe(f.size);
- expect(file.lastModified).toBe(f.lastModified);
- expect(file.path).toBe(`./${name}`);
+it("should use getAsFileSystemHandle when available", async () => {
+ const name = "test.json";
+ const [f, h] = createFileSystemFileHandle(
+ name,
+ { ping: true },
+ {
+ type: "application/json",
+ },
+ );
+ const evt = dragEvtFromItems([dataTransferItemWithFsHandle(f, h)]);
+ const files = await fromEvent(evt);
+ expect(files).toHaveLength(1);
+ expect(files.every((file) => file instanceof File)).toBe(true);
+
+ const [file] = files as FileWithPath[];
+
+ expect(file.name).toBe(f.name);
+ expect(file.type).toBe(f.type);
+ expect(file.size).toBe(f.size);
+ expect(file.lastModified).toBe(f.lastModified);
+ expect(file.path).toBe(`./${name}`);
});
-function dragEvtFromItems(items: DataTransferItem | DataTransferItem[], type: string = 'drop'): DragEvent {
- return {
- type,
- dataTransfer: {
- items: Array.isArray(items) ? items : [items]
- }
- } as any;
+function dragEvtFromItems(
+ items: DataTransferItem | DataTransferItem[],
+ type: string = "drop",
+): DragEvent {
+ return {
+ type,
+ dataTransfer: {
+ items: Array.isArray(items) ? items : [items],
+ },
+ } as any;
}
-function dragEvt(files?: File[], items?: DataTransferItem[], type: string = 'drop'): DragEvent {
- return {
- type,
- dataTransfer: {items, files}
- } as any;
+function dragEvt(
+ files?: File[],
+ items?: DataTransferItem[],
+ type: string = "drop",
+): DragEvent {
+ return {
+ type,
+ dataTransfer: { items, files },
+ } as any;
}
-function dragEvtFromFilesAndItems(files: File[], items: DataTransferItem[], type: string = 'drop'): DragEvent {
- return {
- type,
- dataTransfer: {files, items}
- } as any;
+function dragEvtFromFilesAndItems(
+ files: File[],
+ items: DataTransferItem[],
+ type: string = "drop",
+): DragEvent {
+ return {
+ type,
+ dataTransfer: { files, items },
+ } as any;
}
function dataTransferItemFromFile(file: File): DataTransferItem {
- return {
- kind: 'file',
- type: file.type,
- getAsFile() {
- return file;
- },
- getAsString() {}
- } as any;
+ return {
+ kind: "file",
+ type: file.type,
+ getAsFile() {
+ return file;
+ },
+ getAsString() {},
+ } as any;
}
-function dataTransferItem(file?: any, kind?: string, type: string = ''): DataTransferItem {
- return {
- kind,
- type,
- getAsFile() {
- return file;
- }
- } as any;
+function dataTransferItem(
+ file?: any,
+ kind?: string,
+ type: string = "",
+): DataTransferItem {
+ return {
+ kind,
+ type,
+ getAsFile() {
+ return file;
+ },
+ } as any;
}
function dataTransferItemFromStr(str: string): DataTransferItem {
- return {
- kind: 'string',
- type: 'text/plain',
- getAsFile() {
- return null;
- },
- getAsString(cb: (data: string) => void) {
- return cb(str);
- }
- } as any;
+ return {
+ kind: "string",
+ type: "text/plain",
+ getAsFile() {
+ return null;
+ },
+ getAsString(cb: (data: string) => void) {
+ return cb(str);
+ },
+ } as any;
}
-function dataTransferItemFromEntry(entry: FileEntry | DirEntry, file?: File): DataTransferItem {
- return {
- kind: 'file',
- getAsFile() {
- return file;
- },
- webkitGetAsEntry: () => {
- return entry;
- }
- } as any;
+function dataTransferItemFromEntry(
+ entry: FileEntry | DirEntry,
+ file?: File,
+): DataTransferItem {
+ return {
+ kind: "file",
+ getAsFile() {
+ return file;
+ },
+ webkitGetAsEntry: () => {
+ return entry;
+ },
+ } as any;
}
-function dataTransferItemWithFsHandle(file?: File, h?: FileSystemFileHandle): DataTransferItem {
- return {
- kind: 'file',
- getAsFile() {
- return file;
- },
- getAsFileSystemHandle() {
- return Promise.resolve(h);
- }
- } as any;
+function dataTransferItemWithFsHandle(
+ file?: File,
+ h?: FileSystemFileHandle,
+): DataTransferItem {
+ return {
+ kind: "file",
+ getAsFile() {
+ return file;
+ },
+ getAsFileSystemHandle() {
+ return Promise.resolve(h);
+ },
+ } as any;
}
function fileSystemFileEntryFromFile(file: File, err?: any): FileEntry {
- return {
- isDirectory: false,
- isFile: true,
- file(cb, errCb) {
- if (err) {
- errCb(err);
- } else {
- cb(file);
- }
- }
- };
+ return {
+ isDirectory: false,
+ isFile: true,
+ file(cb, errCb) {
+ if (err) {
+ errCb(err);
+ } else {
+ cb(file);
+ }
+ },
+ };
}
function fileSystemDirEntryFromFile(
- files: FileOrDirEntry[],
- batchSize: number = 1,
- throwAfter: number = 0
+ files: FileOrDirEntry[],
+ batchSize: number = 1,
+ throwAfter: number = 0,
): DirEntry {
- const copy = files.slice(0);
- const batches: FileOrDirEntry[][] = [];
-
- let current = 0;
- while (copy.length) {
- const length = copy.length;
- current += batchSize;
- const batch = copy.splice(0, current > length ? length : current);
- batches.push(batch);
- }
-
- return {
- isDirectory: true,
- isFile: false,
- createReader: () => {
- let cbCount = 0;
-
- return {
- readEntries(cb, errCb) {
- const batch = batches[cbCount];
- cbCount++;
-
- if (throwAfter !== 0 && cbCount === throwAfter) {
- errCb('Failed to read files');
- }
-
- if (batch) {
- cb(batch);
- } else {
- cb([]);
- }
- }
- };
- }
- };
+ const copy = files.slice(0);
+ const batches: FileOrDirEntry[][] = [];
+
+ let current = 0;
+ while (copy.length) {
+ const length = copy.length;
+ current += batchSize;
+ const batch = copy.splice(0, current > length ? length : current);
+ batches.push(batch);
+ }
+
+ return {
+ isDirectory: true,
+ isFile: false,
+ createReader: () => {
+ let cbCount = 0;
+
+ return {
+ readEntries(cb, errCb) {
+ const batch = batches[cbCount];
+ cbCount++;
+
+ if (throwAfter !== 0 && cbCount === throwAfter) {
+ errCb("Failed to read files");
+ }
+
+ if (batch) {
+ cb(batch);
+ } else {
+ cb([]);
+ }
+ },
+ };
+ },
+ };
}
function inputEvtFromFiles(...files: File[]): Event {
- const input = document.createElement('input');
- if (files.length) {
- Object.defineProperty(input, 'files', {
- value: files
- });
- }
- return new Proxy(new CustomEvent('input'), {
- get(t, p) {
- if (p === 'target') {
- return input;
- }
- return (t as any)[p];
- }
+ const input = document.createElement("input");
+ if (files.length) {
+ Object.defineProperty(input, "files", {
+ value: files,
});
+ }
+ return new Proxy(new CustomEvent("input"), {
+ get(t, p) {
+ if (p === "target") {
+ return input;
+ }
+ return (t as any)[p];
+ },
+ });
}
function createFile(name: string, data: T, options?: FilePropertyBag) {
- const json = JSON.stringify(data);
- const file = new File([json], name, options);
- return file;
+ const json = JSON.stringify(data);
+ const file = new File([json], name, options);
+ return file;
}
-function createFileSystemFileHandle(name: string, data: T, options?: FilePropertyBag): [File, FileSystemFileHandle] {
- const json = JSON.stringify(data);
- const file = new File([json], name, options);
- return [file, {
- getFile() {
- return Promise.resolve(file);
- }
- }];
+function createFileSystemFileHandle(
+ name: string,
+ data: T,
+ options?: FilePropertyBag,
+): [File, FileSystemFileHandle] {
+ const json = JSON.stringify(data);
+ const file = new File([json], name, options);
+ return [
+ file,
+ {
+ getFile() {
+ return Promise.resolve(file);
+ },
+ },
+ ];
}
function sortFiles(files: T[]) {
- return files.slice(0)
- .sort((a, b) => a.name.localeCompare(b.name));
+ return files.slice(0).sort((a, b) => a.name.localeCompare(b.name));
}
-
interface FileSystemFileHandle {
- getFile(): Promise;
+ getFile(): Promise;
}
-type FileOrDirEntry = FileEntry | DirEntry
+type FileOrDirEntry = FileEntry | DirEntry;
interface FileEntry extends Entry {
- file(
- cb: (file: File) => void,
- errCb: (err: any) => void
- ): void;
+ file(cb: (file: File) => void, errCb: (err: any) => void): void;
}
interface DirEntry extends Entry {
- createReader(): DirReader;
+ createReader(): DirReader;
}
interface Entry {
- isDirectory: boolean;
- isFile: boolean;
- fullPath?: string;
+ isDirectory: boolean;
+ isFile: boolean;
+ fullPath?: string;
}
interface DirReader {
- readEntries(
- cb: (entries: FileOrDirEntry[]) => void,
- errCb: (err: any) => void
- ): void;
+ readEntries(
+ cb: (entries: FileOrDirEntry[]) => void,
+ errCb: (err: any) => void,
+ ): void;
}
diff --git a/src/file-selector.ts b/src/file-selector.ts
index b51f513..ba0228f 100644
--- a/src/file-selector.ts
+++ b/src/file-selector.ts
@@ -1,13 +1,11 @@
-import {FileWithPath, toFileWithPath} from './file.js';
-
+import { FileWithPath, toFileWithPath } from "./file.js";
const FILES_TO_IGNORE = [
- // Thumbnail cache files for macOS and Windows
- '.DS_Store', // macOs
- 'Thumbs.db' // Windows
+ // Thumbnail cache files for macOS and Windows
+ ".DS_Store", // macOs
+ "Thumbs.db", // Windows
];
-
/**
* Convert a DragEvent's DataTrasfer object to a list of File objects
* NOTE: If some of the items are folders,
@@ -18,61 +16,69 @@ const FILES_TO_IGNORE = [
*
* @param evt
*/
-export async function fromEvent(evt: Event | any): Promise<(FileWithPath | DataTransferItem)[]> {
- if (isObject(evt) && isDataTransfer(evt.dataTransfer)) {
- return getDataTransferFiles(evt.dataTransfer, evt.type);
- } else if (isChangeEvt(evt)) {
- return getInputFiles(evt);
- } else if (Array.isArray(evt) && evt.every(item => 'getFile' in item && typeof item.getFile === 'function')) {
- return getFsHandleFiles(evt)
- }
- return [];
+export async function fromEvent(
+ evt: Event | any,
+): Promise<(FileWithPath | DataTransferItem)[]> {
+ if (isObject(evt) && isDataTransfer(evt.dataTransfer)) {
+ return getDataTransferFiles(evt.dataTransfer, evt.type);
+ } else if (isChangeEvt(evt)) {
+ return getInputFiles(evt);
+ } else if (
+ Array.isArray(evt) &&
+ evt.every((item) => "getFile" in item && typeof item.getFile === "function")
+ ) {
+ return getFsHandleFiles(evt);
+ }
+ return [];
}
function isDataTransfer(value: any): value is DataTransfer {
- return isObject(value);
+ return isObject(value);
}
function isChangeEvt(value: any): value is Event {
- return isObject(value) && isObject(value.target);
+ return isObject(value) && isObject(value.target);
}
function isObject(v: any): v is T {
- return typeof v === 'object' && v !== null
+ return typeof v === "object" && v !== null;
}
function getInputFiles(evt: Event) {
- return fromList((evt.target as HTMLInputElement).files).map(file => toFileWithPath(file));
+ return fromList((evt.target as HTMLInputElement).files).map(
+ (file) => toFileWithPath(file),
+ );
}
// Ee expect each handle to be https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileHandle
async function getFsHandleFiles(handles: any[]) {
- const files = await Promise.all(handles.map(h => h.getFile()));
- return files.map(file => toFileWithPath(file));
+ const files = await Promise.all(handles.map((h) => h.getFile()));
+ return files.map((file) => toFileWithPath(file));
}
-
async function getDataTransferFiles(dt: DataTransfer, type: string) {
- // IE11 does not support dataTransfer.items
- // See https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/items#Browser_compatibility
- if (dt.items) {
- const items = fromList(dt.items)
- .filter(item => item.kind === 'file');
- // According to https://html.spec.whatwg.org/multipage/dnd.html#dndevents,
- // only 'dragstart' and 'drop' has access to the data (source node)
- if (type !== 'drop') {
- return items;
- }
- const files = await Promise.all(items.map(toFilePromises));
- return noIgnoredFiles(flatten(files));
+ // IE11 does not support dataTransfer.items
+ // See https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/items#Browser_compatibility
+ if (dt.items) {
+ const items = fromList(dt.items).filter(
+ (item) => item.kind === "file",
+ );
+ // According to https://html.spec.whatwg.org/multipage/dnd.html#dndevents,
+ // only 'dragstart' and 'drop' has access to the data (source node)
+ if (type !== "drop") {
+ return items;
}
+ const files = await Promise.all(items.map(toFilePromises));
+ return noIgnoredFiles(flatten(files));
+ }
- return noIgnoredFiles(fromList(dt.files)
- .map(file => toFileWithPath(file)));
+ return noIgnoredFiles(
+ fromList(dt.files).map((file) => toFileWithPath(file)),
+ );
}
function noIgnoredFiles(files: FileWithPath[]) {
- return files.filter(file => FILES_TO_IGNORE.indexOf(file.name) === -1);
+ return files.filter((file) => FILES_TO_IGNORE.indexOf(file.name) === -1);
}
// IE11 does not support Array.from()
@@ -80,116 +86,126 @@ function noIgnoredFiles(files: FileWithPath[]) {
// https://developer.mozilla.org/en-US/docs/Web/API/FileList
// https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList
function fromList(items: DataTransferItemList | FileList | null): T[] {
- if (items === null) {
- return [];
- }
+ if (items === null) {
+ return [];
+ }
- const files = [];
+ const files = [];
- for (let i = 0; i < items.length; i++) {
- const file = items[i];
- files.push(file);
- }
+ for (let i = 0; i < items.length; i++) {
+ const file = items[i];
+ files.push(file);
+ }
- return files as any;
+ return files as any;
}
// https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem
function toFilePromises(item: DataTransferItem) {
- if (typeof item.webkitGetAsEntry !== 'function') {
- return fromDataTransferItem(item);
- }
+ if (typeof item.webkitGetAsEntry !== "function") {
+ return fromDataTransferItem(item);
+ }
- const entry = item.webkitGetAsEntry();
+ const entry = item.webkitGetAsEntry();
- // Safari supports dropping an image node from a different window and can be retrieved using
- // the DataTransferItem.getAsFile() API
- // NOTE: FileSystemEntry.file() throws if trying to get the file
- if (entry && entry.isDirectory) {
- return fromDirEntry(entry) as any;
- }
+ // Safari supports dropping an image node from a different window and can be retrieved using
+ // the DataTransferItem.getAsFile() API
+ // NOTE: FileSystemEntry.file() throws if trying to get the file
+ if (entry && entry.isDirectory) {
+ return fromDirEntry(entry) as any;
+ }
- return fromDataTransferItem(item, entry);
+ return fromDataTransferItem(item, entry);
}
function flatten(items: any[]): T[] {
- return items.reduce((acc, files) => [
- ...acc,
- ...(Array.isArray(files) ? flatten(files) : [files])
- ], []);
+ return items.reduce(
+ (acc, files) => [
+ ...acc,
+ ...(Array.isArray(files) ? flatten(files) : [files]),
+ ],
+ [],
+ );
}
-function fromDataTransferItem(item: DataTransferItem, entry?: FileSystemEntry | null) {
- if (typeof (item as any).getAsFileSystemHandle === 'function') {
- return (item as any).getAsFileSystemHandle()
- .then(async (h: any) => {
- const file = await h.getFile();
- file.handle = h;
- return toFileWithPath(file);
- });
- }
- const file = item.getAsFile();
- if (!file) {
- return Promise.reject(`${item} is not a File`);
- }
- const fwp = toFileWithPath(file, entry?.fullPath ?? undefined);
- return Promise.resolve(fwp);
+function fromDataTransferItem(
+ item: DataTransferItem,
+ entry?: FileSystemEntry | null,
+) {
+ if (typeof (item as any).getAsFileSystemHandle === "function") {
+ return (item as any).getAsFileSystemHandle().then(async (h: any) => {
+ const file = await h.getFile();
+ file.handle = h;
+ return toFileWithPath(file);
+ });
+ }
+ const file = item.getAsFile();
+ if (!file) {
+ return Promise.reject(`${item} is not a File`);
+ }
+ const fwp = toFileWithPath(file, entry?.fullPath ?? undefined);
+ return Promise.resolve(fwp);
}
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry
async function fromEntry(entry: any) {
- return entry.isDirectory ? fromDirEntry(entry) : fromFileEntry(entry);
+ return entry.isDirectory ? fromDirEntry(entry) : fromFileEntry(entry);
}
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryEntry
function fromDirEntry(entry: any) {
- const reader = entry.createReader();
-
- return new Promise((resolve, reject) => {
- const entries: Promise[] = [];
-
- function readEntries() {
- // https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryEntry/createReader
- // https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryReader/readEntries
- reader.readEntries(async (batch: any[]) => {
- if (!batch.length) {
- // Done reading directory
- try {
- const files = await Promise.all(entries);
- resolve(files);
- } catch (err) {
- reject(err);
- }
- } else {
- const items = Promise.all(batch.map(fromEntry));
- entries.push(items);
-
- // Continue reading
- readEntries();
- }
- }, (err: any) => {
- reject(err);
- });
- }
-
- readEntries();
- });
+ const reader = entry.createReader();
+
+ return new Promise((resolve, reject) => {
+ const entries: Promise[] = [];
+
+ function readEntries() {
+ // https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryEntry/createReader
+ // https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryReader/readEntries
+ reader.readEntries(
+ async (batch: any[]) => {
+ if (!batch.length) {
+ // Done reading directory
+ try {
+ const files = await Promise.all(entries);
+ resolve(files);
+ } catch (err) {
+ reject(err);
+ }
+ } else {
+ const items = Promise.all(batch.map(fromEntry));
+ entries.push(items);
+
+ // Continue reading
+ readEntries();
+ }
+ },
+ (err: any) => {
+ reject(err);
+ },
+ );
+ }
+
+ readEntries();
+ });
}
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileEntry
async function fromFileEntry(entry: any) {
- return new Promise((resolve, reject) => {
- entry.file((file: FileWithPath) => {
- const fwp = toFileWithPath(file, entry.fullPath);
- resolve(fwp);
- }, (err: any) => {
- reject(err);
- });
- });
+ return new Promise((resolve, reject) => {
+ entry.file(
+ (file: FileWithPath) => {
+ const fwp = toFileWithPath(file, entry.fullPath);
+ resolve(fwp);
+ },
+ (err: any) => {
+ reject(err);
+ },
+ );
+ });
}
// Infinite type recursion
// https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540
interface FileArray extends Array {}
-type FileValue = FileWithPath
- | FileArray[];
+type FileValue = FileWithPath | FileArray[];
diff --git a/src/file.spec.ts b/src/file.spec.ts
index 51be2dd..a4081c7 100644
--- a/src/file.spec.ts
+++ b/src/file.spec.ts
@@ -1,196 +1,195 @@
-import {COMMON_MIME_TYPES, toFileWithPath} from './file.js';
-
-describe('toFile()', () => {
- it('should be an instance of a File', () => {
- const file = new File([], 'test.json');
- const fileWithPath = toFileWithPath(file);
- expect(fileWithPath).toBeInstanceOf(File);
- });
-
- it('has all the File options', () => {
- const type = 'application/json';
- const opts: FilePropertyBag = {type};
- const file = new File([], 'test.json', opts);
- const fileWithPath = toFileWithPath(file);
- expect(fileWithPath.type).toBe(type);
- });
-
- it('does not overwrite {path} if it exists', () => {
- const fullPath = '/Users/test/Desktop/test/test.json';
- const path = '/test/test.json';
- const file = new File([], 'test.json');
- // @ts-expect-error: This is set only in the case of an electron app
- file.path = fullPath;
- const fileWithPath = toFileWithPath(file, path);
- expect(fileWithPath.path).toBe(fullPath);
- });
-
- it('sets the {path} if provided', () => {
- const path = '/test/test.json';
- const file = new File([], 'test.json');
- const fileWithPath = toFileWithPath(file, path);
- expect(fileWithPath.path).toBe(path);
- });
-
- test('{path} is enumerable', () => {
- const path = '/test/test.json';
- const file = new File([], 'test.json');
- const fileWithPath = toFileWithPath(file, path);
-
- expect(Object.keys(fileWithPath)).toContain('path');
-
- const keys: string[] = [];
- for (const key in fileWithPath) {
- keys.push(key);
- }
-
- expect(keys).toContain('path');
- });
-
- it('uses the File {name} as {path} if not provided', () => {
- const name = 'test.json';
- const file = new File([], name);
- const fileWithPath = toFileWithPath(file);
- expect(fileWithPath.path).toBe(`./${name}`);
- });
-
- it('uses the File {webkitRelativePath} as {path} if it exists', () => {
- const name = 'test.json';
- const path = 'test/test.json';
- const file = new File([], name);
- Object.defineProperty(file, 'webkitRelativePath', {
- value: path
- });
- const fileWithPath = toFileWithPath(file);
- expect(fileWithPath.path).toBe(path);
- });
-
- it('sets the {relativePath} if provided without overwriting {path}', () => {
- const fullPath = '/Users/test/Desktop/test/test.json';
- const path = '/test/test.json';
- const file = new File([], 'test.json');
-
- // @ts-expect-error: This is set only in the case of an electron app
- file.path = fullPath;
- const fileWithPath = toFileWithPath(file, path);
- expect(fileWithPath.path).toBe(fullPath);
- expect(fileWithPath.relativePath).toBe(path);
- });
-
- test('{relativePath} is enumerable', () => {
- const path = '/test/test.json';
- const file = new File([], 'test.json');
- const fileWithPath = toFileWithPath(file, path);
-
- expect(Object.keys(fileWithPath)).toContain('relativePath');
-
- const keys: string[] = [];
- for (const key in fileWithPath) {
- keys.push(key);
- }
-
- expect(keys).toContain('relativePath');
- });
-
- it('uses the File {webkitRelativePath} as {relativePath} if it exists', () => {
- const name = 'test.json';
- const path = 'test/test.json';
- const file = new File([], name);
- Object.defineProperty(file, 'webkitRelativePath', {
- value: path
- });
- const fileWithPath = toFileWithPath(file);
- expect(fileWithPath.relativePath).toBe(path);
- });
-
- it('sets the {type} from extension', () => {
- const types = Array.from(COMMON_MIME_TYPES.values());
- const files = Array.from(COMMON_MIME_TYPES.keys())
- .map(ext => new File([], `test.${ext}`))
- .map(f => toFileWithPath(f));
-
- for (const file of files) {
- expect(types.includes(file.type)).toBe(true);
- }
- });
-
- test('{type} is enumerable', () => {
- const file = new File([], 'test.gif');
- const fileWithPath = toFileWithPath(file);
+import { COMMON_MIME_TYPES, toFileWithPath } from "./file.js";
+
+describe("toFile()", () => {
+ it("should be an instance of a File", () => {
+ const file = new File([], "test.json");
+ const fileWithPath = toFileWithPath(file);
+ expect(fileWithPath).toBeInstanceOf(File);
+ });
+
+ it("has all the File options", () => {
+ const type = "application/json";
+ const opts: FilePropertyBag = { type };
+ const file = new File([], "test.json", opts);
+ const fileWithPath = toFileWithPath(file);
+ expect(fileWithPath.type).toBe(type);
+ });
+
+ it("does not overwrite {path} if it exists", () => {
+ const fullPath = "/Users/test/Desktop/test/test.json";
+ const path = "/test/test.json";
+ const file = new File([], "test.json");
+ // @ts-expect-error: This is set only in the case of an electron app
+ file.path = fullPath;
+ const fileWithPath = toFileWithPath(file, path);
+ expect(fileWithPath.path).toBe(fullPath);
+ });
+
+ it("sets the {path} if provided", () => {
+ const path = "/test/test.json";
+ const file = new File([], "test.json");
+ const fileWithPath = toFileWithPath(file, path);
+ expect(fileWithPath.path).toBe(path);
+ });
+
+ test("{path} is enumerable", () => {
+ const path = "/test/test.json";
+ const file = new File([], "test.json");
+ const fileWithPath = toFileWithPath(file, path);
+
+ expect(Object.keys(fileWithPath)).toContain("path");
+
+ const keys: string[] = [];
+ for (const key in fileWithPath) {
+ keys.push(key);
+ }
- expect(Object.keys(fileWithPath)).toContain('type');
+ expect(keys).toContain("path");
+ });
+
+ it("uses the File {name} as {path} if not provided", () => {
+ const name = "test.json";
+ const file = new File([], name);
+ const fileWithPath = toFileWithPath(file);
+ expect(fileWithPath.path).toBe(`./${name}`);
+ });
+
+ it("uses the File {webkitRelativePath} as {path} if it exists", () => {
+ const name = "test.json";
+ const path = "test/test.json";
+ const file = new File([], name);
+ Object.defineProperty(file, "webkitRelativePath", {
+ value: path,
+ });
+ const fileWithPath = toFileWithPath(file);
+ expect(fileWithPath.path).toBe(path);
+ });
+
+ it("sets the {relativePath} if provided without overwriting {path}", () => {
+ const fullPath = "/Users/test/Desktop/test/test.json";
+ const path = "/test/test.json";
+ const file = new File([], "test.json");
+
+ // @ts-expect-error: This is set only in the case of an electron app
+ file.path = fullPath;
+ const fileWithPath = toFileWithPath(file, path);
+ expect(fileWithPath.path).toBe(fullPath);
+ expect(fileWithPath.relativePath).toBe(path);
+ });
+
+ test("{relativePath} is enumerable", () => {
+ const path = "/test/test.json";
+ const file = new File([], "test.json");
+ const fileWithPath = toFileWithPath(file, path);
+
+ expect(Object.keys(fileWithPath)).toContain("relativePath");
+
+ const keys: string[] = [];
+ for (const key in fileWithPath) {
+ keys.push(key);
+ }
- const keys: string[] = [];
- for (const key in fileWithPath) {
- keys.push(key);
- }
+ expect(keys).toContain("relativePath");
+ });
- expect(keys).toContain('type');
+ it("uses the File {webkitRelativePath} as {relativePath} if it exists", () => {
+ const name = "test.json";
+ const path = "test/test.json";
+ const file = new File([], name);
+ Object.defineProperty(file, "webkitRelativePath", {
+ value: path,
});
+ const fileWithPath = toFileWithPath(file);
+ expect(fileWithPath.relativePath).toBe(path);
+ });
- it('sets the {type} from extension regardless of case', () => {
- const types = Array.from(COMMON_MIME_TYPES.values());
- const files = Array.from(COMMON_MIME_TYPES.keys())
- .map(key => key.toUpperCase())
- .map(ext => new File([], `test.${ext}`))
- .map(f => toFileWithPath(f));
+ it("sets the {type} from extension", () => {
+ const types = Array.from(COMMON_MIME_TYPES.values());
+ const files = Array.from(COMMON_MIME_TYPES.keys())
+ .map((ext) => new File([], `test.${ext}`))
+ .map((f) => toFileWithPath(f));
- for (const file of files) {
- expect(types.includes(file.type)).toBe(true);
- }
- });
+ for (const file of files) {
+ expect(types.includes(file.type)).toBe(true);
+ }
+ });
- it('should behave like a File', done => {
- const data = {ping: true};
- const json = JSON.stringify(data);
- const file = new File([json], 'test.json');
- const fileWithPath = toFileWithPath(file);
-
- const reader = new FileReader();
- reader.onload = evt => {
- try {
- const d = JSON.parse(evt.target?.result as string);
- expect(d).toEqual(data);
- done();
- } catch (e) {
- done.fail(e as Error);
- }
- };
-
- reader.readAsText(fileWithPath);
- });
+ test("{type} is enumerable", () => {
+ const file = new File([], "test.gif");
+ const fileWithPath = toFileWithPath(file);
- it('sets the {handle} if provided', () => {
- const path = '/test/test.json';
- const file = new File([], 'test.json');
- const fileWithHandle = toFileWithPath(file, path, fsHandleFromFile(file));
- expect(fileWithHandle.handle).toBeDefined();
- expect(fileWithHandle.handle?.name).toEqual(file.name);
- });
+ expect(Object.keys(fileWithPath)).toContain("type");
- test('{handle} is enumerable', () => {
- const path = '/test/test.json';
- const file = new File([], 'test.json');
- const fileWithHandle = toFileWithPath(file, path, fsHandleFromFile(file));
+ const keys: string[] = [];
+ for (const key in fileWithPath) {
+ keys.push(key);
+ }
- expect(Object.keys(fileWithHandle)).toContain('handle');
+ expect(keys).toContain("type");
+ });
- const keys: string[] = [];
- for (const key in fileWithHandle) {
- keys.push(key);
- }
+ it("sets the {type} from extension regardless of case", () => {
+ const types = Array.from(COMMON_MIME_TYPES.values());
+ const files = Array.from(COMMON_MIME_TYPES.keys())
+ .map((key) => key.toUpperCase())
+ .map((ext) => new File([], `test.${ext}`))
+ .map((f) => toFileWithPath(f));
- expect(keys).toContain('handle');
- });
+ for (const file of files) {
+ expect(types.includes(file.type)).toBe(true);
+ }
+ });
+
+ it("should behave like a File", (done) => {
+ const data = { ping: true };
+ const json = JSON.stringify(data);
+ const file = new File([json], "test.json");
+ const fileWithPath = toFileWithPath(file);
+
+ const reader = new FileReader();
+ reader.onload = (evt) => {
+ try {
+ const d = JSON.parse(evt.target?.result as string);
+ expect(d).toEqual(data);
+ done();
+ } catch (e) {
+ done.fail(e as Error);
+ }
+ };
+
+ reader.readAsText(fileWithPath);
+ });
+
+ it("sets the {handle} if provided", () => {
+ const path = "/test/test.json";
+ const file = new File([], "test.json");
+ const fileWithHandle = toFileWithPath(file, path, fsHandleFromFile(file));
+ expect(fileWithHandle.handle).toBeDefined();
+ expect(fileWithHandle.handle?.name).toEqual(file.name);
+ });
+
+ test("{handle} is enumerable", () => {
+ const path = "/test/test.json";
+ const file = new File([], "test.json");
+ const fileWithHandle = toFileWithPath(file, path, fsHandleFromFile(file));
+
+ expect(Object.keys(fileWithHandle)).toContain("handle");
+
+ const keys: string[] = [];
+ for (const key in fileWithHandle) {
+ keys.push(key);
+ }
+ expect(keys).toContain("handle");
+ });
});
function fsHandleFromFile(f: File): FileSystemHandle {
- return {
- kind: 'file',
- name: f.name,
- isSameEntry() {
- return Promise.resolve(false)
- }
- }
+ return {
+ kind: "file",
+ name: f.name,
+ isSameEntry() {
+ return Promise.resolve(false);
+ },
+ };
}
diff --git a/src/file.ts b/src/file.ts
index c33a201..7b4d8d1 100644
--- a/src/file.ts
+++ b/src/file.ts
@@ -1,1267 +1,1292 @@
export const COMMON_MIME_TYPES = new Map([
- // https://github.com/guzzle/psr7/blob/2d9260799e713f1c475d3c5fdc3d6561ff7441b2/src/MimeType.php
- ['1km', 'application/vnd.1000minds.decision-model+xml'],
- ['3dml', 'text/vnd.in3d.3dml'],
- ['3ds', 'image/x-3ds'],
- ['3g2', 'video/3gpp2'],
- ['3gp', 'video/3gp'],
- ['3gpp', 'video/3gpp'],
- ['3mf', 'model/3mf'],
- ['7z', 'application/x-7z-compressed'],
- ['7zip', 'application/x-7z-compressed'],
- ['123', 'application/vnd.lotus-1-2-3'],
- ['aab', 'application/x-authorware-bin'],
- ['aac', 'audio/x-acc'],
- ['aam', 'application/x-authorware-map'],
- ['aas', 'application/x-authorware-seg'],
- ['abw', 'application/x-abiword'],
- ['ac', 'application/vnd.nokia.n-gage.ac+xml'],
- ['ac3', 'audio/ac3'],
- ['acc', 'application/vnd.americandynamics.acc'],
- ['ace', 'application/x-ace-compressed'],
- ['acu', 'application/vnd.acucobol'],
- ['acutc', 'application/vnd.acucorp'],
- ['adp', 'audio/adpcm'],
- ['aep', 'application/vnd.audiograph'],
- ['afm', 'application/x-font-type1'],
- ['afp', 'application/vnd.ibm.modcap'],
- ['ahead', 'application/vnd.ahead.space'],
- ['ai', 'application/pdf'],
- ['aif', 'audio/x-aiff'],
- ['aifc', 'audio/x-aiff'],
- ['aiff', 'audio/x-aiff'],
- ['air', 'application/vnd.adobe.air-application-installer-package+zip'],
- ['ait', 'application/vnd.dvb.ait'],
- ['ami', 'application/vnd.amiga.ami'],
- ['amr', 'audio/amr'],
- ['apk', 'application/vnd.android.package-archive'],
- ['apng', 'image/apng'],
- ['appcache', 'text/cache-manifest'],
- ['application', 'application/x-ms-application'],
- ['apr', 'application/vnd.lotus-approach'],
- ['arc', 'application/x-freearc'],
- ['arj', 'application/x-arj'],
- ['asc', 'application/pgp-signature'],
- ['asf', 'video/x-ms-asf'],
- ['asm', 'text/x-asm'],
- ['aso', 'application/vnd.accpac.simply.aso'],
- ['asx', 'video/x-ms-asf'],
- ['atc', 'application/vnd.acucorp'],
- ['atom', 'application/atom+xml'],
- ['atomcat', 'application/atomcat+xml'],
- ['atomdeleted', 'application/atomdeleted+xml'],
- ['atomsvc', 'application/atomsvc+xml'],
- ['atx', 'application/vnd.antix.game-component'],
- ['au', 'audio/x-au'],
- ['avi', 'video/x-msvideo'],
- ['avif', 'image/avif'],
- ['aw', 'application/applixware'],
- ['azf', 'application/vnd.airzip.filesecure.azf'],
- ['azs', 'application/vnd.airzip.filesecure.azs'],
- ['azv', 'image/vnd.airzip.accelerator.azv'],
- ['azw', 'application/vnd.amazon.ebook'],
- ['b16', 'image/vnd.pco.b16'],
- ['bat', 'application/x-msdownload'],
- ['bcpio', 'application/x-bcpio'],
- ['bdf', 'application/x-font-bdf'],
- ['bdm', 'application/vnd.syncml.dm+wbxml'],
- ['bdoc', 'application/x-bdoc'],
- ['bed', 'application/vnd.realvnc.bed'],
- ['bh2', 'application/vnd.fujitsu.oasysprs'],
- ['bin', 'application/octet-stream'],
- ['blb', 'application/x-blorb'],
- ['blorb', 'application/x-blorb'],
- ['bmi', 'application/vnd.bmi'],
- ['bmml', 'application/vnd.balsamiq.bmml+xml'],
- ['bmp', 'image/bmp'],
- ['book', 'application/vnd.framemaker'],
- ['box', 'application/vnd.previewsystems.box'],
- ['boz', 'application/x-bzip2'],
- ['bpk', 'application/octet-stream'],
- ['bpmn', 'application/octet-stream'],
- ['bsp', 'model/vnd.valve.source.compiled-map'],
- ['btif', 'image/prs.btif'],
- ['buffer', 'application/octet-stream'],
- ['bz', 'application/x-bzip'],
- ['bz2', 'application/x-bzip2'],
- ['c', 'text/x-c'],
- ['c4d', 'application/vnd.clonk.c4group'],
- ['c4f', 'application/vnd.clonk.c4group'],
- ['c4g', 'application/vnd.clonk.c4group'],
- ['c4p', 'application/vnd.clonk.c4group'],
- ['c4u', 'application/vnd.clonk.c4group'],
- ['c11amc', 'application/vnd.cluetrust.cartomobile-config'],
- ['c11amz', 'application/vnd.cluetrust.cartomobile-config-pkg'],
- ['cab', 'application/vnd.ms-cab-compressed'],
- ['caf', 'audio/x-caf'],
- ['cap', 'application/vnd.tcpdump.pcap'],
- ['car', 'application/vnd.curl.car'],
- ['cat', 'application/vnd.ms-pki.seccat'],
- ['cb7', 'application/x-cbr'],
- ['cba', 'application/x-cbr'],
- ['cbr', 'application/x-cbr'],
- ['cbt', 'application/x-cbr'],
- ['cbz', 'application/x-cbr'],
- ['cc', 'text/x-c'],
- ['cco', 'application/x-cocoa'],
- ['cct', 'application/x-director'],
- ['ccxml', 'application/ccxml+xml'],
- ['cdbcmsg', 'application/vnd.contact.cmsg'],
- ['cda', 'application/x-cdf'],
- ['cdf', 'application/x-netcdf'],
- ['cdfx', 'application/cdfx+xml'],
- ['cdkey', 'application/vnd.mediastation.cdkey'],
- ['cdmia', 'application/cdmi-capability'],
- ['cdmic', 'application/cdmi-container'],
- ['cdmid', 'application/cdmi-domain'],
- ['cdmio', 'application/cdmi-object'],
- ['cdmiq', 'application/cdmi-queue'],
- ['cdr', 'application/cdr'],
- ['cdx', 'chemical/x-cdx'],
- ['cdxml', 'application/vnd.chemdraw+xml'],
- ['cdy', 'application/vnd.cinderella'],
- ['cer', 'application/pkix-cert'],
- ['cfs', 'application/x-cfs-compressed'],
- ['cgm', 'image/cgm'],
- ['chat', 'application/x-chat'],
- ['chm', 'application/vnd.ms-htmlhelp'],
- ['chrt', 'application/vnd.kde.kchart'],
- ['cif', 'chemical/x-cif'],
- ['cii', 'application/vnd.anser-web-certificate-issue-initiation'],
- ['cil', 'application/vnd.ms-artgalry'],
- ['cjs', 'application/node'],
- ['cla', 'application/vnd.claymore'],
- ['class', 'application/octet-stream'],
- ['clkk', 'application/vnd.crick.clicker.keyboard'],
- ['clkp', 'application/vnd.crick.clicker.palette'],
- ['clkt', 'application/vnd.crick.clicker.template'],
- ['clkw', 'application/vnd.crick.clicker.wordbank'],
- ['clkx', 'application/vnd.crick.clicker'],
- ['clp', 'application/x-msclip'],
- ['cmc', 'application/vnd.cosmocaller'],
- ['cmdf', 'chemical/x-cmdf'],
- ['cml', 'chemical/x-cml'],
- ['cmp', 'application/vnd.yellowriver-custom-menu'],
- ['cmx', 'image/x-cmx'],
- ['cod', 'application/vnd.rim.cod'],
- ['coffee', 'text/coffeescript'],
- ['com', 'application/x-msdownload'],
- ['conf', 'text/plain'],
- ['cpio', 'application/x-cpio'],
- ['cpp', 'text/x-c'],
- ['cpt', 'application/mac-compactpro'],
- ['crd', 'application/x-mscardfile'],
- ['crl', 'application/pkix-crl'],
- ['crt', 'application/x-x509-ca-cert'],
- ['crx', 'application/x-chrome-extension'],
- ['cryptonote', 'application/vnd.rig.cryptonote'],
- ['csh', 'application/x-csh'],
- ['csl', 'application/vnd.citationstyles.style+xml'],
- ['csml', 'chemical/x-csml'],
- ['csp', 'application/vnd.commonspace'],
- ['csr', 'application/octet-stream'],
- ['css', 'text/css'],
- ['cst', 'application/x-director'],
- ['csv', 'text/csv'],
- ['cu', 'application/cu-seeme'],
- ['curl', 'text/vnd.curl'],
- ['cww', 'application/prs.cww'],
- ['cxt', 'application/x-director'],
- ['cxx', 'text/x-c'],
- ['dae', 'model/vnd.collada+xml'],
- ['daf', 'application/vnd.mobius.daf'],
- ['dart', 'application/vnd.dart'],
- ['dataless', 'application/vnd.fdsn.seed'],
- ['davmount', 'application/davmount+xml'],
- ['dbf', 'application/vnd.dbf'],
- ['dbk', 'application/docbook+xml'],
- ['dcr', 'application/x-director'],
- ['dcurl', 'text/vnd.curl.dcurl'],
- ['dd2', 'application/vnd.oma.dd2+xml'],
- ['ddd', 'application/vnd.fujixerox.ddd'],
- ['ddf', 'application/vnd.syncml.dmddf+xml'],
- ['dds', 'image/vnd.ms-dds'],
- ['deb', 'application/x-debian-package'],
- ['def', 'text/plain'],
- ['deploy', 'application/octet-stream'],
- ['der', 'application/x-x509-ca-cert'],
- ['dfac', 'application/vnd.dreamfactory'],
- ['dgc', 'application/x-dgc-compressed'],
- ['dic', 'text/x-c'],
- ['dir', 'application/x-director'],
- ['dis', 'application/vnd.mobius.dis'],
- ['disposition-notification', 'message/disposition-notification'],
- ['dist', 'application/octet-stream'],
- ['distz', 'application/octet-stream'],
- ['djv', 'image/vnd.djvu'],
- ['djvu', 'image/vnd.djvu'],
- ['dll', 'application/octet-stream'],
- ['dmg', 'application/x-apple-diskimage'],
- ['dmn', 'application/octet-stream'],
- ['dmp', 'application/vnd.tcpdump.pcap'],
- ['dms', 'application/octet-stream'],
- ['dna', 'application/vnd.dna'],
- ['doc', 'application/msword'],
- ['docm', 'application/vnd.ms-word.template.macroEnabled.12'],
- ['docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
- ['dot', 'application/msword'],
- ['dotm', 'application/vnd.ms-word.template.macroEnabled.12'],
- ['dotx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.template'],
- ['dp', 'application/vnd.osgi.dp'],
- ['dpg', 'application/vnd.dpgraph'],
- ['dra', 'audio/vnd.dra'],
- ['drle', 'image/dicom-rle'],
- ['dsc', 'text/prs.lines.tag'],
- ['dssc', 'application/dssc+der'],
- ['dtb', 'application/x-dtbook+xml'],
- ['dtd', 'application/xml-dtd'],
- ['dts', 'audio/vnd.dts'],
- ['dtshd', 'audio/vnd.dts.hd'],
- ['dump', 'application/octet-stream'],
- ['dvb', 'video/vnd.dvb.file'],
- ['dvi', 'application/x-dvi'],
- ['dwd', 'application/atsc-dwd+xml'],
- ['dwf', 'model/vnd.dwf'],
- ['dwg', 'image/vnd.dwg'],
- ['dxf', 'image/vnd.dxf'],
- ['dxp', 'application/vnd.spotfire.dxp'],
- ['dxr', 'application/x-director'],
- ['ear', 'application/java-archive'],
- ['ecelp4800', 'audio/vnd.nuera.ecelp4800'],
- ['ecelp7470', 'audio/vnd.nuera.ecelp7470'],
- ['ecelp9600', 'audio/vnd.nuera.ecelp9600'],
- ['ecma', 'application/ecmascript'],
- ['edm', 'application/vnd.novadigm.edm'],
- ['edx', 'application/vnd.novadigm.edx'],
- ['efif', 'application/vnd.picsel'],
- ['ei6', 'application/vnd.pg.osasli'],
- ['elc', 'application/octet-stream'],
- ['emf', 'image/emf'],
- ['eml', 'message/rfc822'],
- ['emma', 'application/emma+xml'],
- ['emotionml', 'application/emotionml+xml'],
- ['emz', 'application/x-msmetafile'],
- ['eol', 'audio/vnd.digital-winds'],
- ['eot', 'application/vnd.ms-fontobject'],
- ['eps', 'application/postscript'],
- ['epub', 'application/epub+zip'],
- ['es', 'application/ecmascript'],
- ['es3', 'application/vnd.eszigno3+xml'],
- ['esa', 'application/vnd.osgi.subsystem'],
- ['esf', 'application/vnd.epson.esf'],
- ['et3', 'application/vnd.eszigno3+xml'],
- ['etx', 'text/x-setext'],
- ['eva', 'application/x-eva'],
- ['evy', 'application/x-envoy'],
- ['exe', 'application/octet-stream'],
- ['exi', 'application/exi'],
- ['exp', 'application/express'],
- ['exr', 'image/aces'],
- ['ext', 'application/vnd.novadigm.ext'],
- ['ez', 'application/andrew-inset'],
- ['ez2', 'application/vnd.ezpix-album'],
- ['ez3', 'application/vnd.ezpix-package'],
- ['f', 'text/x-fortran'],
- ['f4v', 'video/mp4'],
- ['f77', 'text/x-fortran'],
- ['f90', 'text/x-fortran'],
- ['fbs', 'image/vnd.fastbidsheet'],
- ['fcdt', 'application/vnd.adobe.formscentral.fcdt'],
- ['fcs', 'application/vnd.isac.fcs'],
- ['fdf', 'application/vnd.fdf'],
- ['fdt', 'application/fdt+xml'],
- ['fe_launch', 'application/vnd.denovo.fcselayout-link'],
- ['fg5', 'application/vnd.fujitsu.oasysgp'],
- ['fgd', 'application/x-director'],
- ['fh', 'image/x-freehand'],
- ['fh4', 'image/x-freehand'],
- ['fh5', 'image/x-freehand'],
- ['fh7', 'image/x-freehand'],
- ['fhc', 'image/x-freehand'],
- ['fig', 'application/x-xfig'],
- ['fits', 'image/fits'],
- ['flac', 'audio/x-flac'],
- ['fli', 'video/x-fli'],
- ['flo', 'application/vnd.micrografx.flo'],
- ['flv', 'video/x-flv'],
- ['flw', 'application/vnd.kde.kivio'],
- ['flx', 'text/vnd.fmi.flexstor'],
- ['fly', 'text/vnd.fly'],
- ['fm', 'application/vnd.framemaker'],
- ['fnc', 'application/vnd.frogans.fnc'],
- ['fo', 'application/vnd.software602.filler.form+xml'],
- ['for', 'text/x-fortran'],
- ['fpx', 'image/vnd.fpx'],
- ['frame', 'application/vnd.framemaker'],
- ['fsc', 'application/vnd.fsc.weblaunch'],
- ['fst', 'image/vnd.fst'],
- ['ftc', 'application/vnd.fluxtime.clip'],
- ['fti', 'application/vnd.anser-web-funds-transfer-initiation'],
- ['fvt', 'video/vnd.fvt'],
- ['fxp', 'application/vnd.adobe.fxp'],
- ['fxpl', 'application/vnd.adobe.fxp'],
- ['fzs', 'application/vnd.fuzzysheet'],
- ['g2w', 'application/vnd.geoplan'],
- ['g3', 'image/g3fax'],
- ['g3w', 'application/vnd.geospace'],
- ['gac', 'application/vnd.groove-account'],
- ['gam', 'application/x-tads'],
- ['gbr', 'application/rpki-ghostbusters'],
- ['gca', 'application/x-gca-compressed'],
- ['gdl', 'model/vnd.gdl'],
- ['gdoc', 'application/vnd.google-apps.document'],
- ['geo', 'application/vnd.dynageo'],
- ['geojson', 'application/geo+json'],
- ['gex', 'application/vnd.geometry-explorer'],
- ['ggb', 'application/vnd.geogebra.file'],
- ['ggt', 'application/vnd.geogebra.tool'],
- ['ghf', 'application/vnd.groove-help'],
- ['gif', 'image/gif'],
- ['gim', 'application/vnd.groove-identity-message'],
- ['glb', 'model/gltf-binary'],
- ['gltf', 'model/gltf+json'],
- ['gml', 'application/gml+xml'],
- ['gmx', 'application/vnd.gmx'],
- ['gnumeric', 'application/x-gnumeric'],
- ['gpg', 'application/gpg-keys'],
- ['gph', 'application/vnd.flographit'],
- ['gpx', 'application/gpx+xml'],
- ['gqf', 'application/vnd.grafeq'],
- ['gqs', 'application/vnd.grafeq'],
- ['gram', 'application/srgs'],
- ['gramps', 'application/x-gramps-xml'],
- ['gre', 'application/vnd.geometry-explorer'],
- ['grv', 'application/vnd.groove-injector'],
- ['grxml', 'application/srgs+xml'],
- ['gsf', 'application/x-font-ghostscript'],
- ['gsheet', 'application/vnd.google-apps.spreadsheet'],
- ['gslides', 'application/vnd.google-apps.presentation'],
- ['gtar', 'application/x-gtar'],
- ['gtm', 'application/vnd.groove-tool-message'],
- ['gtw', 'model/vnd.gtw'],
- ['gv', 'text/vnd.graphviz'],
- ['gxf', 'application/gxf'],
- ['gxt', 'application/vnd.geonext'],
- ['gz', 'application/gzip'],
- ['gzip', 'application/gzip'],
- ['h', 'text/x-c'],
- ['h261', 'video/h261'],
- ['h263', 'video/h263'],
- ['h264', 'video/h264'],
- ['hal', 'application/vnd.hal+xml'],
- ['hbci', 'application/vnd.hbci'],
- ['hbs', 'text/x-handlebars-template'],
- ['hdd', 'application/x-virtualbox-hdd'],
- ['hdf', 'application/x-hdf'],
- ['heic', 'image/heic'],
- ['heics', 'image/heic-sequence'],
- ['heif', 'image/heif'],
- ['heifs', 'image/heif-sequence'],
- ['hej2', 'image/hej2k'],
- ['held', 'application/atsc-held+xml'],
- ['hh', 'text/x-c'],
- ['hjson', 'application/hjson'],
- ['hlp', 'application/winhlp'],
- ['hpgl', 'application/vnd.hp-hpgl'],
- ['hpid', 'application/vnd.hp-hpid'],
- ['hps', 'application/vnd.hp-hps'],
- ['hqx', 'application/mac-binhex40'],
- ['hsj2', 'image/hsj2'],
- ['htc', 'text/x-component'],
- ['htke', 'application/vnd.kenameaapp'],
- ['htm', 'text/html'],
- ['html', 'text/html'],
- ['hvd', 'application/vnd.yamaha.hv-dic'],
- ['hvp', 'application/vnd.yamaha.hv-voice'],
- ['hvs', 'application/vnd.yamaha.hv-script'],
- ['i2g', 'application/vnd.intergeo'],
- ['icc', 'application/vnd.iccprofile'],
- ['ice', 'x-conference/x-cooltalk'],
- ['icm', 'application/vnd.iccprofile'],
- ['ico', 'image/x-icon'],
- ['ics', 'text/calendar'],
- ['ief', 'image/ief'],
- ['ifb', 'text/calendar'],
- ['ifm', 'application/vnd.shana.informed.formdata'],
- ['iges', 'model/iges'],
- ['igl', 'application/vnd.igloader'],
- ['igm', 'application/vnd.insors.igm'],
- ['igs', 'model/iges'],
- ['igx', 'application/vnd.micrografx.igx'],
- ['iif', 'application/vnd.shana.informed.interchange'],
- ['img', 'application/octet-stream'],
- ['imp', 'application/vnd.accpac.simply.imp'],
- ['ims', 'application/vnd.ms-ims'],
- ['in', 'text/plain'],
- ['ini', 'text/plain'],
- ['ink', 'application/inkml+xml'],
- ['inkml', 'application/inkml+xml'],
- ['install', 'application/x-install-instructions'],
- ['iota', 'application/vnd.astraea-software.iota'],
- ['ipfix', 'application/ipfix'],
- ['ipk', 'application/vnd.shana.informed.package'],
- ['irm', 'application/vnd.ibm.rights-management'],
- ['irp', 'application/vnd.irepository.package+xml'],
- ['iso', 'application/x-iso9660-image'],
- ['itp', 'application/vnd.shana.informed.formtemplate'],
- ['its', 'application/its+xml'],
- ['ivp', 'application/vnd.immervision-ivp'],
- ['ivu', 'application/vnd.immervision-ivu'],
- ['jad', 'text/vnd.sun.j2me.app-descriptor'],
- ['jade', 'text/jade'],
- ['jam', 'application/vnd.jam'],
- ['jar', 'application/java-archive'],
- ['jardiff', 'application/x-java-archive-diff'],
- ['java', 'text/x-java-source'],
- ['jhc', 'image/jphc'],
- ['jisp', 'application/vnd.jisp'],
- ['jls', 'image/jls'],
- ['jlt', 'application/vnd.hp-jlyt'],
- ['jng', 'image/x-jng'],
- ['jnlp', 'application/x-java-jnlp-file'],
- ['joda', 'application/vnd.joost.joda-archive'],
- ['jp2', 'image/jp2'],
- ['jpe', 'image/jpeg'],
- ['jpeg', 'image/jpeg'],
- ['jpf', 'image/jpx'],
- ['jpg', 'image/jpeg'],
- ['jpg2', 'image/jp2'],
- ['jpgm', 'video/jpm'],
- ['jpgv', 'video/jpeg'],
- ['jph', 'image/jph'],
- ['jpm', 'video/jpm'],
- ['jpx', 'image/jpx'],
- ['js', 'application/javascript'],
- ['json', 'application/json'],
- ['json5', 'application/json5'],
- ['jsonld', 'application/ld+json'],
- // https://jsonlines.org/
- ['jsonl', 'application/jsonl'],
- ['jsonml', 'application/jsonml+json'],
- ['jsx', 'text/jsx'],
- ['jxr', 'image/jxr'],
- ['jxra', 'image/jxra'],
- ['jxrs', 'image/jxrs'],
- ['jxs', 'image/jxs'],
- ['jxsc', 'image/jxsc'],
- ['jxsi', 'image/jxsi'],
- ['jxss', 'image/jxss'],
- ['kar', 'audio/midi'],
- ['karbon', 'application/vnd.kde.karbon'],
- ['kdb', 'application/octet-stream'],
- ['kdbx', 'application/x-keepass2'],
- ['key', 'application/x-iwork-keynote-sffkey'],
- ['kfo', 'application/vnd.kde.kformula'],
- ['kia', 'application/vnd.kidspiration'],
- ['kml', 'application/vnd.google-earth.kml+xml'],
- ['kmz', 'application/vnd.google-earth.kmz'],
- ['kne', 'application/vnd.kinar'],
- ['knp', 'application/vnd.kinar'],
- ['kon', 'application/vnd.kde.kontour'],
- ['kpr', 'application/vnd.kde.kpresenter'],
- ['kpt', 'application/vnd.kde.kpresenter'],
- ['kpxx', 'application/vnd.ds-keypoint'],
- ['ksp', 'application/vnd.kde.kspread'],
- ['ktr', 'application/vnd.kahootz'],
- ['ktx', 'image/ktx'],
- ['ktx2', 'image/ktx2'],
- ['ktz', 'application/vnd.kahootz'],
- ['kwd', 'application/vnd.kde.kword'],
- ['kwt', 'application/vnd.kde.kword'],
- ['lasxml', 'application/vnd.las.las+xml'],
- ['latex', 'application/x-latex'],
- ['lbd', 'application/vnd.llamagraphics.life-balance.desktop'],
- ['lbe', 'application/vnd.llamagraphics.life-balance.exchange+xml'],
- ['les', 'application/vnd.hhe.lesson-player'],
- ['less', 'text/less'],
- ['lgr', 'application/lgr+xml'],
- ['lha', 'application/octet-stream'],
- ['link66', 'application/vnd.route66.link66+xml'],
- ['list', 'text/plain'],
- ['list3820', 'application/vnd.ibm.modcap'],
- ['listafp', 'application/vnd.ibm.modcap'],
- ['litcoffee', 'text/coffeescript'],
- ['lnk', 'application/x-ms-shortcut'],
- ['log', 'text/plain'],
- ['lostxml', 'application/lost+xml'],
- ['lrf', 'application/octet-stream'],
- ['lrm', 'application/vnd.ms-lrm'],
- ['ltf', 'application/vnd.frogans.ltf'],
- ['lua', 'text/x-lua'],
- ['luac', 'application/x-lua-bytecode'],
- ['lvp', 'audio/vnd.lucent.voice'],
- ['lwp', 'application/vnd.lotus-wordpro'],
- ['lzh', 'application/octet-stream'],
- ['m1v', 'video/mpeg'],
- ['m2a', 'audio/mpeg'],
- ['m2v', 'video/mpeg'],
- ['m3a', 'audio/mpeg'],
- ['m3u', 'text/plain'],
- ['m3u8', 'application/vnd.apple.mpegurl'],
- ['m4a', 'audio/x-m4a'],
- ['m4p', 'application/mp4'],
- ['m4s', 'video/iso.segment'],
- ['m4u', 'application/vnd.mpegurl'],
- ['m4v', 'video/x-m4v'],
- ['m13', 'application/x-msmediaview'],
- ['m14', 'application/x-msmediaview'],
- ['m21', 'application/mp21'],
- ['ma', 'application/mathematica'],
- ['mads', 'application/mads+xml'],
- ['maei', 'application/mmt-aei+xml'],
- ['mag', 'application/vnd.ecowin.chart'],
- ['maker', 'application/vnd.framemaker'],
- ['man', 'text/troff'],
- ['manifest', 'text/cache-manifest'],
- ['map', 'application/json'],
- ['mar', 'application/octet-stream'],
- ['markdown', 'text/markdown'],
- ['mathml', 'application/mathml+xml'],
- ['mb', 'application/mathematica'],
- ['mbk', 'application/vnd.mobius.mbk'],
- ['mbox', 'application/mbox'],
- ['mc1', 'application/vnd.medcalcdata'],
- ['mcd', 'application/vnd.mcd'],
- ['mcurl', 'text/vnd.curl.mcurl'],
- ['md', 'text/markdown'],
- ['mdb', 'application/x-msaccess'],
- ['mdi', 'image/vnd.ms-modi'],
- ['mdx', 'text/mdx'],
- ['me', 'text/troff'],
- ['mesh', 'model/mesh'],
- ['meta4', 'application/metalink4+xml'],
- ['metalink', 'application/metalink+xml'],
- ['mets', 'application/mets+xml'],
- ['mfm', 'application/vnd.mfmp'],
- ['mft', 'application/rpki-manifest'],
- ['mgp', 'application/vnd.osgeo.mapguide.package'],
- ['mgz', 'application/vnd.proteus.magazine'],
- ['mid', 'audio/midi'],
- ['midi', 'audio/midi'],
- ['mie', 'application/x-mie'],
- ['mif', 'application/vnd.mif'],
- ['mime', 'message/rfc822'],
- ['mj2', 'video/mj2'],
- ['mjp2', 'video/mj2'],
- ['mjs', 'application/javascript'],
- ['mk3d', 'video/x-matroska'],
- ['mka', 'audio/x-matroska'],
- ['mkd', 'text/x-markdown'],
- ['mks', 'video/x-matroska'],
- ['mkv', 'video/x-matroska'],
- ['mlp', 'application/vnd.dolby.mlp'],
- ['mmd', 'application/vnd.chipnuts.karaoke-mmd'],
- ['mmf', 'application/vnd.smaf'],
- ['mml', 'text/mathml'],
- ['mmr', 'image/vnd.fujixerox.edmics-mmr'],
- ['mng', 'video/x-mng'],
- ['mny', 'application/x-msmoney'],
- ['mobi', 'application/x-mobipocket-ebook'],
- ['mods', 'application/mods+xml'],
- ['mov', 'video/quicktime'],
- ['movie', 'video/x-sgi-movie'],
- ['mp2', 'audio/mpeg'],
- ['mp2a', 'audio/mpeg'],
- ['mp3', 'audio/mpeg'],
- ['mp4', 'video/mp4'],
- ['mp4a', 'audio/mp4'],
- ['mp4s', 'application/mp4'],
- ['mp4v', 'video/mp4'],
- ['mp21', 'application/mp21'],
- ['mpc', 'application/vnd.mophun.certificate'],
- ['mpd', 'application/dash+xml'],
- ['mpe', 'video/mpeg'],
- ['mpeg', 'video/mpeg'],
- ['mpg', 'video/mpeg'],
- ['mpg4', 'video/mp4'],
- ['mpga', 'audio/mpeg'],
- ['mpkg', 'application/vnd.apple.installer+xml'],
- ['mpm', 'application/vnd.blueice.multipass'],
- ['mpn', 'application/vnd.mophun.application'],
- ['mpp', 'application/vnd.ms-project'],
- ['mpt', 'application/vnd.ms-project'],
- ['mpy', 'application/vnd.ibm.minipay'],
- ['mqy', 'application/vnd.mobius.mqy'],
- ['mrc', 'application/marc'],
- ['mrcx', 'application/marcxml+xml'],
- ['ms', 'text/troff'],
- ['mscml', 'application/mediaservercontrol+xml'],
- ['mseed', 'application/vnd.fdsn.mseed'],
- ['mseq', 'application/vnd.mseq'],
- ['msf', 'application/vnd.epson.msf'],
- ['msg', 'application/vnd.ms-outlook'],
- ['msh', 'model/mesh'],
- ['msi', 'application/x-msdownload'],
- ['msl', 'application/vnd.mobius.msl'],
- ['msm', 'application/octet-stream'],
- ['msp', 'application/octet-stream'],
- ['msty', 'application/vnd.muvee.style'],
- ['mtl', 'model/mtl'],
- ['mts', 'model/vnd.mts'],
- ['mus', 'application/vnd.musician'],
- ['musd', 'application/mmt-usd+xml'],
- ['musicxml', 'application/vnd.recordare.musicxml+xml'],
- ['mvb', 'application/x-msmediaview'],
- ['mvt', 'application/vnd.mapbox-vector-tile'],
- ['mwf', 'application/vnd.mfer'],
- ['mxf', 'application/mxf'],
- ['mxl', 'application/vnd.recordare.musicxml'],
- ['mxmf', 'audio/mobile-xmf'],
- ['mxml', 'application/xv+xml'],
- ['mxs', 'application/vnd.triscape.mxs'],
- ['mxu', 'video/vnd.mpegurl'],
- ['n-gage', 'application/vnd.nokia.n-gage.symbian.install'],
- ['n3', 'text/n3'],
- ['nb', 'application/mathematica'],
- ['nbp', 'application/vnd.wolfram.player'],
- ['nc', 'application/x-netcdf'],
- ['ncx', 'application/x-dtbncx+xml'],
- ['nfo', 'text/x-nfo'],
- ['ngdat', 'application/vnd.nokia.n-gage.data'],
- ['nitf', 'application/vnd.nitf'],
- ['nlu', 'application/vnd.neurolanguage.nlu'],
- ['nml', 'application/vnd.enliven'],
- ['nnd', 'application/vnd.noblenet-directory'],
- ['nns', 'application/vnd.noblenet-sealer'],
- ['nnw', 'application/vnd.noblenet-web'],
- ['npx', 'image/vnd.net-fpx'],
- ['nq', 'application/n-quads'],
- ['nsc', 'application/x-conference'],
- ['nsf', 'application/vnd.lotus-notes'],
- ['nt', 'application/n-triples'],
- ['ntf', 'application/vnd.nitf'],
- ['numbers', 'application/x-iwork-numbers-sffnumbers'],
- ['nzb', 'application/x-nzb'],
- ['oa2', 'application/vnd.fujitsu.oasys2'],
- ['oa3', 'application/vnd.fujitsu.oasys3'],
- ['oas', 'application/vnd.fujitsu.oasys'],
- ['obd', 'application/x-msbinder'],
- ['obgx', 'application/vnd.openblox.game+xml'],
- ['obj', 'model/obj'],
- ['oda', 'application/oda'],
- ['odb', 'application/vnd.oasis.opendocument.database'],
- ['odc', 'application/vnd.oasis.opendocument.chart'],
- ['odf', 'application/vnd.oasis.opendocument.formula'],
- ['odft', 'application/vnd.oasis.opendocument.formula-template'],
- ['odg', 'application/vnd.oasis.opendocument.graphics'],
- ['odi', 'application/vnd.oasis.opendocument.image'],
- ['odm', 'application/vnd.oasis.opendocument.text-master'],
- ['odp', 'application/vnd.oasis.opendocument.presentation'],
- ['ods', 'application/vnd.oasis.opendocument.spreadsheet'],
- ['odt', 'application/vnd.oasis.opendocument.text'],
- ['oga', 'audio/ogg'],
- ['ogex', 'model/vnd.opengex'],
- ['ogg', 'audio/ogg'],
- ['ogv', 'video/ogg'],
- ['ogx', 'application/ogg'],
- ['omdoc', 'application/omdoc+xml'],
- ['onepkg', 'application/onenote'],
- ['onetmp', 'application/onenote'],
- ['onetoc', 'application/onenote'],
- ['onetoc2', 'application/onenote'],
- ['opf', 'application/oebps-package+xml'],
- ['opml', 'text/x-opml'],
- ['oprc', 'application/vnd.palm'],
- ['opus', 'audio/ogg'],
- ['org', 'text/x-org'],
- ['osf', 'application/vnd.yamaha.openscoreformat'],
- ['osfpvg', 'application/vnd.yamaha.openscoreformat.osfpvg+xml'],
- ['osm', 'application/vnd.openstreetmap.data+xml'],
- ['otc', 'application/vnd.oasis.opendocument.chart-template'],
- ['otf', 'font/otf'],
- ['otg', 'application/vnd.oasis.opendocument.graphics-template'],
- ['oth', 'application/vnd.oasis.opendocument.text-web'],
- ['oti', 'application/vnd.oasis.opendocument.image-template'],
- ['otp', 'application/vnd.oasis.opendocument.presentation-template'],
- ['ots', 'application/vnd.oasis.opendocument.spreadsheet-template'],
- ['ott', 'application/vnd.oasis.opendocument.text-template'],
- ['ova', 'application/x-virtualbox-ova'],
- ['ovf', 'application/x-virtualbox-ovf'],
- ['owl', 'application/rdf+xml'],
- ['oxps', 'application/oxps'],
- ['oxt', 'application/vnd.openofficeorg.extension'],
- ['p', 'text/x-pascal'],
- ['p7a', 'application/x-pkcs7-signature'],
- ['p7b', 'application/x-pkcs7-certificates'],
- ['p7c', 'application/pkcs7-mime'],
- ['p7m', 'application/pkcs7-mime'],
- ['p7r', 'application/x-pkcs7-certreqresp'],
- ['p7s', 'application/pkcs7-signature'],
- ['p8', 'application/pkcs8'],
- ['p10', 'application/x-pkcs10'],
- ['p12', 'application/x-pkcs12'],
- ['pac', 'application/x-ns-proxy-autoconfig'],
- ['pages', 'application/x-iwork-pages-sffpages'],
- ['pas', 'text/x-pascal'],
- ['paw', 'application/vnd.pawaafile'],
- ['pbd', 'application/vnd.powerbuilder6'],
- ['pbm', 'image/x-portable-bitmap'],
- ['pcap', 'application/vnd.tcpdump.pcap'],
- ['pcf', 'application/x-font-pcf'],
- ['pcl', 'application/vnd.hp-pcl'],
- ['pclxl', 'application/vnd.hp-pclxl'],
- ['pct', 'image/x-pict'],
- ['pcurl', 'application/vnd.curl.pcurl'],
- ['pcx', 'image/x-pcx'],
- ['pdb', 'application/x-pilot'],
- ['pde', 'text/x-processing'],
- ['pdf', 'application/pdf'],
- ['pem', 'application/x-x509-user-cert'],
- ['pfa', 'application/x-font-type1'],
- ['pfb', 'application/x-font-type1'],
- ['pfm', 'application/x-font-type1'],
- ['pfr', 'application/font-tdpfr'],
- ['pfx', 'application/x-pkcs12'],
- ['pgm', 'image/x-portable-graymap'],
- ['pgn', 'application/x-chess-pgn'],
- ['pgp', 'application/pgp'],
- ['php', 'application/x-httpd-php'],
- ['php3', 'application/x-httpd-php'],
- ['php4', 'application/x-httpd-php'],
- ['phps', 'application/x-httpd-php-source'],
- ['phtml', 'application/x-httpd-php'],
- ['pic', 'image/x-pict'],
- ['pkg', 'application/octet-stream'],
- ['pki', 'application/pkixcmp'],
- ['pkipath', 'application/pkix-pkipath'],
- ['pkpass', 'application/vnd.apple.pkpass'],
- ['pl', 'application/x-perl'],
- ['plb', 'application/vnd.3gpp.pic-bw-large'],
- ['plc', 'application/vnd.mobius.plc'],
- ['plf', 'application/vnd.pocketlearn'],
- ['pls', 'application/pls+xml'],
- ['pm', 'application/x-perl'],
- ['pml', 'application/vnd.ctc-posml'],
- ['png', 'image/png'],
- ['pnm', 'image/x-portable-anymap'],
- ['portpkg', 'application/vnd.macports.portpkg'],
- ['pot', 'application/vnd.ms-powerpoint'],
- ['potm', 'application/vnd.ms-powerpoint.presentation.macroEnabled.12'],
- ['potx', 'application/vnd.openxmlformats-officedocument.presentationml.template'],
- ['ppa', 'application/vnd.ms-powerpoint'],
- ['ppam', 'application/vnd.ms-powerpoint.addin.macroEnabled.12'],
- ['ppd', 'application/vnd.cups-ppd'],
- ['ppm', 'image/x-portable-pixmap'],
- ['pps', 'application/vnd.ms-powerpoint'],
- ['ppsm', 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12'],
- ['ppsx', 'application/vnd.openxmlformats-officedocument.presentationml.slideshow'],
- ['ppt', 'application/powerpoint'],
- ['pptm', 'application/vnd.ms-powerpoint.presentation.macroEnabled.12'],
- ['pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
- ['pqa', 'application/vnd.palm'],
- ['prc', 'application/x-pilot'],
- ['pre', 'application/vnd.lotus-freelance'],
- ['prf', 'application/pics-rules'],
- ['provx', 'application/provenance+xml'],
- ['ps', 'application/postscript'],
- ['psb', 'application/vnd.3gpp.pic-bw-small'],
- ['psd', 'application/x-photoshop'],
- ['psf', 'application/x-font-linux-psf'],
- ['pskcxml', 'application/pskc+xml'],
- ['pti', 'image/prs.pti'],
- ['ptid', 'application/vnd.pvi.ptid1'],
- ['pub', 'application/x-mspublisher'],
- ['pvb', 'application/vnd.3gpp.pic-bw-var'],
- ['pwn', 'application/vnd.3m.post-it-notes'],
- ['pya', 'audio/vnd.ms-playready.media.pya'],
- ['pyv', 'video/vnd.ms-playready.media.pyv'],
- ['qam', 'application/vnd.epson.quickanime'],
- ['qbo', 'application/vnd.intu.qbo'],
- ['qfx', 'application/vnd.intu.qfx'],
- ['qps', 'application/vnd.publishare-delta-tree'],
- ['qt', 'video/quicktime'],
- ['qwd', 'application/vnd.quark.quarkxpress'],
- ['qwt', 'application/vnd.quark.quarkxpress'],
- ['qxb', 'application/vnd.quark.quarkxpress'],
- ['qxd', 'application/vnd.quark.quarkxpress'],
- ['qxl', 'application/vnd.quark.quarkxpress'],
- ['qxt', 'application/vnd.quark.quarkxpress'],
- ['ra', 'audio/x-realaudio'],
- ['ram', 'audio/x-pn-realaudio'],
- ['raml', 'application/raml+yaml'],
- ['rapd', 'application/route-apd+xml'],
- ['rar', 'application/x-rar'],
- ['ras', 'image/x-cmu-raster'],
- ['rcprofile', 'application/vnd.ipunplugged.rcprofile'],
- ['rdf', 'application/rdf+xml'],
- ['rdz', 'application/vnd.data-vision.rdz'],
- ['relo', 'application/p2p-overlay+xml'],
- ['rep', 'application/vnd.businessobjects'],
- ['res', 'application/x-dtbresource+xml'],
- ['rgb', 'image/x-rgb'],
- ['rif', 'application/reginfo+xml'],
- ['rip', 'audio/vnd.rip'],
- ['ris', 'application/x-research-info-systems'],
- ['rl', 'application/resource-lists+xml'],
- ['rlc', 'image/vnd.fujixerox.edmics-rlc'],
- ['rld', 'application/resource-lists-diff+xml'],
- ['rm', 'audio/x-pn-realaudio'],
- ['rmi', 'audio/midi'],
- ['rmp', 'audio/x-pn-realaudio-plugin'],
- ['rms', 'application/vnd.jcp.javame.midlet-rms'],
- ['rmvb', 'application/vnd.rn-realmedia-vbr'],
- ['rnc', 'application/relax-ng-compact-syntax'],
- ['rng', 'application/xml'],
- ['roa', 'application/rpki-roa'],
- ['roff', 'text/troff'],
- ['rp9', 'application/vnd.cloanto.rp9'],
- ['rpm', 'audio/x-pn-realaudio-plugin'],
- ['rpss', 'application/vnd.nokia.radio-presets'],
- ['rpst', 'application/vnd.nokia.radio-preset'],
- ['rq', 'application/sparql-query'],
- ['rs', 'application/rls-services+xml'],
- ['rsa', 'application/x-pkcs7'],
- ['rsat', 'application/atsc-rsat+xml'],
- ['rsd', 'application/rsd+xml'],
- ['rsheet', 'application/urc-ressheet+xml'],
- ['rss', 'application/rss+xml'],
- ['rtf', 'text/rtf'],
- ['rtx', 'text/richtext'],
- ['run', 'application/x-makeself'],
- ['rusd', 'application/route-usd+xml'],
- ['rv', 'video/vnd.rn-realvideo'],
- ['s', 'text/x-asm'],
- ['s3m', 'audio/s3m'],
- ['saf', 'application/vnd.yamaha.smaf-audio'],
- ['sass', 'text/x-sass'],
- ['sbml', 'application/sbml+xml'],
- ['sc', 'application/vnd.ibm.secure-container'],
- ['scd', 'application/x-msschedule'],
- ['scm', 'application/vnd.lotus-screencam'],
- ['scq', 'application/scvp-cv-request'],
- ['scs', 'application/scvp-cv-response'],
- ['scss', 'text/x-scss'],
- ['scurl', 'text/vnd.curl.scurl'],
- ['sda', 'application/vnd.stardivision.draw'],
- ['sdc', 'application/vnd.stardivision.calc'],
- ['sdd', 'application/vnd.stardivision.impress'],
- ['sdkd', 'application/vnd.solent.sdkm+xml'],
- ['sdkm', 'application/vnd.solent.sdkm+xml'],
- ['sdp', 'application/sdp'],
- ['sdw', 'application/vnd.stardivision.writer'],
- ['sea', 'application/octet-stream'],
- ['see', 'application/vnd.seemail'],
- ['seed', 'application/vnd.fdsn.seed'],
- ['sema', 'application/vnd.sema'],
- ['semd', 'application/vnd.semd'],
- ['semf', 'application/vnd.semf'],
- ['senmlx', 'application/senml+xml'],
- ['sensmlx', 'application/sensml+xml'],
- ['ser', 'application/java-serialized-object'],
- ['setpay', 'application/set-payment-initiation'],
- ['setreg', 'application/set-registration-initiation'],
- ['sfd-hdstx', 'application/vnd.hydrostatix.sof-data'],
- ['sfs', 'application/vnd.spotfire.sfs'],
- ['sfv', 'text/x-sfv'],
- ['sgi', 'image/sgi'],
- ['sgl', 'application/vnd.stardivision.writer-global'],
- ['sgm', 'text/sgml'],
- ['sgml', 'text/sgml'],
- ['sh', 'application/x-sh'],
- ['shar', 'application/x-shar'],
- ['shex', 'text/shex'],
- ['shf', 'application/shf+xml'],
- ['shtml', 'text/html'],
- ['sid', 'image/x-mrsid-image'],
- ['sieve', 'application/sieve'],
- ['sig', 'application/pgp-signature'],
- ['sil', 'audio/silk'],
- ['silo', 'model/mesh'],
- ['sis', 'application/vnd.symbian.install'],
- ['sisx', 'application/vnd.symbian.install'],
- ['sit', 'application/x-stuffit'],
- ['sitx', 'application/x-stuffitx'],
- ['siv', 'application/sieve'],
- ['skd', 'application/vnd.koan'],
- ['skm', 'application/vnd.koan'],
- ['skp', 'application/vnd.koan'],
- ['skt', 'application/vnd.koan'],
- ['sldm', 'application/vnd.ms-powerpoint.slide.macroenabled.12'],
- ['sldx', 'application/vnd.openxmlformats-officedocument.presentationml.slide'],
- ['slim', 'text/slim'],
- ['slm', 'text/slim'],
- ['sls', 'application/route-s-tsid+xml'],
- ['slt', 'application/vnd.epson.salt'],
- ['sm', 'application/vnd.stepmania.stepchart'],
- ['smf', 'application/vnd.stardivision.math'],
- ['smi', 'application/smil'],
- ['smil', 'application/smil'],
- ['smv', 'video/x-smv'],
- ['smzip', 'application/vnd.stepmania.package'],
- ['snd', 'audio/basic'],
- ['snf', 'application/x-font-snf'],
- ['so', 'application/octet-stream'],
- ['spc', 'application/x-pkcs7-certificates'],
- ['spdx', 'text/spdx'],
- ['spf', 'application/vnd.yamaha.smaf-phrase'],
- ['spl', 'application/x-futuresplash'],
- ['spot', 'text/vnd.in3d.spot'],
- ['spp', 'application/scvp-vp-response'],
- ['spq', 'application/scvp-vp-request'],
- ['spx', 'audio/ogg'],
- ['sql', 'application/x-sql'],
- ['src', 'application/x-wais-source'],
- ['srt', 'application/x-subrip'],
- ['sru', 'application/sru+xml'],
- ['srx', 'application/sparql-results+xml'],
- ['ssdl', 'application/ssdl+xml'],
- ['sse', 'application/vnd.kodak-descriptor'],
- ['ssf', 'application/vnd.epson.ssf'],
- ['ssml', 'application/ssml+xml'],
- ['sst', 'application/octet-stream'],
- ['st', 'application/vnd.sailingtracker.track'],
- ['stc', 'application/vnd.sun.xml.calc.template'],
- ['std', 'application/vnd.sun.xml.draw.template'],
- ['stf', 'application/vnd.wt.stf'],
- ['sti', 'application/vnd.sun.xml.impress.template'],
- ['stk', 'application/hyperstudio'],
- ['stl', 'model/stl'],
- ['stpx', 'model/step+xml'],
- ['stpxz', 'model/step-xml+zip'],
- ['stpz', 'model/step+zip'],
- ['str', 'application/vnd.pg.format'],
- ['stw', 'application/vnd.sun.xml.writer.template'],
- ['styl', 'text/stylus'],
- ['stylus', 'text/stylus'],
- ['sub', 'text/vnd.dvb.subtitle'],
- ['sus', 'application/vnd.sus-calendar'],
- ['susp', 'application/vnd.sus-calendar'],
- ['sv4cpio', 'application/x-sv4cpio'],
- ['sv4crc', 'application/x-sv4crc'],
- ['svc', 'application/vnd.dvb.service'],
- ['svd', 'application/vnd.svd'],
- ['svg', 'image/svg+xml'],
- ['svgz', 'image/svg+xml'],
- ['swa', 'application/x-director'],
- ['swf', 'application/x-shockwave-flash'],
- ['swi', 'application/vnd.aristanetworks.swi'],
- ['swidtag', 'application/swid+xml'],
- ['sxc', 'application/vnd.sun.xml.calc'],
- ['sxd', 'application/vnd.sun.xml.draw'],
- ['sxg', 'application/vnd.sun.xml.writer.global'],
- ['sxi', 'application/vnd.sun.xml.impress'],
- ['sxm', 'application/vnd.sun.xml.math'],
- ['sxw', 'application/vnd.sun.xml.writer'],
- ['t', 'text/troff'],
- ['t3', 'application/x-t3vm-image'],
- ['t38', 'image/t38'],
- ['taglet', 'application/vnd.mynfc'],
- ['tao', 'application/vnd.tao.intent-module-archive'],
- ['tap', 'image/vnd.tencent.tap'],
- ['tar', 'application/x-tar'],
- ['tcap', 'application/vnd.3gpp2.tcap'],
- ['tcl', 'application/x-tcl'],
- ['td', 'application/urc-targetdesc+xml'],
- ['teacher', 'application/vnd.smart.teacher'],
- ['tei', 'application/tei+xml'],
- ['teicorpus', 'application/tei+xml'],
- ['tex', 'application/x-tex'],
- ['texi', 'application/x-texinfo'],
- ['texinfo', 'application/x-texinfo'],
- ['text', 'text/plain'],
- ['tfi', 'application/thraud+xml'],
- ['tfm', 'application/x-tex-tfm'],
- ['tfx', 'image/tiff-fx'],
- ['tga', 'image/x-tga'],
- ['tgz', 'application/x-tar'],
- ['thmx', 'application/vnd.ms-officetheme'],
- ['tif', 'image/tiff'],
- ['tiff', 'image/tiff'],
- ['tk', 'application/x-tcl'],
- ['tmo', 'application/vnd.tmobile-livetv'],
- ['toml', 'application/toml'],
- ['torrent', 'application/x-bittorrent'],
- ['tpl', 'application/vnd.groove-tool-template'],
- ['tpt', 'application/vnd.trid.tpt'],
- ['tr', 'text/troff'],
- ['tra', 'application/vnd.trueapp'],
- ['trig', 'application/trig'],
- ['trm', 'application/x-msterminal'],
- ['ts', 'video/mp2t'],
- ['tsd', 'application/timestamped-data'],
- ['tsv', 'text/tab-separated-values'],
- ['ttc', 'font/collection'],
- ['ttf', 'font/ttf'],
- ['ttl', 'text/turtle'],
- ['ttml', 'application/ttml+xml'],
- ['twd', 'application/vnd.simtech-mindmapper'],
- ['twds', 'application/vnd.simtech-mindmapper'],
- ['txd', 'application/vnd.genomatix.tuxedo'],
- ['txf', 'application/vnd.mobius.txf'],
- ['txt', 'text/plain'],
- ['u8dsn', 'message/global-delivery-status'],
- ['u8hdr', 'message/global-headers'],
- ['u8mdn', 'message/global-disposition-notification'],
- ['u8msg', 'message/global'],
- ['u32', 'application/x-authorware-bin'],
- ['ubj', 'application/ubjson'],
- ['udeb', 'application/x-debian-package'],
- ['ufd', 'application/vnd.ufdl'],
- ['ufdl', 'application/vnd.ufdl'],
- ['ulx', 'application/x-glulx'],
- ['umj', 'application/vnd.umajin'],
- ['unityweb', 'application/vnd.unity'],
- ['uoml', 'application/vnd.uoml+xml'],
- ['uri', 'text/uri-list'],
- ['uris', 'text/uri-list'],
- ['urls', 'text/uri-list'],
- ['usdz', 'model/vnd.usdz+zip'],
- ['ustar', 'application/x-ustar'],
- ['utz', 'application/vnd.uiq.theme'],
- ['uu', 'text/x-uuencode'],
- ['uva', 'audio/vnd.dece.audio'],
- ['uvd', 'application/vnd.dece.data'],
- ['uvf', 'application/vnd.dece.data'],
- ['uvg', 'image/vnd.dece.graphic'],
- ['uvh', 'video/vnd.dece.hd'],
- ['uvi', 'image/vnd.dece.graphic'],
- ['uvm', 'video/vnd.dece.mobile'],
- ['uvp', 'video/vnd.dece.pd'],
- ['uvs', 'video/vnd.dece.sd'],
- ['uvt', 'application/vnd.dece.ttml+xml'],
- ['uvu', 'video/vnd.uvvu.mp4'],
- ['uvv', 'video/vnd.dece.video'],
- ['uvva', 'audio/vnd.dece.audio'],
- ['uvvd', 'application/vnd.dece.data'],
- ['uvvf', 'application/vnd.dece.data'],
- ['uvvg', 'image/vnd.dece.graphic'],
- ['uvvh', 'video/vnd.dece.hd'],
- ['uvvi', 'image/vnd.dece.graphic'],
- ['uvvm', 'video/vnd.dece.mobile'],
- ['uvvp', 'video/vnd.dece.pd'],
- ['uvvs', 'video/vnd.dece.sd'],
- ['uvvt', 'application/vnd.dece.ttml+xml'],
- ['uvvu', 'video/vnd.uvvu.mp4'],
- ['uvvv', 'video/vnd.dece.video'],
- ['uvvx', 'application/vnd.dece.unspecified'],
- ['uvvz', 'application/vnd.dece.zip'],
- ['uvx', 'application/vnd.dece.unspecified'],
- ['uvz', 'application/vnd.dece.zip'],
- ['vbox', 'application/x-virtualbox-vbox'],
- ['vbox-extpack', 'application/x-virtualbox-vbox-extpack'],
- ['vcard', 'text/vcard'],
- ['vcd', 'application/x-cdlink'],
- ['vcf', 'text/x-vcard'],
- ['vcg', 'application/vnd.groove-vcard'],
- ['vcs', 'text/x-vcalendar'],
- ['vcx', 'application/vnd.vcx'],
- ['vdi', 'application/x-virtualbox-vdi'],
- ['vds', 'model/vnd.sap.vds'],
- ['vhd', 'application/x-virtualbox-vhd'],
- ['vis', 'application/vnd.visionary'],
- ['viv', 'video/vnd.vivo'],
- ['vlc', 'application/videolan'],
- ['vmdk', 'application/x-virtualbox-vmdk'],
- ['vob', 'video/x-ms-vob'],
- ['vor', 'application/vnd.stardivision.writer'],
- ['vox', 'application/x-authorware-bin'],
- ['vrml', 'model/vrml'],
- ['vsd', 'application/vnd.visio'],
- ['vsf', 'application/vnd.vsf'],
- ['vss', 'application/vnd.visio'],
- ['vst', 'application/vnd.visio'],
- ['vsw', 'application/vnd.visio'],
- ['vtf', 'image/vnd.valve.source.texture'],
- ['vtt', 'text/vtt'],
- ['vtu', 'model/vnd.vtu'],
- ['vxml', 'application/voicexml+xml'],
- ['w3d', 'application/x-director'],
- ['wad', 'application/x-doom'],
- ['wadl', 'application/vnd.sun.wadl+xml'],
- ['war', 'application/java-archive'],
- ['wasm', 'application/wasm'],
- ['wav', 'audio/x-wav'],
- ['wax', 'audio/x-ms-wax'],
- ['wbmp', 'image/vnd.wap.wbmp'],
- ['wbs', 'application/vnd.criticaltools.wbs+xml'],
- ['wbxml', 'application/wbxml'],
- ['wcm', 'application/vnd.ms-works'],
- ['wdb', 'application/vnd.ms-works'],
- ['wdp', 'image/vnd.ms-photo'],
- ['weba', 'audio/webm'],
- ['webapp', 'application/x-web-app-manifest+json'],
- ['webm', 'video/webm'],
- ['webmanifest', 'application/manifest+json'],
- ['webp', 'image/webp'],
- ['wg', 'application/vnd.pmi.widget'],
- ['wgt', 'application/widget'],
- ['wks', 'application/vnd.ms-works'],
- ['wm', 'video/x-ms-wm'],
- ['wma', 'audio/x-ms-wma'],
- ['wmd', 'application/x-ms-wmd'],
- ['wmf', 'image/wmf'],
- ['wml', 'text/vnd.wap.wml'],
- ['wmlc', 'application/wmlc'],
- ['wmls', 'text/vnd.wap.wmlscript'],
- ['wmlsc', 'application/vnd.wap.wmlscriptc'],
- ['wmv', 'video/x-ms-wmv'],
- ['wmx', 'video/x-ms-wmx'],
- ['wmz', 'application/x-msmetafile'],
- ['woff', 'font/woff'],
- ['woff2', 'font/woff2'],
- ['word', 'application/msword'],
- ['wpd', 'application/vnd.wordperfect'],
- ['wpl', 'application/vnd.ms-wpl'],
- ['wps', 'application/vnd.ms-works'],
- ['wqd', 'application/vnd.wqd'],
- ['wri', 'application/x-mswrite'],
- ['wrl', 'model/vrml'],
- ['wsc', 'message/vnd.wfa.wsc'],
- ['wsdl', 'application/wsdl+xml'],
- ['wspolicy', 'application/wspolicy+xml'],
- ['wtb', 'application/vnd.webturbo'],
- ['wvx', 'video/x-ms-wvx'],
- ['x3d', 'model/x3d+xml'],
- ['x3db', 'model/x3d+fastinfoset'],
- ['x3dbz', 'model/x3d+binary'],
- ['x3dv', 'model/x3d-vrml'],
- ['x3dvz', 'model/x3d+vrml'],
- ['x3dz', 'model/x3d+xml'],
- ['x32', 'application/x-authorware-bin'],
- ['x_b', 'model/vnd.parasolid.transmit.binary'],
- ['x_t', 'model/vnd.parasolid.transmit.text'],
- ['xaml', 'application/xaml+xml'],
- ['xap', 'application/x-silverlight-app'],
- ['xar', 'application/vnd.xara'],
- ['xav', 'application/xcap-att+xml'],
- ['xbap', 'application/x-ms-xbap'],
- ['xbd', 'application/vnd.fujixerox.docuworks.binder'],
- ['xbm', 'image/x-xbitmap'],
- ['xca', 'application/xcap-caps+xml'],
- ['xcs', 'application/calendar+xml'],
- ['xdf', 'application/xcap-diff+xml'],
- ['xdm', 'application/vnd.syncml.dm+xml'],
- ['xdp', 'application/vnd.adobe.xdp+xml'],
- ['xdssc', 'application/dssc+xml'],
- ['xdw', 'application/vnd.fujixerox.docuworks'],
- ['xel', 'application/xcap-el+xml'],
- ['xenc', 'application/xenc+xml'],
- ['xer', 'application/patch-ops-error+xml'],
- ['xfdf', 'application/vnd.adobe.xfdf'],
- ['xfdl', 'application/vnd.xfdl'],
- ['xht', 'application/xhtml+xml'],
- ['xhtml', 'application/xhtml+xml'],
- ['xhvml', 'application/xv+xml'],
- ['xif', 'image/vnd.xiff'],
- ['xl', 'application/excel'],
- ['xla', 'application/vnd.ms-excel'],
- ['xlam', 'application/vnd.ms-excel.addin.macroEnabled.12'],
- ['xlc', 'application/vnd.ms-excel'],
- ['xlf', 'application/xliff+xml'],
- ['xlm', 'application/vnd.ms-excel'],
- ['xls', 'application/vnd.ms-excel'],
- ['xlsb', 'application/vnd.ms-excel.sheet.binary.macroEnabled.12'],
- ['xlsm', 'application/vnd.ms-excel.sheet.macroEnabled.12'],
- ['xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
- ['xlt', 'application/vnd.ms-excel'],
- ['xltm', 'application/vnd.ms-excel.template.macroEnabled.12'],
- ['xltx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.template'],
- ['xlw', 'application/vnd.ms-excel'],
- ['xm', 'audio/xm'],
- ['xml', 'application/xml'],
- ['xns', 'application/xcap-ns+xml'],
- ['xo', 'application/vnd.olpc-sugar'],
- ['xop', 'application/xop+xml'],
- ['xpi', 'application/x-xpinstall'],
- ['xpl', 'application/xproc+xml'],
- ['xpm', 'image/x-xpixmap'],
- ['xpr', 'application/vnd.is-xpr'],
- ['xps', 'application/vnd.ms-xpsdocument'],
- ['xpw', 'application/vnd.intercon.formnet'],
- ['xpx', 'application/vnd.intercon.formnet'],
- ['xsd', 'application/xml'],
- ['xsl', 'application/xml'],
- ['xslt', 'application/xslt+xml'],
- ['xsm', 'application/vnd.syncml+xml'],
- ['xspf', 'application/xspf+xml'],
- ['xul', 'application/vnd.mozilla.xul+xml'],
- ['xvm', 'application/xv+xml'],
- ['xvml', 'application/xv+xml'],
- ['xwd', 'image/x-xwindowdump'],
- ['xyz', 'chemical/x-xyz'],
- ['xz', 'application/x-xz'],
- ['yaml', 'text/yaml'],
- ['yang', 'application/yang'],
- ['yin', 'application/yin+xml'],
- ['yml', 'text/yaml'],
- ['ymp', 'text/x-suse-ymp'],
- ['z', 'application/x-compress'],
- ['z1', 'application/x-zmachine'],
- ['z2', 'application/x-zmachine'],
- ['z3', 'application/x-zmachine'],
- ['z4', 'application/x-zmachine'],
- ['z5', 'application/x-zmachine'],
- ['z6', 'application/x-zmachine'],
- ['z7', 'application/x-zmachine'],
- ['z8', 'application/x-zmachine'],
- ['zaz', 'application/vnd.zzazz.deck+xml'],
- ['zip', 'application/zip'],
- ['zir', 'application/vnd.zul'],
- ['zirz', 'application/vnd.zul'],
- ['zmm', 'application/vnd.handheld-entertainment+xml'],
- ['zsh', 'text/x-scriptzsh']
+ // https://github.com/guzzle/psr7/blob/2d9260799e713f1c475d3c5fdc3d6561ff7441b2/src/MimeType.php
+ ["1km", "application/vnd.1000minds.decision-model+xml"],
+ ["3dml", "text/vnd.in3d.3dml"],
+ ["3ds", "image/x-3ds"],
+ ["3g2", "video/3gpp2"],
+ ["3gp", "video/3gp"],
+ ["3gpp", "video/3gpp"],
+ ["3mf", "model/3mf"],
+ ["7z", "application/x-7z-compressed"],
+ ["7zip", "application/x-7z-compressed"],
+ ["123", "application/vnd.lotus-1-2-3"],
+ ["aab", "application/x-authorware-bin"],
+ ["aac", "audio/x-acc"],
+ ["aam", "application/x-authorware-map"],
+ ["aas", "application/x-authorware-seg"],
+ ["abw", "application/x-abiword"],
+ ["ac", "application/vnd.nokia.n-gage.ac+xml"],
+ ["ac3", "audio/ac3"],
+ ["acc", "application/vnd.americandynamics.acc"],
+ ["ace", "application/x-ace-compressed"],
+ ["acu", "application/vnd.acucobol"],
+ ["acutc", "application/vnd.acucorp"],
+ ["adp", "audio/adpcm"],
+ ["aep", "application/vnd.audiograph"],
+ ["afm", "application/x-font-type1"],
+ ["afp", "application/vnd.ibm.modcap"],
+ ["ahead", "application/vnd.ahead.space"],
+ ["ai", "application/pdf"],
+ ["aif", "audio/x-aiff"],
+ ["aifc", "audio/x-aiff"],
+ ["aiff", "audio/x-aiff"],
+ ["air", "application/vnd.adobe.air-application-installer-package+zip"],
+ ["ait", "application/vnd.dvb.ait"],
+ ["ami", "application/vnd.amiga.ami"],
+ ["amr", "audio/amr"],
+ ["apk", "application/vnd.android.package-archive"],
+ ["apng", "image/apng"],
+ ["appcache", "text/cache-manifest"],
+ ["application", "application/x-ms-application"],
+ ["apr", "application/vnd.lotus-approach"],
+ ["arc", "application/x-freearc"],
+ ["arj", "application/x-arj"],
+ ["asc", "application/pgp-signature"],
+ ["asf", "video/x-ms-asf"],
+ ["asm", "text/x-asm"],
+ ["aso", "application/vnd.accpac.simply.aso"],
+ ["asx", "video/x-ms-asf"],
+ ["atc", "application/vnd.acucorp"],
+ ["atom", "application/atom+xml"],
+ ["atomcat", "application/atomcat+xml"],
+ ["atomdeleted", "application/atomdeleted+xml"],
+ ["atomsvc", "application/atomsvc+xml"],
+ ["atx", "application/vnd.antix.game-component"],
+ ["au", "audio/x-au"],
+ ["avi", "video/x-msvideo"],
+ ["avif", "image/avif"],
+ ["aw", "application/applixware"],
+ ["azf", "application/vnd.airzip.filesecure.azf"],
+ ["azs", "application/vnd.airzip.filesecure.azs"],
+ ["azv", "image/vnd.airzip.accelerator.azv"],
+ ["azw", "application/vnd.amazon.ebook"],
+ ["b16", "image/vnd.pco.b16"],
+ ["bat", "application/x-msdownload"],
+ ["bcpio", "application/x-bcpio"],
+ ["bdf", "application/x-font-bdf"],
+ ["bdm", "application/vnd.syncml.dm+wbxml"],
+ ["bdoc", "application/x-bdoc"],
+ ["bed", "application/vnd.realvnc.bed"],
+ ["bh2", "application/vnd.fujitsu.oasysprs"],
+ ["bin", "application/octet-stream"],
+ ["blb", "application/x-blorb"],
+ ["blorb", "application/x-blorb"],
+ ["bmi", "application/vnd.bmi"],
+ ["bmml", "application/vnd.balsamiq.bmml+xml"],
+ ["bmp", "image/bmp"],
+ ["book", "application/vnd.framemaker"],
+ ["box", "application/vnd.previewsystems.box"],
+ ["boz", "application/x-bzip2"],
+ ["bpk", "application/octet-stream"],
+ ["bpmn", "application/octet-stream"],
+ ["bsp", "model/vnd.valve.source.compiled-map"],
+ ["btif", "image/prs.btif"],
+ ["buffer", "application/octet-stream"],
+ ["bz", "application/x-bzip"],
+ ["bz2", "application/x-bzip2"],
+ ["c", "text/x-c"],
+ ["c4d", "application/vnd.clonk.c4group"],
+ ["c4f", "application/vnd.clonk.c4group"],
+ ["c4g", "application/vnd.clonk.c4group"],
+ ["c4p", "application/vnd.clonk.c4group"],
+ ["c4u", "application/vnd.clonk.c4group"],
+ ["c11amc", "application/vnd.cluetrust.cartomobile-config"],
+ ["c11amz", "application/vnd.cluetrust.cartomobile-config-pkg"],
+ ["cab", "application/vnd.ms-cab-compressed"],
+ ["caf", "audio/x-caf"],
+ ["cap", "application/vnd.tcpdump.pcap"],
+ ["car", "application/vnd.curl.car"],
+ ["cat", "application/vnd.ms-pki.seccat"],
+ ["cb7", "application/x-cbr"],
+ ["cba", "application/x-cbr"],
+ ["cbr", "application/x-cbr"],
+ ["cbt", "application/x-cbr"],
+ ["cbz", "application/x-cbr"],
+ ["cc", "text/x-c"],
+ ["cco", "application/x-cocoa"],
+ ["cct", "application/x-director"],
+ ["ccxml", "application/ccxml+xml"],
+ ["cdbcmsg", "application/vnd.contact.cmsg"],
+ ["cda", "application/x-cdf"],
+ ["cdf", "application/x-netcdf"],
+ ["cdfx", "application/cdfx+xml"],
+ ["cdkey", "application/vnd.mediastation.cdkey"],
+ ["cdmia", "application/cdmi-capability"],
+ ["cdmic", "application/cdmi-container"],
+ ["cdmid", "application/cdmi-domain"],
+ ["cdmio", "application/cdmi-object"],
+ ["cdmiq", "application/cdmi-queue"],
+ ["cdr", "application/cdr"],
+ ["cdx", "chemical/x-cdx"],
+ ["cdxml", "application/vnd.chemdraw+xml"],
+ ["cdy", "application/vnd.cinderella"],
+ ["cer", "application/pkix-cert"],
+ ["cfs", "application/x-cfs-compressed"],
+ ["cgm", "image/cgm"],
+ ["chat", "application/x-chat"],
+ ["chm", "application/vnd.ms-htmlhelp"],
+ ["chrt", "application/vnd.kde.kchart"],
+ ["cif", "chemical/x-cif"],
+ ["cii", "application/vnd.anser-web-certificate-issue-initiation"],
+ ["cil", "application/vnd.ms-artgalry"],
+ ["cjs", "application/node"],
+ ["cla", "application/vnd.claymore"],
+ ["class", "application/octet-stream"],
+ ["clkk", "application/vnd.crick.clicker.keyboard"],
+ ["clkp", "application/vnd.crick.clicker.palette"],
+ ["clkt", "application/vnd.crick.clicker.template"],
+ ["clkw", "application/vnd.crick.clicker.wordbank"],
+ ["clkx", "application/vnd.crick.clicker"],
+ ["clp", "application/x-msclip"],
+ ["cmc", "application/vnd.cosmocaller"],
+ ["cmdf", "chemical/x-cmdf"],
+ ["cml", "chemical/x-cml"],
+ ["cmp", "application/vnd.yellowriver-custom-menu"],
+ ["cmx", "image/x-cmx"],
+ ["cod", "application/vnd.rim.cod"],
+ ["coffee", "text/coffeescript"],
+ ["com", "application/x-msdownload"],
+ ["conf", "text/plain"],
+ ["cpio", "application/x-cpio"],
+ ["cpp", "text/x-c"],
+ ["cpt", "application/mac-compactpro"],
+ ["crd", "application/x-mscardfile"],
+ ["crl", "application/pkix-crl"],
+ ["crt", "application/x-x509-ca-cert"],
+ ["crx", "application/x-chrome-extension"],
+ ["cryptonote", "application/vnd.rig.cryptonote"],
+ ["csh", "application/x-csh"],
+ ["csl", "application/vnd.citationstyles.style+xml"],
+ ["csml", "chemical/x-csml"],
+ ["csp", "application/vnd.commonspace"],
+ ["csr", "application/octet-stream"],
+ ["css", "text/css"],
+ ["cst", "application/x-director"],
+ ["csv", "text/csv"],
+ ["cu", "application/cu-seeme"],
+ ["curl", "text/vnd.curl"],
+ ["cww", "application/prs.cww"],
+ ["cxt", "application/x-director"],
+ ["cxx", "text/x-c"],
+ ["dae", "model/vnd.collada+xml"],
+ ["daf", "application/vnd.mobius.daf"],
+ ["dart", "application/vnd.dart"],
+ ["dataless", "application/vnd.fdsn.seed"],
+ ["davmount", "application/davmount+xml"],
+ ["dbf", "application/vnd.dbf"],
+ ["dbk", "application/docbook+xml"],
+ ["dcr", "application/x-director"],
+ ["dcurl", "text/vnd.curl.dcurl"],
+ ["dd2", "application/vnd.oma.dd2+xml"],
+ ["ddd", "application/vnd.fujixerox.ddd"],
+ ["ddf", "application/vnd.syncml.dmddf+xml"],
+ ["dds", "image/vnd.ms-dds"],
+ ["deb", "application/x-debian-package"],
+ ["def", "text/plain"],
+ ["deploy", "application/octet-stream"],
+ ["der", "application/x-x509-ca-cert"],
+ ["dfac", "application/vnd.dreamfactory"],
+ ["dgc", "application/x-dgc-compressed"],
+ ["dic", "text/x-c"],
+ ["dir", "application/x-director"],
+ ["dis", "application/vnd.mobius.dis"],
+ ["disposition-notification", "message/disposition-notification"],
+ ["dist", "application/octet-stream"],
+ ["distz", "application/octet-stream"],
+ ["djv", "image/vnd.djvu"],
+ ["djvu", "image/vnd.djvu"],
+ ["dll", "application/octet-stream"],
+ ["dmg", "application/x-apple-diskimage"],
+ ["dmn", "application/octet-stream"],
+ ["dmp", "application/vnd.tcpdump.pcap"],
+ ["dms", "application/octet-stream"],
+ ["dna", "application/vnd.dna"],
+ ["doc", "application/msword"],
+ ["docm", "application/vnd.ms-word.template.macroEnabled.12"],
+ [
+ "docx",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ ],
+ ["dot", "application/msword"],
+ ["dotm", "application/vnd.ms-word.template.macroEnabled.12"],
+ [
+ "dotx",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
+ ],
+ ["dp", "application/vnd.osgi.dp"],
+ ["dpg", "application/vnd.dpgraph"],
+ ["dra", "audio/vnd.dra"],
+ ["drle", "image/dicom-rle"],
+ ["dsc", "text/prs.lines.tag"],
+ ["dssc", "application/dssc+der"],
+ ["dtb", "application/x-dtbook+xml"],
+ ["dtd", "application/xml-dtd"],
+ ["dts", "audio/vnd.dts"],
+ ["dtshd", "audio/vnd.dts.hd"],
+ ["dump", "application/octet-stream"],
+ ["dvb", "video/vnd.dvb.file"],
+ ["dvi", "application/x-dvi"],
+ ["dwd", "application/atsc-dwd+xml"],
+ ["dwf", "model/vnd.dwf"],
+ ["dwg", "image/vnd.dwg"],
+ ["dxf", "image/vnd.dxf"],
+ ["dxp", "application/vnd.spotfire.dxp"],
+ ["dxr", "application/x-director"],
+ ["ear", "application/java-archive"],
+ ["ecelp4800", "audio/vnd.nuera.ecelp4800"],
+ ["ecelp7470", "audio/vnd.nuera.ecelp7470"],
+ ["ecelp9600", "audio/vnd.nuera.ecelp9600"],
+ ["ecma", "application/ecmascript"],
+ ["edm", "application/vnd.novadigm.edm"],
+ ["edx", "application/vnd.novadigm.edx"],
+ ["efif", "application/vnd.picsel"],
+ ["ei6", "application/vnd.pg.osasli"],
+ ["elc", "application/octet-stream"],
+ ["emf", "image/emf"],
+ ["eml", "message/rfc822"],
+ ["emma", "application/emma+xml"],
+ ["emotionml", "application/emotionml+xml"],
+ ["emz", "application/x-msmetafile"],
+ ["eol", "audio/vnd.digital-winds"],
+ ["eot", "application/vnd.ms-fontobject"],
+ ["eps", "application/postscript"],
+ ["epub", "application/epub+zip"],
+ ["es", "application/ecmascript"],
+ ["es3", "application/vnd.eszigno3+xml"],
+ ["esa", "application/vnd.osgi.subsystem"],
+ ["esf", "application/vnd.epson.esf"],
+ ["et3", "application/vnd.eszigno3+xml"],
+ ["etx", "text/x-setext"],
+ ["eva", "application/x-eva"],
+ ["evy", "application/x-envoy"],
+ ["exe", "application/octet-stream"],
+ ["exi", "application/exi"],
+ ["exp", "application/express"],
+ ["exr", "image/aces"],
+ ["ext", "application/vnd.novadigm.ext"],
+ ["ez", "application/andrew-inset"],
+ ["ez2", "application/vnd.ezpix-album"],
+ ["ez3", "application/vnd.ezpix-package"],
+ ["f", "text/x-fortran"],
+ ["f4v", "video/mp4"],
+ ["f77", "text/x-fortran"],
+ ["f90", "text/x-fortran"],
+ ["fbs", "image/vnd.fastbidsheet"],
+ ["fcdt", "application/vnd.adobe.formscentral.fcdt"],
+ ["fcs", "application/vnd.isac.fcs"],
+ ["fdf", "application/vnd.fdf"],
+ ["fdt", "application/fdt+xml"],
+ ["fe_launch", "application/vnd.denovo.fcselayout-link"],
+ ["fg5", "application/vnd.fujitsu.oasysgp"],
+ ["fgd", "application/x-director"],
+ ["fh", "image/x-freehand"],
+ ["fh4", "image/x-freehand"],
+ ["fh5", "image/x-freehand"],
+ ["fh7", "image/x-freehand"],
+ ["fhc", "image/x-freehand"],
+ ["fig", "application/x-xfig"],
+ ["fits", "image/fits"],
+ ["flac", "audio/x-flac"],
+ ["fli", "video/x-fli"],
+ ["flo", "application/vnd.micrografx.flo"],
+ ["flv", "video/x-flv"],
+ ["flw", "application/vnd.kde.kivio"],
+ ["flx", "text/vnd.fmi.flexstor"],
+ ["fly", "text/vnd.fly"],
+ ["fm", "application/vnd.framemaker"],
+ ["fnc", "application/vnd.frogans.fnc"],
+ ["fo", "application/vnd.software602.filler.form+xml"],
+ ["for", "text/x-fortran"],
+ ["fpx", "image/vnd.fpx"],
+ ["frame", "application/vnd.framemaker"],
+ ["fsc", "application/vnd.fsc.weblaunch"],
+ ["fst", "image/vnd.fst"],
+ ["ftc", "application/vnd.fluxtime.clip"],
+ ["fti", "application/vnd.anser-web-funds-transfer-initiation"],
+ ["fvt", "video/vnd.fvt"],
+ ["fxp", "application/vnd.adobe.fxp"],
+ ["fxpl", "application/vnd.adobe.fxp"],
+ ["fzs", "application/vnd.fuzzysheet"],
+ ["g2w", "application/vnd.geoplan"],
+ ["g3", "image/g3fax"],
+ ["g3w", "application/vnd.geospace"],
+ ["gac", "application/vnd.groove-account"],
+ ["gam", "application/x-tads"],
+ ["gbr", "application/rpki-ghostbusters"],
+ ["gca", "application/x-gca-compressed"],
+ ["gdl", "model/vnd.gdl"],
+ ["gdoc", "application/vnd.google-apps.document"],
+ ["geo", "application/vnd.dynageo"],
+ ["geojson", "application/geo+json"],
+ ["gex", "application/vnd.geometry-explorer"],
+ ["ggb", "application/vnd.geogebra.file"],
+ ["ggt", "application/vnd.geogebra.tool"],
+ ["ghf", "application/vnd.groove-help"],
+ ["gif", "image/gif"],
+ ["gim", "application/vnd.groove-identity-message"],
+ ["glb", "model/gltf-binary"],
+ ["gltf", "model/gltf+json"],
+ ["gml", "application/gml+xml"],
+ ["gmx", "application/vnd.gmx"],
+ ["gnumeric", "application/x-gnumeric"],
+ ["gpg", "application/gpg-keys"],
+ ["gph", "application/vnd.flographit"],
+ ["gpx", "application/gpx+xml"],
+ ["gqf", "application/vnd.grafeq"],
+ ["gqs", "application/vnd.grafeq"],
+ ["gram", "application/srgs"],
+ ["gramps", "application/x-gramps-xml"],
+ ["gre", "application/vnd.geometry-explorer"],
+ ["grv", "application/vnd.groove-injector"],
+ ["grxml", "application/srgs+xml"],
+ ["gsf", "application/x-font-ghostscript"],
+ ["gsheet", "application/vnd.google-apps.spreadsheet"],
+ ["gslides", "application/vnd.google-apps.presentation"],
+ ["gtar", "application/x-gtar"],
+ ["gtm", "application/vnd.groove-tool-message"],
+ ["gtw", "model/vnd.gtw"],
+ ["gv", "text/vnd.graphviz"],
+ ["gxf", "application/gxf"],
+ ["gxt", "application/vnd.geonext"],
+ ["gz", "application/gzip"],
+ ["gzip", "application/gzip"],
+ ["h", "text/x-c"],
+ ["h261", "video/h261"],
+ ["h263", "video/h263"],
+ ["h264", "video/h264"],
+ ["hal", "application/vnd.hal+xml"],
+ ["hbci", "application/vnd.hbci"],
+ ["hbs", "text/x-handlebars-template"],
+ ["hdd", "application/x-virtualbox-hdd"],
+ ["hdf", "application/x-hdf"],
+ ["heic", "image/heic"],
+ ["heics", "image/heic-sequence"],
+ ["heif", "image/heif"],
+ ["heifs", "image/heif-sequence"],
+ ["hej2", "image/hej2k"],
+ ["held", "application/atsc-held+xml"],
+ ["hh", "text/x-c"],
+ ["hjson", "application/hjson"],
+ ["hlp", "application/winhlp"],
+ ["hpgl", "application/vnd.hp-hpgl"],
+ ["hpid", "application/vnd.hp-hpid"],
+ ["hps", "application/vnd.hp-hps"],
+ ["hqx", "application/mac-binhex40"],
+ ["hsj2", "image/hsj2"],
+ ["htc", "text/x-component"],
+ ["htke", "application/vnd.kenameaapp"],
+ ["htm", "text/html"],
+ ["html", "text/html"],
+ ["hvd", "application/vnd.yamaha.hv-dic"],
+ ["hvp", "application/vnd.yamaha.hv-voice"],
+ ["hvs", "application/vnd.yamaha.hv-script"],
+ ["i2g", "application/vnd.intergeo"],
+ ["icc", "application/vnd.iccprofile"],
+ ["ice", "x-conference/x-cooltalk"],
+ ["icm", "application/vnd.iccprofile"],
+ ["ico", "image/x-icon"],
+ ["ics", "text/calendar"],
+ ["ief", "image/ief"],
+ ["ifb", "text/calendar"],
+ ["ifm", "application/vnd.shana.informed.formdata"],
+ ["iges", "model/iges"],
+ ["igl", "application/vnd.igloader"],
+ ["igm", "application/vnd.insors.igm"],
+ ["igs", "model/iges"],
+ ["igx", "application/vnd.micrografx.igx"],
+ ["iif", "application/vnd.shana.informed.interchange"],
+ ["img", "application/octet-stream"],
+ ["imp", "application/vnd.accpac.simply.imp"],
+ ["ims", "application/vnd.ms-ims"],
+ ["in", "text/plain"],
+ ["ini", "text/plain"],
+ ["ink", "application/inkml+xml"],
+ ["inkml", "application/inkml+xml"],
+ ["install", "application/x-install-instructions"],
+ ["iota", "application/vnd.astraea-software.iota"],
+ ["ipfix", "application/ipfix"],
+ ["ipk", "application/vnd.shana.informed.package"],
+ ["irm", "application/vnd.ibm.rights-management"],
+ ["irp", "application/vnd.irepository.package+xml"],
+ ["iso", "application/x-iso9660-image"],
+ ["itp", "application/vnd.shana.informed.formtemplate"],
+ ["its", "application/its+xml"],
+ ["ivp", "application/vnd.immervision-ivp"],
+ ["ivu", "application/vnd.immervision-ivu"],
+ ["jad", "text/vnd.sun.j2me.app-descriptor"],
+ ["jade", "text/jade"],
+ ["jam", "application/vnd.jam"],
+ ["jar", "application/java-archive"],
+ ["jardiff", "application/x-java-archive-diff"],
+ ["java", "text/x-java-source"],
+ ["jhc", "image/jphc"],
+ ["jisp", "application/vnd.jisp"],
+ ["jls", "image/jls"],
+ ["jlt", "application/vnd.hp-jlyt"],
+ ["jng", "image/x-jng"],
+ ["jnlp", "application/x-java-jnlp-file"],
+ ["joda", "application/vnd.joost.joda-archive"],
+ ["jp2", "image/jp2"],
+ ["jpe", "image/jpeg"],
+ ["jpeg", "image/jpeg"],
+ ["jpf", "image/jpx"],
+ ["jpg", "image/jpeg"],
+ ["jpg2", "image/jp2"],
+ ["jpgm", "video/jpm"],
+ ["jpgv", "video/jpeg"],
+ ["jph", "image/jph"],
+ ["jpm", "video/jpm"],
+ ["jpx", "image/jpx"],
+ ["js", "application/javascript"],
+ ["json", "application/json"],
+ ["json5", "application/json5"],
+ ["jsonld", "application/ld+json"],
+ // https://jsonlines.org/
+ ["jsonl", "application/jsonl"],
+ ["jsonml", "application/jsonml+json"],
+ ["jsx", "text/jsx"],
+ ["jxr", "image/jxr"],
+ ["jxra", "image/jxra"],
+ ["jxrs", "image/jxrs"],
+ ["jxs", "image/jxs"],
+ ["jxsc", "image/jxsc"],
+ ["jxsi", "image/jxsi"],
+ ["jxss", "image/jxss"],
+ ["kar", "audio/midi"],
+ ["karbon", "application/vnd.kde.karbon"],
+ ["kdb", "application/octet-stream"],
+ ["kdbx", "application/x-keepass2"],
+ ["key", "application/x-iwork-keynote-sffkey"],
+ ["kfo", "application/vnd.kde.kformula"],
+ ["kia", "application/vnd.kidspiration"],
+ ["kml", "application/vnd.google-earth.kml+xml"],
+ ["kmz", "application/vnd.google-earth.kmz"],
+ ["kne", "application/vnd.kinar"],
+ ["knp", "application/vnd.kinar"],
+ ["kon", "application/vnd.kde.kontour"],
+ ["kpr", "application/vnd.kde.kpresenter"],
+ ["kpt", "application/vnd.kde.kpresenter"],
+ ["kpxx", "application/vnd.ds-keypoint"],
+ ["ksp", "application/vnd.kde.kspread"],
+ ["ktr", "application/vnd.kahootz"],
+ ["ktx", "image/ktx"],
+ ["ktx2", "image/ktx2"],
+ ["ktz", "application/vnd.kahootz"],
+ ["kwd", "application/vnd.kde.kword"],
+ ["kwt", "application/vnd.kde.kword"],
+ ["lasxml", "application/vnd.las.las+xml"],
+ ["latex", "application/x-latex"],
+ ["lbd", "application/vnd.llamagraphics.life-balance.desktop"],
+ ["lbe", "application/vnd.llamagraphics.life-balance.exchange+xml"],
+ ["les", "application/vnd.hhe.lesson-player"],
+ ["less", "text/less"],
+ ["lgr", "application/lgr+xml"],
+ ["lha", "application/octet-stream"],
+ ["link66", "application/vnd.route66.link66+xml"],
+ ["list", "text/plain"],
+ ["list3820", "application/vnd.ibm.modcap"],
+ ["listafp", "application/vnd.ibm.modcap"],
+ ["litcoffee", "text/coffeescript"],
+ ["lnk", "application/x-ms-shortcut"],
+ ["log", "text/plain"],
+ ["lostxml", "application/lost+xml"],
+ ["lrf", "application/octet-stream"],
+ ["lrm", "application/vnd.ms-lrm"],
+ ["ltf", "application/vnd.frogans.ltf"],
+ ["lua", "text/x-lua"],
+ ["luac", "application/x-lua-bytecode"],
+ ["lvp", "audio/vnd.lucent.voice"],
+ ["lwp", "application/vnd.lotus-wordpro"],
+ ["lzh", "application/octet-stream"],
+ ["m1v", "video/mpeg"],
+ ["m2a", "audio/mpeg"],
+ ["m2v", "video/mpeg"],
+ ["m3a", "audio/mpeg"],
+ ["m3u", "text/plain"],
+ ["m3u8", "application/vnd.apple.mpegurl"],
+ ["m4a", "audio/x-m4a"],
+ ["m4p", "application/mp4"],
+ ["m4s", "video/iso.segment"],
+ ["m4u", "application/vnd.mpegurl"],
+ ["m4v", "video/x-m4v"],
+ ["m13", "application/x-msmediaview"],
+ ["m14", "application/x-msmediaview"],
+ ["m21", "application/mp21"],
+ ["ma", "application/mathematica"],
+ ["mads", "application/mads+xml"],
+ ["maei", "application/mmt-aei+xml"],
+ ["mag", "application/vnd.ecowin.chart"],
+ ["maker", "application/vnd.framemaker"],
+ ["man", "text/troff"],
+ ["manifest", "text/cache-manifest"],
+ ["map", "application/json"],
+ ["mar", "application/octet-stream"],
+ ["markdown", "text/markdown"],
+ ["mathml", "application/mathml+xml"],
+ ["mb", "application/mathematica"],
+ ["mbk", "application/vnd.mobius.mbk"],
+ ["mbox", "application/mbox"],
+ ["mc1", "application/vnd.medcalcdata"],
+ ["mcd", "application/vnd.mcd"],
+ ["mcurl", "text/vnd.curl.mcurl"],
+ ["md", "text/markdown"],
+ ["mdb", "application/x-msaccess"],
+ ["mdi", "image/vnd.ms-modi"],
+ ["mdx", "text/mdx"],
+ ["me", "text/troff"],
+ ["mesh", "model/mesh"],
+ ["meta4", "application/metalink4+xml"],
+ ["metalink", "application/metalink+xml"],
+ ["mets", "application/mets+xml"],
+ ["mfm", "application/vnd.mfmp"],
+ ["mft", "application/rpki-manifest"],
+ ["mgp", "application/vnd.osgeo.mapguide.package"],
+ ["mgz", "application/vnd.proteus.magazine"],
+ ["mid", "audio/midi"],
+ ["midi", "audio/midi"],
+ ["mie", "application/x-mie"],
+ ["mif", "application/vnd.mif"],
+ ["mime", "message/rfc822"],
+ ["mj2", "video/mj2"],
+ ["mjp2", "video/mj2"],
+ ["mjs", "application/javascript"],
+ ["mk3d", "video/x-matroska"],
+ ["mka", "audio/x-matroska"],
+ ["mkd", "text/x-markdown"],
+ ["mks", "video/x-matroska"],
+ ["mkv", "video/x-matroska"],
+ ["mlp", "application/vnd.dolby.mlp"],
+ ["mmd", "application/vnd.chipnuts.karaoke-mmd"],
+ ["mmf", "application/vnd.smaf"],
+ ["mml", "text/mathml"],
+ ["mmr", "image/vnd.fujixerox.edmics-mmr"],
+ ["mng", "video/x-mng"],
+ ["mny", "application/x-msmoney"],
+ ["mobi", "application/x-mobipocket-ebook"],
+ ["mods", "application/mods+xml"],
+ ["mov", "video/quicktime"],
+ ["movie", "video/x-sgi-movie"],
+ ["mp2", "audio/mpeg"],
+ ["mp2a", "audio/mpeg"],
+ ["mp3", "audio/mpeg"],
+ ["mp4", "video/mp4"],
+ ["mp4a", "audio/mp4"],
+ ["mp4s", "application/mp4"],
+ ["mp4v", "video/mp4"],
+ ["mp21", "application/mp21"],
+ ["mpc", "application/vnd.mophun.certificate"],
+ ["mpd", "application/dash+xml"],
+ ["mpe", "video/mpeg"],
+ ["mpeg", "video/mpeg"],
+ ["mpg", "video/mpeg"],
+ ["mpg4", "video/mp4"],
+ ["mpga", "audio/mpeg"],
+ ["mpkg", "application/vnd.apple.installer+xml"],
+ ["mpm", "application/vnd.blueice.multipass"],
+ ["mpn", "application/vnd.mophun.application"],
+ ["mpp", "application/vnd.ms-project"],
+ ["mpt", "application/vnd.ms-project"],
+ ["mpy", "application/vnd.ibm.minipay"],
+ ["mqy", "application/vnd.mobius.mqy"],
+ ["mrc", "application/marc"],
+ ["mrcx", "application/marcxml+xml"],
+ ["ms", "text/troff"],
+ ["mscml", "application/mediaservercontrol+xml"],
+ ["mseed", "application/vnd.fdsn.mseed"],
+ ["mseq", "application/vnd.mseq"],
+ ["msf", "application/vnd.epson.msf"],
+ ["msg", "application/vnd.ms-outlook"],
+ ["msh", "model/mesh"],
+ ["msi", "application/x-msdownload"],
+ ["msl", "application/vnd.mobius.msl"],
+ ["msm", "application/octet-stream"],
+ ["msp", "application/octet-stream"],
+ ["msty", "application/vnd.muvee.style"],
+ ["mtl", "model/mtl"],
+ ["mts", "model/vnd.mts"],
+ ["mus", "application/vnd.musician"],
+ ["musd", "application/mmt-usd+xml"],
+ ["musicxml", "application/vnd.recordare.musicxml+xml"],
+ ["mvb", "application/x-msmediaview"],
+ ["mvt", "application/vnd.mapbox-vector-tile"],
+ ["mwf", "application/vnd.mfer"],
+ ["mxf", "application/mxf"],
+ ["mxl", "application/vnd.recordare.musicxml"],
+ ["mxmf", "audio/mobile-xmf"],
+ ["mxml", "application/xv+xml"],
+ ["mxs", "application/vnd.triscape.mxs"],
+ ["mxu", "video/vnd.mpegurl"],
+ ["n-gage", "application/vnd.nokia.n-gage.symbian.install"],
+ ["n3", "text/n3"],
+ ["nb", "application/mathematica"],
+ ["nbp", "application/vnd.wolfram.player"],
+ ["nc", "application/x-netcdf"],
+ ["ncx", "application/x-dtbncx+xml"],
+ ["nfo", "text/x-nfo"],
+ ["ngdat", "application/vnd.nokia.n-gage.data"],
+ ["nitf", "application/vnd.nitf"],
+ ["nlu", "application/vnd.neurolanguage.nlu"],
+ ["nml", "application/vnd.enliven"],
+ ["nnd", "application/vnd.noblenet-directory"],
+ ["nns", "application/vnd.noblenet-sealer"],
+ ["nnw", "application/vnd.noblenet-web"],
+ ["npx", "image/vnd.net-fpx"],
+ ["nq", "application/n-quads"],
+ ["nsc", "application/x-conference"],
+ ["nsf", "application/vnd.lotus-notes"],
+ ["nt", "application/n-triples"],
+ ["ntf", "application/vnd.nitf"],
+ ["numbers", "application/x-iwork-numbers-sffnumbers"],
+ ["nzb", "application/x-nzb"],
+ ["oa2", "application/vnd.fujitsu.oasys2"],
+ ["oa3", "application/vnd.fujitsu.oasys3"],
+ ["oas", "application/vnd.fujitsu.oasys"],
+ ["obd", "application/x-msbinder"],
+ ["obgx", "application/vnd.openblox.game+xml"],
+ ["obj", "model/obj"],
+ ["oda", "application/oda"],
+ ["odb", "application/vnd.oasis.opendocument.database"],
+ ["odc", "application/vnd.oasis.opendocument.chart"],
+ ["odf", "application/vnd.oasis.opendocument.formula"],
+ ["odft", "application/vnd.oasis.opendocument.formula-template"],
+ ["odg", "application/vnd.oasis.opendocument.graphics"],
+ ["odi", "application/vnd.oasis.opendocument.image"],
+ ["odm", "application/vnd.oasis.opendocument.text-master"],
+ ["odp", "application/vnd.oasis.opendocument.presentation"],
+ ["ods", "application/vnd.oasis.opendocument.spreadsheet"],
+ ["odt", "application/vnd.oasis.opendocument.text"],
+ ["oga", "audio/ogg"],
+ ["ogex", "model/vnd.opengex"],
+ ["ogg", "audio/ogg"],
+ ["ogv", "video/ogg"],
+ ["ogx", "application/ogg"],
+ ["omdoc", "application/omdoc+xml"],
+ ["onepkg", "application/onenote"],
+ ["onetmp", "application/onenote"],
+ ["onetoc", "application/onenote"],
+ ["onetoc2", "application/onenote"],
+ ["opf", "application/oebps-package+xml"],
+ ["opml", "text/x-opml"],
+ ["oprc", "application/vnd.palm"],
+ ["opus", "audio/ogg"],
+ ["org", "text/x-org"],
+ ["osf", "application/vnd.yamaha.openscoreformat"],
+ ["osfpvg", "application/vnd.yamaha.openscoreformat.osfpvg+xml"],
+ ["osm", "application/vnd.openstreetmap.data+xml"],
+ ["otc", "application/vnd.oasis.opendocument.chart-template"],
+ ["otf", "font/otf"],
+ ["otg", "application/vnd.oasis.opendocument.graphics-template"],
+ ["oth", "application/vnd.oasis.opendocument.text-web"],
+ ["oti", "application/vnd.oasis.opendocument.image-template"],
+ ["otp", "application/vnd.oasis.opendocument.presentation-template"],
+ ["ots", "application/vnd.oasis.opendocument.spreadsheet-template"],
+ ["ott", "application/vnd.oasis.opendocument.text-template"],
+ ["ova", "application/x-virtualbox-ova"],
+ ["ovf", "application/x-virtualbox-ovf"],
+ ["owl", "application/rdf+xml"],
+ ["oxps", "application/oxps"],
+ ["oxt", "application/vnd.openofficeorg.extension"],
+ ["p", "text/x-pascal"],
+ ["p7a", "application/x-pkcs7-signature"],
+ ["p7b", "application/x-pkcs7-certificates"],
+ ["p7c", "application/pkcs7-mime"],
+ ["p7m", "application/pkcs7-mime"],
+ ["p7r", "application/x-pkcs7-certreqresp"],
+ ["p7s", "application/pkcs7-signature"],
+ ["p8", "application/pkcs8"],
+ ["p10", "application/x-pkcs10"],
+ ["p12", "application/x-pkcs12"],
+ ["pac", "application/x-ns-proxy-autoconfig"],
+ ["pages", "application/x-iwork-pages-sffpages"],
+ ["pas", "text/x-pascal"],
+ ["paw", "application/vnd.pawaafile"],
+ ["pbd", "application/vnd.powerbuilder6"],
+ ["pbm", "image/x-portable-bitmap"],
+ ["pcap", "application/vnd.tcpdump.pcap"],
+ ["pcf", "application/x-font-pcf"],
+ ["pcl", "application/vnd.hp-pcl"],
+ ["pclxl", "application/vnd.hp-pclxl"],
+ ["pct", "image/x-pict"],
+ ["pcurl", "application/vnd.curl.pcurl"],
+ ["pcx", "image/x-pcx"],
+ ["pdb", "application/x-pilot"],
+ ["pde", "text/x-processing"],
+ ["pdf", "application/pdf"],
+ ["pem", "application/x-x509-user-cert"],
+ ["pfa", "application/x-font-type1"],
+ ["pfb", "application/x-font-type1"],
+ ["pfm", "application/x-font-type1"],
+ ["pfr", "application/font-tdpfr"],
+ ["pfx", "application/x-pkcs12"],
+ ["pgm", "image/x-portable-graymap"],
+ ["pgn", "application/x-chess-pgn"],
+ ["pgp", "application/pgp"],
+ ["php", "application/x-httpd-php"],
+ ["php3", "application/x-httpd-php"],
+ ["php4", "application/x-httpd-php"],
+ ["phps", "application/x-httpd-php-source"],
+ ["phtml", "application/x-httpd-php"],
+ ["pic", "image/x-pict"],
+ ["pkg", "application/octet-stream"],
+ ["pki", "application/pkixcmp"],
+ ["pkipath", "application/pkix-pkipath"],
+ ["pkpass", "application/vnd.apple.pkpass"],
+ ["pl", "application/x-perl"],
+ ["plb", "application/vnd.3gpp.pic-bw-large"],
+ ["plc", "application/vnd.mobius.plc"],
+ ["plf", "application/vnd.pocketlearn"],
+ ["pls", "application/pls+xml"],
+ ["pm", "application/x-perl"],
+ ["pml", "application/vnd.ctc-posml"],
+ ["png", "image/png"],
+ ["pnm", "image/x-portable-anymap"],
+ ["portpkg", "application/vnd.macports.portpkg"],
+ ["pot", "application/vnd.ms-powerpoint"],
+ ["potm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"],
+ [
+ "potx",
+ "application/vnd.openxmlformats-officedocument.presentationml.template",
+ ],
+ ["ppa", "application/vnd.ms-powerpoint"],
+ ["ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12"],
+ ["ppd", "application/vnd.cups-ppd"],
+ ["ppm", "image/x-portable-pixmap"],
+ ["pps", "application/vnd.ms-powerpoint"],
+ ["ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"],
+ [
+ "ppsx",
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
+ ],
+ ["ppt", "application/powerpoint"],
+ ["pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"],
+ [
+ "pptx",
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
+ ],
+ ["pqa", "application/vnd.palm"],
+ ["prc", "application/x-pilot"],
+ ["pre", "application/vnd.lotus-freelance"],
+ ["prf", "application/pics-rules"],
+ ["provx", "application/provenance+xml"],
+ ["ps", "application/postscript"],
+ ["psb", "application/vnd.3gpp.pic-bw-small"],
+ ["psd", "application/x-photoshop"],
+ ["psf", "application/x-font-linux-psf"],
+ ["pskcxml", "application/pskc+xml"],
+ ["pti", "image/prs.pti"],
+ ["ptid", "application/vnd.pvi.ptid1"],
+ ["pub", "application/x-mspublisher"],
+ ["pvb", "application/vnd.3gpp.pic-bw-var"],
+ ["pwn", "application/vnd.3m.post-it-notes"],
+ ["pya", "audio/vnd.ms-playready.media.pya"],
+ ["pyv", "video/vnd.ms-playready.media.pyv"],
+ ["qam", "application/vnd.epson.quickanime"],
+ ["qbo", "application/vnd.intu.qbo"],
+ ["qfx", "application/vnd.intu.qfx"],
+ ["qps", "application/vnd.publishare-delta-tree"],
+ ["qt", "video/quicktime"],
+ ["qwd", "application/vnd.quark.quarkxpress"],
+ ["qwt", "application/vnd.quark.quarkxpress"],
+ ["qxb", "application/vnd.quark.quarkxpress"],
+ ["qxd", "application/vnd.quark.quarkxpress"],
+ ["qxl", "application/vnd.quark.quarkxpress"],
+ ["qxt", "application/vnd.quark.quarkxpress"],
+ ["ra", "audio/x-realaudio"],
+ ["ram", "audio/x-pn-realaudio"],
+ ["raml", "application/raml+yaml"],
+ ["rapd", "application/route-apd+xml"],
+ ["rar", "application/x-rar"],
+ ["ras", "image/x-cmu-raster"],
+ ["rcprofile", "application/vnd.ipunplugged.rcprofile"],
+ ["rdf", "application/rdf+xml"],
+ ["rdz", "application/vnd.data-vision.rdz"],
+ ["relo", "application/p2p-overlay+xml"],
+ ["rep", "application/vnd.businessobjects"],
+ ["res", "application/x-dtbresource+xml"],
+ ["rgb", "image/x-rgb"],
+ ["rif", "application/reginfo+xml"],
+ ["rip", "audio/vnd.rip"],
+ ["ris", "application/x-research-info-systems"],
+ ["rl", "application/resource-lists+xml"],
+ ["rlc", "image/vnd.fujixerox.edmics-rlc"],
+ ["rld", "application/resource-lists-diff+xml"],
+ ["rm", "audio/x-pn-realaudio"],
+ ["rmi", "audio/midi"],
+ ["rmp", "audio/x-pn-realaudio-plugin"],
+ ["rms", "application/vnd.jcp.javame.midlet-rms"],
+ ["rmvb", "application/vnd.rn-realmedia-vbr"],
+ ["rnc", "application/relax-ng-compact-syntax"],
+ ["rng", "application/xml"],
+ ["roa", "application/rpki-roa"],
+ ["roff", "text/troff"],
+ ["rp9", "application/vnd.cloanto.rp9"],
+ ["rpm", "audio/x-pn-realaudio-plugin"],
+ ["rpss", "application/vnd.nokia.radio-presets"],
+ ["rpst", "application/vnd.nokia.radio-preset"],
+ ["rq", "application/sparql-query"],
+ ["rs", "application/rls-services+xml"],
+ ["rsa", "application/x-pkcs7"],
+ ["rsat", "application/atsc-rsat+xml"],
+ ["rsd", "application/rsd+xml"],
+ ["rsheet", "application/urc-ressheet+xml"],
+ ["rss", "application/rss+xml"],
+ ["rtf", "text/rtf"],
+ ["rtx", "text/richtext"],
+ ["run", "application/x-makeself"],
+ ["rusd", "application/route-usd+xml"],
+ ["rv", "video/vnd.rn-realvideo"],
+ ["s", "text/x-asm"],
+ ["s3m", "audio/s3m"],
+ ["saf", "application/vnd.yamaha.smaf-audio"],
+ ["sass", "text/x-sass"],
+ ["sbml", "application/sbml+xml"],
+ ["sc", "application/vnd.ibm.secure-container"],
+ ["scd", "application/x-msschedule"],
+ ["scm", "application/vnd.lotus-screencam"],
+ ["scq", "application/scvp-cv-request"],
+ ["scs", "application/scvp-cv-response"],
+ ["scss", "text/x-scss"],
+ ["scurl", "text/vnd.curl.scurl"],
+ ["sda", "application/vnd.stardivision.draw"],
+ ["sdc", "application/vnd.stardivision.calc"],
+ ["sdd", "application/vnd.stardivision.impress"],
+ ["sdkd", "application/vnd.solent.sdkm+xml"],
+ ["sdkm", "application/vnd.solent.sdkm+xml"],
+ ["sdp", "application/sdp"],
+ ["sdw", "application/vnd.stardivision.writer"],
+ ["sea", "application/octet-stream"],
+ ["see", "application/vnd.seemail"],
+ ["seed", "application/vnd.fdsn.seed"],
+ ["sema", "application/vnd.sema"],
+ ["semd", "application/vnd.semd"],
+ ["semf", "application/vnd.semf"],
+ ["senmlx", "application/senml+xml"],
+ ["sensmlx", "application/sensml+xml"],
+ ["ser", "application/java-serialized-object"],
+ ["setpay", "application/set-payment-initiation"],
+ ["setreg", "application/set-registration-initiation"],
+ ["sfd-hdstx", "application/vnd.hydrostatix.sof-data"],
+ ["sfs", "application/vnd.spotfire.sfs"],
+ ["sfv", "text/x-sfv"],
+ ["sgi", "image/sgi"],
+ ["sgl", "application/vnd.stardivision.writer-global"],
+ ["sgm", "text/sgml"],
+ ["sgml", "text/sgml"],
+ ["sh", "application/x-sh"],
+ ["shar", "application/x-shar"],
+ ["shex", "text/shex"],
+ ["shf", "application/shf+xml"],
+ ["shtml", "text/html"],
+ ["sid", "image/x-mrsid-image"],
+ ["sieve", "application/sieve"],
+ ["sig", "application/pgp-signature"],
+ ["sil", "audio/silk"],
+ ["silo", "model/mesh"],
+ ["sis", "application/vnd.symbian.install"],
+ ["sisx", "application/vnd.symbian.install"],
+ ["sit", "application/x-stuffit"],
+ ["sitx", "application/x-stuffitx"],
+ ["siv", "application/sieve"],
+ ["skd", "application/vnd.koan"],
+ ["skm", "application/vnd.koan"],
+ ["skp", "application/vnd.koan"],
+ ["skt", "application/vnd.koan"],
+ ["sldm", "application/vnd.ms-powerpoint.slide.macroenabled.12"],
+ [
+ "sldx",
+ "application/vnd.openxmlformats-officedocument.presentationml.slide",
+ ],
+ ["slim", "text/slim"],
+ ["slm", "text/slim"],
+ ["sls", "application/route-s-tsid+xml"],
+ ["slt", "application/vnd.epson.salt"],
+ ["sm", "application/vnd.stepmania.stepchart"],
+ ["smf", "application/vnd.stardivision.math"],
+ ["smi", "application/smil"],
+ ["smil", "application/smil"],
+ ["smv", "video/x-smv"],
+ ["smzip", "application/vnd.stepmania.package"],
+ ["snd", "audio/basic"],
+ ["snf", "application/x-font-snf"],
+ ["so", "application/octet-stream"],
+ ["spc", "application/x-pkcs7-certificates"],
+ ["spdx", "text/spdx"],
+ ["spf", "application/vnd.yamaha.smaf-phrase"],
+ ["spl", "application/x-futuresplash"],
+ ["spot", "text/vnd.in3d.spot"],
+ ["spp", "application/scvp-vp-response"],
+ ["spq", "application/scvp-vp-request"],
+ ["spx", "audio/ogg"],
+ ["sql", "application/x-sql"],
+ ["src", "application/x-wais-source"],
+ ["srt", "application/x-subrip"],
+ ["sru", "application/sru+xml"],
+ ["srx", "application/sparql-results+xml"],
+ ["ssdl", "application/ssdl+xml"],
+ ["sse", "application/vnd.kodak-descriptor"],
+ ["ssf", "application/vnd.epson.ssf"],
+ ["ssml", "application/ssml+xml"],
+ ["sst", "application/octet-stream"],
+ ["st", "application/vnd.sailingtracker.track"],
+ ["stc", "application/vnd.sun.xml.calc.template"],
+ ["std", "application/vnd.sun.xml.draw.template"],
+ ["stf", "application/vnd.wt.stf"],
+ ["sti", "application/vnd.sun.xml.impress.template"],
+ ["stk", "application/hyperstudio"],
+ ["stl", "model/stl"],
+ ["stpx", "model/step+xml"],
+ ["stpxz", "model/step-xml+zip"],
+ ["stpz", "model/step+zip"],
+ ["str", "application/vnd.pg.format"],
+ ["stw", "application/vnd.sun.xml.writer.template"],
+ ["styl", "text/stylus"],
+ ["stylus", "text/stylus"],
+ ["sub", "text/vnd.dvb.subtitle"],
+ ["sus", "application/vnd.sus-calendar"],
+ ["susp", "application/vnd.sus-calendar"],
+ ["sv4cpio", "application/x-sv4cpio"],
+ ["sv4crc", "application/x-sv4crc"],
+ ["svc", "application/vnd.dvb.service"],
+ ["svd", "application/vnd.svd"],
+ ["svg", "image/svg+xml"],
+ ["svgz", "image/svg+xml"],
+ ["swa", "application/x-director"],
+ ["swf", "application/x-shockwave-flash"],
+ ["swi", "application/vnd.aristanetworks.swi"],
+ ["swidtag", "application/swid+xml"],
+ ["sxc", "application/vnd.sun.xml.calc"],
+ ["sxd", "application/vnd.sun.xml.draw"],
+ ["sxg", "application/vnd.sun.xml.writer.global"],
+ ["sxi", "application/vnd.sun.xml.impress"],
+ ["sxm", "application/vnd.sun.xml.math"],
+ ["sxw", "application/vnd.sun.xml.writer"],
+ ["t", "text/troff"],
+ ["t3", "application/x-t3vm-image"],
+ ["t38", "image/t38"],
+ ["taglet", "application/vnd.mynfc"],
+ ["tao", "application/vnd.tao.intent-module-archive"],
+ ["tap", "image/vnd.tencent.tap"],
+ ["tar", "application/x-tar"],
+ ["tcap", "application/vnd.3gpp2.tcap"],
+ ["tcl", "application/x-tcl"],
+ ["td", "application/urc-targetdesc+xml"],
+ ["teacher", "application/vnd.smart.teacher"],
+ ["tei", "application/tei+xml"],
+ ["teicorpus", "application/tei+xml"],
+ ["tex", "application/x-tex"],
+ ["texi", "application/x-texinfo"],
+ ["texinfo", "application/x-texinfo"],
+ ["text", "text/plain"],
+ ["tfi", "application/thraud+xml"],
+ ["tfm", "application/x-tex-tfm"],
+ ["tfx", "image/tiff-fx"],
+ ["tga", "image/x-tga"],
+ ["tgz", "application/x-tar"],
+ ["thmx", "application/vnd.ms-officetheme"],
+ ["tif", "image/tiff"],
+ ["tiff", "image/tiff"],
+ ["tk", "application/x-tcl"],
+ ["tmo", "application/vnd.tmobile-livetv"],
+ ["toml", "application/toml"],
+ ["torrent", "application/x-bittorrent"],
+ ["tpl", "application/vnd.groove-tool-template"],
+ ["tpt", "application/vnd.trid.tpt"],
+ ["tr", "text/troff"],
+ ["tra", "application/vnd.trueapp"],
+ ["trig", "application/trig"],
+ ["trm", "application/x-msterminal"],
+ ["ts", "video/mp2t"],
+ ["tsd", "application/timestamped-data"],
+ ["tsv", "text/tab-separated-values"],
+ ["ttc", "font/collection"],
+ ["ttf", "font/ttf"],
+ ["ttl", "text/turtle"],
+ ["ttml", "application/ttml+xml"],
+ ["twd", "application/vnd.simtech-mindmapper"],
+ ["twds", "application/vnd.simtech-mindmapper"],
+ ["txd", "application/vnd.genomatix.tuxedo"],
+ ["txf", "application/vnd.mobius.txf"],
+ ["txt", "text/plain"],
+ ["u8dsn", "message/global-delivery-status"],
+ ["u8hdr", "message/global-headers"],
+ ["u8mdn", "message/global-disposition-notification"],
+ ["u8msg", "message/global"],
+ ["u32", "application/x-authorware-bin"],
+ ["ubj", "application/ubjson"],
+ ["udeb", "application/x-debian-package"],
+ ["ufd", "application/vnd.ufdl"],
+ ["ufdl", "application/vnd.ufdl"],
+ ["ulx", "application/x-glulx"],
+ ["umj", "application/vnd.umajin"],
+ ["unityweb", "application/vnd.unity"],
+ ["uoml", "application/vnd.uoml+xml"],
+ ["uri", "text/uri-list"],
+ ["uris", "text/uri-list"],
+ ["urls", "text/uri-list"],
+ ["usdz", "model/vnd.usdz+zip"],
+ ["ustar", "application/x-ustar"],
+ ["utz", "application/vnd.uiq.theme"],
+ ["uu", "text/x-uuencode"],
+ ["uva", "audio/vnd.dece.audio"],
+ ["uvd", "application/vnd.dece.data"],
+ ["uvf", "application/vnd.dece.data"],
+ ["uvg", "image/vnd.dece.graphic"],
+ ["uvh", "video/vnd.dece.hd"],
+ ["uvi", "image/vnd.dece.graphic"],
+ ["uvm", "video/vnd.dece.mobile"],
+ ["uvp", "video/vnd.dece.pd"],
+ ["uvs", "video/vnd.dece.sd"],
+ ["uvt", "application/vnd.dece.ttml+xml"],
+ ["uvu", "video/vnd.uvvu.mp4"],
+ ["uvv", "video/vnd.dece.video"],
+ ["uvva", "audio/vnd.dece.audio"],
+ ["uvvd", "application/vnd.dece.data"],
+ ["uvvf", "application/vnd.dece.data"],
+ ["uvvg", "image/vnd.dece.graphic"],
+ ["uvvh", "video/vnd.dece.hd"],
+ ["uvvi", "image/vnd.dece.graphic"],
+ ["uvvm", "video/vnd.dece.mobile"],
+ ["uvvp", "video/vnd.dece.pd"],
+ ["uvvs", "video/vnd.dece.sd"],
+ ["uvvt", "application/vnd.dece.ttml+xml"],
+ ["uvvu", "video/vnd.uvvu.mp4"],
+ ["uvvv", "video/vnd.dece.video"],
+ ["uvvx", "application/vnd.dece.unspecified"],
+ ["uvvz", "application/vnd.dece.zip"],
+ ["uvx", "application/vnd.dece.unspecified"],
+ ["uvz", "application/vnd.dece.zip"],
+ ["vbox", "application/x-virtualbox-vbox"],
+ ["vbox-extpack", "application/x-virtualbox-vbox-extpack"],
+ ["vcard", "text/vcard"],
+ ["vcd", "application/x-cdlink"],
+ ["vcf", "text/x-vcard"],
+ ["vcg", "application/vnd.groove-vcard"],
+ ["vcs", "text/x-vcalendar"],
+ ["vcx", "application/vnd.vcx"],
+ ["vdi", "application/x-virtualbox-vdi"],
+ ["vds", "model/vnd.sap.vds"],
+ ["vhd", "application/x-virtualbox-vhd"],
+ ["vis", "application/vnd.visionary"],
+ ["viv", "video/vnd.vivo"],
+ ["vlc", "application/videolan"],
+ ["vmdk", "application/x-virtualbox-vmdk"],
+ ["vob", "video/x-ms-vob"],
+ ["vor", "application/vnd.stardivision.writer"],
+ ["vox", "application/x-authorware-bin"],
+ ["vrml", "model/vrml"],
+ ["vsd", "application/vnd.visio"],
+ ["vsf", "application/vnd.vsf"],
+ ["vss", "application/vnd.visio"],
+ ["vst", "application/vnd.visio"],
+ ["vsw", "application/vnd.visio"],
+ ["vtf", "image/vnd.valve.source.texture"],
+ ["vtt", "text/vtt"],
+ ["vtu", "model/vnd.vtu"],
+ ["vxml", "application/voicexml+xml"],
+ ["w3d", "application/x-director"],
+ ["wad", "application/x-doom"],
+ ["wadl", "application/vnd.sun.wadl+xml"],
+ ["war", "application/java-archive"],
+ ["wasm", "application/wasm"],
+ ["wav", "audio/x-wav"],
+ ["wax", "audio/x-ms-wax"],
+ ["wbmp", "image/vnd.wap.wbmp"],
+ ["wbs", "application/vnd.criticaltools.wbs+xml"],
+ ["wbxml", "application/wbxml"],
+ ["wcm", "application/vnd.ms-works"],
+ ["wdb", "application/vnd.ms-works"],
+ ["wdp", "image/vnd.ms-photo"],
+ ["weba", "audio/webm"],
+ ["webapp", "application/x-web-app-manifest+json"],
+ ["webm", "video/webm"],
+ ["webmanifest", "application/manifest+json"],
+ ["webp", "image/webp"],
+ ["wg", "application/vnd.pmi.widget"],
+ ["wgt", "application/widget"],
+ ["wks", "application/vnd.ms-works"],
+ ["wm", "video/x-ms-wm"],
+ ["wma", "audio/x-ms-wma"],
+ ["wmd", "application/x-ms-wmd"],
+ ["wmf", "image/wmf"],
+ ["wml", "text/vnd.wap.wml"],
+ ["wmlc", "application/wmlc"],
+ ["wmls", "text/vnd.wap.wmlscript"],
+ ["wmlsc", "application/vnd.wap.wmlscriptc"],
+ ["wmv", "video/x-ms-wmv"],
+ ["wmx", "video/x-ms-wmx"],
+ ["wmz", "application/x-msmetafile"],
+ ["woff", "font/woff"],
+ ["woff2", "font/woff2"],
+ ["word", "application/msword"],
+ ["wpd", "application/vnd.wordperfect"],
+ ["wpl", "application/vnd.ms-wpl"],
+ ["wps", "application/vnd.ms-works"],
+ ["wqd", "application/vnd.wqd"],
+ ["wri", "application/x-mswrite"],
+ ["wrl", "model/vrml"],
+ ["wsc", "message/vnd.wfa.wsc"],
+ ["wsdl", "application/wsdl+xml"],
+ ["wspolicy", "application/wspolicy+xml"],
+ ["wtb", "application/vnd.webturbo"],
+ ["wvx", "video/x-ms-wvx"],
+ ["x3d", "model/x3d+xml"],
+ ["x3db", "model/x3d+fastinfoset"],
+ ["x3dbz", "model/x3d+binary"],
+ ["x3dv", "model/x3d-vrml"],
+ ["x3dvz", "model/x3d+vrml"],
+ ["x3dz", "model/x3d+xml"],
+ ["x32", "application/x-authorware-bin"],
+ ["x_b", "model/vnd.parasolid.transmit.binary"],
+ ["x_t", "model/vnd.parasolid.transmit.text"],
+ ["xaml", "application/xaml+xml"],
+ ["xap", "application/x-silverlight-app"],
+ ["xar", "application/vnd.xara"],
+ ["xav", "application/xcap-att+xml"],
+ ["xbap", "application/x-ms-xbap"],
+ ["xbd", "application/vnd.fujixerox.docuworks.binder"],
+ ["xbm", "image/x-xbitmap"],
+ ["xca", "application/xcap-caps+xml"],
+ ["xcs", "application/calendar+xml"],
+ ["xdf", "application/xcap-diff+xml"],
+ ["xdm", "application/vnd.syncml.dm+xml"],
+ ["xdp", "application/vnd.adobe.xdp+xml"],
+ ["xdssc", "application/dssc+xml"],
+ ["xdw", "application/vnd.fujixerox.docuworks"],
+ ["xel", "application/xcap-el+xml"],
+ ["xenc", "application/xenc+xml"],
+ ["xer", "application/patch-ops-error+xml"],
+ ["xfdf", "application/vnd.adobe.xfdf"],
+ ["xfdl", "application/vnd.xfdl"],
+ ["xht", "application/xhtml+xml"],
+ ["xhtml", "application/xhtml+xml"],
+ ["xhvml", "application/xv+xml"],
+ ["xif", "image/vnd.xiff"],
+ ["xl", "application/excel"],
+ ["xla", "application/vnd.ms-excel"],
+ ["xlam", "application/vnd.ms-excel.addin.macroEnabled.12"],
+ ["xlc", "application/vnd.ms-excel"],
+ ["xlf", "application/xliff+xml"],
+ ["xlm", "application/vnd.ms-excel"],
+ ["xls", "application/vnd.ms-excel"],
+ ["xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12"],
+ ["xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12"],
+ ["xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
+ ["xlt", "application/vnd.ms-excel"],
+ ["xltm", "application/vnd.ms-excel.template.macroEnabled.12"],
+ [
+ "xltx",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
+ ],
+ ["xlw", "application/vnd.ms-excel"],
+ ["xm", "audio/xm"],
+ ["xml", "application/xml"],
+ ["xns", "application/xcap-ns+xml"],
+ ["xo", "application/vnd.olpc-sugar"],
+ ["xop", "application/xop+xml"],
+ ["xpi", "application/x-xpinstall"],
+ ["xpl", "application/xproc+xml"],
+ ["xpm", "image/x-xpixmap"],
+ ["xpr", "application/vnd.is-xpr"],
+ ["xps", "application/vnd.ms-xpsdocument"],
+ ["xpw", "application/vnd.intercon.formnet"],
+ ["xpx", "application/vnd.intercon.formnet"],
+ ["xsd", "application/xml"],
+ ["xsl", "application/xml"],
+ ["xslt", "application/xslt+xml"],
+ ["xsm", "application/vnd.syncml+xml"],
+ ["xspf", "application/xspf+xml"],
+ ["xul", "application/vnd.mozilla.xul+xml"],
+ ["xvm", "application/xv+xml"],
+ ["xvml", "application/xv+xml"],
+ ["xwd", "image/x-xwindowdump"],
+ ["xyz", "chemical/x-xyz"],
+ ["xz", "application/x-xz"],
+ ["yaml", "text/yaml"],
+ ["yang", "application/yang"],
+ ["yin", "application/yin+xml"],
+ ["yml", "text/yaml"],
+ ["ymp", "text/x-suse-ymp"],
+ ["z", "application/x-compress"],
+ ["z1", "application/x-zmachine"],
+ ["z2", "application/x-zmachine"],
+ ["z3", "application/x-zmachine"],
+ ["z4", "application/x-zmachine"],
+ ["z5", "application/x-zmachine"],
+ ["z6", "application/x-zmachine"],
+ ["z7", "application/x-zmachine"],
+ ["z8", "application/x-zmachine"],
+ ["zaz", "application/vnd.zzazz.deck+xml"],
+ ["zip", "application/zip"],
+ ["zir", "application/vnd.zul"],
+ ["zirz", "application/vnd.zul"],
+ ["zmm", "application/vnd.handheld-entertainment+xml"],
+ ["zsh", "text/x-scriptzsh"],
]);
-
-export function toFileWithPath(file: FileWithPath, path?: string, h?: FileSystemHandle): FileWithPath {
- const f = withMimeType(file);
- const {webkitRelativePath} = file;
- const p = typeof path === 'string'
- ? path
- // If is set,
+export function toFileWithPath(
+ file: FileWithPath,
+ path?: string,
+ h?: FileSystemHandle,
+): FileWithPath {
+ const f = withMimeType(file);
+ const { webkitRelativePath } = file;
+ const p =
+ typeof path === "string"
+ ? path
+ : // If is set,
// the File will have a {webkitRelativePath} property
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory
- : typeof webkitRelativePath === 'string' && webkitRelativePath.length > 0
- ? webkitRelativePath
- : `./${file.name}`;
- if (typeof f.path !== 'string') { // on electron, path is already set to the absolute path
- setObjProp(f, 'path', p);
- }
- if (h !== undefined) {
- Object.defineProperty(f, 'handle', {
- value: h,
- writable: false,
- configurable: false,
- enumerable: true
- });
- }
- // Always populate a relative path so that even electron apps have access to a relativePath value
- setObjProp(f, 'relativePath', p);
- return f;
+ typeof webkitRelativePath === "string" && webkitRelativePath.length > 0
+ ? webkitRelativePath
+ : `./${file.name}`;
+ if (typeof f.path !== "string") {
+ // on electron, path is already set to the absolute path
+ setObjProp(f, "path", p);
+ }
+ if (h !== undefined) {
+ Object.defineProperty(f, "handle", {
+ value: h,
+ writable: false,
+ configurable: false,
+ enumerable: true,
+ });
+ }
+ // Always populate a relative path so that even electron apps have access to a relativePath value
+ setObjProp(f, "relativePath", p);
+ return f;
}
export interface FileWithPath extends File {
- readonly path?: string;
- readonly handle?: FileSystemFileHandle;
- readonly relativePath?: string;
+ readonly path?: string;
+ readonly handle?: FileSystemFileHandle;
+ readonly relativePath?: string;
}
function withMimeType(file: FileWithPath) {
- const {name} = file;
- const hasExtension = name && name.lastIndexOf('.') !== -1;
+ const { name } = file;
+ const hasExtension = name && name.lastIndexOf(".") !== -1;
- if (hasExtension && !file.type) {
- const ext = name.split('.')
- .pop()!.toLowerCase();
- const type = COMMON_MIME_TYPES.get(ext);
- if (type) {
- Object.defineProperty(file, 'type', {
- value: type,
- writable: false,
- configurable: false,
- enumerable: true
- });
- }
+ if (hasExtension && !file.type) {
+ const ext = name.split(".").pop()!.toLowerCase();
+ const type = COMMON_MIME_TYPES.get(ext);
+ if (type) {
+ Object.defineProperty(file, "type", {
+ value: type,
+ writable: false,
+ configurable: false,
+ enumerable: true,
+ });
}
+ }
- return file;
+ return file;
}
function setObjProp(f: FileWithPath, key: string, value: string) {
- Object.defineProperty(f, key, {
- value,
- writable: false,
- configurable: false,
- enumerable: true
- })
+ Object.defineProperty(f, key, {
+ value,
+ writable: false,
+ configurable: false,
+ enumerable: true,
+ });
}
diff --git a/src/index.ts b/src/index.ts
index f4966b4..065773a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,2 +1,2 @@
-export {fromEvent} from './file-selector.js';
-export {FileWithPath} from './file.js';
+export { fromEvent } from "./file-selector.js";
+export { FileWithPath } from "./file.js";
diff --git a/tsconfig.build.json b/tsconfig.build.json
index e746ff3..3744585 100644
--- a/tsconfig.build.json
+++ b/tsconfig.build.json
@@ -1,10 +1,8 @@
{
- "extends": "./tsconfig.json",
- "files": [
- "./src/index.ts"
- ],
- "compilerOptions": {
- "outDir": "./dist",
- "declaration": true
- }
+ "extends": "./tsconfig.json",
+ "files": ["./src/index.ts"],
+ "compilerOptions": {
+ "outDir": "./dist",
+ "declaration": true
+ }
}
diff --git a/tsconfig.json b/tsconfig.json
index 3df33be..9ca4674 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,9 +1,9 @@
{
- "compilerOptions": {
- "target": "ESNext",
- "module": "NodeNext",
- "strict": true,
- "noImplicitReturns": true,
- "noUnusedLocals": true
- }
+ "compilerOptions": {
+ "target": "ESNext",
+ "module": "NodeNext",
+ "strict": true,
+ "noImplicitReturns": true,
+ "noUnusedLocals": true
+ }
}