From db05e589e01d9f026cd252940e6acfc87da94964 Mon Sep 17 00:00:00 2001
From: softmarshmallow <woojoo@softmarshmallow.com>
Date: Wed, 29 Dec 2021 04:48:57 +0900
Subject: [PATCH 1/8] monaco extension with worker - wip

---
 .../code-editor/monaco-utils/index.ts         |   1 +
 .../code-editor/monaco-utils/register-jsx.ts  |  64 +++
 .../monaco-utils/register-prettier.ts         |  75 ++++
 .../monaco-utils/register-typings.ts          |  63 +++
 .../code-editor/monaco-utils/register.ts      |  65 +++
 editor/components/code-editor/monaco.tsx      |  30 +-
 editor/package.json                           |   1 +
 .../workers/fetch-types/fetch-types.worker.js | 282 +++++++++++++
 editor/workers/index.js                       |  41 ++
 .../syntax-highlight.worker.js                | 109 +++++
 editor/workers/prettier/prettier.worker.js    |  61 +++
 yarn.lock                                     | 385 ++++++++++--------
 12 files changed, 995 insertions(+), 182 deletions(-)
 create mode 100644 editor/components/code-editor/monaco-utils/index.ts
 create mode 100644 editor/components/code-editor/monaco-utils/register-jsx.ts
 create mode 100644 editor/components/code-editor/monaco-utils/register-prettier.ts
 create mode 100644 editor/components/code-editor/monaco-utils/register-typings.ts
 create mode 100644 editor/components/code-editor/monaco-utils/register.ts
 create mode 100644 editor/workers/fetch-types/fetch-types.worker.js
 create mode 100644 editor/workers/index.js
 create mode 100644 editor/workers/monaco-syntax-highlight/syntax-highlight.worker.js
 create mode 100644 editor/workers/prettier/prettier.worker.js

diff --git a/editor/components/code-editor/monaco-utils/index.ts b/editor/components/code-editor/monaco-utils/index.ts
new file mode 100644
index 00000000..a123a773
--- /dev/null
+++ b/editor/components/code-editor/monaco-utils/index.ts
@@ -0,0 +1 @@
+export * as register from "./register";
diff --git a/editor/components/code-editor/monaco-utils/register-jsx.ts b/editor/components/code-editor/monaco-utils/register-jsx.ts
new file mode 100644
index 00000000..c2e38cdf
--- /dev/null
+++ b/editor/components/code-editor/monaco-utils/register-jsx.ts
@@ -0,0 +1,64 @@
+import { Monaco } from "@monaco-editor/react";
+// import { createWorkerQueue } from "../../../workers";
+// import Worker from '../../../workers/monaco-syntax-highlight/syntax-highlight.worker';
+
+import type { editor } from "monaco-editor";
+export function registerJsxHighlighter(
+  editor: editor.IStandaloneCodeEditor,
+  monaco: Monaco
+) {
+  const { worker: syntaxWorker } = createWorkerQueue(
+    new Worker(
+      new URL(
+        "../../../workers/monaco-syntax-highlight/syntax-highlight.worker.js"
+        // import.meta.url
+      )
+    )
+  );
+
+  const highlightHandler = () => {
+    const title = "app.js";
+    const model = editor.getModel();
+    const version = model!.getVersionId();
+    // @ts-ignore
+    const lang = model._languageIdentifier.language;
+
+    if (lang === "javascript" || "typescript") {
+      const code = model?.getValue();
+      syntaxWorker.postMessage({
+        code,
+        title,
+        version,
+      });
+    }
+  };
+
+  editor.onDidChangeModel(highlightHandler);
+
+  editor.onDidChangeModelContent(highlightHandler);
+
+  let oldDecor = editor.getModel()?.getAllDecorations();
+
+  syntaxWorker.addEventListener("message", (event) => {
+    const { classifications } = event.data;
+
+    requestAnimationFrame(() => {
+      const decorations = classifications.map((classification) => ({
+        range: new monaco.Range(
+          classification.startLine,
+          classification.start,
+          classification.endLine,
+          classification.end
+        ),
+        options: {
+          inlineClassName: classification.type
+            ? `ayu-dark ${classification.kind} ${classification.type}-of-${classification.parentKind}`
+            : classification.kind,
+        },
+      }));
+
+      // @ts-ignore
+      oldDecor = editor.deltaDecorations(oldDecor, decorations);
+    });
+  });
+}
diff --git a/editor/components/code-editor/monaco-utils/register-prettier.ts b/editor/components/code-editor/monaco-utils/register-prettier.ts
new file mode 100644
index 00000000..d7f18701
--- /dev/null
+++ b/editor/components/code-editor/monaco-utils/register-prettier.ts
@@ -0,0 +1,75 @@
+export const dummy = "";
+// import * as monaco from "monaco-editor";
+// import { createWorkerQueue } from "../../../workers";
+
+// export function registerDocumentPrettier(editor, monaco) {
+//   const disposables: monaco.IDisposable[] = [];
+//   let prettierWorker;
+
+//   const formattingEditProvider = {
+//     async provideDocumentFormattingEdits(model, _options, _token) {
+//       if (!prettierWorker) {
+//         prettierWorker = createWorkerQueue(
+//           new Worker(
+//             new URL(
+//               "../../../workers/prettier.worker.js"
+//               // import.meta.url
+//             )
+//           )
+//         );
+//       }
+
+//       const { canceled, error, pretty } = await prettierWorker?.emit({
+//         text: model.getValue(),
+//         language: model.getModeId(),
+//       });
+
+//       if (canceled || error) return [];
+
+//       return [
+//         {
+//           range: model.getFullModelRange(),
+//           text: pretty,
+//         },
+//       ];
+//     },
+//   };
+
+//   disposables.push(
+//     monaco.languages.registerDocumentFormattingEditProvider(
+//       "javascript",
+//       formattingEditProvider
+//     )
+//   );
+
+//   disposables.push(
+//     monaco.languages.registerDocumentFormattingEditProvider(
+//       "html",
+//       formattingEditProvider
+//     )
+//   );
+
+//   disposables.push(
+//     monaco.languages.registerDocumentFormattingEditProvider(
+//       "css",
+//       formattingEditProvider
+//     )
+//   );
+//   disposables.push(
+//     monaco.languages.registerDocumentFormattingEditProvider(
+//       "typescript",
+//       formattingEditProvider
+//     )
+//   );
+
+//   editor.getAction("editor.action.formatDocument").run();
+
+//   return {
+//     dispose() {
+//       disposables.forEach((disposable) => disposable.dispose());
+//       if (prettierWorker) {
+//         prettierWorker.terminate();
+//       }
+//     },
+//   };
+// }
diff --git a/editor/components/code-editor/monaco-utils/register-typings.ts b/editor/components/code-editor/monaco-utils/register-typings.ts
new file mode 100644
index 00000000..7f44b17a
--- /dev/null
+++ b/editor/components/code-editor/monaco-utils/register-typings.ts
@@ -0,0 +1,63 @@
+import { Monaco } from "@monaco-editor/react";
+
+export function registerTypesWorker(monaco: Monaco) {
+  const disposables: any = [];
+  let typesWorker;
+
+  const dependencies = {
+    react: "@latest",
+    "react-dom": "@latest",
+    axios: "@latest",
+  };
+
+  if (!typesWorker) {
+    typesWorker = new Worker(
+      new URL(
+        "../../../workers/fetch-types/fetch-types.worker.js"
+        // import.meta.url
+      )
+    );
+  }
+
+  Object.keys(dependencies).forEach((name) => {
+    typesWorker.postMessage({
+      name,
+      version: dependencies[name],
+    });
+  });
+
+  const createModule = (names) => {
+    const temp = names.map((el) => `export * from './${el}'`);
+    return temp.join("\n");
+  };
+
+  typesWorker.addEventListener("message", (event) => {
+    // name,
+    // version,
+    // typings: result,
+    const key = `node_modules/${event.data.name}/index.d.ts`;
+    const source = event.data.typings[key];
+
+    // const path = `${MONACO_LIB_PREFIX}${event.data.name}`;
+    const libUri = `file:///node_modules/@types/${event.data.name}/index.d.ts`;
+
+    disposables.push(
+      monaco.languages.typescript.javascriptDefaults.addExtraLib(source, libUri)
+    );
+    disposables.push(
+      monaco.languages.typescript.typescriptDefaults.addExtraLib(source, libUri)
+    );
+
+    // When resolving definitions and references, the editor will try to use created models.
+    // Creating a model for the library allows "peek definition/references" commands to work with the library.
+  });
+
+  return {
+    dispose() {
+      disposables.forEach((d) => d.dispose());
+      if (typesWorker) {
+        typesWorker.terminate();
+      }
+    },
+  };
+}
diff --git a/editor/components/code-editor/monaco-utils/register.ts b/editor/components/code-editor/monaco-utils/register.ts
new file mode 100644
index 00000000..7e49e953
--- /dev/null
+++ b/editor/components/code-editor/monaco-utils/register.ts
@@ -0,0 +1,65 @@
+import * as monaco from "monaco-editor";
+import { Monaco, OnMount } from "@monaco-editor/react";
+// import { registerDocumentPrettier } from "./register-prettier";
+import { registerJsxHighlighter } from "./register-jsx";
+import { registerTypesWorker } from "./register-typings";
+
+type CompilerOptions = monaco.languages.typescript.CompilerOptions;
+
+export const initEditor: OnMount = (editor, monaco) => {
+  console.log("Init editor");
+  registerJsxHighlighter(editor, monaco);
+  // registerDocumentPrettier(editor, monaco);
+};
+
+export const initMonaco = (monaco: Monaco) => {
+  console.log("Init Monaco");
+
+  baseConfigure(monaco);
+
+  const { dispose } = registerTypesWorker(monaco);
+
+  // Dispose all disposables and terminate all workers
+  return () => {
+    dispose();
+  };
+};
+
+const baseConfigure = (monaco: Monaco) => {
+  monaco.languages.typescript.typescriptDefaults.setMaximumWorkerIdleTime(-1);
+  monaco.languages.typescript.javascriptDefaults.setMaximumWorkerIdleTime(-1);
+
+  monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true);
+  monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true);
+  monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
+    noSemanticValidation: true,
+    noSyntaxValidation: false,
+  });
+
+  // compiler options
+  monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
+    target: monaco.languages.typescript.ScriptTarget.Latest,
+    allowNonTsExtensions: true,
+  });
+
+  /**
+   * Configure the typescript compiler to detect JSX and load type definitions
+   */
+
+  const opts: CompilerOptions = {
+    allowJs: true,
+    allowSyntheticDefaultImports: true,
+    alwaysStrict: true,
+    moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
+    noEmit: true,
+    reactNamespace: "React",
+    typeRoots: ["node_modules/@types"],
+    jsx: monaco.languages.typescript.JsxEmit.React,
+    allowNonTsExtensions: true,
+    target: monaco.languages.typescript.ScriptTarget.ES2016,
+    jsxFactory: "React.createElement",
+  };
+
+  monaco.languages.typescript.typescriptDefaults.setCompilerOptions(opts);
+  monaco.languages.typescript.javascriptDefaults.setCompilerOptions(opts);
+};
diff --git a/editor/components/code-editor/monaco.tsx b/editor/components/code-editor/monaco.tsx
index 92538629..1654d27d 100644
--- a/editor/components/code-editor/monaco.tsx
+++ b/editor/components/code-editor/monaco.tsx
@@ -1,7 +1,15 @@
-import React, { useEffect } from "react";
-import Editor, { useMonaco, Monaco } from "@monaco-editor/react";
+import React, { useRef, useEffect } from "react";
+import Editor, {
+  useMonaco,
+  Monaco,
+  OnChange,
+  OnMount,
+} from "@monaco-editor/react";
 import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
 import { MonacoEmptyMock } from "./monaco-mock-empty";
