FormatHandler Interface in Convert: A Complete Guide to Building Custom File Converters
The FormatHandler interface in the p2r3/convert repository defines the contract that every conversion plugin must implement, enabling automatic discovery, prioritization, and chaining of format-specific transformations.
The FormatHandler interface serves as the architectural backbone of the convert project, allowing developers to extend the engine with new file format support without modifying core logic. Located in src/FormatHandler.ts, this TypeScript interface standardizes how handlers declare their supported formats, process incoming files, and integrate into the conversion pipeline.
What Is the FormatHandler Interface?
The FormatHandler interface establishes a strict contract between the convert engine and individual format implementations. By implementing this interface, developers ensure their handlers can be automatically registered, discovered, and executed by the traversal graph system.
Core Properties and Methods
The interface requires specific properties and methods that the engine uses to route files through the conversion pipeline:
format: FileFormat— AFileFormatobject (defined insrc/CommonFormats.ts) containing the MIME type, file extensions, and display title the handler processes.process(input: FileData, opts?: any): Promise<FileData>— The core conversion method that accepts aFileDatablob, performs the transformation, and returns a promise resolving to the converted output.supported?: string[]— Optional array of additional MIME types or extensions the handler can accept beyond its primary format.priority?: number— Optional numeric hint used bysrc/TraversionGraph.tsto resolve conflicts when multiple handlers can process the same input format.
How FormatHandler Powers the Convert Engine
The convert engine uses the FormatHandler interface to decouple format-specific logic from the core conversion pipeline. This architecture enables automatic handler discovery and intelligent pathfinding between formats.
Handler Registration in src/handlers/index.ts
All concrete implementations aggregate in src/handlers/index.ts, where the engine collects available handlers into a single array:
// src/handlers/index.ts
const handlers: FormatHandler[] = [
new vtfHandler(),
new threejsHandler(),
new pandocHandler(),
/* … additional handlers … */
];
This registration pattern allows the engine to iterate over all available handlers without importing each implementation individually.
Discovery via TraversionGraph
During application startup in src/main.ts, the handler array feeds into the TraversionGraph class defined in src/TraversionGraph.ts:
// src/main.ts (excerpt)
const allOptions = handlers.map(h => ({ format: h.format, handler: h }));
const graph = new TraversionGraph();
graph.init(supportedFormatCache, allOptions, strictCategories);
The graph constructs a directed acyclic graph where nodes represent FileFormat objects and edges represent available transformations. The priority property on each FormatHandler helps resolve paths when multiple handlers can perform the same conversion.
Execution Pipeline
When a user initiates a conversion, the engine queries the graph for the shortest path from source to target format. It then iteratively invokes each handler's process method, passing the FileData output from one handler as the input to the next. This chaining continues until the final format emerges.
Implementing a Custom FormatHandler
Creating a new format handler requires implementing the interface and registering the class in the handler index.
Minimal Custom Handler Example
This example demonstrates a handler that converts a hypothetical .ex format to text:
// src/handlers/example.ts
import type { FileData, FileFormat, FormatHandler } from '../FormatHandler.js';
const exampleFormat: FileFormat = {
mime: 'application/example',
ext: ['.ex'],
title: 'Example format',
};
export class ExampleHandler implements FormatHandler {
format = exampleFormat;
async process(input: FileData): Promise<FileData> {
// Conversion logic here
const convertedData = new Uint8Array(/* transformation result */);
return {
name: input.name.replace(/\.ex$/, '.txt'),
mime: 'text/plain',
data: convertedData,
};
}
}
After implementation, export the handler in src/handlers/index.ts to activate it.
Using Handlers Through the Engine
Client code typically interacts with handlers indirectly through the main conversion API:
import { convertFile } from './main.js';
const input: FileData = {
name: 'example.ex',
mime: 'application/example',
data: await file.arrayBuffer(),
};
convertFile(input).then(output => {
// Output contains the final FileData after traversing
// all necessary FormatHandlers in the conversion chain
console.log(`Converted to ${output.mime}`);
});
Summary
- The
FormatHandlerinterface insrc/FormatHandler.tsdefines the mandatory contract for all conversion plugins in the p2r3/convert repository. - Required members include the
formatproperty describing supported types and theprocessmethod performing the actual transformation. - Optional properties like
priorityandsupportedenable fine-tuning of handler selection when multiple paths exist. - The
TraversionGraphclass uses these handlers to build a conversion graph, automatically discovering routes between any supported formats. - New handlers require only implementing the interface and registering in
src/handlers/index.ts, requiring no changes to core engine code.
Frequently Asked Questions
What is the difference between FileFormat and FormatHandler?
FileFormat is a data structure defined in src/CommonFormats.ts that describes static properties of a file type, including MIME type, extensions, and display name. FormatHandler is the interface that defines active behavior for converting to or from that format, including the process method that performs transformations. A single FormatHandler references one FileFormat through its format property.
How does convert decide which FormatHandler to use?
The TraversionGraph class in src/TraversionGraph.ts builds a directed graph of all possible conversions during initialization. When multiple handlers can perform the same conversion, the system consults the optional priority property on each FormatHandler, selecting the handler with the highest priority value. If priorities are equal, the graph uses internal heuristics to determine the optimal path.
Can I chain multiple FormatHandlers together?
Yes, chaining is the primary conversion mechanism in the convert engine. When converting between formats where no direct handler exists, the TraversionGraph calculates the shortest path through intermediate formats. The engine then executes each handler's process method sequentially, passing the FileData output from one handler as the input to the next until reaching the target format.
Where should I register a new FormatHandler implementation?
All handlers must be instantiated and added to the handlers array in src/handlers/index.ts. This central registration file imports each handler class, creates an instance, and exports the aggregated array. The main application imports this array in src/main.ts to initialize the TraversionGraph, making the new handler automatically available for conversion path discovery.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →