FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

131
node_modules/seroval-plugins/web/abort-signal.ts generated vendored Normal file
View File

@@ -0,0 +1,131 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
const PROMISE_TO_ABORT_SIGNAL = (promise: Promise<unknown>) => {
const controller = new AbortController();
const abort = controller.abort.bind(controller);
promise.then(abort, abort);
return controller;
};
function resolveAbortSignalResult(
this: AbortSignal,
resolve: (value: unknown) => void,
): void {
resolve(this.reason);
}
function resolveAbortSignal(
this: AbortSignal,
resolve: (value: unknown) => void,
): void {
this.addEventListener('abort', resolveAbortSignalResult.bind(this, resolve), {
once: true,
});
}
function abortSignalToPromise(signal: AbortSignal): Promise<unknown> {
return new Promise(resolveAbortSignal.bind(signal));
}
const ABORT_CONTROLLER = {};
const AbortControllerFactoryPlugin = /* @__PURE__ */ createPlugin<object, {}>({
tag: 'seroval-plugins/web/AbortControllerFactoryPlugin',
test(value) {
return value === ABORT_CONTROLLER;
},
parse: {
sync() {
return ABORT_CONTROLLER;
},
async async() {
return await Promise.resolve(ABORT_CONTROLLER);
},
stream() {
return ABORT_CONTROLLER;
},
},
serialize() {
return PROMISE_TO_ABORT_SIGNAL.toString();
},
deserialize() {
return PROMISE_TO_ABORT_SIGNAL;
},
});
const AbortSignalPlugin = /* @__PURE__ */ createPlugin<
AbortSignal,
{ reason?: SerovalNode; controller?: SerovalNode; factory?: SerovalNode }
>({
tag: 'seroval-plugins/web/AbortSignal',
extends: [AbortControllerFactoryPlugin],
test(value) {
if (typeof AbortSignal === 'undefined') {
return false;
}
return value instanceof AbortSignal;
},
parse: {
sync(value, ctx) {
if (value.aborted) {
return {
reason: ctx.parse(value.reason),
};
}
return {};
},
async async(value, ctx) {
if (value.aborted) {
return {
reason: await ctx.parse(value.reason),
};
}
const result = await abortSignalToPromise(value);
return {
reason: await ctx.parse(result),
};
},
stream(value, ctx) {
if (value.aborted) {
return {
reason: ctx.parse(value.reason),
};
}
const promise = abortSignalToPromise(value);
return {
factory: ctx.parse(ABORT_CONTROLLER),
controller: ctx.parse(promise),
};
},
},
serialize(node, ctx) {
if (node.reason) {
return 'AbortSignal.abort(' + ctx.serialize(node.reason) + ')';
}
if (node.controller && node.factory) {
return (
'(' +
ctx.serialize(node.factory) +
')(' +
ctx.serialize(node.controller) +
').signal'
);
}
return '(new AbortController).signal';
},
deserialize(node, ctx) {
if (node.reason) {
return AbortSignal.abort(ctx.deserialize(node.reason));
}
if (node.controller) {
return PROMISE_TO_ABORT_SIGNAL(ctx.deserialize(node.controller)).signal;
}
const controller = new AbortController();
return controller.signal;
},
});
export default AbortSignalPlugin;

41
node_modules/seroval-plugins/web/blob.ts generated vendored Normal file
View File

@@ -0,0 +1,41 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
type BlobNode = {
type: SerovalNode;
buffer: SerovalNode;
};
const BlobPlugin = /* @__PURE__ */ createPlugin<Blob, BlobNode>({
tag: 'seroval-plugins/web/Blob',
test(value) {
if (typeof Blob === 'undefined') {
return false;
}
return value instanceof Blob;
},
parse: {
async async(value, ctx) {
return {
type: await ctx.parse(value.type),
buffer: await ctx.parse(await value.arrayBuffer()),
};
},
},
serialize(node, ctx) {
return (
'new Blob([' +
ctx.serialize(node.buffer) +
'],{type:' +
ctx.serialize(node.type) +
'})'
);
},
deserialize(node, ctx) {
return new Blob([ctx.deserialize(node.buffer) as ArrayBuffer], {
type: ctx.deserialize(node.type) as string,
});
},
});
export default BlobPlugin;