+import { register } from "./monaco-utils";
+
+type ICodeEditor = monaco.editor.IStandaloneCodeEditor;
 
 export interface MonacoEditorProps {
   defaultValue?: string;
@@ -12,14 +20,29 @@ export interface MonacoEditorProps {
 }
 
 export function MonacoEditor(props: MonacoEditorProps) {
+  const instance = useRef<{ editor: ICodeEditor; format: any } | null>(null);
+  const activeModel = useRef<any>();
+
   const monaco: Monaco = useMonaco();
   useEffect(() => {
     if (monaco) {
       setup_react_support(monaco);
-      // monaco.mo
     }
   }, [monaco]);
 
+  const onMount: OnMount = (editor, monaco) => {
+    const format = editor.getAction("editor.action.formatDocument");
+    instance.current = { editor, format };
+
+    activeModel.current = editor.getModel();
+
+    register.initEditor(editor, monaco);
+
+    editor.onDidChangeModelContent(() => {
+      /* add here */
+    });
+  };
+
   return (
     <Editor
       width={props.width}
@@ -27,6 +50,7 @@ export function MonacoEditor(props: MonacoEditorProps) {
       defaultLanguage={
         pollyfill_language(props.defaultLanguage) ?? "typescript"
       }
+      onMount={onMount}
       loading={<MonacoEmptyMock />}
       defaultValue={props.defaultValue ?? "// no content"}
       theme="vs-dark"
diff --git a/editor/package.json b/editor/package.json
index a498c2ff..91447307 100644
--- a/editor/package.json
+++ b/editor/package.json
@@ -41,6 +41,7 @@
     "moment": "^2.29.1",
     "monaco-editor": "^0.24.0",
     "next": "10.0.3",
+    "p-queue": "^7.1.0",
     "pouchdb-adapter-idb": "^7.2.2",
     "re-resizable": "^6.9.1",
     "react": "17.0.1",
diff --git a/editor/workers/fetch-types/fetch-types.worker.js b/editor/workers/fetch-types/fetch-types.worker.js
new file mode 100644
index 00000000..24f559ee
--- /dev/null
+++ b/editor/workers/fetch-types/fetch-types.worker.js
@@ -0,0 +1,282 @@
+/**
+ * Worker to fetch typescript definitions for dependencies.
+ * Credits to @CompuIves & @sidwebworks
+ * https://github.com/CompuIves/codesandbox-client/blob/dcdb4169bcbe3e5aeaebae19ff1d45940c1af834/packages/app/src/app/components/CodeEditor/Monaco/workers/fetch-dependency-typings.js
+ *
+ */
+
+import path from "path";
+
+self.importScripts(
+  "https://cdnjs.cloudflare.com/ajax/libs/typescript/2.4.2/typescript.min.js"
+);
+
+const ROOT_URL = `https://cdn.jsdelivr.net/`;
+
+const fetchCache = new Map();
+
+const doFetch = (url) => {
+  const cached = fetchCache.get(url);
+
+  if (cached) {
+    return cached;
+  }
+
+  const promise = fetch(url)
+    .then((response) => {
+      if (response.status >= 200 && response.status < 300) {
+        return Promise.resolve(response);
+      }
+
+      const error = new Error(response.statusText || response.status);
+
+      return Promise.reject(error);
+    })
+    .then((response) => response.text());
+
+  fetchCache.set(url, promise);
+
+  return promise;
+};
+
+const fetchFromDefinitelyTyped = (dependency, version, fetchedPaths) =>
+  doFetch(
+    `${ROOT_URL}npm/@types/${dependency
+      .replace("@", "")
+      .replace(/\//g, "__")}/index.d.ts`
+  ).then((typings) => {
+    fetchedPaths[`node_modules/${dependency}/index.d.ts`] = typings;
+  });
+
+const getRequireStatements = (title, code) => {
+  const requires = [];
+
+  const sourceFile = self.ts.createSourceFile(
+    title,
+    code,
+    self.ts.ScriptTarget.Latest,
+    true,
+    self.ts.ScriptKind.TS
+  );
+
+  self.ts.forEachChild(sourceFile, (node) => {
+    switch (node.kind) {
+      case self.ts.SyntaxKind.ImportDeclaration: {
+        requires.push(node.moduleSpecifier.text);
+        break;
+      }
+      case self.ts.SyntaxKind.ExportDeclaration: {
+        // For syntax 'export ... from '...'''
+        if (node.moduleSpecifier) {
+          requires.push(node.moduleSpecifier.text);
+        }
+        break;
+      }
+      default: {
+        /* */
+      }
+    }
+  });
+
+  return requires;
+};
+
+const tempTransformFiles = (files) => {
+  const finalObj = {};
+
+  files.forEach((d) => {
+    finalObj[d.name] = d;
+  });
+
+  return finalObj;
+};
+
+const transformFiles = (dir) =>
+  dir.files
+    ? dir.files.reduce((prev, next) => {
+        if (next.type === "file") {
+          return { ...prev, [next.path]: next };
+        }
+
+        return { ...prev, ...transformFiles(next) };
+      }, {})
+    : {};
+
+const getFileMetaData = (dependency, version, depPath) =>
+  doFetch(
+    `https://data.jsdelivr.com/v1/package/npm/${dependency}@${version}/flat`
+  )
+    .then((response) => JSON.parse(response))
+    .then((response) =>
+      response.files.filter((f) => f.name.startsWith(depPath))
+    )
+    .then(tempTransformFiles);
+
+const resolveAppropiateFile = (fileMetaData, relativePath) => {
+  const absolutePath = `/${relativePath}`;
+
+  if (fileMetaData[`${absolutePath}.d.ts`]) return `${relativePath}.d.ts`;
+  if (fileMetaData[`${absolutePath}.ts`]) return `${relativePath}.ts`;
+  if (fileMetaData[absolutePath]) return relativePath;
+  if (fileMetaData[`${absolutePath}/index.d.ts`])
+    return `${relativePath}/index.d.ts`;
+
+  return relativePath;
+};
+
+const getFileTypes = (
+  depUrl,
+  dependency,
+  depPath,
+  fetchedPaths,
+  fileMetaData
+) => {
+  const virtualPath = path.join("node_modules", dependency, depPath);
+
+  if (fetchedPaths[virtualPath]) return null;
+
+  return doFetch(`${depUrl}/${depPath}`).then((typings) => {
+    if (fetchedPaths[virtualPath]) return null;
+
+    fetchedPaths[virtualPath] = typings;
+
+    // Now find all require statements, so we can download those types too
+    return Promise.all(
+      getRequireStatements(depPath, typings)
+        .filter(
+          // Don't add global deps
+          (dep) => dep.startsWith(".")
+        )
+        .map((relativePath) => path.join(path.dirname(depPath), relativePath))
+        .map((relativePath) =>
+          resolveAppropiateFile(fileMetaData, relativePath)
+        )
+        .map((nextDepPath) =>
+          getFileTypes(
+            depUrl,
+            dependency,
+            nextDepPath,
+            fetchedPaths,
+            fileMetaData
+          )
+        )
+    );
+  });
+};
+
+function fetchFromMeta(dependency, version, fetchedPaths) {
+  const depUrl = `https://data.jsdelivr.com/v1/package/npm/${dependency}@${version}/flat`;
+
+  return doFetch(depUrl)
+    .then((response) => JSON.parse(response))
+    .then((meta) => {
+      const filterAndFlatten = (files, filter) =>
+        files.reduce((paths, file) => {
+          if (filter.test(file.name)) {
+            paths.push(file.name);
+          }
+          return paths;
+        }, []);
+
+      let dtsFiles = filterAndFlatten(meta.files, /\.d\.ts$/);
+      if (dtsFiles.length === 0) {
+        // if no .d.ts files found, fallback to .ts files
+        dtsFiles = filterAndFlatten(meta.files, /\.ts$/);
+      }
+
+      if (dtsFiles.length === 0) {
+        throw new Error(`No inline typings found for ${dependency}@${version}`);
+      }
+
+      dtsFiles.forEach((file) => {
+        doFetch(`https://cdn.jsdelivr.net/npm/${dependency}@${version}${file}`)
+          .then((dtsFile) => {
+            fetchedPaths[`node_modules/${dependency}${file}`] = dtsFile;
+          })
+          .catch(() => {});
+      });
+    });
+}
+
+function fetchFromTypings(dependency, version, fetchedPaths) {
+  const depUrl = `${ROOT_URL}npm/${dependency}@${version}`;
+
+  return doFetch(`${depUrl}/package.json`)
+    .then((response) => JSON.parse(response))
+    .then((packageJSON) => {
+      const types = packageJSON.typings || packageJSON.types;
+      if (types) {
+        // Add package.json, since this defines where all types lie
+        fetchedPaths[`node_modules/${dependency}/package.json`] =
+          JSON.stringify(packageJSON);
+
+        // get all files in the specified directory
+        return getFileMetaData(
+          dependency,
+          version,
+          path.join("/", path.dirname(types))
+        ).then((fileData) =>
+          getFileTypes(
+            depUrl,
+            dependency,
+            resolveAppropiateFile(fileData, types),
+            fetchedPaths,
+            fileData
+          )
+        );
+      }
+
+      throw new Error(
+        `No typings field in package.json for ${dependency}@${version}`
+      );
+    });
+}
+
+function fetchDefinitions(name, version) {
+  if (!version) {
+    return Promise.reject(new Error(`No version specified for ${name}`));
+  }
+
+  // Query cache for the defintions
+  const key = `${name}@${version}`;
+
+  // If result is empty, fetch from remote
+  const fetchedPaths = {};
+
+  return fetchFromTypings(name, version, fetchedPaths)
+    .catch(() =>
+      // not available in package.json, try checking meta for inline .d.ts files
+      fetchFromMeta(name, version, fetchedPaths)
+    )
+    .catch(() =>
+      // Not available in package.json or inline from meta, try checking in @types/
+      fetchFromDefinitelyTyped(name, version, fetchedPaths)
+    )
+    .then(() => {
+      if (Object.keys(fetchedPaths).length) {
+        // Also cache the definitions
+
+        return fetchedPaths;
+      } else {
+        throw new Error(`Type definitions are empty for ${key}`);
+      }
+    });
+}
+
+self.addEventListener("message", (event) => {
+  const { name, version } = event.data;
+
+  fetchDefinitions(name, version)
+    .then((result) => {
+      self.postMessage({
+        name,
+        version,
+        typings: result,
+      });
+    })
+    .catch((error) => {
+      if (process.env.NODE_ENV !== "production") {
+        console.error(error);
+      }
+    });
+});
diff --git a/editor/workers/index.js b/editor/workers/index.js
new file mode 100644
index 00000000..c4fa7cec
--- /dev/null
+++ b/editor/workers/index.js
@@ -0,0 +1,41 @@
+// import PQueue from "p-queue";
+
+// export function createWorkerQueue(worker) {
+//   const queue = new PQueue({ concurrency: 1 });
+//   return {
+//     worker,
+//     emit(data) {
+//       queue.clear();
+//       const _id = Math.random().toString(36).substr(2, 5);
+//       worker.postMessage({ _current: _id });
+//       return queue.add(
+//         () =>
+//           new Promise((resolve) => {
+//             function onMessage(event) {
+//               if (event.data._id !== _id) return;
+//               worker.removeEventListener("message", onMessage);
+//               resolve(event.data);
+//             }
+//             worker.addEventListener("message", onMessage);
+//             worker.postMessage({ ...data, _id });
+//           })
+//       );
+//     },
+//     terminate() {
+//       worker.terminate();
+//     },
+//   };
+// }
+
+// export function requestResponse(worker, data) {
+//   return new Promise((resolve) => {
+//     const _id = Math.random().toString(36).substr(2, 5);
+//     function onMessage(event) {
+//       if (event.data._id !== _id) return;
+//       worker.removeEventListener("message", onMessage);
+//       resolve(event.data);
+//     }
+//     worker.addEventListener("message", onMessage);
+//     worker.postMessage({ ...data, _id });
+//   });
+// }
diff --git a/editor/workers/monaco-syntax-highlight/syntax-highlight.worker.js b/editor/workers/monaco-syntax-highlight/syntax-highlight.worker.js
new file mode 100644
index 00000000..52d0c714
--- /dev/null
+++ b/editor/workers/monaco-syntax-highlight/syntax-highlight.worker.js
@@ -0,0 +1,109 @@
+self.importScripts([
+  "https://cdnjs.cloudflare.com/ajax/libs/typescript/2.4.2/typescript.min.js",
+]);
+
+function getLineNumberAndOffset(start, lines) {
+  let line = 0;
+  let offset = 0;
+  while (offset + lines[line] < start) {
+    offset += lines[line] + 1;
+    line += 1;
+  }
+
+  return { line: line + 1, offset };
+}
+
+function nodeToRange(node) {
+  if (
+    typeof node.getStart === "function" &&
+    typeof node.getEnd === "function"
+  ) {
+    return [node.getStart(), node.getEnd()];
+  } else if (
+    typeof node.pos !== "undefined" &&
+    typeof node.end !== "undefined"
+  ) {
+    return [node.pos, node.end];
+  }
+  return [0, 0];
+}
+
+function getNodeType(parent, node) {
+  return Object.keys(parent).find((key) => parent[key] === node);
+}
+
+function getParentRanges(node) {
+  const ranges = [];
+  const [start, end] = nodeToRange(node);
+  let lastEnd = start;
+
+  self.ts.forEachChild(node, (child) => {
+    const [start, end] = nodeToRange(child);
+
+    ranges.push({
+      start: lastEnd,
+      end: start,
+    });
+    lastEnd = end;
+  });
+
+  if (lastEnd !== end) {
+    ranges.push({
+      start: lastEnd,
+      end,
+    });
+  }
+
+  return ranges;
+}
+
+function addChildNodes(node, lines, classifications) {
+  const parentKind = ts.SyntaxKind[node.kind];
+
+  self.ts.forEachChild(node, (id) => {
+    const type = getNodeType(node, id);
+
+    classifications.push(
+      ...getParentRanges(id).map(({ start, end }) => {
+        const { offset, line: startLine } = getLineNumberAndOffset(
+          start,
+          lines
+        );
+        const { line: endLine } = getLineNumberAndOffset(end, lines);
+
+        return {
+          start: start + 1 - offset,
+          end: end + 1 - offset,
+          kind: ts.SyntaxKind[id.kind],
+          parentKind,
+          type,
+          startLine,
+          endLine,
+        };
+      })
+    );
+
+    addChildNodes(id, lines, classifications);
+  });
+}
+
+// Respond to message from parent thread
+self.addEventListener("message", (event) => {
+  let { code, title, version } = event.data;
+  try {
+    const classifications = [];
+    const sourceFile = self.ts.createSourceFile(
+      title,
+      code,
+      self.ts.ScriptTarget.ES6,
+      true
+    );
+    const lines = code.split("\n").map((line) => line.length);
+
+    addChildNodes(sourceFile, lines, classifications);
+
+    self.postMessage({ classifications, version }, { targetOrigin: "*" });
+  } catch (e) {
+    /* Ignore error */
+  }
+});
diff --git a/editor/workers/prettier/prettier.worker.js b/editor/workers/prettier/prettier.worker.js
new file mode 100644
index 00000000..e17d4350
--- /dev/null
+++ b/editor/workers/prettier/prettier.worker.js
@@ -0,0 +1,61 @@
+import prettier from "prettier";
+
+const options = {
+  html: async () => ({
+    parser: "html",
+    plugins: [await import("prettier/parser-html")],
+    printWidth: 90,
+  }),
+
+  css: async () => ({
+    parser: "css",
+    plugins: [await import("prettier/parser-postcss")],
+    printWidth: 100,
+  }),
+
+  javascript: async () => ({
+    parser: "babel",
+    plugins: [await import("prettier/parser-babel")],
+    printWidth: 100,
+    semi: true,
+    useTabs: false,
+    singleQuote: true,
+  }),
+  typescript: async () => ({
+    parser: "babel",
+    plugins: [await import("prettier/parser-babel")],
+    printWidth: 100,
+    semi: true,
+    useTabs: false,
+    singleQuote: true,
+  }),
+};
+
+let current;
+
+addEventListener("message", async (event) => {
+  if (event.data._current) {
+    current = event.data._current;
+    return;
+  }
+
+  function respond(data) {
+    setTimeout(() => {
+      if (event.data._id === current) {
+        postMessage({ _id: event.data._id, ...data });
+      } else {
+        postMessage({ _id: event.data._id, canceled: true });
+      }
+    }, 0);
+  }
+
+  const opts = await options[event.data.language]();
+
+  try {
+    respond({
+      pretty: prettier.format(event.data.text, opts),
+    });
+  } catch (error) {
+    respond({ error });
+  }
+});
diff --git a/yarn.lock b/yarn.lock
index 5318a80e..b5f90fd2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -345,9 +345,9 @@
     js-tokens "^4.0.0"
 
 "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.0", "@babel/parser@^7.16.5", "@babel/parser@^7.7.2":
-  version "7.16.5"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.5.tgz#beb3af702e54d24796341ab9420fb329131ad658"
-  integrity sha512-+Ce7T5iPNWzfu9C1aB5tN3Lyafs5xb3Ic7vBWyZL2KXT3QSdD1dD3CvgOzPmQKoNNRt6uauc0XwNJTQtXC2/Mw==
+  version "7.16.6"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.6.tgz#8f194828193e8fa79166f34a4b4e52f3e769a314"
+  integrity sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==
 
 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.2":
   version "7.16.2"
@@ -1552,9 +1552,9 @@
     "@babel/plugin-syntax-jsx" "^7.2.0"
 
 "@emotion/babel-plugin@^11.2.0", "@emotion/babel-plugin@^11.3.0", "@emotion/babel-plugin@^11.7.1":
-  version "11.7.1"
-  resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.7.1.tgz#853fc4985d89dab0ea8e17af2858473d1b11be7e"
-  integrity sha512-K3/6Y+J/sIAjplf3uIteWLhPuOyuMNnE+iyYnTF/m294vc6IL90kTHp7y8ldZYbpKlP17rpOWDKM9DvTcrOmNQ==
+  version "11.7.2"
+  resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz#fec75f38a6ab5b304b0601c74e2a5e77c95e5fa0"
+  integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==
   dependencies:
     "@babel/helper-module-imports" "^7.12.13"
     "@babel/plugin-syntax-jsx" "^7.12.13"
@@ -2082,9 +2082,9 @@
     dedent "^0.7.0"
 
 "@grpc/grpc-js@^1.3.2":
-  version "1.4.4"
-  resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.4.4.tgz#59336f13d77bc446bbdf2161564a32639288dc5b"
-  integrity sha512-a6222b7Dl6fIlMgzVl7e+NiRoLiZFbpcwvBH2Oli56Bn7W4/3Ld+86hK4ffPn5rx2DlDidmIcvIJiOQXyhv9gA==
+  version "1.4.5"
+  resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.4.5.tgz#0cd840b47180624eeedf066f2cdc422d052401f8"
+  integrity sha512-A6cOzSu7dqXZ7rzvh/9JZf+Jg/MOpLEMP0IdT8pT8hrWJZ6TB4ydN/MRuqOtAugInJe/VQ9F8BPricUpYZSaZA==
   dependencies:
     "@grpc/proto-loader" "^0.6.4"
     "@types/node" ">=12.12.47"
@@ -2684,13 +2684,13 @@
     "@babel/runtime" "^7.13.10"
     "@radix-ui/react-primitive" "0.1.1"
 
-"@radix-ui/react-arrow@0.1.2":
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-0.1.2.tgz#23058bb4cb86662131baad30ce21ce929393818f"
-  integrity sha512-f3aLDQLzcd96yswYoeJdIpOPSw//jbNLTjsrq9ra4c5Atu/Zi4P2icZ1f8qCmNubrG36jSvwuEkcCkTTDLmbeQ==
+"@radix-ui/react-arrow@0.1.3":
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-0.1.3.tgz#17f86eab216c48aff17b13b811569a9bbabaa44d"
+  integrity sha512-9x1gRYdlUD5OUwY7L+M+4FY/YltDSsrNSj8QXGPbxZxL5ghWXB/4lhyIGccCwk/e8ggfmQYv9SRNmn3LavPo3A==
   dependencies:
     "@babel/runtime" "^7.13.10"
-    "@radix-ui/react-primitive" "0.1.2"
+    "@radix-ui/react-primitive" "0.1.3"
 
 "@radix-ui/react-aspect-ratio@0.1.1":
   version "0.1.1"
@@ -2783,15 +2783,15 @@
     "@radix-ui/react-primitive" "0.1.1"
     "@radix-ui/react-slot" "0.1.1"
 
-"@radix-ui/react-collection@0.1.2":
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-0.1.2.tgz#2b757dc7c5aa1aebe0eaf7dda2c46776987f3187"
-  integrity sha512-sEIlbAaOBm6k9Z/tsf0FrHlsscd8u8waHKzlualgN/CIuouy4rKXoVuysevgQvY7h9HPV5x2AekWq6BABTBOkw==
+"@radix-ui/react-collection@0.1.3":
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-0.1.3.tgz#7b584f5db40ce165883b87c383d3bd16c0000d69"
+  integrity sha512-tMBY65l87tj77fMX44EBjm5p8clR6swkcNFr0/dDVdEPC0Vf3fwkv62dezCnZyrRBpkOgZPDOp2kO73hYlCfXw==
   dependencies:
     "@babel/runtime" "^7.13.10"
     "@radix-ui/react-compose-refs" "0.1.0"
     "@radix-ui/react-context" "0.1.1"
-    "@radix-ui/react-primitive" "0.1.2"
+    "@radix-ui/react-primitive" "0.1.3"
     "@radix-ui/react-slot" "0.1.2"
 
 "@radix-ui/react-compose-refs@0.0.5":
@@ -2834,15 +2834,15 @@
     "@radix-ui/react-use-callback-ref" "0.0.5"
 
 "@radix-ui/react-context-menu@^0.1.1":
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-context-menu/-/react-context-menu-0.1.3.tgz#ebb328f9102313a58c7cf568dae39ab437af4dec"
-  integrity sha512-ZSz2h5kuqTL8ntzJUc5r8EqJoO4vjuiCnPYYQfHQT36fL0wQlo3IFOfRo2L28Pvq0TJoqEWXi1ze8f9YSeZ5Qw==
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-context-menu/-/react-context-menu-0.1.4.tgz#d4706fe029f74b3330c6965601ed6a3f9165fb2c"
+  integrity sha512-GWwzAZDGT66b5HQAD4nfhSTih3pxhbEnNfVBerKYSL/74VWHZY6xpXf6peeb4m1zorVvYPMoT45KTO6hAJwTFg==
   dependencies:
     "@babel/runtime" "^7.13.10"
     "@radix-ui/primitive" "0.1.0"
     "@radix-ui/react-context" "0.1.1"
-    "@radix-ui/react-menu" "0.1.3"
-    "@radix-ui/react-primitive" "0.1.2"
+    "@radix-ui/react-menu" "0.1.4"
+    "@radix-ui/react-primitive" "0.1.3"
     "@radix-ui/react-use-callback-ref" "0.1.0"
 
 "@radix-ui/react-context@0.0.5":
@@ -2937,15 +2937,15 @@
     "@radix-ui/react-use-callback-ref" "0.1.0"
     "@radix-ui/react-use-escape-keydown" "0.1.0"
 
-"@radix-ui/react-dismissable-layer@0.1.2":
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.2.tgz#10192ca6f28f1add825445afdfc23798cfd9342e"
-  integrity sha512-qQ8lK2PW8P3qEjJw3cKauwPNOZ2eaIffp9/WDOh0BjKg0YOf3RdLB3BuFwfULs5avo5rC4u85D0NQuw0IsPplQ==
+"@radix-ui/react-dismissable-layer@0.1.3":
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.3.tgz#d427c7520c3799d2b957e40e7d67045d96120356"
+  integrity sha512-3veE7M8K13Qb+6+tC3DHWmWV9VMuuRoZvRLdrvz7biSraK/qkGBN4LbKZDaTdw2D2HS7RNpSd/sF8pFd3TaAgA==
   dependencies:
     "@babel/runtime" "^7.13.10"
     "@radix-ui/primitive" "0.1.0"
     "@radix-ui/react-context" "0.1.1"
-    "@radix-ui/react-primitive" "0.1.2"
+    "@radix-ui/react-primitive" "0.1.3"
     "@radix-ui/react-use-body-pointer-events" "0.1.0"
     "@radix-ui/react-use-callback-ref" "0.1.0"
     "@radix-ui/react-use-escape-keydown" "0.1.0"
@@ -3022,14 +3022,14 @@
     "@radix-ui/react-primitive" "0.1.1"
     "@radix-ui/react-use-callback-ref" "0.1.0"
 
-"@radix-ui/react-focus-scope@0.1.2":
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.2.tgz#a25da04a5e3ccccc34707837153a5dcb957e86fb"
-  integrity sha512-oYtrTi5in6YWf2H6PEzpHu9upFZXJ1GDmWAZ3TE78d2YBstCykKNTRX/pAmNonxI8Men607eKNbVBHPROjprhA==
+"@radix-ui/react-focus-scope@0.1.3":
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.3.tgz#b1cc825b6190001d731417ed90d192d13b41bce1"
+  integrity sha512-bKi+lw14SriQqYWMBe13b/wvxSqYMC+3FylMUEwOKA6JrBoldpkhX5XffGDdpDRTTpjbncdH3H7d1PL5Bs7Ikg==
   dependencies:
     "@babel/runtime" "^7.13.10"
     "@radix-ui/react-compose-refs" "0.1.0"
-    "@radix-ui/react-primitive" "0.1.2"
+    "@radix-ui/react-primitive" "0.1.3"
     "@radix-ui/react-use-callback-ref" "0.1.0"
 
 "@radix-ui/react-icons@1.0.3", "@radix-ui/react-icons@^1.0.3":
@@ -3052,10 +3052,10 @@
     "@babel/runtime" "^7.13.10"
     "@radix-ui/react-context" "0.1.1"
 
-"@radix-ui/react-id@0.1.3":
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.1.3.tgz#007c41749628ec6c2c801ad0b8f0a454bb181ae3"
-  integrity sha512-kA7erDg8S/bad9O6RTC+laW11gm2pvmEqlZA+rvzI+WEkQXStIgnVp+wA420be4q20UiLQw9cmIP01AIhDVdZQ==
+"@radix-ui/react-id@0.1.4":
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.1.4.tgz#4cd6126e6ac8a43ebe6d52948a068b797cc9ad71"
+  integrity sha512-/hq5m/D0ZfJWOS7TLF+G0l08KDRs87LBE46JkAvgKkg1fW4jkucx9At9D9vauIPSbdNmww5kXEp566hMlA8eXA==
   dependencies:
     "@babel/runtime" "^7.13.10"
     "@radix-ui/react-use-layout-effect" "0.1.0"
@@ -3119,25 +3119,25 @@
     aria-hidden "^1.1.1"
     react-remove-scroll "^2.4.0"
 
-"@radix-ui/react-menu@0.1.3":
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-0.1.3.tgz#08f80cacba749f67b64f51702b16a941c96fec84"
-  integrity sha512-VIzXxzgomYijUIb4Xg6HDDEhgZG02jkLXPkKG/GtSk4/M3BjfwhKZgNJ5/IywwFkZM2EJ0HgnnaEAxrs6AcMoQ==
+"@radix-ui/react-menu@0.1.4":
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-0.1.4.tgz#ed9aca2c2328038e2210e629228db6e3c67495c1"
+  integrity sha512-50HvBojjj2CrwIxcECRF9MdReoALRdpG7vtCAGbYs3eciIOLqtP6+Dx/sVz1YWe6Fsree/5vFQXZGImZYY/3TQ==
   dependencies:
     "@babel/runtime" "^7.13.10"
     "@radix-ui/primitive" "0.1.0"
-    "@radix-ui/react-collection" "0.1.2"
+    "@radix-ui/react-collection" "0.1.3"
     "@radix-ui/react-compose-refs" "0.1.0"
     "@radix-ui/react-context" "0.1.1"
-    "@radix-ui/react-dismissable-layer" "0.1.2"
+    "@radix-ui/react-dismissable-layer" "0.1.3"
     "@radix-ui/react-focus-guards" "0.1.0"
-    "@radix-ui/react-focus-scope" "0.1.2"
-    "@radix-ui/react-id" "0.1.3"
-    "@radix-ui/react-popper" "0.1.2"
-    "@radix-ui/react-portal" "0.1.2"
+    "@radix-ui/react-focus-scope" "0.1.3"
+    "@radix-ui/react-id" "0.1.4"
+    "@radix-ui/react-popper" "0.1.3"
+    "@radix-ui/react-portal" "0.1.3"
     "@radix-ui/react-presence" "0.1.1"
-    "@radix-ui/react-primitive" "0.1.2"
-    "@radix-ui/react-roving-focus" "0.1.3"
+    "@radix-ui/react-primitive" "0.1.3"
+    "@radix-ui/react-roving-focus" "0.1.4"
     "@radix-ui/react-use-callback-ref" "0.1.0"
     "@radix-ui/react-use-direction" "0.1.0"
     aria-hidden "^1.1.1"
@@ -3235,17 +3235,17 @@
     "@radix-ui/react-use-size" "0.1.0"
     "@radix-ui/rect" "0.1.1"
 
-"@radix-ui/react-popper@0.1.2":
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-0.1.2.tgz#9d297649706ff183a65f77110340ca45a008b768"
-  integrity sha512-A7mmodBJckhyi/wmKIQBldX8rjLaKB0JPEfFgGBr9U1Srb2Y330YeXQ0vZH4LpEan2fLeEDNdhSsz8kDZAu9DA==
+"@radix-ui/react-popper@0.1.3":
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-0.1.3.tgz#a93bdd72845566007e5f3868caddd62318bb781e"
+  integrity sha512-2OV2YaJv7iTZexJY3HJ7B6Fs1A/3JXd3fRGU4JY0guACfGMD1C/jSgds505MKQOTiHE/quI6j3/q8yfzFjJR9g==
   dependencies:
     "@babel/runtime" "^7.13.10"
     "@radix-ui/popper" "0.1.0"
-    "@radix-ui/react-arrow" "0.1.2"
+    "@radix-ui/react-arrow" "0.1.3"
     "@radix-ui/react-compose-refs" "0.1.0"
     "@radix-ui/react-context" "0.1.1"
-    "@radix-ui/react-primitive" "0.1.2"
+    "@radix-ui/react-primitive" "0.1.3"
     "@radix-ui/react-use-rect" "0.1.1"
     "@radix-ui/react-use-size" "0.1.0"
     "@radix-ui/rect" "0.1.1"
@@ -3279,13 +3279,13 @@
     "@radix-ui/react-primitive" "0.1.1"
     "@radix-ui/react-use-layout-effect" "0.1.0"
 
-"@radix-ui/react-portal@0.1.2":
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-0.1.2.tgz#a47059fe04ead0749d879818a7cbe9e7c751c4d5"
-  integrity sha512-rLSe5aeJ7yWD6CuUyg+U9wCoMLleRyxQS67eqALzLW7zk0glB5q5x2ihAEjocZH2Tng9v5QkYaLyh2+sO3TMRA==
+"@radix-ui/react-portal@0.1.3":
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-0.1.3.tgz#56826e789b3d4e37983f6d23666e3f1b1b9ee358"
+  integrity sha512-DrV+sPYLs0HhmX5/b7yRT6nLM9Nl6FtQe2KUG+46kiCOKQ+0XzNMO5hmeQtyq0mRf/qlC02rFu6OMsWpIqVsJg==
   dependencies:
     "@babel/runtime" "^7.13.10"
-    "@radix-ui/react-primitive" "0.1.2"
+    "@radix-ui/react-primitive" "0.1.3"
     "@radix-ui/react-use-layout-effect" "0.1.0"
 
 "@radix-ui/react-presence@0.0.14":
@@ -3354,10 +3354,10 @@
     "@babel/runtime" "^7.13.10"
     "@radix-ui/react-slot" "0.1.1"
 
-"@radix-ui/react-primitive@0.1.2":
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-0.1.2.tgz#ca20fb15fc83124eead186333f917145e5e53378"
-  integrity sha512-mVgeBkuNRZRCzHuDm2DWjZEIs3ntp4m3GtKWPXUn+SgmJXIIpVLt7KhvEmNkgXURq/DJgxG9GmJJMXkACioH/A==
+"@radix-ui/react-primitive@0.1.3":
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-0.1.3.tgz#585c35ef2ec06bab0ea9e0fc5c916e556661b881"
+  integrity sha512-fcyADaaAx2jdqEDLsTs6aX50S3L1c9K9CC6XMpJpuXFJCU4n9PGTFDZRtY2gAoXXoRCPIBsklCopSmGb6SsDjQ==
   dependencies:
     "@babel/runtime" "^7.13.10"
     "@radix-ui/react-slot" "0.1.2"
@@ -3429,18 +3429,18 @@
     "@radix-ui/react-use-callback-ref" "0.1.0"
     "@radix-ui/react-use-controllable-state" "0.1.0"
 
-"@radix-ui/react-roving-focus@0.1.3":
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.3.tgz#7dcbf5b8cd79165a0d10e61170ac2a46b1293569"
-  integrity sha512-9VAvw8z3Nufw7PD8u32tJ0VuDi+5PiPlccRNdrtkdir/M4i/9B9D7WSZyzsqusVLFUo8y9Sj61eJIvGcUG6khw==
+"@radix-ui/react-roving-focus@0.1.4":
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.4.tgz#693ca3eaab153feabe37f9d50987d6d2911cf819"
+  integrity sha512-zaixcAxRcWQliUSx6l9rdfJhvcbuY7Tb4Emb7H4DWCTx1kenXH8+n9mwa8gaSIJLLSSSMzBpQATlpFw9xv/bJQ==
   dependencies:
     "@babel/runtime" "^7.13.10"
     "@radix-ui/primitive" "0.1.0"
-    "@radix-ui/react-collection" "0.1.2"
+    "@radix-ui/react-collection" "0.1.3"
     "@radix-ui/react-compose-refs" "0.1.0"
     "@radix-ui/react-context" "0.1.1"
-    "@radix-ui/react-id" "0.1.3"
-    "@radix-ui/react-primitive" "0.1.2"
+    "@radix-ui/react-id" "0.1.4"
+    "@radix-ui/react-primitive" "0.1.3"
     "@radix-ui/react-use-callback-ref" "0.1.0"
     "@radix-ui/react-use-controllable-state" "0.1.0"
 
@@ -3834,26 +3834,26 @@
     "@babel/runtime" "^7.13.10"
 
 "@react-spring/animated@~9.3.0":
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.3.1.tgz#ffc4706121e8406efeaeacb407b42b5022943b46"
-  integrity sha512-23YaERZ++BwZ8F8PxPFqrpOwp/JZun1Pj6aHZtPAU42j5LycBRasT9XMw7Eyr7zNFhT+rl3R3wFfd4WX6Ax+UA==
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.3.2.tgz#bda85e92e9e9b6861c259f2dacb54270a37b0f39"
+  integrity sha512-pBvKydRHbTzuyaeHtxGIOvnskZxGo/S5/YK1rtYm88b9NQZuZa95Rgd3O0muFL+99nvBMBL8cvQGD0UJmsqQsg==
   dependencies:
     "@react-spring/shared" "~9.3.0"
     "@react-spring/types" "~9.3.0"
 
 "@react-spring/core@~9.3.0":
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.3.1.tgz#b98e1dca1eb4871dec75fdab350327e8a5222865"
-  integrity sha512-8rmfmEHLHGtF1CUiXRn64YJqsXNxv2cGX8oNnBnsuoE33c48Zc34t2VIMB4R9q5zwIUCvDBGfiEenA8ZAPxqOQ==
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.3.2.tgz#d1dc5810666ac18550db89c58567f28fbe04fb07"
+  integrity sha512-kMRjkgdQ6LJ0lmb/wQlONpghaMT83UxglXHJC6m9kZS/GKVmN//TYMEK85xN1rC5Gg+BmjG61DtLCSkkLDTfNw==
   dependencies:
     "@react-spring/animated" "~9.3.0"
     "@react-spring/shared" "~9.3.0"
     "@react-spring/types" "~9.3.0"
 
 "@react-spring/konva@~9.3.0":
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/@react-spring/konva/-/konva-9.3.1.tgz#7a915c1c912a81dc27d1a1bc31eb47c0a2a0c643"
-  integrity sha512-woG2DeDcUlz5hB8g9pA/tyUWU6dMrAzyUsNiBWVCyI9UqKA7CUKjz+ODOUi+hS++3Kz7kZSr3u0zzHHfxvoTPQ==
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/@react-spring/konva/-/konva-9.3.2.tgz#726d567c68bdd4b74c8683764c662fae08321910"
+  integrity sha512-LLpmj6bj7Z2LYZDM75JkQ+dNasvdH56+th7VXcoMcOouAcogfI+iJ5tIFFz4yI2f2oTJzy/RkjeovmHMYIP+KQ==
   dependencies:
     "@react-spring/animated" "~9.3.0"
     "@react-spring/core" "~9.3.0"
@@ -3861,9 +3861,9 @@
     "@react-spring/types" "~9.3.0"
 
 "@react-spring/native@~9.3.0":
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/@react-spring/native/-/native-9.3.1.tgz#e1ac9d04d833b8d97e2d63630c4204f71915a29a"
-  integrity sha512-NAC1wHIUvy1umCVQRxcS+31Dmr9NszBY06sHy3jR8/HVuKNtaDUARVF3AYL/HfbIy4m6yR3tcIkM2NQ0SO+rZA==
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/@react-spring/native/-/native-9.3.2.tgz#0d2e4e9f3383e70c7568a5dd94937794bdc669f8"
+  integrity sha512-UQS07N639JIEJBGNGiFre6el6Sk5QEcOQeyBFyA7JmT4ewpRH7mM6JQ7Sd3DNduplsFmypIsWg+9+lmE2d52Rw==
   dependencies:
     "@react-spring/animated" "~9.3.0"
     "@react-spring/core" "~9.3.0"
@@ -3871,22 +3871,22 @@
     "@react-spring/types" "~9.3.0"
 
 "@react-spring/rafz@~9.3.0":
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/@react-spring/rafz/-/rafz-9.3.1.tgz#8dd6a598ffea487252b75d05d199e4aca5ea9d5e"
-  integrity sha512-fEBMCarGVl+/2kdO+g6Zig4F+3ymwmcGN8S71gb1c7Cbbxb87kviPz8EhshfIHoiLeJPGlqwcuGbxNmZbBamvA==
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/@react-spring/rafz/-/rafz-9.3.2.tgz#0cbd296cd17bbf1e7e49d3b3616884e026d5fb67"
+  integrity sha512-YtqNnAYp5bl6NdnDOD5TcYS40VJmB+Civ4LPtcWuRPKDAOa/XAf3nep48r0wPTmkK936mpX8aIm7h+luW59u5A==
 
 "@react-spring/shared@~9.3.0":
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.3.1.tgz#e7f22a4b8f5fea4491fa6a24c108db5abd19ddba"
-  integrity sha512-jhPpxzURGo6Nty90ex1lkxmZae7w/VAbnGmb/nXcYoZwSoNR+W2aAd00iXsh2ZGz6MgoJOsc495JeG3uC7Am8A==
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.3.2.tgz#967ce1d8a16d820a99e6eeb2a8f7ca9311d9dfa0"
+  integrity sha512-ypGQQ8w7mWnrELLon4h6mBCBxdd8j1pgLzmHXLpTC/f4ya2wdP+0WIKBWXJymIf+5NiTsXgSJra5SnHP5FBY+A==
   dependencies:
     "@react-spring/rafz" "~9.3.0"
     "@react-spring/types" "~9.3.0"
 
 "@react-spring/three@~9.3.0":
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/@react-spring/three/-/three-9.3.1.tgz#91a50851639c5a88fed8f76b4e25ff388d2b24e7"
-  integrity sha512-40iRIX2DrY+a81hIliOog6TMg/ZAtHGeZr95r0vKAsl+iX1g9Hs8XCS4wTeQIUgydZpbpShk/JL6mkcstEfBdw==
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/@react-spring/three/-/three-9.3.2.tgz#e4321c1253077661b1a3de74d8a38a167368ef23"
+  integrity sha512-nZHHjOl4GksoOFNTwvP4h5bACm5OymCUsR3nejWFigqCPep8prUHaawX4kZRwfUbWTYgkp15yM5hy7BkWNN16A==
   dependencies:
     "@react-spring/animated" "~9.3.0"
     "@react-spring/core" "~9.3.0"
@@ -3894,14 +3894,14 @@
     "@react-spring/types" "~9.3.0"
 
 "@react-spring/types@~9.3.0":
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/@react-spring/types/-/types-9.3.1.tgz#20f392ecad15a1ea6c0865ffe86ca5016c05a278"
-  integrity sha512-W/YMJMX35XgGGzX0gKORBTwnvQ+1loDOFN3XlZkW5fgpEY+7VkRUpPyqPWXQr3n6lHrsLmHIGdpznqZi54ACTQ==
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/@react-spring/types/-/types-9.3.2.tgz#0277d436e50d7a824897dd7bb880f4842fbcd0fe"
+  integrity sha512-u+IK9z9Re4hjNkBYKebZr7xVDYTai2RNBsI4UPL/k0B6lCNSwuqWIXfKZUDVlMOeZHtDqayJn4xz6HcSkTj3FQ==
 
 "@react-spring/web@~9.3.0":
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/@react-spring/web/-/web-9.3.1.tgz#5b377ba7ad52e746c2b59e2738c021de3f219d0b"
-  integrity sha512-sisZIgFGva/Z+xKWPSfXpukF0AP3kR9ALTxlHL87fVotMUCJX5vtH/YlVcywToEFwTHKt3MpI5Wy2M+vgVEeaw==
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/@react-spring/web/-/web-9.3.2.tgz#07620c17bf50b5b0b8bbf9cd8f1312d13778b207"
+  integrity sha512-zzM95rqanap6s0udRCoI4gerONjQjyI6I0h23UZ0X36w5sXmuzv/tBtjGPbsASo377EGM7tRIg9po1KHwb6yQg==
   dependencies:
     "@react-spring/animated" "~9.3.0"
     "@react-spring/core" "~9.3.0"
@@ -3909,9 +3909,9 @@
     "@react-spring/types" "~9.3.0"
 
 "@react-spring/zdog@~9.3.0":
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/@react-spring/zdog/-/zdog-9.3.1.tgz#70fccd80c35248217de6252c4c2ffca16b4cff2f"
-  integrity sha512-QflA/fII9zWe9CSOA8QGSLMjUwyrtD1TX6YVzUSn/nlr2f7PlZPijdpdu9Cvdirgss472cUS7cRIUfll0TepqA==
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/@react-spring/zdog/-/zdog-9.3.2.tgz#e25307cda0c7171119f8f536f10ce25ef607c372"
+  integrity sha512-E8MtTG4kNBcW/sEu0Im7L2FZXmhZDfeHSNbaL35cebfBlL5iI6+Pdlr7A/RPJ2pCUUKJRLlxYu3DVTuaqwf6hQ==
   dependencies:
     "@react-spring/animated" "~9.3.0"
     "@react-spring/core" "~9.3.0"
@@ -4037,9 +4037,9 @@
     "@types/babel__traverse" "*"
 
 "@types/babel__generator@*":
-  version "7.6.3"
-  resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5"
-  integrity sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==
+  version "7.6.4"
+  resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7"
+  integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==
   dependencies:
     "@babel/types" "^7.0.0"
 
@@ -4142,9 +4142,9 @@
     "@types/ms" "*"
 
 "@types/express-serve-static-core@^4.17.18":
-  version "4.17.26"
-  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz#5d9a8eeecb9d5f9d7fc1d85f541512a84638ae88"
-  integrity sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==
+  version "4.17.27"
+  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.27.tgz#7a776191e47295d2a05962ecbb3a4ce97e38b401"
+  integrity sha512-e/sVallzUTPdyOTiqi8O8pMdBBphscvI6E4JYaKlja4Lm+zh7UFSSdW5VMkRbhDtmrONqOUHOXRguPsDckzxNA==
   dependencies:
     "@types/node" "*"
     "@types/qs" "*"
@@ -4175,9 +4175,9 @@
     is-my-json-valid "*"
 
 "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
-  integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44"
+  integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==
 
 "@types/istanbul-lib-report@*":
   version "3.0.0"
@@ -4244,21 +4244,26 @@
   resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
   integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
 
-"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@^16.10.3", "@types/node@^16.11.7", "@types/node@^16.3.3":
-  version "16.11.12"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.12.tgz#ac7fb693ac587ee182c3780c26eb65546a1a3c10"
-  integrity sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==
+"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
+  version "17.0.5"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.5.tgz#57ca67ec4e57ad9e4ef5a6bab48a15387a1c83e0"
+  integrity sha512-w3mrvNXLeDYV1GKTZorGJQivK6XLCoGwpnyJFbJVK/aTBQUxOCaa/GlFAAN3OTDFcb7h5tiFG+YXCO2By+riZw==
 
 "@types/node@^14.14.37":
-  version "14.18.0"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.0.tgz#98df2397f6936bfbff4f089e40e06fa5dd88d32a"
-  integrity sha512-0GeIl2kmVMXEnx8tg1SlG6Gg8vkqirrW752KqolYo1PHevhhZN3bhJ67qHj+bQaINhX0Ra3TlWwRvMCd9iEfNQ==
+  version "14.18.3"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.3.tgz#b3682cfd9d5542b025df13233d073cb4347f63f3"
+  integrity sha512-GtTH2crF4MtOIrrAa+jgTV9JX/PfoUCYr6MiZw7O/dkZu5b6gm5dc1nAL0jwGo4ortSBBtGyeVaxdC8X6V+pLg==
 
 "@types/node@^15.12.1", "@types/node@^15.6.0":
   version "15.14.9"
   resolved "https://registry.yarnpkg.com/@types/node/-/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa"
   integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==
 
+"@types/node@^16.10.3", "@types/node@^16.11.7", "@types/node@^16.3.3":
+  version "16.11.17"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.17.tgz#ae146499772e33fc6382e1880bc567e41a528586"
+  integrity sha512-C1vTZME8cFo8uxY2ui41xcynEotVkczIVI5AjLmy5pkpBv/FtG+jhtOlfcPysI8VRVwoOMv6NJm44LGnoMSWkw==
+
 "@types/object-path@0.11.1":
   version "0.11.1"
   resolved "https://registry.yarnpkg.com/@types/object-path/-/object-path-0.11.1.tgz#eea5b357518597fc9c0a067ea3147f599fc1514f"
@@ -4319,9 +4324,9 @@
     "@types/react" "*"
 
 "@types/react-virtualized@^9.21.13":
-  version "9.21.15"
-  resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.15.tgz#349a4f9774504e514ea4c8ebbbfe6cc8db17f045"
-  integrity sha512-R4ntUW+Y/a7RgRpfeYz3iRe+kaDWtXieMeQum4AoYjjZsR/QhpKqFu4muSBhzA7OHJHd6qA0KkeTzxj5ah5tmQ==
+  version "9.21.16"
+  resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.16.tgz#5e33c7e8a7c187f2b6d542132fc7a1d132b34f9d"
+  integrity sha512-25QMrouz1VKq5T68+9JfRq3GP4JmN20ARi+hl5z7NMmriy07XmGd1Yh3I4EIZjmifpXhHZoQS/ny2fzZRyiAiw==
   dependencies:
     "@types/prop-types" "*"
     "@types/react" "*"
@@ -4334,9 +4339,9 @@
     "@types/react" "*"
 
 "@types/react@*", "@types/react@^17.0.14", "@types/react@^17.0.3":
-  version "17.0.37"
-  resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.37.tgz#6884d0aa402605935c397ae689deed115caad959"
-  integrity sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg==
+  version "17.0.38"
+  resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.38.tgz#f24249fefd89357d5fa71f739a686b8d7c7202bd"
+  integrity sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ==
   dependencies:
     "@types/prop-types" "*"
     "@types/scheduler" "*"
@@ -4691,9 +4696,9 @@ acorn@^7.1.1:
   integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
 
 acorn@^8.2.4:
-  version "8.6.0"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895"
-  integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==
+  version "8.7.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
+  integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
 
 adjust-sourcemap-loader@3.0.0:
   version "3.0.0"
@@ -5417,10 +5422,10 @@ browserslist@4.14.6:
     escalade "^3.1.1"
     node-releases "^1.1.65"
 
-browserslist@^4.17.5, browserslist@^4.18.1:
-  version "4.19.0"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.0.tgz#5f02742ac2b86dde56ae4cef7be2b003e47b1ee0"
-  integrity sha512-JGHzm73ei2OnAcobcQ61GXNnN6vDCg5Oz5MayudL+FyzjoLnCzUWnuLtDLMIYw8aXgQzzdCZMVky+fftD5jbtA==
+browserslist@^4.17.5, browserslist@^4.19.1:
+  version "4.19.1"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3"
+  integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==
   dependencies:
     caniuse-lite "^1.0.30001286"
     electron-to-chromium "^1.4.17"
@@ -5642,9 +5647,9 @@ camelize@^1.0.0:
   integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
 
 caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001113, caniuse-lite@^1.0.30001154, caniuse-lite@^1.0.30001286:
-  version "1.0.30001286"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001286.tgz#3e9debad420419618cfdf52dc9b6572b28a8fff6"
-  integrity sha512-zaEMRH6xg8ESMi2eQ3R4eZ5qw/hJiVsO/HlLwniIwErij0JDr9P+8V4dtx1l+kLq6j3yy8l8W4fst1lBnat5wQ==
+  version "1.0.30001294"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001294.tgz#4849f27b101fd59ddee3751598c663801032533d"
+  integrity sha512-LiMlrs1nSKZ8qkNhpUf5KD0Al1KCBE3zaT7OLOwEkagXMEDij98SiOovn9wxVGQpklk9vVC/pUSqgYmkmKOS8g==
 
 capture-stack-trace@^1.0.0:
   version "1.0.1"
@@ -5864,9 +5869,9 @@ code-point-at@^1.0.0:
   integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
 
 codemirror@^5.61.0:
-  version "5.64.0"
-  resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.64.0.tgz#182eec65b62178e3cd1de8f9d88ab819cfe5f625"
-  integrity sha512-fqr6CtDQdJ6iNMbD8NX2gH2G876nNDk+TO1rrYkgWnqQdO3O1Xa9tK6q+psqhJJgE5SpbaDcgdfLmukoUVE8pg==
+  version "5.65.0"
+  resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.0.tgz#50344359393579f526ca53797e510ff75477117f"
+  integrity sha512-gWEnHKEcz1Hyz7fsQWpK7P0sPI2/kSkRX2tc7DFA6TmZuDN75x/1ejnH/Pn8adYKrLEA1V2ww6L00GudHZbSKw==
 
 codesandbox-import-util-types@^2.2.3:
   version "2.2.3"
@@ -6127,17 +6132,17 @@ copy-descriptor@^0.1.0:
   integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
 
 core-js-compat@^3.18.0, core-js-compat@^3.19.1:
-  version "3.19.3"
-  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.19.3.tgz#de75e5821c5ce924a0a1e7b7d5c2cb973ff388aa"
-  integrity sha512-59tYzuWgEEVU9r+SRgceIGXSSUn47JknoiXW6Oq7RW8QHjXWz3/vp8pa7dbtuVu40sewz3OP3JmQEcDdztrLhA==
+  version "3.20.1"
+  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.20.1.tgz#96917b4db634fbbbc7b36575b2e8fcbf7e4f9691"
+  integrity sha512-AVhKZNpqMV3Jz8hU0YEXXE06qoxtQGsAqU0u1neUngz5IusDJRX/ZJ6t3i7mS7QxNyEONbCo14GprkBrxPlTZA==
   dependencies:
-    browserslist "^4.18.1"
+    browserslist "^4.19.1"
     semver "7.0.0"
 
 core-js-pure@^3.19.0:
-  version "3.19.3"
-  resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.19.3.tgz#c69b2b36b58927317824994b532ec3f0f7e49607"
-  integrity sha512-N3JruInmCyt7EJj5mAq3csCgGYgiSqu7p7TQp2KOztr180/OAIxyIvL1FCjzgmQk/t3Yniua50Fsak7FShI9lA==
+  version "3.20.1"
+  resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.20.1.tgz#f7a2c62f98de83e4da8fca7b78846d3a2f542145"
+  integrity sha512-yeNNr3L9cEBwNy6vhhIJ0nko7fE7uFO6PgawcacGt2VWep4WqQx0RiqlkgSP7kqUMC1IKdfO9qPeWXcUheHLVQ==
 
 core-js@3.6.5:
   version "3.6.5"
@@ -6950,9 +6955,9 @@ ee-first@1.1.1:
   integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
 
 electron-to-chromium@^1.3.585, electron-to-chromium@^1.4.17:
-  version "1.4.17"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.17.tgz#16ec40f61005582d5d41fac08400a254dccfb85f"
-  integrity sha512-zhk1MravPtq/KBhmGB7TLBILmXTgRG9TFSI3qS3DbgyfHzIl72iiTE37r/BHIbPCJJlWIo5rySyxiH4vWhu2ZA==
+  version "1.4.29"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.29.tgz#a9b85ab888d0122124c9647c04d8dd246fae94b6"
+  integrity sha512-N2Jbwxo5Rum8G2YXeUxycs1sv4Qme/ry71HG73bv8BvZl+I/4JtRgK/En+ST/Wh/yF1fqvVCY4jZBgMxnhjtBA==
 
 elliptic@^6.5.3:
   version "6.5.4"
@@ -7288,6 +7293,11 @@ event-target-shim@^5.0.0:
   resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
   integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
 
+eventemitter3@^4.0.7:
+  version "4.0.7"
+  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+  integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
+
 events@^3.0.0:
   version "3.3.0"
   resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
@@ -7712,9 +7722,9 @@ fragment-cache@^0.2.1:
     map-cache "^0.2.2"
 
 framer-motion@^5.3.1:
-  version "5.4.5"
-  resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-5.4.5.tgz#180047afe6d4e41b8b69eb76cfad13d7a0351073"
-  integrity sha512-OjKfSMO22a9bTedhQ4diwZWCcmwoZmfrkalv4adhHTH2/cXa2eoFAmmPzs6aNpENbMrn47YmlWGwZtYNycXFLg==
+  version "5.5.5"
+  resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-5.5.5.tgz#2cc9345e720ec1b93189ee76423799c72a3224b4"
+  integrity sha512-+LPAF5ddo02qKh+MK4h1ChwqUFvrLkK1NDWwrHy+MuCVmQDGgiFNHvwqOSklTDGkEtbio3dCOEDy23+ZyNAa9g==
   dependencies:
     framesync "6.0.1"
     hey-listen "^1.0.8"
@@ -8989,9 +8999,9 @@ istanbul-lib-source-maps@^4.0.0:
     source-map "^0.6.1"
 
 istanbul-reports@^3.0.2:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.1.tgz#7085857f17d2441053c6ce5c3b8fdf6882289397"
-  integrity sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw==
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.2.tgz#b80e13cbab0120e1c367ebaa099862361aed5ead"
+  integrity sha512-0gHxuT1NNC0aEIL1zbJ+MTgPbbHhU77eJPuU35WKA7TgXiSNlCAx4PENoMrH0Or6M2H80TaZcWKhM0IK6V8gRw==
   dependencies:
     html-escaper "^2.0.0"
     istanbul-lib-report "^3.0.0"
@@ -10579,9 +10589,9 @@ object-copy@^0.1.0:
     kind-of "^3.0.3"
 
 object-inspect@^1.11.0, object-inspect@^1.9.0:
-  version "1.11.1"
-  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.1.tgz#d4bd7d7de54b9a75599f59a00bd698c1f1c6549b"
-  integrity sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==
+  version "1.12.0"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
+  integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==
 
 object-is@^1.0.1:
   version "1.1.5"
@@ -10759,6 +10769,19 @@ p-locate@^4.1.0:
   dependencies:
     p-limit "^2.2.0"
 
+p-queue@^7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-7.1.0.tgz#c2bb28f8dc0ebf3fadb985b8706cf2ce5fe5f275"
+  integrity sha512-V+0vPJbhYkBqknPp0qnaz+dWcj8cNepfXZcsVIVEHPbFQXMPwrzCNIiM4FoxGtwHXtPzVCPHDvqCr1YrOJX2Gw==
+  dependencies:
+    eventemitter3 "^4.0.7"
+    p-timeout "^5.0.0"
+
+p-timeout@^5.0.0:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-5.0.2.tgz#d12964c4b2f988e15f72b455c2c428d82a0ec0a0"
+  integrity sha512-sEmji9Yaq+Tw+STwsGAE56hf7gMy9p0tQfJojIAamB7WHJYJKf1qlsg9jqBWG8q9VCxKPhZaP/AcXwEoBcYQhQ==
+
 p-try@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
@@ -11165,9 +11188,9 @@ postcss-safe-parser@4.0.2:
     postcss "^7.0.26"
 
 postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
-  version "6.0.7"
-  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.7.tgz#48404830a635113a71fd79397de8209ed05a66fc"
-  integrity sha512-U+b/Deoi4I/UmE6KOVPpnhS7I7AYdKbhGcat+qTQ27gycvaACvNEw11ba6RrkwVmDVRW7sigWgLj4/KbbJjeDA==
+  version "6.0.8"
+  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz#f023ed7a9ea736cd7ef70342996e8e78645a7914"
+  integrity sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==
   dependencies:
     cssesc "^3.0.0"
     util-deprecate "^1.0.2"
@@ -11549,7 +11572,7 @@ prompts@^2.0.1:
     kleur "^3.0.3"
     sisteransi "^1.0.5"
 
-prop-types@15.7.2, prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
+prop-types@15.7.2:
   version "15.7.2"
   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
   integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -11558,6 +11581,15 @@ prop-types@15.7.2, prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.7, pro
     object-assign "^4.1.1"
     react-is "^16.8.1"
 
+prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
+  version "15.8.0"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.0.tgz#d237e624c45a9846e469f5f31117f970017ff588"
+  integrity sha512-fDGekdaHh65eI3lMi5OnErU6a8Ighg2KjcjQxO7m8VHyWjcPyj5kiOgV1LQDOOOgVy3+5FgjXvdSSX7B8/5/4g==
+  dependencies:
+    loose-envify "^1.4.0"
+    object-assign "^4.1.1"
+    react-is "^16.13.1"
+
 protobufjs@^6.10.0:
   version "6.11.2"
   resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b"
@@ -11812,7 +11844,7 @@ react-hotkeys-hook@^3.4.4:
   dependencies:
     hotkeys-js "3.8.7"
 
-react-is@16.13.1, react-is@^16.7.0, react-is@^16.8.1:
+react-is@16.13.1, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.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==
@@ -11879,9 +11911,9 @@ react-resizable@^3.0.1, react-resizable@^3.0.4:
     react-draggable "^4.0.3"
 
 react-spring@^9.3.2:
-  version "9.3.2"
-  resolved "https://registry.yarnpkg.com/react-spring/-/react-spring-9.3.2.tgz#1456ef1ab1a3997c6c39693a9fd18cfd46c92930"
-  integrity sha512-LMFgjvTJVg2ltthzgJcZ7siOdRig7L8wJZIHrc7p6ss4AaJ446xHzm9L2ZQha1ZC9QVY8/e6XfLhMTFAG6dtjw==
+  version "9.3.3"
+  resolved "https://registry.yarnpkg.com/react-spring/-/react-spring-9.3.3.tgz#2982065385cf4ecf9c98f0f6976c603a5453f3ba"
+  integrity sha512-S6ZufQylwxwjavylFaU/oqBUZQX2ZvH2bpU3NSoYY8JlArH5sEeKMSzqME3fdp3+AwfOaxPpo25zSFGgytXY3Q==
   dependencies:
     "@react-spring/core" "~9.3.0"
     "@react-spring/konva" "~9.3.0"
@@ -12329,11 +12361,11 @@ rxjs@^6.4.0:
     tslib "^1.9.0"
 
 rxjs@^7.4.0:
-  version "7.4.0"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.4.0.tgz#a12a44d7eebf016f5ff2441b87f28c9a51cebc68"
-  integrity sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==
+  version "7.5.1"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.1.tgz#af73df343cbcab37628197f43ea0c8256f54b157"
+  integrity sha512-KExVEeZWxMZnZhUZtsJcFwz8IvPvgu4G2Z2QyqjZQzUGr32KDYuSxrEYO4w3tFFNbfLozcrKUTvTPi+E9ywJkQ==
   dependencies:
-    tslib "~2.1.0"
+    tslib "^2.1.0"
 
 safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
   version "5.1.2"
@@ -13436,9 +13468,9 @@ tree-visit@^0.1.0:
   integrity sha512-5lARH0BoZY70TwE+MV7v0KRtApSP4LSxC2JLRCUyK6KUCb8f/Qv9dS+PaWx9h3yKyNYjX2/JHwDx8DyQHHFzlw==
 
 ts-jest@^27.0.2, ts-jest@^27.0.3, ts-jest@^27.0.5:
-  version "27.1.1"
-  resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.1.tgz#5a54aca96db1dac37c681f3029dd10f3a8c36192"
-  integrity sha512-Ds0VkB+cB+8g2JUmP/GKWndeZcCKrbe6jzolGrVWdqVUFByY/2KDHqxJ7yBSon7hDB1TA4PXxjfZ+JjzJisvgA==
+  version "27.1.2"
+  resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.2.tgz#5991d6eb3fd8e1a8d4b8f6de3ec0a3cc567f3151"
+  integrity sha512-eSOiJOWq6Hhs6Khzk5wKC5sgWIXgXqOCiIl1+3lfnearu58Hj4QpE5tUhQcA3xtZrELbcvAGCsd6HB8OsaVaTA==
   dependencies:
     bs-logger "0.x"
     fast-json-stable-stringify "2.x"
@@ -13476,11 +13508,6 @@ tslib@^2.0.0, tslib@^2.1.0:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
   integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
 
-tslib@~2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
-  integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
-
 tty-browserify@0.0.0:
   version "0.0.0"
   resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
@@ -14099,9 +14126,9 @@ write-file-atomic@^3.0.0:
     typedarray-to-buffer "^3.1.5"
 
 ws@>=7.4.6:
-  version "8.3.0"
-  resolved "https://registry.yarnpkg.com/ws/-/ws-8.3.0.tgz#7185e252c8973a60d57170175ff55fdbd116070d"
-  integrity sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw==
+  version "8.4.0"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.0.tgz#f05e982a0a88c604080e8581576e2a063802bed6"
+  integrity sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ==
 
 ws@^7.4.6:
   version "7.5.6"

From 6faa69fad2ce7d6ba438f4f8e29787db5f1f1630 Mon Sep 17 00:00:00 2001
From: "UZU, J" <woojoo@softmarshmallow.com>
Date: Wed, 6 Apr 2022 09:41:56 +0900
Subject: [PATCH 2/8] update p-queue

---
 .../code-editor/monaco-utils/register-jsx.ts  |  2 +-
 editor/package.json                           |  4 +-
 editor/workers/index.js                       | 78 +++++++++----------
 yarn.lock                                     | 15 +++-
 4 files changed, 56 insertions(+), 43 deletions(-)

diff --git a/editor/components/code-editor/monaco-utils/register-jsx.ts b/editor/components/code-editor/monaco-utils/register-jsx.ts
index c2e38cdf..763d120d 100644
--- a/editor/components/code-editor/monaco-utils/register-jsx.ts
+++ b/editor/components/code-editor/monaco-utils/register-jsx.ts
@@ -1,5 +1,5 @@
 import { Monaco } from "@monaco-editor/react";
-// import { createWorkerQueue } from "../../../workers";
+import { createWorkerQueue } from "../../../workers";
 // import Worker from '../../../workers/monaco-syntax-highlight/syntax-highlight.worker';
 
 import type { editor } from "monaco-editor";
diff --git a/editor/package.json b/editor/package.json
index 7ea9b19e..2072da7e 100644
--- a/editor/package.json
+++ b/editor/package.json
@@ -41,7 +41,7 @@
     "moment": "^2.29.1",
     "monaco-editor": "^0.24.0",
     "next": "10.0.3",
-    "p-queue": "^7.1.0",
+    "p-queue": "^7.2.0",
     "pouchdb-adapter-idb": "^7.2.2",
     "re-resizable": "^6.9.1",
     "react": "17.0.1",
@@ -71,4 +71,4 @@
     "raw-loader": "^4.0.2",
     "typescript": "^4.2.3"
   }
-}
\ No newline at end of file
+}
diff --git a/editor/workers/index.js b/editor/workers/index.js
index c4fa7cec..e387570e 100644
--- a/editor/workers/index.js
+++ b/editor/workers/index.js
@@ -1,41 +1,41 @@
-// import PQueue from "p-queue";
+import PQueue from "p-queue/dist";
 
-// export function createWorkerQueue(worker) {
-//   const queue = new PQueue({ concurrency: 1 });
-//   return {
-//     worker,
-//     emit(data) {
-//       queue.clear();
-//       const _id = Math.random().toString(36).substr(2, 5);
-//       worker.postMessage({ _current: _id });
-//       return queue.add(
-//         () =>
-//           new Promise((resolve) => {
-//             function onMessage(event) {
-//               if (event.data._id !== _id) return;
-//               worker.removeEventListener("message", onMessage);
-//               resolve(event.data);
-//             }
-//             worker.addEventListener("message", onMessage);
-//             worker.postMessage({ ...data, _id });
-//           })
-//       );
-//     },
-//     terminate() {
-//       worker.terminate();
-//     },
-//   };
-// }
+export function createWorkerQueue(worker) {
+  const queue = new PQueue({ concurrency: 1 });
+  return {
+    worker,
+    emit(data) {
+      queue.clear();
+      const _id = Math.random().toString(36).substr(2, 5);
+      worker.postMessage({ _current: _id });
+      return queue.add(
+        () =>
+          new Promise((resolve) => {
+            function onMessage(event) {
+              if (event.data._id !== _id) return;
+              worker.removeEventListener("message", onMessage);
+              resolve(event.data);
+            }
+            worker.addEventListener("message", onMessage);
+            worker.postMessage({ ...data, _id });
+          })
+      );
+    },
+    terminate() {
+      worker.terminate();
+    },
+  };
+}
 
-// export function requestResponse(worker, data) {
-//   return new Promise((resolve) => {
-//     const _id = Math.random().toString(36).substr(2, 5);
-//     function onMessage(event) {
-//       if (event.data._id !== _id) return;
-//       worker.removeEventListener("message", onMessage);
-//       resolve(event.data);
-//     }
-//     worker.addEventListener("message", onMessage);
-//     worker.postMessage({ ...data, _id });
-//   });
-// }
+export function requestResponse(worker, data) {
+  return new Promise((resolve) => {
+    const _id = Math.random().toString(36).substr(2, 5);
+    function onMessage(event) {
+      if (event.data._id !== _id) return;
+      worker.removeEventListener("message", onMessage);
+      resolve(event.data);
+    }
+    worker.addEventListener("message", onMessage);
+    worker.postMessage({ ...data, _id });
+  });
+}
diff --git a/yarn.lock b/yarn.lock
index 255808ea..b8373f74 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14024,6 +14024,14 @@ p-map@^4.0.0:
   dependencies:
     aggregate-error "^3.0.0"
 
+p-queue@^7.2.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-7.2.0.tgz#e1430e4432f09b43aa8b4913d4c2ff7fdd685479"
+  integrity sha512-Kvv7p13M46lTYLQ/PsZdaj/1Vj6u/8oiIJgyQyx4oVkOfHdd7M2EZvXigDvcsSzRwanCzQirV5bJPQFoSQt5MA==
+  dependencies:
+    eventemitter3 "^4.0.7"
+    p-timeout "^5.0.2"
+
 p-timeout@^3.1.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
@@ -14031,6 +14039,11 @@ p-timeout@^3.1.0:
   dependencies:
     p-finally "^1.0.0"
 
+p-timeout@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-5.0.2.tgz#d12964c4b2f988e15f72b455c2c428d82a0ec0a0"
+  integrity sha512-sEmji9Yaq+Tw+STwsGAE56hf7gMy9p0tQfJojIAamB7WHJYJKf1qlsg9jqBWG8q9VCxKPhZaP/AcXwEoBcYQhQ==
+
 p-try@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
@@ -17407,7 +17420,7 @@ ts-dedent@^2.0.0:
   resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5"
   integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==
 
-ts-jest@^27.0.2, ts-jest@^27.0.3, ts-jest@^27.0.5, ts-jest@^27.1.4:
+ts-jest@^27.0.2, ts-jest@^27.0.3, ts-jest@^27.0.5:
   version "27.1.4"
   resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.4.tgz#84d42cf0f4e7157a52e7c64b1492c46330943e00"
   integrity sha512-qjkZlVPWVctAezwsOD1OPzbZ+k7zA5z3oxII4dGdZo5ggX/PL7kvwTM0pXTr10fAtbiVpJaL3bWd502zAhpgSQ==

From 73a8e4107c5cc15e3c7ebeaee738a4fca52d6914 Mon Sep 17 00:00:00 2001
From: "UZU, J" <woojoo@softmarshmallow.com>
Date: Wed, 6 Apr 2022 10:16:57 +0900
Subject: [PATCH 3/8] yarn

---
 editor/workers/index.js | 2 +-
 yarn.lock               | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/editor/workers/index.js b/editor/workers/index.js
index e387570e..e4fee1cc 100644
--- a/editor/workers/index.js
+++ b/editor/workers/index.js
@@ -1,4 +1,4 @@
-import PQueue from "p-queue/dist";
+import PQueue from "p-queue";
 
 export function createWorkerQueue(worker) {
   const queue = new PQueue({ concurrency: 1 });
diff --git a/yarn.lock b/yarn.lock
index dc1422bc..1166fd0c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8088,7 +8088,7 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.3:
     shebang-command "^2.0.0"
     which "^2.0.1"
 
-crypto-browserify@^3.11.0, crypto-browserify@^3.12.0:
+crypto-browserify@^3.11.0:
   version "3.12.0"
   resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
   integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==

From 57df4eda282e2850908dad4f13dd113fa4ebc641 Mon Sep 17 00:00:00 2001
From: "UZU, J" <woojoo@softmarshmallow.com>
Date: Wed, 6 Apr 2022 10:24:04 +0900
Subject: [PATCH 4/8] bump webworkers

---
 editor/components/code-editor/monaco-utils/register-jsx.ts | 4 ++--
 .../code-editor/monaco-utils/register-typings.ts           | 4 ++--
 editor/components/code-editor/monaco.tsx                   | 7 +------
 3 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/editor/components/code-editor/monaco-utils/register-jsx.ts b/editor/components/code-editor/monaco-utils/register-jsx.ts
index 763d120d..56c238e1 100644
--- a/editor/components/code-editor/monaco-utils/register-jsx.ts
+++ b/editor/components/code-editor/monaco-utils/register-jsx.ts
@@ -10,8 +10,8 @@ export function registerJsxHighlighter(
   const { worker: syntaxWorker } = createWorkerQueue(
     new Worker(
       new URL(
-        "../../../workers/monaco-syntax-highlight/syntax-highlight.worker.js"
-        // import.meta.url
+        "../../../workers/monaco-syntax-highlight/syntax-highlight.worker.js",
+        import.meta.url
       )
     )
   );
diff --git a/editor/components/code-editor/monaco-utils/register-typings.ts b/editor/components/code-editor/monaco-utils/register-typings.ts
index 7f44b17a..22cd7d45 100644
--- a/editor/components/code-editor/monaco-utils/register-typings.ts
+++ b/editor/components/code-editor/monaco-utils/register-typings.ts
@@ -13,8 +13,8 @@ export function registerTypesWorker(monaco: Monaco) {
   if (!typesWorker) {
     typesWorker = new Worker(
       new URL(
-        "../../../workers/fetch-types/fetch-types.worker.js"
-        // import.meta.url
+        "../../../workers/fetch-types/fetch-types.worker.js",
+        import.meta.url
       )
     );
   }
diff --git a/editor/components/code-editor/monaco.tsx b/editor/components/code-editor/monaco.tsx
index 4c186a32..0b438fb6 100644
--- a/editor/components/code-editor/monaco.tsx
+++ b/editor/components/code-editor/monaco.tsx
@@ -1,10 +1,5 @@
 import React, { useRef, useEffect } from "react";
-import Editor, {
-  useMonaco,
-  Monaco,
-  OnChange,
-  OnMount,
-} from "@monaco-editor/react";
+import Editor, { useMonaco, Monaco, OnMount } from "@monaco-editor/react";
 import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
 import { MonacoEmptyMock } from "./monaco-mock-empty";
 import { register } from "./monaco-utils";

From 2f40dc66bccf5f968cfb89ef2d8c5e643dc2ad3d Mon Sep 17 00:00:00 2001
From: "UZU, J" <woojoo@softmarshmallow.com>
Date: Wed, 6 Apr 2022 11:07:54 +0900
Subject: [PATCH 5/8] bump monaco ver

---
 .../code-editor/monaco-utils/register-jsx.ts           | 10 +++-------
 editor/package.json                                    |  8 ++++----
 yarn.lock                                              | 10 +++++-----
 3 files changed, 12 insertions(+), 16 deletions(-)

diff --git a/editor/components/code-editor/monaco-utils/register-jsx.ts b/editor/components/code-editor/monaco-utils/register-jsx.ts
index 56c238e1..92fbe6e6 100644
--- a/editor/components/code-editor/monaco-utils/register-jsx.ts
+++ b/editor/components/code-editor/monaco-utils/register-jsx.ts
@@ -1,6 +1,5 @@
 import { Monaco } from "@monaco-editor/react";
 import { createWorkerQueue } from "../../../workers";
-// import Worker from '../../../workers/monaco-syntax-highlight/syntax-highlight.worker';
 
 import type { editor } from "monaco-editor";
 export function registerJsxHighlighter(
@@ -19,9 +18,8 @@ export function registerJsxHighlighter(
   const highlightHandler = () => {
     const title = "app.js";
     const model = editor.getModel();
-    const version = model!.getVersionId();
-    // @ts-ignore
-    const lang = model._languageIdentifier.language;
+    const version = model?.getVersionId();
+    const lang = model?.getLanguageId();
 
     if (lang === "javascript" || "typescript") {
       const code = model?.getValue();
@@ -51,9 +49,7 @@ export function registerJsxHighlighter(
           classification.end
         ),
         options: {
-          inlineClassName: classification.type
-            ? `ayu-dark ${classification.kind} ${classification.type}-of-${classification.parentKind}`
-            : classification.kind,
+          //
         },
       }));
 
diff --git a/editor/package.json b/editor/package.json
index 600366c6..1c123a57 100644
--- a/editor/package.json
+++ b/editor/package.json
@@ -24,7 +24,7 @@
     "@material-ui/icons": "^4.11.2",
     "@material-ui/lab": "^4.0.0-alpha.60",
     "@modulz/design-system": "^0.6.1",
-    "@monaco-editor/react": "^4.1.3",
+    "@monaco-editor/react": "^4.4.1",
     "@reflect-blocks/figma-embed": "^0.0.5",
     "@use-gesture/react": "^10.2.2",
     "@visx/gradient": "^1.7.0",
@@ -39,9 +39,9 @@
     "framer-motion": "^5.3.1",
     "idb": "^6.1.2",
     "moment": "^2.29.1",
-    "monaco-editor": "^0.24.0",
-    "p-queue": "^7.2.0",
+    "monaco-editor": "^0.33.0",
     "next": "^12.1.4",
+    "p-queue": "^7.2.0",
     "pouchdb-adapter-idb": "^7.2.2",
     "re-resizable": "^6.9.1",
     "react": "^18.0.0",
@@ -71,4 +71,4 @@
     "raw-loader": "^4.0.2",
     "typescript": "^4.2.3"
   }
-}
\ No newline at end of file
+}
diff --git a/yarn.lock b/yarn.lock
index 1166fd0c..f53b4087 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2715,7 +2715,7 @@
   dependencies:
     state-local "^1.0.6"
 
-"@monaco-editor/react@^4.1.3":
+"@monaco-editor/react@^4.4.1":
   version "4.4.1"
   resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.4.1.tgz#2e2b9b369f3082b0e14f47cdbe35658fd56c7c7d"
   integrity sha512-95E/XPC4dbm/7qdkhSsU/a1kRgcn2PYhRTVIc+/cixWCZrwRURW1DRPaIZ2lOawBJ6kAOLywxuD4A4UmbT0ZIw==
@@ -12815,10 +12815,10 @@ moment@^2.29.1:
   resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.2.tgz#00910c60b20843bcba52d37d58c628b47b1f20e4"
   integrity sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==
 
-monaco-editor@^0.24.0:
-  version "0.24.0"
-  resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.24.0.tgz#990b55096bcc95d08d8d28e55264c6eb17707269"
-  integrity sha512-o1f0Lz6ABFNTtnEqqqvlY9qzNx24rQZx1RgYNQ8SkWkE+Ka63keHH/RqxQ4QhN4fs/UYOnvAtEUZsPrzccH++A==
+monaco-editor@^0.33.0:
+  version "0.33.0"
+  resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.33.0.tgz#842e244f3750a2482f8a29c676b5684e75ff34af"
+  integrity sha512-VcRWPSLIUEgQJQIE0pVT8FcGBIgFoxz7jtqctE+IiCxWugD0DwgyQBcZBhdSrdMC84eumoqMZsGl2GTreOzwqw==
 
 move-concurrently@^1.0.1:
   version "1.0.1"

From d1a02782918b8a0485f21c60928a11cd4f474522 Mon Sep 17 00:00:00 2001
From: "UZU, J" <woojoo@softmarshmallow.com>
Date: Wed, 6 Apr 2022 11:08:11 +0900
Subject: [PATCH 6/8] add prettier support & init monaco extended

---
 .../monaco-utils/register-prettier.ts         | 129 +++++++++---------
 .../code-editor/monaco-utils/register.ts      |   4 +-
 editor/components/code-editor/monaco.tsx      |   4 +-
 3 files changed, 69 insertions(+), 68 deletions(-)

diff --git a/editor/components/code-editor/monaco-utils/register-prettier.ts b/editor/components/code-editor/monaco-utils/register-prettier.ts
index d7f18701..5e928cd6 100644
--- a/editor/components/code-editor/monaco-utils/register-prettier.ts
+++ b/editor/components/code-editor/monaco-utils/register-prettier.ts
@@ -1,75 +1,74 @@
-export const dummy = "";
-// import * as monaco from "monaco-editor";
-// import { createWorkerQueue } from "../../../workers";
+import * as monaco from "monaco-editor";
+import { createWorkerQueue } from "../../../workers";
 
-// export function registerDocumentPrettier(editor, monaco) {
-//   const disposables: monaco.IDisposable[] = [];
-//   let prettierWorker;
+export function registerDocumentPrettier(editor, monaco) {
+  const disposables: monaco.IDisposable[] = [];
+  let prettierWorker;
 
-//   const formattingEditProvider = {
-//     async provideDocumentFormattingEdits(model, _options, _token) {
-//       if (!prettierWorker) {
-//         prettierWorker = createWorkerQueue(
-//           new Worker(
-//             new URL(
-//               "../../../workers/prettier.worker.js"
-//               // import.meta.url
-//             )
-//           )
-//         );
-//       }
+  const formattingEditProvider = {
+    async provideDocumentFormattingEdits(model, _options, _token) {
+      if (!prettierWorker) {
+        prettierWorker = createWorkerQueue(
+          new Worker(
+            new URL(
+              "../../../workers/prettier/prettier.worker.js",
+              import.meta.url
+            )
+          )
+        );
+      }
 
-//       const { canceled, error, pretty } = await prettierWorker?.emit({
-//         text: model.getValue(),
-//         language: model.getModeId(),
-//       });
+      const { canceled, error, pretty } = await prettierWorker?.emit({
+        text: model.getValue(),
+        language: model._languageId,
+      });
 
-//       if (canceled || error) return [];
+      if (canceled || error) return [];
 
-//       return [
-//         {
-//           range: model.getFullModelRange(),
-//           text: pretty,
-//         },
-//       ];
-//     },
-//   };
+      return [
+        {
+          range: model.getFullModelRange(),
+          text: pretty,
+        },
+      ];
+    },
+  };
 
-//   disposables.push(
-//     monaco.languages.registerDocumentFormattingEditProvider(
-//       "javascript",
-//       formattingEditProvider
-//     )
-//   );
+  disposables.push(
+    monaco.languages.registerDocumentFormattingEditProvider(
+      "javascript",
+      formattingEditProvider
+    )
+  );
 
-//   disposables.push(
-//     monaco.languages.registerDocumentFormattingEditProvider(
-//       "html",
-//       formattingEditProvider
-//     )
-//   );
+  disposables.push(
+    monaco.languages.registerDocumentFormattingEditProvider(
+      "html",
+      formattingEditProvider
+    )
+  );
 
-//   disposables.push(
-//     monaco.languages.registerDocumentFormattingEditProvider(
-//       "css",
-//       formattingEditProvider
-//     )
-//   );
-//   disposables.push(
-//     monaco.languages.registerDocumentFormattingEditProvider(
-//       "typescript",
-//       formattingEditProvider
-//     )
-//   );
+  disposables.push(
+    monaco.languages.registerDocumentFormattingEditProvider(
+      "css",
+      formattingEditProvider
+    )
+  );
+  disposables.push(
+    monaco.languages.registerDocumentFormattingEditProvider(
+      "typescript",
+      formattingEditProvider
+    )
+  );
 
-//   editor.getAction("editor.action.formatDocument").run();
+  editor.getAction("editor.action.formatDocument").run();
 
-//   return {
-//     dispose() {
-//       disposables.forEach((disposable) => disposable.dispose());
-//       if (prettierWorker) {
-//         prettierWorker.terminate();
-//       }
-//     },
-//   };
-// }
+  return {
+    dispose() {
+      disposables.forEach((disposable) => disposable.dispose());
+      if (prettierWorker) {
+        prettierWorker.terminate();
+      }
+    },
+  };
+}
diff --git a/editor/components/code-editor/monaco-utils/register.ts b/editor/components/code-editor/monaco-utils/register.ts
index 7e49e953..9cbe9d05 100644
--- a/editor/components/code-editor/monaco-utils/register.ts
+++ b/editor/components/code-editor/monaco-utils/register.ts
@@ -1,6 +1,6 @@
 import * as monaco from "monaco-editor";
 import { Monaco, OnMount } from "@monaco-editor/react";
-// import { registerDocumentPrettier } from "./register-prettier";
+import { registerDocumentPrettier } from "./register-prettier";
 import { registerJsxHighlighter } from "./register-jsx";
 import { registerTypesWorker } from "./register-typings";
 
@@ -9,7 +9,7 @@ type CompilerOptions = monaco.languages.typescript.CompilerOptions;
 export const initEditor: OnMount = (editor, monaco) => {
   console.log("Init editor");
   registerJsxHighlighter(editor, monaco);
-  // registerDocumentPrettier(editor, monaco);
+  registerDocumentPrettier(editor, monaco);
 };
 
 export const initMonaco = (monaco: Monaco) => {
diff --git a/editor/components/code-editor/monaco.tsx b/editor/components/code-editor/monaco.tsx
index 0b438fb6..0a0205af 100644
--- a/editor/components/code-editor/monaco.tsx
+++ b/editor/components/code-editor/monaco.tsx
@@ -40,18 +40,20 @@ export function MonacoEditor(props: MonacoEditorProps) {
 
   return (
     <Editor
+      beforeMount={register.initMonaco}
+      onMount={onMount}
       width={props.width}
       height={props.height}
       defaultLanguage={
         pollyfill_language(props.defaultLanguage) ?? "typescript"
       }
-      onMount={onMount}
       loading={<MonacoEmptyMock l={5} />}
       defaultValue={props.defaultValue ?? "// no content"}
       theme="vs-dark"
       options={{
         ...props.options,
         // overrided default options
+        wordWrap: "off",
         unusualLineTerminators: "off",
       }}
     />

From 657bc9313ae4ecee50160207cbb2d9e844f7efcf Mon Sep 17 00:00:00 2001
From: "UZU, J" <woojoo@softmarshmallow.com>
Date: Wed, 6 Apr 2022 11:08:49 +0900
Subject: [PATCH 7/8] clear logs

---
 editor/components/code-editor/monaco-utils/register.ts | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/editor/components/code-editor/monaco-utils/register.ts b/editor/components/code-editor/monaco-utils/register.ts
index 9cbe9d05..7123df48 100644
--- a/editor/components/code-editor/monaco-utils/register.ts
+++ b/editor/components/code-editor/monaco-utils/register.ts
@@ -7,14 +7,11 @@ import { registerTypesWorker } from "./register-typings";
 type CompilerOptions = monaco.languages.typescript.CompilerOptions;
 
 export const initEditor: OnMount = (editor, monaco) => {
-  console.log("Init editor");
   registerJsxHighlighter(editor, monaco);
   registerDocumentPrettier(editor, monaco);
 };
 
 export const initMonaco = (monaco: Monaco) => {
-  console.log("Init Monaco");
-
   baseConfigure(monaco);
 
   const { dispose } = registerTypesWorker(monaco);

From 886c5e00adc76f677de1b560503650163d6434e7 Mon Sep 17 00:00:00 2001
From: "UZU, J" <woojoo@softmarshmallow.com>
Date: Wed, 6 Apr 2022 13:03:10 +0900
Subject: [PATCH 8/8] add format on save

---
 editor/components/code-editor/monaco.tsx | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/editor/components/code-editor/monaco.tsx b/editor/components/code-editor/monaco.tsx
index 0a0205af..0551119d 100644
--- a/editor/components/code-editor/monaco.tsx
+++ b/editor/components/code-editor/monaco.tsx
@@ -33,6 +33,20 @@ export function MonacoEditor(props: MonacoEditorProps) {
 
     register.initEditor(editor, monaco);
 
+    editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, function () {
+      format.run();
+    });
+
+    // disabled. todo: find a way to format on new line, but also with adding new line.
+    // editor.addCommand(monaco.KeyCode.Enter, function () {
+    //   format.run();
+    // });
+
+    editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyR, function () {
+      // don't reload the entire page
+      // do nothing.
+    });
+
     editor.onDidChangeModelContent(() => {
       /* add here */
     });
