file-type 18.5.0 → 18.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core.d.ts CHANGED
@@ -50,6 +50,7 @@ export type FileExtension =
50
50
  | 'epub'
51
51
  | 'mobi'
52
52
  | 'elf'
53
+ | 'macho'
53
54
  | 'exe'
54
55
  | 'swf'
55
56
  | 'rtf'
@@ -152,6 +153,7 @@ export type FileExtension =
152
153
  | 'ace'
153
154
  | 'avro'
154
155
  | 'icc'
156
+ | 'fbx'
155
157
  ; // eslint-disable-line semi-style
156
158
 
157
159
  export type MimeType =
@@ -209,6 +211,7 @@ export type MimeType =
209
211
  | 'audio/amr'
210
212
  | 'application/pdf'
211
213
  | 'application/x-elf'
214
+ | 'application/x-mach-binary'
212
215
  | 'application/x-msdownload'
213
216
  | 'application/x-shockwave-flash'
214
217
  | 'application/rtf'
@@ -300,6 +303,7 @@ export type MimeType =
300
303
  | 'application/x-ace-compressed'
301
304
  | 'application/avro'
302
305
  | 'application/vnd.iccprofile'
306
+ | 'application/x.autodesk.fbx'
303
307
  ; // eslint-disable-line semi-style
304
308
 