66
node_modules/seroval-plugins/web/custom-event.ts generated vendored Normal file
View File

@@ -0,0 +1,66 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
function createCustomEventOptions(current: CustomEvent): CustomEventInit {
return {
detail: current.detail as unknown,
bubbles: current.bubbles,
cancelable: current.cancelable,
composed: current.composed,
};
}
type CustomEventNode = {
type: SerovalNode;
options: SerovalNode;
};
const CustomEventPlugin = /* @__PURE__ */ createPlugin<
CustomEvent,
CustomEventNode
>({
tag: 'seroval-plugins/web/CustomEvent',
test(value) {
if (typeof CustomEvent === 'undefined') {
return false;
}
return value instanceof CustomEvent;
},
parse: {
sync(value, ctx) {
return {
type: ctx.parse(value.type),
options: ctx.parse(createCustomEventOptions(value)),
};
},
async async(value, ctx) {
return {
type: await ctx.parse(value.type),
options: await ctx.parse(createCustomEventOptions(value)),
};
},
stream(value, ctx) {
return {
type: ctx.parse(value.type),
options: ctx.parse(createCustomEventOptions(value)),
};
},
},
serialize(node, ctx) {
return (
'new CustomEvent(' +
ctx.serialize(node.type) +
',' +
ctx.serialize(node.options) +
')'
);
},
deserialize(node, ctx) {
return new CustomEvent(
ctx.deserialize(node.type) as string,
ctx.deserialize(node.options) as CustomEventInit,
);
},
});
export default CustomEventPlugin;

57
node_modules/seroval-plugins/web/dom-exception.ts generated vendored Normal file
View File

@@ -0,0 +1,57 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
type DOMExceptionNode = {
name: SerovalNode;
message: SerovalNode;
};
const DOMExceptionPlugin = /* @__PURE__ */ createPlugin<
DOMException,
DOMExceptionNode
>({
tag: 'seroval-plugins/web/DOMException',
test(value) {
if (typeof DOMException === 'undefined') {
return false;
}
return value instanceof DOMException;
},
parse: {
sync(value, ctx) {
return {
name: ctx.parse(value.name),
message: ctx.parse(value.message),
};
},
async async(value, ctx) {
return {
name: await ctx.parse(value.name),
message: await ctx.parse(value.message),
};
},
stream(value, ctx) {
return {
name: ctx.parse(value.name),
message: ctx.parse(value.message),
};
},
},
serialize(node, ctx) {
return (
'new DOMException(' +
ctx.serialize(node.message) +
',' +
ctx.serialize(node.name) +
')'
);
},
deserialize(node, ctx) {
return new DOMException(
ctx.deserialize(node.message) as string,
ctx.deserialize(node.name) as string,
);
},
});
export default DOMExceptionPlugin;

62
node_modules/seroval-plugins/web/event.ts generated vendored Normal file
View File

@@ -0,0 +1,62 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
function createEventOptions(current: Event): EventInit {
return {
bubbles: current.bubbles,
cancelable: current.cancelable,
composed: current.composed,
};
}
type EventNode = {
type: SerovalNode;
options: SerovalNode;
};
const EventPlugin = /* @__PURE__ */ createPlugin<Event, EventNode>({
tag: 'seroval-plugins/web/Event',
test(value) {
if (typeof Event === 'undefined') {
return false;
}
return value instanceof Event;
},
parse: {
sync(value, ctx) {
return {
type: ctx.parse(value.type),
options: ctx.parse(createEventOptions(value)),
};
},
async async(value, ctx) {
return {
type: await ctx.parse(value.type),
options: await ctx.parse(createEventOptions(value)),
};
},
stream(value, ctx) {
return {
type: ctx.parse(value.type),
options: ctx.parse(createEventOptions(value)),
};
},
},
serialize(node, ctx) {
return (
'new Event(' +
ctx.serialize(node.type) +
',' +
ctx.serialize(node.options) +
')'
);
},
deserialize(node, ctx) {
return new Event(
ctx.deserialize(node.type) as string,
ctx.deserialize(node.options) as EventInit,
);
},
});
export default EventPlugin;

