From 0139b91b5d0b9ac3c3e222c1bb2d5350111b136a Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Wed, 6 May 2026 21:03:47 -0400 Subject: [PATCH] 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. --- app/actions/definitions/documents.tsx | 3 +-- app/components/Analytics.tsx | 2 +- app/components/Collaborators.tsx | 5 +--- app/components/Collection/CollectionForm.tsx | 2 +- .../CommandBar/SharedSearchActions.tsx | 2 +- .../DocumentExplorer/DocumentExplorer.tsx | 16 +++++++----- app/components/DocumentViews.tsx | 3 +-- app/components/Editor.tsx | 2 +- app/components/FilterOptions.tsx | 2 +- app/components/Header.tsx | 2 +- app/components/Highlight.tsx | 2 +- .../IconPicker/components/EmojiPanel.tsx | 2 +- .../IconPicker/components/GridTemplate.tsx | 3 +-- app/components/LanguagePrompt.tsx | 2 +- app/components/Lightbox.tsx | 2 +- app/components/List/Placeholder.tsx | 2 +- app/components/PaginatedList.tsx | 2 +- app/components/Reactions/ReactionList.tsx | 2 +- .../Reactions/ViewReactionsDialog.tsx | 2 +- .../Sharing/Collection/PublicAccess.tsx | 3 +-- .../Sharing/Document/DocumentMemberList.tsx | 2 +- .../Sharing/Document/PublicAccess.tsx | 3 +-- .../Sharing/components/Placeholder.tsx | 2 +- .../components/ShareSettingsPopover.tsx | 3 +-- .../Sharing/components/Suggestions.tsx | 2 +- app/components/Sidebar/Settings.tsx | 2 +- .../Sidebar/components/ArchiveLink.tsx | 2 +- .../components/CollectionLinkChildren.tsx | 2 +- app/components/Tab.tsx | 2 +- app/components/WebsocketProvider.tsx | 2 +- app/editor/components/BlockMenu.tsx | 2 +- app/editor/components/EmojiMenu.tsx | 2 +- app/editor/components/NodeViewRenderer.tsx | 2 +- app/editor/components/SuggestionsMenu.tsx | 3 +-- app/editor/extensions/FindAndReplace.tsx | 3 +-- app/editor/extensions/Multiplayer.ts | 2 +- app/editor/extensions/Suggestion.ts | 2 +- app/editor/index.tsx | 3 +-- app/hooks/useCommandBarActions.ts | 2 +- app/hooks/useEmbeds.ts | 2 +- app/hooks/useIdle.ts | 2 +- app/hooks/useMenuAction.ts | 2 +- app/hooks/usePaginatedRequest.ts | 2 +- app/hooks/useSwipe.tsx | 2 +- app/hooks/useTableRequest.ts | 2 +- app/hooks/useThrottledCallback.ts | 2 +- app/hooks/useWindowScrollPosition.ts | 2 +- app/menus/DocumentMenu.tsx | 2 +- app/models/Comment.ts | 2 +- app/models/Document.ts | 3 +-- app/models/Policy.ts | 2 +- app/models/base/Model.ts | 3 +-- app/scenes/Collection/components/Header.tsx | 2 +- .../components/MembershipPreview.tsx | 2 +- app/scenes/Collection/components/Overview.tsx | 2 +- app/scenes/Document/components/Editor.tsx | 2 +- .../Document/components/History/History.tsx | 2 +- .../Document/components/MultiplayerEditor.tsx | 2 +- .../Document/components/PresentationMode.tsx | 2 +- app/scenes/Document/hooks/useDocumentSave.ts | 4 +-- app/scenes/Login/Login.tsx | 2 +- app/scenes/Login/OAuthScopeHelper.ts | 3 +-- app/scenes/Settings/Details.tsx | 2 +- app/scenes/Settings/Embeds.tsx | 2 +- app/scenes/Settings/Groups.tsx | 2 +- app/scenes/Settings/Import.tsx | 2 +- app/scenes/Settings/Integrations.tsx | 2 +- app/scenes/Settings/Notifications.tsx | 2 +- app/scenes/Settings/Security.tsx | 2 +- app/scenes/Settings/Templates.tsx | 2 +- .../components/DisconnectAnalyticsDialog.tsx | 2 +- .../Settings/components/EmojisTable.tsx | 2 +- .../Settings/components/GroupDialogs.tsx | 2 +- .../Settings/components/GroupMembersTable.tsx | 2 +- .../Settings/components/GroupsTable.tsx | 2 +- .../Settings/components/ImportListItem.tsx | 2 +- .../Settings/components/MembersTable.tsx | 2 +- .../Settings/components/SharesTable.tsx | 2 +- .../Settings/components/TemplatesTable.tsx | 2 +- .../Settings/components/UserRoleFilter.tsx | 2 +- .../Settings/components/UserStatusFilter.tsx | 2 +- app/stores/AuthStore.ts | 2 +- app/stores/AuthenticationProvidersStore.ts | 2 +- app/stores/CollectionsStore.ts | 4 +-- app/stores/CommentsStore.ts | 6 +---- app/stores/DocumentsStore.ts | 5 +--- app/stores/FileOperationsStore.ts | 2 +- app/stores/GroupUsersStore.ts | 2 +- app/stores/GroupsStore.ts | 2 +- app/stores/NotificationsStore.ts | 3 +-- app/stores/RootStore.ts | 2 +- app/stores/SearchesStore.ts | 2 +- app/stores/SharesStore.ts | 5 +--- app/stores/TemplatesStore.ts | 3 +-- app/stores/UsersStore.ts | 5 +--- app/stores/ViewsStore.ts | 5 +--- app/stores/base/Store.ts | 26 ++++++++++++------- app/utils/ApiClient.ts | 2 +- app/utils/PluginManager.ts | 3 +-- app/utils/developer.ts | 2 +- package.json | 2 +- plugins/diagrams/client/Settings.tsx | 2 +- plugins/figma/server/api/schema.ts | 2 +- plugins/figma/server/figma.ts | 2 +- plugins/github/server/api/github.ts | 2 +- plugins/github/server/api/schema.ts | 3 +-- plugins/gitlab/server/api/schema.ts | 2 +- plugins/google/server/auth/google.ts | 2 +- plugins/googleanalytics/client/Settings.tsx | 2 +- plugins/linear/server/api/schema.ts | 2 +- plugins/linear/server/linear.ts | 2 +- plugins/matomo/client/Settings.tsx | 2 +- plugins/notion/server/api/schema.ts | 2 +- plugins/notion/server/notion.ts | 3 +-- .../notion/server/utils/NotionConverter.ts | 2 +- plugins/oidc/server/auth/oidcRouter.ts | 2 +- .../server/PostgresSearchProvider.ts | 4 +-- .../slack/client/components/SlackListItem.tsx | 2 +- plugins/slack/server/api/hooks.ts | 2 +- plugins/slack/server/auth/schema.ts | 2 +- plugins/storage/server/api/schema.ts | 2 +- plugins/umami/client/Settings.tsx | 2 +- .../components/WebhookSubscriptionForm.tsx | 4 +-- .../server/api/webhookSubscriptions.ts | 3 +-- .../commands/documentCollaborativeUpdater.ts | 2 +- server/commands/documentImporter.ts | 2 +- server/commands/documentPermanentDeleter.ts | 2 +- server/commands/teamUpdater.ts | 3 +-- server/commands/userInviter.ts | 3 +-- .../templates/DocumentMentionedEmail.tsx | 2 +- .../templates/GroupDocumentMentionedEmail.tsx | 2 +- server/env.ts | 2 +- server/index.ts | 2 +- server/logging/Logger.ts | 4 +-- server/middlewares/authentication.ts | 2 +- server/middlewares/csp.ts | 2 +- server/middlewares/rateLimiter.ts | 2 +- server/models/Collection.ts | 6 +---- server/models/Document.ts | 4 +-- server/models/Reaction.ts | 3 +-- server/models/WebhookSubscription.ts | 2 +- server/models/base/Model.ts | 4 +-- server/models/decorators/CounterCache.ts | 2 +- server/models/decorators/Encrypted.ts | 3 +-- server/models/helpers/AuthenticationHelper.ts | 2 +- server/models/helpers/NotificationHelper.ts | 3 +-- server/models/helpers/ProsemirrorHelper.tsx | 3 +-- server/models/helpers/TextHelper.ts | 3 +-- server/models/validators/Length.ts | 10 +++---- server/models/validators/TextLength.ts | 4 +-- server/onerror.ts | 4 +-- server/policies/cancan.ts | 6 ++--- server/presenters/policy.ts | 2 +- server/queues/processors/ImportsProcessor.ts | 4 +-- .../queues/processors/WebsocketsProcessor.ts | 5 +--- server/queues/queue.ts | 2 +- server/queues/tasks/APIImportTask.ts | 4 +-- server/queues/tasks/ExportDocumentTreeTask.ts | 2 +- server/queues/tasks/ExportJSONTask.ts | 2 +- server/queues/tasks/ExportTask.ts | 2 +- server/queues/tasks/ImportJSONTask.ts | 2 +- server/queues/tasks/ImportMarkdownZipTask.ts | 2 +- server/queues/tasks/ImportTask.ts | 3 +-- .../tasks/RevisionCreatedNotificationsTask.ts | 2 +- server/routes/api/attachments/schema.ts | 2 +- server/routes/api/auth/auth.ts | 2 +- server/routes/api/collections/schema.ts | 2 +- server/routes/api/comments/comments.ts | 2 +- server/routes/api/comments/schema.ts | 2 +- server/routes/api/cron/schema.ts | 2 +- server/routes/api/documents/documents.ts | 5 +--- server/routes/api/documents/schema.ts | 2 +- server/routes/api/events/events.ts | 2 +- server/routes/api/fileOperations/schema.ts | 2 +- .../api/groupMemberships/groupMemberships.ts | 2 +- server/routes/api/imports/imports.ts | 2 +- .../routes/api/notifications/notifications.ts | 5 +--- server/routes/api/notifications/schema.ts | 2 +- server/routes/api/revisions/revisions.ts | 2 +- server/routes/api/revisions/schema.ts | 2 +- server/routes/api/searches/schema.ts | 2 +- server/routes/api/shares/schema.ts | 2 +- server/routes/api/shares/shares.ts | 2 +- server/routes/api/stars/schema.ts | 2 +- server/routes/api/subscriptions/schema.ts | 2 +- server/routes/api/urls/schema.ts | 2 +- server/routes/app.ts | 2 +- server/storage/files/BaseStorage.ts | 2 +- server/storage/files/S3Storage.ts | 2 +- server/storage/redis.ts | 2 +- server/test/factories.ts | 3 +-- server/utils/DocumentConverter.ts | 2 +- server/utils/PluginManager.ts | 3 +-- server/utils/ShutdownHelper.ts | 2 +- server/utils/authentication.ts | 2 +- server/utils/decorators/Public.ts | 2 +- server/utils/fetch.ts | 2 +- server/utils/koa.ts | 2 +- server/utils/parseAttachmentIds.ts | 3 +-- server/utils/permissions.ts | 3 +-- server/utils/sitemap.ts | 2 +- server/utils/startup.ts | 2 +- server/validation.ts | 2 +- shared/components/ColorPicker.tsx | 2 +- shared/editor/commands/table.ts | 3 +-- shared/editor/components/Image.tsx | 2 +- shared/editor/extensions/CodeHighlighting.ts | 3 +-- shared/editor/extensions/Mermaid.ts | 3 +-- shared/editor/lib/headingToSlug.ts | 2 +- shared/editor/lib/markInputRule.ts | 2 +- shared/editor/nodes/Doc.ts | 2 +- shared/editor/nodes/Mention.tsx | 2 +- shared/editor/plugins/PlaceholderPlugin.ts | 4 +-- shared/editor/queries/findCutAfterHeading.ts | 2 +- shared/editor/utils.ts | 3 +-- shared/utils/IconLibrary.tsx | 2 +- shared/utils/domains.ts | 2 +- shared/utils/emoji.ts | 3 +-- shared/utils/naturalSort.ts | 2 +- shared/utils/rfc6902/diff.ts | 2 +- shared/utils/urls.ts | 2 +- vite.config.ts | 4 +-- yarn.lock | 14 +++++++++- 223 files changed, 266 insertions(+), 335 deletions(-) diff --git a/app/actions/definitions/documents.tsx b/app/actions/definitions/documents.tsx index c078301700..4a4fe5fcf1 100644 --- a/app/actions/definitions/documents.tsx +++ b/app/actions/definitions/documents.tsx @@ -1,6 +1,6 @@ import copy from "copy-to-clipboard"; import invariant from "invariant"; -import uniqBy from "lodash/uniqBy"; +import { capitalize, uniqBy } from "es-toolkit/compat"; import { DownloadIcon, DuplicateIcon, @@ -81,7 +81,6 @@ import { trashPath, documentEditPath, } from "~/utils/routeHelpers"; -import capitalize from "lodash/capitalize"; import CollectionIcon from "~/components/Icons/CollectionIcon"; import type { Action, diff --git a/app/components/Analytics.tsx b/app/components/Analytics.tsx index 5434b5c321..333c176158 100644 --- a/app/components/Analytics.tsx +++ b/app/components/Analytics.tsx @@ -1,6 +1,6 @@ /* oxlint-disable prefer-rest-params */ /* global ga */ -import escape from "lodash/escape"; +import { escape } from "es-toolkit/compat"; import * as React from "react"; import type { PublicEnv } from "@shared/types"; import { IntegrationService } from "@shared/types"; diff --git a/app/components/Collaborators.tsx b/app/components/Collaborators.tsx index f67e15dda4..360e33ffd9 100644 --- a/app/components/Collaborators.tsx +++ b/app/components/Collaborators.tsx @@ -1,7 +1,4 @@ -import filter from "lodash/filter"; -import isEqual from "lodash/isEqual"; -import orderBy from "lodash/orderBy"; -import uniq from "lodash/uniq"; +import { filter, isEqual, orderBy, uniq } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useState, useMemo, useEffect, useCallback } from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/components/Collection/CollectionForm.tsx b/app/components/Collection/CollectionForm.tsx index e35687f79e..d7e1fadb8f 100644 --- a/app/components/Collection/CollectionForm.tsx +++ b/app/components/Collection/CollectionForm.tsx @@ -1,4 +1,4 @@ -import uniq from "lodash/uniq"; +import { uniq } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useMemo, useEffect, useCallback, Suspense } from "react"; import { Controller, useForm } from "react-hook-form"; diff --git a/app/components/CommandBar/SharedSearchActions.tsx b/app/components/CommandBar/SharedSearchActions.tsx index 3d36f15c31..d443bf8a0c 100644 --- a/app/components/CommandBar/SharedSearchActions.tsx +++ b/app/components/CommandBar/SharedSearchActions.tsx @@ -1,5 +1,5 @@ import { useKBar } from "kbar"; -import escapeRegExp from "lodash/escapeRegExp"; +import { escapeRegExp } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { DocumentIcon } from "outline-icons"; import * as React from "react"; diff --git a/app/components/DocumentExplorer/DocumentExplorer.tsx b/app/components/DocumentExplorer/DocumentExplorer.tsx index e0fc79aa73..7bb06360ed 100644 --- a/app/components/DocumentExplorer/DocumentExplorer.tsx +++ b/app/components/DocumentExplorer/DocumentExplorer.tsx @@ -1,11 +1,13 @@ import FuzzySearch from "fuzzy-search"; -import concat from "lodash/concat"; -import difference from "lodash/difference"; -import fill from "lodash/fill"; -import filter from "lodash/filter"; -import flatten from "lodash/flatten"; -import includes from "lodash/includes"; -import map from "lodash/map"; +import { + concat, + difference, + fill, + filter, + flatten, + includes, + map, +} from "es-toolkit/compat"; import { observer } from "mobx-react"; import { StarredIcon, DocumentIcon } from "outline-icons"; import * as React from "react"; diff --git a/app/components/DocumentViews.tsx b/app/components/DocumentViews.tsx index d3d922e1f5..820a66304f 100644 --- a/app/components/DocumentViews.tsx +++ b/app/components/DocumentViews.tsx @@ -1,5 +1,4 @@ -import compact from "lodash/compact"; -import sortBy from "lodash/sortBy"; +import { compact, sortBy } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useMemo, useCallback } from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/components/Editor.tsx b/app/components/Editor.tsx index e270c01ee2..78b3babd72 100644 --- a/app/components/Editor.tsx +++ b/app/components/Editor.tsx @@ -1,4 +1,4 @@ -import difference from "lodash/difference"; +import { difference } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { DOMParser as ProsemirrorDOMParser } from "prosemirror-model"; import { TextSelection } from "prosemirror-state"; diff --git a/app/components/FilterOptions.tsx b/app/components/FilterOptions.tsx index 23a97545fc..049902be2e 100644 --- a/app/components/FilterOptions.tsx +++ b/app/components/FilterOptions.tsx @@ -1,4 +1,4 @@ -import deburr from "lodash/deburr"; +import { deburr } from "es-toolkit/compat"; import * as React from "react"; import { useTranslation } from "react-i18next"; import styled from "styled-components"; diff --git a/app/components/Header.tsx b/app/components/Header.tsx index 5472d3b654..c3169d60a1 100644 --- a/app/components/Header.tsx +++ b/app/components/Header.tsx @@ -1,4 +1,4 @@ -import throttle from "lodash/throttle"; +import { throttle } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { MenuIcon } from "outline-icons"; import { transparentize } from "polished"; diff --git a/app/components/Highlight.tsx b/app/components/Highlight.tsx index b38d75eda7..6b852d8973 100644 --- a/app/components/Highlight.tsx +++ b/app/components/Highlight.tsx @@ -1,4 +1,4 @@ -import escapeRegExp from "lodash/escapeRegExp"; +import { escapeRegExp } from "es-toolkit/compat"; import * as React from "react"; import replace from "string-replace-to-array"; import styled from "styled-components"; diff --git a/app/components/IconPicker/components/EmojiPanel.tsx b/app/components/IconPicker/components/EmojiPanel.tsx index f771c7d4e3..0f807589dc 100644 --- a/app/components/IconPicker/components/EmojiPanel.tsx +++ b/app/components/IconPicker/components/EmojiPanel.tsx @@ -1,4 +1,4 @@ -import concat from "lodash/concat"; +import { concat } from "es-toolkit/compat"; import { PlusIcon } from "outline-icons"; import * as React from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/components/IconPicker/components/GridTemplate.tsx b/app/components/IconPicker/components/GridTemplate.tsx index 998ddc54e1..9447495633 100644 --- a/app/components/IconPicker/components/GridTemplate.tsx +++ b/app/components/IconPicker/components/GridTemplate.tsx @@ -1,5 +1,4 @@ -import chunk from "lodash/chunk"; -import compact from "lodash/compact"; +import { chunk, compact } from "es-toolkit/compat"; import * as React from "react"; import styled from "styled-components"; import { IconType } from "@shared/types"; diff --git a/app/components/LanguagePrompt.tsx b/app/components/LanguagePrompt.tsx index 48095648d7..03835dcfe3 100644 --- a/app/components/LanguagePrompt.tsx +++ b/app/components/LanguagePrompt.tsx @@ -1,5 +1,5 @@ import { m } from "framer-motion"; -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import { useTranslation } from "react-i18next"; import styled from "styled-components"; import { languages, languageOptions } from "@shared/i18n"; diff --git a/app/components/Lightbox.tsx b/app/components/Lightbox.tsx index 71ddc87be1..448dd59a5f 100644 --- a/app/components/Lightbox.tsx +++ b/app/components/Lightbox.tsx @@ -40,7 +40,7 @@ import CopyToClipboard from "./CopyToClipboard"; import { Separator } from "./Actions"; import useSwipe from "~/hooks/useSwipe"; import { toast } from "sonner"; -import { findIndex } from "lodash"; +import { findIndex } from "es-toolkit/compat"; import type { LightboxImage } from "@shared/editor/lib/Lightbox"; import type { ReactZoomPanPinchRef } from "react-zoom-pan-pinch"; import { diff --git a/app/components/List/Placeholder.tsx b/app/components/List/Placeholder.tsx index 0c5f9ecf9e..9c6a0277aa 100644 --- a/app/components/List/Placeholder.tsx +++ b/app/components/List/Placeholder.tsx @@ -1,4 +1,4 @@ -import times from "lodash/times"; +import { times } from "es-toolkit/compat"; import styled from "styled-components"; import Fade from "~/components/Fade"; import Flex from "~/components/Flex"; diff --git a/app/components/PaginatedList.tsx b/app/components/PaginatedList.tsx index 1a1d9df9b1..914957159b 100644 --- a/app/components/PaginatedList.tsx +++ b/app/components/PaginatedList.tsx @@ -1,4 +1,4 @@ -import isEqual from "lodash/isEqual"; +import { isEqual } from "es-toolkit/compat"; import * as React from "react"; import { useTranslation } from "react-i18next"; import { Waypoint } from "react-waypoint"; diff --git a/app/components/Reactions/ReactionList.tsx b/app/components/Reactions/ReactionList.tsx index d3fdf562d4..e05ae75ce0 100644 --- a/app/components/Reactions/ReactionList.tsx +++ b/app/components/Reactions/ReactionList.tsx @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import type Comment from "~/models/Comment"; diff --git a/app/components/Reactions/ViewReactionsDialog.tsx b/app/components/Reactions/ViewReactionsDialog.tsx index d511585a43..3aaa91f9f1 100644 --- a/app/components/Reactions/ViewReactionsDialog.tsx +++ b/app/components/Reactions/ViewReactionsDialog.tsx @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/components/Sharing/Collection/PublicAccess.tsx b/app/components/Sharing/Collection/PublicAccess.tsx index a489baaa74..e11cc00687 100644 --- a/app/components/Sharing/Collection/PublicAccess.tsx +++ b/app/components/Sharing/Collection/PublicAccess.tsx @@ -1,6 +1,5 @@ import copy from "copy-to-clipboard"; -import debounce from "lodash/debounce"; -import isEmpty from "lodash/isEmpty"; +import { debounce, isEmpty } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { CopyIcon, GlobeIcon } from "outline-icons"; import * as React from "react"; diff --git a/app/components/Sharing/Document/DocumentMemberList.tsx b/app/components/Sharing/Document/DocumentMemberList.tsx index 9d8d3def05..7a26dabedc 100644 --- a/app/components/Sharing/Document/DocumentMemberList.tsx +++ b/app/components/Sharing/Document/DocumentMemberList.tsx @@ -1,4 +1,4 @@ -import orderBy from "lodash/orderBy"; +import { orderBy } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { useTranslation, Trans } from "react-i18next"; diff --git a/app/components/Sharing/Document/PublicAccess.tsx b/app/components/Sharing/Document/PublicAccess.tsx index 5b5812c157..86a423c611 100644 --- a/app/components/Sharing/Document/PublicAccess.tsx +++ b/app/components/Sharing/Document/PublicAccess.tsx @@ -1,6 +1,5 @@ import copy from "copy-to-clipboard"; -import debounce from "lodash/debounce"; -import isEmpty from "lodash/isEmpty"; +import { debounce, isEmpty } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { CopyIcon, GlobeIcon } from "outline-icons"; import * as React from "react"; diff --git a/app/components/Sharing/components/Placeholder.tsx b/app/components/Sharing/components/Placeholder.tsx index 0563909128..5ce61d940a 100644 --- a/app/components/Sharing/components/Placeholder.tsx +++ b/app/components/Sharing/components/Placeholder.tsx @@ -1,4 +1,4 @@ -import times from "lodash/times"; +import { times } from "es-toolkit/compat"; import { AvatarSize } from "~/components/Avatar"; import Fade from "~/components/Fade"; import PlaceholderText from "~/components/PlaceholderText"; diff --git a/app/components/Sharing/components/ShareSettingsPopover.tsx b/app/components/Sharing/components/ShareSettingsPopover.tsx index 6cf32c8ed5..2c0bf7309d 100644 --- a/app/components/Sharing/components/ShareSettingsPopover.tsx +++ b/app/components/Sharing/components/ShareSettingsPopover.tsx @@ -1,5 +1,4 @@ -import debounce from "lodash/debounce"; -import uniqueId from "lodash/uniqueId"; +import { debounce, uniqueId } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { ImageIcon, diff --git a/app/components/Sharing/components/Suggestions.tsx b/app/components/Sharing/components/Suggestions.tsx index 4f2b9a6b23..5edd5944ed 100644 --- a/app/components/Sharing/components/Suggestions.tsx +++ b/app/components/Sharing/components/Suggestions.tsx @@ -1,5 +1,5 @@ import { isEmail } from "class-validator"; -import concat from "lodash/concat"; +import { concat } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { CheckmarkIcon, CloseIcon } from "outline-icons"; import * as React from "react"; diff --git a/app/components/Sidebar/Settings.tsx b/app/components/Sidebar/Settings.tsx index 7c87af556c..b6047052ac 100644 --- a/app/components/Sidebar/Settings.tsx +++ b/app/components/Sidebar/Settings.tsx @@ -1,4 +1,4 @@ -import groupBy from "lodash/groupBy"; +import { groupBy } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { BackIcon, SidebarIcon } from "outline-icons"; import { useCallback } from "react"; diff --git a/app/components/Sidebar/components/ArchiveLink.tsx b/app/components/Sidebar/components/ArchiveLink.tsx index 0ffb8e93d5..9a5b7dd940 100644 --- a/app/components/Sidebar/components/ArchiveLink.tsx +++ b/app/components/Sidebar/components/ArchiveLink.tsx @@ -1,4 +1,4 @@ -import isUndefined from "lodash/isUndefined"; +import { isUndefined } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { ArchiveIcon } from "outline-icons"; import { useState, useEffect, useCallback } from "react"; diff --git a/app/components/Sidebar/components/CollectionLinkChildren.tsx b/app/components/Sidebar/components/CollectionLinkChildren.tsx index 65cd2a082c..1cd70bba1d 100644 --- a/app/components/Sidebar/components/CollectionLinkChildren.tsx +++ b/app/components/Sidebar/components/CollectionLinkChildren.tsx @@ -1,4 +1,4 @@ -import noop from "lodash/noop"; +import { noop } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useState, useRef, useEffect, useCallback } from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/components/Tab.tsx b/app/components/Tab.tsx index 6d872fddc1..16d7af3797 100644 --- a/app/components/Tab.tsx +++ b/app/components/Tab.tsx @@ -1,6 +1,6 @@ import { m } from "framer-motion"; import type { LocationDescriptor } from "history"; -import isEqual from "lodash/isEqual"; +import { isEqual } from "es-toolkit/compat"; import queryString from "query-string"; import * as React from "react"; import styled, { css, useTheme } from "styled-components"; diff --git a/app/components/WebsocketProvider.tsx b/app/components/WebsocketProvider.tsx index 06cecab32a..bd5bb744a9 100644 --- a/app/components/WebsocketProvider.tsx +++ b/app/components/WebsocketProvider.tsx @@ -1,6 +1,6 @@ import * as Sentry from "@sentry/react"; import invariant from "invariant"; -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import { action } from "mobx"; import { observer } from "mobx-react"; import { createContext, useEffect, useState } from "react"; diff --git a/app/editor/components/BlockMenu.tsx b/app/editor/components/BlockMenu.tsx index f093098262..9cc09ecfc0 100644 --- a/app/editor/components/BlockMenu.tsx +++ b/app/editor/components/BlockMenu.tsx @@ -1,5 +1,5 @@ import { DocumentIcon, ShapesIcon } from "outline-icons"; -import cloneDeep from "lodash/cloneDeep"; +import { cloneDeep } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useCallback, useMemo } from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/editor/components/EmojiMenu.tsx b/app/editor/components/EmojiMenu.tsx index f25355c489..dae085cbbc 100644 --- a/app/editor/components/EmojiMenu.tsx +++ b/app/editor/components/EmojiMenu.tsx @@ -1,4 +1,4 @@ -import capitalize from "lodash/capitalize"; +import { capitalize } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useCallback, useMemo, useEffect } from "react"; import { emojiMartToGemoji, snakeCase } from "@shared/editor/lib/emoji"; diff --git a/app/editor/components/NodeViewRenderer.tsx b/app/editor/components/NodeViewRenderer.tsx index aaa392e755..1db107e2b9 100644 --- a/app/editor/components/NodeViewRenderer.tsx +++ b/app/editor/components/NodeViewRenderer.tsx @@ -1,4 +1,4 @@ -import isEqual from "lodash/isEqual"; +import { isEqual } from "es-toolkit/compat"; import { action, computed, observable } from "mobx"; import type { FunctionComponent } from "react"; import { createPortal } from "react-dom"; diff --git a/app/editor/components/SuggestionsMenu.tsx b/app/editor/components/SuggestionsMenu.tsx index 3860074e82..e45d90b811 100644 --- a/app/editor/components/SuggestionsMenu.tsx +++ b/app/editor/components/SuggestionsMenu.tsx @@ -1,7 +1,6 @@ import * as VisuallyHidden from "@radix-ui/react-visually-hidden"; import commandScore from "command-score"; -import capitalize from "lodash/capitalize"; -import orderBy from "lodash/orderBy"; +import { capitalize, orderBy } from "es-toolkit/compat"; import { TextSelection } from "prosemirror-state"; import * as React from "react"; import { Trans, useTranslation } from "react-i18next"; diff --git a/app/editor/extensions/FindAndReplace.tsx b/app/editor/extensions/FindAndReplace.tsx index db12f404ab..29721ab420 100644 --- a/app/editor/extensions/FindAndReplace.tsx +++ b/app/editor/extensions/FindAndReplace.tsx @@ -1,5 +1,4 @@ -import deburr from "lodash/deburr"; -import escapeRegExp from "lodash/escapeRegExp"; +import { deburr, escapeRegExp } from "es-toolkit/compat"; import { observable } from "mobx"; import type { Node } from "prosemirror-model"; import type { Command } from "prosemirror-state"; diff --git a/app/editor/extensions/Multiplayer.ts b/app/editor/extensions/Multiplayer.ts index 27e3b5718c..88aa66ea3c 100644 --- a/app/editor/extensions/Multiplayer.ts +++ b/app/editor/extensions/Multiplayer.ts @@ -1,5 +1,5 @@ import type { HocuspocusProvider } from "@hocuspocus/provider"; -import isEqual from "lodash/isEqual"; +import { isEqual } from "es-toolkit/compat"; import { Plugin } from "prosemirror-state"; import { ySyncPlugin, diff --git a/app/editor/extensions/Suggestion.ts b/app/editor/extensions/Suggestion.ts index 6904568bb2..bead0e9cae 100644 --- a/app/editor/extensions/Suggestion.ts +++ b/app/editor/extensions/Suggestion.ts @@ -1,4 +1,4 @@ -import escapeRegExp from "lodash/escapeRegExp"; +import { escapeRegExp } from "es-toolkit/compat"; import { action, observable } from "mobx"; import { InputRule } from "prosemirror-inputrules"; import type { NodeType, Schema } from "prosemirror-model"; diff --git a/app/editor/index.tsx b/app/editor/index.tsx index b7bb4f6635..330c9fa93b 100644 --- a/app/editor/index.tsx +++ b/app/editor/index.tsx @@ -53,8 +53,7 @@ import EditorContext from "./components/EditorContext"; import type { NodeViewRenderer } from "./components/NodeViewRenderer"; import WithTheme from "./components/WithTheme"; -import isNull from "lodash/isNull"; -import { isArray, map } from "lodash"; +import { isArray, isNull, map } from "es-toolkit/compat"; import type { LightboxImage } from "@shared/editor/lib/Lightbox"; import { LightboxImageFactory } from "@shared/editor/lib/Lightbox"; import Lightbox from "~/components/Lightbox"; diff --git a/app/hooks/useCommandBarActions.ts b/app/hooks/useCommandBarActions.ts index daee2b9f40..04e32ac47b 100644 --- a/app/hooks/useCommandBarActions.ts +++ b/app/hooks/useCommandBarActions.ts @@ -1,5 +1,5 @@ import { useRegisterActions } from "kbar"; -import flattenDeep from "lodash/flattenDeep"; +import { flattenDeep } from "es-toolkit/compat"; import { useLocation } from "react-router-dom"; import { actionToKBar } from "~/actions"; import type { ActionVariant } from "~/types"; diff --git a/app/hooks/useEmbeds.ts b/app/hooks/useEmbeds.ts index 4b2f2a5739..aaaad31ddc 100644 --- a/app/hooks/useEmbeds.ts +++ b/app/hooks/useEmbeds.ts @@ -1,4 +1,4 @@ -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import { useEffect, useMemo } from "react"; import embeds from "@shared/editor/embeds"; import { IntegrationType, TeamPreference } from "@shared/types"; diff --git a/app/hooks/useIdle.ts b/app/hooks/useIdle.ts index 811040742f..d0088091c9 100644 --- a/app/hooks/useIdle.ts +++ b/app/hooks/useIdle.ts @@ -1,4 +1,4 @@ -import throttle from "lodash/throttle"; +import { throttle } from "es-toolkit/compat"; import { useState, useRef, useCallback, useEffect } from "react"; import { Minute } from "@shared/utils/time"; import useIsMounted from "./useIsMounted"; diff --git a/app/hooks/useMenuAction.ts b/app/hooks/useMenuAction.ts index f62a3995f6..ee10b7f7df 100644 --- a/app/hooks/useMenuAction.ts +++ b/app/hooks/useMenuAction.ts @@ -1,4 +1,4 @@ -import isEqual from "lodash/isEqual"; +import { isEqual } from "es-toolkit/compat"; import { useRef } from "react"; import { createRootMenuAction } from "~/actions"; import type { diff --git a/app/hooks/usePaginatedRequest.ts b/app/hooks/usePaginatedRequest.ts index 4f24e1a397..0bea24fc43 100644 --- a/app/hooks/usePaginatedRequest.ts +++ b/app/hooks/usePaginatedRequest.ts @@ -1,4 +1,4 @@ -import uniqBy from "lodash/uniqBy"; +import { uniqBy } from "es-toolkit/compat"; import { useState, useEffect, useCallback } from "react"; import type { PaginationParams } from "~/types"; import useRequest from "./useRequest"; diff --git a/app/hooks/useSwipe.tsx b/app/hooks/useSwipe.tsx index c54b60d56f..c95d5d6af9 100644 --- a/app/hooks/useSwipe.tsx +++ b/app/hooks/useSwipe.tsx @@ -1,4 +1,4 @@ -import { isNumber } from "lodash"; +import { isNumber } from "es-toolkit/compat"; import { useRef } from "react"; type Props = { diff --git a/app/hooks/useTableRequest.ts b/app/hooks/useTableRequest.ts index 559d8bed3d..0c92f555e5 100644 --- a/app/hooks/useTableRequest.ts +++ b/app/hooks/useTableRequest.ts @@ -1,5 +1,5 @@ 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 type { FetchPageParams, PaginatedResponse } from "~/stores/base/Store"; import { PAGINATION_SYMBOL } from "~/stores/base/Store"; diff --git a/app/hooks/useThrottledCallback.ts b/app/hooks/useThrottledCallback.ts index 9797f7337a..a42831c5b6 100644 --- a/app/hooks/useThrottledCallback.ts +++ b/app/hooks/useThrottledCallback.ts @@ -1,4 +1,4 @@ -import throttle from "lodash/throttle"; +import { throttle } from "es-toolkit/compat"; import * as React from "react"; import useUnmount from "./useUnmount"; diff --git a/app/hooks/useWindowScrollPosition.ts b/app/hooks/useWindowScrollPosition.ts index 10713d58f1..839dd4cef2 100644 --- a/app/hooks/useWindowScrollPosition.ts +++ b/app/hooks/useWindowScrollPosition.ts @@ -1,6 +1,6 @@ // Based on https://github.com/rehooks/window-scroll-position which is no longer // maintained. -import throttle from "lodash/throttle"; +import { throttle } from "es-toolkit/compat"; import { useState, useEffect } from "react"; import { supportsPassiveListener } from "@shared/utils/browser"; diff --git a/app/menus/DocumentMenu.tsx b/app/menus/DocumentMenu.tsx index b87e33851f..894e480de4 100644 --- a/app/menus/DocumentMenu.tsx +++ b/app/menus/DocumentMenu.tsx @@ -1,4 +1,4 @@ -import noop from "lodash/noop"; +import { noop } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/models/Comment.ts b/app/models/Comment.ts index b16783bf85..129e484c4a 100644 --- a/app/models/Comment.ts +++ b/app/models/Comment.ts @@ -1,5 +1,5 @@ import invariant from "invariant"; -import uniq from "lodash/uniq"; +import { uniq } from "es-toolkit/compat"; import { action, computed, observable } from "mobx"; import { Pagination } from "@shared/constants"; import type { ProsemirrorData, ReactionSummary } from "@shared/types"; diff --git a/app/models/Document.ts b/app/models/Document.ts index 13362d64f6..13245af3ff 100644 --- a/app/models/Document.ts +++ b/app/models/Document.ts @@ -1,7 +1,6 @@ import { addDays, differenceInDays } from "date-fns"; import i18n, { t } from "i18next"; -import capitalize from "lodash/capitalize"; -import floor from "lodash/floor"; +import { capitalize, floor } from "es-toolkit/compat"; import { action, autorun, comparer, computed, observable, set } from "mobx"; import type { JSONObject, diff --git a/app/models/Policy.ts b/app/models/Policy.ts index 44f58be61c..0b4a89eff6 100644 --- a/app/models/Policy.ts +++ b/app/models/Policy.ts @@ -1,4 +1,4 @@ -import isEqual from "lodash/isEqual"; +import { isEqual } from "es-toolkit/compat"; import { computed, observable } from "mobx"; import Model from "./base/Model"; import Field from "./decorators/Field"; diff --git a/app/models/base/Model.ts b/app/models/base/Model.ts index d683a24d1f..901f116125 100644 --- a/app/models/base/Model.ts +++ b/app/models/base/Model.ts @@ -1,4 +1,4 @@ -import pick from "lodash/pick"; +import { isEqual, pick } from "es-toolkit/compat"; import { observable, action, toJS } from "mobx"; import type { JSONObject } from "@shared/types"; import type Store from "~/stores/base/Store"; @@ -6,7 +6,6 @@ import Logger from "~/utils/Logger"; import { getFieldsForModel } from "../decorators/Field"; import { LifecycleManager } from "../decorators/Lifecycle"; import { getRelationsForModelClass } from "../decorators/Relation"; -import { isEqual } from "lodash"; export default abstract class Model { static modelName: string; diff --git a/app/scenes/Collection/components/Header.tsx b/app/scenes/Collection/components/Header.tsx index deac81bd7d..94aeee2bf8 100644 --- a/app/scenes/Collection/components/Header.tsx +++ b/app/scenes/Collection/components/Header.tsx @@ -1,6 +1,6 @@ import { IconTitleWrapper } from "@shared/components/Icon"; import breakpoint from "styled-components-breakpoint"; -import first from "lodash/first"; +import { first } from "es-toolkit/compat"; import { Suspense, useCallback } from "react"; import styled from "styled-components"; import { CollectionValidation } from "@shared/validations"; diff --git a/app/scenes/Collection/components/MembershipPreview.tsx b/app/scenes/Collection/components/MembershipPreview.tsx index 584752fe9d..d09d19868c 100644 --- a/app/scenes/Collection/components/MembershipPreview.tsx +++ b/app/scenes/Collection/components/MembershipPreview.tsx @@ -1,4 +1,4 @@ -import sortBy from "lodash/sortBy"; +import { sortBy } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/scenes/Collection/components/Overview.tsx b/app/scenes/Collection/components/Overview.tsx index cd906d9835..09f991679f 100644 --- a/app/scenes/Collection/components/Overview.tsx +++ b/app/scenes/Collection/components/Overview.tsx @@ -1,4 +1,4 @@ -import debounce from "lodash/debounce"; +import { debounce } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useMemo, useRef, useCallback, useEffect, Suspense } from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/scenes/Document/components/Editor.tsx b/app/scenes/Document/components/Editor.tsx index 66d9af3f53..fa11d09532 100644 --- a/app/scenes/Document/components/Editor.tsx +++ b/app/scenes/Document/components/Editor.tsx @@ -35,7 +35,7 @@ import { decodeURIComponentSafe } from "~/utils/urls"; import MultiplayerEditor from "./AsyncMultiplayerEditor"; import DocumentMeta from "./DocumentMeta"; import DocumentTitle from "./DocumentTitle"; -import first from "lodash/first"; +import { first } from "es-toolkit/compat"; import { getLangFor } from "~/utils/language"; import useShare from "@shared/hooks/useShare"; diff --git a/app/scenes/Document/components/History/History.tsx b/app/scenes/Document/components/History/History.tsx index 6dd9aa3186..4f5211f737 100644 --- a/app/scenes/Document/components/History/History.tsx +++ b/app/scenes/Document/components/History/History.tsx @@ -1,5 +1,5 @@ import isEqual from "fast-deep-equal"; -import orderBy from "lodash/orderBy"; +import { orderBy } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/scenes/Document/components/MultiplayerEditor.tsx b/app/scenes/Document/components/MultiplayerEditor.tsx index 6bdf9c38b6..d21060b40d 100644 --- a/app/scenes/Document/components/MultiplayerEditor.tsx +++ b/app/scenes/Document/components/MultiplayerEditor.tsx @@ -1,5 +1,5 @@ import { HocuspocusProvider, WebSocketStatus } from "@hocuspocus/provider"; -import throttle from "lodash/throttle"; +import { throttle } from "es-toolkit/compat"; import { useState, useLayoutEffect, diff --git a/app/scenes/Document/components/PresentationMode.tsx b/app/scenes/Document/components/PresentationMode.tsx index 6c61e87b19..5bf1cfaa9d 100644 --- a/app/scenes/Document/components/PresentationMode.tsx +++ b/app/scenes/Document/components/PresentationMode.tsx @@ -7,7 +7,7 @@ import Icon from "@shared/components/Icon"; import { richExtensions } from "@shared/editor/nodes"; import { canUseElementFullscreen } from "@shared/utils/browser"; 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 { ProsemirrorHelper } from "@shared/utils/ProsemirrorHelper"; import { colorPalette } from "@shared/utils/collections"; diff --git a/app/scenes/Document/hooks/useDocumentSave.ts b/app/scenes/Document/hooks/useDocumentSave.ts index a674330568..ccd7db3097 100644 --- a/app/scenes/Document/hooks/useDocumentSave.ts +++ b/app/scenes/Document/hooks/useDocumentSave.ts @@ -1,6 +1,4 @@ -import cloneDeep from "lodash/cloneDeep"; -import debounce from "lodash/debounce"; -import isEqual from "lodash/isEqual"; +import { cloneDeep, debounce, isEqual } from "es-toolkit/compat"; import { Node } from "prosemirror-model"; import type { Selection } from "prosemirror-state"; import { AllSelection, TextSelection } from "prosemirror-state"; diff --git a/app/scenes/Login/Login.tsx b/app/scenes/Login/Login.tsx index 30e0d4ba5c..02c97a136f 100644 --- a/app/scenes/Login/Login.tsx +++ b/app/scenes/Login/Login.tsx @@ -1,4 +1,4 @@ -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { EmailIcon } from "outline-icons"; import * as React from "react"; diff --git a/app/scenes/Login/OAuthScopeHelper.ts b/app/scenes/Login/OAuthScopeHelper.ts index ac301e4fb6..078ee8810e 100644 --- a/app/scenes/Login/OAuthScopeHelper.ts +++ b/app/scenes/Login/OAuthScopeHelper.ts @@ -1,6 +1,5 @@ import type { TFunction } from "i18next"; -import capitalize from "lodash/capitalize"; -import uniq from "lodash/uniq"; +import { capitalize, uniq } from "es-toolkit/compat"; import { Scope } from "@shared/types"; export class OAuthScopeHelper { diff --git a/app/scenes/Settings/Details.tsx b/app/scenes/Settings/Details.tsx index 2f4af0e274..39582ec556 100644 --- a/app/scenes/Settings/Details.tsx +++ b/app/scenes/Settings/Details.tsx @@ -1,5 +1,5 @@ import { isHexColor } from "class-validator"; -import pickBy from "lodash/pickBy"; +import { pickBy } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { TeamIcon } from "outline-icons"; import { useRef, useState } from "react"; diff --git a/app/scenes/Settings/Embeds.tsx b/app/scenes/Settings/Embeds.tsx index 77f47fa507..f12209ed56 100644 --- a/app/scenes/Settings/Embeds.tsx +++ b/app/scenes/Settings/Embeds.tsx @@ -1,4 +1,4 @@ -import debounce from "lodash/debounce"; +import { debounce } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { BrowserIcon } from "outline-icons"; import * as React from "react"; diff --git a/app/scenes/Settings/Groups.tsx b/app/scenes/Settings/Groups.tsx index a42bfb1d7f..84d6d4c30a 100644 --- a/app/scenes/Settings/Groups.tsx +++ b/app/scenes/Settings/Groups.tsx @@ -1,5 +1,5 @@ import type { ColumnSort } from "@tanstack/react-table"; -import deburr from "lodash/deburr"; +import { deburr } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { PlusIcon, GroupIcon } from "outline-icons"; import * as React from "react"; diff --git a/app/scenes/Settings/Import.tsx b/app/scenes/Settings/Import.tsx index 225725013a..6893ae7bc1 100644 --- a/app/scenes/Settings/Import.tsx +++ b/app/scenes/Settings/Import.tsx @@ -1,4 +1,4 @@ -import orderBy from "lodash/orderBy"; +import { orderBy } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { NewDocumentIcon } from "outline-icons"; import * as React from "react"; diff --git a/app/scenes/Settings/Integrations.tsx b/app/scenes/Settings/Integrations.tsx index 95a975e9c3..bb4a138c6e 100644 --- a/app/scenes/Settings/Integrations.tsx +++ b/app/scenes/Settings/Integrations.tsx @@ -1,4 +1,4 @@ -import groupBy from "lodash/groupBy"; +import { groupBy } from "es-toolkit/compat"; import * as React from "react"; import { Trans, useTranslation } from "react-i18next"; import styled from "styled-components"; diff --git a/app/scenes/Settings/Notifications.tsx b/app/scenes/Settings/Notifications.tsx index ddaa61432c..9a87c5c2b8 100644 --- a/app/scenes/Settings/Notifications.tsx +++ b/app/scenes/Settings/Notifications.tsx @@ -1,4 +1,4 @@ -import debounce from "lodash/debounce"; +import { debounce } from "es-toolkit/compat"; import { runInAction } from "mobx"; import { observer } from "mobx-react"; import { diff --git a/app/scenes/Settings/Security.tsx b/app/scenes/Settings/Security.tsx index 93445473b4..c38344a311 100644 --- a/app/scenes/Settings/Security.tsx +++ b/app/scenes/Settings/Security.tsx @@ -1,4 +1,4 @@ -import debounce from "lodash/debounce"; +import { debounce } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { ShieldIcon } from "outline-icons"; import { useState } from "react"; diff --git a/app/scenes/Settings/Templates.tsx b/app/scenes/Settings/Templates.tsx index 6e12a9429c..27426afd11 100644 --- a/app/scenes/Settings/Templates.tsx +++ b/app/scenes/Settings/Templates.tsx @@ -1,5 +1,5 @@ import type { ColumnSort } from "@tanstack/react-table"; -import deburr from "lodash/deburr"; +import { deburr } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { ShapesIcon } from "outline-icons"; import { useEffect, useMemo, useCallback, useState } from "react"; diff --git a/app/scenes/Settings/components/DisconnectAnalyticsDialog.tsx b/app/scenes/Settings/components/DisconnectAnalyticsDialog.tsx index c26b7692b1..f361547d58 100644 --- a/app/scenes/Settings/components/DisconnectAnalyticsDialog.tsx +++ b/app/scenes/Settings/components/DisconnectAnalyticsDialog.tsx @@ -7,7 +7,7 @@ import useStores from "~/hooks/useStores"; import { useHistory } from "react-router-dom"; import { settingsPath } from "~/utils/routeHelpers"; import { observer } from "mobx-react"; -import capitalize from "lodash/capitalize"; +import { capitalize } from "es-toolkit/compat"; type Props = { integration: Integration; diff --git a/app/scenes/Settings/components/EmojisTable.tsx b/app/scenes/Settings/components/EmojisTable.tsx index a93cad326d..2289743038 100644 --- a/app/scenes/Settings/components/EmojisTable.tsx +++ b/app/scenes/Settings/components/EmojisTable.tsx @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { useCallback } from "react"; diff --git a/app/scenes/Settings/components/GroupDialogs.tsx b/app/scenes/Settings/components/GroupDialogs.tsx index f839d0f072..fb8f4a9a26 100644 --- a/app/scenes/Settings/components/GroupDialogs.tsx +++ b/app/scenes/Settings/components/GroupDialogs.tsx @@ -1,4 +1,4 @@ -import debounce from "lodash/debounce"; +import { debounce } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { Trans, useTranslation } from "react-i18next"; diff --git a/app/scenes/Settings/components/GroupMembersTable.tsx b/app/scenes/Settings/components/GroupMembersTable.tsx index 4c0630919d..b68ef3ecae 100644 --- a/app/scenes/Settings/components/GroupMembersTable.tsx +++ b/app/scenes/Settings/components/GroupMembersTable.tsx @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useMemo, useCallback } from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/scenes/Settings/components/GroupsTable.tsx b/app/scenes/Settings/components/GroupsTable.tsx index df7f2e66ab..e969f6c477 100644 --- a/app/scenes/Settings/components/GroupsTable.tsx +++ b/app/scenes/Settings/components/GroupsTable.tsx @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { GroupIcon, HiddenIcon } from "outline-icons"; import * as React from "react"; diff --git a/app/scenes/Settings/components/ImportListItem.tsx b/app/scenes/Settings/components/ImportListItem.tsx index d65b1c86c1..6b098afae8 100644 --- a/app/scenes/Settings/components/ImportListItem.tsx +++ b/app/scenes/Settings/components/ImportListItem.tsx @@ -1,4 +1,4 @@ -import capitalize from "lodash/capitalize"; +import { capitalize } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { CrossIcon, DoneIcon, WarningIcon } from "outline-icons"; import { useMemo, useCallback } from "react"; diff --git a/app/scenes/Settings/components/MembersTable.tsx b/app/scenes/Settings/components/MembersTable.tsx index b26382d924..2aeb4496fc 100644 --- a/app/scenes/Settings/components/MembersTable.tsx +++ b/app/scenes/Settings/components/MembersTable.tsx @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useMemo, useCallback } from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/scenes/Settings/components/SharesTable.tsx b/app/scenes/Settings/components/SharesTable.tsx index 5657eb7be5..a5a2eea92f 100644 --- a/app/scenes/Settings/components/SharesTable.tsx +++ b/app/scenes/Settings/components/SharesTable.tsx @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { useMemo, useCallback } from "react"; diff --git a/app/scenes/Settings/components/TemplatesTable.tsx b/app/scenes/Settings/components/TemplatesTable.tsx index 1b0b7499a6..f404d10e29 100644 --- a/app/scenes/Settings/components/TemplatesTable.tsx +++ b/app/scenes/Settings/components/TemplatesTable.tsx @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { DocumentIcon } from "outline-icons"; import React, { useCallback } from "react"; diff --git a/app/scenes/Settings/components/UserRoleFilter.tsx b/app/scenes/Settings/components/UserRoleFilter.tsx index 84019f0c24..ae38a59cf4 100644 --- a/app/scenes/Settings/components/UserRoleFilter.tsx +++ b/app/scenes/Settings/components/UserRoleFilter.tsx @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useMemo } from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/scenes/Settings/components/UserStatusFilter.tsx b/app/scenes/Settings/components/UserStatusFilter.tsx index 98a691d6d6..7dd83a5fef 100644 --- a/app/scenes/Settings/components/UserStatusFilter.tsx +++ b/app/scenes/Settings/components/UserStatusFilter.tsx @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { observer } from "mobx-react"; import { useMemo } from "react"; import { useTranslation } from "react-i18next"; diff --git a/app/stores/AuthStore.ts b/app/stores/AuthStore.ts index 5d6e0f0bc7..7e12ef5c44 100644 --- a/app/stores/AuthStore.ts +++ b/app/stores/AuthStore.ts @@ -1,6 +1,6 @@ import * as Sentry from "@sentry/react"; import invariant from "invariant"; -import isNil from "lodash/isNil"; +import { isNil } from "es-toolkit/compat"; import { observable, action, computed, autorun, runInAction } from "mobx"; import { getCookie, setCookie } from "tiny-cookie"; import type { CustomTheme } from "@shared/types"; diff --git a/app/stores/AuthenticationProvidersStore.ts b/app/stores/AuthenticationProvidersStore.ts index fc5a051bbe..697b408724 100644 --- a/app/stores/AuthenticationProvidersStore.ts +++ b/app/stores/AuthenticationProvidersStore.ts @@ -1,4 +1,4 @@ -import orderBy from "lodash/orderBy"; +import { orderBy } from "es-toolkit/compat"; import { computed } from "mobx"; import AuthenticationProvider from "~/models/AuthenticationProvider"; import type RootStore from "./RootStore"; diff --git a/app/stores/CollectionsStore.ts b/app/stores/CollectionsStore.ts index 8c12ad9c1b..a491abbb20 100644 --- a/app/stores/CollectionsStore.ts +++ b/app/stores/CollectionsStore.ts @@ -1,7 +1,5 @@ import invariant from "invariant"; -import isEmpty from "lodash/isEmpty"; -import orderBy from "lodash/orderBy"; -import sortBy from "lodash/sortBy"; +import { isEmpty, orderBy, sortBy } from "es-toolkit/compat"; import { computed, action, runInAction } from "mobx"; import { CollectionPermission, diff --git a/app/stores/CommentsStore.ts b/app/stores/CommentsStore.ts index 956d26b88b..cb531c002a 100644 --- a/app/stores/CommentsStore.ts +++ b/app/stores/CommentsStore.ts @@ -1,9 +1,5 @@ import invariant from "invariant"; -import compact from "lodash/compact"; -import differenceBy from "lodash/differenceBy"; -import keyBy from "lodash/keyBy"; -import orderBy from "lodash/orderBy"; -import uniq from "lodash/uniq"; +import { compact, differenceBy, keyBy, orderBy, uniq } from "es-toolkit/compat"; import { action, computed } from "mobx"; import Comment from "~/models/Comment"; import { type CommentSortOption, CommentSortType } from "~/types"; diff --git a/app/stores/DocumentsStore.ts b/app/stores/DocumentsStore.ts index 25a761b4f1..9c150ddee2 100644 --- a/app/stores/DocumentsStore.ts +++ b/app/stores/DocumentsStore.ts @@ -1,8 +1,5 @@ import invariant from "invariant"; -import compact from "lodash/compact"; -import filter from "lodash/filter"; -import omitBy from "lodash/omitBy"; -import orderBy from "lodash/orderBy"; +import { compact, filter, omitBy, orderBy } from "es-toolkit/compat"; import { observable, action, computed, runInAction } from "mobx"; import type { DirectionFilter, SortFilter } from "@shared/types"; import { diff --git a/app/stores/FileOperationsStore.ts b/app/stores/FileOperationsStore.ts index 6b4df8fc31..76b9fcfb6f 100644 --- a/app/stores/FileOperationsStore.ts +++ b/app/stores/FileOperationsStore.ts @@ -1,4 +1,4 @@ -import orderBy from "lodash/orderBy"; +import { orderBy } from "es-toolkit/compat"; import { computed } from "mobx"; import { FileOperationType } from "@shared/types"; import FileOperation from "~/models/FileOperation"; diff --git a/app/stores/GroupUsersStore.ts b/app/stores/GroupUsersStore.ts index 74823c1e1b..06e790cde9 100644 --- a/app/stores/GroupUsersStore.ts +++ b/app/stores/GroupUsersStore.ts @@ -1,5 +1,5 @@ import invariant from "invariant"; -import filter from "lodash/filter"; +import { filter } from "es-toolkit/compat"; import { action, runInAction } from "mobx"; import GroupUser from "~/models/GroupUser"; import type { PaginationParams } from "~/types"; diff --git a/app/stores/GroupsStore.ts b/app/stores/GroupsStore.ts index 5b55af06d8..22bb61c126 100644 --- a/app/stores/GroupsStore.ts +++ b/app/stores/GroupsStore.ts @@ -1,5 +1,5 @@ import invariant from "invariant"; -import filter from "lodash/filter"; +import { filter } from "es-toolkit/compat"; import { action, runInAction, computed } from "mobx"; import naturalSort from "@shared/utils/naturalSort"; import Group from "~/models/Group"; diff --git a/app/stores/NotificationsStore.ts b/app/stores/NotificationsStore.ts index fce6381ae6..244f31d0af 100644 --- a/app/stores/NotificationsStore.ts +++ b/app/stores/NotificationsStore.ts @@ -1,6 +1,5 @@ import invariant from "invariant"; -import orderBy from "lodash/orderBy"; -import sortBy from "lodash/sortBy"; +import { orderBy, sortBy } from "es-toolkit/compat"; import { action, computed, runInAction } from "mobx"; import Notification from "~/models/Notification"; import type { PaginationParams } from "~/types"; diff --git a/app/stores/RootStore.ts b/app/stores/RootStore.ts index b4843ff0fc..07fb24bd2e 100644 --- a/app/stores/RootStore.ts +++ b/app/stores/RootStore.ts @@ -1,5 +1,5 @@ import invariant from "invariant"; -import lowerFirst from "lodash/lowerFirst"; +import { lowerFirst } from "es-toolkit/compat"; import pluralize from "pluralize"; import ApiKeysStore from "./ApiKeysStore"; import AuthStore from "./AuthStore"; diff --git a/app/stores/SearchesStore.ts b/app/stores/SearchesStore.ts index 16d736a007..6f030ed34f 100644 --- a/app/stores/SearchesStore.ts +++ b/app/stores/SearchesStore.ts @@ -1,4 +1,4 @@ -import uniqBy from "lodash/uniqBy"; +import { uniqBy } from "es-toolkit/compat"; import { computed } from "mobx"; import SearchQuery from "~/models/SearchQuery"; import type RootStore from "./RootStore"; diff --git a/app/stores/SharesStore.ts b/app/stores/SharesStore.ts index 1ba7e510d1..781b277403 100644 --- a/app/stores/SharesStore.ts +++ b/app/stores/SharesStore.ts @@ -1,8 +1,5 @@ import invariant from "invariant"; -import filter from "lodash/filter"; -import find from "lodash/find"; -import isUndefined from "lodash/isUndefined"; -import orderBy from "lodash/orderBy"; +import { filter, find, isUndefined, orderBy } from "es-toolkit/compat"; import { action, computed, observable } from "mobx"; import type { NavigationNode, PublicTeam } from "@shared/types"; import type Document from "~/models/Document"; diff --git a/app/stores/TemplatesStore.ts b/app/stores/TemplatesStore.ts index 97e67eb483..410d984719 100644 --- a/app/stores/TemplatesStore.ts +++ b/app/stores/TemplatesStore.ts @@ -1,5 +1,4 @@ -import orderBy from "lodash/orderBy"; -import filter from "lodash/filter"; +import { filter, orderBy } from "es-toolkit/compat"; import { action, computed } from "mobx"; import { invariant } from "mobx-utils"; import naturalSort from "@shared/utils/naturalSort"; diff --git a/app/stores/UsersStore.ts b/app/stores/UsersStore.ts index ecab0267bd..a89ecc18b8 100644 --- a/app/stores/UsersStore.ts +++ b/app/stores/UsersStore.ts @@ -1,9 +1,6 @@ import commandScore from "command-score"; import invariant from "invariant"; -import deburr from "lodash/deburr"; -import differenceWith from "lodash/differenceWith"; -import filter from "lodash/filter"; -import orderBy from "lodash/orderBy"; +import { deburr, differenceWith, filter, orderBy } from "es-toolkit/compat"; import { computed, action, runInAction } from "mobx"; import type { UserRole } from "@shared/types"; import User from "~/models/User"; diff --git a/app/stores/ViewsStore.ts b/app/stores/ViewsStore.ts index 2945bbf248..2baef846f6 100644 --- a/app/stores/ViewsStore.ts +++ b/app/stores/ViewsStore.ts @@ -1,7 +1,4 @@ -import filter from "lodash/filter"; -import find from "lodash/find"; -import orderBy from "lodash/orderBy"; -import reduce from "lodash/reduce"; +import { filter, find, orderBy, reduce } from "es-toolkit/compat"; import View from "~/models/View"; import type RootStore from "./RootStore"; import Store, { RPCAction } from "./base/Store"; diff --git a/app/stores/base/Store.ts b/app/stores/base/Store.ts index c1cf3c3224..cf5458141d 100644 --- a/app/stores/base/Store.ts +++ b/app/stores/base/Store.ts @@ -1,13 +1,13 @@ import commandScore from "command-score"; import invariant from "invariant"; -// oxlint-disable-next-line lodash/import-scope -import type { ObjectIterateeCustom } from "lodash"; -import deburr from "lodash/deburr"; -import filter from "lodash/filter"; -import find from "lodash/find"; -import flatten from "lodash/flatten"; -import lowerFirst from "lodash/lowerFirst"; -import orderBy from "lodash/orderBy"; +import { + deburr, + filter, + find, + flatten, + lowerFirst, + orderBy, +} from "es-toolkit/compat"; import { observable, action, computed, runInAction } from "mobx"; import pluralize from "pluralize"; import { Pagination } from "@shared/constants"; @@ -24,6 +24,12 @@ import { client } from "~/utils/ApiClient"; import { AuthorizationError, NotFoundError } from "~/utils/errors"; import ParanoidModel from "~/models/base/ParanoidModel"; +type ListPredicate = + | ((value: T, index: number, collection: ArrayLike) => boolean) + | PropertyKey + | [PropertyKey, unknown] + | Partial; + export enum RPCAction { Info = "info", List = "list", @@ -475,7 +481,7 @@ export default abstract class Store { * * @param predicate A function that returns true if the item matches, or an object with the properties to match. */ - find = (predicate: ObjectIterateeCustom): T | undefined => + find = (predicate: ListPredicate): T | undefined => // @ts-expect-error not sure why T is incompatible find(this.orderedData, predicate); @@ -484,7 +490,7 @@ export default abstract class Store { * * @param predicate A function that returns true if the item matches, or an object with the properties to match. */ - filter = (predicate: ObjectIterateeCustom): T[] => + filter = (predicate: ListPredicate): T[] => // @ts-expect-error not sure why T is incompatible filter(this.orderedData, predicate); } diff --git a/app/utils/ApiClient.ts b/app/utils/ApiClient.ts index 91a4af051a..e71f42adf9 100644 --- a/app/utils/ApiClient.ts +++ b/app/utils/ApiClient.ts @@ -1,5 +1,5 @@ import retry from "fetch-retry"; -import trim from "lodash/trim"; +import { trim } from "es-toolkit/compat"; import queryString from "query-string"; import EDITOR_VERSION from "@shared/editor/version"; import type { JSONObject } from "@shared/types"; diff --git a/app/utils/PluginManager.ts b/app/utils/PluginManager.ts index 8f22d544d3..b6b7826b41 100644 --- a/app/utils/PluginManager.ts +++ b/app/utils/PluginManager.ts @@ -1,5 +1,4 @@ -import isArray from "lodash/isArray"; -import sortBy from "lodash/sortBy"; +import { isArray, sortBy } from "es-toolkit/compat"; import { action, observable } from "mobx"; import type Team from "~/models/Team"; import type User from "~/models/User"; diff --git a/app/utils/developer.ts b/app/utils/developer.ts index a0a2351d20..7a70652085 100644 --- a/app/utils/developer.ts +++ b/app/utils/developer.ts @@ -1,4 +1,4 @@ -import flatten from "lodash/flatten"; +import { flatten } from "es-toolkit/compat"; import stores from "~/stores"; import { flattenTree } from "@shared/utils/tree"; diff --git a/package.json b/package.json index 7196400a0a..077998ccab 100644 --- a/package.json +++ b/package.json @@ -126,6 +126,7 @@ "email-providers": "^1.14.0", "emoji-mart": "^5.6.0", "emoji-regex": "^10.6.0", + "es-toolkit": "^1.46.1", "es6-error": "^4.1.1", "fast-deep-equal": "^3.1.3", "fetch-retry": "^5.0.6", @@ -163,7 +164,6 @@ "koa-send": "5.0.1", "koa-sslify": "5.0.1", "koa-useragent": "^4.1.0", - "lodash": "^4.17.23", "mailparser": "^3.7.5", "mammoth": "^1.11.0", "markdown-it": "^14.1.1", diff --git a/plugins/diagrams/client/Settings.tsx b/plugins/diagrams/client/Settings.tsx index 6a30744378..23ac7ddeba 100644 --- a/plugins/diagrams/client/Settings.tsx +++ b/plugins/diagrams/client/Settings.tsx @@ -1,4 +1,4 @@ -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { useForm } from "react-hook-form"; diff --git a/plugins/figma/server/api/schema.ts b/plugins/figma/server/api/schema.ts index f8682d12ef..ce23a3e466 100644 --- a/plugins/figma/server/api/schema.ts +++ b/plugins/figma/server/api/schema.ts @@ -1,5 +1,5 @@ import { BaseSchema } from "@server/routes/api/schema"; -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; export const FigmaCallbackSchema = BaseSchema.extend({ diff --git a/plugins/figma/server/figma.ts b/plugins/figma/server/figma.ts index e8803213da..569636908a 100644 --- a/plugins/figma/server/figma.ts +++ b/plugins/figma/server/figma.ts @@ -3,7 +3,7 @@ import fetch from "@server/utils/fetch"; import env from "./env"; import { FigmaUtils } from "../shared/FigmaUtils"; import type { UnfurlSignature } from "@server/types"; -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import type { User } from "@server/models"; import { Integration } from "@server/models"; import { IntegrationType } from "@shared/types"; diff --git a/plugins/github/server/api/github.ts b/plugins/github/server/api/github.ts index 400b9e9a00..73f09b11d8 100644 --- a/plugins/github/server/api/github.ts +++ b/plugins/github/server/api/github.ts @@ -1,5 +1,5 @@ import Router from "koa-router"; -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import { IntegrationService, IntegrationType } from "@shared/types"; import { createContext } from "@server/context"; import { ValidationError } from "@server/errors"; diff --git a/plugins/github/server/api/schema.ts b/plugins/github/server/api/schema.ts index 48f6914814..fa2a64350c 100644 --- a/plugins/github/server/api/schema.ts +++ b/plugins/github/server/api/schema.ts @@ -1,5 +1,4 @@ -import isEmpty from "lodash/isEmpty"; -import isUndefined from "lodash/isUndefined"; +import { isEmpty, isUndefined } from "es-toolkit/compat"; import { z } from "zod"; import { BaseSchema } from "@server/routes/api/schema"; diff --git a/plugins/gitlab/server/api/schema.ts b/plugins/gitlab/server/api/schema.ts index dc8720e055..d6fdff9280 100644 --- a/plugins/gitlab/server/api/schema.ts +++ b/plugins/gitlab/server/api/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { BaseSchema } from "@server/routes/api/schema"; diff --git a/plugins/google/server/auth/google.ts b/plugins/google/server/auth/google.ts index d884524d3f..b030950373 100644 --- a/plugins/google/server/auth/google.ts +++ b/plugins/google/server/auth/google.ts @@ -1,7 +1,7 @@ import passport from "@outlinewiki/koa-passport"; import type { Context } from "koa"; import Router from "koa-router"; -import capitalize from "lodash/capitalize"; +import { capitalize } from "es-toolkit/compat"; import type { Profile } from "passport"; import { Strategy as GoogleStrategy } from "passport-google-oauth2"; import { languages } from "@shared/i18n"; diff --git a/plugins/googleanalytics/client/Settings.tsx b/plugins/googleanalytics/client/Settings.tsx index c455b4c9a4..1a8b885eb4 100644 --- a/plugins/googleanalytics/client/Settings.tsx +++ b/plugins/googleanalytics/client/Settings.tsx @@ -1,4 +1,4 @@ -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { useForm } from "react-hook-form"; diff --git a/plugins/linear/server/api/schema.ts b/plugins/linear/server/api/schema.ts index fdea51ae65..86b331a57f 100644 --- a/plugins/linear/server/api/schema.ts +++ b/plugins/linear/server/api/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { BaseSchema } from "@server/routes/api/schema"; diff --git a/plugins/linear/server/linear.ts b/plugins/linear/server/linear.ts index 0c44992ca8..63179dfca8 100644 --- a/plugins/linear/server/linear.ts +++ b/plugins/linear/server/linear.ts @@ -1,7 +1,7 @@ import type { Issue, WorkflowState } from "@linear/sdk"; import { LinearClient } from "@linear/sdk"; import fetch from "@server/utils/fetch"; -import sortBy from "lodash/sortBy"; +import { sortBy } from "es-toolkit/compat"; import { z } from "zod"; import type { IntegrationType } from "@shared/types"; import { IntegrationService, UnfurlResourceType } from "@shared/types"; diff --git a/plugins/matomo/client/Settings.tsx b/plugins/matomo/client/Settings.tsx index d5a3989802..2c1a2e3e59 100644 --- a/plugins/matomo/client/Settings.tsx +++ b/plugins/matomo/client/Settings.tsx @@ -1,4 +1,4 @@ -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { useForm } from "react-hook-form"; diff --git a/plugins/notion/server/api/schema.ts b/plugins/notion/server/api/schema.ts index 0428e3e80a..8e632ad31b 100644 --- a/plugins/notion/server/api/schema.ts +++ b/plugins/notion/server/api/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { BaseSchema } from "@server/routes/api/schema"; diff --git a/plugins/notion/server/notion.ts b/plugins/notion/server/notion.ts index af393005de..84e96d548b 100644 --- a/plugins/notion/server/notion.ts +++ b/plugins/notion/server/notion.ts @@ -15,8 +15,7 @@ import type { } from "@notionhq/client/build/src/api-endpoints"; import { RateLimit } from "async-sema"; import emojiRegex from "emoji-regex"; -import compact from "lodash/compact"; -import truncate from "lodash/truncate"; +import { compact, truncate } from "es-toolkit/compat"; import { z } from "zod"; import { Second } from "@shared/utils/time"; import { isUrl } from "@shared/utils/urls"; diff --git a/plugins/notion/server/utils/NotionConverter.ts b/plugins/notion/server/utils/NotionConverter.ts index 21ee0f6d81..bc3d23e17d 100644 --- a/plugins/notion/server/utils/NotionConverter.ts +++ b/plugins/notion/server/utils/NotionConverter.ts @@ -32,7 +32,7 @@ import type { SyncedBlockBlockObjectResponse, LinkToPageBlockObjectResponse, } from "@notionhq/client/build/src/api-endpoints"; -import isArray from "lodash/isArray"; +import { isArray } from "es-toolkit/compat"; import { NoticeTypes } from "@shared/editor/nodes/Notice"; import type { ProsemirrorData, ProsemirrorDoc } from "@shared/types"; import { MentionType } from "@shared/types"; diff --git a/plugins/oidc/server/auth/oidcRouter.ts b/plugins/oidc/server/auth/oidcRouter.ts index 827d27b377..89eaa00cb8 100644 --- a/plugins/oidc/server/auth/oidcRouter.ts +++ b/plugins/oidc/server/auth/oidcRouter.ts @@ -2,7 +2,7 @@ import passport from "@outlinewiki/koa-passport"; import JWT from "jsonwebtoken"; import type { Context } from "koa"; import type Router from "koa-router"; -import get from "lodash/get"; +import { get } from "es-toolkit/compat"; import { slugifyDomain } from "@shared/utils/domains"; import { parseEmail } from "@shared/utils/email"; import { isBase64Url } from "@shared/utils/urls"; diff --git a/plugins/search-postgres/server/PostgresSearchProvider.ts b/plugins/search-postgres/server/PostgresSearchProvider.ts index 1361beafa3..c00bc091e4 100644 --- a/plugins/search-postgres/server/PostgresSearchProvider.ts +++ b/plugins/search-postgres/server/PostgresSearchProvider.ts @@ -1,7 +1,5 @@ import invariant from "invariant"; -import escapeRegExp from "lodash/escapeRegExp"; -import find from "lodash/find"; -import map from "lodash/map"; +import { escapeRegExp, find, map } from "es-toolkit/compat"; import queryParser from "pg-tsquery"; import type { BindOrReplacements, diff --git a/plugins/slack/client/components/SlackListItem.tsx b/plugins/slack/client/components/SlackListItem.tsx index 36c45f6094..4498f96c15 100644 --- a/plugins/slack/client/components/SlackListItem.tsx +++ b/plugins/slack/client/components/SlackListItem.tsx @@ -1,4 +1,4 @@ -import uniq from "lodash/uniq"; +import { uniq } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { Trans, useTranslation } from "react-i18next"; diff --git a/plugins/slack/server/api/hooks.ts b/plugins/slack/server/api/hooks.ts index 4614b25f8c..ba656bffb8 100644 --- a/plugins/slack/server/api/hooks.ts +++ b/plugins/slack/server/api/hooks.ts @@ -1,6 +1,6 @@ import { t } from "i18next"; import Router from "koa-router"; -import escapeRegExp from "lodash/escapeRegExp"; +import { escapeRegExp } from "es-toolkit/compat"; import queryString from "query-string"; import { z } from "zod"; import { IntegrationService, IntegrationType } from "@shared/types"; diff --git a/plugins/slack/server/auth/schema.ts b/plugins/slack/server/auth/schema.ts index 29157ef466..3cc681f7c0 100644 --- a/plugins/slack/server/auth/schema.ts +++ b/plugins/slack/server/auth/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { BaseSchema } from "@server/routes/api/schema"; diff --git a/plugins/storage/server/api/schema.ts b/plugins/storage/server/api/schema.ts index 8482bd8e13..ff58a72bd1 100644 --- a/plugins/storage/server/api/schema.ts +++ b/plugins/storage/server/api/schema.ts @@ -1,5 +1,5 @@ import type formidable from "formidable"; -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { ValidateKey } from "@server/validation"; diff --git a/plugins/umami/client/Settings.tsx b/plugins/umami/client/Settings.tsx index 7fcb8a7618..c89c0a938f 100644 --- a/plugins/umami/client/Settings.tsx +++ b/plugins/umami/client/Settings.tsx @@ -1,4 +1,4 @@ -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import { observer } from "mobx-react"; import * as React from "react"; import { useForm } from "react-hook-form"; diff --git a/plugins/webhooks/client/components/WebhookSubscriptionForm.tsx b/plugins/webhooks/client/components/WebhookSubscriptionForm.tsx index b6881bb034..f79af68ecc 100644 --- a/plugins/webhooks/client/components/WebhookSubscriptionForm.tsx +++ b/plugins/webhooks/client/components/WebhookSubscriptionForm.tsx @@ -1,7 +1,5 @@ import * as Collapsible from "@radix-ui/react-collapsible"; -import filter from "lodash/filter"; -import includes from "lodash/includes"; -import isEqual from "lodash/isEqual"; +import { filter, includes, isEqual } from "es-toolkit/compat"; import { DisclosureIcon } from "outline-icons"; import { useEffect, useRef } from "react"; import { useForm } from "react-hook-form"; diff --git a/plugins/webhooks/server/api/webhookSubscriptions.ts b/plugins/webhooks/server/api/webhookSubscriptions.ts index 59fa2bb28a..00ef4b94db 100644 --- a/plugins/webhooks/server/api/webhookSubscriptions.ts +++ b/plugins/webhooks/server/api/webhookSubscriptions.ts @@ -1,6 +1,5 @@ import Router from "koa-router"; -import compact from "lodash/compact"; -import isEmpty from "lodash/isEmpty"; +import { compact, isEmpty } from "es-toolkit/compat"; import { Op, Sequelize, type WhereOptions } from "sequelize"; import { UserRole } from "@shared/types"; import auth from "@server/middlewares/authentication"; diff --git a/server/commands/documentCollaborativeUpdater.ts b/server/commands/documentCollaborativeUpdater.ts index 5d3b423442..d8b2bb42bf 100644 --- a/server/commands/documentCollaborativeUpdater.ts +++ b/server/commands/documentCollaborativeUpdater.ts @@ -1,5 +1,5 @@ import isEqual from "fast-deep-equal"; -import uniq from "lodash/uniq"; +import { uniq } from "es-toolkit/compat"; import { yDocToProsemirrorJSON } from "y-prosemirror"; import * as Y from "yjs"; import type { ProsemirrorData } from "@shared/types"; diff --git a/server/commands/documentImporter.ts b/server/commands/documentImporter.ts index 0bdd8be82b..bbde02ab4f 100644 --- a/server/commands/documentImporter.ts +++ b/server/commands/documentImporter.ts @@ -1,5 +1,5 @@ import mime from "mime-types"; -import truncate from "lodash/truncate"; +import { truncate } from "es-toolkit/compat"; import type { ProsemirrorData } from "@shared/types"; import { DocumentValidation } from "@shared/validations"; import { serializer } from "@server/editor"; diff --git a/server/commands/documentPermanentDeleter.ts b/server/commands/documentPermanentDeleter.ts index 6060cc580d..b136716391 100644 --- a/server/commands/documentPermanentDeleter.ts +++ b/server/commands/documentPermanentDeleter.ts @@ -1,4 +1,4 @@ -import uniq from "lodash/uniq"; +import { uniq } from "es-toolkit/compat"; import { Op, QueryTypes } from "sequelize"; import Logger from "@server/logging/Logger"; import { Document, Attachment } from "@server/models"; diff --git a/server/commands/teamUpdater.ts b/server/commands/teamUpdater.ts index df1c3251f0..6f8b3e60ca 100644 --- a/server/commands/teamUpdater.ts +++ b/server/commands/teamUpdater.ts @@ -1,5 +1,4 @@ -import has from "lodash/has"; -import isEqual from "lodash/isEqual"; +import { has, isEqual } from "es-toolkit/compat"; import { TeamPreference } from "@shared/types"; import env from "@server/env"; import type { Team, User } from "@server/models"; diff --git a/server/commands/userInviter.ts b/server/commands/userInviter.ts index 7f2e4434dc..770fe06752 100644 --- a/server/commands/userInviter.ts +++ b/server/commands/userInviter.ts @@ -1,5 +1,4 @@ -import uniqBy from "lodash/uniqBy"; -import partition from "lodash/partition"; +import { partition, uniqBy } from "es-toolkit/compat"; import { UserRole } from "@shared/types"; import InviteEmail from "@server/emails/templates/InviteEmail"; import env from "@server/env"; diff --git a/server/emails/templates/DocumentMentionedEmail.tsx b/server/emails/templates/DocumentMentionedEmail.tsx index 72ef3ba081..0f0a7a910a 100644 --- a/server/emails/templates/DocumentMentionedEmail.tsx +++ b/server/emails/templates/DocumentMentionedEmail.tsx @@ -1,4 +1,4 @@ -import differenceBy from "lodash/differenceBy"; +import { differenceBy } from "es-toolkit/compat"; import * as React from "react"; import { MentionType } from "@shared/types"; import { Document, Revision } from "@server/models"; diff --git a/server/emails/templates/GroupDocumentMentionedEmail.tsx b/server/emails/templates/GroupDocumentMentionedEmail.tsx index 35c7e10635..01e6c57540 100644 --- a/server/emails/templates/GroupDocumentMentionedEmail.tsx +++ b/server/emails/templates/GroupDocumentMentionedEmail.tsx @@ -1,4 +1,4 @@ -import differenceBy from "lodash/differenceBy"; +import { differenceBy } from "es-toolkit/compat"; import * as React from "react"; import { MentionType } from "@shared/types"; import { Document, Revision, Group } from "@server/models"; diff --git a/server/env.ts b/server/env.ts index deb18e32e1..463ae6af8a 100644 --- a/server/env.ts +++ b/server/env.ts @@ -15,7 +15,7 @@ import { IsBoolean, Min, } from "class-validator"; -import uniq from "lodash/uniq"; +import { uniq } from "es-toolkit/compat"; import { languages } from "@shared/i18n"; import { Day, Hour } from "@shared/utils/time"; import { diff --git a/server/index.ts b/server/index.ts index 8c74969fd6..98132d0a28 100644 --- a/server/index.ts +++ b/server/index.ts @@ -14,7 +14,7 @@ import Router from "koa-router"; import type { AddressInfo } from "node:net"; import stoppable from "stoppable"; import throng from "throng"; -import escape from "lodash/escape"; +import { escape } from "es-toolkit/compat"; import Logger from "./logging/Logger"; import services from "./services"; import { getArg } from "./utils/args"; diff --git a/server/logging/Logger.ts b/server/logging/Logger.ts index f1565c7783..faef2611ea 100644 --- a/server/logging/Logger.ts +++ b/server/logging/Logger.ts @@ -1,9 +1,7 @@ /* oxlint-disable no-console */ import type { IncomingMessage } from "node:http"; import { styleText } from "node:util"; -import isArray from "lodash/isArray"; -import isEmpty from "lodash/isEmpty"; -import isObject from "lodash/isObject"; +import { isArray, isEmpty, isObject } from "es-toolkit/compat"; import winston from "winston"; import env from "@server/env"; import Metrics from "@server/logging/Metrics"; diff --git a/server/middlewares/authentication.ts b/server/middlewares/authentication.ts index 6c9da3540e..014b8a8d8d 100644 --- a/server/middlewares/authentication.ts +++ b/server/middlewares/authentication.ts @@ -1,5 +1,5 @@ import type { Next } from "koa"; -import capitalize from "lodash/capitalize"; +import { capitalize } from "es-toolkit/compat"; import type { UserRole } from "@shared/types"; import { UserRoleHelper } from "@shared/utils/UserRoleHelper"; import tracer, { diff --git a/server/middlewares/csp.ts b/server/middlewares/csp.ts index 477793da6d..2e56cbae3d 100644 --- a/server/middlewares/csp.ts +++ b/server/middlewares/csp.ts @@ -1,7 +1,7 @@ import crypto from "node:crypto"; import type { Context, Next } from "koa"; import { contentSecurityPolicy } from "koa-helmet"; -import uniq from "lodash/uniq"; +import { uniq } from "es-toolkit/compat"; import env from "@server/env"; const getBucketOrigin = () => { diff --git a/server/middlewares/rateLimiter.ts b/server/middlewares/rateLimiter.ts index 95edd36f68..c5beb6deb9 100644 --- a/server/middlewares/rateLimiter.ts +++ b/server/middlewares/rateLimiter.ts @@ -1,5 +1,5 @@ import type { Next } from "koa"; -import defaults from "lodash/defaults"; +import { defaults } from "es-toolkit/compat"; import env from "@server/env"; import { RateLimitExceededError } from "@server/errors"; import Logger from "@server/logging/Logger"; diff --git a/server/models/Collection.ts b/server/models/Collection.ts index 1b27f8aa31..7e51f28062 100644 --- a/server/models/Collection.ts +++ b/server/models/Collection.ts @@ -1,10 +1,6 @@ /* oxlint-disable lines-between-class-members */ import fractionalIndex from "fractional-index"; -import find from "lodash/find"; -import findIndex from "lodash/findIndex"; -import isNil from "lodash/isNil"; -import remove from "lodash/remove"; -import uniq from "lodash/uniq"; +import { find, findIndex, isNil, remove, uniq } from "es-toolkit/compat"; import type { Identifier, Transaction, diff --git a/server/models/Document.ts b/server/models/Document.ts index 5e04740618..924588b541 100644 --- a/server/models/Document.ts +++ b/server/models/Document.ts @@ -1,7 +1,5 @@ /* oxlint-disable lines-between-class-members */ -import compact from "lodash/compact"; -import isNil from "lodash/isNil"; -import uniq from "lodash/uniq"; +import { compact, isNil, uniq } from "es-toolkit/compat"; import type { Identifier, InferAttributes, diff --git a/server/models/Reaction.ts b/server/models/Reaction.ts index 7dc27d42a5..a09fe492a2 100644 --- a/server/models/Reaction.ts +++ b/server/models/Reaction.ts @@ -1,5 +1,4 @@ -import cloneDeep from "lodash/cloneDeep"; -import uniq from "lodash/uniq"; +import { cloneDeep, uniq } from "es-toolkit/compat"; import type { Attributes, CreationAttributes, diff --git a/server/models/WebhookSubscription.ts b/server/models/WebhookSubscription.ts index f64d05e084..4c000adf22 100644 --- a/server/models/WebhookSubscription.ts +++ b/server/models/WebhookSubscription.ts @@ -1,5 +1,5 @@ import crypto from "node:crypto"; -import isNil from "lodash/isNil"; +import { isNil } from "es-toolkit/compat"; import type { InferAttributes, InferCreationAttributes, diff --git a/server/models/base/Model.ts b/server/models/base/Model.ts index f966fae9c7..8408198a09 100644 --- a/server/models/base/Model.ts +++ b/server/models/base/Model.ts @@ -1,7 +1,5 @@ import isEqual from "fast-deep-equal"; -import isArray from "lodash/isArray"; -import isObject from "lodash/isObject"; -import pick from "lodash/pick"; +import { isArray, isObject, pick } from "es-toolkit/compat"; import type { Attributes, CreateOptions, diff --git a/server/models/decorators/CounterCache.ts b/server/models/decorators/CounterCache.ts index 86e9953f79..22314ce285 100644 --- a/server/models/decorators/CounterCache.ts +++ b/server/models/decorators/CounterCache.ts @@ -1,4 +1,4 @@ -import isNil from "lodash/isNil"; +import { isNil } from "es-toolkit/compat"; import type { IncludeOptions, InferAttributes, diff --git a/server/models/decorators/Encrypted.ts b/server/models/decorators/Encrypted.ts index 8bbffcf5a3..3535b1e25f 100644 --- a/server/models/decorators/Encrypted.ts +++ b/server/models/decorators/Encrypted.ts @@ -1,5 +1,4 @@ -import isEmpty from "lodash/isEmpty"; -import isNil from "lodash/isNil"; +import { isEmpty, isNil } from "es-toolkit/compat"; import { getAttributes } from "sequelize-typescript"; import Logger from "@server/logging/Logger"; import vaults from "@server/storage/vaults"; diff --git a/server/models/helpers/AuthenticationHelper.ts b/server/models/helpers/AuthenticationHelper.ts index 13153d46f0..cdb32fdb1d 100644 --- a/server/models/helpers/AuthenticationHelper.ts +++ b/server/models/helpers/AuthenticationHelper.ts @@ -1,5 +1,5 @@ /* oxlint-disable @typescript-eslint/no-var-requires */ -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import env from "@server/env"; import type Team from "@server/models/Team"; import User from "@server/models/User"; diff --git a/server/models/helpers/NotificationHelper.ts b/server/models/helpers/NotificationHelper.ts index b28dea72c5..951732ad0d 100644 --- a/server/models/helpers/NotificationHelper.ts +++ b/server/models/helpers/NotificationHelper.ts @@ -1,5 +1,4 @@ -import uniq from "lodash/uniq"; -import uniqBy from "lodash/uniqBy"; +import { uniq, uniqBy } from "es-toolkit/compat"; import { Op } from "sequelize"; import { NotificationEventType, diff --git a/server/models/helpers/ProsemirrorHelper.tsx b/server/models/helpers/ProsemirrorHelper.tsx index 9b356de7fa..b4dddf6846 100644 --- a/server/models/helpers/ProsemirrorHelper.tsx +++ b/server/models/helpers/ProsemirrorHelper.tsx @@ -1,9 +1,8 @@ import emojiRegex from "emoji-regex"; import { JSDOM } from "jsdom"; -import chunk from "lodash/chunk"; +import { chunk, isMatch } from "es-toolkit/compat"; import { EditorState } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; -import isMatch from "lodash/isMatch"; import { Node, Fragment } from "prosemirror-model"; import { renderToString } from "react-dom/server"; import styled, { ServerStyleSheet, ThemeProvider } from "styled-components"; diff --git a/server/models/helpers/TextHelper.ts b/server/models/helpers/TextHelper.ts index 3bcd101a68..d995b3cd33 100644 --- a/server/models/helpers/TextHelper.ts +++ b/server/models/helpers/TextHelper.ts @@ -1,5 +1,4 @@ -import chunk from "lodash/chunk"; -import escapeRegExp from "lodash/escapeRegExp"; +import { chunk, escapeRegExp } from "es-toolkit/compat"; import { AttachmentPreset } from "@shared/types"; import { isInternalUrl } from "@shared/utils/urls"; import attachmentCreator from "@server/commands/attachmentCreator"; diff --git a/server/models/validators/Length.ts b/server/models/validators/Length.ts index 19d9e7911d..b8f906bfe1 100644 --- a/server/models/validators/Length.ts +++ b/server/models/validators/Length.ts @@ -1,9 +1,8 @@ -import size from "lodash/size"; import { addAttributeOptions } from "sequelize-typescript"; /** - * A decorator that validates the size of a string based on lodash's size. - * function. Useful for strings with unicode characters of variable lengths. + * A decorator that validates the length of a string by counting Unicode + * code points. Useful for strings with unicode characters of variable lengths. */ export default function Length({ msg, @@ -17,8 +16,9 @@ export default function Length({ return (target: object, propertyName: string) => addAttributeOptions(target, propertyName, { validate: { - validLength(value: string) { - if (size(value) > max || size(value) < min) { + validLength(value: string | null | undefined) { + const length = value ? [...value].length : 0; + if (length > max || length < min) { throw new Error(msg); } }, diff --git a/server/models/validators/TextLength.ts b/server/models/validators/TextLength.ts index 83374ee0e3..91c1252224 100644 --- a/server/models/validators/TextLength.ts +++ b/server/models/validators/TextLength.ts @@ -1,4 +1,3 @@ -import size from "lodash/size"; import { Node } from "prosemirror-model"; import { addAttributeOptions } from "sequelize-typescript"; import type { ProsemirrorData } from "@shared/types"; @@ -30,7 +29,8 @@ export default function TextLength({ throw new Error("Invalid data"); } - if (size(text) > max || size(text) < min) { + const length = text ? [...text].length : 0; + if (length > max || length < min) { throw new Error(msg); } }, diff --git a/server/onerror.ts b/server/onerror.ts index 32bbc4021c..a60bf6ffb4 100644 --- a/server/onerror.ts +++ b/server/onerror.ts @@ -3,9 +3,7 @@ import http from "node:http"; import path from "node:path"; import formidable from "formidable"; import type Koa from "koa"; -import escape from "lodash/escape"; -import isNil from "lodash/isNil"; -import snakeCase from "lodash/snakeCase"; +import { escape, isNil, snakeCase } from "es-toolkit/compat"; import env from "@server/env"; import { ClientClosedRequestError, InternalError } from "@server/errors"; import { requestErrorHandler } from "@server/logging/sentry"; diff --git a/server/policies/cancan.ts b/server/policies/cancan.ts index be585560ac..8425012f68 100644 --- a/server/policies/cancan.ts +++ b/server/policies/cancan.ts @@ -1,4 +1,4 @@ -import isObject from "lodash/isPlainObject"; +import { isPlainObject } from "es-toolkit/compat"; import type { Model } from "sequelize-typescript"; import { AuthorizationError } from "@server/errors"; @@ -42,14 +42,14 @@ export class CanCan { if ( typeof condition !== "undefined" && typeof condition !== "function" && - !isObject(condition) + !isPlainObject(condition) ) { throw new TypeError( `Expected condition to be object or function, got ${typeof condition}` ); } - if (condition && isObject(condition)) { + if (condition && isPlainObject(condition)) { condition = this.getConditionFn(condition); } diff --git a/server/presenters/policy.ts b/server/presenters/policy.ts index 17ec4b3c96..b355bb8058 100644 --- a/server/presenters/policy.ts +++ b/server/presenters/policy.ts @@ -1,4 +1,4 @@ -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import { traceFunction } from "@server/logging/tracing"; import type { User } from "@server/models"; import { serialize } from "../policies"; diff --git a/server/queues/processors/ImportsProcessor.ts b/server/queues/processors/ImportsProcessor.ts index 615b954ff0..65bcabc02b 100644 --- a/server/queues/processors/ImportsProcessor.ts +++ b/server/queues/processors/ImportsProcessor.ts @@ -1,7 +1,5 @@ import fractionalIndex from "fractional-index"; -import chunk from "lodash/chunk"; -import keyBy from "lodash/keyBy"; -import truncate from "lodash/truncate"; +import { chunk, keyBy, truncate } from "es-toolkit/compat"; import { Fragment, Node } from "prosemirror-model"; import type { CreateOptions, CreationAttributes, Transaction } from "sequelize"; import { UniqueConstraintError } from "sequelize"; diff --git a/server/queues/processors/WebsocketsProcessor.ts b/server/queues/processors/WebsocketsProcessor.ts index 1c578820ff..5a5717774f 100644 --- a/server/queues/processors/WebsocketsProcessor.ts +++ b/server/queues/processors/WebsocketsProcessor.ts @@ -1,7 +1,4 @@ -import compact from "lodash/compact"; -import concat from "lodash/concat"; -import uniq from "lodash/uniq"; -import uniqBy from "lodash/uniqBy"; +import { compact, concat, uniq, uniqBy } from "es-toolkit/compat"; import type { Server } from "socket.io"; import { Comment, diff --git a/server/queues/queue.ts b/server/queues/queue.ts index 442ae6d5fe..57dd605ec6 100644 --- a/server/queues/queue.ts +++ b/server/queues/queue.ts @@ -1,6 +1,6 @@ /* oxlint-disable @typescript-eslint/no-misused-promises */ import Queue from "bull"; -import snakeCase from "lodash/snakeCase"; +import { snakeCase } from "es-toolkit/compat"; import { Second } from "@shared/utils/time"; import env from "@server/env"; import Metrics from "@server/logging/Metrics"; diff --git a/server/queues/tasks/APIImportTask.ts b/server/queues/tasks/APIImportTask.ts index 334347199e..41e3e3749b 100644 --- a/server/queues/tasks/APIImportTask.ts +++ b/server/queues/tasks/APIImportTask.ts @@ -1,7 +1,5 @@ import type { JobOptions } from "bull"; -import chunk from "lodash/chunk"; -import truncate from "lodash/truncate"; -import uniqBy from "lodash/uniqBy"; +import { chunk, truncate, uniqBy } from "es-toolkit/compat"; import { Fragment, Node } from "prosemirror-model"; import type { WhereOptions } from "sequelize"; import { Transaction } from "sequelize"; diff --git a/server/queues/tasks/ExportDocumentTreeTask.ts b/server/queues/tasks/ExportDocumentTreeTask.ts index 0f5a681cab..448d09ab0f 100644 --- a/server/queues/tasks/ExportDocumentTreeTask.ts +++ b/server/queues/tasks/ExportDocumentTreeTask.ts @@ -1,6 +1,6 @@ import path from "node:path"; import type JSZip from "jszip"; -import escapeRegExp from "lodash/escapeRegExp"; +import { escapeRegExp } from "es-toolkit/compat"; import type { NavigationNode } from "@shared/types"; import { FileOperationFormat } from "@shared/types"; import Logger from "@server/logging/Logger"; diff --git a/server/queues/tasks/ExportJSONTask.ts b/server/queues/tasks/ExportJSONTask.ts index 6a8d486559..401b4aec8c 100644 --- a/server/queues/tasks/ExportJSONTask.ts +++ b/server/queues/tasks/ExportJSONTask.ts @@ -1,5 +1,5 @@ import JSZip from "jszip"; -import omit from "lodash/omit"; +import { omit } from "es-toolkit/compat"; import type { NavigationNode } from "@shared/types"; import env from "@server/env"; import Logger from "@server/logging/Logger"; diff --git a/server/queues/tasks/ExportTask.ts b/server/queues/tasks/ExportTask.ts index af19dc590d..7d87be51f7 100644 --- a/server/queues/tasks/ExportTask.ts +++ b/server/queues/tasks/ExportTask.ts @@ -1,5 +1,5 @@ import fs from "fs-extra"; -import truncate from "lodash/truncate"; +import { truncate } from "es-toolkit/compat"; import type { NavigationNode } from "@shared/types"; import { FileOperationState, NotificationEventType } from "@shared/types"; import { bytesToHumanReadable } from "@shared/utils/files"; diff --git a/server/queues/tasks/ImportJSONTask.ts b/server/queues/tasks/ImportJSONTask.ts index 824db125eb..f240e05dd4 100644 --- a/server/queues/tasks/ImportJSONTask.ts +++ b/server/queues/tasks/ImportJSONTask.ts @@ -1,6 +1,6 @@ import path from "node:path"; import fs from "fs-extra"; -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import mime from "mime-types"; import { Fragment, Node } from "prosemirror-model"; import { randomUUID } from "node:crypto"; diff --git a/server/queues/tasks/ImportMarkdownZipTask.ts b/server/queues/tasks/ImportMarkdownZipTask.ts index 03114b39ac..8a05a10854 100644 --- a/server/queues/tasks/ImportMarkdownZipTask.ts +++ b/server/queues/tasks/ImportMarkdownZipTask.ts @@ -1,6 +1,6 @@ import path from "node:path"; import fs from "fs-extra"; -import escapeRegExp from "lodash/escapeRegExp"; +import { escapeRegExp } from "es-toolkit/compat"; import mime from "mime-types"; import { randomUUID } from "node:crypto"; import documentImporter from "@server/commands/documentImporter"; diff --git a/server/queues/tasks/ImportTask.ts b/server/queues/tasks/ImportTask.ts index e3569b6f65..61d3efaabe 100644 --- a/server/queues/tasks/ImportTask.ts +++ b/server/queues/tasks/ImportTask.ts @@ -1,7 +1,6 @@ import path from "node:path"; import fs from "fs-extra"; -import chunk from "lodash/chunk"; -import truncate from "lodash/truncate"; +import { chunk, truncate } from "es-toolkit/compat"; import type { InferCreationAttributes } from "sequelize"; import tmp from "tmp"; import type { CollectionSort, ProsemirrorData } from "@shared/types"; diff --git a/server/queues/tasks/RevisionCreatedNotificationsTask.ts b/server/queues/tasks/RevisionCreatedNotificationsTask.ts index f718187a97..2a7fcf8f06 100644 --- a/server/queues/tasks/RevisionCreatedNotificationsTask.ts +++ b/server/queues/tasks/RevisionCreatedNotificationsTask.ts @@ -1,5 +1,5 @@ import { subHours } from "date-fns"; -import differenceBy from "lodash/differenceBy"; +import { differenceBy } from "es-toolkit/compat"; import { Op } from "sequelize"; import { MentionType, NotificationEventType } from "@shared/types"; import { createSubscriptionsForDocument } from "@server/commands/subscriptionCreator"; diff --git a/server/routes/api/attachments/schema.ts b/server/routes/api/attachments/schema.ts index 5fd6679775..fbbb9af8b8 100644 --- a/server/routes/api/attachments/schema.ts +++ b/server/routes/api/attachments/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { AttachmentPreset } from "@shared/types"; import { BaseSchema } from "@server/routes/api/schema"; diff --git a/server/routes/api/auth/auth.ts b/server/routes/api/auth/auth.ts index 4ebd2d2f0e..15f3d9dbdb 100644 --- a/server/routes/api/auth/auth.ts +++ b/server/routes/api/auth/auth.ts @@ -1,6 +1,6 @@ import { subHours, subMinutes } from "date-fns"; import Router from "koa-router"; -import uniqBy from "lodash/uniqBy"; +import { uniqBy } from "es-toolkit/compat"; import { TeamPreference } from "@shared/types"; import { parseDomain } from "@shared/utils/domains"; import env from "@server/env"; diff --git a/server/routes/api/collections/schema.ts b/server/routes/api/collections/schema.ts index dbba413be9..10f01debcb 100644 --- a/server/routes/api/collections/schema.ts +++ b/server/routes/api/collections/schema.ts @@ -1,4 +1,4 @@ -import isUndefined from "lodash/isUndefined"; +import { isUndefined } from "es-toolkit/compat"; import { z } from "zod"; import { CollectionPermission, diff --git a/server/routes/api/comments/comments.ts b/server/routes/api/comments/comments.ts index c7e88c7a30..2564889619 100644 --- a/server/routes/api/comments/comments.ts +++ b/server/routes/api/comments/comments.ts @@ -1,5 +1,5 @@ import Router from "koa-router"; -import difference from "lodash/difference"; +import { difference } from "es-toolkit/compat"; import type { FindOptions, WhereOptions } from "sequelize"; import { Op } from "sequelize"; import { diff --git a/server/routes/api/comments/schema.ts b/server/routes/api/comments/schema.ts index 0cbad755c1..f354d6c6e1 100644 --- a/server/routes/api/comments/schema.ts +++ b/server/routes/api/comments/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { CommentStatusFilter } from "@shared/types"; import { commentSchema } from "@server/editor"; diff --git a/server/routes/api/cron/schema.ts b/server/routes/api/cron/schema.ts index 1384dffbe6..5b6a0cebf8 100644 --- a/server/routes/api/cron/schema.ts +++ b/server/routes/api/cron/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { BaseSchema } from "../schema"; diff --git a/server/routes/api/documents/documents.ts b/server/routes/api/documents/documents.ts index 7951b0a92e..e8f3cac070 100644 --- a/server/routes/api/documents/documents.ts +++ b/server/routes/api/documents/documents.ts @@ -5,10 +5,7 @@ import invariant from "invariant"; import contentDisposition from "content-disposition"; import JSZip from "jszip"; import Router from "koa-router"; -import escapeRegExp from "lodash/escapeRegExp"; -import has from "lodash/has"; -import remove from "lodash/remove"; -import uniq from "lodash/uniq"; +import { escapeRegExp, has, remove, uniq } from "es-toolkit/compat"; import mime from "mime-types"; import type { Order, ScopeOptions, WhereOptions } from "sequelize"; import { Op, Sequelize } from "sequelize"; diff --git a/server/routes/api/documents/schema.ts b/server/routes/api/documents/schema.ts index 68e8f12028..d50844cd15 100644 --- a/server/routes/api/documents/schema.ts +++ b/server/routes/api/documents/schema.ts @@ -1,5 +1,5 @@ import type formidable from "formidable"; -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { DirectionFilter, diff --git a/server/routes/api/events/events.ts b/server/routes/api/events/events.ts index e430a716bb..d754eae15f 100644 --- a/server/routes/api/events/events.ts +++ b/server/routes/api/events/events.ts @@ -1,5 +1,5 @@ import Router from "koa-router"; -import intersection from "lodash/intersection"; +import { intersection } from "es-toolkit/compat"; import type { WhereOptions } from "sequelize"; import { Op } from "sequelize"; import { EventHelper } from "@shared/utils/EventHelper"; diff --git a/server/routes/api/fileOperations/schema.ts b/server/routes/api/fileOperations/schema.ts index b25c1b9285..b18c5138a3 100644 --- a/server/routes/api/fileOperations/schema.ts +++ b/server/routes/api/fileOperations/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import z from "zod"; import { FileOperationType } from "@shared/types"; import { FileOperation } from "@server/models"; diff --git a/server/routes/api/groupMemberships/groupMemberships.ts b/server/routes/api/groupMemberships/groupMemberships.ts index d333db6df1..8e6c443e80 100644 --- a/server/routes/api/groupMemberships/groupMemberships.ts +++ b/server/routes/api/groupMemberships/groupMemberships.ts @@ -1,5 +1,5 @@ import Router from "koa-router"; -import uniqBy from "lodash/uniqBy"; +import { uniqBy } from "es-toolkit/compat"; import { Op } from "sequelize"; import auth from "@server/middlewares/authentication"; import validate from "@server/middlewares/validate"; diff --git a/server/routes/api/imports/imports.ts b/server/routes/api/imports/imports.ts index 66a33b9b4e..58d5d58f59 100644 --- a/server/routes/api/imports/imports.ts +++ b/server/routes/api/imports/imports.ts @@ -1,5 +1,5 @@ import Router from "koa-router"; -import truncate from "lodash/truncate"; +import { truncate } from "es-toolkit/compat"; import type { WhereOptions } from "sequelize"; import type { IntegrationType } from "@shared/types"; import { ImportState, UserRole } from "@shared/types"; diff --git a/server/routes/api/notifications/notifications.ts b/server/routes/api/notifications/notifications.ts index 77b5366f8a..877079a307 100644 --- a/server/routes/api/notifications/notifications.ts +++ b/server/routes/api/notifications/notifications.ts @@ -1,8 +1,5 @@ import Router from "koa-router"; -import isEmpty from "lodash/isEmpty"; -import isNil from "lodash/isNil"; -import isNull from "lodash/isNull"; -import isUndefined from "lodash/isUndefined"; +import { isEmpty, isNil, isNull, isUndefined } from "es-toolkit/compat"; import type { WhereOptions } from "sequelize"; import { Op } from "sequelize"; import type { NotificationEventType } from "@shared/types"; diff --git a/server/routes/api/notifications/schema.ts b/server/routes/api/notifications/schema.ts index c0dadc92cb..e40e78c229 100644 --- a/server/routes/api/notifications/schema.ts +++ b/server/routes/api/notifications/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { NotificationEventType } from "@shared/types"; import { BaseSchema } from "../schema"; diff --git a/server/routes/api/revisions/revisions.ts b/server/routes/api/revisions/revisions.ts index 40067b88c1..b914ad83e6 100644 --- a/server/routes/api/revisions/revisions.ts +++ b/server/routes/api/revisions/revisions.ts @@ -2,7 +2,7 @@ import path from "node:path"; import Router from "koa-router"; import contentDisposition from "content-disposition"; import JSZip from "jszip"; -import escapeRegExp from "lodash/escapeRegExp"; +import { escapeRegExp } from "es-toolkit/compat"; import mime from "mime-types"; import { UserRole } from "@shared/types"; import { RevisionHelper } from "@shared/utils/RevisionHelper"; diff --git a/server/routes/api/revisions/schema.ts b/server/routes/api/revisions/schema.ts index eb2058cb42..2ed1f1eee5 100644 --- a/server/routes/api/revisions/schema.ts +++ b/server/routes/api/revisions/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { RevisionValidation } from "@shared/validations"; import { Revision } from "@server/models"; diff --git a/server/routes/api/searches/schema.ts b/server/routes/api/searches/schema.ts index 61184f0d55..fff2c93f6a 100644 --- a/server/routes/api/searches/schema.ts +++ b/server/routes/api/searches/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { BaseSchema } from "../schema"; diff --git a/server/routes/api/shares/schema.ts b/server/routes/api/shares/schema.ts index d36df15c48..8d88baf764 100644 --- a/server/routes/api/shares/schema.ts +++ b/server/routes/api/shares/schema.ts @@ -1,5 +1,5 @@ import { isURL } from "class-validator"; -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { UrlHelper } from "@shared/utils/UrlHelper"; import { ShareValidation } from "@shared/validations"; diff --git a/server/routes/api/shares/shares.ts b/server/routes/api/shares/shares.ts index 1700b31430..b1daea22f8 100644 --- a/server/routes/api/shares/shares.ts +++ b/server/routes/api/shares/shares.ts @@ -1,5 +1,5 @@ import Router from "koa-router"; -import isUndefined from "lodash/isUndefined"; +import { isUndefined } from "es-toolkit/compat"; import type { FindOptions, WhereAttributeHash, WhereOptions } from "sequelize"; import { Op } from "sequelize"; import { subMinutes } from "date-fns"; diff --git a/server/routes/api/stars/schema.ts b/server/routes/api/stars/schema.ts index 8799d3ce91..a4f0c799dc 100644 --- a/server/routes/api/stars/schema.ts +++ b/server/routes/api/stars/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { ValidateDocumentId, ValidateIndex } from "@server/validation"; import { BaseSchema } from "../schema"; diff --git a/server/routes/api/subscriptions/schema.ts b/server/routes/api/subscriptions/schema.ts index 48cb82cb70..aa163ad141 100644 --- a/server/routes/api/subscriptions/schema.ts +++ b/server/routes/api/subscriptions/schema.ts @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import { z } from "zod"; import { SubscriptionType } from "@shared/types"; import { ValidateDocumentId } from "@server/validation"; diff --git a/server/routes/api/urls/schema.ts b/server/routes/api/urls/schema.ts index addb74cd4d..70ccd36c02 100644 --- a/server/routes/api/urls/schema.ts +++ b/server/routes/api/urls/schema.ts @@ -1,4 +1,4 @@ -import isNil from "lodash/isNil"; +import { isNil } from "es-toolkit/compat"; import isUUID from "validator/lib/isUUID"; import { z } from "zod"; import { UrlHelper } from "@shared/utils/UrlHelper"; diff --git a/server/routes/app.ts b/server/routes/app.ts index fe07b8aeac..510dc59cb3 100644 --- a/server/routes/app.ts +++ b/server/routes/app.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import path from "node:path"; import util from "node:util"; import type { Context, Next } from "koa"; -import escape from "lodash/escape"; +import { escape } from "es-toolkit/compat"; import { Sequelize } from "sequelize"; import isUUID from "validator/lib/isUUID"; import { diff --git a/server/storage/files/BaseStorage.ts b/server/storage/files/BaseStorage.ts index e74d48d29f..fb354d2b61 100644 --- a/server/storage/files/BaseStorage.ts +++ b/server/storage/files/BaseStorage.ts @@ -1,7 +1,7 @@ import type { Blob } from "node:buffer"; import type { Readable } from "node:stream"; import type { PresignedPost } from "@aws-sdk/s3-presigned-post"; -import omit from "lodash/omit"; +import { omit } from "es-toolkit/compat"; import FileHelper from "@shared/editor/lib/FileHelper"; import { isBase64Url, isInternalUrl } from "@shared/utils/urls"; import { Week } from "@shared/utils/time"; diff --git a/server/storage/files/S3Storage.ts b/server/storage/files/S3Storage.ts index 7b5996248b..7b605d49d2 100644 --- a/server/storage/files/S3Storage.ts +++ b/server/storage/files/S3Storage.ts @@ -15,7 +15,7 @@ import { createPresignedPost } from "@aws-sdk/s3-presigned-post"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import fs from "fs-extra"; import invariant from "invariant"; -import compact from "lodash/compact"; +import { compact } from "es-toolkit/compat"; import tmp from "tmp"; import env from "@server/env"; import Logger from "@server/logging/Logger"; diff --git a/server/storage/redis.ts b/server/storage/redis.ts index ec240015f6..6625247772 100644 --- a/server/storage/redis.ts +++ b/server/storage/redis.ts @@ -1,6 +1,6 @@ import type { RedisOptions } from "ioredis"; import Redis from "ioredis"; -import defaults from "lodash/defaults"; +import { defaults } from "es-toolkit/compat"; import env from "@server/env"; import Logger from "@server/logging/Logger"; import { getConnectionName } from "./utils"; diff --git a/server/test/factories.ts b/server/test/factories.ts index 8f939a993d..1e1ef8729a 100644 --- a/server/test/factories.ts +++ b/server/test/factories.ts @@ -1,6 +1,5 @@ import { faker } from "@faker-js/faker"; -import isNil from "lodash/isNil"; -import isNull from "lodash/isNull"; +import { isNil, isNull } from "es-toolkit/compat"; import { Node } from "prosemirror-model"; import type { InferCreationAttributes } from "sequelize"; import type { DeepPartial } from "utility-types"; diff --git a/server/utils/DocumentConverter.ts b/server/utils/DocumentConverter.ts index b67582bd79..3b4011078a 100644 --- a/server/utils/DocumentConverter.ts +++ b/server/utils/DocumentConverter.ts @@ -1,6 +1,6 @@ import { parse } from "@fast-csv/parse"; import { JSDOM } from "jsdom"; -import escapeRegExp from "lodash/escapeRegExp"; +import { escapeRegExp } from "es-toolkit/compat"; import { simpleParser } from "mailparser"; import mammoth from "mammoth"; import type { Node } from "prosemirror-model"; diff --git a/server/utils/PluginManager.ts b/server/utils/PluginManager.ts index d9091d328f..14cec019e4 100644 --- a/server/utils/PluginManager.ts +++ b/server/utils/PluginManager.ts @@ -1,8 +1,7 @@ import path from "node:path"; import { glob } from "glob"; import type Router from "koa-router"; -import isArray from "lodash/isArray"; -import sortBy from "lodash/sortBy"; +import { isArray, sortBy } from "es-toolkit/compat"; import type BaseEmail from "@server/emails/templates/BaseEmail"; import env from "@server/env"; import Logger from "@server/logging/Logger"; diff --git a/server/utils/ShutdownHelper.ts b/server/utils/ShutdownHelper.ts index 8ffb83e3c0..115234d08a 100644 --- a/server/utils/ShutdownHelper.ts +++ b/server/utils/ShutdownHelper.ts @@ -1,4 +1,4 @@ -import groupBy from "lodash/groupBy"; +import { groupBy } from "es-toolkit/compat"; import Logger from "@server/logging/Logger"; import { sleep } from "@shared/utils/timers"; diff --git a/server/utils/authentication.ts b/server/utils/authentication.ts index c6e8a93aa8..2ee94e0709 100644 --- a/server/utils/authentication.ts +++ b/server/utils/authentication.ts @@ -1,7 +1,7 @@ import querystring from "node:querystring"; import { addMonths } from "date-fns"; import type { Context } from "koa"; -import pick from "lodash/pick"; +import { pick } from "es-toolkit/compat"; import { Client } from "@shared/types"; import { getCookieDomain } from "@shared/utils/domains"; import env from "@server/env"; diff --git a/server/utils/decorators/Public.ts b/server/utils/decorators/Public.ts index 3f61f59719..4d9214ebc9 100644 --- a/server/utils/decorators/Public.ts +++ b/server/utils/decorators/Public.ts @@ -1,5 +1,5 @@ import "reflect-metadata"; -import isUndefined from "lodash/isUndefined"; +import { isUndefined } from "es-toolkit/compat"; import type { Environment } from "@server/env"; const key = Symbol("env:public"); diff --git a/server/utils/fetch.ts b/server/utils/fetch.ts index b895219ca5..8be7ba9e09 100644 --- a/server/utils/fetch.ts +++ b/server/utils/fetch.ts @@ -13,7 +13,7 @@ import tunnelAgent, { type TunnelAgent } from "tunnel-agent"; import env from "@server/env"; import { InternalError } from "@server/errors"; import Logger from "@server/logging/Logger"; -import { capitalize } from "lodash"; +import { capitalize } from "es-toolkit/compat"; import { type RequestFilteringAgentOptions, useAgent as useFilteringAgent, diff --git a/server/utils/koa.ts b/server/utils/koa.ts index 247e8cb462..75c21dd493 100644 --- a/server/utils/koa.ts +++ b/server/utils/koa.ts @@ -1,6 +1,6 @@ import type formidable from "formidable"; import type { Request } from "koa"; -import isArray from "lodash/isArray"; +import { isArray } from "es-toolkit/compat"; /** * Get the first file from an incoming koa request diff --git a/server/utils/parseAttachmentIds.ts b/server/utils/parseAttachmentIds.ts index 2cd008fd1f..ec0f602021 100644 --- a/server/utils/parseAttachmentIds.ts +++ b/server/utils/parseAttachmentIds.ts @@ -1,5 +1,4 @@ -import compact from "lodash/compact"; -import uniq from "lodash/uniq"; +import { compact, uniq } from "es-toolkit/compat"; import { attachmentPublicRegex, attachmentRedirectRegex, diff --git a/server/utils/permissions.ts b/server/utils/permissions.ts index ba7cb00951..b5e3684a26 100644 --- a/server/utils/permissions.ts +++ b/server/utils/permissions.ts @@ -1,5 +1,4 @@ -import compact from "lodash/compact"; -import orderBy from "lodash/orderBy"; +import { compact, orderBy } from "es-toolkit/compat"; import type { WhereOptions } from "sequelize"; import { Op } from "sequelize"; import { CollectionPermission, DocumentPermission } from "@shared/types"; diff --git a/server/utils/sitemap.ts b/server/utils/sitemap.ts index acbd15cf3d..50a381bfa0 100644 --- a/server/utils/sitemap.ts +++ b/server/utils/sitemap.ts @@ -1,4 +1,4 @@ -import escape from "lodash/escape"; +import { escape } from "es-toolkit/compat"; import type { NavigationNode } from "@shared/types"; /** diff --git a/server/utils/startup.ts b/server/utils/startup.ts index a56c36f8bc..0a40f22cbe 100644 --- a/server/utils/startup.ts +++ b/server/utils/startup.ts @@ -1,5 +1,5 @@ import { styleText } from "node:util"; -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "es-toolkit/compat"; import env from "@server/env"; import Logger from "@server/logging/Logger"; import AuthenticationProvider from "@server/models/AuthenticationProvider"; diff --git a/server/validation.ts b/server/validation.ts index 5ba5f54cb0..27aa093f68 100644 --- a/server/validation.ts +++ b/server/validation.ts @@ -1,4 +1,4 @@ -import isArrayLike from "lodash/isArrayLike"; +import { isArrayLike } from "es-toolkit/compat"; import sanitize from "sanitize-filename"; import type { Primitive } from "utility-types"; import validator from "validator"; diff --git a/shared/components/ColorPicker.tsx b/shared/components/ColorPicker.tsx index 5790b07ff9..8b40967c6f 100644 --- a/shared/components/ColorPicker.tsx +++ b/shared/components/ColorPicker.tsx @@ -1,5 +1,5 @@ import copy from "copy-to-clipboard"; -import debounce from "lodash/debounce"; +import { debounce } from "es-toolkit/compat"; import { CheckmarkIcon, CopyIcon } from "outline-icons"; import { useMemo, useState, useEffect, useRef, useCallback } from "react"; import { diff --git a/shared/editor/commands/table.ts b/shared/editor/commands/table.ts index 4c35f13810..daba099d26 100644 --- a/shared/editor/commands/table.ts +++ b/shared/editor/commands/table.ts @@ -41,8 +41,7 @@ import { collapseSelection } from "./collapseSelection"; import { RowSelection } from "../selection/RowSelection"; import { ColumnSelection } from "../selection/ColumnSelection"; import type { Attrs } from "prosemirror-model"; -import isUndefined from "lodash/isUndefined"; -import find from "lodash/find"; +import { find, isUndefined } from "es-toolkit/compat"; /** * Restores column selection after a table operation that may have changed cell diff --git a/shared/editor/components/Image.tsx b/shared/editor/components/Image.tsx index 8a403a1392..2f41d1f0d6 100644 --- a/shared/editor/components/Image.tsx +++ b/shared/editor/components/Image.tsx @@ -3,7 +3,7 @@ import type { EditorView } from "prosemirror-view"; import * as React from "react"; import styled from "styled-components"; import { useTranslation } from "react-i18next"; -import find from "lodash/find"; +import { find } from "es-toolkit/compat"; import Flex from "../../components/Flex"; import { s } from "../../styles"; import { isExternalUrl, sanitizeUrl } from "../../utils/urls"; diff --git a/shared/editor/extensions/CodeHighlighting.ts b/shared/editor/extensions/CodeHighlighting.ts index e39ed398cd..8218d30e1f 100644 --- a/shared/editor/extensions/CodeHighlighting.ts +++ b/shared/editor/extensions/CodeHighlighting.ts @@ -1,5 +1,4 @@ -import flattenDeep from "lodash/flattenDeep"; -import padStart from "lodash/padStart"; +import { flattenDeep, padStart } from "es-toolkit/compat"; import type { Node } from "prosemirror-model"; import type { Transaction } from "prosemirror-state"; import { Plugin, PluginKey } from "prosemirror-state"; diff --git a/shared/editor/extensions/Mermaid.ts b/shared/editor/extensions/Mermaid.ts index b255d0a4b1..43dd98a61c 100644 --- a/shared/editor/extensions/Mermaid.ts +++ b/shared/editor/extensions/Mermaid.ts @@ -1,6 +1,5 @@ +import { last, sortBy } from "es-toolkit/compat"; import { t } from "i18next"; -import last from "lodash/last"; -import sortBy from "lodash/sortBy"; import { v4 as uuidv4 } from "uuid"; import type MermaidUnsafe from "mermaid"; import type { IconPack } from "@fortawesome/fontawesome-common-types"; diff --git a/shared/editor/lib/headingToSlug.ts b/shared/editor/lib/headingToSlug.ts index 6f32c50421..5a58c2b34f 100644 --- a/shared/editor/lib/headingToSlug.ts +++ b/shared/editor/lib/headingToSlug.ts @@ -1,4 +1,4 @@ -import escape from "lodash/escape"; +import { escape } from "es-toolkit/compat"; import type { Node } from "prosemirror-model"; import slugify from "slugify"; diff --git a/shared/editor/lib/markInputRule.ts b/shared/editor/lib/markInputRule.ts index 83a9f9e419..517e05b476 100644 --- a/shared/editor/lib/markInputRule.ts +++ b/shared/editor/lib/markInputRule.ts @@ -1,4 +1,4 @@ -import escapeRegExp from "lodash/escapeRegExp"; +import { escapeRegExp } from "es-toolkit/compat"; import { InputRule } from "prosemirror-inputrules"; import type { MarkType } from "prosemirror-model"; import type { EditorState } from "prosemirror-state"; diff --git a/shared/editor/nodes/Doc.ts b/shared/editor/nodes/Doc.ts index 7f6670e996..5a11c07453 100644 --- a/shared/editor/nodes/Doc.ts +++ b/shared/editor/nodes/Doc.ts @@ -1,4 +1,4 @@ -import isNull from "lodash/isNull"; +import { isNull } from "es-toolkit/compat"; import type { NodeSpec } from "prosemirror-model"; import { PlaceholderPlugin } from "../plugins/PlaceholderPlugin"; import Node from "./Node"; diff --git a/shared/editor/nodes/Mention.tsx b/shared/editor/nodes/Mention.tsx index 77a015b41f..b311d3c6ef 100644 --- a/shared/editor/nodes/Mention.tsx +++ b/shared/editor/nodes/Mention.tsx @@ -1,4 +1,4 @@ -import isMatch from "lodash/isMatch"; +import { isMatch } from "es-toolkit/compat"; import { sanitizeUrl } from "../../utils/urls"; import type { Token } from "markdown-it"; import type { diff --git a/shared/editor/plugins/PlaceholderPlugin.ts b/shared/editor/plugins/PlaceholderPlugin.ts index 5395c49540..2511bf55b5 100644 --- a/shared/editor/plugins/PlaceholderPlugin.ts +++ b/shared/editor/plugins/PlaceholderPlugin.ts @@ -1,6 +1,4 @@ -import filter from "lodash/filter"; -import find from "lodash/find"; -import map from "lodash/map"; +import { filter, find, map } from "es-toolkit/compat"; import type { Node, ResolvedPos } from "prosemirror-model"; import type { EditorState } from "prosemirror-state"; import { Plugin } from "prosemirror-state"; diff --git a/shared/editor/queries/findCutAfterHeading.ts b/shared/editor/queries/findCutAfterHeading.ts index 7e83094ff1..335be3bde8 100644 --- a/shared/editor/queries/findCutAfterHeading.ts +++ b/shared/editor/queries/findCutAfterHeading.ts @@ -1,4 +1,4 @@ -import filter from "lodash/filter"; +import { filter } from "es-toolkit/compat"; import type { ResolvedPos } from "prosemirror-model"; import { findBlockNodes } from "./findChildren"; diff --git a/shared/editor/utils.ts b/shared/editor/utils.ts index 808febf1c2..a7aed48639 100644 --- a/shared/editor/utils.ts +++ b/shared/editor/utils.ts @@ -1,5 +1,4 @@ -import filter from "lodash/filter"; -import isNull from "lodash/isNull"; +import { filter, isNull } from "es-toolkit/compat"; import type { Node, NodeType, ResolvedPos, Attrs } from "prosemirror-model"; import { Slice, Fragment } from "prosemirror-model"; import type { TextSelection, Transaction } from "prosemirror-state"; diff --git a/shared/utils/IconLibrary.tsx b/shared/utils/IconLibrary.tsx index 48754bbe12..ba2276c9a7 100644 --- a/shared/utils/IconLibrary.tsx +++ b/shared/utils/IconLibrary.tsx @@ -117,7 +117,7 @@ import { faSpiral, } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import intersection from "lodash/intersection"; +import { intersection } from "es-toolkit/compat"; import { BookmarkedIcon, BicycleIcon, diff --git a/shared/utils/domains.ts b/shared/utils/domains.ts index 126505b7d0..464316ce58 100644 --- a/shared/utils/domains.ts +++ b/shared/utils/domains.ts @@ -1,4 +1,4 @@ -import trim from "lodash/trim"; +import { trim } from "es-toolkit/compat"; import env from "../env"; type Domain = { diff --git a/shared/utils/emoji.ts b/shared/utils/emoji.ts index 47b1941708..07b3d66d78 100644 --- a/shared/utils/emoji.ts +++ b/shared/utils/emoji.ts @@ -2,8 +2,7 @@ import RawData from "@emoji-mart/data"; import type { EmojiMartData, Skin } from "@emoji-mart/data"; import { init, Data } from "emoji-mart"; import FuzzySearch from "fuzzy-search"; -import capitalize from "lodash/capitalize"; -import sortBy from "lodash/sortBy"; +import { capitalize, sortBy } from "es-toolkit/compat"; import type { Emoji, EmojiVariants } from "../types"; import { EmojiCategory, EmojiSkinTone } from "../types"; diff --git a/shared/utils/naturalSort.ts b/shared/utils/naturalSort.ts index c7ca6fbf7e..f83b544db6 100644 --- a/shared/utils/naturalSort.ts +++ b/shared/utils/naturalSort.ts @@ -1,5 +1,5 @@ import emojiRegex from "emoji-regex"; -import deburr from "lodash/deburr"; +import { deburr } from "es-toolkit/compat"; import naturalSort from "natural-sort"; type NaturalSortOptions = { diff --git a/shared/utils/rfc6902/diff.ts b/shared/utils/rfc6902/diff.ts index 75ab50d9a1..709714669f 100644 --- a/shared/utils/rfc6902/diff.ts +++ b/shared/utils/rfc6902/diff.ts @@ -1,4 +1,4 @@ -import isEqual from "lodash/isEqual"; +import { isEqual } from "es-toolkit/compat"; import type { Pointer } from "./pointer"; import { hasOwn, objectType } from "./util"; diff --git a/shared/utils/urls.ts b/shared/utils/urls.ts index 08efdf9b05..7836363a59 100644 --- a/shared/utils/urls.ts +++ b/shared/utils/urls.ts @@ -1,4 +1,4 @@ -import escapeRegExp from "lodash/escapeRegExp"; +import { escapeRegExp } from "es-toolkit/compat"; import env from "../env"; import { isBrowser } from "./browser"; import { parseDomain } from "./domains"; diff --git a/vite.config.ts b/vite.config.ts index 8293462434..335dbfc8f3 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -239,8 +239,8 @@ export default () => priority: 20, }, { - name: "vendor-lodash", - test: /node_modules[\\/](lodash|lodash-es)/, + name: "vendor-es-toolkit", + test: /node_modules[\\/]es-toolkit/, priority: 20, }, { diff --git a/yarn.lock b/yarn.lock index 080070ca0d..b7643fc5b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11703,6 +11703,18 @@ __metadata: languageName: node linkType: hard +"es-toolkit@npm:^1.46.1": + version: 1.46.1 + resolution: "es-toolkit@npm:1.46.1" + dependenciesMeta: + "@trivago/prettier-plugin-sort-imports@4.3.0": + unplugged: true + prettier-plugin-sort-re-exports@0.0.1: + unplugged: true + checksum: 10c0/6a4c3dd0ddc2138fa13d983d93ebaf8061759c52c2cf7c3101315139fc1fca826d253daa67fe85ad880c03cc4c092bd53a83a7cbf58b4721c251479122ba5303 + languageName: node + linkType: hard + "es6-error@npm:^4.1.1": version: 4.1.1 resolution: "es6-error@npm:4.1.1" @@ -16896,6 +16908,7 @@ __metadata: email-providers: "npm:^1.14.0" emoji-mart: "npm:^5.6.0" emoji-regex: "npm:^10.6.0" + es-toolkit: "npm:^1.46.1" es6-error: "npm:^4.1.1" fast-deep-equal: "npm:^3.1.3" fetch-retry: "npm:^5.0.6" @@ -16940,7 +16953,6 @@ __metadata: koa-sslify: "npm:5.0.1" koa-useragent: "npm:^4.1.0" lint-staged: "npm:^16.4.0" - lodash: "npm:^4.17.23" mailparser: "npm:^3.7.5" mammoth: "npm:^1.11.0" markdown-it: "npm:^14.1.1"