[playground] remove multi-file support and preview (#767)

This commit is contained in:
Jan Kassens
2022-11-11 12:11:08 -05:00
parent 3b3107fb3e
commit b9ffb59478
15 changed files with 47 additions and 1761 deletions
@@ -8,9 +8,7 @@ import invariant from "invariant";
import type { editor } from "monaco-editor";
import { useEffect, useState } from "react";
import { renderForgetMarkers } from "../../lib/forgetMonacoDiagnostics";
import { createInputFile, getSelectedFile } from "../../lib/stores";
import { useStore, useStoreDispatch } from "../StoreContext";
import InputTabSelector from "./InputTabSelector";
import { monacoOptions } from "./monacoOptions";
// TODO: Make TS recognize .d.ts files, in addition to loading them with webpack.
// @ts-ignore
@@ -20,37 +18,25 @@ export default function Input({ diagnostics }: { diagnostics: Diagnostic[] }) {
const [monaco, setMonaco] = useState<Monaco | null>(null);
const store = useStore();
const dispatchStore = useStoreDispatch();
const selectedFile = getSelectedFile(store);
useEffect(() => {
if (!monaco) return;
const uri = monaco.Uri.parse(`file:///${selectedFile.id}`);
const uri = monaco.Uri.parse(`file:///index.js`);
const model = monaco.editor.getModel(uri);
invariant(model, "Model must exist for the selected input file.");
renderForgetMarkers({ monaco, model, diagnostics });
}, [diagnostics, monaco, selectedFile.id]);
}, [diagnostics, monaco]);
// Set tab width to 2 spaces for the selected input file.
useEffect(() => {
if (!monaco) return;
const uri = monaco.Uri.parse(`file:///${selectedFile.id}`);
const uri = monaco.Uri.parse(`file:///index.js`);
const model = monaco.editor.getModel(uri);
invariant(model, "Model must exist for the selected input file.");
// N.B. that `tabSize` is a model property, not an editor property.
// So, the tab size has to be set per model.
model.updateOptions({ tabSize: 2 });
}, [monaco, selectedFile.id]);
useEffect(() => {
if (!monaco) return;
// Let Monaco Editor know of the input files so that its language
// service can correctly resolve import statements.
store.files.forEach((file) => {
const lib = [file.content, `file:///${file.id}`] as const;
monaco.languages.typescript.javascriptDefaults.addExtraLib(...lib);
monaco.languages.typescript.typescriptDefaults.addExtraLib(...lib);
});
}, [monaco, store.files]);
}, [monaco]);
const handleChange = (value: string | undefined) => {
if (!value) return;
@@ -58,7 +44,7 @@ export default function Input({ diagnostics }: { diagnostics: Diagnostic[] }) {
dispatchStore({
type: "updateFile",
payload: {
file: createInputFile(store.selectedFileId, value),
source: value,
},
});
};
@@ -113,21 +99,16 @@ export default function Input({ diagnostics }: { diagnostics: Diagnostic[] }) {
return (
<div className="relative flex flex-col flex-none border-r border-gray-200">
<InputTabSelector />
{/* Restrict MonacoEditor's height, since the config autoLayout:true
will grow the editor to fit within parent element */}
<div className="w-full h-monaco_small sm:h-monaco">
<MonacoEditor
path={selectedFile.id}
path={"index.js"}
// .js and .jsx files are specified to be TS so that Monaco can actually
// check their syntax using its TS language service. They are still JS files
// due to their extensions, so TS language features don't work.
language={
selectedFile.language === "javascript"
? "typescript"
: selectedFile.language
}
value={selectedFile.content}
language={"javascript"}
value={store.source}
onMount={handleMount}
onChange={handleChange}
options={monacoOptions}
@@ -1,108 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import XIcon from "@heroicons/react/solid/XIcon";
import clsx from "clsx";
import type { RefObject } from "react";
import { memo, useEffect, useRef, useState } from "react";
const MemoizedInputTab = memo(InputTab);
export default MemoizedInputTab;
function InputTab({
tabId,
autoFocus,
allowEdit,
isDeletable,
borderColor,
cursorStyle,
onMountEffect,
onSubmit,
onDelete,
onSwitchTab,
}: {
tabId: string;
autoFocus: boolean;
allowEdit: boolean;
isDeletable: boolean;
borderColor: string;
cursorStyle: string;
onMountEffect: (tabId: string, tabRef: RefObject<HTMLDivElement>) => void;
onSubmit: (oldTabId: string, newTabId: string) => void;
onDelete: (tabId: string) => void;
onSwitchTab: (tabId: string) => void;
}) {
const [newTabId, setNewTabId] = useState(tabId);
const tabIdWidth = `${newTabId.length}ch`;
const [isEditing, setIsEditing] = useState(autoFocus);
const tabRef = useRef<HTMLDivElement>(null);
useEffect(() => {
onMountEffect(tabId, tabRef);
}, [tabId, onMountEffect]);
return (
<div
ref={tabRef}
className={clsx(
"border-b-2 border-white px-2.5 py-0.5 h-full flex flex-1 items-center cursor-pointer",
borderColor
)}
onClick={() => {
onSwitchTab(tabId);
}}
>
{isEditing ? (
<form
spellCheck={false}
onSubmit={(e) => {
e.preventDefault();
onSubmit(tabId, newTabId);
}}
>
<input
type="text"
autoFocus
value={newTabId}
style={{ width: tabIdWidth }}
className={clsx("text-center bg-white outline-none", {
"text-gray-500": isEditing,
})}
onChange={(e) => setNewTabId(e.target.value)}
onBlur={(e) => {
// Stop if clicking on delete button.
if (e.relatedTarget && e.relatedTarget.id === "delete-button")
return;
setIsEditing(false);
onSubmit(tabId, newTabId);
}}
/>
</form>
) : (
<div
style={{ width: tabIdWidth }}
className={clsx("text-center", cursorStyle)}
onClick={() => {
if (allowEdit) setIsEditing(true);
}}
>
{tabId}
</div>
)}
{isDeletable ? (
<button
id="delete-button"
className="relative top-[1px] z-10"
onClick={(e) => {
e.stopPropagation();
onDelete(tabId);
}}
>
<XIcon className="w-[18px] h-[18px] transition-colors duration-150 ease-in hover:fill-gray-800 fill-gray-500" />
</button>
) : null}
</div>
);
}
@@ -1,203 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import { PlusIcon } from "@heroicons/react/solid";
import invariant from "invariant";
import { useSnackbar } from "notistack";
import { useState, type RefObject } from "react";
import {
checkInputFile,
createInputFile,
createMessage,
MessageLevel,
MessageSource,
type Store,
} from "../../lib/stores";
import { useStore, useStoreDispatch } from "../StoreContext";
import InputTab from "./InputTab";
export default function InputTabSelector() {
const store = useStore();
const dispatchStore = useStoreDispatch();
const [isCreating, setIsCreating] = useState(false);
const tabIds = isCreating
? [...store.files.map((f) => f.id), generateUniqueFileId(store.files)]
: store.files.map((f) => f.id);
const { enqueueSnackbar } = useSnackbar();
const handleMountEffect = (
tabId: string,
tabRef: RefObject<HTMLDivElement>
) => {
const isPendingCreation = isCreating && tabIds[tabIds.length - 1] === tabId;
if (isPendingCreation || store.selectedFileId === tabId) {
// Scroll new or selected tab into view when loading the page, switching tabs,
// and adding new tabs.
tabRef.current?.scrollIntoView({
block: "nearest",
inline: "start",
behavior: "smooth",
});
}
};
// Create a new tab.
const handleAddTab = (_oldTabId: string, newTabId: string) => {
try {
const newTab = createInputFile(newTabId, "");
checkInputFile(newTab, undefined, store);
dispatchStore({
type: "addFile",
payload: { file: newTab },
});
setIsCreating(false);
} catch (e) {
if (e instanceof Error) {
enqueueSnackbar(e.message, {
variant: "message",
...createMessage(
e.message,
MessageLevel.Error,
MessageSource.Playground
),
});
}
}
};
// Update ID of an existing tab.
const handleUpdateId = (oldTabId: string, newTabId: string) => {
if (newTabId === oldTabId) return;
const oldTab = store.files.find((f) => f.id === oldTabId);
invariant(oldTab, "Tab being updated must exist.");
try {
const newTab = createInputFile(newTabId, oldTab.content);
checkInputFile(newTab, oldTab, store);
dispatchStore({
type: "updateFile",
payload: { oldFileId: oldTabId, file: newTab },
});
} catch (e) {
if (e instanceof Error) {
enqueueSnackbar(e.message, {
variant: "message",
...createMessage(
e.message,
MessageLevel.Error,
MessageSource.Playground
),
});
}
}
};
const handleDeleteTab = (tabId: string) => {
// Tab being created.
if (isCreating) {
setIsCreating(false);
}
// Existing tabs.
else {
const ok = confirm(`Are you sure you want to delete ${tabId}?`);
if (!ok) return;
dispatchStore({
type: "deleteFile",
payload: { fileId: tabId },
});
}
};
const handleSwitchTab = (tabId: string) => {
const isPendingCreation = isCreating && tabIds[tabIds.length - 1] === tabId;
if (!isPendingCreation) {
dispatchStore({
type: "switchInputTab",
payload: { selectedFileId: tabId },
});
}
};
return (
<div className="relative flex w-full border-b border-gray-200 h-9">
<div className="flex h-full overflow-x-auto no-scrollbar">
{tabIds.map((tabId, index) => {
// Hide _app.js on UI.
if (tabId === "_app.js") return;
const isSelected = store.selectedFileId === tabId;
const isPendingCreation = isCreating && index === tabIds.length - 1;
const isIndexTab = index === 1;
const isDeletable = !isIndexTab || isPendingCreation;
const shouldDivide = index < tabIds.length - 1;
return (
<div
className="flex items-center h-full"
// So that once the new tab is created its states are reset,
// essentially blurring its input field (especially when creating
// the tab by pressing Enter).
key={`${tabId}${isPendingCreation ? "_new" : ""}`}
>
<InputTab
tabId={tabId}
autoFocus={isPendingCreation}
allowEdit={isSelected}
isDeletable={isDeletable}
borderColor={
isPendingCreation
? "border-gray-400"
: isSelected
? "border-link"
: "border-white"
}
cursorStyle={
isSelected || isPendingCreation
? "cursor-text"
: "cursor-pointer"
}
onMountEffect={handleMountEffect}
onSubmit={isPendingCreation ? handleAddTab : handleUpdateId}
onDelete={handleDeleteTab}
onSwitchTab={handleSwitchTab}
/>
{shouldDivide && (
<div className="w-[1px] h-[18px] border-gray-200 border-l mx-1" />
)}
</div>
);
})}
</div>
<button
className="z-10 flex items-center justify-center flex-none w-8 h-full bg-transparent group"
onClick={() => setIsCreating(true)}
>
<PlusIcon className="w-[18px] h-[18px] transition-colors duration-150 ease-in group-hover:fill-gray-800 fill-gray-500" />
</button>
<div className="absolute w-16 h-full right-8 bg-gradient-to-l from-white" />
</div>
);
}
/**
* Generate a file ID different from those of exsiting @param inputFiles.
*/
function generateUniqueFileId(inputFiles: Store["files"]) {
let name = "Component";
const ext = "js";
let i = 0;
while (true) {
if (inputFiles.find((f) => f.id === `${name}.${ext}`)) {
name = `Component${++i}`;
} else {
break;
}
}
return `${name}.${ext}`;
}
@@ -15,9 +15,8 @@ import {
} from "babel-plugin-react-forget";
import { memo, useEffect, useMemo } from "react";
import compile from "../../lib/compilerDriver";
import { getSelectedFile, type Store } from "../../lib/stores";
import type { Store } from "../../lib/stores";
import GraphView from "../GraphView";
import Preview from "../Preview";
import { monacoOptions } from "./monacoOptions";
import HIRTabContent from "./HIRTabContent";
@@ -32,7 +31,7 @@ type Props = {
function Output({ store, updateDiagnostics }: Props) {
const { outputs, diagnostics } = useMemo(
() => compile(getSelectedFile(store), store.compilerFlags),
() => compile(store.source, store.compilerFlags),
[store]
);
useEffect(() => {
@@ -42,7 +41,6 @@ function Output({ store, updateDiagnostics }: Props) {
<TabbedWindow
defaultTab="HIR"
tabs={{
Preview: <Preview store={store} />,
IR: <TextTabContent outputs={outputs} kind={OutputKind.IR} />,
HIR: <HIRTabContent source={getSelectedFile(store).content} />,
CFG: <TextTabContent outputs={outputs} kind={OutputKind.CFG} />,
@@ -1,137 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import LightBulbIcon from "@heroicons/react/solid/LightBulbIcon";
import { FormControlLabel, Switch } from "@mui/material";
import clsx from "clsx";
import invariant from "invariant";
import { useEffect, useRef, useState } from "react";
import { useMountEffect } from "../hooks";
import { bundle, BundleResult, defaultBundleRes } from "../lib/moduleBundler";
import { Store } from "../lib/stores";
const srcDoc = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<script>
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script>
window.addEventListener("message", async ({ data }) => {
try {
const { event, source, id } = data;
if (event === "CodeUpdate") {
const encodedCode = encodeURIComponent(source);
const dataUri = "data:text/javascript;charset=utf-8," + encodedCode;
await import(dataUri);
}
} catch (e) {
console.error(e);
}
});
</script>
</head>
<body>
<div id="app" />
</body>
</html>
`;
enum MessageType {
CodeUpdate = "CodeUpdate",
}
export default function Preview({ store }: { store: Store }) {
const [iframeReady, setIframeReady] = useState(false);
const iframeRef = useRef<HTMLIFrameElement>(null);
const [bundleRes, setBundleRes] = useState<BundleResult>(defaultBundleRes);
const [enableForget, setEnableForget] = useState<boolean>(true);
// used to invalidate import cache (when toggling enableForget)
const [toggleCount, setToggleCount] = useState<number>(0);
useMountEffect(() => {
if (!iframeRef || !iframeRef.current) return;
iframeRef.current.srcdoc = srcDoc;
iframeRef.current.addEventListener("load", () => {
setIframeReady(true);
});
});
// Perform async operations which will trigger a 2nd render.
useEffect(() => {
async function bundleInputs() {
const bundleRes = await bundle(store.files, store.compilerFlags);
setBundleRes(bundleRes);
}
bundleInputs();
}, [store.files, store.compilerFlags]);
// Synchronzie with iframe and messaging UIs.
useEffect(() => {
if (!bundleRes) return;
const { res } = bundleRes;
if (iframeReady && res) {
iframeRef.current!.contentWindow!.postMessage({
event: MessageType.CodeUpdate,
source: res.getCode(enableForget ? "after" : "before", toggleCount),
});
}
}, [iframeReady, bundleRes, store.selectedFileId, enableForget, toggleCount]);
const diff = bundleRes.res?.codeSizeDiff;
const showCodeSizeChange = diff != null && enableForget;
const ticker = (percentage: number) => (
<>
{percentage >= 0 ? "increased" : "decreased"} by{" "}
<span
className={clsx("text-red-600", {
"text-emerald-600": percentage <= 0,
})}
>
{Math.abs(percentage).toFixed(2)}%
</span>
</>
);
return (
<div className="flex flex-col w-full h-full">
<FormControlLabel
className={"mx-3"}
control={
<Switch
checked={enableForget}
onChange={(e) => {
setEnableForget(e.target.checked);
setToggleCount(toggleCount + 1);
}}
/>
}
label="Compile using Forget?"
/>
{showCodeSizeChange && (
<div className="flex items-center gap-1 p-2 bg-slate-200">
<LightBulbIcon className="flex-none w-5 h-5 text-yellow-500" />
<p className="text-sm">
Compiled code size {ticker(diff.minPercent)} ({diff.min} minified)
and {ticker(diff.gzipPercent)} ({diff.gzip} minified & gzipped) from
the original.
</p>
</div>
)}
<iframe
title="React Forget Playground"
ref={iframeRef}
className="flex-1 w-full"
/>
</div>
);
}
@@ -6,7 +6,7 @@ import type { Dispatch, ReactNode } from "react";
import { useReducer } from "react";
import createContext from "../lib/createContext";
import { emptyStore } from "../lib/defaultStore";
import type { InputFile, Store } from "../lib/stores";
import type { Store } from "../lib/stores";
import { saveStore } from "../lib/stores";
import { ForgetCompilerFlags } from "../lib/compilerDriver";
@@ -46,27 +46,12 @@ type ReducerAction =
store: Store;
};
}
| {
type: "addFile";
payload: {
file: InputFile;
};
}
| {
type: "updateFile";
payload: {
file: InputFile;
oldFileId?: string;
source: string;
};
}
| {
type: "deleteFile";
payload: { fileId: string };
}
| {
type: "switchInputTab";
payload: { selectedFileId: string };
}
| {
type: "setCompilerFlag";
payload: { flag: keyof ForgetCompilerFlags; value: boolean };
@@ -80,57 +65,12 @@ function storeReducer(store: Store, action: ReducerAction): Store {
saveStore(newStore);
return newStore;
}
case "addFile": {
const { file } = action.payload;
const newStore = {
...store,
files: [...store.files, file],
selectedFileId: file.id,
};
saveStore(newStore);
return newStore;
}
case "updateFile": {
const { file, oldFileId } = action.payload;
const { source } = action.payload;
const newStore = {
...store,
files: store.files.map((f) =>
f.id === file.id || f.id === oldFileId ? file : f
),
selectedFileId: file.id,
};
saveStore(newStore);
return newStore;
}
case "deleteFile": {
const { fileId } = action.payload;
// If the current selected file is deleted, fall back to selecting
// the index file (at index 1 of the files array).
const fallbackFileId =
store.selectedFileId === fileId
? store.files[1].id
: store.selectedFileId;
const newStore = {
...store,
files: store.files.filter((f) => f.id !== fileId),
selectedFileId: fallbackFileId,
};
saveStore(newStore);
return newStore;
}
case "switchInputTab": {
const { selectedFileId } = action.payload;
const newStore = {
...store,
selectedFileId: selectedFileId,
source,
};
saveStore(newStore);
@@ -18,7 +18,6 @@ import {
import { PassName } from "../../../dist/Pass";
// @ts-ignore
import ESLint from "eslint-browser";
import type { InputFile } from "./stores";
import { getBabelPlugins } from "./utils";
declare global {
@@ -54,19 +53,11 @@ function validateNoUseBeforeDefine(source: string) {
}
export default function compile(
file: InputFile,
source: string,
compilerFlags: ForgetCompilerFlags
): CompileResult {
const outputs = createCompilerOutputs();
// Bail out if file is CSS.
if (file.language === "css") {
return {
outputs,
diagnostics: [],
};
}
const forgetLogs: string[] = [];
const forgetPlaygroundOptions: Partial<CompilerOptions> = {
logger: createArrayLogger(forgetLogs),
@@ -78,18 +69,18 @@ export default function compile(
}
const babelPlugins = getBabelPlugins(
file.language,
"javascript",
true,
forgetPlaygroundOptions
);
const babelOptions: TransformOptions = {
compact: true,
plugins: babelPlugins,
filename: file.id,
filename: "index.js",
};
try {
const result = transform(file.content, babelOptions);
const result = transform(source, babelOptions);
// Don't throw if resulting code is any string. This includes the
// empty string, which is when `source` is an empty string.
@@ -3,210 +3,24 @@
*/
import type { Store } from "./stores";
import { createInputFile } from "./stores";
import { createCompilerFlags } from "babel-plugin-react-forget";
// Entry point to rendering Preview.
const _app = `\
import { createRoot } from "react-dom/client";
import Home from "./index";
// Persist the root in the global scope.
let root = globalThis.Forget$PlaygroundRoot;
if (!root) {
root = createRoot(document.getElementById("app"));
globalThis.Forget$PlaygroundRoot = root;
}
root.render(<Home />);
`;
// TODO: Add banner similar to the one in Preview to aid the user
// instead of using the comment below.
const index = `\
import { useState } from "react";
import "./styles.css";
import Task from "./Task";
import AddTask from "./AddTask";
const initialTasks = [
{ id: 0, text: "Buy milk", done: true },
{ id: 1, text: "Eat tacos", done: false },
{ id: 2, text: "Brew tea", done: false },
];
function TaskBoard() {
const [tasks, setTasks] = useState(initialTasks);
const onChangeTask = task =>
setTasks(ts => ts.map(t => (t.id === task.id ? task : t)));
return (
<div>
<AddTask setTasks={setTasks} />
{tasks.map(task => (
<Task key={task.id} task={task} onChange={onChangeTask} />
))}
</div>
);
}
// Default export a React component to render in the Preview.
export default TaskBoard;
`;
const task = `\
import { useState, useRef } from "react";
export default function Task({ task, onChange }) {
const count = useRef(0);
const [isEditing, setIsEditing] = useState(false);
let taskContent;
if (isEditing) {
taskContent = (
<>
<input
value={task.text}
onChange={e => {
onChange({
...task,
text: e.target.value,
});
}}
/>
<button onClick={() => setIsEditing(false)}>Save</button>
</>
)
} else {
taskContent = (
<>
{task.text}
<button onClick={() => setIsEditing(true)}>Edit</button>
</>
)
function fibbonacci(n) {
let a = 0;
let b = 1;
let c = 1;
for (let i = 0; i < n; i++) {
a = b;
b = c;
c = a + b;
}
return (
<li>
<label>
<input
type="checkbox"
checked={task.done}
onChange={e => {
onChange({
...task,
done: e.target.checked,
});
}}
/>
{taskContent}
{count.current++}
</label>
</li>
);
}`;
const addTask = `\
import { useState } from "react";
const defaultTask = "Code bugs";
let nextId = 3;
export default function AddTask({ setTasks }) {
const [text, setText] = useState(defaultTask);
const handleAddTask = (text) => {
setTasks((ts) => [
...ts,
{
id: nextId++,
text: text,
done: false,
},
]);
};
return (
<>
<input
placeholder="Add task"
value={text}
onChange={(e) => setText(e.target.value)}
/>
<button
onClick={() => {
setText(defaultTask);
handleAddTask(text);
}}
>
Add
</button>
</>
);
return a;
}
`;
const styles = `\
* {
box-sizing: border-box;
}
body {
font-family: "Optimistic Display App", sans-serif;
margin: 20px;
padding: 0;
}
h1 {
margin-top: 0;
font-size: 22px;
}
h2 {
margin-top: 0;
font-size: 20px;
}
h3 {
margin-top: 0;
font-size: 18px;
}
h4 {
margin-top: 0;
font-size: 16px;
}
h5 {
margin-top: 0;
font-size: 14px;
}
h6 {
margin-top: 0;
font-size: 12px;
}
ul {
padding-left: 20px;
}
button { margin: 5px; }
li { list-style-type: none; }
ul, li { margin: 0; padding: 0; }
`;
const defaultFiles: Store["files"] = [
// Hidden tab.
createInputFile("_app.js", _app),
createInputFile("index.js", index),
createInputFile("Task.js", task),
createInputFile("AddTask.js", addTask),
createInputFile("styles.css", styles),
];
export const defaultStore: Store = {
files: defaultFiles,
selectedFileId: "index.js",
source: index,
compilerFlags: createCompilerFlags(),
};
@@ -217,16 +31,11 @@ export default function MyApp() {
`;
export const minimalStore: Store = {
files: [
createInputFile("_app.js", _app),
createInputFile("index.js", minimalIndex),
],
selectedFileId: "index.js",
source: minimalIndex,
compilerFlags: createCompilerFlags(),
};
export const emptyStore: Store = {
files: [createInputFile("_app.js", _app)],
selectedFileId: "_app.js",
source: "",
compilerFlags: createCompilerFlags(),
};
@@ -1,199 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import type { TransformOptions } from "@babel/core";
import { transform } from "@babel/standalone";
import invariant from "invariant";
import type { Plugin } from "rollup";
import { ForgetCompilerFlags } from "./compilerDriver";
import patchUseMemoCache from "./patchUseMemoCache";
import { FileExt, matchFileId, type InputFile } from "./stores";
import { getBabelPlugins } from "./utils";
const MODULE_PREFIX = "\0";
const CDN = "https://esm.sh";
/**
* Rollup plugin that interprets input tabs as a virtual file system
* and monkeypatches `useMemoCache` into `react`.
*/
export default function forgetPlaygroundPlugin({
files,
enableForget,
reactVersion,
compilerFlags,
}: {
files: InputFile[];
enableForget: boolean;
reactVersion: string;
compilerFlags: ForgetCompilerFlags;
}): Plugin {
const fileTable = new Map<string, InputFile>();
files.forEach((f) => fileTable.set(`./${f.id}`, f));
return {
name: "forget-playground-plugin",
resolveId(source) {
/*
Instruct Rollup to resolve `react` and `react-dom` as internal modules,
where we'll then define their module content in the load hook below.
Note that setting the `syntheticNamedExports` option to `true` allows
Rollup to fall back missing named exports to the properties of the default
export. This is so that we don't have to export properties of `react` by
name (e.g., export { useState } from "react"). Instead we only export default
from `react` and the subsequent uses of otherwise named exports will be
transformed into the form of `React.useState`.
Refer to https://github.com/rollup/rollup/pull/3295 for details on
`syntheticNamedExports`.
*/
if (source === "react" || source.startsWith("react/")) {
return {
// Prefix each internal module ID with `\0` to prevent other plugins
// from trying to process it. (https://rollupjs.org/guide/en/#conventions)
id: `${MODULE_PREFIX}${source}`,
syntheticNamedExports: true,
};
}
if (source.startsWith("react-dom")) {
return {
id: `${MODULE_PREFIX}${source}`,
syntheticNamedExports: true,
};
}
// User-defined CSS
if (source.startsWith(".") && source.endsWith(".css")) {
return `${MODULE_PREFIX}${source}`;
}
// Playground input tabs
// Signals Rollup to not try to find the id elsewhere
if (source.startsWith(".")) {
const match = matchFileId(source);
const hasExtension = match !== null;
const isValidImportPath =
hasExtension && (match[1] === "js" || match[1] === "jsx");
// ES Module imports only allow extensions to be .js/.jsx (can be optionally
// omitted). For .ts/.tsx files, the extension must be omitted. So, whenever
// an file doesn't have an extension or has one that's not .js/.jsx, we try
// to add one and see if the resulting ID exists in the input files.
if (!isValidImportPath) {
for (const ext of Object.keys(FileExt)) {
if (ext === "css") continue;
if (fileTable.has(`${source}.${ext}`)) {
return `${MODULE_PREFIX}${source}.${ext}`;
}
}
this.error("Bundling failed: invalid import path.");
}
return `${MODULE_PREFIX}${source}`;
}
// External URL
if (source.includes("://")) {
return {
id: source,
external: true,
};
}
// Fallback to NPM packages
return {
id: `${CDN}/${source}`,
external: true,
};
},
load(id) {
if (!id.startsWith(MODULE_PREFIX)) return null;
id = id.slice(MODULE_PREFIX.length);
if (id === "react") {
return patchUseMemoCache(dev(`${CDN}/react@${reactVersion}`));
}
// `react/jsx-runtime`, etc.
else if (id.startsWith("react/")) {
const URL = id.replace("react", `${CDN}/react@${reactVersion}`);
return `export { default } from "${dev(URL)}"`;
}
// `react-dom/client`, etc.
else if (id.startsWith("react-dom")) {
const URL = id.replace("react-dom", `${CDN}/react-dom@${reactVersion}`);
return `export { default } from "${dev(URL)}"`;
}
// Load input tab content.
const file = fileTable.get(id);
invariant(
file,
"All non-external IDs that are not `react` or `react-dom` must be in fileTable."
);
return file.content;
},
transform(code, filename) {
filename = filename.slice(MODULE_PREFIX.length);
const file = fileTable.get(filename);
if (file && file.language === "css") {
// Append CSS as a style tag to the iframe <head> element.
return `
(() => {
let stylesheet = document.getElementById("${filename}");
// Remove and recreate the style tag to keep the order among style
// tags up to date, so that CSS imported later overrides previous CSS.
if (stylesheet) stylesheet.remove();
stylesheet = document.createElement("style");
stylesheet.setAttribute("id", "${filename}");
document.head.appendChild(stylesheet);
const styles = document.createTextNode(\`${code}\`);
stylesheet.innerHTML = "";
stylesheet.appendChild(styles);
})();
`;
}
const babelPlugins = getBabelPlugins(
file?.language ?? null,
enableForget,
{ flags: compilerFlags }
);
const babelOptions: TransformOptions = {
presets: [["react", { runtime: "automatic" }]],
plugins: babelPlugins,
filename: filename.replace("./", ""),
};
/*
TODO: Using the Babel Rollup plugin doesn't work out of the box due to
this plugin treating the input tabs as a virtual file system. The Babel
Rollup plugin's default configuration looks for files in the local file
system, so it requires some set up for it to work (since it can work with
this plugin in theory as Rollup plugins execute in turns by each hook).
*/
const result = transform(code, babelOptions);
if (!result?.code) this.error("Bundling failed.");
return result.code;
},
};
}
/**
* @see https://esm.sh/ - Development mode.
*/
const dev = (url: string) => `${url}?dev`;
@@ -1,142 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import { rollup } from "rollup";
import forgetPlaygroundPlugin from "./forgetPlaygroundPlugin";
import type { Store } from "./stores";
import { minify } from "terser";
import invariant from "invariant";
import { gzip, strToU8 } from "fflate";
import prettyBytes from "pretty-bytes";
import { ForgetCompilerFlags } from "./compilerDriver";
let bundleId = 0;
const ROLLUP_ENTRY = "./_app.js";
export interface BundleResult {
id: number;
res:
| undefined
| {
getCode(version: "before" | "after", cacheBreakId?: number): string;
codeSizeDiff: {
min: string;
minPercent: number;
gzip: string;
gzipPercent: number;
};
};
}
export const defaultBundleRes = {
id: 0,
res: undefined,
messages: [],
};
export async function bundle(
files: Store["files"],
compilerFlags: ForgetCompilerFlags,
reactVersion = "18.2.0"
): Promise<BundleResult> {
const codeAfter = await bundleWithRollup(
files,
true,
reactVersion,
compilerFlags
);
if (!codeAfter) return { id: bundleId, res: undefined };
const codeBefore = await bundleWithRollup(
files,
false,
reactVersion,
compilerFlags
);
invariant(codeBefore, "codeBefore should be consistent with codeAfter.");
const [minAfter, gzipAfter] = await compress(codeAfter);
const [minBefore, gzipBefore] = await compress(codeBefore);
return {
id: bundleId++,
res: {
getCode(version: "before" | "after", cacheBreakId?: number): string {
// Annotate with cache-busting bundleId and cacheBreakId to form unique moduleName.
// @see https://twitter.com/Huxpro/status/1551017434462621696
return `${
version === "before" ? codeBefore : codeAfter
} /* ${version} ${bundleId} ${cacheBreakId ?? ""} */`;
},
codeSizeDiff: {
min: prettyBytes(minAfter - minBefore, { signed: true }),
minPercent: getPercentage(minAfter, minBefore),
gzip: prettyBytes(gzipAfter - gzipBefore, { signed: true }),
gzipPercent: getPercentage(gzipAfter, gzipBefore),
},
},
};
}
/**
* Bundle @param files with Rollup.
* @returns a tuple of bundled code (undefined when error) and messages.
*/
async function bundleWithRollup(
files: Store["files"],
enableForget: boolean,
reactVersion: string,
compilerFlags: ForgetCompilerFlags
): Promise<string | undefined> {
try {
const rollupBuild = await rollup({
input: ROLLUP_ENTRY,
plugins: [
forgetPlaygroundPlugin({
files,
enableForget,
reactVersion,
compilerFlags,
}),
],
});
const {
output: [{ code }],
} = await rollupBuild.generate({
format: "esm",
});
return code;
} catch (e) {
return undefined;
}
}
/**
* Given @param code, @returns both minified and minified + gzipped code.
*/
async function compress(code: string): Promise<[number, number]> {
const minified = (await minify(code)).code;
invariant(minified, "Must have valid minified code.");
const minifiedSize = new Blob([minified]).size;
const gzipped = await execGzip(minified);
const gzippedSize = new Blob([gzipped]).size;
return [minifiedSize, gzippedSize];
}
/**
* @returns the percentage of @param a in relation to @param b.
*/
function getPercentage(a: number, b: number): number {
return ((a - b) / b) * 100;
}
function execGzip(code: string): Promise<Uint8Array> {
return new Promise((resolve, reject) => {
gzip(strToU8(code), (err, data) => {
if (err) reject(err);
resolve(data);
});
});
}
@@ -1,137 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
/**
* Monkeypatch `useMemoCache` into `react`. The default export will be
* used for Rollup to generate synthetic named exports.
*/
export default function patchUseMemoCache(reactSource: string) {
return `\
import React from "${reactSource}";
const REACT_MEMOCACHE_SENTINEL = Symbol.for('react.memocache_sentinel');
function useMemoCache(i) {
"use no forget";
const $ = new Array(i).fill(REACT_MEMOCACHE_SENTINEL)
$._ = REACT_MEMOCACHE_SENTINEL
const ref = React.useRef($);
return ref.current;
};
useMemoCache.read = function (memoCache, index) {
const value = memoCache[index];
if (value === REACT_MEMOCACHE_SENTINEL) {
throw new Error('useMemoCache.read: read before write');
}
return value;
};
// Utility functions
function isWriteable(desc) {
return (desc.writable || desc.set) && desc.configurable;
}
function getOrInsertDefault(m, k) {
const entry = m.get(k);
if (entry) {
return { existed: true, entry };
}
else {
const newEntry = new Map();
m.set(k, newEntry);
return { existed: false, entry: newEntry };
}
}
function buildMakeReadOnly(logger, skippedClasses, isInROMode) {
// All saved proxys
const savedROObjects = new WeakMap();
// Overwrites an object property with its proxy and saves its original value
function addProperty(obj, key, prop, savedEntries) {
const proxy = {
get() {
// read from backing cache entry
return makeReadOnly(savedEntries.get(key).savedVal);
},
set(newVal) {
if (isInROMode()) {
logger("FORGET_MUTATE_IMMUT", key, newVal);
}
// update backing cache entry
savedEntries.get(key).savedVal = newVal;
},
};
if (prop.configurable != null) {
proxy.configurable = prop.configurable;
}
if (prop.enumerable != null) {
proxy.enumerable = prop.enumerable;
}
savedEntries.set(key, { savedVal: obj[key], getter: proxy.get });
Object.defineProperty(obj, key, proxy);
}
// Changes an object to be read-only, returns its input
function makeReadOnly(o) {
if (typeof o !== "object" || o == null) {
return o;
}
else if (skippedClasses.includes(o.constructor.name)) {
return o;
}
const { existed, entry: cache } = getOrInsertDefault(savedROObjects, o);
for (const [k, entry] of cache.entries()) {
const currentProp = Object.getOwnPropertyDescriptor(o, k);
if (currentProp && !isWriteable(currentProp)) {
continue;
}
const currentPropGetter = currentProp?.get;
const cachedGetter = entry.getter;
if (currentPropGetter !== cachedGetter) {
// cache is currently holding an old property
// - it may have been deleted
// - it may have been deleted + re-set
// (meaning that new value is not proxied,
// and the current proxied value is stale)
cache.delete(k);
if (!currentProp && isInROMode()) {
logger("FORGET_DELETE_PROP_IMMUT", k);
}
else if (currentProp) {
if (isInROMode()) {
logger("FORGET_CHANGE_PROP_IMMUT", k);
}
addProperty(o, k, currentProp, cache);
}
}
}
for (const [k, prop] of Object.entries(Object.getOwnPropertyDescriptors(o))) {
if (!cache.has(k) && isWriteable(prop)) {
if (isInROMode() && existed) {
logger("FORGET_ADD_PROP_IMMUT", k);
}
addProperty(o, k, prop, cache);
}
}
return o;
}
return makeReadOnly;
}
useMemoCache.makeReadOnly = buildMakeReadOnly(
console.log,
[
// some immutVals have a transitive reference to global (e.g. LexicalEditor)
'Window',
'Storage', // useBrowserStorage
// some immutVals (e.g. ref.current) have a ref to DOM nodes (e.g. BaseDOMContainer)
// - since FiberNodes -should- be interior mutable, this is safe
'FiberNode',
],
() => true, // always read-only
);
React.unstable_useMemoCache = React.useMemoCache = useMemoCache;
export default React;
`;
}
@@ -4,7 +4,6 @@
export enum MessageSource {
Babel,
Rollup,
Forget,
Playground,
}
@@ -2,106 +2,22 @@
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import { createCompilerFlags, OutputKind } from "babel-plugin-react-forget";
import { createCompilerFlags } from "babel-plugin-react-forget";
import invariant from "invariant";
import { defaultStore } from "../defaultStore";
import { codec } from "../utils";
import { ForgetCompilerFlags } from "../compilerDriver";
import { parseCompilerFlags } from "babel-plugin-react-forget";
export enum FileExt {
js = "javascript",
jsx = "javascript",
ts = "typescript",
tsx = "typescript",
css = "css",
}
export interface InputFile {
id: string;
language: string;
content: string;
}
/**
* Match @param fileId with valid FileExt's.
*/
export function matchFileId(fileId: string) {
return fileId.match(new RegExp(`.+\\.(${Object.keys(FileExt).join("|")})$`));
}
/**
* Refine @param ext string to a key in FileExt.
*/
function isValidFileExt(ext: string): ext is keyof typeof FileExt {
return Object.keys(FileExt).includes(ext);
}
/**
* Checks if @param id is a valid file ID.
* @returns an input file that may or may not be a valid input tab to add to Store.
*/
export function createInputFile(id: string, content: string): InputFile {
const match = matchFileId(id);
if (!match || !isValidFileExt(match[1])) {
throw new Error(
`Invalid tab name or extension. The tab must have a name and a supported extension (${Object.keys(
FileExt
).join(", ")}).`
);
}
return {
id,
language: FileExt[match[1]],
content,
};
}
export function checkInputFile(
inputFile: InputFile,
fromFile: InputFile | undefined,
store: Store
) {
const isDuplicateFileId =
store.files.find((file) => file.id === inputFile.id) !== undefined;
if (isDuplicateFileId) {
throw new Error(`A tab with ID "${inputFile.id}" already exists.`);
}
const isIndexLikeId = (id: string) => /^index\..*$/.test(id);
const fromIndex = fromFile && isIndexLikeId(fromFile.id);
if (fromIndex && !isIndexLikeId(inputFile.id)) {
throw new Error(`Only the file extension of the index tab can be changed.`);
}
if (!fromIndex && isIndexLikeId(inputFile.id)) {
throw new Error(`Only the index tab can be named as "index".`);
}
}
/**
* Global Store for Playground
*/
export interface Store {
/**
* Input tabs. The key is FileId joined by a dot.
*
* @example "index.js" => { id: "index.js", language: "javascript", content: "// index.js", isIdEditable: false }
*/
files: InputFile[];
source: string;
selectedFileId: string;
/* Compiler settings */
compilerFlags: ForgetCompilerFlags;
}
export function getSelectedFile(store: Store): InputFile {
const selectedFile = store.files.find((f) => f.id === store.selectedFileId);
invariant(selectedFile, "Selected file must exists.");
return selectedFile;
}
/**
* Serialize, encode, and save @param store to localStorage and update URL.
*/
@@ -113,20 +29,13 @@ export function saveStore(store: Store) {
/**
* Check if @param raw is a valid Store by if
* - it has a `files` property and is an Array
* - it has a `selectedFileId` property and is a string
* - its `selectedFileId` has a corresponding file in `files`
* - it has a `source` property and is a string
*/
function getValidStore(raw: any): Store | null {
if ("compilerFlags" in raw && !(raw["compilerFlags"] instanceof Object)) {
return null;
}
const isValidStore =
"files" in raw &&
raw["files"] instanceof Array &&
"selectedFileId" in raw &&
typeof raw["selectedFileId"] === "string" &&
raw["files"].find((f) => f.id === raw["selectedFileId"]);
const isValidStore = "source" in raw && typeof raw["source"] === "string";
if (isValidStore) {
if ("compilerFlags" in raw) {
// Merge flags from decoded store into flags valid for this compiler version
@@ -11,26 +11,19 @@
},
"dependencies": {
"@babel/standalone": "^7.18.4",
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
"@heroicons/react": "^1.0.6",
"@hpcc-js/wasm": "^1.15.0",
"@monaco-editor/react": "^4.4.5",
"@mui/material": "^5.9.1",
"@use-gesture/react": "^10.2.20",
"fflate": "^0.7.3",
"hermes-eslint": "^0.9.0",
"invariant": "^2.2.4",
"monaco-editor": "^0.33.0",
"next": "12.1.6",
"notistack": "^3.0.0-alpha.7",
"prettier": "^2.6.2",
"pretty-bytes": "^6.0.0",
"pretty-format": "^28.1.3",
"react": "18.1.0",
"react-dom": "18.1.0",
"rollup": "^2.75.7",
"terser": "^5.14.2"
"react-dom": "18.1.0"
},
"devDependencies": {
"@types/babel__standalone": "^7.1.4",
+12 -420
View File
@@ -48,18 +48,6 @@
"@babel/template" "^7.18.10"
"@babel/types" "^7.19.0"
"@babel/helper-module-imports@^7.12.13":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-plugin-utils@^7.18.6":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f"
integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==
"@babel/helper-split-export-declaration@^7.0.0":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
@@ -105,13 +93,6 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.1.tgz#6f6d6c2e621aad19a92544cc217ed13f1aac5b4c"
integrity sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==
"@babel/plugin-syntax-jsx@^7.12.13":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0"
integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/runtime-corejs3@^7.10.2":
version "7.18.3"
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.18.3.tgz#52f0241a31e0ec61a6187530af6227c2846bd60c"
@@ -127,13 +108,6 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.13.10", "@babel/runtime@^7.17.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/standalone@^7.18.4":
version "7.18.5"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.18.5.tgz#69aeb99edacb55c509895d7fa6131ec9dbda7c6d"
@@ -189,107 +163,6 @@
"@babel/helper-validator-identifier" "^7.18.6"
to-fast-properties "^2.0.0"
"@emotion/babel-plugin@^11.7.1":
version "11.9.2"
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz#723b6d394c89fb2ef782229d92ba95a740576e95"
integrity sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==
dependencies:
"@babel/helper-module-imports" "^7.12.13"
"@babel/plugin-syntax-jsx" "^7.12.13"
"@babel/runtime" "^7.13.10"
"@emotion/hash" "^0.8.0"
"@emotion/memoize" "^0.7.5"
"@emotion/serialize" "^1.0.2"
babel-plugin-macros "^2.6.1"
convert-source-map "^1.5.0"
escape-string-regexp "^4.0.0"
find-root "^1.1.0"
source-map "^0.5.7"
stylis "4.0.13"
"@emotion/cache@^11.9.3":
version "11.9.3"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.9.3.tgz#96638449f6929fd18062cfe04d79b29b44c0d6cb"
integrity sha512-0dgkI/JKlCXa+lEXviaMtGBL0ynpx4osh7rjOXE71q9bIF8G+XhJgvi+wDu0B0IdCVx37BffiwXlN9I3UuzFvg==
dependencies:
"@emotion/memoize" "^0.7.4"
"@emotion/sheet" "^1.1.1"
"@emotion/utils" "^1.0.0"
"@emotion/weak-memoize" "^0.2.5"
stylis "4.0.13"
"@emotion/hash@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
"@emotion/is-prop-valid@^1.1.3":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.1.3.tgz#f0907a416368cf8df9e410117068e20fe87c0a3a"
integrity sha512-RFg04p6C+1uO19uG8N+vqanzKqiM9eeV1LDOG3bmkYmuOj7NbKNlFC/4EZq5gnwAIlcC/jOT24f8Td0iax2SXA==
dependencies:
"@emotion/memoize" "^0.7.4"
"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
"@emotion/react@^11.9.3":
version "11.9.3"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.9.3.tgz#f4f4f34444f6654a2e550f5dab4f2d360c101df9"
integrity sha512-g9Q1GcTOlzOEjqwuLF/Zd9LC+4FljjPjDfxSM7KmEakm+hsHXk+bYZ2q+/hTJzr0OUNkujo72pXLQvXj6H+GJQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@emotion/babel-plugin" "^11.7.1"
"@emotion/cache" "^11.9.3"
"@emotion/serialize" "^1.0.4"
"@emotion/utils" "^1.1.0"
"@emotion/weak-memoize" "^0.2.5"
hoist-non-react-statics "^3.3.1"
"@emotion/serialize@^1.0.2", "@emotion/serialize@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.4.tgz#ff31fd11bb07999611199c2229e152faadc21a3c"
integrity sha512-1JHamSpH8PIfFwAMryO2bNka+y8+KA5yga5Ocf2d7ZEiJjb7xlLW7aknBGZqJLajuLOvJ+72vN+IBSwPlXD1Pg==
dependencies:
"@emotion/hash" "^0.8.0"
"@emotion/memoize" "^0.7.4"
"@emotion/unitless" "^0.7.5"
"@emotion/utils" "^1.0.0"
csstype "^3.0.2"
"@emotion/sheet@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.1.tgz#015756e2a9a3c7c5f11d8ec22966a8dbfbfac787"
integrity sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA==
"@emotion/styled@^11.9.3":
version "11.9.3"
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.9.3.tgz#47f0c71137fec7c57035bf3659b52fb536792340"
integrity sha512-o3sBNwbtoVz9v7WB1/Y/AmXl69YHmei2mrVnK7JgyBJ//Rst5yqPZCecEJlMlJrFeWHp+ki/54uN265V2pEcXA==
dependencies:
"@babel/runtime" "^7.13.10"
"@emotion/babel-plugin" "^11.7.1"
"@emotion/is-prop-valid" "^1.1.3"
"@emotion/serialize" "^1.0.4"
"@emotion/utils" "^1.1.0"
"@emotion/unitless@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf"
integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==
"@emotion/weak-memoize@^0.2.5":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
"@eslint/eslintrc@^1.3.3":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95"
@@ -343,46 +216,6 @@
dependencies:
"@sinclair/typebox" "^0.24.1"
"@jridgewell/gen-mapping@^0.3.0":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9"
integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==
dependencies:
"@jridgewell/set-array" "^1.0.0"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/resolve-uri@^3.0.3":
version "3.0.7"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe"
integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==
"@jridgewell/set-array@^1.0.0":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea"
integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==
"@jridgewell/source-map@^0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
dependencies:
"@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.13"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c"
integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==
"@jridgewell/trace-mapping@^0.3.9":
version "0.3.13"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea"
integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@monaco-editor/loader@^1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.3.2.tgz#04effbb87052d19cd7d3c9d81c0635490f9bb6d8"
@@ -398,86 +231,6 @@
"@monaco-editor/loader" "^1.3.2"
prop-types "^15.7.2"
"@mui/base@5.0.0-alpha.90":
version "5.0.0-alpha.90"
resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.90.tgz#73700ba74e5c75096ee5d0bfe3ba4a3b3b81beef"
integrity sha512-hNKwzr+RkiuGsGrakz8Q2i5ezr4Dz4b4Qsdipt9SiMrhuFAra/i501VSaEIzwec9LC4G+vtW4fE7yJBB0XaAYw==
dependencies:
"@babel/runtime" "^7.17.2"
"@emotion/is-prop-valid" "^1.1.3"
"@mui/types" "^7.1.4"
"@mui/utils" "^5.9.1"
"@popperjs/core" "^2.11.5"
clsx "^1.2.1"
prop-types "^15.8.1"
react-is "^18.2.0"
"@mui/material@^5.9.1":
version "5.9.1"
resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.9.1.tgz#92990e6d4035792430dcf548b91db6f335aebdd3"
integrity sha512-c09SbaMm7Rl7Df9JRkXwPWNbnfrutmHERTJC46OJ9OMAM9+HGQihIbGln1k2Xj65jb3E+G498FZFAoSrrBDvwQ==
dependencies:
"@babel/runtime" "^7.17.2"
"@mui/base" "5.0.0-alpha.90"
"@mui/system" "^5.9.1"
"@mui/types" "^7.1.4"
"@mui/utils" "^5.9.1"
"@types/react-transition-group" "^4.4.5"
clsx "^1.2.1"
csstype "^3.1.0"
prop-types "^15.8.1"
react-is "^18.2.0"
react-transition-group "^4.4.2"
"@mui/private-theming@^5.9.1":
version "5.9.1"
resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.9.1.tgz#4f714ed9ebd587373dc77b3fc69e9f3e720f0190"
integrity sha512-eIh2IZJInNTdgPLMo9cruzm8UDX5amBBxxsSoNre7lRj3wcsu3TG5OKjIbzkf4VxHHEhdPeNNQyt92k7L78u2A==
dependencies:
"@babel/runtime" "^7.17.2"
"@mui/utils" "^5.9.1"
prop-types "^15.8.1"
"@mui/styled-engine@^5.8.7":
version "5.8.7"
resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.8.7.tgz#63d0779c07677fe76d4705a02c7ae99f89b50780"
integrity sha512-tVqtowjbYmiRq+qcqXK731L9eWoL9H8xTRhuTgaDGKdch1zlt4I2UwInUe1w2N9N/u3/jHsFbLcl1Un3uOwpQg==
dependencies:
"@babel/runtime" "^7.17.2"
"@emotion/cache" "^11.9.3"
csstype "^3.1.0"
prop-types "^15.8.1"
"@mui/system@^5.9.1":
version "5.9.1"
resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.9.1.tgz#dadd1094b1582781cc524b112a0a126f60b23c25"
integrity sha512-ZixTmc2+sYp++avoYJ38eM70nfwwudN06vYCU4kfwa4nQPiH+bhLYZnfYkcXRKiDR/hfT0dptbOOfQGZqBYczQ==
dependencies:
"@babel/runtime" "^7.17.2"
"@mui/private-theming" "^5.9.1"
"@mui/styled-engine" "^5.8.7"
"@mui/types" "^7.1.4"
"@mui/utils" "^5.9.1"
clsx "^1.2.1"
csstype "^3.1.0"
prop-types "^15.8.1"
"@mui/types@^7.1.4":
version "7.1.4"
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.1.4.tgz#4185c05d6df63ec673cda15feab80440abadc764"
integrity sha512-uveM3byMbthO+6tXZ1n2zm0W3uJCQYtwt/v5zV5I77v2v18u0ITkb8xwhsDD2i3V2Kye7SaNR6FFJ6lMuY/WqQ==
"@mui/utils@^5.9.1":
version "5.9.1"
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.9.1.tgz#2b2c9dadbf8ba6561e145b5688fb7df5ef15a934"
integrity sha512-8+4adOR3xusyJwvbnZxcjqcmbWvl7Og+260ZKIrSvwnFs0aLubL+8MhiceeDDGcmb0bTKxfUgRJ96j32Jb7P+A==
dependencies:
"@babel/runtime" "^7.17.2"
"@types/prop-types" "^15.7.5"
"@types/react-is" "^16.7.1 || ^17.0.0"
prop-types "^15.8.1"
react-is "^18.2.0"
"@next/env@12.1.6":
version "12.1.6"
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.6.tgz#5f44823a78335355f00f1687cfc4f1dafa3eca08"
@@ -571,11 +324,6 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@popperjs/core@^2.11.5":
version "2.11.5"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64"
integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==
"@rushstack/eslint-patch@^1.1.3":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz#6801033be7ff87a6b7cadaf5b337c9f366a3c4b0"
@@ -603,17 +351,12 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.40.tgz#76ee88ae03650de8064a6cf75b8d95f9f4a16090"
integrity sha512-UXdBxNGqTMtm7hCwh9HtncFVLrXoqA3oJW30j6XWp5BH/wu3mVeaxo7cq5benFdBw34HB3XDT2TRPI7rXZ+mDg==
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
"@types/prettier@^2.6.3":
version "2.6.3"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.3.tgz#68ada76827b0010d0db071f739314fa429943d0a"
integrity sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==
"@types/prop-types@*", "@types/prop-types@^15.7.5":
"@types/prop-types@*":
version "15.7.5"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
@@ -625,20 +368,6 @@
dependencies:
"@types/react" "*"
"@types/react-is@^16.7.1 || ^17.0.0":
version "17.0.3"
resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.3.tgz#2d855ba575f2fc8d17ef9861f084acc4b90a137a"
integrity sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==
dependencies:
"@types/react" "*"
"@types/react-transition-group@^4.4.5":
version "4.4.5"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416"
integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@18.0.12":
version "18.0.12"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.12.tgz#cdaa209d0a542b3fcf69cf31a03976ec4cdd8840"
@@ -733,7 +462,7 @@ acorn@^7.0.0:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.5.0, acorn@^8.8.0:
acorn@^8.8.0:
version "8.8.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
@@ -861,15 +590,6 @@ axobject-query@^2.2.0:
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==
babel-plugin-macros@^2.6.1:
version "2.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==
dependencies:
"@babel/runtime" "^7.7.2"
cosmiconfig "^6.0.0"
resolve "^1.12.0"
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@@ -906,11 +626,6 @@ browserslist@^4.20.3:
node-releases "^2.0.5"
picocolors "^1.0.0"
buffer-from@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
call-bind@^1.0.0, call-bind@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
@@ -975,7 +690,7 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
clsx@^1.1.0, clsx@^1.2.1:
clsx@^1.1.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
@@ -1009,17 +724,12 @@ color-name@^1.1.4, color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
convert-source-map@^1.1.0, convert-source-map@^1.5.0:
convert-source-map@^1.1.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
@@ -1031,17 +741,6 @@ core-js-pure@^3.20.2:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.23.1.tgz#0b27e4c3ad46178b84e790dbbb81987218ab82ad"
integrity sha512-3qNgf6TqI3U1uhuSYRzJZGfFd4T+YlbyVPl+jgRiKjdZopvG4keZQwWZDAWpu1UH9nCgTpUzIV3GFawC7cJsqg==
cosmiconfig@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982"
integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==
dependencies:
"@types/parse-json" "^4.0.0"
import-fresh "^3.1.0"
parse-json "^5.0.0"
path-type "^4.0.0"
yaml "^1.7.2"
cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -1056,7 +755,7 @@ cssesc@^3.0.0:
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
csstype@^3.0.2, csstype@^3.1.0:
csstype@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2"
integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==
@@ -1145,14 +844,6 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
dom-helpers@^5.0.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
dependencies:
"@babel/runtime" "^7.8.7"
csstype "^3.0.2"
electron-to-chromium@^1.4.147:
version "1.4.155"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.155.tgz#9c7190bf5e8608c5a5e4953b1ccf0facf3d1b49d"
@@ -1176,13 +867,6 @@ enhanced-resolve@^5.7.0:
graceful-fs "^4.2.4"
tapable "^2.2.0"
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5:
version "1.20.1"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814"
@@ -1482,11 +1166,6 @@ fastq@^1.6.0:
dependencies:
reusify "^1.0.4"
fflate@^0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.7.3.tgz#288b034ff0e9c380eaa2feff48c787b8371b7fa5"
integrity sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==
file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
@@ -1501,11 +1180,6 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
find-up@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
@@ -1730,19 +1404,12 @@ hermes-parser@0.9.0:
dependencies:
hermes-estree "0.9.0"
hoist-non-react-statics@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
ignore@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1:
import-fresh@^3.0.0, import-fresh@^3.2.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
@@ -1784,11 +1451,6 @@ invariant@^2.2.4:
dependencies:
loose-envify "^1.0.0"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
is-bigint@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
@@ -1927,11 +1589,6 @@ jsesc@^2.5.1:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-parse-even-better-errors@^2.3.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@@ -1987,11 +1644,6 @@ lilconfig@^2.0.5:
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25"
integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
locate-path@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
@@ -2264,16 +1916,6 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
parse-json@^5.0.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
dependencies:
"@babel/code-frame" "^7.0.0"
error-ex "^1.3.1"
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
path-exists@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
@@ -2391,11 +2033,6 @@ prettier@^2.6.2:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.0.tgz#a4fdae07e5596c51c9857ea676cd41a0163879d6"
integrity sha512-nwoX4GMFgxoPC6diHvSwmK/4yU8FFH3V8XWtLQrbj4IBsK2pkYhG4kf/ljF/haaZ/aii+wNJqISrCDPgxGWDVQ==
pretty-bytes@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-6.0.0.tgz#928be2ad1f51a2e336add8ba764739f9776a8140"
integrity sha512-6UqkYefdogmzqAZWzJ7laYeJnaXDy2/J+ZqiiMtS7t7OfpXWTlaeGMwX8U6EFvPV/YWWEKRkS8hKS4k60WHTOg==
pretty-format@^28.1.3:
version "28.1.3"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5"
@@ -2406,7 +2043,7 @@ pretty-format@^28.1.3:
ansi-styles "^5.0.0"
react-is "^18.0.0"
prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -2438,26 +2075,16 @@ react-dom@18.1.0:
loose-envify "^1.1.0"
scheduler "^0.22.0"
react-is@^16.13.1, react-is@^16.7.0:
react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^18.0.0, react-is@^18.2.0:
react-is@^18.0.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
react-transition-group@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==
dependencies:
"@babel/runtime" "^7.5.5"
dom-helpers "^5.0.1"
loose-envify "^1.4.0"
prop-types "^15.6.2"
react@18.1.0:
version "18.1.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.1.0.tgz#6f8620382decb17fdc5cc223a115e2adbf104890"
@@ -2517,7 +2144,7 @@ resolve@^1.1.7, resolve@^1.20.0, resolve@^1.22.0:
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
resolve@^1.12.0, resolve@^1.3.2:
resolve@^1.3.2:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@@ -2546,13 +2173,6 @@ rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
rollup@^2.75.7:
version "2.75.7"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.75.7.tgz#221ff11887ae271e37dcc649ba32ce1590aaa0b9"
integrity sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ==
optionalDependencies:
fsevents "~2.3.2"
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
@@ -2620,24 +2240,11 @@ source-map-js@^1.0.1, source-map-js@^1.0.2:
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
source-map-support@~0.5.20:
version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.5.0, source-map@^0.5.7:
source-map@^0.5.0:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
source-map@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
state-local@^1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5"
@@ -2706,11 +2313,6 @@ styled-jsx@5.0.2:
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.2.tgz#ff230fd593b737e9e68b630a694d460425478729"
integrity sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==
stylis@4.0.13:
version "4.0.13"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91"
integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -2763,16 +2365,6 @@ tapable@^2.2.0:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
terser@^5.14.2:
version "5.14.2"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
dependencies:
"@jridgewell/source-map" "^0.3.2"
acorn "^8.5.0"
commander "^2.20.0"
source-map-support "~0.5.20"
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -2908,7 +2500,7 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@^1.10.2, yaml@^1.7.2:
yaml@^1.10.2:
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==