UNPKG

@lyleunderwood/filereader-polyfill

Version:

W3C File API specification compliant FileReader polyfill for Node.js environments

322 lines (236 loc) 9.4 kB
# FileReader Polyfill A comprehensive FileReader API polyfill for Node.js environments that provides **100% W3C File API specification compliance** with full compatibility with the Web FileReader API, including support for both File and Blob objects. ## Features -**W3C File API Specification Compliant** - Passes comprehensive spec compliance tests - ✅ Complete FileReader API implementation - ✅ Support for all read methods: `readAsText`, `readAsDataURL`, `readAsArrayBuffer`, `readAsBinaryString` - ✅ Full event support: `loadstart`, `progress`, `load`, `error`, `abort`, `loadend` - ✅ Proper error handling with DOMException types (`InvalidStateError`, `NotReadableError`, `AbortError`) - ✅ Works with both File and Blob objects - ✅ Stream-based reading with progress events - ✅ Proper abort functionality - ✅ File path support for Node.js environments - ✅ TypeScript support with full type definitions - ✅ Event-driven architecture with EventTarget inheritance ## Requirements - Node.js 16.7.0 or higher (required for native `Blob` and `EventTarget` support) ## Installation ```bash npm install @lyleunderwood/filereader-polyfill ``` ## Usage ### Basic Usage ```javascript import { FileReader, File } from '@lyleunderwood/filereader-polyfill'; // Reading from a Blob const blob = new Blob(['Hello, World!'], { type: 'text/plain' }); const reader = new FileReader(); reader.onload = (event) => { console.log('Result:', reader.result); }; reader.readAsText(blob); ``` ### Reading from File Paths (Node.js specific) ```javascript import { FileReader, File } from '@lyleunderwood/filereader-polyfill'; // Create File from file path const file = new File('/path/to/your/file.txt'); const reader = new FileReader(); reader.onload = () => { console.log('File content:', reader.result); }; reader.readAsText(file); ``` ### Global Polyfill The polyfill automatically installs itself globally if `FileReader` or `File` don't exist: ```javascript import '@lyleunderwood/filereader-polyfill'; // Now you can use FileReader and File globally const reader = new FileReader(); const file = new File(['data'], 'example.txt'); ``` ### Event Handling ```javascript const reader = new FileReader(); reader.onloadstart = () => console.log('Started reading'); reader.onprogress = (event) => { if (event.lengthComputable) { const progress = (event.loaded / event.total) * 100; console.log(`Progress: ${progress}%`); } }; reader.onload = () => console.log('Reading completed'); reader.onerror = () => console.error('Error occurred:', reader.error); reader.onabort = () => console.log('Reading aborted'); reader.onloadend = () => console.log('Reading finished'); // You can also use addEventListener reader.addEventListener('load', (event) => { console.log('Load event:', event); }); ``` ### Reading Different Formats ```javascript const reader = new FileReader(); const blob = new Blob(['Hello, World!']); // Read as text reader.readAsText(blob); // Read as ArrayBuffer reader.readAsArrayBuffer(blob); // Read as Data URL reader.readAsDataURL(blob); // Read as binary string reader.readAsBinaryString(blob); ``` ### Abort Reading ```javascript const reader = new FileReader(); const blob = new Blob(['Large file content...']); reader.readAsText(blob); // Abort the reading operation setTimeout(() => { reader.abort(); }, 100); ``` ### Error Handling The polyfill provides W3C-compliant error handling with proper DOMException types: ```javascript const reader = new FileReader(); // Handle different error scenarios reader.onerror = (event) => { console.log('Error name:', reader.error.name); console.log('Error message:', reader.error.message); }; reader.onabort = (event) => { console.log('Operation was aborted'); // reader.error will be AbortError }; // Reading from non-existent file (Node.js path constructor) try { const file = new File('/path/to/nonexistent/file.txt'); reader.readAsText(file); // Will trigger error event with NotReadableError } catch (error) { // File constructor errors are deferred to read operations } // Attempting to read while already reading try { reader.readAsText(blob); reader.readAsText(blob); // Throws InvalidStateError } catch (error) { console.log(error.name); // "InvalidStateError" } ``` ## API Reference ### FileReader Class Extends `EventTarget` and implements the complete Web FileReader API. #### Properties - `readyState`: Current state (`EMPTY`, `LOADING`, `DONE`) - `result`: The file's contents (available after successful read) - `error`: Error information if reading failed #### Methods - `readAsText(blob, encoding?)`: Read as text with optional encoding - `readAsDataURL(blob)`: Read as Data URL - `readAsArrayBuffer(blob)`: Read as ArrayBuffer - `readAsBinaryString(blob)`: Read as binary string - `abort()`: Abort the current reading operation #### Events - `loadstart`: Reading started - `progress`: Reading progress (includes `loaded` and `total` properties) - `load`: Reading completed successfully - `error`: Error occurred during reading - `abort`: Reading was aborted - `loadend`: Reading finished (success, error, or abort) ### File Class Extends native `Blob` and supports both Web API and Node.js file path constructors. #### Constructors ```javascript // Web API style new File(fileBits, fileName, options) // Node.js file path style new File(filePath) ``` #### Properties - `name`: File name - `lastModified`: Last modification timestamp - `size`: File size in bytes - `type`: MIME type - `path`: File path (Node.js specific, when created from path) ## TypeScript Support Full W3C specification-compliant TypeScript definitions are included: ```typescript import { FileReader, File, type IFileReader, type IFile, type NodeFile, type EventHandler, type ProgressEvent, type FileReaderState, type BlobPart, type FilePropertyBag } from '@lyleunderwood/filereader-polyfill'; // W3C compliant usage const reader: FileReader = new FileReader(); const file: File = new File(['content'], 'example.txt'); // Type-safe event handlers reader.onload = (event: Event) => { console.log(reader.result); }; reader.onprogress = (event: Event) => { const progressEvent = event as ProgressEvent; if (progressEvent.lengthComputable) { const progress = progressEvent.loaded / progressEvent.total; console.log(`Progress: ${Math.round(progress * 100)}%`); } }; // File constructor with proper types const fileFromBits: File = new File( ['Hello, World!'] as BlobPart[], 'hello.txt', { type: 'text/plain', lastModified: Date.now() } as FilePropertyBag ); // Node.js specific file path constructor const fileFromPath: NodeFile = new File('/path/to/file.txt'); console.log(fileFromPath.path); // string | undefined ``` ### Available Types - **`IFileReader`**: W3C specification compliant FileReader interface - **`IFile`**: W3C specification compliant File interface - **`NodeFile`**: Extended File interface with Node.js specific `path` property - **`EventHandler`**: W3C compliant event handler function type - **`ProgressEvent`**: Progress event interface with `lengthComputable`, `loaded`, and `total` - **`FileReaderState`**: Enum for FileReader states (EMPTY, LOADING, DONE) - **`BlobPart`**: Union type for valid Blob constructor parts - **`FilePropertyBag`**: Options interface for File constructor ## W3C Specification Compliance This polyfill implements the [W3C File API specification](https://www.w3.org/TR/FileAPI/) with 100% compliance for Node.js environments. It includes comprehensive test coverage that verifies: - ✅ All FileReader interface requirements (constants, attributes, methods, events) - ✅ All File interface requirements (constructor, properties, Blob inheritance) - ✅ Proper error handling with correct DOMException types - ✅ Event firing order and timing per specification - ✅ State management and concurrent operation prevention - ✅ Progress events with proper `lengthComputable`, `loaded`, and `total` properties ### Known Limitations Due to the Node.js environment, some aspects cannot be implemented with 100% browser fidelity: - **File system access**: Cannot detect file changes after File creation (deferred to read operations) - **Event objects**: Uses generic Event instead of native ProgressEvent (properties are preserved) - **Microtask timing**: Event firing may differ slightly from browser microtask scheduling - **Memory management**: Cannot replicate exact browser garbage collection behavior - **Security restrictions**: Cannot enforce same-origin policies or file access permissions These limitations do not affect functional compatibility with the W3C specification. ## Browser Compatibility This polyfill is designed for Node.js environments. For browser usage, use the native FileReader API which is widely supported. ## Testing Run the comprehensive test suite including W3C specification compliance tests: ```bash npm test ``` The test suite includes: - Unit tests for all functionality - W3C File API specification compliance tests - Error handling and edge case coverage - Integration tests between File and FileReader ## Contributing Contributions are welcome! Please ensure all tests pass and maintain W3C specification compliance when making changes. ## License MIT License - see LICENSE file for details.