Skip to content

Commit 8f981c3

Browse files
Borewitsindresorhus
andcommitted
Rewrite the API (#286)
Co-authored-by: Sindre Sorhus <[email protected]>
1 parent 3840e6a commit 8f981c3

19 files changed

+2019
-1513
lines changed

browser.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as core from './core';
2+
3+
/**
4+
* Determine file type from ReadableStream
5+
* @param stream - ReadableStream: https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream
6+
* @return Promise with file-type
7+
*/
8+
export declare function fromStream(stream: ReadableStream): Promise<core.FileType>;
9+
10+
/**
11+
* Determine file type from Blob
12+
* @param blob - Blob to parse: https://developer.mozilla.org/en-US/docs/Web/API/Blob
13+
* @returns Promise with file-type
14+
*/
15+
export declare function fromeBlob(blob: Blob): Promise<core.FileType>;

browser.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'use strict';
2+
const {ReadableWebToNodeStream} = require('readable-web-to-node-stream');
3+
const toBuffer = require('typedarray-to-buffer');
4+
const core = require('./core');
5+
6+
async function fromStream(stream) {
7+
const readableWebToNodeStream = new ReadableWebToNodeStream(stream);
8+
const fileType = await core.fromStream(readableWebToNodeStream);
9+
await readableWebToNodeStream.close();
10+
return fileType;
11+
}
12+
13+
async function fromBlob(blob) {
14+
const buf = await convertBlobToBuffer(blob);
15+
return core.fromBuffer(buf);
16+
}
17+
18+
/**
19+
* Convert Web API File to Node Buffer
20+
* @param {Blob} blob Web API Blob
21+
* @return {Promise<Buffer>}
22+
*/
23+
function convertBlobToBuffer(blob) {
24+
return new Promise((resolve, reject) => {
25+
const fileReader = new FileReader();
26+
fileReader.addEventListener('loadend', event => {
27+
let data = event.target.result;
28+
if (data instanceof ArrayBuffer) {
29+
data = toBuffer(new Uint8Array(event.target.result));
30+
}
31+
32+
resolve(data);
33+
});
34+
35+
fileReader.addEventListener('error', event => {
36+
reject(new Error(event.message));
37+
});
38+
39+
fileReader.addEventListener('abort', event => {
40+
reject(new Error(event.type));
41+
});
42+
43+
fileReader.readAsArrayBuffer(blob);
44+
});
45+
}
46+
47+
Object.assign(module.exports, core, {
48+
fromStream,
49+
fromBlob
50+
});

core.d.ts

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
/// <reference types="node"/>
2+
import { Readable } from 'stream';
3+
import { ITokenizer } from 'strtok3/lib/core';
4+
5+
declare namespace core {
6+
type FileType =
7+
| 'jpg'
8+
| 'png'
9+
| 'apng'
10+
| 'gif'
11+
| 'webp'
12+
| 'flif'
13+
| 'cr2'
14+
| 'orf'
15+
| 'arw'
16+
| 'dng'
17+
| 'nef'
18+
| 'rw2'
19+
| 'raf'
20+
| 'tif'
21+
| 'bmp'
22+
| 'jxr'
23+
| 'psd'
24+
| 'zip'
25+
| 'tar'
26+
| 'rar'
27+
| 'gz'
28+
| 'bz2'
29+
| '7z'
30+
| 'dmg'
31+
| 'mp4'
32+
| 'mid'
33+
| 'mkv'
34+
| 'webm'
35+
| 'mov'
36+
| 'avi'
37+
| 'wmv'
38+
| 'mpg'
39+
| 'mp2'
40+
| 'mp3'
41+
| 'm4a'
42+
| 'ogg'
43+
| 'opus'
44+
| 'flac'
45+
| 'wav'
46+
| 'qcp'
47+
| 'amr'
48+
| 'pdf'
49+
| 'epub'
50+
| 'mobi'
51+
| 'exe'
52+
| 'swf'
53+
| 'rtf'
54+
| 'woff'
55+
| 'woff2'
56+
| 'eot'
57+
| 'ttf'
58+
| 'otf'
59+
| 'ico'
60+
| 'flv'
61+
| 'ps'
62+
| 'xz'
63+
| 'sqlite'
64+
| 'nes'
65+
| 'crx'
66+
| 'xpi'
67+
| 'cab'
68+
| 'deb'
69+
| 'ar'
70+
| 'rpm'
71+
| 'Z'
72+
| 'lz'
73+
| 'msi'
74+
| 'mxf'
75+
| 'mts'
76+
| 'wasm'
77+
| 'blend'
78+
| 'bpg'
79+
| 'docx'
80+
| 'pptx'
81+
| 'xlsx'
82+
| '3gp'
83+
| '3g2'
84+
| 'jp2'
85+
| 'jpm'
86+
| 'jpx'
87+
| 'mj2'
88+
| 'aif'
89+
| 'odt'
90+
| 'ods'
91+
| 'odp'
92+
| 'xml'
93+
| 'heic'
94+
| 'cur'
95+
| 'ktx'
96+
| 'ape'
97+
| 'wv'
98+
| 'asf'
99+
| 'wma'
100+
| 'dcm'
101+
| 'mpc'
102+
| 'ics'
103+
| 'glb'
104+
| 'pcap'
105+
| 'dsf'
106+
| 'lnk'
107+
| 'alias'
108+
| 'voc'
109+
| 'ac3'
110+
| 'm4b'
111+
| 'm4p'
112+
| 'm4v'
113+
| 'f4a'
114+
| 'f4b'
115+
| 'f4p'
116+
| 'f4v'
117+
| 'mie'
118+
| 'ogv'
119+
| 'ogm'
120+
| 'oga'
121+
| 'spx'
122+
| 'ogx'
123+
| 'arrow'
124+
| 'shp'
125+
| 'aac'
126+
| 'mp1';
127+
128+
type MimeType =
129+
| 'image/jpeg'
130+
| 'image/png'
131+
| 'image/gif'
132+
| 'image/webp'
133+
| 'image/flif'
134+
| 'image/x-canon-cr2'
135+
| 'image/tiff'
136+
| 'image/bmp'
137+
| 'image/vnd.ms-photo'
138+
| 'image/vnd.adobe.photoshop'
139+
| 'application/epub+zip'
140+
| 'application/x-xpinstall'
141+
| 'application/vnd.oasis.opendocument.text'
142+
| 'application/vnd.oasis.opendocument.spreadsheet'
143+
| 'application/vnd.oasis.opendocument.presentation'
144+
| 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
145+
| 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
146+
| 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
147+
| 'application/zip'
148+
| 'application/x-tar'
149+
| 'application/x-rar-compressed'
150+
| 'application/gzip'
151+
| 'application/x-bzip2'
152+
| 'application/x-7z-compressed'
153+
| 'application/x-apple-diskimage'
154+
| 'video/mp4'
155+
| 'audio/midi'
156+
| 'video/x-matroska'
157+
| 'video/webm'
158+
| 'video/quicktime'
159+
| 'video/vnd.avi'
160+
| 'audio/vnd.wave'
161+
| 'audio/qcelp'
162+
| 'audio/x-ms-wma'
163+
| 'video/x-ms-asf'
164+
| 'application/vnd.ms-asf'
165+
| 'video/mpeg'
166+
| 'video/3gpp'
167+
| 'audio/mpeg'
168+
| 'audio/mp4' // RFC 4337
169+
| 'audio/opus'
170+
| 'video/ogg'
171+
| 'audio/ogg'
172+
| 'application/ogg'
173+
| 'audio/x-flac'
174+
| 'audio/ape'
175+
| 'audio/wavpack'
176+
| 'audio/amr'
177+
| 'application/pdf'
178+
| 'application/x-msdownload'
179+
| 'application/x-shockwave-flash'
180+
| 'application/rtf'
181+
| 'application/wasm'
182+
| 'font/woff'
183+
| 'font/woff2'
184+
| 'application/vnd.ms-fontobject'
185+
| 'font/ttf'
186+
| 'font/otf'
187+
| 'image/x-icon'
188+
| 'video/x-flv'
189+
| 'application/postscript'
190+
| 'application/x-xz'
191+
| 'application/x-sqlite3'
192+
| 'application/x-nintendo-nes-rom'
193+
| 'application/x-google-chrome-extension'
194+
| 'application/vnd.ms-cab-compressed'
195+
| 'application/x-deb'
196+
| 'application/x-unix-archive'
197+
| 'application/x-rpm'
198+
| 'application/x-compress'
199+
| 'application/x-lzip'
200+
| 'application/x-msi'
201+
| 'application/x-mie'
202+
| 'application/x-apache-arrow'
203+
| 'application/mxf'
204+
| 'video/mp2t'
205+
| 'application/x-blender'
206+
| 'image/bpg'
207+
| 'image/jp2'
208+
| 'image/jpx'
209+
| 'image/jpm'
210+
| 'image/mj2'
211+
| 'audio/aiff'
212+
| 'application/xml'
213+
| 'application/x-mobipocket-ebook'
214+
| 'image/heif'
215+
| 'image/heif-sequence'
216+
| 'image/heic'
217+
| 'image/heic-sequence'
218+
| 'image/ktx'
219+
| 'application/dicom'
220+
| 'audio/x-musepack'
221+
| 'text/calendar'
222+
| 'model/gltf-binary'
223+
| 'application/vnd.tcpdump.pcap'
224+
| 'audio/x-dsf' // Non-standard
225+
| 'application/x.ms.shortcut' // Invented by us
226+
| 'application/x.apple.alias' // Invented by us
227+
| 'audio/x-voc'
228+
| 'audio/vnd.dolby.dd-raw'
229+
| 'audio/x-m4a'
230+
| 'image/apng'
231+
| 'image/x-olympus-orf'
232+
| 'image/x-sony-arw'
233+
| 'image/x-adobe-dng'
234+
| 'image/x-nikon-nef'
235+
| 'image/x-panasonic-rw2'
236+
| 'image/x-fujifilm-raf'
237+
| 'video/x-m4v'
238+
| 'video/3gpp2'
239+
| 'application/x-esri-shape'
240+
| 'audio/aac'
241+
242+
interface FileTypeResult {
243+
/**
244+
One of the supported [file types](https://github.com/sindresorhus/file-type#supported-file-types).
245+
*/
246+
ext: FileType;
247+
248+
/**
249+
The detected [MIME type](https://en.wikipedia.org/wiki/Internet_media_type).
250+
*/
251+
mime: MimeType;
252+
}
253+
254+
type ReadableStreamWithFileType = Readable & {
255+
readonly fileType?: FileTypeResult;
256+
};
257+
258+
/**
259+
Detect the file type of a `Buffer`/`Uint8Array`/`ArrayBuffer`. The file type is detected by checking the [magic number](https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files) of the buffer.
260+
261+
If file access is available, it is recommended to use `fromFile()` instead
262+
263+
@param buffer - It works best if the buffer contains the entire file, it may work with a smaller portion as well
264+
@returns The detected file type and MIME type, or `undefined` when there was no match.
265+
*/
266+
function fromBuffer(buffer: Buffer | Uint8Array | ArrayBuffer): Promise<core.FileTypeResult | undefined>;
267+
268+
/**
269+
Detect the file type of a Node.js Readable.
270+
The file type is detected by checking the [magic number](https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files) of the buffer.
271+
272+
@param stream - Node.js readable stream
273+
@returns The detected file type and MIME type, or `undefined` when there was no match.
274+
*/
275+
function fromStream(stream: Readable): Promise<core.FileTypeResult | undefined>;
276+
277+
/**
278+
Detect the file type from an ITokenizer source.
279+
This method is used internally, but can also be used for a special 'tokenizer' reader.
280+
For more information see: https://github.com/Borewit/strtok3#tokenizer
281+
@param tokenizer - File source implementing the tokenizer interface.
282+
@returns The detected file type and MIME type, or `undefined` when there was no match.
283+
*/
284+
function fromTokenizer(tokenizer: ITokenizer): Promise<core.FileTypeResult>;
285+
286+
/**
287+
Deprecated: The minimum amount of bytes needed to detect a file type. Currently, it's 4100 bytes, but it can change, so don't hard-code it.
288+
*/
289+
const minimumBytes: number;
290+
291+
/**
292+
Supported file extensions.
293+
*/
294+
const extensions: readonly core.FileType[];
295+
296+
/**
297+
Supported MIME types.
298+
*/
299+
const mimeTypes: readonly core.MimeType[];
300+
301+
/**
302+
Detect the file type of a readable stream.
303+
@param readableStream - A readable stream containing a file to examine, see: [`stream.Readable`](https://nodejs.org/api/stream.html#stream_class_stream_readable).
304+
@returns A `Promise` which resolves to the original readable stream argument, but with an added `fileType` property, which is an object like the one returned from `fileType()`.
305+
@example
306+
```
307+
import * as fs from 'fs';
308+
import * as crypto from 'crypto';
309+
import fileType = require('file-type');
310+
(async () => {
311+
const read = fs.createReadStream('encrypted.enc');
312+
const decipher = crypto.createDecipheriv(alg, key, iv);
313+
const stream = await fileType.stream(read.pipe(decipher));
314+
console.log(stream.fileType);
315+
//=> {ext: 'mov', mime: 'video/quicktime'}
316+
const write = fs.createWriteStream(`decrypted.${stream.fileType.ext}`);
317+
stream.pipe(write);
318+
})();
319+
```
320+
*/
321+
function stream(readableStream: Readable): Promise<core.ReadableStreamWithFileType>
322+
}
323+
324+
export = core;
325+

0 commit comments

Comments
 (0)