50
node_modules/seroval-plugins/web/file.ts generated vendored Normal file
View File

@@ -0,0 +1,50 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
type FileNode = {
name: SerovalNode;
options: SerovalNode;
buffer: SerovalNode;
};
const FilePlugin = /* @__PURE__ */ createPlugin<File, FileNode>({
tag: 'seroval-plugins/web/File',
test(value) {
if (typeof File === 'undefined') {
return false;
}
return value instanceof File;
},
parse: {
async async(value, ctx) {
return {
name: await ctx.parse(value.name),
options: await ctx.parse({
type: value.type,
lastModified: value.lastModified,
}),
buffer: await ctx.parse(await value.arrayBuffer()),
};
},
},
serialize(node, ctx) {
return (
'new File([' +
ctx.serialize(node.buffer) +
'],' +
ctx.serialize(node.name) +
',' +
ctx.serialize(node.options) +
')'
);
},
deserialize(node, ctx) {
return new File(
[ctx.deserialize(node.buffer) as ArrayBuffer],
ctx.deserialize(node.name) as string,
ctx.deserialize(node.options) as FilePropertyBag,
);
},
});
export default FilePlugin;

105
node_modules/seroval-plugins/web/form-data.ts generated vendored Normal file
View File

@@ -0,0 +1,105 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
import FilePlugin from './file';
type FormDataInit = [key: string, value: FormDataEntryValue][];
function convertFormData(instance: FormData): FormDataInit {
const items: FormDataInit = [];
instance.forEach((value, key) => {
items.push([key, value]);
});
return items;
}
const FORM_DATA_FACTORY = {};
const FORM_DATA_FACTORY_CONSTRUCTOR = (
e: [key: string, value: FormDataEntryValue][],
f = new FormData(),
i = 0,
s = e.length,
t?: [key: string, value: FormDataEntryValue],
) => {
for (; i < s; i++) {
t = e[i];
f.append(t[0], t[1]);
}
return f;
};
const FormDataFactoryPlugin = /* @__PURE__ */ createPlugin<object, {}>({
tag: 'seroval-plugins/web/FormDataFactory',
test(value) {
return value === FORM_DATA_FACTORY;
},
parse: {
sync() {
return FORM_DATA_FACTORY;
},
async async() {
return await Promise.resolve(FORM_DATA_FACTORY);
},
stream() {
return FORM_DATA_FACTORY;
},
},
serialize() {
return FORM_DATA_FACTORY_CONSTRUCTOR.toString();
},
deserialize() {
return FORM_DATA_FACTORY;
},
});
type FormDataNode = {
factory: SerovalNode;
entries: SerovalNode;
};
const FormDataPlugin = /* @__PURE__ */ createPlugin<FormData, FormDataNode>({
tag: 'seroval-plugins/web/FormData',
extends: [FilePlugin, FormDataFactoryPlugin],
test(value) {
if (typeof FormData === 'undefined') {
return false;
}
return value instanceof FormData;
},
parse: {
sync(value, ctx) {
return {
factory: ctx.parse(FORM_DATA_FACTORY),
entries: ctx.parse(convertFormData(value)),
};
},
async async(value, ctx) {
return {
factory: await ctx.parse(FORM_DATA_FACTORY),
entries: await ctx.parse(convertFormData(value)),
};
},
stream(value, ctx) {
return {
factory: ctx.parse(FORM_DATA_FACTORY),
entries: ctx.parse(convertFormData(value)),
};
},
},
serialize(node, ctx) {
return (
'(' +
ctx.serialize(node.factory) +
')(' +
ctx.serialize(node.entries) +
')'
);
},
deserialize(node, ctx) {
return FORM_DATA_FACTORY_CONSTRUCTOR(
ctx.deserialize(node.entries) as FormDataInit,
);
},
});
export default FormDataPlugin;

