chore: Replace lodash with es-toolkit (#12281)

* chore: Replace lodash with es-toolkit

Migrate all direct lodash imports to es-toolkit/compat for a smaller,
faster, lodash-compatible utility library. Transitive lodash usage from
other packages remains unchanged.

* fix: Restore isPlainObject semantics in CanCan policy

The lodash migration aliased `isObject` to `lodash/isPlainObject` and
the codemod incorrectly mapped the local name to es-toolkit's `isObject`,
which also returns true for arrays and functions. This caused condition
objects in policy definitions to be skipped, breaking authorization
checks across the codebase.

* fix: Restore unicode-aware length counting in validators

es-toolkit/compat's size() returns string.length, while lodash's _.size()
counts unicode code points. Switch to [...value].length to preserve the
previous behavior so multi-byte characters like emoji count as one.
This commit is contained in:
Tom Moor
2026-05-06 21:03:47 -04:00
committed by GitHub
parent 4387f3ced7
commit 0139b91b5d
223 changed files with 266 additions and 335 deletions
+1 -2
View File
@@ -1,6 +1,6 @@
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
import invariant from "invariant"; import invariant from "invariant";
import uniqBy from "lodash/uniqBy"; import { capitalize, uniqBy } from "es-toolkit/compat";
import { import {
DownloadIcon, DownloadIcon,
DuplicateIcon, DuplicateIcon,
@@ -81,7 +81,6 @@ import {
trashPath, trashPath,
documentEditPath, documentEditPath,
} from "~/utils/routeHelpers"; } from "~/utils/routeHelpers";
import capitalize from "lodash/capitalize";
import CollectionIcon from "~/components/Icons/CollectionIcon"; import CollectionIcon from "~/components/Icons/CollectionIcon";
import type { import type {
Action, Action,
+1 -1
View File
@@ -1,6 +1,6 @@
/* oxlint-disable prefer-rest-params */ /* oxlint-disable prefer-rest-params */
/* global ga */ /* global ga */
import escape from "lodash/escape"; import { escape } from "es-toolkit/compat";
import * as React from "react"; import * as React from "react";
import type { PublicEnv } from "@shared/types"; import type { PublicEnv } from "@shared/types";
import { IntegrationService } from "@shared/types"; import { IntegrationService } from "@shared/types";
+1 -4
View File
@@ -1,7 +1,4 @@
import filter from "lodash/filter"; import { filter, isEqual, orderBy, uniq } from "es-toolkit/compat";
import isEqual from "lodash/isEqual";
import orderBy from "lodash/orderBy";
import uniq from "lodash/uniq";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useState, useMemo, useEffect, useCallback } from "react"; import { useState, useMemo, useEffect, useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
+1 -1
View File
@@ -1,4 +1,4 @@
import uniq from "lodash/uniq"; import { uniq } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useMemo, useEffect, useCallback, Suspense } from "react"; import { useMemo, useEffect, useCallback, Suspense } from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
@@ -1,5 +1,5 @@
import { useKBar } from "kbar"; import { useKBar } from "kbar";
import escapeRegExp from "lodash/escapeRegExp"; import { escapeRegExp } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { DocumentIcon } from "outline-icons"; import { DocumentIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
@@ -1,11 +1,13 @@
import FuzzySearch from "fuzzy-search"; import FuzzySearch from "fuzzy-search";
import concat from "lodash/concat"; import {
import difference from "lodash/difference"; concat,
import fill from "lodash/fill"; difference,
import filter from "lodash/filter"; fill,
import flatten from "lodash/flatten"; filter,
import includes from "lodash/includes"; flatten,
import map from "lodash/map"; includes,
map,
} from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { StarredIcon, DocumentIcon } from "outline-icons"; import { StarredIcon, DocumentIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
+1 -2
View File
@@ -1,5 +1,4 @@
import compact from "lodash/compact"; import { compact, sortBy } from "es-toolkit/compat";
import sortBy from "lodash/sortBy";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useMemo, useCallback } from "react"; import { useMemo, useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
+1 -1
View File
@@ -1,4 +1,4 @@
import difference from "lodash/difference"; import { difference } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { DOMParser as ProsemirrorDOMParser } from "prosemirror-model"; import { DOMParser as ProsemirrorDOMParser } from "prosemirror-model";
import { TextSelection } from "prosemirror-state"; import { TextSelection } from "prosemirror-state";
+1 -1
View File
@@ -1,4 +1,4 @@
import deburr from "lodash/deburr"; import { deburr } from "es-toolkit/compat";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import styled from "styled-components"; import styled from "styled-components";
+1 -1
View File
@@ -1,4 +1,4 @@
import throttle from "lodash/throttle"; import { throttle } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { MenuIcon } from "outline-icons"; import { MenuIcon } from "outline-icons";
import { transparentize } from "polished"; import { transparentize } from "polished";
+1 -1
View File
@@ -1,4 +1,4 @@
import escapeRegExp from "lodash/escapeRegExp"; import { escapeRegExp } from "es-toolkit/compat";
import * as React from "react"; import * as React from "react";
import replace from "string-replace-to-array"; import replace from "string-replace-to-array";
import styled from "styled-components"; import styled from "styled-components";
@@ -1,4 +1,4 @@
import concat from "lodash/concat"; import { concat } from "es-toolkit/compat";
import { PlusIcon } from "outline-icons"; import { PlusIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -1,5 +1,4 @@
import chunk from "lodash/chunk"; import { chunk, compact } from "es-toolkit/compat";
import compact from "lodash/compact";
import * as React from "react"; import * as React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { IconType } from "@shared/types"; import { IconType } from "@shared/types";
+1 -1
View File
@@ -1,5 +1,5 @@
import { m } from "framer-motion"; import { m } from "framer-motion";
import find from "lodash/find"; import { find } from "es-toolkit/compat";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import styled from "styled-components"; import styled from "styled-components";
import { languages, languageOptions } from "@shared/i18n"; import { languages, languageOptions } from "@shared/i18n";
+1 -1
View File
@@ -40,7 +40,7 @@ import CopyToClipboard from "./CopyToClipboard";
import { Separator } from "./Actions"; import { Separator } from "./Actions";
import useSwipe from "~/hooks/useSwipe"; import useSwipe from "~/hooks/useSwipe";
import { toast } from "sonner"; import { toast } from "sonner";
import { findIndex } from "lodash"; import { findIndex } from "es-toolkit/compat";
import type { LightboxImage } from "@shared/editor/lib/Lightbox"; import type { LightboxImage } from "@shared/editor/lib/Lightbox";
import type { ReactZoomPanPinchRef } from "react-zoom-pan-pinch"; import type { ReactZoomPanPinchRef } from "react-zoom-pan-pinch";
import { import {
+1 -1
View File
@@ -1,4 +1,4 @@
import times from "lodash/times"; import { times } from "es-toolkit/compat";
import styled from "styled-components"; import styled from "styled-components";
import Fade from "~/components/Fade"; import Fade from "~/components/Fade";
import Flex from "~/components/Flex"; import Flex from "~/components/Flex";
+1 -1
View File
@@ -1,4 +1,4 @@
import isEqual from "lodash/isEqual"; import { isEqual } from "es-toolkit/compat";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Waypoint } from "react-waypoint"; import { Waypoint } from "react-waypoint";
+1 -1
View File
@@ -1,4 +1,4 @@
import compact from "lodash/compact"; import { compact } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import type Comment from "~/models/Comment"; import type Comment from "~/models/Comment";
@@ -1,4 +1,4 @@
import compact from "lodash/compact"; import { compact } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -1,6 +1,5 @@
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
import debounce from "lodash/debounce"; import { debounce, isEmpty } from "es-toolkit/compat";
import isEmpty from "lodash/isEmpty";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { CopyIcon, GlobeIcon } from "outline-icons"; import { CopyIcon, GlobeIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
@@ -1,4 +1,4 @@
import orderBy from "lodash/orderBy"; import { orderBy } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import { useTranslation, Trans } from "react-i18next"; import { useTranslation, Trans } from "react-i18next";
@@ -1,6 +1,5 @@
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
import debounce from "lodash/debounce"; import { debounce, isEmpty } from "es-toolkit/compat";
import isEmpty from "lodash/isEmpty";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { CopyIcon, GlobeIcon } from "outline-icons"; import { CopyIcon, GlobeIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
@@ -1,4 +1,4 @@
import times from "lodash/times"; import { times } from "es-toolkit/compat";
import { AvatarSize } from "~/components/Avatar"; import { AvatarSize } from "~/components/Avatar";
import Fade from "~/components/Fade"; import Fade from "~/components/Fade";
import PlaceholderText from "~/components/PlaceholderText"; import PlaceholderText from "~/components/PlaceholderText";
@@ -1,5 +1,4 @@
import debounce from "lodash/debounce"; import { debounce, uniqueId } from "es-toolkit/compat";
import uniqueId from "lodash/uniqueId";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { import {
ImageIcon, ImageIcon,
@@ -1,5 +1,5 @@
import { isEmail } from "class-validator"; import { isEmail } from "class-validator";
import concat from "lodash/concat"; import { concat } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { CheckmarkIcon, CloseIcon } from "outline-icons"; import { CheckmarkIcon, CloseIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
+1 -1
View File
@@ -1,4 +1,4 @@
import groupBy from "lodash/groupBy"; import { groupBy } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { BackIcon, SidebarIcon } from "outline-icons"; import { BackIcon, SidebarIcon } from "outline-icons";
import { useCallback } from "react"; import { useCallback } from "react";
@@ -1,4 +1,4 @@
import isUndefined from "lodash/isUndefined"; import { isUndefined } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { ArchiveIcon } from "outline-icons"; import { ArchiveIcon } from "outline-icons";
import { useState, useEffect, useCallback } from "react"; import { useState, useEffect, useCallback } from "react";
@@ -1,4 +1,4 @@
import noop from "lodash/noop"; import { noop } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useState, useRef, useEffect, useCallback } from "react"; import { useState, useRef, useEffect, useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
+1 -1
View File
@@ -1,6 +1,6 @@
import { m } from "framer-motion"; import { m } from "framer-motion";
import type { LocationDescriptor } from "history"; import type { LocationDescriptor } from "history";
import isEqual from "lodash/isEqual"; import { isEqual } from "es-toolkit/compat";
import queryString from "query-string"; import queryString from "query-string";
import * as React from "react"; import * as React from "react";
import styled, { css, useTheme } from "styled-components"; import styled, { css, useTheme } from "styled-components";
+1 -1
View File
@@ -1,6 +1,6 @@
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import invariant from "invariant"; import invariant from "invariant";
import find from "lodash/find"; import { find } from "es-toolkit/compat";
import { action } from "mobx"; import { action } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { createContext, useEffect, useState } from "react"; import { createContext, useEffect, useState } from "react";
+1 -1
View File
@@ -1,5 +1,5 @@
import { DocumentIcon, ShapesIcon } from "outline-icons"; import { DocumentIcon, ShapesIcon } from "outline-icons";
import cloneDeep from "lodash/cloneDeep"; import { cloneDeep } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useCallback, useMemo } from "react"; import { useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
+1 -1
View File
@@ -1,4 +1,4 @@
import capitalize from "lodash/capitalize"; import { capitalize } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useCallback, useMemo, useEffect } from "react"; import { useCallback, useMemo, useEffect } from "react";
import { emojiMartToGemoji, snakeCase } from "@shared/editor/lib/emoji"; import { emojiMartToGemoji, snakeCase } from "@shared/editor/lib/emoji";
+1 -1
View File
@@ -1,4 +1,4 @@
import isEqual from "lodash/isEqual"; import { isEqual } from "es-toolkit/compat";
import { action, computed, observable } from "mobx"; import { action, computed, observable } from "mobx";
import type { FunctionComponent } from "react"; import type { FunctionComponent } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
+1 -2
View File
@@ -1,7 +1,6 @@
import * as VisuallyHidden from "@radix-ui/react-visually-hidden"; import * as VisuallyHidden from "@radix-ui/react-visually-hidden";
import commandScore from "command-score"; import commandScore from "command-score";
import capitalize from "lodash/capitalize"; import { capitalize, orderBy } from "es-toolkit/compat";
import orderBy from "lodash/orderBy";
import { TextSelection } from "prosemirror-state"; import { TextSelection } from "prosemirror-state";
import * as React from "react"; import * as React from "react";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
+1 -2
View File
@@ -1,5 +1,4 @@
import deburr from "lodash/deburr"; import { deburr, escapeRegExp } from "es-toolkit/compat";
import escapeRegExp from "lodash/escapeRegExp";
import { observable } from "mobx"; import { observable } from "mobx";
import type { Node } from "prosemirror-model"; import type { Node } from "prosemirror-model";
import type { Command } from "prosemirror-state"; import type { Command } from "prosemirror-state";
+1 -1
View File
@@ -1,5 +1,5 @@
import type { HocuspocusProvider } from "@hocuspocus/provider"; import type { HocuspocusProvider } from "@hocuspocus/provider";
import isEqual from "lodash/isEqual"; import { isEqual } from "es-toolkit/compat";
import { Plugin } from "prosemirror-state"; import { Plugin } from "prosemirror-state";
import { import {
ySyncPlugin, ySyncPlugin,
+1 -1
View File
@@ -1,4 +1,4 @@
import escapeRegExp from "lodash/escapeRegExp"; import { escapeRegExp } from "es-toolkit/compat";
import { action, observable } from "mobx"; import { action, observable } from "mobx";
import { InputRule } from "prosemirror-inputrules"; import { InputRule } from "prosemirror-inputrules";
import type { NodeType, Schema } from "prosemirror-model"; import type { NodeType, Schema } from "prosemirror-model";
+1 -2
View File
@@ -53,8 +53,7 @@ import EditorContext from "./components/EditorContext";
import type { NodeViewRenderer } from "./components/NodeViewRenderer"; import type { NodeViewRenderer } from "./components/NodeViewRenderer";
import WithTheme from "./components/WithTheme"; import WithTheme from "./components/WithTheme";
import isNull from "lodash/isNull"; import { isArray, isNull, map } from "es-toolkit/compat";
import { isArray, map } from "lodash";
import type { LightboxImage } from "@shared/editor/lib/Lightbox"; import type { LightboxImage } from "@shared/editor/lib/Lightbox";
import { LightboxImageFactory } from "@shared/editor/lib/Lightbox"; import { LightboxImageFactory } from "@shared/editor/lib/Lightbox";
import Lightbox from "~/components/Lightbox"; import Lightbox from "~/components/Lightbox";
+1 -1
View File
@@ -1,5 +1,5 @@
import { useRegisterActions } from "kbar"; import { useRegisterActions } from "kbar";
import flattenDeep from "lodash/flattenDeep"; import { flattenDeep } from "es-toolkit/compat";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { actionToKBar } from "~/actions"; import { actionToKBar } from "~/actions";
import type { ActionVariant } from "~/types"; import type { ActionVariant } from "~/types";
+1 -1
View File
@@ -1,4 +1,4 @@
import find from "lodash/find"; import { find } from "es-toolkit/compat";
import { useEffect, useMemo } from "react"; import { useEffect, useMemo } from "react";
import embeds from "@shared/editor/embeds"; import embeds from "@shared/editor/embeds";
import { IntegrationType, TeamPreference } from "@shared/types"; import { IntegrationType, TeamPreference } from "@shared/types";
+1 -1
View File
@@ -1,4 +1,4 @@
import throttle from "lodash/throttle"; import { throttle } from "es-toolkit/compat";
import { useState, useRef, useCallback, useEffect } from "react"; import { useState, useRef, useCallback, useEffect } from "react";
import { Minute } from "@shared/utils/time"; import { Minute } from "@shared/utils/time";
import useIsMounted from "./useIsMounted"; import useIsMounted from "./useIsMounted";
+1 -1
View File
@@ -1,4 +1,4 @@
import isEqual from "lodash/isEqual"; import { isEqual } from "es-toolkit/compat";
import { useRef } from "react"; import { useRef } from "react";
import { createRootMenuAction } from "~/actions"; import { createRootMenuAction } from "~/actions";
import type { import type {
+1 -1
View File
@@ -1,4 +1,4 @@
import uniqBy from "lodash/uniqBy"; import { uniqBy } from "es-toolkit/compat";
import { useState, useEffect, useCallback } from "react"; import { useState, useEffect, useCallback } from "react";
import type { PaginationParams } from "~/types"; import type { PaginationParams } from "~/types";
import useRequest from "./useRequest"; import useRequest from "./useRequest";
+1 -1
View File
@@ -1,4 +1,4 @@
import { isNumber } from "lodash"; import { isNumber } from "es-toolkit/compat";
import { useRef } from "react"; import { useRef } from "react";
type Props = { type Props = {
+1 -1
View File
@@ -1,5 +1,5 @@
import type { ColumnSort } from "@tanstack/react-table"; import type { ColumnSort } from "@tanstack/react-table";
import orderBy from "lodash/orderBy"; import { orderBy } from "es-toolkit/compat";
import { useState, useRef, useCallback, useEffect } from "react"; import { useState, useRef, useCallback, useEffect } from "react";
import type { FetchPageParams, PaginatedResponse } from "~/stores/base/Store"; import type { FetchPageParams, PaginatedResponse } from "~/stores/base/Store";
import { PAGINATION_SYMBOL } from "~/stores/base/Store"; import { PAGINATION_SYMBOL } from "~/stores/base/Store";
+1 -1
View File
@@ -1,4 +1,4 @@
import throttle from "lodash/throttle"; import { throttle } from "es-toolkit/compat";
import * as React from "react"; import * as React from "react";
import useUnmount from "./useUnmount"; import useUnmount from "./useUnmount";
+1 -1
View File
@@ -1,6 +1,6 @@
// Based on https://github.com/rehooks/window-scroll-position which is no longer // Based on https://github.com/rehooks/window-scroll-position which is no longer
// maintained. // maintained.
import throttle from "lodash/throttle"; import { throttle } from "es-toolkit/compat";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { supportsPassiveListener } from "@shared/utils/browser"; import { supportsPassiveListener } from "@shared/utils/browser";
+1 -1
View File
@@ -1,4 +1,4 @@
import noop from "lodash/noop"; import { noop } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
+1 -1
View File
@@ -1,5 +1,5 @@
import invariant from "invariant"; import invariant from "invariant";
import uniq from "lodash/uniq"; import { uniq } from "es-toolkit/compat";
import { action, computed, observable } from "mobx"; import { action, computed, observable } from "mobx";
import { Pagination } from "@shared/constants"; import { Pagination } from "@shared/constants";
import type { ProsemirrorData, ReactionSummary } from "@shared/types"; import type { ProsemirrorData, ReactionSummary } from "@shared/types";
+1 -2
View File
@@ -1,7 +1,6 @@
import { addDays, differenceInDays } from "date-fns"; import { addDays, differenceInDays } from "date-fns";
import i18n, { t } from "i18next"; import i18n, { t } from "i18next";
import capitalize from "lodash/capitalize"; import { capitalize, floor } from "es-toolkit/compat";
import floor from "lodash/floor";
import { action, autorun, comparer, computed, observable, set } from "mobx"; import { action, autorun, comparer, computed, observable, set } from "mobx";
import type { import type {
JSONObject, JSONObject,
+1 -1
View File
@@ -1,4 +1,4 @@
import isEqual from "lodash/isEqual"; import { isEqual } from "es-toolkit/compat";
import { computed, observable } from "mobx"; import { computed, observable } from "mobx";
import Model from "./base/Model"; import Model from "./base/Model";
import Field from "./decorators/Field"; import Field from "./decorators/Field";
+1 -2
View File
@@ -1,4 +1,4 @@
import pick from "lodash/pick"; import { isEqual, pick } from "es-toolkit/compat";
import { observable, action, toJS } from "mobx"; import { observable, action, toJS } from "mobx";
import type { JSONObject } from "@shared/types"; import type { JSONObject } from "@shared/types";
import type Store from "~/stores/base/Store"; import type Store from "~/stores/base/Store";
@@ -6,7 +6,6 @@ import Logger from "~/utils/Logger";
import { getFieldsForModel } from "../decorators/Field"; import { getFieldsForModel } from "../decorators/Field";
import { LifecycleManager } from "../decorators/Lifecycle"; import { LifecycleManager } from "../decorators/Lifecycle";
import { getRelationsForModelClass } from "../decorators/Relation"; import { getRelationsForModelClass } from "../decorators/Relation";
import { isEqual } from "lodash";
export default abstract class Model { export default abstract class Model {
static modelName: string; static modelName: string;
+1 -1
View File
@@ -1,6 +1,6 @@
import { IconTitleWrapper } from "@shared/components/Icon"; import { IconTitleWrapper } from "@shared/components/Icon";
import breakpoint from "styled-components-breakpoint"; import breakpoint from "styled-components-breakpoint";
import first from "lodash/first"; import { first } from "es-toolkit/compat";
import { Suspense, useCallback } from "react"; import { Suspense, useCallback } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { CollectionValidation } from "@shared/validations"; import { CollectionValidation } from "@shared/validations";
@@ -1,4 +1,4 @@
import sortBy from "lodash/sortBy"; import { sortBy } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -1,4 +1,4 @@
import debounce from "lodash/debounce"; import { debounce } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useMemo, useRef, useCallback, useEffect, Suspense } from "react"; import { useMemo, useRef, useCallback, useEffect, Suspense } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
+1 -1
View File
@@ -35,7 +35,7 @@ import { decodeURIComponentSafe } from "~/utils/urls";
import MultiplayerEditor from "./AsyncMultiplayerEditor"; import MultiplayerEditor from "./AsyncMultiplayerEditor";
import DocumentMeta from "./DocumentMeta"; import DocumentMeta from "./DocumentMeta";
import DocumentTitle from "./DocumentTitle"; import DocumentTitle from "./DocumentTitle";
import first from "lodash/first"; import { first } from "es-toolkit/compat";
import { getLangFor } from "~/utils/language"; import { getLangFor } from "~/utils/language";
import useShare from "@shared/hooks/useShare"; import useShare from "@shared/hooks/useShare";
@@ -1,5 +1,5 @@
import isEqual from "fast-deep-equal"; import isEqual from "fast-deep-equal";
import orderBy from "lodash/orderBy"; import { orderBy } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -1,5 +1,5 @@
import { HocuspocusProvider, WebSocketStatus } from "@hocuspocus/provider"; import { HocuspocusProvider, WebSocketStatus } from "@hocuspocus/provider";
import throttle from "lodash/throttle"; import { throttle } from "es-toolkit/compat";
import { import {
useState, useState,
useLayoutEffect, useLayoutEffect,
@@ -7,7 +7,7 @@ import Icon from "@shared/components/Icon";
import { richExtensions } from "@shared/editor/nodes"; import { richExtensions } from "@shared/editor/nodes";
import { canUseElementFullscreen } from "@shared/utils/browser"; import { canUseElementFullscreen } from "@shared/utils/browser";
import { s, depths, hover } from "@shared/styles"; import { s, depths, hover } from "@shared/styles";
import cloneDeep from "lodash/cloneDeep"; import { cloneDeep } from "es-toolkit/compat";
import type { ProsemirrorData } from "@shared/types"; import type { ProsemirrorData } from "@shared/types";
import { ProsemirrorHelper } from "@shared/utils/ProsemirrorHelper"; import { ProsemirrorHelper } from "@shared/utils/ProsemirrorHelper";
import { colorPalette } from "@shared/utils/collections"; import { colorPalette } from "@shared/utils/collections";
+1 -3
View File
@@ -1,6 +1,4 @@
import cloneDeep from "lodash/cloneDeep"; import { cloneDeep, debounce, isEqual } from "es-toolkit/compat";
import debounce from "lodash/debounce";
import isEqual from "lodash/isEqual";
import { Node } from "prosemirror-model"; import { Node } from "prosemirror-model";
import type { Selection } from "prosemirror-state"; import type { Selection } from "prosemirror-state";
import { AllSelection, TextSelection } from "prosemirror-state"; import { AllSelection, TextSelection } from "prosemirror-state";
+1 -1
View File
@@ -1,4 +1,4 @@
import find from "lodash/find"; import { find } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { EmailIcon } from "outline-icons"; import { EmailIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
+1 -2
View File
@@ -1,6 +1,5 @@
import type { TFunction } from "i18next"; import type { TFunction } from "i18next";
import capitalize from "lodash/capitalize"; import { capitalize, uniq } from "es-toolkit/compat";
import uniq from "lodash/uniq";
import { Scope } from "@shared/types"; import { Scope } from "@shared/types";
export class OAuthScopeHelper { export class OAuthScopeHelper {
+1 -1
View File
@@ -1,5 +1,5 @@
import { isHexColor } from "class-validator"; import { isHexColor } from "class-validator";
import pickBy from "lodash/pickBy"; import { pickBy } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { TeamIcon } from "outline-icons"; import { TeamIcon } from "outline-icons";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
+1 -1
View File
@@ -1,4 +1,4 @@
import debounce from "lodash/debounce"; import { debounce } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { BrowserIcon } from "outline-icons"; import { BrowserIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
+1 -1
View File
@@ -1,5 +1,5 @@
import type { ColumnSort } from "@tanstack/react-table"; import type { ColumnSort } from "@tanstack/react-table";
import deburr from "lodash/deburr"; import { deburr } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { PlusIcon, GroupIcon } from "outline-icons"; import { PlusIcon, GroupIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
+1 -1
View File
@@ -1,4 +1,4 @@
import orderBy from "lodash/orderBy"; import { orderBy } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { NewDocumentIcon } from "outline-icons"; import { NewDocumentIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
+1 -1
View File
@@ -1,4 +1,4 @@
import groupBy from "lodash/groupBy"; import { groupBy } from "es-toolkit/compat";
import * as React from "react"; import * as React from "react";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import styled from "styled-components"; import styled from "styled-components";
+1 -1
View File
@@ -1,4 +1,4 @@
import debounce from "lodash/debounce"; import { debounce } from "es-toolkit/compat";
import { runInAction } from "mobx"; import { runInAction } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { import {
+1 -1
View File
@@ -1,4 +1,4 @@
import debounce from "lodash/debounce"; import { debounce } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { ShieldIcon } from "outline-icons"; import { ShieldIcon } from "outline-icons";
import { useState } from "react"; import { useState } from "react";
+1 -1
View File
@@ -1,5 +1,5 @@
import type { ColumnSort } from "@tanstack/react-table"; import type { ColumnSort } from "@tanstack/react-table";
import deburr from "lodash/deburr"; import { deburr } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { ShapesIcon } from "outline-icons"; import { ShapesIcon } from "outline-icons";
import { useEffect, useMemo, useCallback, useState } from "react"; import { useEffect, useMemo, useCallback, useState } from "react";
@@ -7,7 +7,7 @@ import useStores from "~/hooks/useStores";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { settingsPath } from "~/utils/routeHelpers"; import { settingsPath } from "~/utils/routeHelpers";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import capitalize from "lodash/capitalize"; import { capitalize } from "es-toolkit/compat";
type Props = { type Props = {
integration: Integration<IntegrationType.Analytics>; integration: Integration<IntegrationType.Analytics>;
@@ -1,4 +1,4 @@
import compact from "lodash/compact"; import { compact } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import { useCallback } from "react"; import { useCallback } from "react";
@@ -1,4 +1,4 @@
import debounce from "lodash/debounce"; import { debounce } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
@@ -1,4 +1,4 @@
import compact from "lodash/compact"; import { compact } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useMemo, useCallback } from "react"; import { useMemo, useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -1,4 +1,4 @@
import compact from "lodash/compact"; import { compact } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { GroupIcon, HiddenIcon } from "outline-icons"; import { GroupIcon, HiddenIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
@@ -1,4 +1,4 @@
import capitalize from "lodash/capitalize"; import { capitalize } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { CrossIcon, DoneIcon, WarningIcon } from "outline-icons"; import { CrossIcon, DoneIcon, WarningIcon } from "outline-icons";
import { useMemo, useCallback } from "react"; import { useMemo, useCallback } from "react";
@@ -1,4 +1,4 @@
import compact from "lodash/compact"; import { compact } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useMemo, useCallback } from "react"; import { useMemo, useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -1,4 +1,4 @@
import compact from "lodash/compact"; import { compact } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import { useMemo, useCallback } from "react"; import { useMemo, useCallback } from "react";
@@ -1,4 +1,4 @@
import compact from "lodash/compact"; import { compact } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { DocumentIcon } from "outline-icons"; import { DocumentIcon } from "outline-icons";
import React, { useCallback } from "react"; import React, { useCallback } from "react";
@@ -1,4 +1,4 @@
import compact from "lodash/compact"; import { compact } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useMemo } from "react"; import { useMemo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -1,4 +1,4 @@
import compact from "lodash/compact"; import { compact } from "es-toolkit/compat";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useMemo } from "react"; import { useMemo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
+1 -1
View File
@@ -1,6 +1,6 @@
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import invariant from "invariant"; import invariant from "invariant";
import isNil from "lodash/isNil"; import { isNil } from "es-toolkit/compat";
import { observable, action, computed, autorun, runInAction } from "mobx"; import { observable, action, computed, autorun, runInAction } from "mobx";
import { getCookie, setCookie } from "tiny-cookie"; import { getCookie, setCookie } from "tiny-cookie";
import type { CustomTheme } from "@shared/types"; import type { CustomTheme } from "@shared/types";
+1 -1
View File
@@ -1,4 +1,4 @@
import orderBy from "lodash/orderBy"; import { orderBy } from "es-toolkit/compat";
import { computed } from "mobx"; import { computed } from "mobx";
import AuthenticationProvider from "~/models/AuthenticationProvider"; import AuthenticationProvider from "~/models/AuthenticationProvider";
import type RootStore from "./RootStore"; import type RootStore from "./RootStore";
+1 -3
View File
@@ -1,7 +1,5 @@
import invariant from "invariant"; import invariant from "invariant";
import isEmpty from "lodash/isEmpty"; import { isEmpty, orderBy, sortBy } from "es-toolkit/compat";
import orderBy from "lodash/orderBy";
import sortBy from "lodash/sortBy";
import { computed, action, runInAction } from "mobx"; import { computed, action, runInAction } from "mobx";
import { import {
CollectionPermission, CollectionPermission,
+1 -5
View File
@@ -1,9 +1,5 @@
import invariant from "invariant"; import invariant from "invariant";
import compact from "lodash/compact"; import { compact, differenceBy, keyBy, orderBy, uniq } from "es-toolkit/compat";
import differenceBy from "lodash/differenceBy";
import keyBy from "lodash/keyBy";
import orderBy from "lodash/orderBy";
import uniq from "lodash/uniq";
import { action, computed } from "mobx"; import { action, computed } from "mobx";
import Comment from "~/models/Comment"; import Comment from "~/models/Comment";
import { type CommentSortOption, CommentSortType } from "~/types"; import { type CommentSortOption, CommentSortType } from "~/types";
+1 -4
View File
@@ -1,8 +1,5 @@
import invariant from "invariant"; import invariant from "invariant";
import compact from "lodash/compact"; import { compact, filter, omitBy, orderBy } from "es-toolkit/compat";
import filter from "lodash/filter";
import omitBy from "lodash/omitBy";
import orderBy from "lodash/orderBy";
import { observable, action, computed, runInAction } from "mobx"; import { observable, action, computed, runInAction } from "mobx";
import type { DirectionFilter, SortFilter } from "@shared/types"; import type { DirectionFilter, SortFilter } from "@shared/types";
import { import {
+1 -1
View File
@@ -1,4 +1,4 @@
import orderBy from "lodash/orderBy"; import { orderBy } from "es-toolkit/compat";
import { computed } from "mobx"; import { computed } from "mobx";
import { FileOperationType } from "@shared/types"; import { FileOperationType } from "@shared/types";
import FileOperation from "~/models/FileOperation"; import FileOperation from "~/models/FileOperation";
+1 -1
View File
@@ -1,5 +1,5 @@
import invariant from "invariant"; import invariant from "invariant";
import filter from "lodash/filter"; import { filter } from "es-toolkit/compat";
import { action, runInAction } from "mobx"; import { action, runInAction } from "mobx";
import GroupUser from "~/models/GroupUser"; import GroupUser from "~/models/GroupUser";
import type { PaginationParams } from "~/types"; import type { PaginationParams } from "~/types";
+1 -1
View File
@@ -1,5 +1,5 @@
import invariant from "invariant"; import invariant from "invariant";
import filter from "lodash/filter"; import { filter } from "es-toolkit/compat";
import { action, runInAction, computed } from "mobx"; import { action, runInAction, computed } from "mobx";
import naturalSort from "@shared/utils/naturalSort"; import naturalSort from "@shared/utils/naturalSort";
import Group from "~/models/Group"; import Group from "~/models/Group";
+1 -2
View File
@@ -1,6 +1,5 @@
import invariant from "invariant"; import invariant from "invariant";
import orderBy from "lodash/orderBy"; import { orderBy, sortBy } from "es-toolkit/compat";
import sortBy from "lodash/sortBy";
import { action, computed, runInAction } from "mobx"; import { action, computed, runInAction } from "mobx";
import Notification from "~/models/Notification"; import Notification from "~/models/Notification";
import type { PaginationParams } from "~/types"; import type { PaginationParams } from "~/types";
+1 -1
View File
@@ -1,5 +1,5 @@
import invariant from "invariant"; import invariant from "invariant";
import lowerFirst from "lodash/lowerFirst"; import { lowerFirst } from "es-toolkit/compat";
import pluralize from "pluralize"; import pluralize from "pluralize";
import ApiKeysStore from "./ApiKeysStore"; import ApiKeysStore from "./ApiKeysStore";
import AuthStore from "./AuthStore"; import AuthStore from "./AuthStore";
+1 -1
View File
@@ -1,4 +1,4 @@
import uniqBy from "lodash/uniqBy"; import { uniqBy } from "es-toolkit/compat";
import { computed } from "mobx"; import { computed } from "mobx";
import SearchQuery from "~/models/SearchQuery"; import SearchQuery from "~/models/SearchQuery";
import type RootStore from "./RootStore"; import type RootStore from "./RootStore";
+1 -4
View File
@@ -1,8 +1,5 @@
import invariant from "invariant"; import invariant from "invariant";
import filter from "lodash/filter"; import { filter, find, isUndefined, orderBy } from "es-toolkit/compat";
import find from "lodash/find";
import isUndefined from "lodash/isUndefined";
import orderBy from "lodash/orderBy";
import { action, computed, observable } from "mobx"; import { action, computed, observable } from "mobx";
import type { NavigationNode, PublicTeam } from "@shared/types"; import type { NavigationNode, PublicTeam } from "@shared/types";
import type Document from "~/models/Document"; import type Document from "~/models/Document";
+1 -2
View File
@@ -1,5 +1,4 @@
import orderBy from "lodash/orderBy"; import { filter, orderBy } from "es-toolkit/compat";
import filter from "lodash/filter";
import { action, computed } from "mobx"; import { action, computed } from "mobx";
import { invariant } from "mobx-utils"; import { invariant } from "mobx-utils";
import naturalSort from "@shared/utils/naturalSort"; import naturalSort from "@shared/utils/naturalSort";
+1 -4
View File
@@ -1,9 +1,6 @@
import commandScore from "command-score"; import commandScore from "command-score";
import invariant from "invariant"; import invariant from "invariant";
import deburr from "lodash/deburr"; import { deburr, differenceWith, filter, orderBy } from "es-toolkit/compat";
import differenceWith from "lodash/differenceWith";
import filter from "lodash/filter";
import orderBy from "lodash/orderBy";
import { computed, action, runInAction } from "mobx"; import { computed, action, runInAction } from "mobx";
import type { UserRole } from "@shared/types"; import type { UserRole } from "@shared/types";
import User from "~/models/User"; import User from "~/models/User";
+1 -4
View File
@@ -1,7 +1,4 @@
import filter from "lodash/filter"; import { filter, find, orderBy, reduce } from "es-toolkit/compat";
import find from "lodash/find";
import orderBy from "lodash/orderBy";
import reduce from "lodash/reduce";
import View from "~/models/View"; import View from "~/models/View";
import type RootStore from "./RootStore"; import type RootStore from "./RootStore";
import Store, { RPCAction } from "./base/Store"; import Store, { RPCAction } from "./base/Store";
+16 -10
View File
@@ -1,13 +1,13 @@
import commandScore from "command-score"; import commandScore from "command-score";
import invariant from "invariant"; import invariant from "invariant";
// oxlint-disable-next-line lodash/import-scope import {
import type { ObjectIterateeCustom } from "lodash"; deburr,
import deburr from "lodash/deburr"; filter,
import filter from "lodash/filter"; find,
import find from "lodash/find"; flatten,
import flatten from "lodash/flatten"; lowerFirst,
import lowerFirst from "lodash/lowerFirst"; orderBy,
import orderBy from "lodash/orderBy"; } from "es-toolkit/compat";
import { observable, action, computed, runInAction } from "mobx"; import { observable, action, computed, runInAction } from "mobx";
import pluralize from "pluralize"; import pluralize from "pluralize";
import { Pagination } from "@shared/constants"; import { Pagination } from "@shared/constants";
@@ -24,6 +24,12 @@ import { client } from "~/utils/ApiClient";
import { AuthorizationError, NotFoundError } from "~/utils/errors"; import { AuthorizationError, NotFoundError } from "~/utils/errors";
import ParanoidModel from "~/models/base/ParanoidModel"; import ParanoidModel from "~/models/base/ParanoidModel";
type ListPredicate<T> =
| ((value: T, index: number, collection: ArrayLike<T>) => boolean)
| PropertyKey
| [PropertyKey, unknown]
| Partial<T>;
export enum RPCAction { export enum RPCAction {
Info = "info", Info = "info",
List = "list", List = "list",
@@ -475,7 +481,7 @@ export default abstract class Store<T extends Model> {
* *
* @param predicate A function that returns true if the item matches, or an object with the properties to match. * @param predicate A function that returns true if the item matches, or an object with the properties to match.
*/ */
find = (predicate: ObjectIterateeCustom<T, boolean>): T | undefined => find = (predicate: ListPredicate<T>): T | undefined =>
// @ts-expect-error not sure why T is incompatible // @ts-expect-error not sure why T is incompatible
find(this.orderedData, predicate); find(this.orderedData, predicate);
@@ -484,7 +490,7 @@ export default abstract class Store<T extends Model> {
* *
* @param predicate A function that returns true if the item matches, or an object with the properties to match. * @param predicate A function that returns true if the item matches, or an object with the properties to match.
*/ */
filter = (predicate: ObjectIterateeCustom<T, boolean>): T[] => filter = (predicate: ListPredicate<T>): T[] =>
// @ts-expect-error not sure why T is incompatible // @ts-expect-error not sure why T is incompatible
filter(this.orderedData, predicate); filter(this.orderedData, predicate);
} }
+1 -1
View File
@@ -1,5 +1,5 @@
import retry from "fetch-retry"; import retry from "fetch-retry";
import trim from "lodash/trim"; import { trim } from "es-toolkit/compat";
import queryString from "query-string"; import queryString from "query-string";
import EDITOR_VERSION from "@shared/editor/version"; import EDITOR_VERSION from "@shared/editor/version";
import type { JSONObject } from "@shared/types"; import type { JSONObject } from "@shared/types";
+1 -2
View File
@@ -1,5 +1,4 @@
import isArray from "lodash/isArray"; import { isArray, sortBy } from "es-toolkit/compat";
import sortBy from "lodash/sortBy";
import { action, observable } from "mobx"; import { action, observable } from "mobx";
import type Team from "~/models/Team"; import type Team from "~/models/Team";
import type User from "~/models/User"; import type User from "~/models/User";
+1 -1
View File
@@ -1,4 +1,4 @@
import flatten from "lodash/flatten"; import { flatten } from "es-toolkit/compat";
import stores from "~/stores"; import stores from "~/stores";
import { flattenTree } from "@shared/utils/tree"; import { flattenTree } from "@shared/utils/tree";

Some files were not shown because too many files have changed in this diff Show More