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..92fbe6e6 --- /dev/null +++ b/editor/components/code-editor/monaco-utils/register-jsx.ts @@ -0,0 +1,60 @@ +import { Monaco } from "@monaco-editor/react"; +import { createWorkerQueue } from "../../../workers"; + +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(); + const lang = model?.getLanguageId(); + + 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: { + // + }, + })); + + // @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..5e928cd6 --- /dev/null +++ b/editor/components/code-editor/monaco-utils/register-prettier.ts @@ -0,0 +1,74 @@ +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/prettier.worker.js", + import.meta.url + ) + ) + ); + } + + const { canceled, error, pretty } = await prettierWorker?.emit({ + text: model.getValue(), + language: model._languageId, + }); + + 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..22cd7d45 --- /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..7123df48 --- /dev/null +++ b/editor/components/code-editor/monaco-utils/register.ts @@ -0,0 +1,62 @@ +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) => { + registerJsxHighlighter(editor, monaco); + registerDocumentPrettier(editor, monaco); +}; + +export const initMonaco = (monaco: 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 e8f02634..0551119d 100644 --- a/editor/components/code-editor/monaco.tsx +++ b/editor/components/code-editor/monaco.tsx @@ -1,7 +1,10 @@ -import React, { useEffect } from "react"; -import Editor, { useMonaco, Monaco } from "@monaco-editor/react"; +import React, { useRef, useEffect } from "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"; + +type ICodeEditor = monaco.editor.IStandaloneCodeEditor; export interface MonacoEditorProps { defaultValue?: string; @@ -12,16 +15,47 @@ export interface MonacoEditorProps { } export function MonacoEditor(props: MonacoEditorProps) { + const instance = useRef<{ editor: ICodeEditor; format: any } | null>(null); + const activeModel = useRef(); + 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.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 */ + }); + }; + return ( diff --git a/editor/package.json b/editor/package.json index 2a9cc48e..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,8 +39,9 @@ "framer-motion": "^5.3.1", "idb": "^6.1.2", "moment": "^2.29.1", - "monaco-editor": "^0.24.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", @@ -70,4 +71,4 @@ "raw-loader": "^4.0.2", "typescript": "^4.2.3" } -} \ No newline at end of file +} 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..e4fee1cc --- /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 7d183deb..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== @@ -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== @@ -9140,6 +9140,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" @@ -12810,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" @@ -13429,6 +13434,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" @@ -13436,6 +13449,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"