const shouldSerializeAst = () => // `BigInt` can't be serialized in chrome // `/(?ims:^[a-z])/u` can't be serialized in Node.js v20 (firefox) true; function responseInBrowser(function_, context) { const { accessPath, optionsIndex, browser } = context; function resolve(value) { // Comments in `graphql` can't be serialized, and we are not using it in format test if (accessPath === "formatWithCursor") { value.comments = []; } if (accessPath === "__debug.parse" && shouldSerializeAst(context)) { value.ast = serializeAst(value.ast); } return { status: "fulfilled", value }; } function reject(error) { const response = { status: "rejected", reason: error }; // Firefox can't serialize `Error` if (browser === "firefox") { delete response.reason; } response.serializedError = serializeError(error); return response; } return async function (...arguments_) { // `Infinity` can't be serialized in chrome if (browser === "chrome") { const options = deserializeOptions(arguments_[optionsIndex]); arguments_[optionsIndex] = options; } try { return resolve(await function_(...arguments_)); } catch (error) { return reject(error); } }; } function requestFromNode(function_, context) { const { accessPath, optionsIndex, browser } = context; function resolve({ value }) { if (accessPath === "__debug.parse" && shouldSerializeAst(context)) { value.ast = deserializeAst(value.ast); } return value; } function reject(response) { const error = deserializeError(response.serializedError); throw error; } return async function (...arguments_) { // `Infinity` can't be serialized in chrome if (browser === "chrome") { const options = arguments_[optionsIndex]; arguments_[optionsIndex] = serializeOptions(options); } const response = await function_(...arguments_); if (response.status === "rejected") { return reject(response); } return resolve(response); }; } function deserializeError(serialized) { const error = new Error(serialized.message); Object.assign(error, serialized); if (serialized.cause) { // eslint-disable-next-line unicorn/no-error-property-assignment error.cause = deserializeError(serialized.cause); } return error; } function serializeError(originalError) { const error = { message: originalError.message, ...originalError }; delete error.cause; if (originalError.cause instanceof Error) { error.cause = serializeError(originalError.cause); } return error; } function serializeOptions(options = {}) { return { ...options, printWidth: serializeValue(options?.printWidth), }; } function deserializeOptions(options = {}) { return { ...options, printWidth: deserializeValue(options?.printWidth), }; } function serializeAst(ast) { let shouldSerialize = false; const serialized = JSON.stringify(ast, (_, value) => { const serialized = serializeValue(value); if (serialized !== value) { shouldSerialize ||= true; } return serialized; }); return shouldSerialize ? serialized : ast; } function deserializeAst(ast) { if (typeof ast !== "string") { return ast; } return JSON.parse(ast, (_, value) => deserializeValue(value)); } const INTERNAL_VALUE_KIND = "[[INTERNAL_VALUE_KIND]]"; function deserializeValue(value) { switch (value?.[INTERNAL_VALUE_KIND]) { case "Number.POSITIVE_INFINITY": return Number.POSITIVE_INFINITY; case "bigint": return BigInt(value.bigint); case "regex": try { return new RegExp(value.pattern, value.flags); } catch { return null; } } return value; } function serializeValue(value) { if (value === Number.POSITIVE_INFINITY) { return { [INTERNAL_VALUE_KIND]: "Number.POSITIVE_INFINITY" }; } if (typeof value === "bigint") { return { [INTERNAL_VALUE_KIND]: "bigint", bigint: String(value) }; } if (value instanceof RegExp) { return { [INTERNAL_VALUE_KIND]: "regex", source: value.source, flags: value.flags, }; } return value; } const ensurePromise = (value) => { if (!(value instanceof Promise)) { throw new TypeError("Expected value to be a 'Promise'."); } return value; }; export { ensurePromise, requestFromNode, responseInBrowser };