react-router
Version:
Declarative routing for React
180 lines (179 loc) • 6.04 kB
JavaScript
/**
* react-router v8.0.0
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
import "../../lib/router/utils.js";
import { Deferred, createLineSplittingTransform } from "./utils.js";
import { flatten } from "./flatten.js";
import { unflatten } from "./unflatten.js";
//#region vendor/turbo-stream-v2/turbo-stream.ts
async function decode(readable, options) {
const { plugins } = options ?? {};
const done = new Deferred();
const reader = readable.pipeThrough(createLineSplittingTransform()).getReader();
const decoder = {
values: [],
hydrated: [],
deferred: {},
plugins
};
const decoded = await decodeInitial.call(decoder, reader);
let donePromise = done.promise;
if (decoded.done) done.resolve();
else donePromise = decodeDeferred.call(decoder, reader).then(done.resolve).catch((reason) => {
for (const deferred of Object.values(decoder.deferred)) deferred.reject(reason);
done.reject(reason);
});
return {
done: donePromise.then(() => reader.closed),
value: decoded.value
};
}
async function decodeInitial(reader) {
const read = await reader.read();
if (!read.value) throw new SyntaxError();
let line;
try {
line = JSON.parse(read.value);
} catch (reason) {
throw new SyntaxError();
}
return {
done: read.done,
value: unflatten.call(this, line)
};
}
async function decodeDeferred(reader) {
let read = await reader.read();
while (!read.done) {
if (!read.value) continue;
const line = read.value;
switch (line[0]) {
case "P": {
const colonIndex = line.indexOf(":");
const deferredId = Number(line.slice(1, colonIndex));
const deferred = this.deferred[deferredId];
if (!deferred) throw new Error(`Deferred ID ${deferredId} not found in stream`);
const lineData = line.slice(colonIndex + 1);
let jsonLine;
try {
jsonLine = JSON.parse(lineData);
} catch (reason) {
throw new SyntaxError();
}
const value = unflatten.call(this, jsonLine);
deferred.resolve(value);
break;
}
case "E": {
const colonIndex = line.indexOf(":");
const deferredId = Number(line.slice(1, colonIndex));
const deferred = this.deferred[deferredId];
if (!deferred) throw new Error(`Deferred ID ${deferredId} not found in stream`);
const lineData = line.slice(colonIndex + 1);
let jsonLine;
try {
jsonLine = JSON.parse(lineData);
} catch (reason) {
throw new SyntaxError();
}
const value = unflatten.call(this, jsonLine);
deferred.reject(value);
break;
}
default: throw new SyntaxError();
}
read = await reader.read();
}
}
function encode(input, options) {
const { onComplete, plugins, postPlugins, signal } = options ?? {};
const encoder = {
deferred: {},
index: 0,
indices: /* @__PURE__ */ new Map(),
stringified: [],
plugins,
postPlugins,
signal
};
const textEncoder = new TextEncoder();
let lastSentIndex = 0;
return new ReadableStream({ async start(controller) {
const id = await flatten.call(encoder, input);
if (Array.isArray(id)) throw new Error("This should never happen");
if (id < 0) controller.enqueue(textEncoder.encode(`${id}\n`));
else {
controller.enqueue(textEncoder.encode(`[${encoder.stringified.join(",")}]\n`));
lastSentIndex = encoder.stringified.length - 1;
}
const seenPromises = /* @__PURE__ */ new WeakSet();
let processingChain = Promise.resolve();
if (Object.keys(encoder.deferred).length) {
let raceDone;
const racePromise = new Promise((resolve, reject) => {
raceDone = resolve;
if (signal) {
const rejectPromise = () => reject(signal.reason || /* @__PURE__ */ new Error("Signal was aborted."));
if (signal.aborted) rejectPromise();
else signal.addEventListener("abort", (event) => {
rejectPromise();
});
}
});
while (Object.keys(encoder.deferred).length > 0) {
for (const [deferredId, deferred] of Object.entries(encoder.deferred)) {
if (seenPromises.has(deferred)) continue;
seenPromises.add(encoder.deferred[Number(deferredId)] = Promise.race([racePromise, deferred]).then((resolved) => {
processingChain = processingChain.then(async () => {
const id = await flatten.call(encoder, resolved);
if (Array.isArray(id)) {
controller.enqueue(textEncoder.encode(`P${deferredId}:[["Z",${id[0]}]]\n`));
encoder.index++;
lastSentIndex++;
} else if (id < 0) controller.enqueue(textEncoder.encode(`P${deferredId}:${id}\n`));
else {
const values = encoder.stringified.slice(lastSentIndex + 1).join(",");
controller.enqueue(textEncoder.encode(`P${deferredId}:[${values}]\n`));
lastSentIndex = encoder.stringified.length - 1;
}
});
return processingChain;
}, (reason) => {
processingChain = processingChain.then(async () => {
if (!reason || typeof reason !== "object" || !(reason instanceof Error)) reason = /* @__PURE__ */ new Error("An unknown error occurred");
const id = await flatten.call(encoder, reason);
if (Array.isArray(id)) {
controller.enqueue(textEncoder.encode(`E${deferredId}:[["Z",${id[0]}]]\n`));
encoder.index++;
lastSentIndex++;
} else if (id < 0) controller.enqueue(textEncoder.encode(`E${deferredId}:${id}\n`));
else {
const values = encoder.stringified.slice(lastSentIndex + 1).join(",");
controller.enqueue(textEncoder.encode(`E${deferredId}:[${values}]\n`));
lastSentIndex = encoder.stringified.length - 1;
}
});
return processingChain;
}).finally(() => {
delete encoder.deferred[Number(deferredId)];
}));
}
await Promise.race(Object.values(encoder.deferred));
}
raceDone();
}
await Promise.all(Object.values(encoder.deferred));
await processingChain;
controller.close();
onComplete?.();
} });
}
//#endregion
export { decode, encode };