mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[playground] remove multi-file support and preview (#767)
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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==
|
||||
|
||||
Reference in New Issue
Block a user