From b815b5e173dd9f521311615eb33e955181030ca9 Mon Sep 17 00:00:00 2001 From: Borewit Date: Mon, 8 Jul 2024 00:05:58 +0200 Subject: [PATCH] Add support for reading from a web stream (#635) Co-authored-by: Sindre Sorhus --- .github/workflows/main.yml | 1 + browser.d.ts | 29 ----------- browser.js | 15 ------ core.d.ts | 61 +++++------------------ core.js | 52 +++----------------- index.d.ts | 60 ++++++++++++++++++++++- index.js | 63 +++++++++++++++++++++++- index.test-d.ts | 4 +- package.json | 5 +- readme.md | 4 +- test.js | 99 ++++++++++++++++++++++---------------- 11 files changed, 204 insertions(+), 189 deletions(-) delete mode 100644 browser.d.ts delete mode 100644 browser.js diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 346585cf..6e981506 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,6 +10,7 @@ jobs: fail-fast: false matrix: node-version: + - 22 - 20 - 18 steps: diff --git a/browser.d.ts b/browser.d.ts deleted file mode 100644 index 83c015f9..00000000 --- a/browser.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type {FileTypeResult} from './core.js'; - -/** -Detect the file type of a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream). - -@example -``` -import {fileTypeFromStream} from 'file-type'; - -const url = 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg'; - -const response = await fetch(url); -const fileType = await fileTypeFromStream(response.body); - -console.log(fileType); -//=> {ext: 'jpg', mime: 'image/jpeg'} -``` -*/ -export declare function fileTypeFromStream(stream: ReadableStream): Promise; - -export { - fileTypeFromBuffer, - fileTypeFromBlob, - supportedExtensions, - supportedMimeTypes, - type FileTypeResult, - type FileExtension, - type MimeType, -} from './core.js'; diff --git a/browser.js b/browser.js deleted file mode 100644 index 54cdb06e..00000000 --- a/browser.js +++ /dev/null @@ -1,15 +0,0 @@ -import {ReadableWebToNodeStream} from 'readable-web-to-node-stream'; -import {fileTypeFromStream as coreFileTypeFromStream} from './core.js'; - -export async function fileTypeFromStream(stream) { - const readableWebToNodeStream = new ReadableWebToNodeStream(stream); - const fileType = await coreFileTypeFromStream(readableWebToNodeStream); - await readableWebToNodeStream.close(); - return fileType; -} - -export { - fileTypeFromTokenizer, - fileTypeFromBuffer, - fileTypeStream, -} from './core.js'; diff --git a/core.d.ts b/core.d.ts index 9247a843..2c6a7180 100644 --- a/core.d.ts +++ b/core.d.ts @@ -1,6 +1,16 @@ -import type {Readable as ReadableStream} from 'node:stream'; +/** +Typings for primary entry point, Node.js specific typings can be found in index.d.ts +*/ + +import type {ReadableStream as WebReadableStream} from 'node:stream/web'; import type {ITokenizer} from 'strtok3'; +/** +Either the Node.js ReadableStream or the `lib.dom.d.ts` ReadableStream. +Related issue: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/60377 +*/ +export type AnyWebReadableStream = WebReadableStream | ReadableStream; + export type FileExtension = | 'jpg' | 'png' @@ -318,10 +328,6 @@ export type FileTypeResult = { readonly mime: MimeType; }; -export type ReadableStreamWithFileType = ReadableStream & { - readonly fileType?: FileTypeResult; -}; - /** Detect the file type of a `Uint8Array`, or `ArrayBuffer`. @@ -339,10 +345,10 @@ Detect the file type of a Node.js [readable stream](https://nodejs.org/api/strea 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. -@param stream - A readable stream representing file data. +@param stream - A Node.js Readable stream or Web API Readable Stream representing file data. The Web Readable stream **must be a byte stream**. @returns The detected file type, or `undefined` when there is no match. */ -export function fileTypeFromStream(stream: ReadableStream): Promise; +export function fileTypeFromStream(stream: AnyWebReadableStream): Promise; /** Detect the file type from an [`ITokenizer`](https://github.com/Borewit/strtok3#tokenizer) source. @@ -391,37 +397,6 @@ export type StreamOptions = { readonly sampleSize?: number; }; -/** -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 `fileTypeFromFile()`. - -This method can be handy to put in between a stream, but it comes with a price. -Internally `stream()` builds up a buffer of `sampleSize` bytes, used as a sample, to determine the file type. -The sample size impacts the file detection resolution. -A smaller sample size will result in lower probability of the best file type detection. - -**Note:** This method is only available when using Node.js. -**Note:** Requires Node.js 14 or later. - -@param readableStream - A [readable stream](https://nodejs.org/api/stream.html#stream_class_stream_readable) containing a file to examine. -@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 `fileTypeFromFile()`. - -@example -``` -import got from 'got'; -import {fileTypeStream} from 'file-type'; - -const url = 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg'; - -const stream1 = got.stream(url); -const stream2 = await fileTypeStream(stream1, {sampleSize: 1024}); - -if (stream2.fileType?.mime === 'image/jpeg') { - // stream2 can be used to stream the JPEG image (from the very beginning of the stream) -} -``` -*/ -export function fileTypeStream(readableStream: ReadableStream, options?: StreamOptions): Promise; - /** 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). @@ -508,11 +483,6 @@ export declare class FileTypeParser { */ fromBuffer(buffer: Uint8Array | ArrayBuffer): Promise; - /** - Works the same way as {@link fileTypeFromStream}, additionally taking into account custom detectors (if any were provided to the constructor). - */ - fromStream(stream: ReadableStream): Promise; - /** Works the same way as {@link fileTypeFromTokenizer}, additionally taking into account custom detectors (if any were provided to the constructor). */ @@ -522,9 +492,4 @@ export declare class FileTypeParser { Works the same way as {@link fileTypeFromBlob}, additionally taking into account custom detectors (if any were provided to the constructor). */ fromBlob(blob: Blob): Promise; - - /** - Works the same way as {@link fileTypeStream}, additionally taking into account custom detectors (if any were provided to the constructor). - */ - toDetectionStream(readableStream: ReadableStream, options?: StreamOptions): Promise; } diff --git a/core.js b/core.js index 5f92e5f9..bf9ee61b 100644 --- a/core.js +++ b/core.js @@ -1,3 +1,7 @@ +/** +Primary entry point, Node.js specific entry point is index.js +*/ + import * as Token from 'token-types'; import * as strtok3 from 'strtok3/core'; import {includes, indexOf, getUintBE} from 'uint8array-extras'; @@ -8,7 +12,7 @@ import { } from './util.js'; import {extensions, mimeTypes} from './supported.js'; -const minimumBytes = 4100; // A fair amount of file-types are detectable within this range. +export const reasonableDetectionSizeInBytes = 4100; // A fair amount of file-types are detectable within this range. export async function fileTypeFromStream(stream) { return new FileTypeParser().fromStream(stream); @@ -88,12 +92,11 @@ export class FileTypeParser { } async fromBlob(blob) { - const buffer = await blob.arrayBuffer(); - return this.fromBuffer(new Uint8Array(buffer)); + return this.fromStream(blob.stream()); } async fromStream(stream) { - const tokenizer = await strtok3.fromStream(stream); + const tokenizer = await strtok3.fromWebStream(stream); try { return await this.fromTokenizer(tokenizer); } finally { @@ -101,41 +104,6 @@ export class FileTypeParser { } } - async toDetectionStream(readableStream, options = {}) { - const {default: stream} = await import('node:stream'); - const {sampleSize = minimumBytes} = options; - - return new Promise((resolve, reject) => { - readableStream.on('error', reject); - - readableStream.once('readable', () => { - (async () => { - try { - // Set up output stream - const pass = new stream.PassThrough(); - const outputStream = stream.pipeline ? stream.pipeline(readableStream, pass, () => {}) : readableStream.pipe(pass); - - // Read the input stream and detect the filetype - const chunk = readableStream.read(sampleSize) ?? readableStream.read() ?? new Uint8Array(0); - try { - pass.fileType = await this.fromBuffer(chunk); - } catch (error) { - if (error instanceof strtok3.EndOfStreamError) { - pass.fileType = undefined; - } else { - reject(error); - } - } - - resolve(outputStream); - } catch (error) { - reject(error); - } - })(); - }); - }); - } - check(header, options) { return _check(this.buffer, header, options); } @@ -145,7 +113,7 @@ export class FileTypeParser { } async parse(tokenizer) { - this.buffer = new Uint8Array(minimumBytes); + this.buffer = new Uint8Array(reasonableDetectionSizeInBytes); // Keep reading until EOF if the file size is unknown. if (tokenizer.fileInfo.size === undefined) { @@ -1690,9 +1658,5 @@ export class FileTypeParser { } } -export async function fileTypeStream(readableStream, options = {}) { - return new FileTypeParser().toDetectionStream(readableStream, options); -} - export const supportedExtensions = new Set(extensions); export const supportedMimeTypes = new Set(mimeTypes); diff --git a/index.d.ts b/index.d.ts index e2b91ad4..06405516 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,13 +1,69 @@ -import type {FileTypeResult} from './core.js'; +/** +Typings for Node.js specific entry point. +*/ + +import type {Readable as NodeReadableStream} from 'node:stream'; +import type {FileTypeResult, StreamOptions, AnyWebReadableStream} from './core.js'; +import {FileTypeParser} from './core.js'; + +export type ReadableStreamWithFileType = NodeReadableStream & { + readonly fileType?: FileTypeResult; +}; + +export declare class NodeFileTypeParser extends FileTypeParser { + /** + @param stream - Node.js `stream.Readable` or Web API `ReadableStream`. + */ + fromStream(stream: AnyWebReadableStream | NodeReadableStream): Promise; + + /** + Works the same way as {@link fileTypeStream}, additionally taking into account custom detectors (if any were provided to the constructor). + */ + toDetectionStream(readableStream: NodeReadableStream, options?: StreamOptions): Promise; +} /** Detect the file type of a file path. 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. -@param path - The file path to parse. +@param path @returns The detected file type and MIME type or `undefined` when there is no match. */ export function fileTypeFromFile(path: string): Promise; +export function fileTypeFromStream(stream: AnyWebReadableStream | NodeReadableStream): Promise; + +/** +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 `fileTypeFromFile()`. + +This method can be handy to put in between a stream, but it comes with a price. +Internally `stream()` builds up a buffer of `sampleSize` bytes, used as a sample, to determine the file type. +The sample size impacts the file detection resolution. +A smaller sample size will result in lower probability of the best file type detection. + +**Note:** This method is only available when using Node.js. +**Note:** Requires Node.js 14 or later. + +@param readableStream - A [readable stream](https://nodejs.org/api/stream.html#stream_class_stream_readable) containing a file to examine. +@param options - Maybe used to override the default sample-size. +@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 `fileTypeFromFile()`. + +@example +``` +import got from 'got'; +import {fileTypeStream} from 'file-type'; + +const url = 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg'; + +const stream1 = got.stream(url); +const stream2 = await fileTypeStream(stream1, {sampleSize: 1024}); + +if (stream2.fileType?.mime === 'image/jpeg') { + // stream2 can be used to stream the JPEG image (from the very beginning of the stream) +} +``` + */ +export function fileTypeStream(readableStream: NodeReadableStream, options?: StreamOptions): Promise; + export * from './core.js'; diff --git a/index.js b/index.js index 24bacf9d..47670fa5 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,56 @@ +/** +Node.js specific entry point. +*/ + +import {ReadableStream as WebReadableStream} from 'node:stream/web'; import * as strtok3 from 'strtok3'; -import {FileTypeParser} from './core.js'; +import {FileTypeParser, reasonableDetectionSizeInBytes} from './core.js'; + +export class NodeFileTypeParser extends FileTypeParser { + async fromStream(stream) { + const tokenizer = await (stream instanceof WebReadableStream ? strtok3.fromWebStream(stream) : strtok3.fromStream(stream)); + try { + return super.fromTokenizer(tokenizer); + } finally { + await tokenizer.close(); + } + } + + async toDetectionStream(readableStream, options = {}) { + const {default: stream} = await import('node:stream'); + const {sampleSize = reasonableDetectionSizeInBytes} = options; + + return new Promise((resolve, reject) => { + readableStream.on('error', reject); + + readableStream.once('readable', () => { + (async () => { + try { + // Set up output stream + const pass = new stream.PassThrough(); + const outputStream = stream.pipeline ? stream.pipeline(readableStream, pass, () => {}) : readableStream.pipe(pass); + + // Read the input stream and detect the filetype + const chunk = readableStream.read(sampleSize) ?? readableStream.read() ?? new Uint8Array(0); + try { + pass.fileType = await this.fromBuffer(chunk); + } catch (error) { + if (error instanceof strtok3.EndOfStreamError) { + pass.fileType = undefined; + } else { + reject(error); + } + } + + resolve(outputStream); + } catch (error) { + reject(error); + } + })(); + }); + }); + } +} export async function fileTypeFromFile(path, fileTypeOptions) { const tokenizer = await strtok3.fromFile(path); @@ -11,4 +62,12 @@ export async function fileTypeFromFile(path, fileTypeOptions) { } } -export * from './core.js'; +export async function fileTypeFromStream(stream, fileTypeOptions) { + return (new NodeFileTypeParser(fileTypeOptions)).fromStream(stream); +} + +export async function fileTypeStream(readableStream, options = {}) { + return new NodeFileTypeParser().toDetectionStream(readableStream, options); +} + +export {fileTypeFromBuffer, fileTypeFromBlob, FileTypeParser, supportedMimeTypes, supportedExtensions} from './core.js'; diff --git a/index.test-d.ts b/index.test-d.ts index d37b2ccb..72804263 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -2,7 +2,7 @@ import {createReadStream} from 'node:fs'; import {expectType} from 'tsd'; import { type FileTypeResult as FileTypeResultBrowser, -} from './browser.js'; +} from './core.js'; import { fileTypeFromBlob, fileTypeFromBuffer, @@ -63,4 +63,4 @@ expectType>(streamWithFileType); })(); // Browser -expectType>(fileTypeFromBlob(new Blob())); +expectType>(fileTypeFromBlob(new Blob([]))); diff --git a/package.json b/package.json index a7c6eccf..057c444c 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "exports": { ".": { "node": "./index.js", - "default": "./browser.js" + "default": "./core.js" }, "./core": "./core.js" }, @@ -28,8 +28,6 @@ "files": [ "index.js", "index.d.ts", - "browser.js", - "browser.d.ts", "core.js", "core.d.ts", "supported.js", @@ -210,7 +208,6 @@ "fbx" ], "dependencies": { - "readable-web-to-node-stream": "^3.0.2", "strtok3": "^7.1.0", "token-types": "^6.0.0", "uint8array-extras": "^1.3.0" diff --git a/readme.md b/readme.md index bc1cc465..332d263c 100644 --- a/readme.md +++ b/readme.md @@ -147,7 +147,7 @@ The file path to parse. ### fileTypeFromStream(stream) -Detect the file type of a Node.js [readable stream](https://nodejs.org/api/stream.html#stream_class_stream_readable). +Detect the file type of a [Node.js readable stream](https://nodejs.org/api/stream.html#stream_class_stream_readable) or a [Web API ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream). 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. @@ -168,6 +168,8 @@ A readable stream representing file data. Detect the file type of a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). +It will **stream** the underlying Blob, and required a [ReadableStreamBYOBReader](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamBYOBReader) which **require Node.js ≥ 20**. + 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. Returns a `Promise` for an object with the detected file type: diff --git a/test.js b/test.js index 8d937afe..fab062a7 100644 --- a/test.js +++ b/test.js @@ -10,13 +10,13 @@ import * as strtok3 from 'strtok3/core'; import {areUint8ArraysEqual} from 'uint8array-extras'; import { fileTypeFromBuffer, - fileTypeFromStream, + fileTypeFromStream as fileTypeNodeFromStream, fileTypeFromFile, fileTypeFromBlob, - FileTypeParser, fileTypeStream, supportedExtensions, supportedMimeTypes, + NodeFileTypeParser, } from './index.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -25,6 +25,9 @@ const missingTests = new Set([ 'mpc', ]); +const [nodeMajorVersion] = process.versions.node.split('.').map(Number); +const nodeVersionSupportingByeBlobStream = 20; + const types = [...supportedExtensions].filter(ext => !missingTests.has(ext)); // Define an entry here only if the fixture has a different @@ -320,10 +323,10 @@ async function testFalsePositive(t, ext, name) { t.is(await fileTypeFromBuffer(chunk.buffer), undefined); } -async function testFileFromStream(t, ext, name) { +async function testFileNodeFromStream(t, ext, name) { const filename = `${(name ?? 'fixture')}.${ext}`; const file = path.join(__dirname, 'fixture', filename); - const fileType = await fileTypeFromStream(fs.createReadStream(file)); + const fileType = await fileTypeNodeFromStream(fs.createReadStream(file)); t.truthy(fileType, `identify ${filename}`); t.is(fileType.ext, ext, 'fileType.ext'); @@ -362,6 +365,10 @@ async function testStream(t, ext, name) { t.true(areUint8ArraysEqual(bufferA, bufferB)); } +test('Test suite must be able to detect Node.js major version', t => { + t.is(typeof nodeMajorVersion, 'number', 'Detected Node.js major version should be a number'); +}); + let i = 0; for (const type of types) { if (Object.prototype.hasOwnProperty.call(names, type)) { @@ -371,8 +378,12 @@ for (const type of types) { _test(`${name}.${type} ${i++} .fileTypeFromFile() method - same fileType`, testFromFile, type, name); _test(`${name}.${type} ${i++} .fileTypeFromBuffer() method - same fileType`, testFromBuffer, type, name); - _test(`${name}.${type} ${i++} .fileTypeFromBlob() method - same fileType`, testFromBlob, type, name); - _test(`${name}.${type} ${i++} .fileTypeFromStream() method - same fileType`, testFileFromStream, type, name); + if (nodeMajorVersion >= nodeVersionSupportingByeBlobStream) { + // Blob requires to stream to BYOB ReadableStream, requiring Node.js ≥ 20 + _test(`${name}.${type} ${i++} .fileTypeFromBlob() method - same fileType`, testFromBlob, type, name); + } + + _test(`${name}.${type} ${i++} .fileTypeFromStream() Node.js method - same fileType`, testFileNodeFromStream, type, name); test(`${name}.${type} ${i++} .fileTypeStream() - identical streams`, testStream, type, name); } } else { @@ -381,7 +392,7 @@ for (const type of types) { _test(`${type} ${i++} .fileTypeFromFile()`, testFromFile, type); _test(`${type} ${i++} .fileTypeFromBuffer()`, testFromBuffer, type); - _test(`${type} ${i++} .fileTypeFromStream()`, testFileFromStream, type); + _test(`${type} ${i++} .fileTypeFromStream() Node.js`, testFileNodeFromStream, type); test(`${type} ${i++} .fileTypeStream() - identical streams`, testStream, type); } @@ -636,7 +647,7 @@ test('odd file sizes', async t => { for (const size of oddFileSizes) { const buffer = new Uint8Array(size); const stream = new BufferedStream(buffer); - await t.notThrowsAsync(fileTypeFromStream(stream), `fromStream: File size: ${size} bytes`); + await t.notThrowsAsync(fileTypeNodeFromStream(stream), `fromStream: File size: ${size} bytes`); } }); @@ -693,48 +704,52 @@ const tokenizerPositionChanger = tokenizer => { tokenizer.readBuffer(buffer, {length: 1, mayBeLess: true}); }; -test('fileTypeFromBlob should detect custom file type "unicorn" using custom detectors', async t => { - // Set up the "unicorn" file content - const header = 'UNICORN FILE\n'; - const blob = new Blob([header]); +if (nodeMajorVersion >= nodeVersionSupportingByeBlobStream) { + // Blob requires to stream to BYOB ReadableStream, requiring Node.js ≥ 20 - const customDetectors = [unicornDetector]; - const parser = new FileTypeParser({customDetectors}); + test('fileTypeFromBlob should detect custom file type "unicorn" using custom detectors', async t => { + // Set up the "unicorn" file content + const header = 'UNICORN FILE\n'; + const blob = new Blob([header]); - const result = await parser.fromBlob(blob); - t.deepEqual(result, {ext: 'unicorn', mime: 'application/unicorn'}); -}); + const customDetectors = [unicornDetector]; + const parser = new NodeFileTypeParser({customDetectors}); -test('fileTypeFromBlob should keep detecting default file types when no custom detector matches', async t => { - const file = path.join(__dirname, 'fixture', 'fixture.png'); - const chunk = fs.readFileSync(file); - const blob = new Blob([chunk]); + const result = await parser.fromBlob(blob); + t.deepEqual(result, {ext: 'unicorn', mime: 'application/unicorn'}); + }); - const customDetectors = [unicornDetector]; - const parser = new FileTypeParser({customDetectors}); + test('fileTypeFromBlob should keep detecting default file types when no custom detector matches', async t => { + const file = path.join(__dirname, 'fixture', 'fixture.png'); + const chunk = fs.readFileSync(file); + const blob = new Blob([chunk]); - const result = await parser.fromBlob(blob); - t.deepEqual(result, {ext: 'png', mime: 'image/png'}); -}); + const customDetectors = [unicornDetector]; + const parser = new NodeFileTypeParser({customDetectors}); -test('fileTypeFromBlob should allow overriding default file type detectors', async t => { - const file = path.join(__dirname, 'fixture', 'fixture.png'); - const chunk = fs.readFileSync(file); - const blob = new Blob([chunk]); + const result = await parser.fromBlob(blob); + t.deepEqual(result, {ext: 'png', mime: 'image/png'}); + }); - const customDetectors = [mockPngDetector]; - const parser = new FileTypeParser({customDetectors}); + test('fileTypeFromBlob should allow overriding default file type detectors', async t => { + const file = path.join(__dirname, 'fixture', 'fixture.png'); + const chunk = fs.readFileSync(file); + const blob = new Blob([chunk]); - const result = await parser.fromBlob(blob); - t.deepEqual(result, {ext: 'mockPng', mime: 'image/mockPng'}); -}); + const customDetectors = [mockPngDetector]; + const parser = new NodeFileTypeParser({customDetectors}); + + const result = await parser.fromBlob(blob); + t.deepEqual(result, {ext: 'mockPng', mime: 'image/mockPng'}); + }); +} test('fileTypeFromBuffer should detect custom file type "unicorn" using custom detectors', async t => { const header = 'UNICORN FILE\n'; const uint8ArrayContent = new TextEncoder().encode(header); const customDetectors = [unicornDetector]; - const parser = new FileTypeParser({customDetectors}); + const parser = new NodeFileTypeParser({customDetectors}); const result = await parser.fromBuffer(uint8ArrayContent); t.deepEqual(result, {ext: 'unicorn', mime: 'application/unicorn'}); @@ -745,7 +760,7 @@ test('fileTypeFromBuffer should keep detecting default file types when no custom const uint8ArrayContent = fs.readFileSync(file); const customDetectors = [unicornDetector]; - const parser = new FileTypeParser({customDetectors}); + const parser = new NodeFileTypeParser({customDetectors}); const result = await parser.fromBuffer(uint8ArrayContent); t.deepEqual(result, {ext: 'png', mime: 'image/png'}); @@ -756,7 +771,7 @@ test('fileTypeFromBuffer should allow overriding default file type detectors', a const uint8ArrayContent = fs.readFileSync(file); const customDetectors = [mockPngDetector]; - const parser = new FileTypeParser({customDetectors}); + const parser = new NodeFileTypeParser({customDetectors}); const result = await parser.fromBuffer(uint8ArrayContent); t.deepEqual(result, {ext: 'mockPng', mime: 'image/mockPng'}); @@ -771,7 +786,7 @@ test('fileTypeFromStream should detect custom file type "unicorn" using custom d const readableStream = new CustomReadableStream(); const customDetectors = [unicornDetector]; - const parser = new FileTypeParser({customDetectors}); + const parser = new NodeFileTypeParser({customDetectors}); const result = await parser.fromStream(readableStream); t.deepEqual(result, {ext: 'unicorn', mime: 'application/unicorn'}); @@ -782,7 +797,7 @@ test('fileTypeFromStream should keep detecting default file types when no custom const readableStream = fs.createReadStream(file); const customDetectors = [unicornDetector]; - const parser = new FileTypeParser({customDetectors}); + const parser = new NodeFileTypeParser({customDetectors}); const result = await parser.fromStream(readableStream); t.deepEqual(result, {ext: 'png', mime: 'image/png'}); @@ -793,7 +808,7 @@ test('fileTypeFromStream should allow overriding default file type detectors', a const readableStream = fs.createReadStream(file); const customDetectors = [mockPngDetector]; - const parser = new FileTypeParser({customDetectors}); + const parser = new NodeFileTypeParser({customDetectors}); const result = await parser.fromStream(readableStream); t.deepEqual(result, {ext: 'mockPng', mime: 'image/mockPng'}); @@ -832,7 +847,7 @@ test('fileTypeFromTokenizer should return undefined when a custom detector chang // Include the unicormDetector here to verify it's not used after the tokenizer.position changed const customDetectors = [tokenizerPositionChanger, unicornDetector]; - const parser = new FileTypeParser({customDetectors}); + const parser = new NodeFileTypeParser({customDetectors}); const result = await parser.fromTokenizer(strtok3.fromBuffer(uint8ArrayContent)); t.is(result, undefined);