49
node_modules/seroval-plugins/web/headers.ts generated vendored Normal file
View File

@@ -0,0 +1,49 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
function convertHeaders(instance: Headers): HeadersInit {
const items: HeadersInit = [];
// biome-ignore lint/complexity/noForEach: <explanation>
instance.forEach((value, key) => {
items.push([key, value]);
});
return items;
}
const HeadersPlugin = /* @__PURE__ */ createPlugin<
Headers,
{ value: SerovalNode }
>({
tag: 'seroval-plugins/web/Headers',
test(value) {
if (typeof Headers === 'undefined') {
return false;
}
return value instanceof Headers;
},
parse: {
sync(value, ctx) {
return {
value: ctx.parse(convertHeaders(value)),
};
},
async async(value, ctx) {
return {
value: await ctx.parse(convertHeaders(value)),
};
},
stream(value, ctx) {
return {
value: ctx.parse(convertHeaders(value)),
};
},
},
serialize(node, ctx) {
return 'new Headers(' + ctx.serialize(node.value) + ')';
},
deserialize(node, ctx) {
return new Headers(ctx.deserialize(node.value) as HeadersInit);
},
});
export default HeadersPlugin;

74
node_modules/seroval-plugins/web/image-data.ts generated vendored Normal file
View File

@@ -0,0 +1,74 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
type ImageDataNode = {
data: SerovalNode;
width: SerovalNode;
height: SerovalNode;
options: SerovalNode;
};
const ImageDataPlugin = /* @__PURE__ */ createPlugin<ImageData, ImageDataNode>({
tag: 'seroval-plugins/web/ImageData',
test(value) {
if (typeof ImageData === 'undefined') {
return false;
}
return value instanceof ImageData;
},
parse: {
sync(value, ctx) {
return {
data: ctx.parse(value.data),
width: ctx.parse(value.width),
height: ctx.parse(value.height),
options: ctx.parse({
colorSpace: value.colorSpace,
}),
};
},
async async(value, ctx) {
return {
data: await ctx.parse(value.data),
width: await ctx.parse(value.width),
height: await ctx.parse(value.height),
options: await ctx.parse({
colorSpace: value.colorSpace,
}),
};
},
stream(value, ctx) {
return {
data: ctx.parse(value.data),
width: ctx.parse(value.width),
height: ctx.parse(value.height),
options: ctx.parse({
colorSpace: value.colorSpace,
}),
};
},
},
serialize(node, ctx) {
return (
'new ImageData(' +
ctx.serialize(node.data) +
',' +
ctx.serialize(node.width) +
',' +
ctx.serialize(node.height) +
',' +
ctx.serialize(node.options) +
')'
);
},
deserialize(node, ctx) {
return new ImageData(
ctx.deserialize(node.data) as Uint8ClampedArray<ArrayBuffer>,
ctx.deserialize(node.width) as number,
ctx.deserialize(node.height) as number,
ctx.deserialize(node.options) as ImageDataSettings,
);
},
});
export default ImageDataPlugin;

14
node_modules/seroval-plugins/web/index.ts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
export { default as AbortSignalPlugin } from './abort-signal';
export { default as BlobPlugin } from './blob';
export { default as CustomEventPlugin } from './custom-event';
export { default as DOMExceptionPlugin } from './dom-exception';
export { default as EventPlugin } from './event';
export { default as FilePlugin } from './file';
export { default as FormDataPlugin } from './form-data';
export { default as HeadersPlugin } from './headers';
export { default as ImageDataPlugin } from './image-data';
export { default as ReadableStreamPlugin } from './readable-stream';
export { default as RequestPlugin } from './request';
export { default as ResponsePlugin } from './response';
export { default as URLPlugin } from './url';
export { default as URLSearchParamsPlugin } from './url-search-params';

133
node_modules/seroval-plugins/web/readable-stream.ts generated vendored Normal file
View File

