Initial commit: Text encoding component with UTF-8 polyfills

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Chris Daßler
2025-08-29 14:54:44 +02:00
commit 3342f7e40b
10 changed files with 1430 additions and 0 deletions

132
TextEncodingFactory.ts Normal file
View File

@@ -0,0 +1,132 @@
/**
* Text Encoding Factory
*
* Creates encoder/decoder instances with automatic polyfill selection
*
* @module text-encoding@1.0.0
*/
import { TextDecoderPolyfill } from './TextDecoderPolyfill';
import { TextEncoderPolyfill } from './TextEncoderPolyfill';
import type {
ITextDecoder,
ITextEncoder,
ITextEncodingFactory,
TextDecoderOptions,
} from './interfaces';
export class TextEncodingFactory implements ITextEncodingFactory {
private static instance: TextEncodingFactory;
/**
* Get factory singleton instance
*/
static getInstance(): TextEncodingFactory {
if (!TextEncodingFactory.instance) {
TextEncodingFactory.instance = new TextEncodingFactory();
}
return TextEncodingFactory.instance;
}
/**
* Create a new TextEncoder instance
* Uses native implementation if available, otherwise polyfill
*/
createEncoder(): ITextEncoder {
// @ts-expect-error - Check for native TextEncoder
if (typeof TextEncoder !== 'undefined') {
try {
// @ts-expect-error - Try to use native
return new TextEncoder();
} catch (e) {
// Fall back to polyfill if native fails
console.warn('[TextEncodingFactory] Native TextEncoder failed, using polyfill:', e);
}
}
return new TextEncoderPolyfill();
}
/**
* Create a new TextDecoder instance
* Uses native implementation if available, otherwise polyfill
*/
createDecoder(label: string = 'utf-8', options?: TextDecoderOptions): ITextDecoder {
// @ts-expect-error - Check for native TextDecoder
if (typeof TextDecoder !== 'undefined') {
try {
// @ts-expect-error - Try to use native
return new TextDecoder(label, options);
} catch (e) {
// Fall back to polyfill if native fails
console.warn('[TextEncodingFactory] Native TextDecoder failed, using polyfill:', e);
}
}
return new TextDecoderPolyfill(label, options);
}
/**
* Check if native TextEncoder/TextDecoder are available
*/
isNativelySupported(): boolean {
// @ts-expect-error - Check global scope
if (typeof TextEncoder === 'undefined' || typeof TextDecoder === 'undefined') {
return false;
}
// Try to instantiate to make sure they work
try {
// @ts-expect-error
const encoder = new TextEncoder();
// @ts-expect-error
const decoder = new TextDecoder();
// Basic functionality test
const testString = 'test';
const encoded = encoder.encode(testString);
const decoded = decoder.decode(encoded);
return decoded === testString;
} catch (_e) {
return false;
}
}
}
/**
* Convenience function to create an encoder
*/
export function createTextEncoder(): ITextEncoder {
return TextEncodingFactory.getInstance().createEncoder();
}
/**
* Convenience function to create a decoder
*/
export function createTextDecoder(label?: string, options?: TextDecoderOptions): ITextDecoder {
return TextEncodingFactory.getInstance().createDecoder(label, options);
}
/**
* Install polyfills globally if not present
* This makes TextEncoder/TextDecoder available everywhere
*/
export function installTextEncodingPolyfills(): void {
// @ts-expect-error
if (typeof global !== 'undefined') {
// @ts-expect-error
if (typeof global.TextEncoder === 'undefined') {
// @ts-expect-error
global.TextEncoder = TextEncoderPolyfill;
console.info('[TextEncodingFactory] Installed TextEncoder polyfill globally');
}
// @ts-expect-error
if (typeof global.TextDecoder === 'undefined') {
// @ts-expect-error
global.TextDecoder = TextDecoderPolyfill;
console.info('[TextEncodingFactory] Installed TextDecoder polyfill globally');
}
}
}