305
309
  export type FileTypeResult = {
@@ -325,8 +329,8 @@ The file type is detected by checking the [magic number](https://en.wikipedia.or
325
329
 
326
330
  If file access is available, it is recommended to use `.fromFile()` instead.
327
331
 
328
- @param buffer - An Uint8Array or Buffer representing file data. It works best if the buffer contains the entire file, it may work with a smaller portion as well.
329
- @returns The detected file type and MIME type, or `undefined` when there is no match.
332
+ @param buffer - An Uint8Array or Buffer representing file data. It works best if the buffer contains the entire file. It may work with a smaller portion as well.
333
+ @returns The detected file type, or `undefined` when there is no match.
330
334
  */
331
335
  export function fileTypeFromBuffer(buffer: Uint8Array | ArrayBuffer): Promise<FileTypeResult | undefined>;
332
336
 
@@ -336,7 +340,7 @@ Detect the file type of a Node.js [readable stream](https://nodejs.org/api/strea
336
340
  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.
337
341
 
338
342
  @param stream - A readable stream representing file data.
339
- @returns The detected file type and MIME type, or `undefined` when there is no match.
343
+ @returns The detected file type, or `undefined` when there is no match.
340
344
  */
341
345
  export function fileTypeFromStream(stream: ReadableStream): Promise<FileTypeResult | undefined>;
342
346
 
@@ -348,7 +352,7 @@ This method is used internally, but can also be used for a special "tokenizer" r
348
352
  A tokenizer propagates the internal read functions, allowing alternative transport mechanisms, to access files, to be implemented and used.
349
353
 
350
354
  @param tokenizer - File source implementing the tokenizer interface.
351
- @returns The detected file type and MIME type, or `undefined` when there is no match.
355
+ @returns The detected file type, or `undefined` when there is no match.
352
356
 
353
357
  An example is [`@tokenizer/http`](https://github.com/Borewit/tokenizer-http), which requests data using [HTTP-range-requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests). A difference with a conventional stream and the [*tokenizer*](https://github.com/Borewit/strtok3#tokenizer), is that it is able to *ignore* (seek, fast-forward) in the stream. For example, you may only need and read the first 6 bytes, and the last 128 bytes, which may be an advantage in case reading the entire file would take longer.
354
358
 
@@ -419,19 +423,108 @@ if (stream2.fileType?.mime === 'image/jpeg') {
419
423
  export function fileTypeStream(readableStream: ReadableStream, options?: StreamOptions): Promise<ReadableStreamWithFileType>;
420
424
 
421
425
  /**
422
- Detect the file type of a [`Blob`](https://nodejs.org/api/buffer.html#class-blob).
426
+ Detect the file type of a [`Blob`](https://nodejs.org/api/buffer.html#class-blob) or [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File).
427
+
428
+ @param blob - The [`Blob`](https://nodejs.org/api/buffer.html#class-blob) used for file detection.
429
+ @returns The detected file type, or `undefined` when there is no match.
423
430
 
424
431
  @example
425
432
  ```
426
433
  import {fileTypeFromBlob} from 'file-type';
427
434
 
428
435
  const blob = new Blob(['<?xml version="1.0" encoding="ISO-8859-1" ?>'], {
429
- type: 'plain/text',
436
+ type: 'text/plain',
430
437
  endings: 'native'
431
438
  });
432
439
 
433
440
  console.log(await fileTypeFromBlob(blob));
434
- //=> {ext: 'txt', mime: 'plain/text'}
441
+ //=> {ext: 'txt', mime: 'text/plain'}
435
442
  ```
436
443
  */
437
444
  export declare function fileTypeFromBlob(blob: Blob): Promise<FileTypeResult | undefined>;
445
+
446
+ /**
447
+ Function that allows specifying custom detection mechanisms.
448
+
449
+ An iterable of detectors can be provided via the `fileTypeOptions` argument for the {@link FileTypeParser.constructor}.
450
+
451
+ The detectors are called before the default detections in the provided order.
452
+
453
+ Custom detectors can be used to add new `FileTypeResults` or to modify return behavior of existing `FileTypeResult` detections.
454
+
455
+ If the detector returns `undefined`, there are 2 possible scenarios:
456
+
457
+ 1. The detector has not read from the tokenizer, it will be proceeded with the next available detector.
458
+ 2. The detector has read from the tokenizer (`tokenizer.position` has been increased).
459
+ In that case no further detectors will be executed and the final conclusion is that file-type returns undefined.
460
+ Note that this an exceptional scenario, as the detector takes the opportunity from any other detector to determine the file type.
461
+
462
+ Example detector array which can be extended and provided via the fileTypeOptions argument:
463
+
464
+ ```
465
+ import {FileTypeParser} from 'file-type';
466
+
467
+ const customDetectors = [
468
+ async tokenizer => {
469
+ const unicornHeader = [85, 78, 73, 67, 79, 82, 78]; // 'UNICORN' as decimal string
470
+
471
+ const buffer = Buffer.alloc(7);
472
+ await tokenizer.peekBuffer(buffer, {length: unicornHeader.length, mayBeLess: true});
473
+ if (unicornHeader.every((value, index) => value === buffer[index])) {
474
+ return {ext: 'unicorn', mime: 'application/unicorn'};
475
+ }
476
+
477
+ return undefined;
478
+ },
479
+ ];
480
+
481
+ const buffer = Buffer.from('UNICORN');
482
+ const parser = new FileTypeParser({customDetectors});
483
+ const fileType = await parser.fromBuffer(buffer);
484
+ console.log(fileType);
485
+ ```
486
+
487
+ @param tokenizer - The [tokenizer](https://github.com/Borewit/strtok3#tokenizer) used to read the file content from.
488
+ @param fileType - The file type detected by the standard detections or a previous custom detection, or `undefined`` if no matching file type could be found.
489
+ @returns The detected file type, or `undefined` when there is no match.
490
+ */
491
+ export type Detector = (tokenizer: ITokenizer, fileType?: FileTypeResult) => Promise<FileTypeResult | undefined>;
492
+
493
+ export type FileTypeOptions = {
494
+ customDetectors?: Iterable<Detector>;
495
+ };
496
+
497
+ export declare class TokenizerPositionError extends Error {
498
+ constructor(message?: string);
499
+ }
500
+
501
+ export declare class FileTypeParser {
502
+ detectors: Iterable<Detector>;
503
+
504
+ constructor(options?: {customDetectors?: Iterable<Detector>});
505
+
506
+ /**
507
+ Works the same way as {@link fileTypeFromBuffer}, additionally taking into account custom detectors (if any were provided to the constructor).
508
+ */
509
+ fromBuffer(buffer: Uint8Array | ArrayBuffer): Promise<FileTypeResult | undefined>;
510
+
511
+ /**
512
+ Works the same way as {@link fileTypeFromStream}, additionally taking into account custom detectors (if any were provided to the constructor).
513
+ */
514
+ fromStream(stream: ReadableStream): Promise<FileTypeResult | undefined>;
515
+
516
+ /**
517
+ Works the same way as {@link fileTypeFromTokenizer}, additionally taking into account custom detectors (if any were provided to the constructor).
518
+ */
519
+ fromTokenizer(tokenizer: ITokenizer): Promise<FileTypeResult | undefined>;
520
+
521
+ /**
522
+ Works the same way as {@link fileTypeFromBlob}, additionally taking into account custom detectors (if any were provided to the constructor).
523
+ */
524
+ fromBlob(blob: Blob): Promise<FileTypeResult | undefined>;
525
+
526
+ /**
527
+ Works the same way as {@link fileTypeStream}, additionally taking into account custom detectors (if any were provided to the constructor).
528
+ */
529
+ toDetectionStream(readableStream: ReadableStream, options?: StreamOptions): Promise<FileTypeResult | undefined>;
530
+ }
package/core.js CHANGED
@@ -11,31 +11,15 @@ import {extensions, mimeTypes} from './supported.js';
11
11
  const minimumBytes = 4100; // A fair amount of file-types are detectable within this range.
12
12
 
13
13
  export async function fileTypeFromStream(stream) {
14
- const tokenizer = await strtok3.fromStream(stream);
15
- try {
16
- return await fileTypeFromTokenizer(tokenizer);
17
- } finally {
18
- await tokenizer.close();
19
- }
14
+ return new FileTypeParser().fromStream(stream);
20
15
  }
21
16
 
22
17
  export async function fileTypeFromBuffer(input) {
23
- if (!(input instanceof Uint8Array || input instanceof ArrayBuffer)) {
24
- throw new TypeError(`Expected the \`input\` argument to be of type \`Uint8Array\` or \`Buffer\` or \`ArrayBuffer\`, got \`${typeof input}\``);
25
- }
26
-
27
- const buffer = input instanceof Uint8Array ? input : new Uint8Array(input);
28
-
29
- if (!(buffer?.length > 1)) {
30
- return;
31
- }
32
-
33
- return fileTypeFromTokenizer(strtok3.fromBuffer(buffer));
18
+ return new FileTypeParser().fromBuffer(input);
34
19
  }
35
20
 
36
21
  export async function fileTypeFromBlob(blob) {
37
- const buffer = await blob.arrayBuffer();
38
- return fileTypeFromBuffer(new Uint8Array(buffer));
22
+ return new FileTypeParser().fromBlob(blob);
39
23
  }
40
24
 
41
25
  function _check(buffer, headers, options) {
@@ -60,16 +44,98 @@ function _check(buffer, headers, options) {
60
44
  }
61
45
 
62
46
  export async function fileTypeFromTokenizer(tokenizer) {
63
- try {
64
- return new FileTypeParser().parse(tokenizer);
65
- } catch (error) {
66
- if (!(error instanceof strtok3.EndOfStreamError)) {
67
- throw error;
47
+ return new FileTypeParser().fromTokenizer(tokenizer);
48
+ }
49
+
50
+ export class FileTypeParser {
51
+ constructor(options) {
52
+ this.detectors = options?.customDetectors;
53
+
54
+ this.fromTokenizer = this.fromTokenizer.bind(this);
55
+ this.fromBuffer = this.fromBuffer.bind(this);
56
+ this.parse = this.parse.bind(this);
57
+ }
58
+
59
+ async fromTokenizer(tokenizer) {
60
+ const initialPosition = tokenizer.position;
61
+
62
+ for (const detector of this.detectors || []) {
63
+ const fileType = await detector(tokenizer);
64
+ if (fileType) {
65
+ return fileType;
66
+ }
67
+
68
+ if (initialPosition !== tokenizer.position) {
69
+ return undefined; // Cannot proceed scanning of the tokenizer is at an arbitrary position
70
+ }
68
71
  }
72
+
73
+ return this.parse(tokenizer);
74
+ }
75
+
76
+ async fromBuffer(input) {
77
+ if (!(input instanceof Uint8Array || input instanceof ArrayBuffer)) {
78
+ throw new TypeError(`Expected the \`input\` argument to be of type \`Uint8Array\` or \`Buffer\` or \`ArrayBuffer\`, got \`${typeof input}\``);
79
+ }
80
+
81
+ const buffer = input instanceof Uint8Array ? input : new Uint8Array(input);
82
+
83
+ if (!(buffer?.length > 1)) {
84
+ return;
85
+ }
86
+
87
+ return this.fromTokenizer(strtok3.fromBuffer(buffer));
88
+ }
89
+
90
+ async fromBlob(blob) {
91
+ const buffer = await blob.arrayBuffer();
92
+ return this.fromBuffer(new Uint8Array(buffer));
93
+ }
94
+
95
+ async fromStream(stream) {
96
+ const tokenizer = await strtok3.fromStream(stream);
97
+ try {
98
+ return await this.fromTokenizer(tokenizer);
99
+ } finally {
100
+ await tokenizer.close();
101
+ }
102
+ }
103
+
104
+ async toDetectionStream(readableStream, options = {}) {
105
+ const {default: stream} = await import('node:stream');
106
+ const {sampleSize = minimumBytes} = options;
107
+
108
+ return new Promise((resolve, reject) => {
109
+ readableStream.on('error', reject);
110
+
111
+ readableStream.once('readable', () => {
112
+ (async () => {
113
+ try {
114
+ // Set up output stream
115
+ const pass = new stream.PassThrough();
116
+ const outputStream = stream.pipeline ? stream.pipeline(readableStream, pass, () => {}) : readableStream.pipe(pass);
117
+
118
+ // Read the input stream and detect the filetype
119
+ const chunk = readableStream.read(sampleSize) ?? readableStream.read() ?? Buffer.alloc(0);
120
+ try {
121
+ pass.fileType = await this.fromBuffer(chunk);
122
+ } catch (error) {
123
+ if (error instanceof strtok3.EndOfStreamError) {
124
+ pass.fileType = undefined;
125
+ } else {
126
+ reject(error);
127
+ }
128
+ }
129
+
130
+ resolve(outputStream);
131
+ } catch (error) {
132
+ reject(error);
133
+ }
134
+ })();
135
+ });
136
+ });
69
137
  }
70
- }
71
138
 
72
- class FileTypeParser {
73
139
  check(header, options) {
74
140
  return _check(this.buffer, header, options);
75
141
  }
@@ -211,7 +277,7 @@ class FileTypeParser {
211
277
  }
212
278
 
213
279
  await tokenizer.ignore(id3HeaderLength);
214
- return fileTypeFromTokenizer(tokenizer); // Skip ID3 header, recursion
280
+ return this.fromTokenizer(tokenizer); // Skip ID3 header, recursion
215
281
  }
216
282
 
217
283
  // Musepack, SV7
@@ -694,7 +760,7 @@ class FileTypeParser {
694
760
  };
695
761
  }
696
762
 
697
- // https://github.com/threatstack/libmagic/blob/master/magic/Magdir/matroska
763
+ // https://github.com/file/file/blob/master/magic/Magdir/matroska
698
764
  if (this.check([0x1A, 0x45, 0xDF, 0xA3])) { // Root element: EBML
699
765
  async function readField() {
700
766
  const msb = await tokenizer.peekNumber(Token.UINT8);
@@ -855,6 +921,13 @@ class FileTypeParser {
855
921
  };
856
922
  }
857
923
 
924
+ if (this.check([0xCF, 0xFA, 0xED, 0xFE])) {
925
+ return {
926
+ ext: 'macho',
927
+ mime: 'application/x-mach-binary',
928
+ };
929
+ }
930
+
858
931
  // -- 5-byte signatures --
859
932
 
860
933
  if (this.check([0x4F, 0x54, 0x54, 0x4F, 0x00])) {
@@ -1433,6 +1506,13 @@ class FileTypeParser {
1433
1506
  };
1434
1507
  }
1435
1508
 
1509
+ if (this.checkString('Kaydara FBX Binary \u0000')) {
1510
+ return {
1511
+ ext: 'fbx',
1512
+ mime: 'application/x.autodesk.fbx', // Invented by us
1513
+ };
1514
+ }
1515
+
1436
1516
  if (
1437
1517
  this.check([0x4C, 0x50], {offset: 34})
1438
1518
  && (
@@ -1602,39 +1682,8 @@ class FileTypeParser {
1602
1682
  }
1603
1683
  }
1604
1684
 
1605
- export async function fileTypeStream(readableStream, {sampleSize = minimumBytes} = {}) {
1606
- const {default: stream} = await import('node:stream');
1607
-
1608
- return new Promise((resolve, reject) => {
1609
- readableStream.on('error', reject);
1610
-
1611
- readableStream.once('readable', () => {
1612
- (async () => {
1613
- try {
1614
- // Set up output stream
1615
- const pass = new stream.PassThrough();
1616
- const outputStream = stream.pipeline ? stream.pipeline(readableStream, pass, () => {}) : readableStream.pipe(pass);
1617
-
1618
- // Read the input stream and detect the filetype
1619
- const chunk = readableStream.read(sampleSize) ?? readableStream.read() ?? Buffer.alloc(0);
1620
- try {
1621
- const fileType = await fileTypeFromBuffer(chunk);
1622
- pass.fileType = fileType;
1623
- } catch (error) {
1624
- if (error instanceof strtok3.EndOfStreamError) {
1625
- pass.fileType = undefined;
1626
- } else {
1627
- reject(error);
1628
- }
1629
- }
1630
-
1631
- resolve(outputStream);
1632
- } catch (error) {
1633
- reject(error);
1634
- }
1635
- })();
1636
- });
1637
- });
1685
+ export async function fileTypeStream(readableStream, options = {}) {
1686
+ return new FileTypeParser().toDetectionStream(readableStream, options);
1638
1687
  }
1639
1688
 
1640
1689
  export const supportedExtensions = new Set(extensions);
package/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import * as strtok3 from 'strtok3';
2
- import {fileTypeFromTokenizer} from './core.js';
2
+ import {FileTypeParser} from './core.js';
3
3
 
4
- export async function fileTypeFromFile(path) {
4
+ export async function fileTypeFromFile(path, fileTypeOptions) {
5
5
  const tokenizer = await strtok3.fromFile(path);
6
6
  try {
7
- return await fileTypeFromTokenizer(tokenizer);
7
+ const parser = new FileTypeParser(fileTypeOptions);
8
+ return await parser.fromTokenizer(tokenizer);
8
9
  } finally {
9
10
  await tokenizer.close();
10
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "file-type",
3
- "version": "18.5.0",
3
+ "version": "18.7.0",
4
4
  "description": "Detect the file type of a Buffer/Uint8Array/ArrayBuffer",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/file-type",
@@ -18,6 +18,7 @@
18
18
  },
19
19
  "./core": "./core.js"
20
20
  },
21
+ "sideEffects": false,
21
22
  "engines": {
22
23
  "node": ">=14.16"
23
24
  },
@@ -52,6 +53,7 @@
52
53
  "is",
53
54
  "exif",
54
55
  "elf",
56
+ "macho",
55
57
  "exe",
56
58
  "binary",
57
59
  "buffer",
@@ -204,7 +206,8 @@
204
206
  "cpio",
205
207
  "ace",
206
208
  "avro",
207
- "icc"
209
+ "icc",
210
+ "fbx"
208
211
  ],
209
212
  "dependencies": {
210
213
  "readable-web-to-node-stream": "^3.0.2",
package/readme.md CHANGED
@@ -113,7 +113,7 @@ The file type is detected by checking the [magic number](https://en.wikipedia.or
113
113
 
114
114
  If file access is available, it is recommended to use `fileTypeFromFile()` instead.
115
115
 
116
- Returns a `Promise` for an object with the detected file type and MIME type:
116
+ Returns a `Promise` for an object with the detected file type:
117
117
 
118
118
  - `ext` - One of the [supported file types](#supported-file-types)
119
119
  - `mime` - The [MIME type](https://en.wikipedia.org/wiki/Internet_media_type)
@@ -124,7 +124,7 @@ Or `undefined` when there is no match.
124
124
 
125
125
  Type: `Buffer | Uint8Array | ArrayBuffer`
126
126
 
127
- A buffer representing file data. It works best if the buffer contains the entire file, it may work with a smaller portion as well.
127
+ A buffer representing file data. It works best if the buffer contains the entire file. It may work with a smaller portion as well.
128
128
 
129
129
  ### fileTypeFromFile(filePath)
130
130
 
@@ -132,7 +132,7 @@ Detect the file type of a file path.
132
132
 
133
133
  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.
134
134
 
135
- Returns a `Promise` for an object with the detected file type and MIME type:
135
+ Returns a `Promise` for an object with the detected file type:
136
136
 
137
137
  - `ext` - One of the [supported file types](#supported-file-types)
138
138
  - `mime` - The [MIME type](https://en.wikipedia.org/wiki/Internet_media_type)
@@ -151,7 +151,7 @@ Detect the file type of a Node.js [readable stream](https://nodejs.org/api/strea
151
151
 
152
152
  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.
153
153
 
154
- Returns a `Promise` for an object with the detected file type and MIME type:
154
+ Returns a `Promise` for an object with the detected file type:
155
155
 
156
156
  - `ext` - One of the [supported file types](#supported-file-types)
157
157
  - `mime` - The [MIME type](https://en.wikipedia.org/wiki/Internet_media_type)
@@ -170,7 +170,7 @@ Detect the file type of a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/
170
170
 
171
171
  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.
172
172
 
173
- Returns a `Promise` for an object with the detected file type and MIME type:
173
+ Returns a `Promise` for an object with the detected file type:
174
174
 
175
175
  - `ext` - One of the [supported file types](#supported-file-types)
176
176
  - `mime` - The [MIME type](https://en.wikipedia.org/wiki/Internet_media_type)
@@ -181,14 +181,18 @@ Or `undefined` when there is no match.
181
181
  import {fileTypeFromBlob} from 'file-type';
182
182
 
183
183
  const blob = new Blob(['<?xml version="1.0" encoding="ISO-8859-1" ?>'], {
184
- type: 'plain/text',
184
+ type: 'text/plain',
185
185
  endings: 'native'
186
186
  });
187
187
 
188
188
  console.log(await fileTypeFromBlob(blob));
189
- //=> {ext: 'txt', mime: 'plain/text'}
189
+ //=> {ext: 'txt', mime: 'text/plain'}
190
190
  ```
191
191
 
192
+ #### blob
193
+
194
+ Type: [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
195
+
192
196
  ### fileTypeFromTokenizer(tokenizer)
193
197
 
194
198
  Detect the file type from an `ITokenizer` source.
@@ -197,7 +201,7 @@ This method is used internally, but can also be used for a special "tokenizer" r
197
201
 
198
202
  A tokenizer propagates the internal read functions, allowing alternative transport mechanisms, to access files, to be implemented and used.
199
203
 
200
- Returns a `Promise` for an object with the detected file type and MIME type:
204
+ Returns a `Promise` for an object with the detected file type:
201
205
 
202
206
  - `ext` - One of the [supported file types](#supported-file-types)
203
207
  - `mime` - The [MIME type](https://en.wikipedia.org/wiki/Internet_media_type)
@@ -305,6 +309,49 @@ Returns a `Set<string>` of supported file extensions.
305
309
 
306
310
  Returns a `Set<string>` of supported MIME types.
307
311
 
312
+ ## Custom detectors
313
+
314
+ A custom detector is a function that allows specifying custom detection mechanisms.
315
+
316
+ An iterable of detectors can be provided via the `fileTypeOptions` argument for the `FileTypeParser` constructor.
317
+
318
+ The detectors are called before the default detections in the provided order.
319
+
320
+ Custom detectors can be used to add new `FileTypeResults` or to modify return behaviour of existing `FileTypeResult` detections.
321
+
322
+ If the detector returns `undefined`, there are 2 possible scenarios:
323
+
324
+ 1. The detector has not read from the tokenizer, it will be proceeded with the next available detector.
325
+ 2. The detector has read from the tokenizer (`tokenizer.position` has been increased).
326
+ In that case no further detectors will be executed and the final conclusion is that file-type returns undefined.
327
+ Note that this an exceptional scenario, as the detector takes the opportunity from any other detector to determine the file type.
328
+
329
+ Example detector array which can be extended and provided to each public method via the `fileTypeOptions` argument:
330
+
331
+ ```js
332
+ import {FileTypeParser} from 'file-type';
333
+
334
+ const customDetectors = [
335
+ async tokenizer => {
336
+ const unicornHeader = [85, 78, 73, 67, 79, 82, 78]; // 'UNICORN' as decimal string
337
+
338
+ const buffer = Buffer.alloc(7);
339
+ await tokenizer.peekBuffer(buffer, {length: unicornHeader.length, mayBeLess: true});
340
+
341
+ if (unicornHeader.every((value, index) => value === buffer[index])) {
342
+ return {ext: 'unicorn', mime: 'application/unicorn'};
343
+ }
344
+
345
+ return undefined;
346
+ },
347
+ ];
348
+
349
+ const buffer = Buffer.from('UNICORN');
350
+ const parser = new FileTypeParser({customDetectors});
351
+ const fileType = await parser.fromBuffer(buffer);
352
+ console.log(fileType);
353
+ ```
354
+
308
355
  ## Supported file types
309
356
 
310
357
  - [`3g2`](https://en.wikipedia.org/wiki/3GP_and_3G2#3G2) - Multimedia container format defined by the 3GPP2 for 3G CDMA2000 multimedia services
@@ -335,7 +382,7 @@ Returns a `Set<string>` of supported MIME types.
335
382
  - [`bpg`](https://bellard.org/bpg/) - Better Portable Graphics file
336
383
  - [`bz2`](https://en.wikipedia.org/wiki/Bzip2) - Archive file
337
384
  - [`cab`](https://en.wikipedia.org/wiki/Cabinet_(file_format)) - Cabinet file
338
- - [`cfb`](https://en.wikipedia.org/wiki/Compound_File_Binary_Format) - Compount File Binary Format
385
+ - [`cfb`](https://en.wikipedia.org/wiki/Compound_File_Binary_Format) - Compound File Binary Format
339
386
  - [`chm`](https://en.wikipedia.org/wiki/Microsoft_Compiled_HTML_Help) - Microsoft Compiled HTML Help
340
387
  - [`class`](https://en.wikipedia.org/wiki/Java_class_file) - Java class file
341
388
  - [`cpio`](https://en.wikipedia.org/wiki/Cpio) - Cpio archive
@@ -347,7 +394,7 @@ Returns a `Set<string>` of supported MIME types.
347
394
  - [`deb`](https://en.wikipedia.org/wiki/Deb_(file_format)) - Debian package
348
395
  - [`dmg`](https://en.wikipedia.org/wiki/Apple_Disk_Image) - Apple Disk Image
349
396
  - [`dng`](https://en.wikipedia.org/wiki/Digital_Negative) - Adobe Digital Negative image file
350
- - [`docx`](https://en.wikipedia.org/wiki/Office_Open_XML) - Microsoft Word
397
+ - [`docx`](https://en.wikipedia.org/wiki/Office_Open_XML) - Microsoft Word document
351
398
  - [`dsf`](https://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf) - Sony DSD Stream File (DSF)
352
399
  - [`dwg`](https://en.wikipedia.org/wiki/.dwg) - Autodesk CAD file
353
400
  - [`elf`](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) - Unix Executable and Linkable Format
@@ -359,6 +406,7 @@ Returns a `Set<string>` of supported MIME types.
359
406
  - [`f4b`](https://en.wikipedia.org/wiki/Flash_Video) - Audiobook and podcast ISO base media file format used by Adobe Flash Player
360
407
  - [`f4p`](https://en.wikipedia.org/wiki/Flash_Video) - ISO base media file format protected by Adobe Access DRM used by Adobe Flash Player
361
408
  - [`f4v`](https://en.wikipedia.org/wiki/Flash_Video) - ISO base media file format used by Adobe Flash Player
409
+ - [`fbx`](https://en.wikipedia.org/wiki/FBX) - Filmbox is a proprietary file format used to provide interoperability between digital content creation apps.
362
410
  - [`flac`](https://en.wikipedia.org/wiki/FLAC) - Free Lossless Audio Codec
363
411
  - [`flif`](https://en.wikipedia.org/wiki/Free_Lossless_Image_Format) - Free Lossless Image Format
364
412
  - [`flv`](https://en.wikipedia.org/wiki/Flash_Video) - Flash video
@@ -382,12 +430,13 @@ Returns a `Set<string>` of supported MIME types.
382
430
  - [`jxr`](https://en.wikipedia.org/wiki/JPEG_XR) - Joint Photographic Experts Group extended range
383
431
  - [`ktx`](https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/) - OpenGL and OpenGL ES textures
384
432
  - [`lnk`](https://en.wikipedia.org/wiki/Shortcut_%28computing%29#Microsoft_Windows) - Microsoft Windows file shortcut
385
- - [`lz`](https://en.wikipedia.org/wiki/Lzip) - Arhive file
433
+ - [`lz`](https://en.wikipedia.org/wiki/Lzip) - Archive file
386
434
  - [`lzh`](https://en.wikipedia.org/wiki/LHA_(file_format)) - LZH archive
387
435
  - [`m4a`](https://en.wikipedia.org/wiki/M4A) - Audio-only MPEG-4 files
388
436
  - [`m4b`](https://en.wikipedia.org/wiki/M4B) - Audiobook and podcast MPEG-4 files, which also contain metadata including chapter markers, images, and hyperlinks
389
437
  - [`m4p`](https://en.wikipedia.org/wiki/MPEG-4_Part_14#Filename_extensions) - MPEG-4 files with audio streams encrypted by FairPlay Digital Rights Management as were sold through the iTunes Store
390
438
  - [`m4v`](https://en.wikipedia.org/wiki/M4V) - Video container format developed by Apple, which is very similar to the MP4 format
439
+ - [`macho`](https://en.wikipedia.org/wiki/Mach-O) - Mach-O binary format
391
440
  - [`mid`](https://en.wikipedia.org/wiki/MIDI) - Musical Instrument Digital Interface file
392
441
  - [`mie`](https://en.wikipedia.org/wiki/Sidecar_file) - Dedicated meta information format which supports storage of binary as well as textual meta information
393
442
  - [`mj2`](https://en.wikipedia.org/wiki/Motion_JPEG_2000) - Motion JPEG 2000
@@ -420,7 +469,7 @@ Returns a `Set<string>` of supported MIME types.
420
469
  - [`pdf`](https://en.wikipedia.org/wiki/Portable_Document_Format) - Portable Document Format
421
470
  - [`pgp`](https://en.wikipedia.org/wiki/Pretty_Good_Privacy) - Pretty Good Privacy
422
471
  - [`png`](https://en.wikipedia.org/wiki/Portable_Network_Graphics) - Portable Network Graphics
423
- - [`pptx`](https://en.wikipedia.org/wiki/Office_Open_XML) - Microsoft Powerpoint
472
+ - [`pptx`](https://en.wikipedia.org/wiki/Office_Open_XML) - Microsoft Powerpoint document
424
473
  - [`ps`](https://en.wikipedia.org/wiki/Postscript) - Postscript
425
474
  - [`psd`](https://en.wikipedia.org/wiki/Adobe_Photoshop#File_format) - Adobe Photoshop document
426
475
  - [`pst`](https://en.wikipedia.org/wiki/Personal_Storage_Table) - Personal Storage Table file
@@ -450,7 +499,7 @@ Returns a `Set<string>` of supported MIME types.
450
499
  - [`woff2`](https://en.wikipedia.org/wiki/Web_Open_Font_Format) - Web Open Font Format
451
500
  - [`wv`](https://en.wikipedia.org/wiki/WavPack) - WavPack
452
501
  - [`xcf`](https://en.wikipedia.org/wiki/XCF_(file_format)) - eXperimental Computing Facility
453
- - [`xlsx`](https://en.wikipedia.org/wiki/Office_Open_XML) - Microsoft Excel
502
+ - [`xlsx`](https://en.wikipedia.org/wiki/Office_Open_XML) - Microsoft Excel document
454
503
  - [`xm`](https://wiki.openmpt.org/Manual:_Module_formats#The_FastTracker_2_format_.28.xm.29) - Audio module format: FastTracker 2
455
504
  - [`xml`](https://en.wikipedia.org/wiki/XML) - eXtensible Markup Language
456
505
  - [`xpi`](https://en.wikipedia.org/wiki/XPInstall) - XPInstall file
@@ -458,7 +507,7 @@ Returns a `Set<string>` of supported MIME types.
458
507
  - [`zip`](https://en.wikipedia.org/wiki/Zip_(file_format)) - Archive file
459
508
  - [`zst`](https://en.wikipedia.org/wiki/Zstandard) - Archive file
460
509
 
461
- *Pull requests are welcome for additional commonly used file types.*
510
+ *[Pull requests](.github/pull_request_template.md) are welcome for additional commonly used file types.*
462
511
 
463
512
  The following file types will not be accepted:
464
513
  - [MS-CFB: Microsoft Compound File Binary File Format based formats](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/53989ce4-7b05-4f8d-829b-d08d6148375b), too old and difficult to parse:
@@ -469,16 +518,26 @@ The following file types will not be accepted:
469
518
  - `.csv` - [Reason.](https://github.com/sindresorhus/file-type/issues/264#issuecomment-568439196)
470
519
  - `.svg` - Detecting it requires a full-blown parser. Check out [`is-svg`](https://github.com/sindresorhus/is-svg) for something that mostly works.
471
520
 
521
+ #### tokenizer
522
+
523
+ Type: [`ITokenizer`](https://github.com/Borewit/strtok3#tokenizer)
524
+
525
+ Usable as source of the examined file.
526
+
527
+ #### fileType
528
+
529
+ Type: `FileTypeResult`
530
+
531
+ An object having an `ext` (extension) and `mime` (mime type) property.
532
+
533
+ Detected by the standard detections or a previous custom detection. Undefined if no matching fileTypeResult could be found.
534
+
472
535
  ## Related
473
536
 
474
537
  - [file-type-cli](https://github.com/sindresorhus/file-type-cli) - CLI for this module
538
+ - [image-dimensions](https://github.com/sindresorhus/image-dimensions) - Get the dimensions of an image
475
539
 
476
540
  ## Maintainers
477
541
 
478
542
  - [Sindre Sorhus](https://github.com/sindresorhus)
479
543
  - [Borewit](https://github.com/Borewit)
480
-
481
- **Former**
482
-
483
- - [Mikael Finstad](https://github.com/mifi)
484
- - [Ben Brook](https://github.com/bencmbrook)
package/supported.js CHANGED
@@ -48,6 +48,7 @@ export const extensions = [
48
48
  'pdf',
49
49
  'epub',
50
50
  'elf',
51
+ 'macho',
51
52
  'exe',
52
53
  'swf',
53
54
  'rtf',
@@ -149,6 +150,7 @@ export const extensions = [
149
150
  'ace',
150
151
  'avro',
151
152
  'icc',
153
+ 'fbx',
152
154
  ];
153
155
 
154
156
  export const mimeTypes = [
@@ -206,6 +208,7 @@ export const mimeTypes = [
206
208
  'audio/amr',
207
209
  'application/pdf',
208
210
  'application/x-elf',
211
+ 'application/x-mach-binary',
209
212
  'application/x-msdownload',
210
213
  'application/x-shockwave-flash',
211
214
  'application/rtf',
@@ -297,4 +300,5 @@ export const mimeTypes = [
297
300
  'application/x-ace-compressed',
298
301
  'application/avro',
299
302
  'application/vnd.iccprofile',
303
+ 'application/x.autodesk.fbx', // Invented by us
300
304
  ];