Add FilePathTarget

This commit is contained in:
Vanilagy
2025-10-02 15:59:46 +02:00
parent 203c0f307e
commit f2f9b2f0c3
3 changed files with 99 additions and 1 deletions
+2
View File
@@ -92,6 +92,8 @@ export {
export {
Target,
BufferTarget,
FilePathTarget,
FilePathTargetOptions,
NullTarget,
StreamTarget,
StreamTargetOptions,
+69
View File
@@ -6,8 +6,15 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import type { FileHandle } from 'node:fs/promises';
import { BufferTargetWriter, NullTargetWriter, StreamTargetWriter, Writer } from './writer';
import { Output } from './output';
import * as nodeAlias from './node';
import { assert } from './misc';
const node = typeof nodeAlias !== 'undefined'
? nodeAlias // Aliasing it prevents some bundler warnings
: undefined!;
/**
* Base class for targets, specifying where output files are written.
@@ -121,6 +128,68 @@ export class StreamTarget extends Target {
}
}
/**
* Options for {@link FilePathTarget}.
* @group Output targets
* @public
*/
export type FilePathTargetOptions = StreamTargetOptions;
/**
* A target that writes to a file at the specified path. Intended for server-side usage in Node, Bun, or Deno.
*
* Writing is chunked by default. The internally held file handle will be closed when `.finalize()` or `.cancel()` are
* called on the corresponding {@link Output}.
* @group Output targets
* @public
*/
export class FilePathTarget extends Target {
/** @internal */
_streamTarget: StreamTarget;
/** @internal */
_fileHandle: FileHandle | null = null;
/** Creates a new {@link FilePathTarget} that writes to the file at the specified file path. */
constructor(filePath: string, options: FilePathTargetOptions = {}) {
if (typeof filePath !== 'string') {
throw new TypeError('filePath must be a string.');
}
if (!options || typeof options !== 'object') {
throw new TypeError('options must be an object.');
}
super();
// Let's back this target with a StreamTarget, makes the implementation very simple
const writable = new WritableStream<StreamTargetChunk>({
start: async () => {
this._fileHandle = await node.fs.open(filePath, 'w');
},
write: async (chunk) => {
assert(this._fileHandle);
await this._fileHandle.write(chunk.data, 0, chunk.data.byteLength, chunk.position);
},
close: async () => {
if (this._fileHandle) {
await this._fileHandle.close();
this._fileHandle = null;
}
},
});
this._streamTarget = new StreamTarget(writable, {
chunked: true,
...options,
});
this._streamTarget._output = this._output;
}
/** @internal */
_createWriter(): Writer {
return this._streamTarget._createWriter();
}
}
/**
* This target just discards all incoming data. It is useful for when you need an {@link Output} but extract data from
* it differently, for example through format-specific callbacks (`onMoof`, `onMdat`, ...) or encoder events.