@@ -0,0 +1,133 @@
import type { SerovalNode, Stream } from 'seroval';
import { createPlugin, createStream } from 'seroval';
const READABLE_STREAM_FACTORY = {};
const READABLE_STREAM_FACTORY_CONSTRUCTOR = (stream: Stream<unknown>) =>
new ReadableStream({
start: controller => {
stream.on({
next: value => {
try {
controller.enqueue(value);
} catch (_error) {
// no-op
}
},
throw: value => {
controller.error(value);
},
return: () => {
try {
controller.close();
} catch (_error) {
// no-op
}
},
});
},
});
const ReadableStreamFactoryPlugin = /* @__PURE__ */ createPlugin<object, {}>({
tag: 'seroval-plugins/web/ReadableStreamFactory',
test(value) {
return value === READABLE_STREAM_FACTORY;
},
parse: {
sync() {
return READABLE_STREAM_FACTORY;
},
async async() {
return await Promise.resolve(READABLE_STREAM_FACTORY);
},
stream() {
return READABLE_STREAM_FACTORY;
},
},
serialize() {
return READABLE_STREAM_FACTORY_CONSTRUCTOR.toString();
},
deserialize() {
return READABLE_STREAM_FACTORY;
},
});
function toStream<T>(value: ReadableStream<T>): Stream<T | undefined> {
const stream = createStream<T | undefined>();
const reader = value.getReader();
async function push(): Promise<void> {
try {
const result = await reader.read();
if (result.done) {
stream.return(result.value);
} else {
stream.next(result.value);
await push();
}
} catch (error) {
stream.throw(error);
}
}
push().catch(() => {
//
});
return stream;
}
type ReadableStreamNode = {
factory: SerovalNode;
stream: SerovalNode;
};
const ReadableStreamPlugin = /* @__PURE__ */ createPlugin<
ReadableStream,
ReadableStreamNode
>({
tag: 'seroval/plugins/web/ReadableStream',
extends: [ReadableStreamFactoryPlugin],
test(value) {
if (typeof ReadableStream === 'undefined') {
return false;
}
return value instanceof ReadableStream;
},
parse: {
sync(_value, ctx) {
return {
factory: ctx.parse(READABLE_STREAM_FACTORY),
stream: ctx.parse(createStream()),
};
},
async async(value, ctx) {
return {
factory: await ctx.parse(READABLE_STREAM_FACTORY),
stream: await ctx.parse(toStream(value)),
};
},
stream(value, ctx) {
return {
factory: ctx.parse(READABLE_STREAM_FACTORY),
stream: ctx.parse(toStream(value)),
};
},
},
serialize(node, ctx) {
return (
'(' +
ctx.serialize(node.factory) +
')(' +
ctx.serialize(node.stream) +
')'
);
},
deserialize(node, ctx) {
const stream = ctx.deserialize(node.stream) as Stream<any>;
return READABLE_STREAM_FACTORY_CONSTRUCTOR(stream);
},
});
export default ReadableStreamPlugin;

82
node_modules/seroval-plugins/web/request.ts generated vendored Normal file
View File

@@ -0,0 +1,82 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
import HeadersPlugin from './headers';
import ReadableStreamPlugin from './readable-stream';
function createRequestOptions(
current: Request,
body: ArrayBuffer | ReadableStream | null,
): RequestInit {
return {
body,
cache: current.cache,
credentials: current.credentials,
headers: current.headers,
integrity: current.integrity,
keepalive: current.keepalive,
method: current.method,
mode: current.mode,
redirect: current.redirect,
referrer: current.referrer,
referrerPolicy: current.referrerPolicy,
};
}
type RequestNode = {
url: SerovalNode;
options: SerovalNode;
};
const RequestPlugin = /* @__PURE__ */ createPlugin<Request, RequestNode>({
tag: 'seroval-plugins/web/Request',
extends: [ReadableStreamPlugin, HeadersPlugin],
test(value) {
if (typeof Request === 'undefined') {
return false;
}
return value instanceof Request;
},
parse: {
async async(value, ctx) {
return {
url: await ctx.parse(value.url),
options: await ctx.parse(
createRequestOptions(
value,
value.body && !value.bodyUsed
? await value.clone().arrayBuffer()
: null,
),
),
};
},
stream(value, ctx) {
return {
url: ctx.parse(value.url),
options: ctx.parse(
createRequestOptions(
value,
value.body && !value.bodyUsed ? value.clone().body : null,
),
),
};
},
},
serialize(node, ctx) {
return (
'new Request(' +
ctx.serialize(node.url) +
',' +
ctx.serialize(node.options) +
')'
);
},
deserialize(node, ctx) {
return new Request(
ctx.deserialize(node.url) as string,
ctx.deserialize(node.options) as RequestInit,
);
},
});
export default RequestPlugin;

