From 14cb3a36c1a7073fef8dfbdf03e8788492631439 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Fri, 14 Aug 2020 17:23:58 -0700 Subject: [PATCH] perf: Reduce initial bundle size / async bundle loading (#1456) * feat: Move to React.lazy * perf: Remove duplicate babel/runtime * fix: Run yarn-deduplicate * Further attempts to remove rich-markdown-editor from initial chunk * perf: Lazy loading of authenticated routes * perf: Move color picker to async loading fix: Display placeholder when loading rich editor * fix: Cache bust on auto reload --- .babelrc | 2 +- .eslintrc | 3 + app/components/DelayedMount.js | 2 +- app/components/Editor.js | 26 +- app/components/ErrorBoundary.js | 15 +- app/components/FullscreenLoading.js | 24 ++ app/components/HoverPreview.js | 2 +- app/components/HoverPreviewDocument.js | 16 +- app/components/IconPicker.js | 28 +- app/components/InputRich.js | 30 +- app/routes.js | 121 -------- app/routes/authenticated.js | 76 +++++ app/routes/index.js | 31 ++ app/routes/settings.js | 35 +++ app/scenes/Collection.js | 17 +- app/scenes/Document/components/DataLoader.js | 2 +- app/scenes/Document/components/Document.js | 30 +- app/scenes/Document/components/Editor.js | 72 ++--- app/utils/ApiClient.js | 3 +- flow-typed/globals.js | 2 + package.json | 2 +- server/services/backlinks.js | 2 +- {shared => server}/utils/parseDocumentIds.js | 11 - .../utils/parseDocumentIds.test.js | 0 shared/utils/parseDocumentSlug.js | 12 + webpack.config.dev.js | 3 + webpack.config.js | 4 + yarn.lock | 282 ++---------------- 28 files changed, 338 insertions(+), 515 deletions(-) create mode 100644 app/components/FullscreenLoading.js delete mode 100644 app/routes.js create mode 100644 app/routes/authenticated.js create mode 100644 app/routes/index.js create mode 100644 app/routes/settings.js rename {shared => server}/utils/parseDocumentIds.js (83%) rename {shared => server}/utils/parseDocumentIds.test.js (100%) create mode 100644 shared/utils/parseDocumentSlug.js diff --git a/.babelrc b/.babelrc index e5f862d4a..4696bad1f 100644 --- a/.babelrc +++ b/.babelrc @@ -9,7 +9,7 @@ "version": "2", "proposals": true }, - "useBuiltIns": "usage", + "useBuiltIns": "usage" } ] ], diff --git a/.eslintrc b/.eslintrc index 99ccf23d4..87aabc376 100644 --- a/.eslintrc +++ b/.eslintrc @@ -97,5 +97,8 @@ }, "env": { "jest": true + }, + "globals": { + "EDITOR_VERSION": true } } \ No newline at end of file diff --git a/app/components/DelayedMount.js b/app/components/DelayedMount.js index 9800bcff4..65c515784 100644 --- a/app/components/DelayedMount.js +++ b/app/components/DelayedMount.js @@ -6,7 +6,7 @@ type Props = { children: React.Node, }; -export default function DelayedMount({ delay = 150, children }: Props) { +export default function DelayedMount({ delay = 250, children }: Props) { const [isShowing, setShowing] = React.useState(false); React.useEffect(() => { diff --git a/app/components/Editor.js b/app/components/Editor.js index 42553f37d..cdba893a9 100644 --- a/app/components/Editor.js +++ b/app/components/Editor.js @@ -2,14 +2,16 @@ import { lighten } from "polished"; import * as React from "react"; import { withRouter, type RouterHistory } from "react-router-dom"; -import RichMarkdownEditor from "rich-markdown-editor"; import styled, { withTheme } from "styled-components"; import UiStore from "stores/UiStore"; +import ErrorBoundary from "components/ErrorBoundary"; import Tooltip from "components/Tooltip"; import embeds from "../embeds"; import isInternalUrl from "utils/isInternalUrl"; import { uploadFile } from "utils/uploadFile"; +const RichMarkdownEditor = React.lazy(() => import("rich-markdown-editor")); + const EMPTY_ARRAY = []; type Props = { @@ -22,7 +24,7 @@ type Props = { }; type PropsWithRef = Props & { - forwardedRef: React.Ref, + forwardedRef: React.Ref, history: RouterHistory, }; @@ -67,15 +69,17 @@ class Editor extends React.Component { render() { return ( - + + + ); } } diff --git a/app/components/ErrorBoundary.js b/app/components/ErrorBoundary.js index ebd875d84..24c087e50 100644 --- a/app/components/ErrorBoundary.js +++ b/app/components/ErrorBoundary.js @@ -12,6 +12,7 @@ import env from "env"; type Props = { children: React.Node, + reloadOnChunkMissing?: boolean, }; @observer @@ -23,13 +24,25 @@ class ErrorBoundary extends React.Component { this.error = error; console.error(error); + if ( + this.props.reloadOnChunkMissing && + error.message && + error.message.match(/chunk/) + ) { + // If the editor bundle fails to load then reload the entire window. This + // can happen if a deploy happens between the user loading the initial JS + // bundle and the async-loaded editor JS bundle as the hash will change. + window.location.reload(true); + return; + } + if (window.Sentry) { window.Sentry.captureException(error); } } handleReload = () => { - window.location.reload(); + window.location.reload(true); }; handleShowDetails = () => { diff --git a/app/components/FullscreenLoading.js b/app/components/FullscreenLoading.js new file mode 100644 index 000000000..d645361a1 --- /dev/null +++ b/app/components/FullscreenLoading.js @@ -0,0 +1,24 @@ +// @flow +import * as React from "react"; +import styled from "styled-components"; +import Empty from "components/Empty"; +import Fade from "components/Fade"; +import Flex from "components/Flex"; + +export default function FullscreenLoading() { + return ( + + + Loading… + + + ); +} + +const Centered = styled(Flex)` + text-align: center; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; +`; diff --git a/app/components/HoverPreview.js b/app/components/HoverPreview.js index 38c719bad..1b05cf01c 100644 --- a/app/components/HoverPreview.js +++ b/app/components/HoverPreview.js @@ -5,7 +5,7 @@ import * as React from "react"; import { Portal } from "react-portal"; import styled from "styled-components"; import { fadeAndSlideIn } from "shared/styles/animations"; -import { parseDocumentSlugFromUrl } from "shared/utils/parseDocumentIds"; +import { parseDocumentSlugFromUrl } from "shared/utils/parseDocumentSlug"; import DocumentsStore from "stores/DocumentsStore"; import HoverPreviewDocument from "components/HoverPreviewDocument"; import isInternalUrl from "utils/isInternalUrl"; diff --git a/app/components/HoverPreviewDocument.js b/app/components/HoverPreviewDocument.js index e1ad229ef..b5e9a2c7c 100644 --- a/app/components/HoverPreviewDocument.js +++ b/app/components/HoverPreviewDocument.js @@ -3,7 +3,7 @@ import { inject, observer } from "mobx-react"; import * as React from "react"; import { Link } from "react-router-dom"; import styled from "styled-components"; -import { parseDocumentSlugFromUrl } from "shared/utils/parseDocumentIds"; +import { parseDocumentSlugFromUrl } from "shared/utils/parseDocumentSlug"; import DocumentsStore from "stores/DocumentsStore"; import DocumentMetaWithViews from "components/DocumentMetaWithViews"; import Editor from "components/Editor"; @@ -29,12 +29,14 @@ function HoverPreviewDocument({ url, documents, children }: Props) { {document.titleWithDefault} - + }> + + ); } diff --git a/app/components/IconPicker.js b/app/components/IconPicker.js index 2e2b07db9..32c008354 100644 --- a/app/components/IconPicker.js +++ b/app/components/IconPicker.js @@ -22,13 +22,17 @@ import { VehicleIcon, } from "outline-icons"; import * as React from "react"; -import { TwitterPicker } from "react-color"; import styled from "styled-components"; import { DropdownMenu } from "components/DropdownMenu"; import Flex from "components/Flex"; +import HelpText from "components/HelpText"; import { LabelText } from "components/Input"; import NudeButton from "components/NudeButton"; +const TwitterPicker = React.lazy(() => + import("react-color/lib/components/twitter/Twitter") +); + export const icons = { collection: { component: CollectionIcon, @@ -193,14 +197,16 @@ class IconPicker extends React.Component { })} - - this.props.onChange(color.hex, this.props.icon) - } - colors={colors} - triangle="hide" - /> + Loading…}> + + this.props.onChange(color.hex, this.props.icon) + } + colors={colors} + triangle="hide" + /> + @@ -226,6 +232,10 @@ const IconButton = styled(NudeButton)` height: 30px; `; +const Loading = styled(HelpText)` + padding: 16px; +`; + const ColorPicker = styled(TwitterPicker)` box-shadow: none !important; background: transparent !important; diff --git a/app/components/InputRich.js b/app/components/InputRich.js index 7c3a29f6c..d9dd68d74 100644 --- a/app/components/InputRich.js +++ b/app/components/InputRich.js @@ -4,6 +4,8 @@ import { observer, inject } from "mobx-react"; import * as React from "react"; import styled, { withTheme } from "styled-components"; import UiStore from "stores/UiStore"; +import Editor from "components/Editor"; +import HelpText from "components/HelpText"; import { LabelText, Outline } from "components/Input"; type Props = { @@ -19,10 +21,6 @@ class InputRich extends React.Component { @observable editorComponent: React.ComponentType; @observable focused: boolean = false; - componentDidMount() { - this.loadEditor(); - } - handleBlur = () => { this.focused = false; }; @@ -31,36 +29,18 @@ class InputRich extends React.Component { this.focused = true; }; - loadEditor = async () => { - try { - const EditorImport = await import("./Editor"); - this.editorComponent = EditorImport.default; - } catch (err) { - if (err.message && err.message.match(/chunk/)) { - // If the editor bundle fails to load then reload the entire window. This - // can happen if a deploy happens between the user loading the initial JS - // bundle and the async-loaded editor JS bundle as the hash will change. - window.location.reload(); - return; - } - throw err; - } - }; - render() { const { label, minHeight, maxHeight, ui, ...rest } = this.props; - const Editor = this.editorComponent; return ( <> {label} - - {Editor ? ( + Loading editor…}> { grow {...rest} /> - ) : ( - "Loading…" - )} + ); diff --git a/app/routes.js b/app/routes.js deleted file mode 100644 index 8dcf0e659..000000000 --- a/app/routes.js +++ /dev/null @@ -1,121 +0,0 @@ -// @flow -import * as React from "react"; -import { Switch, Route, Redirect, type Match } from "react-router-dom"; -import Archive from "scenes/Archive"; -import Collection from "scenes/Collection"; -import Dashboard from "scenes/Dashboard"; -import KeyedDocument from "scenes/Document/KeyedDocument"; -import DocumentNew from "scenes/DocumentNew"; -import Drafts from "scenes/Drafts"; -import Error404 from "scenes/Error404"; -import Login from "scenes/Login"; -import Search from "scenes/Search"; -import Settings from "scenes/Settings"; -import Details from "scenes/Settings/Details"; -import Events from "scenes/Settings/Events"; -import Export from "scenes/Settings/Export"; -import Groups from "scenes/Settings/Groups"; -import Notifications from "scenes/Settings/Notifications"; -import People from "scenes/Settings/People"; -import Security from "scenes/Settings/Security"; -import Shares from "scenes/Settings/Shares"; -import Slack from "scenes/Settings/Slack"; -import Tokens from "scenes/Settings/Tokens"; -import Zapier from "scenes/Settings/Zapier"; -import Starred from "scenes/Starred"; -import Templates from "scenes/Templates"; -import Trash from "scenes/Trash"; - -import Authenticated from "components/Authenticated"; -import Layout from "components/Layout"; -import SocketProvider from "components/SocketProvider"; -import { matchDocumentSlug as slug } from "utils/routeHelpers"; - -const NotFound = () => ; -const RedirectDocument = ({ match }: { match: Match }) => ( - -); - -export default function Routes() { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/app/routes/authenticated.js b/app/routes/authenticated.js new file mode 100644 index 000000000..5ee755df8 --- /dev/null +++ b/app/routes/authenticated.js @@ -0,0 +1,76 @@ +// @flow +import * as React from "react"; +import { Switch, Route, Redirect, type Match } from "react-router-dom"; +import Archive from "scenes/Archive"; +import Collection from "scenes/Collection"; +import Dashboard from "scenes/Dashboard"; +import KeyedDocument from "scenes/Document/KeyedDocument"; +import DocumentNew from "scenes/DocumentNew"; +import Drafts from "scenes/Drafts"; +import Error404 from "scenes/Error404"; +import Search from "scenes/Search"; +import Starred from "scenes/Starred"; +import Templates from "scenes/Templates"; +import Trash from "scenes/Trash"; + +import CenteredContent from "components/CenteredContent"; +import Layout from "components/Layout"; +import LoadingPlaceholder from "components/LoadingPlaceholder"; +import SocketProvider from "components/SocketProvider"; +import { matchDocumentSlug as slug } from "utils/routeHelpers"; + +const SettingsRoutes = React.lazy(() => import("./settings")); + +const NotFound = () => ; +const RedirectDocument = ({ match }: { match: Match }) => ( + +); + +export default function AuthenticatedRoutes() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + } + > + + + + + + + ); +} diff --git a/app/routes/index.js b/app/routes/index.js new file mode 100644 index 000000000..2be6870fb --- /dev/null +++ b/app/routes/index.js @@ -0,0 +1,31 @@ +// @flow +import * as React from "react"; +import { Switch, Route } from "react-router-dom"; +import DelayedMount from "components/DelayedMount"; +import FullscreenLoading from "components/FullscreenLoading"; + +const Authenticated = React.lazy(() => import("components/Authenticated")); +const AuthenticatedRoutes = React.lazy(() => import("./authenticated")); +const KeyedDocument = React.lazy(() => import("scenes/Document/KeyedDocument")); +const Login = React.lazy(() => import("scenes/Login")); + +export default function Routes() { + return ( + + + + } + > + + + + + + + + + + ); +} diff --git a/app/routes/settings.js b/app/routes/settings.js new file mode 100644 index 000000000..48c85e5c7 --- /dev/null +++ b/app/routes/settings.js @@ -0,0 +1,35 @@ +// @flow +import * as React from "react"; +import { Switch, Route } from "react-router-dom"; +import Settings from "scenes/Settings"; +import Details from "scenes/Settings/Details"; +import Events from "scenes/Settings/Events"; +import Export from "scenes/Settings/Export"; +import Groups from "scenes/Settings/Groups"; +import Notifications from "scenes/Settings/Notifications"; +import People from "scenes/Settings/People"; +import Security from "scenes/Settings/Security"; +import Shares from "scenes/Settings/Shares"; +import Slack from "scenes/Settings/Slack"; +import Tokens from "scenes/Settings/Tokens"; +import Zapier from "scenes/Settings/Zapier"; + +export default function SettingsRoutes() { + return ( + + + + + + + + + + + + + + + + ); +} diff --git a/app/scenes/Collection.js b/app/scenes/Collection.js index 256bffddc..9a4e9b99b 100644 --- a/app/scenes/Collection.js +++ b/app/scenes/Collection.js @@ -5,7 +5,6 @@ import { observer, inject } from "mobx-react"; import { NewDocumentIcon, PlusIcon, PinIcon } from "outline-icons"; import * as React from "react"; import { Redirect, Link, Switch, Route, type Match } from "react-router-dom"; -import RichMarkdownEditor from "rich-markdown-editor"; import styled, { withTheme } from "styled-components"; import CollectionsStore from "stores/CollectionsStore"; @@ -22,6 +21,7 @@ import Button from "components/Button"; import CenteredContent from "components/CenteredContent"; import CollectionIcon from "components/CollectionIcon"; import DocumentList from "components/DocumentList"; +import Editor from "components/Editor"; import Flex from "components/Flex"; import Heading from "components/Heading"; import HelpText from "components/HelpText"; @@ -218,13 +218,14 @@ class CollectionScene extends React.Component { {collection.description && ( - + Loading…

}> + +
)} {hasPinnedDocuments && ( diff --git a/app/scenes/Document/components/DataLoader.js b/app/scenes/Document/components/DataLoader.js index 60f5d6e74..ee119623a 100644 --- a/app/scenes/Document/components/DataLoader.js +++ b/app/scenes/Document/components/DataLoader.js @@ -128,7 +128,7 @@ class DataLoader extends React.Component { // If we're attempting to update an archived, deleted, or otherwise // uneditable document then forward to the canonical read url. if (!can.update && this.isEditing) { - this.props.history.push(this.document.url); + this.props.history.push(document.url); return; } diff --git a/app/scenes/Document/components/Document.js b/app/scenes/Document/components/Document.js index 78b3f7334..847fdc4fa 100644 --- a/app/scenes/Document/components/Document.js +++ b/app/scenes/Document/components/Document.js @@ -24,9 +24,9 @@ import Time from "components/Time"; import Container from "./Container"; import Contents from "./Contents"; import DocumentMove from "./DocumentMove"; +import Editor from "./Editor"; import Header from "./Header"; import KeyboardShortcutsButton from "./KeyboardShortcutsButton"; -import Loading from "./Loading"; import MarkAsViewed from "./MarkAsViewed"; import References from "./References"; import { type LocationWithState } from "types"; @@ -39,7 +39,6 @@ import { documentUrl, } from "utils/routeHelpers"; -let EditorImport; const AUTOSAVE_DELAY = 3000; const IS_DIRTY_DELAY = 500; const DISCARD_CHANGES = ` @@ -69,7 +68,6 @@ type Props = { @observer class DocumentScene extends React.Component { @observable editor: ?any; - @observable editorComponent = EditorImport; @observable isUploading: boolean = false; @observable isSaving: boolean = false; @observable isPublishing: boolean = false; @@ -84,7 +82,6 @@ class DocumentScene extends React.Component { super(); this.title = props.document.title; this.lastRevision = props.document.revision; - this.loadEditor(); } componentDidMount() { @@ -197,25 +194,6 @@ class DocumentScene extends React.Component { } } - loadEditor = async () => { - if (this.editorComponent) return; - - try { - const EditorImport = await import("./Editor"); - this.editorComponent = EditorImport.default; - } catch (err) { - if (err.message && err.message.match(/chunk/)) { - // If the editor bundle fails to load then reload the entire window. This - // can happen if a deploy happens between the user loading the initial JS - // bundle and the async-loaded editor JS bundle as the hash will change. - window.location.reload(); - return; - } - - throw err; - } - }; - handleCloseMoveModal = () => (this.moveModalOpen = false); handleOpenMoveModal = () => (this.moveModalOpen = true); @@ -338,20 +316,14 @@ class DocumentScene extends React.Component { document, revision, readOnly, - location, abilities, auth, ui, match, } = this.props; const team = auth.team; - const Editor = this.editorComponent; const isShare = !!match.params.shareId; - if (!Editor) { - return ; - } - const value = revision ? revision.text : document.text; const injectTemplate = document.injectTemplate; const disableEmbeds = diff --git a/app/scenes/Document/components/Editor.js b/app/scenes/Document/components/Editor.js index 1ea00a158..023aea02a 100644 --- a/app/scenes/Document/components/Editor.js +++ b/app/scenes/Document/components/Editor.js @@ -3,7 +3,6 @@ import { observable } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; import Textarea from "react-autosize-textarea"; -import RichMarkdownEditor from "rich-markdown-editor"; import styled from "styled-components"; import parseTitle from "shared/utils/parseTitle"; import Document from "models/Document"; @@ -12,6 +11,7 @@ import DocumentMetaWithViews from "components/DocumentMetaWithViews"; import Editor from "components/Editor"; import Flex from "components/Flex"; import HoverPreview from "components/HoverPreview"; +import LoadingPlaceholder from "components/LoadingPlaceholder"; import { documentHistoryUrl } from "utils/routeHelpers"; type Props = { @@ -27,7 +27,7 @@ type Props = { @observer class DocumentEditor extends React.Component { @observable activeLinkEvent: ?MouseEvent; - editor = React.createRef(); + editor = React.createRef(); focusAtStart = () => { if (this.editor.current) { @@ -78,39 +78,43 @@ class DocumentEditor extends React.Component { return ( - - <DocumentMetaWithViews - isDraft={isDraft} - document={document} - to={documentHistoryUrl(document)} - /> - <Editor - ref={this.editor} - autoFocus={title && !this.props.defaultValue} - placeholder="…the rest is up to you" - onHoverLink={this.handleLinkActive} - scrollTo={window.location.hash} - grow - {...this.props} - /> - {!readOnly && <ClickablePadding onClick={this.focusAtEnd} grow />} - {this.activeLinkEvent && !isShare && readOnly && ( - <HoverPreview - node={this.activeLinkEvent.target} - event={this.activeLinkEvent} - onClose={this.handleLinkInactive} + <React.Suspense fallback={<LoadingPlaceholder />}> + <Title + type="text" + onChange={onChangeTitle} + onKeyDown={this.handleTitleKeyDown} + placeholder={document.placeholder} + value={!title && readOnly ? document.titleWithDefault : title} + style={ + startsWithEmojiAndSpace ? { marginLeft: "-1.2em" } : undefined + } + readOnly={readOnly} + autoFocus={!title} + maxLength={100} /> - )} + <DocumentMetaWithViews + isDraft={isDraft} + document={document} + to={documentHistoryUrl(document)} + /> + <Editor + ref={this.editor} + autoFocus={title && !this.props.defaultValue} + placeholder="…the rest is up to you" + onHoverLink={this.handleLinkActive} + scrollTo={window.location.hash} + grow + {...this.props} + /> + {!readOnly && <ClickablePadding onClick={this.focusAtEnd} grow />} + {this.activeLinkEvent && !isShare && readOnly && ( + <HoverPreview + node={this.activeLinkEvent.target} + event={this.activeLinkEvent} + onClose={this.handleLinkInactive} + /> + )} + </React.Suspense> </Flex> ); } diff --git a/app/utils/ApiClient.js b/app/utils/ApiClient.js index 09b25c41c..545f0578d 100644 --- a/app/utils/ApiClient.js +++ b/app/utils/ApiClient.js @@ -1,7 +1,6 @@ // @flow import invariant from "invariant"; import { map, trim } from "lodash"; -import pkg from "rich-markdown-editor/package.json"; import stores from "stores"; import download from "./download"; import { @@ -57,7 +56,7 @@ class ApiClient { Accept: "application/json", "Content-Type": "application/json", "cache-control": "no-cache", - "x-editor-version": pkg.version, + "x-editor-version": EDITOR_VERSION, pragma: "no-cache", }); if (stores.auth.authenticated) { diff --git a/flow-typed/globals.js b/flow-typed/globals.js index 050ab88e7..f90a60a40 100644 --- a/flow-typed/globals.js +++ b/flow-typed/globals.js @@ -4,3 +4,5 @@ declare var process: { [string]: string, }, }; + +declare var EDITOR_VERSION: string; diff --git a/package.json b/package.json index 8ab3010b9..1abe7a917 100644 --- a/package.json +++ b/package.json @@ -191,4 +191,4 @@ "js-yaml": "^3.13.1" }, "version": "0.46.0" -} +} \ No newline at end of file diff --git a/server/services/backlinks.js b/server/services/backlinks.js index 1d1995650..2fe1686ca 100644 --- a/server/services/backlinks.js +++ b/server/services/backlinks.js @@ -1,8 +1,8 @@ // @flow import { difference } from "lodash"; -import parseDocumentIds from "../../shared/utils/parseDocumentIds"; import type { DocumentEvent } from "../events"; import { Document, Revision, Backlink } from "../models"; +import parseDocumentIds from "../utils/parseDocumentIds"; import slugify from "../utils/slugify"; export default class Backlinks { diff --git a/shared/utils/parseDocumentIds.js b/server/utils/parseDocumentIds.js similarity index 83% rename from shared/utils/parseDocumentIds.js rename to server/utils/parseDocumentIds.js index 6f3147e68..6a4f557f9 100644 --- a/shared/utils/parseDocumentIds.js +++ b/server/utils/parseDocumentIds.js @@ -37,14 +37,3 @@ export default function parseDocumentIds(text: string): string[] { findLinks(value); return links; } - -export function parseDocumentSlugFromUrl(url: string) { - let parsed; - try { - parsed = new URL(url); - } catch (err) { - return; - } - - return parsed.pathname.replace(/^\/doc\//, ""); -} diff --git a/shared/utils/parseDocumentIds.test.js b/server/utils/parseDocumentIds.test.js similarity index 100% rename from shared/utils/parseDocumentIds.test.js rename to server/utils/parseDocumentIds.test.js diff --git a/shared/utils/parseDocumentSlug.js b/shared/utils/parseDocumentSlug.js new file mode 100644 index 000000000..19e9ed6ba --- /dev/null +++ b/shared/utils/parseDocumentSlug.js @@ -0,0 +1,12 @@ +// @flow + +export function parseDocumentSlugFromUrl(url: string) { + let parsed; + try { + parsed = new URL(url); + } catch (err) { + return; + } + + return parsed.pathname.replace(/^\/doc\//, ""); +} diff --git a/webpack.config.dev.js b/webpack.config.dev.js index 52f565cc6..447593ef0 100644 --- a/webpack.config.dev.js +++ b/webpack.config.dev.js @@ -10,6 +10,9 @@ const developmentWebpackConfig = Object.assign(commonWebpackConfig, { "webpack-hot-middleware/client", "./app/index", ], + optimization: { + usedExports: true, + }, }); developmentWebpackConfig.plugins = [ diff --git a/webpack.config.js b/webpack.config.js index 533bd04e8..e95c8da73 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,6 +3,7 @@ const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const { RelativeCiAgentWebpackPlugin } = require('@relative-ci/agent'); +const pkg = require("rich-markdown-editor/package.json"); require('dotenv').config({ silent: true }); @@ -48,6 +49,9 @@ module.exports = { } }, plugins: [ + new webpack.DefinePlugin({ + EDITOR_VERSION: JSON.stringify(pkg.version) + }), new webpack.ProvidePlugin({ fetch: 'imports-loader?this=>global!exports-loader?global.fetch!isomorphic-fetch', }), diff --git a/yarn.lock b/yarn.lock index db4b61ae1..1967a24dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,14 +2,7 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== - dependencies: - "@babel/highlight" "^7.8.3" - -"@babel/code-frame@^7.10.4": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== @@ -47,7 +40,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.11.0": +"@babel/generator@^7.11.0", "@babel/generator@^7.8.6": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.0.tgz#4b90c78d8c12825024568cbe83ee6c9af193585c" integrity sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ== @@ -56,24 +49,7 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.8.6": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.7.tgz#870b3cf7984f5297998152af625c4f3e341400f7" - integrity sha512-DQwjiKJqH4C3qGiyQCAExJHoZssn49JTMJgZ8SANGgVFdkupcUhLOdkAeoC6kmHZCPfoDG5M0b6cFlSN5wW7Ew== - dependencies: - "@babel/types" "^7.8.7" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/helper-annotate-as-pure@^7.0.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" - integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-annotate-as-pure@^7.10.4": +"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== @@ -154,7 +130,7 @@ "@babel/traverse" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/helper-function-name@^7.10.4": +"@babel/helper-function-name@^7.10.4", "@babel/helper-function-name@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== @@ -163,29 +139,13 @@ "@babel/template" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/helper-function-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" - integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-get-function-arity@^7.10.4": +"@babel/helper-get-function-arity@^7.10.4", "@babel/helper-get-function-arity@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== dependencies: "@babel/types" "^7.10.4" -"@babel/helper-get-function-arity@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" - integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== - dependencies: - "@babel/types" "^7.8.3" - "@babel/helper-hoist-variables@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" @@ -200,14 +160,7 @@ dependencies: "@babel/types" "^7.11.0" -"@babel/helper-module-imports@^7.0.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" - integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-imports@^7.0.0-beta.49", "@babel/helper-module-imports@^7.10.4": +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.0.0-beta.49", "@babel/helper-module-imports@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== @@ -282,30 +235,18 @@ dependencies: "@babel/types" "^7.11.0" -"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": +"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0", "@babel/helper-split-export-declaration@^7.8.3": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== dependencies: "@babel/types" "^7.11.0" -"@babel/helper-split-export-declaration@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" - integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-validator-identifier@^7.10.4": +"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.9.0": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== -"@babel/helper-validator-identifier@^7.9.0": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" - integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== - "@babel/helper-wrap-function@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" @@ -325,16 +266,7 @@ "@babel/traverse" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/highlight@^7.0.0", "@babel/highlight@^7.8.3": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" - integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/highlight@^7.10.4": +"@babel/highlight@^7.0.0", "@babel/highlight@^7.10.4", "@babel/highlight@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== @@ -343,16 +275,11 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.1", "@babel/parser@^7.7.0": +"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.1", "@babel/parser@^7.7.0", "@babel/parser@^7.8.6": version "7.11.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.3.tgz#9e1eae46738bcd08e23e867bab43e7b95299a8f9" integrity sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA== -"@babel/parser@^7.8.6": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.7.tgz#7b8facf95d25fef9534aad51c4ffecde1a61e26a" - integrity sha512-9JWls8WilDXFGxs0phaXAZgpxTZhSk/yOYH2hTHC0X1yC7Z78IJfvR1vJ+rmJKq3I35td2XzXzN6ZLYlna+r/A== - "@babel/plugin-proposal-async-generator-functions@^7.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz#3491cabf2f7c179ab820606cec27fed15e0e8558" @@ -897,15 +824,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/polyfill@^7.0.0": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.8.7.tgz#151ec24c7135481336168c3bd8b8bf0cf91c032f" - integrity sha512-LeSfP9bNZH2UOZgcGcZ0PIHUt1ZuHub1L3CVmEyqLxCeDLm4C5Gi8jRH8ZX2PNpDhQCo0z6y/+DIs2JlliXW8w== - dependencies: - core-js "^2.6.5" - regenerator-runtime "^0.13.4" - -"@babel/polyfill@^7.10.4": +"@babel/polyfill@^7.0.0", "@babel/polyfill@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.10.4.tgz#915e5bfe61490ac0199008e35ca9d7d151a8e45a" integrity sha512-8BYcnVqQ5kMD2HXoHInBH7H1b/uP3KdnwCYXOqFnXqguOyuu443WXusbIUbWEfY3Z0Txk0M1uG/8YuAMhNl6zg== @@ -1038,28 +957,14 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.4.0": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" - integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.10.2", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.4.0", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.9.2": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.1.tgz#b6eb75cac279588d3100baecd1b9894ea2840822" - integrity sha512-nQbbCbQc9u/rpg1XCxoMYQTbSMVZjCDxErQ1ClCn9Pvcmv1lGads19ep0a2VsEiIJeHqjZley6EQGEC3Yo1xMA== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.10.4", "@babel/template@^7.3.3": +"@babel/template@^7.10.4", "@babel/template@^7.3.3", "@babel/template@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== @@ -1068,16 +973,7 @@ "@babel/parser" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/template@^7.8.3": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" - integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0", "@babel/traverse@^7.7.0": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.0.tgz#9b996ce1b98f53f7c3e4175115605d56ed07dd24" integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg== @@ -1092,22 +988,7 @@ globals "^11.1.0" lodash "^4.17.19" -"@babel/traverse@^7.4.5": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.6.tgz#acfe0c64e1cd991b3e32eae813a6eb564954b5ff" - integrity sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.6" - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": +"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.8.7": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d" integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA== @@ -1116,15 +997,6 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" -"@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.7.tgz#1fc9729e1acbb2337d5b6977a63979b4819f5d1d" - integrity sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw== - dependencies: - esutils "^2.0.2" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -1964,12 +1836,7 @@ ajv-errors@^1.0.0: resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== -ajv-keywords@^3.1.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" - integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== - -ajv-keywords@^3.4.1: +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== @@ -1984,17 +1851,7 @@ ajv@^5.0.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5: - version "6.12.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" - integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^6.10.0, ajv@^6.12.2: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.5.5: version "6.12.3" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706" integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA== @@ -2428,17 +2285,7 @@ babel-plugin-lodash@^3.3.4: lodash "^4.17.10" require-package-name "^2.0.1" -"babel-plugin-styled-components@>= 1": - version "1.10.7" - resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.7.tgz#3494e77914e9989b33cc2d7b3b29527a949d635c" - integrity sha512-MBMHGcIA22996n9hZRf/UJLVVgkEOITuR2SvjHLb5dSTUyR4ZRGn+ngITapes36FI3WLxZHfRhkA1ffHxihOrg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-module-imports" "^7.0.0" - babel-plugin-syntax-jsx "^6.18.0" - lodash "^4.17.11" - -babel-plugin-styled-components@^1.11.1: +"babel-plugin-styled-components@>= 1", babel-plugin-styled-components@^1.11.1: version "1.11.1" resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.11.1.tgz#5296a9e557d736c3186be079fff27c6665d63d76" integrity sha512-YwrInHyKUk1PU3avIRdiLyCpM++18Rs1NgyMXEAQC33rIXs/vro0A+stf4sT0Gf22Got+xRWB8Cm0tw+qkRzBA== @@ -4347,12 +4194,7 @@ entities@^1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== -entities@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" - integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== - -entities@~2.0.0: +entities@^2.0.0, entities@~2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.2.tgz#ac74db0bba8d33808bbf36809c3a5c3683531436" integrity sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw== @@ -4589,16 +4431,11 @@ eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.3.0: +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint-visitor-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" - integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== - eslint@^7.6.0: version "7.6.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.6.0.tgz#522d67cfaea09724d96949c70e7a0550614d64d6" @@ -5464,12 +5301,7 @@ got@^8.3.2: url-parse-lax "^3.0.0" url-to-options "^1.0.1" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - -graceful-fs@^4.1.15, graceful-fs@^4.2.0, graceful-fs@^4.2.4: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== @@ -6020,12 +5852,7 @@ internal-slot@^1.0.2: has "^1.0.3" side-channel "^1.0.2" -interpret@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" - integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== - -interpret@^1.4.0: +interpret@^1.0.0, interpret@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== @@ -6855,16 +6682,7 @@ jest-watcher@^26.2.0: jest-util "^26.2.0" string-length "^4.0.1" -jest-worker@^26.2.1: - version "26.2.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.2.1.tgz#5d630ab93f666b53f911615bc13e662b382bd513" - integrity sha512-+XcGMMJDTeEGncRb5M5Zq9P7K4sQ1sirhjdOxsN1462h6lFo9w59bl2LVQmdGEEeU3m+maZCkS2Tcc9SfCHO4A== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - -jest-worker@^26.3.0: +jest-worker@^26.2.1, jest-worker@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.3.0.tgz#7c8a97e4f4364b4f05ed8bca8ca0c24de091871f" integrity sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw== @@ -8180,12 +7998,7 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo-async@^2.5.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" - integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== - -neo-async@^2.6.1: +neo-async@^2.5.0, neo-async@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -9311,19 +9124,10 @@ prosemirror-utils@^0.9.6: resolved "https://registry.yarnpkg.com/prosemirror-utils/-/prosemirror-utils-0.9.6.tgz#3d97bd85897e3b535555867dc95a51399116a973" integrity sha512-UC+j9hQQ1POYfMc5p7UFxBTptRiGPR7Kkmbl3jVvU8VgQbkI89tR/GK+3QYC8n+VvBZrtAoCrJItNhWSxX3slA== -prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3: - version "1.14.9" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.14.9.tgz#9efb96f362caaa0c25f0676f226202f48b500fb4" - integrity sha512-b2aMFJR9mHyKc0Zvk3lNS7Fw12LqQXIiEJj1oAMjr/cEJpPIbGNpb2z7+c0fyGA/41F+fnEyKSZiTwpgno37iw== - dependencies: - prosemirror-model "^1.1.0" - prosemirror-state "^1.0.0" - prosemirror-transform "^1.1.0" - -prosemirror-view@^1.14.11: - version "1.14.11" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.14.11.tgz#cb1fa9910ac5c834fd8bb15598d4ed6609465a5c" - integrity sha512-zcd6saORBuYkn2bVh9Nqu0BfSPE4xl2ct3VpWTu/BUShs/8hlIpckxz/9+NwcDqgYc+AgBgo/XcL0HNcLdxvjw== +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.14.11: + version "1.15.4" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.15.4.tgz#69a6217e3557dd1eb34a6d45caed1c3ee8e05b12" + integrity sha512-SzcszIrDJnQIS+f7WiS5KmQBfdYEhPqp/Hx9bKmXH7ZxrxRiBKPy1/9MoZzxjXUkm+5WHjX+N1fjAMXKoz/OQw== dependencies: prosemirror-model "^1.1.0" prosemirror-state "^1.0.0" @@ -10024,14 +9828,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.13.1, resolve@^1.5.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.16.1.tgz#49fac5d8bacf1fd53f200fa51247ae736175832c" - integrity sha512-rmAglCSqWWMrrBv/XM6sW0NuRFiKViw/W4d9EbC4pt+49H8JwHy+mcGmALTEg504AUDcLTvb1T2q3E9AnmY+ig== - dependencies: - path-parse "^1.0.6" - -resolve@^1.12.0, resolve@^1.17.0, resolve@^1.3.2: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.5.0: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== @@ -11428,16 +11225,11 @@ tsconfig-paths@^3.9.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.9.0: +tslib@^1.9.0, tslib@^1.9.3: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== -tslib@^1.9.3: - version "1.11.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" - integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== - tsscmp@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" @@ -11534,12 +11326,7 @@ typescript-compiler@^1.4.1-2: resolved "https://registry.yarnpkg.com/typescript-compiler/-/typescript-compiler-1.4.1-2.tgz#ba4f7db22d91534a1929d90009dce161eb72fd3f" integrity sha1-uk99si2RU0oZKdkACdzhYety/T8= -typescript@^3.4: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== - -typescript@^3.7.5: +typescript@^3.4, typescript@^3.7.5: version "3.9.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9" integrity sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw== @@ -12198,12 +11985,7 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" -ws@^7.1.2: - version "7.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" - integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ== - -ws@^7.2.3: +ws@^7.1.2, ws@^7.2.3: version "7.3.1" resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==