(function () {
const { core, primordials } = __bootstrap;
const { op_encode_binary_string } = core.ops;
const {
ArrayPrototypePush,
ArrayPrototypeReduce,
FunctionPrototypeCall,
MapPrototypeGet,
MapPrototypeSet,
ObjectDefineProperty,
ObjectPrototypeIsPrototypeOf,
queueMicrotask,
SafeArrayIterator,
SafeMap,
Symbol,
SymbolFor,
TypedArrayPrototypeSet,
TypedArrayPrototypeGetBuffer,
TypedArrayPrototypeGetByteLength,
TypedArrayPrototypeGetSymbolToStringTag,
TypeError,
Uint8Array,
} = primordials;
const webidl = core.loadExtScript("ext:deno_webidl/00_webidl.js");
const { createFilteredInspectProxy } = core.loadExtScript(
"ext:deno_web/01_console.js",
);
const { forgivingBase64Encode } = core.loadExtScript(
"ext:deno_web/00_infra.js",
);
const { EventTarget, ProgressEvent } = core.loadExtScript(
"ext:deno_web/02_event.js",
);
const { decode, TextDecoder } = core.loadExtScript(
"ext:deno_web/08_text_encoding.js",
);
const { parseMimeType } = core.loadExtScript("ext:deno_web/01_mimesniff.js");
const { DOMException } = core.loadExtScript("ext:deno_web/01_dom_exception.js");
const state = Symbol("[[state]]");
const result = Symbol("[[result]]");
const error = Symbol("[[error]]");
const aborted = Symbol("[[aborted]]");
const handlerSymbol = Symbol("eventHandlers");
class FileReader extends EventTarget {
[state] = "empty";
[result] = null;
[error] = null;
[aborted] = null;
#readOperation(blob, readtype) {
if (this[state] === "loading") {
throw new DOMException(
"Invalid FileReader state",
"InvalidStateError",
);
}
this[state] = "loading";
this[result] = null;
this[error] = null;
const abortedState = this[aborted] = { aborted: false };
const stream = blob.stream();
const reader = stream.getReader();
const chunks = [];
let chunkPromise = reader.read();
let isFirstChunk = true;
(async () => {
while (!abortedState.aborted) {
try {
const chunk = await chunkPromise;
if (abortedState.aborted) return;
if (isFirstChunk) {
queueMicrotask(() => {
if (abortedState.aborted) return;
const ev = new ProgressEvent("loadstart", {});
this.dispatchEvent(ev);
});
}
isFirstChunk = false;
if (
!chunk.done &&
TypedArrayPrototypeGetSymbolToStringTag(chunk.value) ===
"Uint8Array"
) {
ArrayPrototypePush(chunks, chunk.value);
{
const size = ArrayPrototypeReduce(
chunks,
(p, i) => p + TypedArrayPrototypeGetByteLength(i),
0,
);
const ev = new ProgressEvent("progress", {
loaded: size,
});
queueMicrotask(() => {
if (abortedState.aborted) return;
this.dispatchEvent(ev);
});
}
chunkPromise = reader.read();
} else if (chunk.done === true) {
queueMicrotask(() => {
if (abortedState.aborted) return;
this[state] = "done";
const size = ArrayPrototypeReduce(
chunks,
(p, i) => p + TypedArrayPrototypeGetByteLength(i),
0,
);
const bytes = new Uint8Array(size);
let offs = 0;
for (let i = 0; i < chunks.length; ++i) {
const chunk = chunks[i];
TypedArrayPrototypeSet(bytes, chunk, offs);
offs += TypedArrayPrototypeGetByteLength(chunk);
}
switch (readtype.kind) {
case "ArrayBuffer": {
this[result] = TypedArrayPrototypeGetBuffer(bytes);
break;
}
case "BinaryString":
this[result] = op_encode_binary_string(bytes);
break;
case "Text": {
let decoder = undefined;
if (readtype.encoding) {
try {
decoder = new TextDecoder(readtype.encoding);
} catch {
}
}
if (decoder === undefined) {
const mimeType = parseMimeType(blob.type);
if (mimeType) {
const charset = MapPrototypeGet(
mimeType.parameters,
"charset",
);
if (charset) {
try {
decoder = new TextDecoder(charset);
} catch {
}
}
}
}
if (decoder === undefined) {
decoder = new TextDecoder();
}
this[result] = decode(bytes, decoder.encoding);
break;
}
case "DataUrl": {
const mediaType = blob.type || "application/octet-stream";
this[result] = `data:${mediaType};base64,${
forgivingBase64Encode(bytes)
}`;
break;
}
}
{
const ev = new ProgressEvent("load", {
lengthComputable: true,
loaded: size,
total: size,
});
this.dispatchEvent(ev);
}
if (this[state] !== "loading") {
const ev = new ProgressEvent("loadend", {
lengthComputable: true,
loaded: size,
total: size,
});
this.dispatchEvent(ev);
}
});
break;
}
} catch (err) {
queueMicrotask(() => {
if (abortedState.aborted) return;
this[state] = "done";
this[error] = err;
{
const ev = new ProgressEvent("error", {});
this.dispatchEvent(ev);
}
if (this[state] !== "loading") {
const ev = new ProgressEvent("loadend", {});
this.dispatchEvent(ev);
}
});
break;
}
}
})();
}
#getEventHandlerFor(name) {
webidl.assertBranded(this, FileReaderPrototype);
const maybeMap = this[handlerSymbol];
if (!maybeMap) return null;
return MapPrototypeGet(maybeMap, name)?.handler ?? null;
}
#setEventHandlerFor(name, value) {
webidl.assertBranded(this, FileReaderPrototype);
if (!this[handlerSymbol]) {
this[handlerSymbol] = new SafeMap();
}
let handlerWrapper = MapPrototypeGet(this[handlerSymbol], name);
if (handlerWrapper) {
handlerWrapper.handler = value;
} else {
handlerWrapper = makeWrappedHandler(value);
this.addEventListener(name, handlerWrapper);
}
MapPrototypeSet(this[handlerSymbol], name, handlerWrapper);
}
constructor() {
super();
this[webidl.brand] = webidl.brand;
}
get readyState() {
webidl.assertBranded(this, FileReaderPrototype);
switch (this[state]) {
case "empty":
return FileReader.EMPTY;
case "loading":
return FileReader.LOADING;
case "done":
return FileReader.DONE;
default:
throw new TypeError("Invalid state");
}
}
get result() {
webidl.assertBranded(this, FileReaderPrototype);
return this[result];
}
get error() {
webidl.assertBranded(this, FileReaderPrototype);
return this[error];
}
abort() {
webidl.assertBranded(this, FileReaderPrototype);
if (
this[state] === "empty" ||
this[state] === "done"
) {
this[result] = null;
return;
}
if (this[state] === "loading") {
this[state] = "done";
this[result] = null;
}
if (this[aborted] !== null) {
this[aborted].aborted = true;
}
const ev = new ProgressEvent("abort", {});
this.dispatchEvent(ev);
if (this[state] !== "loading") {
const ev = new ProgressEvent("loadend", {});
this.dispatchEvent(ev);
}
}
readAsArrayBuffer(blob) {
webidl.assertBranded(this, FileReaderPrototype);
const prefix = "Failed to execute 'readAsArrayBuffer' on 'FileReader'";
webidl.requiredArguments(arguments.length, 1, prefix);
this.#readOperation(blob, { kind: "ArrayBuffer" });
}
readAsBinaryString(blob) {
webidl.assertBranded(this, FileReaderPrototype);
const prefix = "Failed to execute 'readAsBinaryString' on 'FileReader'";
webidl.requiredArguments(arguments.length, 1, prefix);
this.#readOperation(blob, { kind: "BinaryString" });
}
readAsDataURL(blob) {
webidl.assertBranded(this, FileReaderPrototype);
const prefix = "Failed to execute 'readAsDataURL' on 'FileReader'";
webidl.requiredArguments(arguments.length, 1, prefix);
this.#readOperation(blob, { kind: "DataUrl" });
}
readAsText(blob, encoding = undefined) {
webidl.assertBranded(this, FileReaderPrototype);
const prefix = "Failed to execute 'readAsText' on 'FileReader'";
webidl.requiredArguments(arguments.length, 1, prefix);
if (encoding !== undefined) {
encoding = webidl.converters["DOMString"](encoding, prefix, "Argument 2");
}
this.#readOperation(blob, { kind: "Text", encoding });
}
get onerror() {
return this.#getEventHandlerFor("error");
}
set onerror(value) {
this.#setEventHandlerFor("error", value);
}
get onloadstart() {
return this.#getEventHandlerFor("loadstart");
}
set onloadstart(value) {
this.#setEventHandlerFor("loadstart", value);
}
get onload() {
return this.#getEventHandlerFor("load");
}
set onload(value) {
this.#setEventHandlerFor("load", value);
}
get onloadend() {
return this.#getEventHandlerFor("loadend");
}
set onloadend(value) {
this.#setEventHandlerFor("loadend", value);
}
get onprogress() {
return this.#getEventHandlerFor("progress");
}
set onprogress(value) {
this.#setEventHandlerFor("progress", value);
}
get onabort() {
return this.#getEventHandlerFor("abort");
}
set onabort(value) {
this.#setEventHandlerFor("abort", value);
}
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
return inspect(
createFilteredInspectProxy({
object: this,
evaluate: ObjectPrototypeIsPrototypeOf(FileReaderPrototype, this),
keys: [
"error",
"readyState",
"result",
],
}),
inspectOptions,
);
}
}
webidl.configureInterface(FileReader);
const FileReaderPrototype = FileReader.prototype;
ObjectDefineProperty(FileReader, "EMPTY", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 0,
});
ObjectDefineProperty(FileReader, "LOADING", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 1,
});
ObjectDefineProperty(FileReader, "DONE", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 2,
});
ObjectDefineProperty(FileReader.prototype, "EMPTY", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 0,
});
ObjectDefineProperty(FileReader.prototype, "LOADING", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 1,
});
ObjectDefineProperty(FileReader.prototype, "DONE", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 2,
});
function makeWrappedHandler(handler) {
function wrappedHandler(...args) {
if (typeof wrappedHandler.handler !== "function") {
return;
}
return FunctionPrototypeCall(
wrappedHandler.handler,
this,
...new SafeArrayIterator(args),
);
}
wrappedHandler.handler = handler;
return wrappedHandler;
}
return { FileReader };
})();