65
node_modules/seroval-plugins/web/response.ts generated vendored Normal file
View File

@@ -0,0 +1,65 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
import HeadersPlugin from './headers';
import ReadableStreamPlugin from './readable-stream';
function createResponseOptions(current: Response): ResponseInit {
return {
headers: current.headers,
status: current.status,
statusText: current.statusText,
};
}
type ResponseNode = {
body: SerovalNode;
options: SerovalNode;
};
const ResponsePlugin = /* @__PURE__ */ createPlugin<Response, ResponseNode>({
tag: 'seroval-plugins/web/Response',
extends: [ReadableStreamPlugin, HeadersPlugin],
test(value) {
if (typeof Response === 'undefined') {
return false;
}
return value instanceof Response;
},
parse: {
async async(value, ctx) {
return {
body: await ctx.parse(
value.body && !value.bodyUsed
? await value.clone().arrayBuffer()
: null,
),
options: await ctx.parse(createResponseOptions(value)),
};
},
stream(value, ctx) {
return {
body: ctx.parse(
value.body && !value.bodyUsed ? value.clone().body : null,
),
options: ctx.parse(createResponseOptions(value)),
};
},
},
serialize(node, ctx) {
return (
'new Response(' +
ctx.serialize(node.body) +
',' +
ctx.serialize(node.options) +
')'
);
},
deserialize(node, ctx) {
return new Response(
ctx.deserialize(node.body) as BodyInit,
ctx.deserialize(node.options) as ResponseInit,
);
},
});
export default ResponsePlugin;

40
node_modules/seroval-plugins/web/url-search-params.ts generated vendored Normal file
View File

@@ -0,0 +1,40 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
const URLSearchParamsPlugin = /* @__PURE__ */ createPlugin<
URLSearchParams,
{ value: SerovalNode }
>({
tag: 'seroval-plugins/web/URLSearchParams',
test(value) {
if (typeof URLSearchParams === 'undefined') {
return false;
}
return value instanceof URLSearchParams;
},
parse: {
sync(value, ctx) {
return {
value: ctx.parse(value.toString()),
};
},
async async(value, ctx) {
return {
value: await ctx.parse(value.toString()),
};
},
stream(value, ctx) {
return {
value: ctx.parse(value.toString()),
};
},
},
serialize(node, ctx) {
return 'new URLSearchParams(' + ctx.serialize(node.value) + ')';
},
deserialize(node, ctx) {
return new URLSearchParams(ctx.deserialize(node.value) as string);
},
});
export default URLSearchParamsPlugin;

37
node_modules/seroval-plugins/web/url.ts generated vendored Normal file
View File

@@ -0,0 +1,37 @@
import type { SerovalNode } from 'seroval';
import { createPlugin } from 'seroval';
const URLPlugin = /* @__PURE__ */ createPlugin<URL, { value: SerovalNode }>({
tag: 'seroval-plugins/web/URL',
test(value) {
if (typeof URL === 'undefined') {
return false;
}
return value instanceof URL;
},
parse: {
sync(value, ctx) {
return {
value: ctx.parse(value.href),
};
},
async async(value, ctx) {
return {
value: await ctx.parse(value.href),
};
},
stream(value, ctx) {
return {
value: ctx.parse(value.href),
};
},
},
serialize(node, ctx) {
return 'new URL(' + ctx.serialize(node.value) + ')';
},
deserialize(node, ctx) {
return new URL(ctx.deserialize(node.value) as string);
},
});
export default URLPlugin;